# Mehrere mySQL Befehle per mysql_query()?



## ddhb (3. Januar 2007)

Hallo!

Ist es eigentlich möglich per mysql_query() mehrer mySQL Befehle an die Datenbank zu senden?
Also soetwas wie folgendes

```
mysql_query("SELECT name FROM table; UPDATE table SET name='ddhb'");
```

Denn ich habe mich etwas mit SQL-Injections beschäftigt und soetwas ähnliches wie das Beispiel 27-2 von http://de.php.net/manual/de/security.database.sql-injection.php auf die Beine gestellt. allerdings funktioniert das Beispiel bei mir nicht, da ich einen SQL Error erhalte wenn ich mein obriges Beispiel teste.



> You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '; UPDATE table SET name='ddhb'' at line 1


----------



## birnkammer (3. Januar 2007)

ddhb hat gesagt.:


> Ist es eigentlich möglich per mysql_query() mehrer mySQL Befehle an die Datenbank zu senden?


Nein, mit einer Abfrage AFAIK nicht.


ddhb hat gesagt.:


> Also soetwas wie folgendes
> 
> ```
> mysql_query("SELECT name FROM table; UPDATE table SET name='ddhb'");
> ```


Warum nicht einfach so:

```
$res1 = mysql_query("SELECT name FROM table");
mysql_free_result($res1);
$res2 =mysql_query("UPDATE table SET name='ddhb'");
mysql_free_result($res2)
```


----------



## ddhb (3. Januar 2007)

Weil ich über eine SQL-Injection die ich auf meiner Homepage habe, eben diese einfache SELECT Anweisung, eine UPDATE Anweisung einfügen möchte.

Du musst dir vorstellen das ich keinen Zugriff auf die PHP Datei habe, sondern nur eine Abfrage wie diese 
	
	
	



```
SELECT name FROM ddhb WHERE name='Externe Variable'
```
Und über die Externe Variable würde ich jetzt gerne zu Testzwecken eine UPDATE Anweisung machen, damit ich per SQL-Injection die Datenbank ändern kann.


----------



## Dr Dau (3. Januar 2007)

Hallo!


birnkammer hat gesagt.:


> Nein, mit einer Abfrage AFAIK nicht.


Wie kommst Du zu dieser Erkenntnis?
Das Stichwort SQL-Injection ist schon gefallen. 
In der Reihenfolge schlägt aber die Abfrage (SELECT) fehl, da nur auf den letzten Rückgabewert zugegriffen werden kann.
Wenn also zuerst UPDATE und dann SELECT ausgeführt wird, kann der Inhalt der Tabelle auch ausgegeben werden.
Ob das UPDATE allerdings erfolgreich war, kann nicht festgestellt werden.
Es sei denn man führt anschliessend ein SELECT durch und überprüft die Daten.

@ddhb, ich denke Du wirst hier keine "Anleitung" dazu bekommen wie Du eine SQL-Injection durchführst.
Schliesslich lässt es sich nicht überprüfen ob die Datenbank wirklich Dir gehört.

Gruss Dr Dau


----------



## KlaDi (3. Januar 2007)

Ähm nur so ne Frage, wenn es sich um eine MySQL-Datenbank handelt ist es doch eh nicht möglich eine SQL-Injection zu machen, weil meines Wissens nach diese nur einen SQL-Befehl abarbeiten und der Zweite wird verworfen.

Bitte verbessert mich, wenn ich mich täusche!

Gruß.


----------



## Dr Dau (3. Januar 2007)

KlaDi hat gesagt.:


> Bitte verbessert mich, wenn ich mich täusche!


Du täuscht Dich..... siehe meine vorherige Erklärung. 
Wenn MySQL den 2. SQL Befehl verwerfen würde, dann bräuchte es ganz sicher nicht die Funktion mysql_real_escape_string() geben..... denn diese ist ja dazu da, um zusätzlich eingeschläuste Querys (z.b. über die URL oder ein Formular) "unschädlich" zu machen.


----------



## ddhb (3. Januar 2007)

Dr Dau hat gesagt.:


> Hallo!
> Wie kommst Du zu dieser Erkenntnis?
> Das Stichwort SQL-Injection ist schon gefallen.
> In der Reihenfolge schlägt aber die Abfrage (SELECT) fehl, da nur auf den letzten Rückgabewert zugegriffen werden kann.
> ...


Also würde das Beispiel auf php.net auch nicht funktionieren? Denn dort wird danach ebenfalls eine UPDATE Anweisung gestartet.

Ich will ledeglich probieren wie sich eine ungeschützte Variable auswirken kann. Aber soetwas funktioniert ja dann wohl doch nicht, oder täusche ich mich da?


----------



## nom (3. Januar 2007)

so ne sql injection is doch sinnlos. Machs doch einfach so:

mal auf meiner Clanpage:
http://mythclan.my.funpic.de/index....assword,1,1,1 from webs_user where userID=1/*

