SECCON CTF Online 解けなかった問題を2つほど
一つ前にSECCON CTF 2013 Online にでさせてもらいましたという記事を書いて、解けた問題(一問)だけWrite upしましたので、今回は解けなかった問題を途中まで、です。需要はないかな・・・・
自分の頭のなかでの整理と、記録のためです
拙いコードですがお暇な方は見ていってください。
SECCON 2013 CTF OnlineのWriteupまとめはこちらのブログさんが参考になると思いますので、詳しい解法が知りたい方はどうぞ つ:SECCON 2013 CTF オンライン予選のWriteupとかまとめてみた。 - piyolog
プログラミング/Crypt 500
telnet 133.242.50.48 65437 で問題サーバに接続して、 5個のシーザー暗号と、5個の換字式暗号と、 単語区切りのスペースが消されたシーザー暗号と換字式暗号、 計12個を、それぞれ10秒以内に解いてください。答えは、平文の「a」が、暗号文だと何になるかで答えてください。
フラグが3つあります。
10問目まで解けた時点で350点。11問目までで+50点。 12問目まですべて解けると、+100点で、計500点が得られます。
telnetすると暗号問題が降ってくるのでさぁといてね!って問題です。一見すると簡単そうに見えますがこれがかなり難しい。
[bash]'transposition ciphers' challenge for SECCON 2013.
by KeigoYAMAZAKI, 2013.11.06-
- Challenge 01-05 => Caesar cipher
- Challenge 06-10 => simple substitution cipher
- Challenge 11 => Caesar cipher without separators ("space" removed)
- Challenge 12 => simple substitution cipher without separators
*** Challenge 01 (of 12)
Kmbsjc::Glqryjj fyq jmrq md amkkylbq qayrrcpcb gl rfc cvrclqgmlq.
Rfgq gq y qfmpr bcqapgnrgml md rfc nspnmqc md rfc bgqrpgzsrgml.
Rfcqc ypc rfc amkkylbq rm upgrc yarsyj kcry dgjcq.
plain [a] -> cipher ?
[/bash]
こういうのが降ってくるのでときましょうという問題
タイムリミットが一問10秒と超短かったので、さすがに手動では無理と断念。
とりあえずプログラムに説かせるべく、PythonのTelnetlibを使って接続しました。
CeaserCipherのプログラムは前書いていたのを使用。
telnetlibの使い方がいまいちよくわからなかったのですが、なんとか接続して取得し、投稿まで出来るようにしました。
Challange 01-05を攻略するプログラム
[bash]
# -*- coding: utf-8 -*-
import telnetlib
from string import *
import sys
#Telnetする
HOST = "133.242.50.48"
tn = telnetlib.Telnet(HOST, 65437)
#問題文を解き終わるまでループ
while True:
arr =
msg = ""
#ceaser結果をarrに格納
def ceaser(source):
for n in range(26):
trns = translate(source, maketrans(uppercase + lowercase, uppercase[n:] + uppercase[:n] + lowercase[n:] + lowercase[:n]))
arr.append(trns)
print "> [", n,"] "
print arr[n],
tn.read_until("(of 12)")
tn.read_until("\n")
#問題文
msg = tn.read_until("plain [a]")
ceaser(msg)
msg = msg.replace('\n', '').replace('\r', '')
print msg
#bunが正しい文かどうかを調べる。正しければTrue
def isSentence(bun):
count = 0
bun = bun.replace('\n', '').replace('\r', '').split(" ")
for tango in bun:
if tango == 'in':
count = count + 1
if tango == 'is':
count = count + 1
if tango == 'a':
count = count + 1
if tango == 'the':
count = count + 1
if tango == 'of':
count = count + 1
if tango == 'and':
count = count + 1
if tango == 'this':
count = count + 1
if tango == 'was':
count = count + 1
if tango == 'from':
count = count + 1
if count >= 2:
return True
else:
return False
#正解の文の中でのAの位置を返す
def findAEX():
for bun in arr:
if isSentence(bun):
bun = bun.replace('\n', '').replace('\r', '')
return bun.find('a')
indexofA = findAEX()
if indexofA == False:
answer = ""
else:
answer = msg[int(findAEX())]
tn.read_until("cipher ? ")
tn.write(answer + '\n')
print tn.read_until("!")
[/bash]
な、何だこのコードは(呆然
関数名やら変数名やら組み方やらひどいのはご勘弁を(とりあえず動けばいいやと思って書いたので・・・)
はじめは、CeaserCipherを行い、0-26回ずらしたものを単純に表示させて、あとは目で見て確認するという方法でやってみました。ですが、この方法では10秒以内に正しい文章を見つけ、aの位置と対応する文字を見つけて入力するのは大変だったため断念。
・・・
そこで自動判別するプログラムを書いてみました。
telnet接続をし、降ってきた文章の中の問題文だけを取り出してmsgに格納。その後、CeaserCipher結果をarrに格納。arrの中から文章であると思われるものを判別(isSentence())し、その中でaが含まれていればその位置に対応する文字を取り出し、提出するという感じです。
isSentence(bun)の部分はin, is, a, the, of, and・・・・といった単語を見つけ出し、カウント。そのうち2つ以上が含まれていれば文章であると判断しました。(・・・辞書ファイル用意してforで回したほうが楽そうですね)
正答率は9.5割位でしょうか?(5回セットを何回か回すとエラーでたりします)もっと辞書増やせば正確に判別できそうな感じです。。
これを使えば、Challange 1はクリアできるようになりました。が、Challenge 06-10は、この方法では無理でした。
---
プログラムは割愛しますがChallenge06-10は、simple substitution cipher(換字式暗号)で、実行するたびにランダムに文字が置換されるというもの。ランダムに置換されるので、前の結果を使用することは無理。
方法が全くわからなかったので、とりあえず与えられる文章を書き出してみました。・・・・が、法則性など見当たらなかった。
辞書ファイルを眺めているうちに、なんとなく、一文の単語数と、単語の長さで判別すればいいのでは、と思いついたので、プログラム化。
辞書ファイルから"."までの文章を引き出し、リストに落とし込み、さらにスペースで分けて単語別にリストにしました。ついでに単語の文字数もリストにしました。↓こんな感じ・・・・
[bash]#listDict => 文字を格納
#listDictList => 文字をリスト化したもののリスト
#numlistDict => 文字数を格納
#['Valid values range from 0 to 250, where 0 means use the default value 30', .....
#[['Valid', 'values', 'range', 'from', '0', 'to', '250,', 'where', '0', 'means', 'use', 'the', 'default', 'value', '30'], ...
#[[5, 6, 5, 4, 1, 2, 4, 5, 1, 5, 3, 3, 7, 5, 2], .....
[/bash]
この辞書リストの文章の単語数と単語文字数リストが、与えられた問題文と一致すれば良さそうだなという感じで書いてました。
・・・・ここでタイムアップ。チームのメンバーさんが先にといちゃいました!さすがはやい。
その方はスペースの位置で判別したそうです。なるほど。そっちのほうがわかりやすそうだ。
プログラムも見せていただきましたがすごい。。。私のコードとは天と地の差ですね()
もっと綺麗に書けるようになりたい!
[ネットワーク100] repeat after me
followme.pcap
pcapが渡される。内容を見ると何やらtelnetしている模様。
とりあえずFollow TCP Streamしてみる。
[bash]
.nslookup 133.0xf2.010357
.ssh -p 311.37.37 follow .me@133.0xf2.010357
.repeat after me
.ls-l.. -l
.ls -l.followme$ whoami.ls-l... -l...
.ls -l
.exit
.
[/bash]
送信情報だけ抜き出すとこんな感じですnslookupで謎の数値を渡してますね・・・・
とりあえずnslookupで133.0xf2.010357に問い合わせてみると
[bash]
** server can't find 133.0xf2.010357: NXDOMAIN
[/bash]
となりますが、これは正常のようです(サーバーからの受信情報見てもそうなってるみたい)
次にsshしているようなのでとりあえずssh。・・・もちろんそのままだとエラーで怒られちゃいました。
ポートのところがおかしいみたいです。311.37.37とは一体?
何かがおかしいようなので、HEXDumpデータを読んでみました。
[bash]
0000007D 73 68 24 20 sh$
00000081 73 s
00000082 73 s
00000083 68 h
00000084 20
00000085 2d -
00000086 70 p
00000087 20
00000088 33 3
00000089 31 1
0000008A 31 1
### 0000008B 08 20 08 . .
0000008E 33 3
0000008F 37 7
### 00000090 08 20 08 . .
00000093 33 3
00000094 37 7
00000095 20
00000096 66 f
00000097 6f o
00000098 6c l
00000099 6c l
0000009A 6f o
0000009B 77 w
0000009C 20
0000009D 08 .
0000009E 6d m
0000009F 65 e
000000A0 40 @
000000A1 31 1
000000A2 33 3
000000A3 33 3
000000A4 2e .
000000A5 30 0
000000A6 78 x
000000A7 66 f
000000A8 32 2
000000A9 2e .
000000AA 30 0
000000AB 31 1
000000AC 30 0
000000AD 33 3
000000AE 35 5
000000AF 37 7
[/bash]
###の部分、-p[space]311まで打ったあと、08 20 08と入力している模様。
この部分のASCIIコードは0x08→[backspece]に当たるものです。また0x20は[space]。
ということで入力は-p[space]311[BS][Space][BS]37[BS][Space][BS]37となりますので、-p 31337。
同様に見ていくとfollow[space][BS]meとなり、@133.0xf2.010357の.は0x2eなのでそのまま.となります。
最終的にssh -p 31337 followme@133.0xf2.010357となりますので接続。
次にパスワードを聞かれるので同じような手順で読んでいくと、repaet after meと入れて[Enter]、ls -lと入れて[Enter]していますがいずれも違うパスワードの模様。
次のls -l.followme$ whoami.ls-l... -l...が正しいパスワードみたいです。
これの途中でも0x15→[NAK]、0x17→[ETB]と言う文字を送ってますが構わず突っ込む。すると認証に成功する。
・・・・はずでしたが、文字コード送信方法に手間取ってしまい、ここでタイムアップ。メンバーさんがry
バイナリをそのまま突っ込んだら解けたらしいのですが、どういうことなのでしょう?
後から解いてみたのですが、普通にテキストエディタにGoogleIME文字パレットから持ってきた制御コードもろともぶち込んで、コピペすれば行けました。ぐぬぬ・・・・
-------------
# 追記
@shiracamusさんよりこんなリプを頂きました。
https://twitter.com/shiracamus/status/429952739842334720
制御文字をそのまま突っ込むのではなく、対応するコマンドを実行した結果を送ってみてもいいみたいです
対応表はここがわかりやすいかも
- 雑多なメモ: http://d.hatena.ne.jp/miduhima/20050709
- MOVION.net ≫ [Linux]シェルでの入力操作(Ctrl-U,Ctrl-W)など:http://movion.net/2008/11/20/linux-command-line-options/
[bash]00000065 6c l
00000066 73 s
00000067 20
00000068 2d -
00000069 6c l
### 0000006A 15 .
0000006B 66 6f 6c 6c 6f 77 6d 65 24 20 followme $
00000075 77 w
00000076 68 h
00000077 6f o
00000078 61 a
00000079 6d m
0000007A 69 i
### 0000007B 17 .
0000007C 6c l
0000007D 73 s
0000007E 2d -
0000007F 6c l
00000080 7f .
00000081 7f .
00000082 2e .
00000083 20
00000084 2d -
00000085 6c l
00000086 2e .
### 00000087 02 .
### 00000088 7f .
00000089 0d 00
[/bash]
0x15(Ctrl+U)で前半を消し、0x17(Ctrl+W)で1単語(前のスペースまで)削って、0x02を入力直後に0x7fでBackSpaceしているので、
結局followme$ ls. -lになるということですかね。
なるほどこっちのほうがわかりやすい。勉強になりました
######
長くなりすぎましたのでとりあえずこのへんで。