2023校赛总结
0 前言
- 我是什么垃圾 出题给大佬做(瑟瑟发抖
- 大概就记录一下审WP过程中佬们的非预期和发现的题中的一些问题
1 signin
这题还有非预期我是没想到的 菜狗哭泣(当时出的时候也没多想 就按磐石那个出的来着
1
2
3
4
5
6
7
8
9
10
11
12
13int __cdecl main(int argc, const char **argv, const char **envp)
{
__int64 v4[2]; // [rsp+0h] [rbp-10h] BYREF
v4[1] = __readfsqword(0x28u);
put(argc, argv, envp);
__isoc99_scanf("%ld", v4);
if ( v4[0] > 3 )
exit(-1);
if ( LODWORD(v4[0]) == B )
b4ckdo0r();
return 0;
}只要符号位为1 低32位为0x42就行 至于高32位的数值位为多少都行
然后关于如何发送的问题
但是这里读入用的是scanf,所以必须以字符串或者bytes的形式输入数字(X1ngCHEN师傅)
p64是不行的 但我查了查p64就是将整数转换成字节啊?(不过我好像用p64只会是地址
patchelf还可以这样写(X1ngCHEN师傅)
1
patchelf --set-interpreter /home/akyuu/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/ld-2.23.so --replace-needed libc.so.6 /home/akyuu/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc.so.6 pwn
2 EZest
有的师傅只写了一个SigFrame
用pop_rbp_ret
写/bin/sh1
2
3
4
5
6
7
8
9
10b'a'*0x10 + p64(pop_rbp_ret) + p64(bss - 0x10) + p64(0x40110e)
.text:000000000040110E 48 C7 C0 00 00 00 00 mov rax, 0
.text:0000000000401115 48 C7 C7 00 00 00 00 mov rdi, 0 ; fd
.text:000000000040111C 48 8D 75 F0 lea rsi, [rbp+buf] ; buf
.text:0000000000401120 48 C7 C2 00 02 00 00 mov rdx, 200h ; count
.text:0000000000401127 0F 05 syscall ; LINUX - sys_read
.text:0000000000401129 C3 retn
.text:0000000000401129
.text:0000000000401129 main endp ; sp-analysis failed不过本来也是板子题
3 magicode
这题可能出的还可以??(小心翼翼 还好当时没有把这么丑的代码改掉😏 不然师傅们就觉得贼简单了
但这题之前说过 保护那里应该可以怎么弄不显示rwx段(FSCTF那
Ephemeral1y师傅真的强 手打shellcode来着
pANz0e师傅add(-10)也是可以的还有Whhxy4师傅提到了绕过canary的问题
alloca在汇编⾥⾯的效果是add rsp,rdx
也就是1是分配⼀个栈根据rbp的位置往下减,输⼊0就是在rbp-0x10的位置开始以此类推 ,这题有
canary所以输⼊0正好跳过canary
emmm 我仔细看了一下 首先是sub rsp, rdx 然后是根据rsp的位置往下减,确实和canary无关 rbp的位置是固定的
X1ngCHEN师傅说有爆破? 啊出题和做题还是有些不同的 完全没考虑到
试了试X1ingCHEN师傅的exp,其实也并不用爆破 ,好像最后\x10
完全没用到 每一次都能getshell的1
payload = b'a'*(0x70) + shellcode.ljust(0x50, b'\x00')+b'\x10'
嗯嗯 确实 magic函数的实现为
1
2.text:0000000000001568 48 8B 45 E0 mov rax, [rbp+var_20] # 这个var_20我gdb看好像就是固定为0x20 然后这个位置存放的就是shellcode的起始位置
.text:000000000000156C FF D0 call rax好好好 alloca函数是为了对齐并且多0x10(可能是为了安全) 就是如果为alloca(0x60) 实际分配的是0x70 如果是alloca(0x64) 分配的也是0x70
gdb应该是能看到的会多分配0x10 alloca在汇编上的效果是
sub rsp, rdx
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# 这是执行完sub rsp, rdx以后 size输入的是0x20
0x555555555496 <main+311> sub rsp, rdx
► 0x555555555499 <main+314> mov rdx, rax
0x55555555549c <main+317> and edx, 0xfff
0x5555555554a2 <main+323> test rdx, rdx
0x5555555554a5 <main+326> je main+344 <main+344>
0x5555555554a7 <main+328> and eax, 0xfff
0x5555555554ac <main+333> sub rax, 8
──────────────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]───────────────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffdd10 ◂— 0xa3233 /* '32\n' */ # alloca(0x20)以后rsp的位置
01:0008│ 0x7fffffffdd18 ◂— 0x0
02:0010│ 0x7fffffffdd20 —▸ 0x7fffffffdf18 —▸ 0x7fffffffe278 ◂— '/home/yech0/sskd/hectf2023/2magicode/magicode'zhe
03:0018│ 0x7fffffffdd28 ◂— 0xe4c8453177346a00
04:0020│ 0x7fffffffdd30 —▸ 0x7fffffffde00 ◂— 0x1
05:0028│ 0x7fffffffdd38 —▸ 0x55555555543d (main+222) ◂— mov dword ptr [rbp - 0x2c], eax
06:0030│ 0x7fffffffdd40 —▸ 0x555555558020 (stdout@GLIBC_2.2.5) —▸ 0x7ffff7e1a780 (_IO_2_1_stdout_) ◂— 0xfbad2887 # rsp原先的位置
# 我这里gdb是如何实现多0x10的:(size输入0x20以后
0x555555555445 <main+230> lea rdx, [rax + 8] rdx:0x28
0x555555555449 <main+234> mov eax, 0x10 rax:0x10
0x55555555544e <main+239> sub rax, 1 rax:0xf
0x555555555452 <main+243> add rax, rdx rax:0x37
0x555555555455 <main+246> mov esi, 0x10
0x55555555545a <main+251> mov edx, 0
0x55555555545f <main+256> div rsi rax:0x3 rd:0x7
0x555555555462 <main+259> imul rax, rax, 0x10 rax:0x30
4 fmt
好好好 没有师傅用预期方法 菜狗爆哭 师傅们都太强了
我都不道会有stack_chk_fail的利用 那其实能利用多次的话就完全不用给后门了 师傅们好像也没用(555555 有一个(蔚蓝师傅用了fini_array pANz0e师傅用了fini_array没有泄露libc 又改stack_chk_fail泄露然后利用后门
读了题目都知道是格式化字符串漏洞了,但是正常情况下只能使用一次,这显然是无法让我们拿到shell的。
刚开始往格式化字符串泄露canary然后构造ROP的办法来想的,但是意识到第一步获得了canary又能干什么呢?啥都干不了,就exit了。所以我们不能这么平庸地看问题。
考虑到绕过Canary,不如与其正面硬刚,直接让Canary失效。
众所周知,如果程序检测到Canary被更改了,那么就会在函数结束的时候调用stk_chk_fail这个函数,然后就退出了。但是我们正是可以利用这一点,用格式化字符串更改stk_chk_fail的got表地址为main函数地址,那么就可以构造较长的payload来修改Canary从而可以无限次调用main函数,也是可以通过较短的payload不修改Canary来达到不接着调用
函数直接ret的效果。
既然可以控制main函数的执行了,那么我们也就可以控制格式化字符串漏洞的利用了。
于是我们这样利用漏洞:
1.第一次格式化字符串漏洞:修改__stk_chk_fail函数的got表地址为main函数地址。
2.第二次格式化字符串漏洞:获取栈上面__libc_start_main+128的地址。
3.第三次格式化字符串漏洞:构建并且输入ROP,但是这里payload的长度肯定会覆盖Canary,因此我们这里一定会进入下一层main函数,但是在下一层main函数我们随便传一个短短的字符串就行了,就可以不修改Canary从而达到退出执行上一层main函数输入的ROP的效果。
这里输入用的是scanf,遇到0d会截断,亲测system似乎打不通(我只试了本地,远程不知道),反正都有libc基址了,啥gedgets就都有了,而且ROP空间充足那么我们倒不如直接调用成功率更大的execve(X1ngCHEN师傅
然后这里还有个问题就是高版本rop的话没有pop_rdi_ret的这种gadget 于是师傅们用了libc里的
上面还说到system打不通 有的师傅用了execve 有的用的onegagetmagicode和这题enllus1on师傅都拿了一血 magicode不用多说 应该是做过fcalc那个题 这个题写的exp看不懂(最强双非22级是吧 瑟瑟发抖
sublime text ctrl shif L多行编辑
5 风水小狮
- emmmm 这个应该没啥注意的 都是预期解
6 风水中狮
- 又是enllus1on师傅 唯一解 真的强 %50$p和 %51%p都是flag的地址
- 沃趣 好像给的解释错了 给师傅们磕一个
7 风水大狮
- 好家伙 田总说加载沙箱的代码忘写了 非预期了 没有绕沙箱也能做的 好家伙 除了Ephemeral1y师傅用了看不懂的链子
怪我怪我 没审好题 - 如果有沙箱的话 就得绕 但还没看懂
8 easyweb
- 就X1ngCHEN师傅的唯一解呢 预期解 看看就欧克