hohl dir die md5 hash (des 32 zeichen Teil)
geh auf dc3.dl.am => Tools => MD5-Cracker => tipp die Hash ein und lass sie cracken.

logg dich mit dem admin account ein (meist userID 1) und hohl dir ein db backup. Ändere es und lad es mit dem admin account hoch.

http://mythclan.my.funpic.de/admin/database.php?action=write&userID=1

für DB backup


----------



## ddhb (3. Januar 2007)

Trotzdem interessiert es mich ob, und warum dieses Beispiel auf php.net funktioniert.


----------



## Matthias Reitinger (3. Januar 2007)

Hallo,



Dr Dau hat gesagt.:


> Du täuscht Dich..... siehe meine vorherige Erklärung.
> Wenn MySQL den 2. SQL Befehl verwerfen würde, dann bräuchte es ganz sicher nicht die Funktion mysql_real_escape_string() geben..... denn diese ist ja dazu da, um zusätzlich eingeschläuste Querys (z.b. über die URL oder ein Formular) "unschädlich" zu machen.


Nein, du täuschst dich. [phpf]mysql_real_escape_string[/phpf] dient nicht dazu, das Einfügen zusätzlicher Anfragen zu unterbinden. Vielmehr kann man mit dieser Funktion verhindern, dass die Anfrage ungewollt modifiziert wird.

[phpf]mysql_query[/phpf] kann tatsächlich nur eine einzige Anfrage abarbeiten (inkl. zugehöriger Unterabfragen natürlich). So steht's ja auch im Handbuch (Hervorhebung von mir):


			
				http://de.php.net/manual/de/function.mysql-query.php hat gesagt.:
			
		

> mysql_query() sendet *eine* Anfrage an die zur Zeit aktiven Datenbank, […]



Grüße,
Matthias


----------



## Dr Dau (3. Januar 2007)

ddhb hat gesagt.:


> Also würde das Beispiel auf php.net auch nicht funktionieren? Denn dort wird danach ebenfalls eine UPDATE Anweisung gestartet.


Ja und nein.
Einen "Hacker" wird wohl kaum das Rückgabeergebins vom SELECT interessieren..... ihn interessiert nur ob sein Update geklappt hat. 
Um an die geupdateten Daten zu kommen, schleust er hinterher halt noch ein SELECT ein.
Dieses kann er auch gelichzeitig mit dem UPDATE machen, so lange das Update zuerst angegeben wird.


Matthias Reitinger hat gesagt.:


> mysql_query() kann tatsächlich nur eine einzige Anfrage abarbeiten (inkl. zugehöriger Unterabfragen natürlich). So steht's ja auch im Handbuch (Hervorhebung von mir)


Glaubst Du alles was im Handbuch steht?
Ich habe es getestet.....
UPDATE.....; SELECT.....; (funktioniert anstandslos, es lässt sich aber nicht prüfen ob UPDATE funktioniert hat)
DELETE.....; SELECT.....; (funktioniert anstandslos, es lässt sich aber nicht prüfen ob DELETE funktioniert hat)
SELECT.....; UPDATE.....; (auf den Rückgabewert von SELECT lässt sich nicht zugreifen, UPDATE wird aber trotzdem ausgeführt)
SELECT.....; DELETE.....; (dito)


----------



## ddhb (3. Januar 2007)

Dr Dau hat gesagt.:


> SELECT.....; UPDATE.....; (auf den Rückgabewert von SELECT lässt sich nicht zugreifen, UPDATE wird aber trotzdem ausgeführt)


Wird es bei meinem Beispiel eben nicht, und ich verstehe auch nicht warum nicht.


----------



## Matthias Reitinger (3. Januar 2007)

Hallo,



Dr Dau hat gesagt.:


> Glaubst Du alles was im Handbuch steht?


Ich habe meine Aussage nicht am Handbuch festgemacht. Der Text im Handbuch sollte nur ein weiteres Indiz sein. Mit den mit PHP mitgelieferten, offiziellen MySQL-Erweiterungen ist es nicht möglich, mehrere Anfragen mit einem einzigen [phpf]mysql_query[/phpf]-Aufruf abzuarbeiten (zumindest nicht ohne Tricks, siehe weiter unten). Das hängt direkt mit der C-API von MySQL zusammen, welche von der MySQL-Extension verwendet wird. Da steht's dann auch nochmal in aller Deutlichkeit in der Dokumentation:


			
				http://dev.mysql.com/doc/refman/4.1/en/mysql-query.html hat gesagt.:
			
		

> *17.2.3.49. mysql_query()*
> 
> int mysql_query(MYSQL *mysql, const char *query)
> 
> ...





			
				http://dev.mysql.com/doc/refman/4.1/en/c-api-multiple-queries.html hat gesagt.:
			
		

