LFI2RCE via Eternal waiting
Basic Information
Standaard, wanneer 'n lêer na PHP opgelaai word (selfs al verwag dit nie), sal dit 'n tydelike lêer in /tmp
genereer met 'n naam soos php[a-zA-Z0-9]{6}
, alhoewel ek sommige docker beelde gesien het waar die gegenereerde lêers geen syfers bevat nie.
In 'n plaaslike lêerinvoeging, as jy daarin slaag om daardie opgelaaide lêer in te sluit, sal jy RCE kry.
Let daarop dat standaard PHP slegs toelaat om 20 lêers in 'n enkele versoek op te laai (gestel in /etc/php/<version>/apache2/php.ini
):
Ook, die aantal potensiële lêernames is 62*62*62*62*62*62 = 56800235584
Ander tegnieke
Ander tegnieke berus op die aanval van PHP protokolle (jy sal nie in staat wees as jy net die laaste deel van die pad beheer nie), die pad van die lêer openbaar, die misbruik van verwagte lêers, of maak PHP 'n segmentasiefout ly sodat opgelaaide tydelike lêers nie verwyder word nie. Hierdie tegniek is baie soortgelyk aan die laaste een, maar sonder om 'n nuldag te vind.
Ewige wag tegniek
In hierdie tegniek het ons net 'n relatiewe pad nodig om te beheer. As ons daarin slaag om lêers op te laai en die LFI nooit te laat eindig nie, sal ons "genoeg tyd" hê om brute-force opgelaaide lêers en vind enige van die opgelaaide.
Voordele van hierdie tegniek:
Jy moet net 'n relatiewe pad binne 'n insluiting beheer
Vereis nie nginx of 'n onverwagte vlak van toegang tot log lêers nie
Vereis nie 'n 0 dag om 'n segmentasiefout te veroorsaak nie
Vereis nie 'n pad openbaar nie
Die hoofprobleme van hierdie tegniek is:
'n Spesifieke lêer(s) moet teenwoordig wees (daar mag meer wees)
Die mal hoeveelheid potensiële lêernames: 56800235584
As die bediener nie syfers gebruik nie is die totale potensiële hoeveelheid: 19770609664
Standaard kan slegs 20 lêers in 'n enkele versoek opgelaai word.
Die maksimum aantal parallelle werkers van die gebruikte bediener.
Hierdie limiet saam met die vorige kan hierdie aanval te lank laat duur
Tydsduur vir 'n PHP versoek. Ideaal gesproke moet dit ewige wees of die PHP-proses moet doodgemaak word sonder om die tydelike opgelaaide lêers te verwyder, anders sal dit ook 'n pyn wees
So, hoe kan jy maak dat 'n PHP insluiting nooit eindig nie? Net deur die lêer /sys/kernel/security/apparmor/revision
in te sluit (nie beskikbaar in Docker houers ongelukkig...).
Probeer dit net deur te bel:
Apache2
Standaard ondersteun Apache 150 gelyktydige verbindings, volgens https://ubiq.co/tech-blog/increase-max-connections-apache/ is dit moontlik om hierdie getal tot 8000 te verhoog. Volg dit om PHP met daardie module te gebruik: https://www.digitalocean.com/community/tutorials/how-to-configure-apache-http-with-mpm-event-and-php-fpm-on-ubuntu-18-04.
Standaard, (soos ek in my toetse kan sien), kan 'n PHP-proses ewig duur.
Kom ons doen 'n bietjie wiskunde:
Ons kan 149 verbindings gebruik om 149 * 20 = 2980 tydelike lêers met ons webshell te genereer.
Dan, gebruik die laaste verbinding om brute-force potensiële lêers.
Teen 'n spoed van 10 versoeke/s is die tye:
56800235584 / 2980 / 10 / 3600 ~= 530 ure (50% kans in 265h)
(sonder syfers) 19770609664 / 2980 / 10 / 3600 ~= 185h (50% kans in 93h)
Let daarop dat ons in die vorige voorbeeld heeltemal ander kliënte DoSing!
As die Apache-bediener verbeter word en ons 4000 verbindings kan misbruik (halfpad na die maksimum getal). Ons kan 3999*20 = 79980
lêers skep en die getal sou verminder tot ongeveer 19.7h of 6.9h (10h, 3.5h 50% kans).
PHP-FMP
As die webblad PHP-FMP gebruik in plaas van die gewone php-mod vir apache om PHP-skripte uit te voer (dit verbeter die doeltreffendheid van die webblad, so dit is algemeen om dit te vind), is daar iets anders wat gedoen kan word om die tegniek te verbeter.
PHP-FMP laat toe om die parameter request_terminate_timeout
in /etc/php/<php-version>/fpm/pool.d/www.conf
te konfigureer.
Hierdie parameter dui die maksimum aantal sekondes aan wanneer versoek aan PHP moet beëindig (oneindig per standaard, maar 30s as die param nie kommentaar is nie). Wanneer 'n versoek deur PHP verwerk word, word die aangeduide aantal sekondes, dit vermoor. Dit beteken dat as die versoek tydelike lêers opgelaai het, omdat die php-verwerking gestop is, daardie lêers nie verwyder gaan word nie. Daarom, as jy 'n versoek kan laat duur vir daardie tyd, kan jy duisende tydelike lêers genereer wat nie verwyder sal word nie, wat die proses om hulle te vind versnel en die waarskynlikheid van 'n DoS op die platform verminder deur al die verbindings te verbruik.
So, om DoS te vermy, kom ons veronderstel dat 'n aanvaller slegs 100 verbindings terselfdertyd sal gebruik en die maksimum verwerkingstyd van php deur php-fmp (request_terminate_timeout
) is 30s. Daarom is die aantal tydelike lêers wat per sekonde gegenereer kan word 100*20/30 = 66.67
.
Dan, om 10000 lêers te genereer, sal 'n aanvaller nodig hê: 10000/66.67 = 150s
(om 100000 lêers te genereer, sal die tyd 25min wees).
Dan kan die aanvaller daardie 100 verbindings gebruik om 'n soek brute-force uit te voer. **** Veronderstel 'n spoed van 300 req/s, die tyd wat nodig is om dit te ontgin is die volgende:
56800235584 / 10000 / 300 / 3600 ~= 5.25 ure (50% kans in 2.63h)
(met 100000 lêers) 56800235584 / 100000 / 300 / 3600 ~= 0.525 ure (50% kans in 0.263h)
Ja, dit is moontlik om 100000 tydelike lêers in 'n EC2 medium grootte instansie te genereer:
Let daarop dat dit voldoende sou wees om die kwesbare LFI-bladsy in te sluit om die tydsduur te aktiveer, sodat dit in 'n ewige insluitingslus ingaan.
Nginx
Dit lyk of Nginx standaard 512 parallel verbindings terselfdertyd ondersteun (en hierdie getal kan verbeter word).
Last updated