2014年12月7日日曜日

SECCON 2014 オンライン予選 Writeup

2014/12/6 〜 2014/12/7 で、日本最大のCTFイベントであるSECCON 2014 オンライン予選が
開催されました。

私も自宅から参加させて頂きました。

私が解けた問題の1つについて、僭越ながらWriteupを書かせて頂きます。


Choose the number

Genre Programming
Points 100
Question text 
nc number.quals.seccon.jp 31337

sorry fixed URL
こちらのジャンル「Programming」、ポイント「100点」の問題です。

問題文で提示されたソケットに対してncでアクセスすると、下記の応答があります。

$ nc number.quals.seccon.jp 31337
0, 6
The minimum number? 
Timeout, bye.
$ nc number.quals.seccon.jp 31337
5, 1
The minimum number? 5
Wrong, bye.
$ nc number.quals.seccon.jp 31337
9, 8
The minimum number? 8
-3, -2, 6
The maximum number? 6
0, 5, 7, 0
The maximum number? 7
1, 9, 5, 2, -7
The maximum number? 9
9, 7, -9, 7, -9, 3
The maximum number? 9
0, -1, 8, -2, -5, -6, -7
The maximum number? 8
3, 6, 6, -6, -3, 8, 5, -4
The maximum number? 8
-3, -8, -4, 1, 5, 8, 3, 2, -8
The maximum number? 8
98, 63, 3, -37, 35, -85, 47, 44, 73, -94
The maximum number? 98
-99, 56, 9, -36, -70, 97, -8, -76, -46, 14, -39
The minimum number? -99
-49, 17, 14, -62, -48, 31, 59, -57, 60, 9, 18, -11
The minimum number? -57
Wrong, bye.
提示された数列の中から、最大値もしくは最小値を連続で答えさせる問題です。
手動で進めていくと、だんだんタイムアウトが厳しくなるようで、人間の判断、入力速度では
どうしても最後まで進めない感じでした。

ジャンルは「Programming」であることから、自動的に正解値を送り続けるプログラムを組んで
やれば良いのだと想定出来ます。

