SECCON 2015 オンライン予選 write-up
はじめに
SECCON 2015 オンライン予選にぼっちチームhoge444として出てた。
競技開催期間は2015年12月05日(土) 15:00:00(JST)から24時間。
実質2問しか解けなかった。
Title | Genre | Points |
---|---|---|
Start SECCON CTF | Exercises | 50 |
SECCON WARS 2015 | Stegano | 100 |
Connect the server | Web/Network | 100 |
Last Challenge (Thank you for playing) | Exercises | 50 |
Start SECCON CTF
問題文
ex1 Cipher:PXFR}QIVTMSZCNDKUWAGJB{LHYEO Plain: ABCDEFGHIJKLMNOPQRSTUVWXYZ{} ex2 Cipher:EV}ZZD{DWZRA}FFDNFGQO Plain: {HELLOWORLDSECCONCTF} quiz Cipher:A}FFDNEVPFSGV}KZPN}GO Plain: ?????????????????????
解法
置換表がex1で与えられているのでPythonのstring.maketransを使って変換テーブルを作る。
#!/usr/bin/env python2 # -*- conding: utf-8 -*- import string cihper = 'A}FFDNEVPFSGV}KZPN}GO' table = string.maketrans('PXFR}QIVTMSZCNDKUWAGJB{LHYEO', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ{}') print cihper.translate(table)
trコマンドでも解ける。
$ echo "A}FFDNEVPFSGV}KZPN}GO" | tr PXFR}QIVTMSZCNDKUWAGJB{LHYEO ABCDEFGHIJKLMNOPQRSTUVWXYZ{} SECCON{HACKTHEPLANET}
FLAG:
SECCON{HACKTHEPLANET}
Connect the server
問題文
login.pwn.seccon.jp:10000
解法
まずncコマンドで接続を試みる。
WireSharkで通信を監視して適当にFollow TCP StreamするとFLAGっぽいものが見える。
FLAG:
SECCON{Sometimes_what_you_see_is_NOT_what_you_get}
SECCON WARS 2015
問題文
https://youtu.be/8SFsln4VyEk
解法
[追記]
よくよく考えたらgifをそのままPythonで処理すればよかった。
- Youtubeからmp4の動画をダウンロードし
Free Video to GIF Converter
で動画の00:25から01:05を切り取ってhoge.gifに変換(このときフレームレートは2 fpsで幅は600pxぐらいにするとよい)
#!/usr/bin/env python #-*- coding: utf-8 -*- from PIL import Image gif = Image.open('hoge.gif') width, height = gif.size png = Image.new('RGB', gif.size, 'black') while True: gif.load() for pos in ((x, y) for x in range(width) for y in range(height)): if gif.getpixel(pos) < 0x80: png.putpixel(pos, (0xff, 0xff, 0xff)) try: gif.seek(gif.tell() + 1) except: break png.save('flag.png', 'PNG')
[ここまで追記]
ひどい解き方をした。手順は次の通り。
youtubeから、問題の動画をダウンロード
Free Video to GIF Converterで動画の00:25から01:05を切り取ってhoge.gifに変換(フレームレートは1fpsにした)
convertコマンドで分離
$ convert +adjoin hoge.gif fuga.gif
(最初まっ黒な画像を作って読み込んだgifに白いところがあったら白を描画してる)
※このコードは汚いだけでなくて実行時間もかなりかかるので色々とひどい。
- flag.png
- 最後にQRコードを読み取るとFLAGが分かる。
FLAG:
SECCON{TH3F0RC3AVVAK3N53P7}
Last Challenge (Thank you for playing)
問題文
ex1 Cipher:PXFR}QIVTMSZCNDKUWAGJB{LHYEO Plain: ABCDEFGHIJKLMNOPQRSTUVWXYZ{} ex2 Cipher:EV}ZZD{DWZRA}FFDNFGQO Plain: {HELLOWORLDSECCONCTF} quiz Cipher:A}FFDNEA}}HDJN}LGH}PWO Plain: ??????????????????????
解法
最初の問題と同じ。
$ echo "A}FFDNEA}}HDJN}LGH}PWO" | tr PXFR}QIVTMSZCNDKUWAGJB{LHYEO ABCDEFGHIJKLMNOPQRSTUVWXYZ{} SECCON{SEEYOUNEXTYEAR}
FLAG:
SECCON{SEEYOUNEXTYEAR}
おわりに
問題は全然解けなかったけど、時間はたくさん溶けた。とても辛かった。
x86アセンブリ言語に関するメモ
x86系マイクロプロセッサの持つ主なレジスタ
レジスタ名 | 呼び名 | 主な機能 |
---|---|---|
EAX | アキュムレータ | 算術演算の結果を格納 |
EBX | ベースレジスタ | メモリアドレスを格納 |
ECX | カウントレジスタ | ループ回数をカウント |
EDX | データレジスタ | データを格納 |
ESI | ソースインデックス | データ転送元のメモリアドレスを格納 |
EDI | ディスティネーションインデックス | データ転送先のメモリアドレスを格納 |
EBP | ベースポインタ | データの格納領域のメモリアドレスを格納 |
ESP | スタックポインタ | スタック領域のメモリアドレスを格納 |
主な命令
命令 | 使用例 | 意味 | 詳細 |
---|---|---|---|
MOV | MOV EAX,ECX | EAX = ECX | ECXの値をEAXに格納 |
MOVZX | MOVZX_EAX,ECX | EAX = ECX | MOVのサイズが違うレジスタにコピーするとき用いる版 |
ADD | ADD EAX,ECX | EAX += ECX | EAXにECXを加算 |
SUB | SUB EAX,ECX | EAX -= ECX | EAXからECXを減算 |
MUL | MUL EAX,ECX | EAX *= ECX | EAXにECXを乗算 |
DIV | DIV EAX,ECX | EAX =EAX / ECX | EAXをECXで割って,商をEAXに,余りをEDXに格納 |
EDX = EAX % ECX | |||
INC | INC EAX | EAX++ | EAXに1を加算 |
DEC | DEC EAX | EAX-- | EAXに1を減算 |
XOR | XOR EAX,ECX | EAX = EAX ^ ECX | EAXとECXの各ビットごとに排他的論理和を取り,結果をEAXに格納 |
LEA | LEA EAX,[ECX+4] | EAX = ECX + 4 | ECX+4(アドレス値)をEAXに格納 |
CMP | CMP EAX,ECX | if(EAX==ECX)_ZF=1 | EAXとECXの値を比較してフラグに反映 |
else ZF = 0 | EAXとECXが等しければZF=1,EAXとECXが等しくなければ、ZF=0 | ||
TEST | TEST EAX,EAX | if(EAX==0) ZF = 1 | EAXの値を0と比較してフラグに反映 |
else ZF = 0 | EAXが0と等しければZF=1,EAXが0でなければZF=0 | ||
JE(JZ) | JE 041001000 | if(ZF == 1) | ZFが1なら041001000にジャンプ |
GOTO 041001000 | |||
JNE(JNZ) | JNE 041001000 | if(ZF == 0) | ZFが0なら041001000にジャンプ |
GOTO 041001000 | |||
JMP | JMP 041001000 | GOTO 041001000 | 無条件で041001000にジャンプ |
CALL | CALL lstrcmpW | lstrcmpW() | lstrcmpw関数の呼び出し |
PUSH | PUSH 00000001 | スタックへ00000001を格納 | |
POP | POP EAX | スタックからEAXへ値を取得 | |
NOP | NOP | 何もしない | |
SAR | SAR EAX | EAXを右にシフトする,すなわち2で割る | |
RET | RET | 処理を呼び出し元に戻す |
豆知識
XOR EAX,EAX は MOV EAX,0 と同様の働きをする。
dword ptr は、指定されたメモリアドレスから4バイトのデータを読み出すことを示す。
例えば、
MOV DWORD PTR SS:[EBP-8],1
の場合ベースポインタのアドレス-8から4バイトまでのデータに整数値1を格納している。
Pythonで16進文字列をintに変換
16進文字列からint
- 基数を指定してintにパースすればいい。
>>> s = 'abcdef' >>> print int(s, 16) 11259375
- ちなみにインタラクティブシェルなら0xからはじめた16進文字列を入力すれば10進数にしたものを返してくれる。
>>> 0xdeadbeef 3735928559
intから16進文字列
- hex()を使う
>>> a = 111223 >>> print hex(a) 0x1b277
- 先頭に0xがつくのがいやならformatメソッドを使うとよい
>>> a = 111223 >>> print format(a, 'x') 1b277
- こうなふうに先頭2文字を削除するという手もある
>>> a = 111223 >>> print hex(a)[2:] 1b277
- フォーマット指定子(%記法)を使ってもいい
>>> a = 111223 >>> print '%x' % a 1b277
簡単なタイピングゲーム
はじめに
C言語で簡単なタイピングゲームを作ってみた。
Visual C++でビルドすることを前提としてる。
コード
/*typing_cui1.c*/ #include <time.h> #include <conio.h> #include <ctype.h> #include <stdio.h> #include <string.h> #define Qnumber 20 int main(){ int i, stage, miss = 0, alpsum = 0; char *japanese[Qnumber] = { "交わした約束忘れないよ", "目を閉じ確かめる", "押し寄せた闇", "振り払って進むよ", "いつになったらなくした未来を", "私ここでまた見ることできるの?", "溢れ出した不安の影を", "何度でも裂いて", "この世界歩んでこう", "とめどなく刻まれた", "時は今始まり告げ", "変わらない思いをのせ", "閉ざされた扉開けよう", "目覚めた心は走り出した", "未来を描くため", "難しい道で立ち止まっても", "空はきれいな青さで", "いつも待っててくれる", "だから怖くない", "もう何があっても挫けない" }; char *roman[Qnumber] = { "kawasitayakusokuwasurenaiyo", "mewotojitasikameru", "osiyosetayami", "huriharattesusumuyo", "ituninattaranakusitamiraiwo", "watasikokodematamirukotodekiruno", "ahuredasitahuannnokagewo", "nandodemosaite", "konosekaiayundekou", "tomedonakukizamareta", "tokihaimahajimarituge", "kawaranaiomoiwonose", "tozasaretatobiraakeyou", "mezametakokorohahasiridasita", "miraiwoegakutame", "muzukasiimitidetatidomattemo", "sorahakireinaaosade", "itumomattetekureru", "dakarakowakunai", "mounanigaattemokujikenai" }; double time; clock_t start, end; for (i = 0; i < Qnumber; i++) alpsum += strlen(roman[i]); printf("スペースキーで開始です。\n"); while (_getch() != ' ') ; start = clock(); for (stage = 0; stage < Qnumber; stage++){ printf("%s\n", japanese[stage]); fflush(stdout); int len = strlen(roman[stage]); for (i = 0; i < len; i++){ int ch; do{ ch = _getch(); if (isprint(ch)){ _putch(ch); if (ch != roman[stage][i]){ miss++; _putch('\b'); } } } while (ch != roman[stage][i]); } printf("\n"); } end = clock(); time = (end - start) / CLOCKS_PER_SEC; printf("\n%.2ftypes/sec\n%.1ftypes/min\nmiss types:%d\n", alpsum / time, alpsum / time * 60,miss); return 0; }
入力されるアルファベットも指定しているのでかなり手抜き。
_getch()や_putch()など標準Cでは定義されてない関数を使っているので例えばgccでコンパイルしようとするとエラーになる。
参考
- 作者: 柴田望洋
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2008/10/22
- メディア: 単行本
- 購入: 1人 クリック: 10回
- この商品を含むブログ (3件) を見る