軽い感じで参加してみました。400 点で提出 930 チーム中 286 位という結果でした。

Vigenere

問題文を読んでヴィジュネル暗号についてググってプログラミングするだけ。

まずSECCON{に対応するキーの先頭7文字を求めておきます。
するとキーは少なくともVIGENER?????であることが分かります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#!/usr/bin/env perl

use strict;
use warnings;
use Digest::MD5;

my $md5 = Digest::MD5->new;

my @cipher = split(//,"LMIG}RPEDOEEWKJIQIWKJWMNDTSR}TFVUFWYOCBAJBQ");
my %dic = (
'A' => 0,
'B' => 1,
'C' => 2,
'D' => 3,
'E' => 4,
'F' => 5,
'G' => 6,
'H' => 7,
'I' => 8,
'J' => 9,
'K' => 10,
'L' => 11,
'M' => 12,
'N' => 13,
'O' => 14,
'P' => 15,
'Q' => 16,
'R' => 17,
'S' => 18,
'T' => 19,
'U' => 20,
'V' => 21,
'W' => 22,
'X' => 23,
'Y' => 24,
'Z' => 25,
'{' => 26,
'}' => 27,
);
my @key = split(//,'VIGENEREAAAA');
my @next = split(//,'BCDEFGHIJKLMNOPQRSTUVWXYZ{}A');

my %table;
my @A = split(//,'ABCDEFGHIJKLMNOPQRSTUVWXYZ{}');
$table{'A'} = \@A;
my @B = split(//,'BCDEFGHIJKLMNOPQRSTUVWXYZ{}A');
$table{'B'} = \@B;
my @C = split(//,'CDEFGHIJKLMNOPQRSTUVWXYZ{}AB');
$table{'C'} = \@C;
my @D = split(//,'DEFGHIJKLMNOPQRSTUVWXYZ{}ABC');
$table{'D'} = \@D;
my @E = split(//,'EFGHIJKLMNOPQRSTUVWXYZ{}ABCD');
$table{'E'} = \@E;
my @F = split(//,'FGHIJKLMNOPQRSTUVWXYZ{}ABCDE');
$table{'F'} = \@F;
my @G = split(//,'GHIJKLMNOPQRSTUVWXYZ{}ABCDEF');
$table{'G'} = \@G;
my @H = split(//,'HIJKLMNOPQRSTUVWXYZ{}ABCDEFG');
$table{'H'} = \@H;
my @I = split(//,'IJKLMNOPQRSTUVWXYZ{}ABCDEFGH');
$table{'I'} = \@I;
my @J = split(//,'JKLMNOPQRSTUVWXYZ{}ABCDEFGHI');
$table{'J'} = \@J;
my @K = split(//,'KLMNOPQRSTUVWXYZ{}ABCDEFGHIJ');
$table{'K'} = \@K;
my @L = split(//,'LMNOPQRSTUVWXYZ{}ABCDEFGHIJK');
$table{'L'} = \@L;
my @M = split(//,'MNOPQRSTUVWXYZ{}ABCDEFGHIJKL');
$table{'M'} = \@M;
my @N = split(//,'NOPQRSTUVWXYZ{}ABCDEFGHIJKLM');
$table{'N'} = \@N;
my @O = split(//,'OPQRSTUVWXYZ{}ABCDEFGHIJKLMN');
$table{'O'} = \@O;
my @P = split(//,'PQRSTUVWXYZ{}ABCDEFGHIJKLMNO');
$table{'P'} = \@P;
my @Q = split(//,'QRSTUVWXYZ{}ABCDEFGHIJKLMNOP');
$table{'Q'} = \@Q;
my @R = split(//,'RSTUVWXYZ{}ABCDEFGHIJKLMNOPQ');
$table{'R'} = \@R;
my @S = split(//,'STUVWXYZ{}ABCDEFGHIJKLMNOPQR');
$table{'S'} = \@S;
my @T = split(//,'TUVWXYZ{}ABCDEFGHIJKLMNOPQRS');
$table{'T'} = \@T;
my @U = split(//,'UVWXYZ{}ABCDEFGHIJKLMNOPQRST');
$table{'U'} = \@U;
my @V = split(//,'VWXYZ{}ABCDEFGHIJKLMNOPQRSTU');
$table{'V'} = \@V;
my @W = split(//,'WXYZ{}ABCDEFGHIJKLMNOPQRSTUV');
$table{'W'} = \@W;
my @X = split(//,'XYZ{}ABCDEFGHIJKLMNOPQRSTUVW');
$table{'X'} = \@X;
my @Y = split(//,'YZ{}ABCDEFGHIJKLMNOPQRSTUVWX');
$table{'Y'} = \@Y;
my @Z = split(//,'Z{}ABCDEFGHIJKLMNOPQRSTUVWXY');
$table{'Z'} = \@Z;
my @bra1 = split(//,'{}ABCDEFGHIJKLMNOPQRSTUVWXYZ');
$table{'{'} = \@bra1;
my @bra2 = split(//,'}ABCDEFGHIJKLMNOPQRSTUVWXYZ{');
$table{'}'} = \@bra2;

while(1) {
print join("", @key),"\n";
my $buf = "";
for (my $i = 0; $i < @cipher; $i++) {
my $ni = $i % 12;
my @t = @{$table{$key[$ni]}};
for (my $j = 0; $j < @t; $j++) {
if ($t[$j] eq $cipher[$i]) {
foreach (keys %dic) {
if ($dic{$_} == $j) {
$buf .= $_;
last;
}
}
last;
}
}
}
my $h = $md5->add($buf)->hexdigest;
if ($h eq 'f528a6ab914c1ecf856a1d93103948fe') {
print $buf,"\n";
exit;
}
$key[11] = $next[$dic{$key[11]}];
if ($key[11] eq 'A') {
$key[10] = $next[$dic{$key[10]}];
if ($key[10] eq 'A') {
$key[9] = $next[$dic{$key[9]}];
if ($key[9] eq 'A') {
$key[8] = $next[$dic{$key[8]}];
if ($key[8] eq 'A') {
$key[7] = $next[$dic{$key[7]}];
}
}
}
}
}

我ながら酷いコードですね。
while文の中がメインの探索部で、最初のforで復号、MD5 を取って正解チェック、違ったら次のキーへ、という処理を回しています。単純なブルートフォースです。
最初は完全に確定しているVIGENERまでを固定しておいて回したんですが、終わりそうになかったので推測でVIGENEREと埋めて回したら1分くらいですぐ見つかりました。

VoIP

とりあえず Wireshark で開いて、全パケットを結合しないといけないの?と思いながらググったところ、Wireshark に VoIP パケットを再生できる機能があることが分かりました。
電話(y)VoIP通話(V)ストリームを再生で再生できます。
これで再生はできたんですがシークする機能がないようで、自分の英語力では一発で聞き取れなくてかなり厳しかったので、Soundflower と Audacity でさくっと録音して繰り返し聴いてなんとかなりました。
DTM やっててよかった!あと英語力大事!

Memory Analysis

説明に書いてある通り、ダウンロードしたファイルを Volatility Framework に入れてごちゃごちゃします。

「Volatility Frameworkを使ったメモリフォレンジック」と言うハンズオンに参加させて頂きました。 | Developers.IO

このサイトがめちゃくちゃ参考になりました。

まずimageinfoでOSを特定し、pstreeで起動しているプロセス一覧を取得、connectionsconnscanで接続先を取得するところまでは上のサイト通りにやりました。

いまいち正確な解答がわかっていないのですが、
結局hostsを抽出し、IEの履歴を見てそのURLにhostsが適用されているものとしてアクセスする、すなわちhttp://153.127.200.178/entry/Data-Science-import-pandas-as-pdにアクセスするとフラグが取れます。
説明にWebサイトにアクセスすればフラグが取れますと追記されたのが逆に悩む元になって、crattack.tistory.com の中をくまなく探したりしてしまいました。
crattack.tistory.com のアクセスカウンタがどんどん回っているのがとにかく気になって仕方がなかったです。

$ vol.py -f forensic_100.raw --profile=WinXPSP2x86 filescan | grep hosts
Volatility Foundation Volatility Framework 2.5
0x000000000217b748 1 0 R--rw- \Device\HarddiskVolume1\WINDOWS\system32\drivers\etc\hosts
------------------------------------------------------------
$ vol.py -f forensic_100.raw --profile=WinXPSP2x86 dumpfiles -D output2/ -Q 0x000000000217b748
Volatility Foundation Volatility Framework 2.5
DataSectionObject 0x0217b748 None \Device\HarddiskVolume1\WINDOWS\system32\drivers\etc\hosts
$ vol.py -f forensic_100.raw --profile=WinXPSP2x86 iehistory
Volatility Foundation Volatility Framework 2.5
(省略)
**************************************************
Process: 380 IEXPLORE.EXE
Cache type "URL " at 0x76be00
Record length: 0x180
Location: http://crattack.tistory.com/entry/Data-Science-import-pandas-as-pd
Last modified: 2016-12-06 03:39:11 UTC+0000
Last accessed: 2016-12-06 05:28:40 UTC+0000
File Offset: 0x180, Data Offset: 0xac, Data Length: 0xd0
File: Data-Science-import-pandas-as-pd[1]
Data: HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Length: 42
ETag: "584632df-2a"

~U:system
**************************************************
(省略)

Anti-Debugging

まず手元に CPU が Atom のへっぽこ Windows マシンしかなくて解こうか迷ったんですが、他に解けそうな問題が見当たらなかったので挑戦してみました。

問題名からデバッガが必要なんだろうなと思い、とりあえず Mac だけでなんとかならないか足掻いてみようと IDA というデバッガを Wine で実行してみたんですが、なんかうまく動きそうになかったので Mac でやるのは早々に断念。

次に Windows に移動して、Immunity Debugger というデバッガで実行。

まず正しいパスワードがわからなくて困ったんですが、Mac でstringsコマンドに通してみたところ、出力されているメッセージのあたりにI have a pen.という文字列があったのでこれを入力してみたところYour password is correct.となったのでパスワードを発見。
そのついでに、あきらかに何かしらの暗号化が施されている文字列;aj&@:JQ7HBOt[h?U8aCBk]OaI38"が見え、これをどうにかしたら復号できるんじゃないかとも思いましたが、まじめにアンチデバッギングを一つ一つ処理しました。

しかし、CheckRemoteDebuggerPresentをスキップさせるために試行錯誤しているあたりで、アンチデバッギング対策なんてチートの必須技術なんだから何かツールがあるんじゃないかと思いググったところ ScyllaHide というツールを発見。
ScyllaHide は、OllyDbg などで動作するプラグインで各種アンチデバッギングに自動で対応してくれる優れものです。
OllyDbg に移ってこれを使ってみたところ一通りアンチデバッギングを回避はできているようなんですが、なぜか途中で変なところにジャンプしてしまい、ここで結構悩みました。
ふと、最初のIsDebuggerPresentのところにブレークポイントを置きステップ実行していったところ、途中で無条件に CALL し飛んでいったっきり帰ってこないようになっていることに気づきました。
つまり、0x00401590CALL命令が諸悪の根源であるということに気づき、なのでとりあえずその命令をNOP命令に置き換えてみたところ、少し下の別のところで引っかかるので、JMPで怪しい文字列の直前である0x00401663にジャンプするように置き換え直して、メッセージダイアログが表示されフラグを取ることができました。

00401590   CALL bin.00401240    ; を
00401590 JMP bin.00401663 ; に変更

OllyDbg なら該当の命令を右クリック→AssembleJMP 00401663と入力→Assembleとすればできます。

感想

とりあえず多くの人が解けている問題を全部解けたので満足です。
cheer msgとか200点の問題を解けるともうちょっと楽しめそうなのでいろいろやろうと思います。