java 解析sh文件内容_java 文件读取
show me she shell
这是一道tomato师傅出的不完整的java题,java…,java…我恨java┑( ̄Д  ̄)┍
这是一个题目一是列目录+任意文件读取,
二是垂直越权+CLRF配SSRF打redis+反序列化命令执行
题目的难度在于代码本身的不完整和java,没办法实际测试,所以只能强行阅读源码,幸运的是代码结构是spring完成的,和python的flask/django结构很强,这为我们阅读源码提供了可能。
1
整个代码中,控制器只有5个,其中
1
2
3
4
5
index 首页
login 登陆、注册
manager 管理员管理
post 用户发送post
user 用户功能,包括上传头像和删除自己发送的post
entity是python中类似于model的定义,其中包括了User、Post
interceptor主要负责路由以及权限设置,核心代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
String requestUri = request.getRequestURI();
for (String s : excludedUrls) {
if (requestUri.endsWith(s)) {
return true;
}
}
User user = (User) request.getSession().getAttribute("user");
if(user == null){
request.getRequestDispatcher("/WEB-INF/pages/login.jsp").forward(request, response);
return false;
}else{
return true;
}
}
通过request.getRequestURL获取连接,其中后缀在excludedUrls的不需要登陆,其他都需要登陆才能访问。
关于excludedUrls的设置在配置文件中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/register.do
/login.do
/doregister.do
mapper其中包含了部分核心函数,但只有函数定义,没有代码
service中包含了关于user操作和post操作的核心函数
utiles是一些其余的核心函数
第一个漏洞点其实比较容易发现,在user的控制器中我们可以看到关于更换头像的函数
1
2
3
4
5
6
7
8
@RequestMapping(value = "/headimg.do",method = RequestMethod.GET)
public void UpdateHead(@RequestParam("url")String url){
String downloadPath = request.getSession().getServletContext().getRealPath("/")+"/headimg/";
String headurl = "/headimg/"+ HttpReq.Download(url,downloadPath);
User user = (User) session.getAttribute("user");
Integer uid = user.getId();
userMapper.UpdateHeadurl(headurl,uid);
}
关于获取头像的地方调用了HttpReq.Download函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static String Download(String urlString,String path){
String filename = "default.jpg";
if(endWithImg(urlString)) {
try {
URL url = new URL(urlString);
URLConnection urlConnection = url.openConnection();
urlConnection.setReadTimeout(5*1000);
InputStream is = urlConnection.getInputStream();
byte[] bs = new byte[1024];
int len;
filename = generateRamdonFilename(getFileSufix(urlString));
String outfilename = path + filename;
OutputStream os = new FileOutputStream(outfilename);
while ((len = is.read(bs)) != -1) {
os.write(bs, 0, len);
}
os.close();
is.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return filename;
}
这里调用URL类来获取返回
1
2
URL url = new URL(urlString);
URLConnection urlConnection = url.openConnection();
但这之前我们需要绕过endWithImg的判断
1
2
3
4
5
6
7
8
9
private static boolean endWithImg(String imgUrl){
if(StringUtils.isNotBlank(imgUrl)&&(imgUrl.endsWith(".bmp")||imgUrl.endsWith(".gif")
||imgUrl.endsWith(".jpeg")||imgUrl.endsWith(".jpg")
||imgUrl.endsWith(".png"))){
return true;
}else{
return false;
}
}
函数比较清楚,对图片链接的结尾做了判断,也很好绕过,我们可以用形似
1
http://11111/111.php?a=1.jpg
就可以直接绕过判断了,这里还算比较明白,我们可以直接用file协议去读本地文件,形似file:///etc/passwd?a=1.jpg就可以获取文件内容了。
唯一的问题是,我们如何找到flag位置了,这就涉及到一个小trick了
在java中,我们可以用file:///或netdoc:///来列目录
通过这种方式,我们可以获取到服务器上的第一个flag
2
当然这里的第一题是当时的非预期,因为这种列目录方式只在java中才有,我们回到题目继续分析。
在第一题中我们找到了一个SSRF漏洞,在第二题中,修复了headimg使用file协议读文件的漏洞,但我们可以用CRLF向Redis写入数据。
1
headimg.do?url=http://127.0.0.1%0a%0dSET%20A%20A:6379
–>
1
redis set A A
但是有什么用呢?
让我们再回到题目代码
在managercontroller中,我们可以发现所有关于redis的操作都在这里,但这里有一个限制是要求当前用户的isadmin必须为1,但整个代码中并没有任何关于这部分的操作,所以我们顺着回顾代码中可能接触到设置isadmin的位置。
跟入注册代码controller.LoginController中,关于注册的代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@RequestMapping(value = "/doregister.do",method = RequestMethod.POST)
public String DoRegister(User user, String repassword, Model model){
String result = userService.register(user,repassword);
if(result.equals("ok")){
return "login";
}else{
model.addAttribute("message",result);
return "register";
}
}
@RequestMapping(value = "/register.do",method = RequestMethod.GET)
public String Register(){
return "register";
}
跟入userService.register函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public String register(User user,String repassword) {
String username = user.getUsername();
String password = user.getPassword();
if(StringUtils.isBlank(username.trim())|| StringUtils.isBlank(password.trim())){
return "You need set username and password";
}
int uid = userMapper.SelectIdByUsername(username);
if(uid>0){
return "This username has been registered!";
}
if(!password.equals(repassword)){
return "repassword";
}
userMapper.InsertUser(user);
return "ok";
}
仔细观察我们可以发现,虽然函数中从user中获取了username和password并进入userMapper.SelectIdByUsername验证,但在插入数据的时候仍然直接传入了user类。
这里我们看看user类的定义(这应该是类似于python中model的定义方式)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class User{
private Integer id;
private String username;
private String password;
private String headurl;
private Boolean isadmin;
public User(Integer id, String username, String password, String headurl, Boolean isadmin) {
this.id = id;
this.username = username;
this.password = password;
this.headurl = headurl;
this.isadmin = isadmin;
}
...
我们可以注意到这个函数在初始化时接受了isadmin,而在控制器中路由接收到这个参数时也没有做任何的处理,所以这里存在AutoBuilding漏洞
当我们在注册的时候,原post参数为
1
username=test&password=test&repassword=test
我们只要加入isadmin即可
1
username=test&password=test&repassword=test&isadmin=1
我们成功给当前用户加入了管理员权限
在获得了manager权限后,我们就可以执行manager控制器下的操作了,让我们来看看代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@RequestMapping(value = "/audit.do")
public String AuditPost(@RequestParam("pid") Integer pid,HttpSession session) {
User user = (User) session.getAttribute("user");
try {
if (user.getIsadmin()) {
postMapper.AuditPost(pid);
Post post = postMapper.GetOne(pid);
redisClient.set(pid,post);
return "manager";
}
}catch (Exception e){
return "redirect:/";
}
return "redirect:/";
}
@RequestMapping(value = "/check.do")
public String CheckPost(@RequestParam("pid") Integer pid, HttpSession session, Model model){
User user = (User) session.getAttribute("user");
try {
if (user.getIsadmin()) {
Post post = redisClient.getObject(pid);
model.addAttribute("post", post);
return "manager";
}
}catch(Exception e){
return "redirect:/";
}
return "redirect:/";
}
这其中有一个特殊的操作就是对于redis的操作,关于redis的代码在utils.RedisClient中
1
2
3
4
5
6
7
8
9
10
11
12
13
public void set(Integer id, T t) {
byte[] key = getKey(id);
RedisSerializer serializer = redisTemplate.getValueSerializer();
byte[] val = serializer.serialize(t);
getConnection().set(key, val);
}
public T getObject(Integer id) {
byte[] key = getKey(id);
byte[] result = getConnection().get(key);
return (T) redisTemplate.getValueSerializer().deserialize(result);
}
很明显其中的getObject函数有反序列化的操作,如果我们想要通过反序列化来构造RCE的话,我们需要一个gadget.
这里tomato用了SpringAbstractBeanFactoryPointcutAdvisor
https://github.com/mbechler/marshalsec
这下思路就非常清晰了,整个利用链如下
注册->使用AutoBuilding越权登陆->使用headimg的ssrf配合crlf向redis中写入序列化数据->check.do反序列化->RCE
完整exp如下
java 解析sh文件内容_java 文件读取相关推荐
- java 读取文件内容_Java如何读取txt文件的内容?
这个并不困难,大概的步骤是这样的: TXT是一个文本文件,一般采用流的方式读取: java提供了一个FileInputStream,我们可以直接以文件路径构造这个流,也可以以文件对象构造他,如:Fil ...
- java 读文件 二进制_JAVA中读取文件(二进制,字符)内容的几种方法总结
JAVA中读取文件内容的方法有很多,比如按字节读取文件内容,按字符读取文件内容,按行读取文件内容,随机读取文件内容等方法,本文就以上方法的具体实现给出代码,需要的可以直接复制使用 public cla ...
- python读文件每一行-Python文件内容按行读取到列表中
Python文件内容按行读取到列表中 示例文件内容如下: Hello World Python 通常来讲,我们如果只是迭代文件对象每一行,并做一些处理,是不需要将文件对象转成列表的,因为文件对象本身可 ...
- Java解析魔兽争霸3录像W3G文件(五):Action和APM计算
在游戏进行中,玩家会进行各种操作,例如编队.移动.技能.造建筑等,这些操作就是Action.APM(Actions Per Minute),表示每分钟的操作次数,APM可以很好的反映玩家的手速和实力, ...
- linux命令看文件内容,Linux文件内容查看相关命令
1.more命令 在Linux中,more命令是一个基于vi编辑器的文本过滤器,它能以全屏的方式按页显示文本文件的内容,more里面内置了一些快捷键. (1)命令语法 more(选项)(参数) (2) ...
- 比Everything更强的文件搜索工具,支持文件名、文件内容和文件图片上的文字搜索,文件内容搜索工具,文件图片内容搜索工具,OCR图片文本识别搜索,文件快速搜索工具,文字识别文件搜索工具
Windows自带的文件搜索功能想必不需要过多吐槽,搜索速度简直是在龟爬,所以小编很早之前就在用Everything进行文件搜索了,不过,今天的主角不是它,而是比它更更更更更强的一款软件! 这款软件适 ...
- 无法确定本地文件类型_如何从文件内容确定文件类型
无法确定本地文件类型 I. Introduction 一,引言 There's an interesting discussion going on now in an Experts Exchang ...
- java ftp读取文件内容_java读取ftp中TXT文件的案例
最近在开发关于java读取ftp中TXT文件,其中有些坑踩了一下,再次做个记录 1.读取文件时我会根据文件名称去生成数据库表,oracle数据库对于表名的长度是有限制的,最多30个字符 2.对于多个文 ...
- java 按行读取大文件文件内容_Java实现按行读取大文件
Java实现按行读取大文件 String file = "F:" + File.separator + "a.txt"; FileInputStream fis ...
最新文章
- 后备干部,究竟应该提拔什么样的员工?
- 个人IHttpHandler,IHttpModule认识
- php 数组 组成新数组,PHP让数组中相同值的组组成新的数组详解
- excel合并两列内容_还在为合并WPS表格(Excel)中两列内容而犯愁?此方法简单高效...
- 基于智慧教室|无纸化会议的新选择:RTMP解决方案
- java 接口 设计模式吗_JAVA接口设计模式-工厂模式
- android excel布局,Androidui布局控件(2)表格布局excelPanel
- A3C的算法原理和算法流程
- 遍历JSON的三种方法
- APP银联支付(微信、支付宝、云闪付)
- navicat mysql 数据库备份_怎么用navicat自动备份mysql数据库
- 老挑毛u盘一键装系统计算机意外地,u盘装系统 重装Win7系统出现提示计算机意外的重新启动或遇到错误怎么处理 我已经删除了所有分...
- *4-2 CCF 2014-12-2 Z字形扫描
- HTML+CSS大作业 电影网站设计——电影介绍(11页) 大学生电影网页作品 电影网页设计作业模板 学生网页制作源代码下载
- 算法训练营 图的应用(最小生成树)
- 输出姓名对应的电话号码C语言,C语言电话本程序(只是简单的姓名和电话号码增删改查),在线等...
- 高德坐标与谷歌坐标互相转换
- springboot+flyway+oracle11g+mysql8 整合包
- 1248. 统计「优美子数组」 前缀和
- 要给视频批量添加背景音乐该怎么办?