まずサーバから送られてくる問題の文字列の規則性を考えてみます。
1. 数列と最小値 or 最大値を聞いてくる文言の必ず2行で構成されている
2. 数列は「, 」と、カンマとスペースで区切られている
3. 数列は問題に正解する毎に数が増えていく
4. 最小値 or 最大値を聞いてくる文言は、「minimum」か「maximum」の2つしか無い
5. 最小値 or 最大値を聞いてくる文言の「minimum」か[maximum」は必ず左から2番目の箇所に存在する

以上から、問題文をParseするのは比較的容易な事が分かります。
また、Parseした結果から正解手を導くアルゴリズムも非常に単純な為、比較的解きやすい問題だと思います。

下記のコードを書いて実行することで、keyが手に入りました。

#!/usr/bin/env python
# coding=utf-8

import socket
HOST = 'number.quals.seccon.jp'
PORT = 31337

def main():
    clientsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    clientsock.connect((HOST, PORT))
    while True:
        rcvmsg = clientsock.recv(4096)
        print rcvmsg
        answer = solve(rcvmsg)
        print answer
        clientsock.sendall(answer)
    clientsock.close()


def solve(rcvmsg):
    # parse
    temp = rcvmsg.split("\n")
    str_number_list = temp[0].split(", ")
    max_or_min = temp[1].split(" ")[1]

    number_list = []
    for i in str_number_list:
        number_list.append(int(i))

    if max_or_min == "minimum":
        answer = min(number_list)
    else:
        answer = max(number_list)
    return str(answer)
    
if __name__ == "__main__":
    main()

key: SECCON{Programming is so fun!}

下記、実際にコードを実行した時の実行ログです(長いです)。

2, 8
The minimum number? 
2
5, 5, 0
The minimum number? 
0
-1, 2, 2, -4
The maximum number? 
2
8, 4, 3, -8, 9
The maximum number? 
9
8, -7, 2, -5, 1, 7
The maximum number? 
8
-3, 5, 7, 5, -6, -7, 3
The maximum number? 
7
6, 5, 2, -4, -8, 1, -7, -6
The minimum number? 
-8
4, -3, -5, -9, -5, -1, 4, 7, -9
The minimum number? 
-9
-99, -61, -81, -32, 50, 16, 75, 85, 7, -22
The minimum number? 
-99
82, 30, -28, 10, -23, -92, 27, 16, 14, -92, 78
The minimum number? 
-92
8, 56, -1, -74, -28, 43, -84, -32, -4, -56, 35, -52
The maximum number? 
56
3, 5, 26, -2, -81, 39, -53, 64, 28, 92, -83, -90, 44
The maximum number? 
92
4, 26, -50, 67, -55, 72, -72, -44, -77, -58, 75, 21, 70, 49
The maximum number? 
75
73, 12, -27, 22, 73, -12, 0, -16, 89, 66, 2, -43, -26, -2, -55
The minimum number? 
-55
-72, 5, -47, -80, 45, -3, 73, -95, -85, 58, 89, 22, 61, 60, -75, 27
The minimum number? 
-95
86, -41, -31, -30, 67, 33, 76, -14, 78, 95, 26, 88, -91, -20, 45, 51, 83
The minimum number? 
-91
-68, -47, 60, 85, 1, -17, -92, 94, -33, 47, -64, -76, 87, 21, 84, -8, -86, -14
The maximum number? 
94
18, 50, 9, 41, -26, 40, 39, -83, 7, -96, -45, 41, 47, -87, 28, -30, -70, 92, 8
The minimum number? 
-96
973, -220, -62, -952, -63, -18, 420, 121, 556, 267, -576, -421, 775, 421, 830, -70, 229, 2, 581, 839
The minimum number? 
-952
490, 742, 118, 634, -207, 181, -187, 72, 70, -932, -341, 842, -53, -520, -701, 286, 632, -333, -611, 580, 171
The maximum number? 
842
96, -215, 616, 983, 901, -547, 423, -666, 507, -852, -102, 92, -602, 613, 287, 680, 664, -43, -660, -655, -269, -733
The minimum number? 
-852

・・・略・・・

556459593, 2124483131, 2159881254, -3749776183, -2956358028, -525066711, -181583130, 804390823, 1740090484, -793541476, -771482074, 3981865877, -1781852942, 1733051694, -1229826280, -1252056066, 2302429424, -127597216, 584347400, 3201495296, 3793190324, -3792414033, 1778463825, 3285874942, -2696920906, 2556983581, 4058759995, 98217082, -2611145952, -324523284, -3921510686, 4250415544, -3727489945, -1627669983, -3852674381, 4156209840, 1684566595, -559196578, 331587419, 2164599710, 1250638363, 2661376500, -3009444945, 274000465, 3379372586, 3614523634, 4171421938, 619691208, -611617890, 1790148465, -2489245162, -1565675134, -2352506611, 1996182388, -3737895020, 4166992857, -1384468141, 3603231049, 418250494, -1170383247, -4207411230, -1371190709, -2836728233, -1687718214, -605700096, -3148453710, 1719740456, -1854546036, -3313019035, 3529400825, 3170707133, 60340683, -858105108, 2774783484, 4110192850, 908959548, -166441903, -2216610426, -2582470585, 2612317046, 2524067276, -2097902704, -3952326444, 3689731992, 1755793330, 3127603599, 162955011, 381420595, 1091122758, 4131177934, 971526781, 1344495679, -893926365, -1557417848, 457045675, -2006055280, -2434870581, 2715139040, 704942641, -1699474743, -721176381
The minimum number? 
-4207411230
Congratulations!
The flag is SECCON{Programming is so fun!}

Traceback (most recent call last):
  File "./programming_resolver.py", line 37, in 
    main()
  File "./programming_resolver.py", line 14, in main
    answer = solve(rcvmsg)
  File "./programming_resolver.py", line 28, in solve
    number_list.append(int(i))
ValueError: invalid literal for int() with base 10: 'Congratulations!'

最後にParseに失敗しているのは、サーバから飛んでくる文字列形式が異なるからで、気にしない。

一部 XSS Bonsai という問題で、Windowsが無いと問題に挑戦することすら出来ない問題があり、
私はLinuxしか手元にない為、どんな問題だったのかそれだけ見ることが出来ませんでした・・。
wine でも動作せず・・・。 CTFはプロプライエタリソフトウェアを持っていることが前提なのでしょうか・・・。

2014年12月3日水曜日

負荷の正体はなんなんだ!?定期的に重くなるLinux mint 17 (qiana)

久しぶりにブログ書きます。

私はLinux mint MATE を日常的に使っているのですが、ここ数ヶ月の間
たまに何も自分では処理をさせているつもりがないのにOS全体がもっさりと
重くなることがありました。

今までずっと原因がわからずにいたのですが、今日判明して嬉しくなってこのエントリを書いていますw

状況ですが、OS起動して数分後から突然ストレージアクセスランプが点灯しっぱなしに十数分程
なってしまい、何をするにもIO待ちになってしまいます。

ストレージアクセスランプが光っぱなしなので、IO負荷がかかっていることは容易に分かっていたのですが
じゃあ、どのプロセスがIO負荷をかけているのか?までは掴みきれていませんでした。

今回重い腰を上げて、色々調べてみましたところ、Linuxには「iotop」という素晴らしいコマンドがありました。
このコマンドを実行すると、IO負荷が高いプロセス順にtopコマンドのような出力が得られました。

で、今回判明したプロセスはこれ
「fstrim」

初めて見るコマンドですが、こいつがIOを99%奪い続けていました。
なんだろうかと調べてみると、どうやらUbuntu 14.04ベースのLinuxでは
一週間に1回、自動的にこのコマンドを定期実行するように最初から
スケジューリングされていることが判明しました。

/etc/cron.weekly/fstrim

にしっかり定義されています。

このコマンドは、WindowsでいうところのHDDのデフラグみたいなコマンドらしい。
定期的に実行することでIOパフォーマンスが劣化しないようにしてくれてる模様。

PostgreSQLのvacuum みたいなイメージかなぁ・・・。
Linuxにもこの手のコマンドあるとは知りませんでした。

なんかたまにIO負荷ががくんと十数分上がりっぱなしになって原因がわからず
困っている人の何かしらの参考になれば・・・。