Gen's blog

CTFとか、競プロとか、その他諸々

セキュリティ・キャンプ全国大会2016の応募用紙を晒す

今年も死んだよ。選択問題だけ晒す。


選択問題. 1

hogeはローカル変数であり、int型の10個ぶんの配列である。main関数の中でスタックポインタ(rsp)がずらされることにより、必要なサイズ(sizeof(int)*10bytes)がスタック上に確保される。C言語で配列名は配列の先頭アドレスを指すので、hogeにはスタック上に確保されたメモリの先頭アドレスが格納されていることになる。よって、0x7fff539799f0付近はスタックのアドレスであることがわかる。 fugaはintポインタとして宣言されており、malloc()により動的に確保されたメモリのアドレスが格納されている。malloc()はヒープ上にアドレスを確保するので、0x7fca11404c70付近はヒープのアドレスであることがわかる。

選択問題. 2

  1. HTTPS
    Webブラウザのアドレスバーに書かれている、スキーマからHTTPSを用いていることがわかる。Firefoxでは、ページ内で右クリック→ページ情報の情報を表示→「セキュリティ」タブと操作することで、より詳しい内容が表示できる。この内容から、認証局が「Google Inc」であることや、暗号化の方式が「TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256」であることがわかる。
  2. Cache-Controlヘッダ
    Firefoxでは、ツール→Web開発→ネットワークと操作することで、Webサーバとのやりとりを詳しく見ることができる。その中で、サーバからの応答の中に、「Cache-Control: "private, max-age=0"」というヘッダがあることがわかる。privateのほうは、コンテンツが複数のユーザで共有するキャッシュに記録されるべきでないことを示している。max-age=0は変更をその都度確認させるための指定だ。「Expires: "-1"」というヘッダもあり、これは「Cache-Control: "max-age=0"」と同様の記述らしいが、ブラウザによっては片方しかサポートしていないため、両方書かれているらしい。
  3. X-Frame-Optionsヘッダ
    「X-Frame-Options: "SAMEORIGIN"」というヘッダがあることから、自身と生成元が同じフレーム内に限り、ページを表示することができる。これによって、<iframe>タグなどを用いたクリックジャッキング攻撃を防止することができる。
  4. X-XSS-Protectionヘッダ
    「X-XSS-Protection: "1; mode=block"」というヘッダがあることから、IEXSSフィルターが有効になることがわかる。有効にするだけなら、「X-XSS-Protection: "1"」だけでよいのだが、mode=blockを指定することでより強固になる。過去のバージョンのIEでは、XSS Filterでブロックしたスクリプトをそのままブラウザ上で表示していた。これによって、XSS Filterを利用したXSSが生まれてしまった。現在はmode=blockがなくても、直接ソースが表示されるようなことはないようだが、過去のブラウザを利用している人も多いだろうから、mode=blockが指定されているのだと思う。

選択問題. 6

'や"など、SQLのメタ文字を入力してみる。なぜならば、IDとパスワードを入力してユーザ認証を行っているWebアプリは、大抵の場合、裏でデータベースにアクセスし、問い合わせの結果でログインの可否を判断しているからだ。もし、入力サニタイズが不十分であるなら、エラーが表示されるはずだ。そうなれば、SQLインジェクションができる可能性があり、大きな脅威となる。

選択問題. 8

まず、この逆アセンブルを眺めて気づいたのは、この逆アセンブルが大きく2つの部分に分かれることです。 0x400080...0x4000fcは、主にpushq命令で構成されていて、 0x400101...0x40012eは、主にretq命令、pop命令で構成されています。 脳内で上から順番に実行してみると、ROPのような挙動をすることがわかりました。 すなわち、0x400080...0x4000fcで戻りアドレスやレジスタにセットする値をスタック上にpushしておき、 0x400101...0x40012eでretqをjmp、popをmovのように使用しています。 したがって、これはROPを応用し、難読化が施されたバイナリの逆アセンブルであることがわかりました。 若干読みにくいので、手動で難読化を解除してみることにしました。

mov $0x0,%rax
mov $0x0,%rdi
mov %rsp,%rsi
mov $0x0,%r10
mov $0x8,%rdx
syscall ;read(STDIN,%rsi,0x8,0)
mov $0xffffffffffffffe0,%rbp
mov $0x7,%rcx
xorb $0x55,(%rsi,%rcx,1) ;-> 標準入力から受け取った文字列の最後の文字と0x55のXORをとっている。
; decが0x7->0x0までループする
dec %rcx
xorb $0x55,(%rsi,%rcx,1)
; ループここまで
mov $0x0,%rdi
movabs $0x63391a67251b1536,%rax
cmp %rax,(%rsi)
mov 0x3c,%rax
(jne $0x40012c ;もし入力のすべての文字を0x55とXORした結果が$0x63391a67251b1536と一致しないなら)
(syscall ;一致した時の処理, exit(0))
mov $0x1,%rdi
syscall ;exit(1)

若干不整合がある気がしますが…

  1. 基本的には、標準入力から8文字受け取り
  2. すべての文字を0x55とXORをとった結果に変更し、
  3. 0x63391a67251b1536と比較する(リトルエンディアンなことに注意する)
  4. 一致していれば、exit(0)、していなければexit(1)

というプログラムのようです。 すなわち、"c@Np2Ol6"という入力であれば、正常終了するプログラムであるということがわかりました。 (Pythonインタプリタで、0x63391a67251b1536をpackして、listにして、mapして...として求めました。

xorb $0x55,(%rsi,%rcx,1)がどういう処理をするのか、最初わかりませんでしたが、 rasm2を用いてintel記法にしてみると、xor byte [rsi + rcx], 0x55となり、理解できました。

正直、ループのところはあまりちゃんと読んでいないのですが、decとjneがあることから、%rcxが0まで回るループだろうなと断定して読み進めた結果、それらしい感じになりました。

CTFのような問題で、非常に楽しめました。個人的には一番好きな設問です。


提出前の僕


その後

来年も一応応募資格はあるけれど、これで3回落ちているし最早受かる気がしないので迷っている。