入门题,考察 x64的字符格式化漏洞
和 Canray
main
里一个switch case
1 | 1.add |
menu()
这也有
再看每个函数
add()
naming()
这里很明显的存在fmt漏洞,变量名上其实也给了提示
edit()
这里是一个写入,写入长度是_b
所存储的长度。
gdb断点看下b
所在的位置
下一个rip
地址0x55555555533c
+0x2d2c
=0x555555558068
其实这个是在bss
部分
从反编译也可以看到
show()
思路
从反编译的地址可以看出这题开了pie
,还有喜闻乐见的canary
。
顺便题目还给了个libc
既然考点是format
,那存在fmt漏洞的也就只有naming
函数,不过他写死了长度0x30
,也就只能做fmt漏洞使用,触发点不在这个func里
另一个可以输入但是没有完全写死长度的是edit()
这里他是从bss部分的_b
里取长度值的,泄露pie
基地址+4068
就可以获取_b
的地址,用fmt
的$n
直接写就好
梳理一下
1.现在
naming()
存在fmt
漏洞2.题目存在
pie
和canary
以及需要泄露libc
3.
edit
的_b
作为输入长度取值地址,获取pie
基地址算出_b
就可以fmt
修改值
因为是x64的所以fmt的取值先过6个寄存器 rdi rsi rdx rcx r8 r9
测一下 这里我给了7个%p
这里不出意外的话会输出
0x7ffff7f9c643.<nil>.0x7ffff7ec44e0.0xa.<nil>.0x70252e70252e7025.0x252e70252e70252e
x64的传值顺序是
1 | rdi rsi rdx rcx r8 r9 栈 |
小tips:直接%p
的话会跳过第一个rdi
这里用%num$p
的还是会跳过
泄露pie
肉眼观察printf
这部分寄存器和栈上有没有可以用的func
我看中了rbp
后的main+133
1 | 09:0048│+008 0x7fffffffdd78 —▸ 0x555555555461 (main+113) ◂— jmp 0x555555555497 |
数了下需要%15$p
就可以leak,然后- 113
就可以获取func_main
,再用elf.symbol["main"]
减去偏移就可以获得pie的base
payload
1 | from pwn import * |
就获得了PIE的base
Canary
一样,用fmt泄露就行
这个位置的话是%13$p
1 | ··· |
输出0x33c0c0aef6d92700
libc
泄露libc的话我这里用%7$p
的setbuffer - 198
就可以获取到func_setbuffer
的地址
payload
1 | io.sendlineafter('>>','2') |
修改_b
所存储的内容
这里用pie的base
+ elf.symbols["b"]
就可以得到b的地址
1 | b_addr = base + elf.symbols["b"] |
然后是修改,因为是x64的,p64的地址其实是整个8
地址长度,超出8但不满16的像这里0x7fffffffdd50
会0x00补前面的位
又因为是小端序,所以在fmt写的时候如果先输入地址,read到\x00
时会结束,导致后面fmt写操作的%numc%num$lln
不会被读取到。
那就fmt_write + p64(b_addr)
就ok
1 | io.sendlineafter('>>','2') |
第一次接触的话可能会对这个write的payload有点疑惑%256c
其实就是256个空格,%8$lln
是把前面的字符数量计数,以(lln
)64位十进制整数 写到第8个地址所指向的地址(也就是栈上数从头往下数第三个),因为这里$n
写的话必须是要写到一个指针所指向的地址,所以我们%8
的位置需要写我们刚base+b
算出的b_addr
为了避免让read对我们的write不满足字节对齐8位,%256c%8$lln
长度是11,需要再补满16,就是%256c%8$llnaaaaa
如下图
继续走,看写入
此时edit()
的写入长度b
就被我们改为了0x100
我们再去看edit()
,0x58
可以覆盖完rbp
,rbp-0x10
的位置要放canary
我们再去找俩rop用的指令
找一下pop_rdi
和ret
1 | └─$ ROPgadget --binary ./book |grep "pop rdi" |
1 | └─$ ROPgadget --binary ./book --only "ret" |
pie_base
+对应的偏移即可
现在我们就凑齐了
1 | 1.edit()长度使用的b所指向的0x20被改写为0x100,使得edit存在溢出 |
此时payload
1 | payload = 0x48 * b"a" + p64(canary) + p64(ret) +p64(ret)+ p64(pop_rdi) + p64(binsh_addr) + p64(system_addr) |
完整payload
1 | from pwn import* |