作业7.13
分析:
漏洞成因:
如下代码第二十三行将接受到的参数直接拼接到sql语句中并且在第二十五行处执行了。
代码解释成因:
靶场使用的是报错注。如果将第41行的代码注释了报错注入也就行不通了。 我通过实验发现也可以使用联合注入。此时就还需要43行的代码将结果返回。
/**
* @vul JDBC模式下,采用拼接的SQL语句
* @poc http://127.0.0.1:8888/SQLI/jdbc?id=1' and updatexml(1,concat(0x7e,(SELECT user()),0x7e),1)--%20+
*/
@RequestMapping("/jdbc")
public String sql_1(String id) {
StringBuilder result = new StringBuilder();
try {
Class.forName("com.mysql.cj.jdbc.Driver");
// 建立连接
Connection conn = DriverManager.getConnection(db_url, db_user, db_pass);
// 执行查询
Statement stmt = conn.createStatement();
String sql = "select * from users where id = '" + id + "'";
System.out.println("[*] 执行SQL语句:" + sql);
ResultSet rs = stmt.executeQuery(sql);
// 获取查询结果
while (rs.next()) {
String res_name = rs.getString("user");
String res_pass = rs.getString("pass");
String info = String.format("查询结果 %s: %s", res_name, res_pass);
result.append(info);
}
rs.close();
conn.close();
} catch (Exception e) {
// 输出错误,用于报错注入。。。
return e.toString();
}
return result.toString();
}
复现:
如下情况预编译也无法防御注入漏洞: PrepareStatement虽然进⾏了预编译,但在预编译前进行了以拼接⽅式构造SQL语句的情况下仍然会产⽣SQL注⼊
2、分析并复现mybatis注入漏洞复并简述审计方法和漏洞原理
分析:
首先找到路由位置。
/**
* @vul order by 注入,#{} 会将对象转成字符串,形成 order by "user" desc 造成错误,因此很多研发会采用${}来解决,从而造成SQL注入
* @poc http://127.0.0.1:8888/SQLI/mybatis/vul/order?field=id&sort=desc,1
*/
@GetMapping("/mybatis/vul/order")
public List<User> orderBy(String field, String sort) {
return userMapper.orderBy(field, sort);
}
通过跟踪可以找到调用userMapper.orderBy的地方。
/**
* 传统的xml配置
*/
List<User> orderBy(String field, String sort);
List<User> orderBySafe(String field);
发现是传统的xml配置,继续跟进。最终找到底层进行sql查询的语句,发现漏洞所在,即将field和sort参数直接拼接进sql语句中。
<!-- id的值必须和数据处理层的接口名一致 -->
<select id="orderBy" resultType="com.best.hello.entity.User">
select *
from users
order by ${field} ${sort}
</select>
复现:
3、分析并复现命令执行漏洞,简述什么情况下无法进行命令注入以及原因。
分析:
ProcessBuilder方式
漏洞成因: 在代码第四行将外部获取的参数拼接进入命令并在第九行执行。期间没进行过滤。 并在后续代码中将命令执行的结果全部添加到stringbuilder对象中,最后转成字符串输出。
@RequestMapping("/ProcessBuilder")
public static String cmd(String filepath) {
// 提供一个命令字典
String[] cmdList = {"sh", "-c", "ls -l " + filepath};
StringBuilder sb = new StringBuilder();
String line;
// 利用指定的操作系统程序和参数构造一个进程生成器
ProcessBuilder pb = new ProcessBuilder(cmdList);
pb.redirectErrorStream(true);
// 使用此进程生成器的属性启动一个新进程
Process process = null;
try {
process = pb.start();
// 取得命令结果的输出流
InputStream fis = process.getInputStream();
// 用一个读输出流类去读
InputStreamReader isr = new InputStreamReader(fis);
// 用缓存器读行
BufferedReader br = new BufferedReader(isr);
//直到读完为止
while ((line = br.readLine()) != null) {
System.out.println(line);
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}
return sb.toString();
}
runtime方式
漏洞成因: 成因和processBuilder方式相同,区别在于执行方式不同。不过runtime最底层还是调用ProcessBuilder方法来实现的。
@RequestMapping("/runtime")
public static String cmd2(String cmd) {
StringBuilder sb = new StringBuilder();
String line;
try {
// 执行命令
Process proc = Runtime.getRuntime().exec(cmd);
InputStream fis = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);
while ((line = br.readLine()) != null) {
System.out.println(line);
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}
return sb.toString();
}
复现:
ProcessBuilder方式
因为是win10系统搭建的环境无法执行linux的命令
runtime方式
如果参数是以数组形式传进来的并且在执行前没有调用StringTokenizer()方法,则可以直接利用。 当一下情况是ProcessBuilder无法实现命令注入。
-
ls -lh; id => ["ls", "-lh;", "id"]
分割完后方法会将id作为参数执行而不是命令,因此会报错。 ls: illegal option
-
ls -lh;id => ["ls", "-lh;id"]
同样的会将-lh;id作为参数执行而不是将id作为单独的命令执行,因此也会报错。 ls: illegal option
-
sh -c 'ls -lh;id' => ["sh", "-c", "'ls", "-lh;id'"]
如命令中两边有单引号也是无法执行的因为单引号没有闭合,因此会报错。
-lh;id’: -c: line 0: unexpected EOF while looking for matching `’’
-
sh -c "ls;id" => ["sh", "-c", ""ls;id"]
会报如下错误,看报错我猜测是将ls;id当做命令执行。
sh: ls;id: command not found
4、简述表达式注入漏洞原理及常见漏洞函数及利用方法
漏洞成因:
通过ex获取外部的的参数并且没有进行任何过滤,在第八行代码进行表达式的解析是形成漏洞的关键。
@GetMapping("/spel")
public String rce(String ex) {
// 1. 创建解析器:SpEL使用ExpressionParser接口表示解析器,提供SpelExpressionParser默认实现
ExpressionParser parser = new SpelExpressionParser();
// 2. 解析表达式: 使用ExpressionParser的parseExpression来解析相应的表达式为Expression对象
// 3. 求值:通过 Expression 接口的 getValue 方法根据上下文获得表达式值
String result = parser.parseExpression(ex).getValue().toString();
System.out.println(result);
return result;
}
常见漏洞函数及利用方法
Spring SPEL
String expression = "T(java.lang.Runtime).getRuntime().exec(/"calc/")";
String result = parser.parseExpression(expression).getValue().toString();
Struts2 OGNL
//模版
@[类全名(包括包路径)]@[方法名 | 值名],例如:
@java.lang.String@format('foo %s', 'bar')
//实例
ActionContext AC = ActionContext.getContext();
String expression = "${(new java.lang.ProcessBuilder('calc')).start()}";
AC.getValueStack().findValue(expression));
JSP JSTL_EL
<spring:message text="${/"/".getClass().forName(/"java.lang.Runtime/").getMethod(/"getRuntime/",null).invoke(null,null).exec(/"calc/",null).toString()}">
</spring:message>
Elasticsearch MVEL
String expression = "new java.lang.ProcessBuilder(/"calc/").start();";
Boolean result = (Boolean) MVEL.eval(expression, vars);
5、简述actuator模块的作用及常见漏洞利用方式
作用:
Spring Boot Actuator 是 Spring Boot 提供的一个监控和管理生产环境应用程序的模块,它允许开发者在应用程序运行时获取关于应用程序运行状况、性能指标、日志级别、环境配置等方面的信息。Actuator 提供了一些内置的端点(endpoints),可以通过 HTTP 端点或 JMX 管理端点获取这些信息,同时也可以自定义端点来暴露应用程序的其他内部信息。
常见漏洞利用方式
-
未授权访问:如果 Actuator 端点没有进行适当的安全配置,可能导致未经授权的用户可以访问敏感信息,如环境配置、敏感数据等。
-
信息泄露:如果 Actuator 端点暴露了过多的信息,可能导致泄露敏感数据,如数据库连接信息、用户凭证等。
-
POST 请求利用:某些 Actuator 端点可能包含可以执行敏感操作的端点,如果未进行权限验证或安全控制,可能被攻击者利用进行恶意操作。
6、逻辑漏洞中,越权漏洞一般审计思路及常见功能点有哪些?
审计思路:
-
识别功能点:首先要了解应用程序的功能、用户角色权限和数据访问权限,识别可能存在越权漏洞的功能点。
-
模拟攻击:通过模拟攻击者行为,尝试利用逻辑漏洞访问未授权的功能或数据。
-
测试权限验证:测试用户身份验证和授权机制的完整性和正确性,确认是否能够越过权限验证逻辑进行越权操作。
-
分析代码逻辑:审查应用程序的代码逻辑,特别关注与用户权限、访问控制相关的部分,查找可能存在的逻辑漏洞。
常见功能点:
-
用户身份验证:登录认证过程中可能存在缺陷导致越权。
-
数据访问:查询、添加、修改或删除数据的功能点中,未正确校验用户权限可能导致越权。
-
功能访问控制:功能级别的访问控制机制,如管理页面、操作按钮等的权限验证不完善。
-
重置密码:重置密码功能存在越权漏洞时,攻击者可能重置其他用户的密码。
-
文件上传:文件上传功能中未正确限制访问权限可能导致越权下载文件。
7、部署华夏erp的前后端并实现功能正常使用
前端: 用小皮搭建网站,新建网址域名随便取,端口85,根目录是华夏erp前端包中含义index.html文件的目录。
启动前端http://域名:85
后端: 将后端源码用IDEA打开然后等待maven配置和下载完成然后启动,需要注意的是JDK需要8版本。 前后端联系: 在小皮面板的设置->配置文件->vhosts.conf中有个名字为域名_85的文件点开。 在红框位置输入如下代码
location /jshERP-boot/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://localhost:9999/jshERP-boot/;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】