分析源码框架
Spring MVC/Boot
Struts2
科蓝PE 常见于网银
JSP/Servlet
刨析项目结构
SPringBoot
简化结构
[用户]
⇅
[服务器]
⇅
┌───────────────────────────┐
│ Web 中间件 │
│ ┌───────────────────┐ │
│ │ Filter / Interceptor │ │
│ └───────────────────┘ │
│ ⇅ │
│ Controller │
│ ⇅ │
│ Service │
│ ⇅ │
│ Mapper │
└───────────────────────────┘
⇅
[数据库]
登录鉴权审计
首先关注 拦截器(Interceptor)、过滤器(Filter)或安全框架如Shiro/Spring Security
关注其中 JWT 、Shiro 等硬编码造成的 认证伪造
若鉴权绕过初步判断不存在,则鉴别权限分配越权(普通用户/管理员用户) 水平越权/垂直越权
SQL注入
第一步先分析 pom.xml (如果是 maven 项目) ,依赖包。
分析SQL采用框架 : JDBC mybatis mybatis-plus Hibernate
Mybatis
Mybatis -> Mapper 层搜索 ${
重点关注排序注入
例如:
JDBC
搜索拼接关键字定位
关键字: statement prepareStatement
定位关键字 statement
定位关键字 prepareStatement
(错误用法等价 statement
)
定位关键字 SQLException
(异常处理处周围潜在SQL
函数执行)
单独的 SQL 处理方法
如果采用 Statement
则默认非预编译 , 采用 PreparedStatement
则采用预编译 参数绑定
下面采用 Statement
潜在 SQL 注入
/*执勤Sql前截取最后面的空格和英文逗号,并加上‘;’*/
exeSql = exeSql.substring(0, exeSql.length() - 2) + ";";
int status= statement.executeUpdate(exeSql);
statement.close();
connection.close();
// 错误:在预编译语句外部拼接字符串! 未使用 ? 占位符
String sql = "SELECT * FROM users WHERE username = '" + userInput + "'";
PreparedStatement pstmt = connection.prepareStatement(sql); // 等同于 Statement,仍有注入风险
常见拼接方式
+
append()
concat()
join()
不能被预编译的结构
在预编译中, 字面量(literals)能通过 ?
占位符绑定,所有“结构”层面的东西都必须在 SQL 字符串里写死或由程序拼接预编译处理不了。
数据库对象 & 标识符
表名、视图名、模式(schema)名
// 不可通过 ? 绑定
String table = getFromUser();
String sql = "SELECT * FROM " + table + " WHERE id = ?";
列名、别名
// 列名也不能用 ?
String col = getFromUser();
String sql = "SELECT " + col + " FROM users WHERE status = ?";
索引名、触发器名、存储过程名
数据库名、链接名
SQL 关键字 & 语法结构
排序子句 ORDER BY <column> [ASC|DESC]
分组子句 GROUP BY <column_list>
过滤子句 HAVING <agg_expr> > ?
中的聚合表达式本身不能参数化
分页子句
MySQL:
LIMIT offset, count
PostgreSQL:
LIMIT count OFFSET offset
SQL Server:
OFFSET x ROWS FETCH NEXT y ROWS ONLY
JOIN 类型(INNER
/ LEFT
/ RIGHT
/ FULL
/ CROSS
)
UNION / INTERSECT / EXCEPT
子查询体,如动态决定要 union 几个子查询
// 这些都属于 SQL “结构”或“控制流”,只能拼接,不能 ?
绑定
操作符 & 函数名
算术/逻辑操作符:+ - * / %
、AND
、OR
、NOT
、LIKE
、IN
(关键字)
比较操作符:=
、<>
、!=
、<
、>
、<=
、>=
字符串操作符:||
(串接)
函数名:NOW()
、COUNT()
、SUM()
、SUBSTR()
、CONCAT()
等
窗口函数:ROW_NUMBER()
、RANK()
、OVER
子句
动态 SQL 片段
片段拼接:如动态加 WHERE、AND、OR 的子句序列
开关型语句:是否加 FOR UPDATE
、WITH (NOLOCK)
、OPTION (RECOMPILE)
等提示
文件操作类
文件上传
// 也要时刻注意是否可目录遍历
上传 html 造成 XSS
危害较小,但是可以造成存储型 XSS
JSP 马
上传可用的 JSP马 有条件限制: 1: 需要能上传 jsp 后缀的文件(或绕过过滤)
2:需要目标服务器采用 Tomcat 搭建,且存在 jsp 解析环境
SpringBoot
SpringBoot
默认是不对 jsp
进行解析的。
想要在 SpringBoot
中使用 jsp
,就需要引入相关依赖,或者自建 WEB-INF
, web.xml
等操作,然后在 pom.xml
导入解析依赖。
<!-- 用于编译jsp -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
存在过滤时的绕过方法
后缀
#探测
#对同一个已知存在的 .jsp 页面改后缀(如 index.jspx、index.jsw)查看是否仍然返回 200/500。
当 jsp
被限制时,我们也可以考虑采用的后缀有下不等:
jsp jspa jspx jsw jsv jspf jhtml jSp jSpx jSpa jSw jSv jSpf jHtml #大小写转换
其中容器支持(默认映射到 JspServlet
的后缀): Apache Tomcat / Jetty / GlassFish / Payara
.jsp .jspx
IBM WebSphere / Open Liberty
.jsp .jspx .jsw .jsv
Oracle/BEA WebLogic
.jsp .jspx(JSP Document) .jhtml(需把 PageCompileServlet 或 JSPServlet 手动映射到 .jhtml)
WildFly / JBoss AS
同 Tomcat(继承自 Undertow/Servlet 实现)
.jsp .jspx
截断
::$DATA %00
::$DATA
详细参阅: https://labs.portcullis.co.uk/blog/ntfs-alternate-data-streams-for-pentesters-part-1/
NTFS 支持 "一文件多数据流":格式是 文件名:流名:流类型
。 (NTFS文件系统,ADS语法)
省略
流名
就是“默认流”;流类型
通常固定写$DATA
。因此
foo.jsp::$DATA
、foo.jsp:
、foo.jsp
三者对真正读写文件时效果完全一样。
Windows API 在解析路径时,只把 冒号之前 的部分当文件名。后面的 :$
… 不会出现在硬盘目录里,但路径仍被认为合法。
关键字
// 也要时刻注意是否可目录遍历
───────────────────── Commons FileUpload ─────────────────────
ServletFileUpload
FileItem
FileItemHeaders
FileItemHeadersImpl
FileItemFactory
DefaultFileItem
DefaultFileItemFactory
ProgressListener
──────────────────────── Servlet 3.0+ ─────────────────────────
Part
javax.servlet.http.Part
jakarta.servlet.http.Part
@MultipartConfig
MultipartConfigElement
HttpServletRequest#getPart
HttpServletRequest#getParts
───────────────────────── Spring MVC ─────────────────────────
MultipartResolver
CommonsMultipartResolver
StandardServletMultipartResolver
MultipartHttpServletRequest
CommonsMultipartFile
StandardMultipartFile
MultipartException
MultipartParsingResult
MultipartFilter
──────────────────────── Spring WebFlux ───────────────────────
FilePart
FormFieldPart
PartEvent
PartHttpMessageReader
───────────────────────── Struts2 / OGNL ──────────────────────
FileUploadInterceptor
com.opensymphony.xwork2.FileManager
org.apache.struts2.dispatch.multipart.MultiPartRequest
struts.multipart.maxSize
struts.multipart.saveDir
────────────────────── Jersey / JAX-RS ────────────────────────
FormDataParam
FormDataContentDisposition
MultiPartFeature
InputStreamDataSource
──────────────────── Apache HttpClient / OkHttp ───────────────
MultipartEntityBuilder
MultipartEntity
MultipartBody
MultipartBody.Builder
FormBodyPart
InputStreamEntity
──────────────────────── Netty / Reactor ─────────────────────
HttpPostRequestDecoder
InterfaceHttpData
FileUploadData
DiskFileUpload
MixedFileUpload
───────────────────── 其他常见工具/类 ─────────────────────────
IOUtils
FilenameUtils
Files.copy
Files.write
Paths.get
Path.toFile
FileInputStream
FileOutputStream
BufferedOutputStream
RandomAccessFile
FileChannel
DiskFileItemFactory
TemporaryFile
tempFilePrefix
uploadTempDir
功能点
富文本编辑器图片 -- 高发
模板 / 主题 / 皮肤包上传 -- 解压运行导致的 rce
后台文件管理 / 在线文件操作 -- 易造成文件覆盖形成可利用rce
产品详情图片
商品缩略图
品牌 LOGO
文档附件上传
合同 / 证照上传
身份证照片上传
银行卡照片上传
报销凭证上传
发票图片
二维码生成图
活动海报
CMS 资源文件
静态资源替换
系统配置导入
后台配置文件上传
数据导入 Excel
CSV 数据批量导入
日志备份上传
数据库备份还原
补丁 / 升级文件上传
插件 / 扩展包上传
APK / IPA 上传
微服务 JAR 上传
脚本文件上传
…
额外注意点
现在的 Spring 的 MultipartFile.getOriginalFilename()
实现一般存在 3 种
CommonsMultipartFile.getOriginalFilename()
StandardMultipartFile.getOriginalFilename()
MockMultipartFile.getOriginalFilename()
CommonsMultipartFile 中
// 在获取原始文件名时,会默认做一部分的截断清洗,导致目录遍历失效
int unixSep = filename.lastIndexOf(47);
int winSep = filename.lastIndexOf(92);
int pos = Math.max(winSep, unixSep);
return pos != -1 ? filename.substring(pos + 1) : filename;
// 而 StandardMultipartFile 与 MockMultipartFile 均默认返回传入的 filename
SSRF
函数: isSiteLocalAddress
#只能拦截:
10/8、172.16/12、192.168/16 以及 IPv6 fec0::/10
支付处理
提取 Restful API
Spring Boot 2.x 特性提供支持
配置依赖 访问端点 /actuator/mappings
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
反射扫描
后续待完善