2025/7/26-27に開催されたSECCON Beginners CTF 2025に、チームHashMistressとして8人で参加、18問を解いて126位という成績でした。
私はrev+αを担当し、rev全問を答えたのでそのwriteupを公開します。
今年は全体的に易化傾向で初学者が取り組みやすい問題が多かったのではないかと思います。
revも例外なく易しい問題が多かったのですが、しっかり勉強になる問題が解けたので非常に良かったですね。
運営の方々、今年も楽しいCTFをありがとうございました。
CrazyLazyProgram1 (100pt / 654 solves)
改行が面倒だったのでワンライナーにしてみました。
C#のワンライナーのコードが渡される。途中に
if(flag[0]==0x63&&flag[1]==0x74&&flag[2]==0x66&&...
というflagの照合部分があるので、これを順番に復号すればflagになる。
ちなみにvscodeにコピーして正規表現で
&&flag\[\d{1,2}\]==
で置き換えてcyberchefでデコードすると一発で出てくるので便利。
CrazyLazyProgram2 (100pt / 468 solves)
コーディングが面倒だったので機械語で作ってみました
exeが渡される。IDAfreeで開くと分岐分岐分岐で読みづらかったのでghidraで開いてみる。
if (((((((((local_38 == 'c') && (local_c = 1, cStack_37 == 't')) &&
(local_c = 2, cStack_36 == 'f')) &&
(((local_c = 3, cStack_35 == '4' && (local_c = 4, cStack_34 == 'b')) &&
((local_c = 5, cStack_33 == '{' &&
((local_c = 6, cStack_32 == 'G' && (local_c = 7, cStack_31 == 'O')))))))) &&
(local_c = 8, cStack_30 == 'T')) &&
(((((local_c = 9, cStack_2f == 'O' && (local_c = 10, cStack_2e == '_')) &&
(local_c = 0xb, cStack_2d == 'G')) &&
((local_c = 0xc, cStack_2c == '0' && (local_c = 0xd, cStack_2b == 'T')))) &&
(local_c = 0xe, cStack_2a == '0')))) &&
(((local_c = 0xf, cStack_29 == '_' && (local_c = 0x10, cStack_28 == '9')) &&
(((local_c = 0x11, cStack_27 == '0' &&
(((local_c = 0x12, cStack_26 == 't' && (local_c = 0x13, cStack_25 == '0')) &&
(local_c = 0x14, cStack_24 == '_')))) &&
(((local_c = 0x15, cStack_23 == 'N' && (local_c = 0x16, cStack_22 == '0')) &&
(local_c = 0x17, cStack_21 == 'm')))))))) &&
(((local_c = 0x18, cStack_20 == '0' && (local_c = 0x19, cStack_1f == 'r')) &&
((local_c = 0x1a, cStack_1e == '3' &&
(((local_c = 0x1b, cStack_1d == '_' && (local_c = 0x1c, cStack_1c == '9')) &&
(local_c = 0x1d, cStack_1b == '0')))))))) &&
(((local_c = 0x1e, cStack_1a == 't' && (local_c = 0x1f, cStack_19 == '0')) &&
(local_c = 0x20, cStack_18 == '}')))) {
puts("Flag is correct!");
}
return;
1と同じように順番に拾っていけばflag。
D-compile (100pt / 335 solves)
C言語の次はこれ!
This is the next trending programming language!
※一部環境ではlibgphobos5が必要となります。 また必要に応じてecho -nをご利用ください。
Note:In some environments, libgphobos5 is required. Also, use the echo -n command as necessary.
おそらくD言語で書いてコンパイルされたexeファイルが渡される。
これもghidraで開いて
puVar2 = (undefined8 *)_d_arrayliteralTX(&_D11TypeInfo_Aa6__initZ,0x20);
*puVar2 = 0x334e7b6234667463;
puVar2[1] = 0x646e3372545f7478;
puVar2[2] = 0x75396e61315f445f;
puVar2[3] = 0x7d3130315f336761;
の部分にリトルエンディアンで入っているのでcyberchefでreverseしたりして戻す。
一部、「ghidraだとうまく読めない」という話を聞きましたが読めましたね。ver10.3です。なんだろう。
wasm_S_exp (100pt / 330 solves)
フラグをチェックしてくれるプログラム
wasmだ!ブラウザで実行できるバイナリみたいなやつ。
関数check_flagでフラグのチェックをしている。
i32.const 0x7b
i32.const 38
call $stir
i32.load8_u
i32.ne
if
i32.const 0
return
end
それぞれスタックに数字を2つずつ積みつつ、stir関数
(func $stir (param $x i32) (result i32)
i32.const 1024
i32.const 23
i32.const 37
local.get $x
i32.const 0x5a5a
i32.xor
i32.mul
i32.add
i32.const 101
i32.rem_u
i32.add
return
)
を呼び出すことで2番目に積んだ数字を$xとしてpopして計算したのち返す。
メモリの文字列(インプットしたフラグ)の該当箇所をloadして、スタックからpopした数字(最初に積んだ16進数のこと)と照合。間違っていれば0を返すという処理を繰り返している。要は最初に積んだ16進数がフラグの文字列、2番目に積んだ数字を計算するとindexが出てくる。
stackからpopしつつ計算していくので、0x5a5aとのxorをとる→37かける→23足す→101で剰余とる→1024足すの順番。1024はメモリ上の場所を考慮したものなので、単純にインデックスが欲しければ(23 + 37 * (i ^ 0x5a5a)) % 101で良い。
str_lis = [0x7b,0x67,0x5f,0x21,0x63,0x6e,0x5f,0x79,0x34,0x57,0x35,0x33,0x62,0x63,0x7d,0x30,0x74,0x31,0x66,0x34,0x34,0x54,0x5f,0x6c,0x41]
ind_lis =[38,20,46,3,18,119,51,59,9,4,37,12,111,45,97,54,112,106,43,17,98,120,25,127,26]
ind =[]
for i in ind_lis:
a = (23 + 37 * (i ^ 0x5a5a)) % 101
ind.append(a)
ans = ""
for i in range(25):
a = ind.index(i)
ans += chr(str_lis[a])
print(ans)
煩雑なコードですみません。
MAFC (339pt / 144 solves)
flagが欲しいかい?ならこのマルウェアを解析してみな。
Wanna get flag? if so, Reversing this Malware if you can
flag.encryptedという0x40bytesの暗号化されたフラグと暗号化に用いたであろうexeファイルが渡される。IDAfreeで見てみると、flag.txtというファイルを読み込み、flag.encryptedを出力することが分かる。
分岐を追いかけていくと、 Wincryptを使って暗号化を行っていることが分かる。

WindowsAPIを多用するexeは、IDAfreeで見ると既知のAPIならどれが何のパラメータか教えてくれるので便利。ここではAlgidが0x800Cであることが分かる。microsoftのページでALG_IDを確認すると、
CALG_SHA_256 0x0000800c 256 ビット SHA ハッシュ アルゴリズム。 このアルゴリズムは、Microsoft Enhanced RSA および AES 暗号化プロバイダーによってサポートされています。
というわけでSHA256を使っていることが分かった。さらに分岐を追っていくと、xmm0レジスタに入った"ThisIsTheEncryptKey"というwordがスタックに積まれていくことが分かる。文字通りこれがKeyだと思われる。さらに進めると、

CryptDeriveKeyを呼び出す。同じくAlgidが設定されており、0x6610で調べると
CALG_AES_256 0x00006610 256 ビット AES。 このアルゴリズムは、 Microsoft AES 暗号化プロバイダーによってサポートされています。
ということでAESが使われていることが分かる。さらに進めていくと、

CryptSetKeyParamでpbDataを設定している。microsoftのページを見ると初期化バッファーへのポインターとなっており、IVだと分かる。よってIVはUTF-16LEのIVCanObfuscation。以上のキーのsha256とIVで元のflag.encryptedをCBCモードで復号するとフラグになる。
ちなみにUTF-16LEにするには、cyberchefに張り付けてinput部分の右下のRawBytesのところを変更すると早い。
この問題はかなり好きだった。実際にCTF以外でexeを読むときにはこのWindowsAPIのパラメータから何をやっているか探るのをよくやっている。
code_injection (441pt / 88 solves)
ある条件のときにフラグが表示されるみたい。
powershellのスクリプト実行ファイルとsh.txtなるuuidっぽいものがいっぱいつまったテキストファイルが渡される。なんじゃこりゃ。
add-type '
using System;
using System.Runtime.InteropServices;
[StructLayout( LayoutKind.Sequential )]
public static class kernel32{
[DllImport( "kernel32.dll" )]
public static extern IntPtr VirtualAlloc( IntPtr address, int size, int AllocType, int protect );
[DllImport( "kernel32.dll" )]
public static extern bool EnumSystemLocalesA( IntPtr buf, uint flags );
}
public static class Rpcrt4{
[DllImport( "rpcrt4.dll" )]
public static extern void UuidFromStringA( string uuid, IntPtr buf );
}';
$workdir = ( Get-Location ).Path;
[System.IO.Directory]::SetCurrentDirectory( $workdir );
$lines = [System.IO.File]::ReadAllLines( ".\sh.txt" );
$buf = [kernel32]::VirtualAlloc( [IntPtr]::Zero, $lines.Length * 16, 0x1000, 0x40 );
$proc = $buf;
foreach( $line in $lines ){
$tmp = [Rpcrt4]::UuidFromStringA( $line, $buf );
$buf = [IntPtr]( $buf.ToInt64() + 16 )
}
$tmp = [kernel32]::EnumSystemLocalesA( $proc, 0 );
動かしてみたが何も表示されない。
見たところsh.txtの文字列からUUIDを取り出してこれをバッファに詰め込んでいるっぽい。UuidFromStringAで検索してみると、UUIDを使ったシェルコード実行の記事を見つけた。へえー
powershell上で生のバイナリを動かせるという話は聞いたことがあったのだが、この攻撃方法ははじめまして。面白い。
というわけで、sh.txtが本体みたいなのでなんとかして取り出したい。後半を少し書き換えて
add-type '
using System;
using System.Runtime.InteropServices;
[StructLayout( LayoutKind.Sequential )]
public static class Kernel32{
[DllImport( "kernel32.dll" )]
public static extern IntPtr VirtualAlloc( IntPtr address, int size, int AllocType, int protect );
}
public static class Rpcrt4{
[DllImport( "rpcrt4.dll" )]
public static extern void UuidFromStringA( string uuid, IntPtr buf );
}'
$workdir = ( Get-Location ).Path
[System.IO.Directory]::SetCurrentDirectory( $workdir )
$lines = [System.IO.File]::ReadAllLines( ".\sh.txt" )
$bufSize = $lines.Length * 16
$buf = [Kernel32]::VirtualAlloc( [IntPtr]::Zero, $bufSize, 0x1000, 0x40 )
$ptr = $buf
foreach( $line in $lines ){
[Rpcrt4]::UuidFromStringA( $line, $ptr )
$ptr = [IntPtr]( $ptr.ToInt64() + 16 )
}
$data = New-Object byte[] $bufSize
[Runtime.InteropServices.Marshal]::Copy($buf, $data, 0, $bufSize)
[System.IO.File]::WriteAllBytes("shellcode.bin", $data)
これでシェルコード自体を取り出す。取り出したシェルコードはバイナリなので、
ndisasm -b 32 shellcode.bin
でnasmを使ってアセンブラにしてみる。
00000000 53 push ebx
00000001 51 push ecx
00000002 52 push edx
00000003 56 push esi
00000004 57 push edi
00000005 41 inc ecx
00000006 50 push eax
00000007 41 inc ecx
00000008 51 push ecx
00000009 55 push ebp
0000000A 48 dec eax
0000000B 89E5 mov ebp,esp
0000000D 48 dec eax
0000000E 83E4F0 and esp,byte -0x10
00000011 48 dec eax
00000012 83EC30 sub esp,byte +0x30
00000015 6548 gs dec eax
00000017 8B042560000000 mov eax,[0x60]
0000001E 48 dec eax
0000001F 8B4020 mov eax,[eax+0x20]
00000022 48 dec eax
00000023 8BB080000000 mov esi,[eax+0x80]
00000029 833E00 cmp dword [esi],byte +0x0
0000002C 0F84A7010000 jz near 0x1d9
00000032 813E43005400 cmp dword [esi],0x540043
00000038 7526 jnz 0x60
0000003A 817E0446003400 cmp dword [esi+0x4],0x340046
00000041 751D jnz 0x60
00000043 817E0842003D00 cmp dword [esi+0x8],0x3d0042
0000004A 7514 jnz 0x60
0000004C 837E0C31 cmp dword [esi+0xc],byte +0x31
00000050 750E jnz 0x60
00000052 48 dec eax
00000053 8B1E mov ebx,[esi]
00000055 48 dec eax
00000056 C1E308 shl ebx,byte 0x8
00000059 48 dec eax
0000005A 895C2420 mov [esp+0x20],ebx
0000005E EB06 jmp short 0x66
00000060 48 dec eax
00000061 83C602 add esi,byte +0x2
00000064 EBC3 jmp short 0x29
00000066 6548 gs dec eax
00000068 8B042560000000 mov eax,[0x60]
0000006F 48 dec eax
00000070 8B4018 mov eax,[eax+0x18]
00000073 48 dec eax
00000074 8B4020 mov eax,[eax+0x20]
00000077 48 dec eax
00000078 8B00 mov eax,[eax]
0000007A 48 dec eax
0000007B 8B7850 mov edi,[eax+0x50]
0000007E 48 dec eax
0000007F 8B1F mov ebx,[edi]
00000081 48 dec eax
00000082 B920002000 mov ecx,0x200020
00000087 2000 and [eax],al
00000089 2000 and [eax],al
0000008B 48 dec eax
0000008C 09CB or ebx,ecx
0000008E 48 dec eax
0000008F C1E308 shl ebx,byte 0x8
00000092 48 dec eax
00000093 335C2420 xor ebx,[esp+0x20]
00000097 48 dec eax
00000098 8B00 mov eax,[eax]
0000009A 48 dec eax
0000009B 8B7850 mov edi,[eax+0x50]
0000009E 48 dec eax
0000009F 031F add ebx,[edi]
000000A1 48 dec eax
000000A2 B920002000 mov ecx,0x200020
000000A7 2000 and [eax],al
000000A9 2000 and [eax],al
000000AB 48 dec eax
000000AC 09CB or ebx,ecx
000000AE 48 dec eax
000000AF 895C2420 mov [esp+0x20],ebx
000000B3 48 dec eax
000000B4 8B5820 mov ebx,[eax+0x20]
000000B7 8B433C mov eax,[ebx+0x3c]
000000BA 48 dec eax
000000BB 01D8 add eax,ebx
000000BD 8BB888000000 mov edi,[eax+0x88]
000000C3 48 dec eax
000000C4 01DF add edi,ebx
000000C6 8B7720 mov esi,[edi+0x20]
000000C9 48 dec eax
000000CA 01DE add esi,ebx
000000CC 48 dec eax
000000CD BA0540564E mov edx,0x4e564005
000000D2 45 inc ebp
000000D3 7D08 jnl 0xdd
000000D5 2A4889 sub cl,[eax-0x77]
000000D8 54 push esp
000000D9 2410 and al,0x10
000000DB 48 dec eax
000000DC 31C9 xor ecx,ecx
000000DE 8B148E mov edx,[esi+ecx*4]
000000E1 48 dec eax
000000E2 01DA add edx,ebx
000000E4 813A47657453 cmp dword [edx],0x53746547
000000EA 7514 jnz 0x100
000000EC 817A0474644861 cmp dword [edx+0x4],0x61486474
000000F3 750B jnz 0x100
000000F5 817A086E646C65 cmp dword [edx+0x8],0x656c646e
000000FC 7502 jnz 0x100
000000FE EB05 jmp short 0x105
00000100 48 dec eax
00000101 FFC1 inc ecx
00000103 EBD9 jmp short 0xde
00000105 8B7724 mov esi,[edi+0x24]
00000108 48 dec eax
00000109 01DE add esi,ebx
0000010B 668B0C4E mov cx,[esi+ecx*2]
0000010F 8B771C mov esi,[edi+0x1c]
00000112 48 dec eax
00000113 01DE add esi,ebx
00000115 8B048E mov eax,[esi+ecx*4]
00000118 48 dec eax
00000119 01D8 add eax,ebx
0000011B 48 dec eax
0000011C BA5B403A50 mov edx,0x503a405b
00000121 41 inc ecx
00000122 40 inc eax
00000123 135248 adc edx,[edx+0x48]
00000126 89542418 mov [esp+0x18],edx
0000012A B9F5FFFFFF mov ecx,0xfffffff5
0000012F FFD0 call eax
00000131 49 dec ecx
00000132 89C0 mov eax,eax
00000134 48 dec eax
00000135 BA08590314 mov edx,0x14035908
0000013A 105909 adc [ecx+0x9],bl
0000013D 6B488914 imul ecx,[eax-0x77],byte +0x14
00000141 248B and al,0x8b
00000143 7720 ja 0x165
00000145 48 dec eax
00000146 01DE add esi,ebx
00000148 48 dec eax
00000149 31C9 xor ecx,ecx
0000014B 8B148E mov edx,[esi+ecx*4]
0000014E 48 dec eax
0000014F 01DA add edx,ebx
00000151 813A57726974 cmp dword [edx],0x74697257
00000157 7514 jnz 0x16d
00000159 817A0465436F6E cmp dword [edx+0x4],0x6e6f4365
00000160 750B jnz 0x16d
00000162 817A08736F6C65 cmp dword [edx+0x8],0x656c6f73
00000169 7502 jnz 0x16d
0000016B EB05 jmp short 0x172
0000016D 48 dec eax
0000016E FFC1 inc ecx
00000170 EBD9 jmp short 0x14b
00000172 8B7724 mov esi,[edi+0x24]
00000175 48 dec eax
00000176 01DE add esi,ebx
00000178 668B0C4E mov cx,[esi+ecx*2]
0000017C 48 dec eax
0000017D BA1F72564E mov edx,0x4e56721f
00000182 0413 add al,0x13
00000184 1C68 sbb al,0x68
00000186 48 dec eax
00000187 89542408 mov [esp+0x8],edx
0000018B 8B771C mov esi,[edi+0x1c]
0000018E 48 dec eax
0000018F 01DE add esi,ebx
00000191 8B048E mov eax,[esi+ecx*4]
00000194 48 dec eax
00000195 01D8 add eax,ebx
00000197 48 dec eax
00000198 83EC30 sub esp,byte +0x30
0000019B 48 dec eax
0000019C 8D542430 lea edx,[esp+0x30]
000001A0 48 dec eax
000001A1 31C9 xor ecx,ecx
000001A3 48 dec eax
000001A4 83F904 cmp ecx,byte +0x4
000001A7 7412 jz 0x1bb
000001A9 4C dec esp
000001AA 8B4C2450 mov ecx,[esp+0x50]
000001AE 4C dec esp
000001AF 330CCA xor ecx,[edx+ecx*8]
000001B2 4C dec esp
000001B3 890CCA mov [edx+ecx*8],ecx
000001B6 48 dec eax
000001B7 FFC1 inc ecx
000001B9 EBE8 jmp short 0x1a3
000001BB 4C dec esp
000001BC 89C1 mov ecx,eax
000001BE 49 dec ecx
000001BF C7C020000000 mov eax,0x20
000001C5 4D dec ebp
000001C6 31C9 xor ecx,ecx
000001C8 48 dec eax
000001C9 C744242000000000 mov dword [esp+0x20],0x0
000001D1 FFD0 call eax
000001D3 48 dec eax
000001D4 83C430 add esp,byte +0x30
000001D7 EB00 jmp short 0x1d9
000001D9 48 dec eax
000001DA 31C0 xor eax,eax
000001DC 48 dec eax
000001DD 89EC mov esp,ebp
000001DF 5D pop ebp
000001E0 41 inc ecx
000001E1 59 pop ecx
000001E2 41 inc ecx
000001E3 58 pop eax
000001E4 5F pop edi
000001E5 5E pop esi
000001E6 5A pop edx
000001E7 59 pop ecx
000001E8 5B pop ebx
000001E9 C3 ret
000001EA 0000 add [eax],al
000001EC 0000 add [eax],al
000001EE 0000 add [eax],al
こんな感じ。
追記
このwriteupをXに投稿したところ、Tanさん(@Tan90909090)からご指摘をいただきまして、64bitのシェルコードを間違えて32bitで逆アセンブルしていたことが分かりました。
わァ……ぁ……
ndisasm -b 64 shellcode.bin
正確にはこう
00000000 53 push rbx
00000001 51 push rcx
00000002 52 push rdx
00000003 56 push rsi
00000004 57 push rdi
00000005 4150 push r8
00000007 4151 push r9
00000009 55 push rbp
0000000A 4889E5 mov rbp,rsp
0000000D 4883E4F0 and rsp,byte -0x10
00000011 4883EC30 sub rsp,byte +0x30
00000015 65488B0425600000 mov rax,[gs:0x60]
-00
0000001E 488B4020 mov rax,[rax+0x20]
00000022 488BB080000000 mov rsi,[rax+0x80]
00000029 833E00 cmp dword [rsi],byte +0x0
0000002C 0F84A7010000 jz near 0x1d9
00000032 813E43005400 cmp dword [rsi],0x540043
00000038 7526 jnz 0x60
0000003A 817E0446003400 cmp dword [rsi+0x4],0x340046
00000041 751D jnz 0x60
00000043 817E0842003D00 cmp dword [rsi+0x8],0x3d0042
0000004A 7514 jnz 0x60
0000004C 837E0C31 cmp dword [rsi+0xc],byte +0x31
00000050 750E jnz 0x60
00000052 488B1E mov rbx,[rsi]
00000055 48C1E308 shl rbx,byte 0x8
00000059 48895C2420 mov [rsp+0x20],rbx
0000005E EB06 jmp short 0x66
00000060 4883C602 add rsi,byte +0x2
00000064 EBC3 jmp short 0x29
00000066 65488B0425600000 mov rax,[gs:0x60]
-00
0000006F 488B4018 mov rax,[rax+0x18]
00000073 488B4020 mov rax,[rax+0x20]
00000077 488B00 mov rax,[rax]
0000007A 488B7850 mov rdi,[rax+0x50]
0000007E 488B1F mov rbx,[rdi]
00000081 48B9200020002000 mov rcx,0x20002000200020
-2000
0000008B 4809CB or rbx,rcx
0000008E 48C1E308 shl rbx,byte 0x8
00000092 48335C2420 xor rbx,[rsp+0x20]
00000097 488B00 mov rax,[rax]
0000009A 488B7850 mov rdi,[rax+0x50]
0000009E 48031F add rbx,[rdi]
000000A1 48B9200020002000 mov rcx,0x20002000200020
-2000
000000AB 4809CB or rbx,rcx
000000AE 48895C2420 mov [rsp+0x20],rbx
000000B3 488B5820 mov rbx,[rax+0x20]
000000B7 8B433C mov eax,[rbx+0x3c]
000000BA 4801D8 add rax,rbx
000000BD 8BB888000000 mov edi,[rax+0x88]
000000C3 4801DF add rdi,rbx
000000C6 8B7720 mov esi,[rdi+0x20]
000000C9 4801DE add rsi,rbx
000000CC 48BA0540564E457D mov rdx,0x2a087d454e564005
-082A
000000D6 4889542410 mov [rsp+0x10],rdx
000000DB 4831C9 xor rcx,rcx
000000DE 8B148E mov edx,[rsi+rcx*4]
000000E1 4801DA add rdx,rbx
000000E4 813A47657453 cmp dword [rdx],0x53746547
000000EA 7514 jnz 0x100
000000EC 817A0474644861 cmp dword [rdx+0x4],0x61486474
000000F3 750B jnz 0x100
000000F5 817A086E646C65 cmp dword [rdx+0x8],0x656c646e
000000FC 7502 jnz 0x100
000000FE EB05 jmp short 0x105
00000100 48FFC1 inc rcx
00000103 EBD9 jmp short 0xde
00000105 8B7724 mov esi,[rdi+0x24]
00000108 4801DE add rsi,rbx
0000010B 668B0C4E mov cx,[rsi+rcx*2]
0000010F 8B771C mov esi,[rdi+0x1c]
00000112 4801DE add rsi,rbx
00000115 8B048E mov eax,[rsi+rcx*4]
00000118 4801D8 add rax,rbx
0000011B 48BA5B403A504140 mov rdx,0x52134041503a405b
-1352
00000125 4889542418 mov [rsp+0x18],rdx
0000012A B9F5FFFFFF mov ecx,0xfffffff5
0000012F FFD0 call rax
00000131 4989C0 mov r8,rax
00000134 48BA085903141059 mov rdx,0x6b09591014035908
-096B
0000013E 48891424 mov [rsp],rdx
00000142 8B7720 mov esi,[rdi+0x20]
00000145 4801DE add rsi,rbx
00000148 4831C9 xor rcx,rcx
0000014B 8B148E mov edx,[rsi+rcx*4]
0000014E 4801DA add rdx,rbx
00000151 813A57726974 cmp dword [rdx],0x74697257
00000157 7514 jnz 0x16d
00000159 817A0465436F6E cmp dword [rdx+0x4],0x6e6f4365
00000160 750B jnz 0x16d
00000162 817A08736F6C65 cmp dword [rdx+0x8],0x656c6f73
00000169 7502 jnz 0x16d
0000016B EB05 jmp short 0x172
0000016D 48FFC1 inc rcx
00000170 EBD9 jmp short 0x14b
00000172 8B7724 mov esi,[rdi+0x24]
00000175 4801DE add rsi,rbx
00000178 668B0C4E mov cx,[rsi+rcx*2]
0000017C 48BA1F72564E0413 mov rdx,0x681c13044e56721f
-1C68
00000186 4889542408 mov [rsp+0x8],rdx
0000018B 8B771C mov esi,[rdi+0x1c]
0000018E 4801DE add rsi,rbx
00000191 8B048E mov eax,[rsi+rcx*4]
00000194 4801D8 add rax,rbx
00000197 4883EC30 sub rsp,byte +0x30
0000019B 488D542430 lea rdx,[rsp+0x30]
000001A0 4831C9 xor rcx,rcx
000001A3 4883F904 cmp rcx,byte +0x4
000001A7 7412 jz 0x1bb
000001A9 4C8B4C2450 mov r9,[rsp+0x50]
000001AE 4C330CCA xor r9,[rdx+rcx*8]
000001B2 4C890CCA mov [rdx+rcx*8],r9
000001B6 48FFC1 inc rcx
000001B9 EBE8 jmp short 0x1a3
000001BB 4C89C1 mov rcx,r8
000001BE 49C7C020000000 mov r8,0x20
000001C5 4D31C9 xor r9,r9
000001C8 48C7442420000000 mov qword [rsp+0x20],0x0
-00
000001D1 FFD0 call rax
000001D3 4883C430 add rsp,byte +0x30
000001D7 EB00 jmp short 0x1d9
000001D9 4831C0 xor rax,rax
000001DC 4889EC mov rsp,rbp
000001DF 5D pop rbp
000001E0 4159 pop r9
000001E2 4158 pop r8
000001E4 5F pop rdi
000001E5 5E pop rsi
000001E6 5A pop rdx
000001E7 59 pop rcx
000001E8 5B pop rbx
000001E9 C3 ret
000001EA 0000 add [rax],al
000001EC 0000 add [rax],al
000001EE 0000 add [rax],al
(Q.powershellにx64dbgをアタッチした時点で気が付きませんでしたか?
A.本職の不徳の致すところです)
わりと読めそうな感じがするので少し気が付きづらいのですが、32bitで読んだときにincやdecが多い傾向だと誤読の可能性が高いそうです。
参考文献を教えていただいたので情報共有いたします。x86_64 機械語入門
4?が命令の前にいると64bitの演算になるんですね。48っていう単独の命令いっぱいあるなとは思ったんですよ。
追記終わり。
00000032 813E43005400 cmp dword [esi],0x540043
00000038 7526 jnz 0x60
0000003A 817E0446003400 cmp dword [esi+0x4],0x340046
00000041 751D jnz 0x60
00000043 817E0842003D00 cmp dword [esi+0x8],0x3d0042
0000004A 7514 jnz 0x60
0000004C 837E0C31 cmp dword [esi+0xc],byte +0x31
00000050 750E jnz 0x60
この辺でおそらくUTF-16のCTF4B=1と何かを比較して、合っていれば出力みたいな処理に分岐させている。
とりあえずsh.txtの該当部分を丸々NOP(90)で埋めてみて再度実行。
\code_injection> .\ps_z.ps1
ctf4bhgUt_3nv"rVnm3n7Lf0m_p3q}l
なんか惜しいな。
とりあえずここの比較があっていればいけそうだが、何度読んでもesiがどこから来たのか分からず、どこにCTF4B=1があれば読んでくれるのか分からない。chatGPTに丸々投げてみるが、「メモリの中にないか見ています」みたいな回答が返ってくる。
powershellにx64dbgをアタッチしながらどこを読んでいるか探すが、うまいこと見つからない。
ここで惜しかったがために分岐に合わせて綺麗にフラグを出すことにこだわりすぎて、「復号部分から計算」みたいな視野がなくなった気がする。というわけで、思いついたことをとにかく試しまくった。
1.$CTF4B = 1として変数をコードに入れる(惜しいな……)
2.echo CTF4B=1してから実行してみる
3.CTF4B=1という引数で実行してみる
4.スクリプトの名前をCTF4B=1.ps1に変更して実行してみる
5.sh.txtの名前をCTF4B=1.txtに変更して実行してみる
6.powershellの名前をCTF4B=1.exeにしてみる(思い切りよすぎ)
最終的に、
7.$env:CTF4B = "1"という環境変数をコードに入れる
これでフラグが出てきた。長かった。
今思うと惜しかったフラグの中に3nv"rVnm3n7と見えるので、もっと早くメタ読みしても良かったのでは……
というわけで、環境変数にCTF4B = "1"があるかがポイントでした。偶然当てただけで解けたとは言いづらい状況なので、もっと精進します。
