ASIS CTF Finals 2013に参加した
久しぶりにCTFの参戦記。これまでもいくつか参加していたけど、ブログに書く余裕がなかったのであった。 write upではないので、詳細な解説はないです。
今回のCTFは、イランの ASIS CTF Finals 2013。Finalsだけど参加は誰でもできる。 ジャンルはWeb, Forensic, PPC (Professional Programming and Coding), RE (Reverse Engineering), Crypto, Stegoの6つ。 自分はPPCぐらいしか解けなかった。WebもCryptoも解けなかったのはつらい。 128チーム中45チームが解けていた "[RE 51] Simple Binary" が解けなかったのもつらい。
[PPC 76] Maze
$ nc *** 12433 Hi! Solve these mazes like the sample 1000111111 1101100101 0110111001 1011010111 1101010101 1011010101 1101101101 0100110101 0111010101 1101111101 => *000111111 **01100101 0**0111001 10**010*** 110*010*0* 101*010*0* 110**01*0* 0100**0*0* 01110*0*0* 11011***0* go ahead 1011101111 1110111001 0001000011 1111111110 1000010001 1111101101 0100110111 1010010101 1111010101 1001111101 ^C
迷路を解く問題。
単純な深さ優先で解けた。微妙。
import sys import socket from copy import deepcopy def solve1(stage, r=0, c=0): stage[r][c] = ord('*') print "[+]\n%s\n" % '\n'.join(map(str, stage)) if r == len(stage)-1 and c == len(stage[0])-1: return stage for (dr, dc) in [(0,-1), (-1,0), (0,1), (1,0)]: (r2, c2) = (r+dr, c+dc) if not (0 <= r2 < len(stage) and 0 <= c2 < len(stage[0])): continue if stage[r2][c2] == ord('1'): ans = solve1(deepcopy(stage), r2, c2) if ans: return ans def solve(data): stage = map(bytearray, data.split()) answer = solve1(stage) answer = '\n'.join(map(str, answer)) return answer HOST = '***' # The remote host PORT = 12433 # The same port as used by the server s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)) data = s.recv(1024) print "[+] Received: %r" % data while data: data = s.recv(1024) print "[+] Received: %r" % data answer = solve(data) print "[+] Answer\n%s\n" % answer s.sendall(answer) print "[+] Sended: %r" % answer data = s.recv(1024) print "[+] Received: %r" % data s.close()
[+] Received: '\nCongratulations! The flag is ASIS_1274a1c4f3a6f00ae92d2985f1413759\n'
[Forensic 75] rm-rf
We have received a usb flash backup. Which file the flag is in?
[for-75.img.xz]
$ unxz for-75.img.xz $ ll -h for-75.img -rw-r--r-- 1 john None 512M Aug 29 21:44 for-75.img $ file for-75.img for-75.img: Linux rev 1.0 ext3 filesystem data, UUID=f2b52915-94b9-418c-963b-b7f6e15b4f25 (large files)
512MBのext3ダンプからフラグを探す問題。
Mazeの答えからflagのフォーマットを推測し、stringsしただけで解けた。微妙。
$ strings for-75.img | grep -i ASIS > grep-asis.log $ head grep-asis.log ASIS_logo_200.png ASIS_b34c5b5b1b78cf9f352099aa35610ced!.D@ %%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See portions thereof) either on an unmodified basis, with other COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN ``AS IS'' BASIS, basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See portions thereof) either on an unmodified basis, with other COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN ``AS IS'' BASIS, basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
ASIS_b34c5b5b1b78cf9f352099aa35610ced
[PPC 203] Code Code Code
$ nc *** 12435 MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM MMMMMMMMMMMNNWNXNNWMMMMNXXKKXXNWMMMMMMMMMM MMMMMNOKOdkXxdK0XWMMMMMMWXOxdlloodkOXWMMMM MMNOKXxlOWMMMWMMMMNkddkKMMMMMKdollodxdkNMM MMXol0XOo0WMMMMMO,,:okc'.dWMMMWOllloxoco0W XxXNkONW0kWMMMMO lkXOdKOl.lMMMMWKXkllllcdN KlkWWKOXWKWMMMMo'NXWMWkx0:,MMMMWkdolllccoX Nxo0WNd:xWWMMMMX.cNW0KXkc.OMMMMKoooddlllkW MWOdNMXx:oKWWMWo:l;:c.';lXMMMWKOlcdd:lo0WM MMMWNNMKlcON0c..oNMMNNWMMMMXkkOldkkkKKWMMM MMMMMMMMMXO: lNMMMMMMMMNO0KOKWXKNMMMMMMMM MMMMMMMMMMMNkWMMMMMMMMMMMMMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM Are you ready for this, man! press any key What is the message hidden below: - - - - - - - + - - - + + + - + + - + + - + - - - - - - - - + + + + + - + - + - + + - - - - + + + - + - + + + + + - - + - - - + - + + - + + - + - + + + + + - + - + - - - + - - + - - - + - + + + - - - + + - - + - - - + - + - - - + - - + - - - + - + - - + - + - - - + - - + - + - + - - - + - - + + + + + - + - + + + + - - - + + - - - + - + + + + + - - - - - - - - + - + - + - + - + - + - + - + - - - - - - - + + + + + + + + + - - - - + + + + - - - - + + + + + + + + - - - - + - - + + + + - + - + - + - + - + - + - - + + - - + + - - - - + + + + - - + - - - + - - - + + - + + - + + + + + + - - - - - - + - + + - - + - - - - - - + + + + + + + + - + + + + + - + + + + - + - - + + + + - + - - + + + + - + - - - - + - + - + + - + - - + - + + - + - - + - + + - + - - + + + + + - - - + + - + - - - - + + - + - - - - + + - - - + + - + - + + - + - - + - + + - + - - + - + + - + - - - + + + - + + - - - + - - + - + - - - - - + - + + - + - - + - + - - - - + + + + + + - + + + + - + + - - + + + - + + + - + - - - + + - - - + + - + + + - - + - - - - - - - - - - + + - - + - + - - + - - - - + - - - - + - + + + - + - - + - - + + - + + + - + - - + - - + - + - + - + - - + + + - + - - + - - - - - + + - - - + - - + - + - - - - - - - - - + + + + + + + + + + - - + + + - - + + - - + + + - - - + - - - - - - - - + + - + + - - + + + + - + - + - + - + - + - - + + + + + - + - + - + + + + + + - - - - + + + - + - - + - + - - - + - + + + - + + - + - - - + - - - - - - - - + + - + - - - + - + - + + + - + + - - + + - - + + + - + + - - - + - - - + - + - - + + - + + - + + + + - - - + + + - - + - + + + + + - + - + - - - + - - - + + + - - - - + + - - + - - - - - - - + - + + - - + + + + - + - - + - + + + - + + Dont sleep!!!
QRコードをデコードする問題。
ZBarというライブラリがPILオブジェクトから直接デコードできて便利そうだったので、これを使って解いた。
import sys import socket import zbar import Image def solve(data): pixels = [] for line in data.splitlines(): pixels.append([0xFF if c == '+' else 0 for c in line.split()]) im = Image.new('L', (len(pixels), len(pixels[0]))) width, height = im.size for r in range(width): for c in range(height): im.putpixel((r,c), pixels[r][c]) width, height = width*10, height*10 im = im.resize((width, height)) scanner = zbar.ImageScanner() scanner.parse_config('enable') zbar_img = zbar.Image(width, height, 'Y800', im.tostring()) scanner.scan(zbar_img) for symbol in zbar_img: answer = symbol.data del(zbar_img) return answer HOST = '***' # The remote host PORT = 12435 # The same port as used by the server s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)) data = s.recv(1024) print "[+] Received: %r" % data data = s.recv(1024) print "[+] Received: %r" % data s.sendall("\n") print "[+] Sended: %r" % "\n" while data: data = s.recv(34) print "[+] Received: %r" % data data = s.recv(2048) print "[+] Received: %r" % data answer = solve(data) s.sendall(answer) print "[+] Sended: %r" % answer data = s.recv(1024) print "[+] Received: %r" % data s.close()
[+] Received: 'the flag is: ASIS_ebd814d43f558d1b73d077234f65b71b\n'
[PPC 450] Captcha (時間切れ)
1枚の画像に8つの円が描かれているので、それらの背景色を文字列として答える問題。
Python-OpenCVで円を認識させるところまではできたが、HoughCirclesのパラメータがうまく決まらず、個数が合わない。 パラメータを変えながら何度も試さないといけないんだろうな……と思い当たったあたりで、時間が取れず終了。
# -*- coding: utf-8 -*- import urllib2 import Image from cStringIO import StringIO import cv, cv2 import numpy as np def solve(im, cv_im): color2char = {'100': 'r', '010': 'g', '001': 'b', '110': 'y', '101': 'm', '011': 'c', '111': 'w'} cv_im = np.asarray(cv_im[:,:]) cv_im_gray = cv2.cvtColor(cv_im, cv.CV_BGR2GRAY) circles = cv2.HoughCircles(cv_im_gray, cv.CV_HOUGH_GRADIENT, dp=2, minDist=10, circles=None, param1=100, param2=100, minRadius=10, maxRadius=100) answer = "" for (x, y, radius) in circles[0]: rgb = im.getpixel((int(x), int(y))) color = ''.join([str(x >> 7) for x in rgb]) answer += color2char[color] assert len(answer) == 8 return answer if __name__ == '__main__': f = urllib2.urlopen('http://***:65437/') cookie = f.info()['Set-Cookie'].split(';', 1)[0] f.close() print "[+] cookie: %r" % cookie while True: opener = urllib2.build_opener() opener.addheaders.append(('Cookie', cookie)) f = opener.open('http://***:65437/captcha.png') png = f.read() f.close() im = Image.open(StringIO(png)) cv_im = cv.CreateImageHeader(im.size, cv.IPL_DEPTH_8U, 3) cv.SetData(cv_im, im.tostring()) assert im.size == cv.GetSize(cv_im) assert im.tostring() == cv_im.tostring() im.save('test.png') # for debugging answer = solve(im, cv_im) print "[+] answer: %r" % answer postdata = "username=&password=&captcha=%s&submit=" % answer print "[+] postdata: %r" % postdata f = opener.open('http://***:65437/', postdata) html = f.read() f.close() print "[+] result:\n%s" % html