> *17.2.9. C API Handling of Multiple Statement Execution*
> 
> From version 4.1, MySQL supports the execution of multiple statements specified in a single query string. To use this capability with a given connection, you must specify the CLIENT_MULTI_STATEMENTS option in the flags parameter of mysql_real_connect() when opening the connection. You can also set this for an existing connection by calling mysql_set_server_option(MYSQL_OPTION_MULTI_STATEMENTS_ON)



Zieht man nun zusätzlich noch den Quellcode der aktuellen Version der MySQL-Erweiterung zu Rate, wird man feststellen, dass weder CLIENT_MULTI_STATEMENTS noch MYSQL_OPTION_MULTI_STATEMENTS_ON darin auftauchen.

Allerdings kann man seit PHP 4.3.0 beim Aufruf von [phpf]mysql_connect[/phpf] die „client flags“ von Hand setzen. Diese werden dann direkt zur C-Funktion mysql_real_connect durchgereicht. Aus dem Quellcode der MySQL-API kann man dann noch rauslesen, dass CLIENT_MULTI_STATEMENTS dem Wert 65536 entspricht. Baut man nun die Verbindung mit einem Aufruf wie bspw. mysql_connect("host", "user", "pass", true, 65536); auf, dann (und nur dann) kann man auch mehrere Statements mit einem einzelnen [phpf]mysql_query[/phpf] abarbeiten lassen. Allerdings konnte ich das nur mit der aktuellen Version von PHP5 verifizieren – PHP4 liefert nachwievor die Meldung, dass ein Syntaxfehler in der SQL-Abfrage vorliege.

Grüße,
Matthias


----------



## Dr Dau (3. Januar 2007)

@Matthias, wie gesagt, ich habe es (mit erfolg) getestet (MySQL 4.1.11 und PHP 5.0.4).
Bevor wir noch mehr in die Tiefen gehen, lass uns doch darauf einigen dass es u.U. möglich währe aber nicht zwingend möglich sein muss. 
Mit anderen Worten, wer sich mit den zur verfügung stehenden Mitteln gegen SQL-Injections schützt, braucht sich i.d.R. auch vor nichts zu fürchten (Ausnahmen wird es natürlich immer geben).


----------



## Matthias Reitinger (3. Januar 2007)

Hallo,



Dr Dau hat gesagt.:


> @Matthias, wie gesagt, ich habe es (mit erfolg) getestet (MySQL 4.1.11 und PHP 5.0.4).


Das interessiert mich jetzt aber. Aus dem Quelltext der MySQL-Extension von PHP 5.0.4 ist nicht ersichtlich, warum dies möglich sein sollte. Kannst du mal den PHP-Quelltext reinstellen, mit dem du getestet hast?

Grüße,
Matthias


----------



## Dr Dau (4. Januar 2007)

Ich habe es mit phpMyAdmin getestet.
Mag sein dass phpMyAdmin die Querys am Semikolon zerlegt..... aber dass können andere Scripte ja auch.
Und ob die Daten nun per POST oder per GET kommen, spielt nur noch eine untergeordnete Rolle.
Es ist also keine Frage dessen wie PHP mit mehreren Querys umgeht, sondern wie das Script damit umgeht.
MySQL kümmert sich auch einen feuchten Kehricht darum wie viele Querys auf mal kommen (kannst Du ja auf der Konsole testen).


----------



## Matthias Reitinger (4. Januar 2007)

Hallo,



Dr Dau hat gesagt.:


> Ich habe es mit phpMyAdmin getestet.
> Mag sein dass phpMyAdmin die Querys am Semikolon zerlegt.....


Genau das macht phpMyAdmin, und deswegen kann man mit diesem Verfahren keine Schlüsse über das Verhalten von [phpf]mysql_query[/phpf] ziehen.



Dr Dau hat gesagt.:


> MySQL kümmert sich auch einen feuchten Kehricht darum wie viele Querys auf mal kommen (kannst Du ja auf der Konsole testen).


Die MySQL-Konsole hat aber wiederum nichts mit [phpf]mysql_query[/phpf] zu tun.

Grüße,
Matthias


----------



## Unicate (4. Januar 2007)

Jo, ich bin auch Matthias seiner Meinung.
Ich hab das auch mal versucht und bin da hängen geblieben.

Ich habs dann halt zusammen gefasst:

```
$sql[] = "SELECT.....;"
$sql[] = "UPATE.....;"
/* es können beliebig viele folgen */

foreach($sql as $query)
{
  mysql_query($query);
}
```

Aber ich mein wenn du als SQL injection machst, dann gehst du eben 2 mal in die selbe Lücke.

Das erste mal holst du dir eben die Daten raus die du brauchst und das nächste mal änderst du etwas mit UPDATE.
Also ich mein die Lücke schliesst sich doch nicht von allein...


----------



## ddhb (4. Januar 2007)

Nur ist ein UPDATE bei solch einer Lücke nicht möglich.


----------

