SHA-2017 Teaser-Round Network
Website Attack write up
문제 풀이를 위한 pcap파일이 주어진다.
PCAP 은 Packet Capture 의미로 네트워크 트래픽을 캡쳐하기 위한
API 로 구성이 되어 있다. 윈도우로 포팅되어 있는 것은 WinPcap 이며, 유닉스 환경에서는 libpcap 이다. libpcap 과 winpcap 라이브러리를 이용하여 캡쳐된 패킷을 파일로 저장하거나, 저장된 패킷을 읽고 또는 다른 프로그램에서 라이브러리를 이용해 패킷파일을 분석/편집 등을 할 수 있다. 이를 이용한 대표적인 패킷 캡쳐 프로그램이 tcpdump 나 wireshark 이다.
출처 : 패킷인사이드
와이어 샤크를 이용하여 pcap을 열어보면 TCP, IPA 패킷이 저장되어 있는 것을 확인할 수 있다. IPA 패킷 내용을 확인해보면 HTTP 패킷으로 보이므로 분석의 용이성을 위해서 HTTP 패킷으로 변환하여 분석하도록 한다.
Wireshark -> Analyze -> Enabled Protocol -> GSM over IP 체크 해제
참고 URL
Data which has been sent over TCP\IP has been recognized by wireshark as “IPA” Protocol
[Malformed Packet: GSM over IP]
패킷의 흐름을 살펴보면 다음과 같다.
여기서 word의 값만 변경되는 데 총 3개의 word를 요청한다.
kl
Trad
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
각각의 word 값을 암호화된 값에 짝지어보면 다음과 같다.
kl : ce3926706794d911
Trad : f1274d671988ce151a0b
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA : e4146d4252bafb3b38212df186497a7479d5e95af4796e7573a65e6849952032e4146d4252bafb3b38212df186497a7479d5e95af4796e7573a65e6849952032e4146d4252bafb3b38212df186497a7479d5e95af4796e7573a65e6849952032e4146d4252bafb3b38212df186497a7479d5e95af4796e7573a65e6849952032e4146d4252bafb3b38212df186497a74799edb6fda5b44
여기서 문자열 수에 관련된 한 가지 규칙을 찾을 수 있다.
평문 | 평문 문자열 수 | 암호화한 문자열 수 | 문자열 수 방정식 |
---|---|---|---|
kl | 2 | 16 | 16 = 2x + y |
Trad | 4 | 20 | 20 = 4x + y |
A*146 | 146 | 302 | 302 = 146x + y |
암호화 키 재사용 시 평문 문자열로 복호화가 가능한 취약점이 있는 RC4 평문공격을 시도해보자.
RC4 알고리즘은 암호화 키를 이용하여 긴 바이트 문자열(키 스트림)을 생성한 후 긴 바이트 문자열(키 스트림)을 이용하여 일반 텍스트와 함께 암호문을 생성한다.
만약 우리가 다른 평문 문자열과 암호화한 문자열을 알고 있고 암호화 키가 동일하다면 다음과 같이 식을 세울 수 있다.
두 식을 합치면 다음과 같은 결론을 얻을 수 있다.
RC4 , Is it possible to find the key if we know the plaintext and ciphertext?
POC
targetCipher = "af7d6f4240be9a2d31252290ef5b7e797dd7fc3be66d6d6766b5375a79b84d42"
sourceCipher= "e4146d4252bafb3b38212df186497a7479d5e95af4796e7573a65e6849952032"
plainText = "4141414141414141414141414141414141414141414141414141414141414141"
result = ""
for i in range(len(targetCipher) / 2):
aa = ord(targetCipher[i*2:i*2 + 2].decode('hex'))
bb = ord(sourceCipher[i*2:i*2 + 2].decode('hex'))
cc = ord(plainText[i*2:i*2 + 2].decode('hex'))
result = result + chr(aa ^ bb ^ cc)
print result
파이썬 코드를 실행해보면 (CASE WHEN (SELECT SUBSTR(sql,1
이 출력되는 것을 확인할 수 있다.
동일한 방법으로 다른 암호문을 복호화 해보자. Wireshark의 Export Object -> HTTP
기능을 사용하면 HTTP 패킷만 따로 저장할 수 있다. 해당 기능을 이용하여 패킷을 저장한 후 파이썬 스크립트를 수행하자.
from os import listdir
fileNames = listdir("/Users/seungyonglee/ctf/sha_2017/HTTP")
for fileName in fileNames:
cipherString = fileName[23:]
result = ""
for I in range(len(cipherString) / 64 + 1):
a = cipherString[I*64:(I+1)*64]
b = "e4146d4252bafb3b38212df186497a7479d5e95af4796e7573a65e6849952032"
c = "4141414141414141414141414141414141414141414141414141414141414141"
for i in range(len(a) / 2):
aa = ord(a[i*2:i*2 + 2].decode('hex'))
bb = ord(b[i*2:i*2 + 2].decode('hex'))
cc = ord(c[i*2:i*2 + 2].decode('hex'))
result = result + chr(aa ^ bb ^ cc)
print result
실행 결과 다음과 같이 Blind SQL Injection 수행 문자열을 확인할 수 있다.
(CASE WHEN (SELECT SUBSTR(flag,5,1) FROM secret_flag LIMIT 0,1) = ‘{’ THEN stock ELSE price END
(CASE WHEN (SELECT SUBSTR(flag,5,1) FROM secret_flag LIMIT 0,1) = ‘z’ THEN stock ELSE price END
(CASE WHEN (SELECT SUBSTR(flag,5,1) FROM secret_flag LIMIT 0,1) = ‘y’ THEN stock ELSE price END
(CASE WHEN (SELECT SUBSTR(flag,5,1) FROM secret_flag LIMIT 0,1) = ‘x’ THEN stock ELSE price END
(CASE WHEN (SELECT SUBSTR(flag,5,1) FROM secret_flag LIMIT 0,1) = ‘s’ THEN stock ELSE price END
(CASE WHEN (SELECT SUBSTR(flag,5,1) FROM secret_flag LIMIT 0,1) = ‘r’ THEN stock ELSE price END
(CASE WHEN (SELECT SUBSTR(flag,5,1) FROM secret_flag LIMIT 0,1) = ‘q’ THEN stock ELSE price END
…
공격에 성공한 값만 보기 위해서 스크립트를 수정하자.
from os import listdir
fileNames = listdir('/Users/seungyonglee/ctf/sha_2017/HTTP')
# Decrypt routine, without changes
def decrypt(z):
result = ""
for I in range(len(z) / 64 + 1):
a = z[I*64:(I+1)*64]
b = "e4146d4252bafb3b38212df186497a7479d5e95af4796e7573a65e6849952032"
c = "4141414141414141414141414141414141414141414141414141414141414141"
for i in range(len(a) / 2):
aa = ord(a[i*2:i*2 + 2].decode('hex'))
bb = ord(b[i*2:i*2 + 2].decode('hex'))
cc = ord(c[i*2:i*2 + 2].decode('hex'))
result = result + chr(aa ^ bb ^ cc)
return result
# A flag placeholder (string is immutable :/ )
flag = [' ' for _ in range(40)]
# For all files
for fileName in fileNames:
f = open('/Users/seungyonglee/ctf/sha_2017/HTTP/' + fileName, 'r')
fc = f.read()
# If it's a hit (the ordering of products is different)
if fc.find('hyper') < fc.find('Traditional'):
# fileName[23:] == Get only the ciphertext from filename
r = decrypt(fileName[23:])
# If the SQLi attempt targeted flag (not the SQL schema!)
if r.find('flag') != -1:
chi = r.find("'") + 1
if chi != 0:
ch = r[chi]
indi = r.find(',') + 1
if indi != 0:
ind = r[indi:indi+2]
if ind[1] == ',':
ind = ind[0]
if chi != 0:
print ind, ch
flag[int(ind)] = ch
print ''.join(flag)
flag가 출력되는 것을 확인할 수 있다.
flag{7307e3ee8da198ca4a7f9b1f8b018d8e}