Cypher语法
本次使用tabby来分析相关利用链子,会用到Cypher的相关语句,
如以下语句是查询readobject被谁调用,深度为5,查询20条链,
match (source:Method {NAME:"readObject"})
match (sink:Method {NAME:"put", CLASSNAME:"java.util.Hashtable"})<-[:CALL]-(m1:Method)
call apoc.algo.allSimplePaths(source, m1, "ALIAS>|CALL>", 5) yield path
return * limit 20
通过寻找equals函数到toString函数的链子,其中source点可序列化
match (source:Method)<-[:HAS]-(c:Class)-[:INTERFACE|EXTENDS*]->(c1:Class {NAME:"java.io.Serializable"})
where source.NAME in ["equals"]
and source.CLASSNAME in ["com.fr.esd.query.DSQueryEntity"]
match (sink:Method {NAME:"toString"})<-[:CALL]-(m1:Method)
call apoc.algo.allSimplePaths(source, m1, "ALIAS>|CALL>", 2) yield path
return * limit 2
可设置多个source点,然后定义最终的sink点,
match (source:Method) where source.NAME in ["equals","hashCode","compareTo"]
match (sink:Method {NAME:"toString"})<-[:CALL]-(m1:Method)
call apoc.algo.allSimplePaths(source, m1, "ALIAS>|CALL>", 5) yield path
return * limit 1
分析
在分析过程中,可以根据以下草稿,这里可以利用正则去匹配,不过费时费力,因此可以去使用tabby来分析,
入口hashmap,hashtable
hashcode() equals(key) tostring() m.get(key) readobject()
最终调用到tostring
正则表达式: hashcode(((?!public)[sS]){1,1000}[.]toString
readobject(((?!public)[sS]){1,1000}[.](toString|put|compareto|getValue|getkey)
hashcode+tostring
readobject+tostring
get+tostring
equals+tostring
readobject->put
readobject->put
StringComparator
TreeMap.put->compare->compareto+tostring
TreeMap.put->compare->compareto->getValue+tostring
TreeMap.put->compare->compareto->getkey+tostring
(readobject|hashcode|equals)(((?!public)[sS]){1,1000}[.]put(
第二希望在equals找到put
第一希望hashcode->getValue->tostring
查找equals->...->toString,
match (source:Method)<-[:HAS]-(c:Class)-[:INTERFACE|EXTENDS*]->(c1:Class {NAME:"java.io.Serializable"})
where source.NAME in ["equals"]
match (sink:Method {NAME:"toString", CLASSNAME:"java.lang.Object"})<-[:CALL]-(m1:Method)
call apoc.algo.allSimplePaths(source, m1, "ALIAS>|CALL>", 7) yield path
where none(n in nodes(path) where n.CLASSNAME in ["com.fr.esd.query.DSQueryEntity", "com.fr.base.PaperSize", "java.util.EnumMap", "java.time.temporal.WeekFields", "sun.security.util.DerValue", "sun.security.x509.AlgorithmId", "java.util.concurrent.ConcurrentHashMap", "java.util.Hashtable", "com.fr.file.CacheManager$DBKey4Procedure", "com.fr.third.jgroups.stack.RouterStubManager$Target", "javax.security.auth.Subject", "java.lang.String", "sun.security.x509.CertificateExtensions", "com.fr.retry.Predicates$IsEqualToPredicate", "java.text.AttributedCharacterIterator$Attribute", "sun.security.x509.CRLExtensions", "java.util.AbstractMap", "com.fr.plugin.basic.CloseableUtils", "com.fr.data.dao.ClassArrayKey$KEY", "com.fr.base.headerfooter.TextHFElement", "com.fr.stable.version.ProductVersion", "com.fr.cluster.engine.member.persistence.FineClusterNode", "java.util.jar.Attributes$Name", "java.lang.reflect.WeakCache$CacheValue", "java.lang.reflect.WeakCache$LookupValue", "sun.security.x509.OtherName"])
return * limit 20
查找hashCode->...->toString,
match (source:Method)<-[:HAS]-(c:Class)-[:INTERFACE|EXTENDS*]->(c1:Class {NAME:"java.io.Serializable"})
where source.NAME in ["hashCode"]
match (sink:Method {NAME:"toString", CLASSNAME:"java.lang.Object"})<-[:CALL]-(m1:Method)
call apoc.algo.allSimplePaths(source, m1, "ALIAS>|CALL>", 5) yield path
where none(n in nodes(path) where n.CLASSNAME in ["com.fr.esd.query.DSQueryEntity", "java.util.concurrent.ConcurrentHashMap$KeySetView", "sun.security.util.DerValue"])
return * limit 20
查找get->...->toString,
match (source:Method)<-[:HAS]-(c:Class)-[:INTERFACE|EXTENDS*]->(c1:Class {NAME:"java.io.Serializable"})
where source.NAME in ["get"]
match (sink:Method {NAME:"toString", CLASSNAME:"java.lang.Object"})<-[:CALL]-(m1:Method)
call apoc.algo.allSimplePaths(source, m1, "ALIAS>|CALL>", 5) yield path
where none(n in nodes(path) where n.CLASSNAME in ["java.time.LocalDate", "com.fr.esd.query.DSQueryEntity", "java.time.temporal.TemporalAccessor"])
return * limit 20
查找readobject->...->toString,
match (source:Method)<-[:HAS]-(c:Class)-[:INTERFACE|EXTENDS*]->(c1:Class {NAME:"java.io.Serializable"})
where source.NAME in ["readObject"]
match (sink:Method {NAME:"toString", CLASSNAME:"java.lang.Object"})<-[:CALL]-(m1:Method)
call apoc.algo.allSimplePaths(source, m1, "ALIAS>|CALL>", 6) yield path
where none(n in nodes(path) where n.CLASSNAME in ["com.fr.esd.query.DSQueryEntity", "java.security.Provider", "java.security.PermissionsHash", "java.security.Permissions", "java.util.PropertyPermissionCollection", "java.security.BasicPermissionCollection", "java.util.EnumMap", "java.io.FilePermissionCollection", "sun.security.util.DerValue", "java.util.concurrent.ConcurrentHashMap", "java.util.Locale", "com.fr.base.headerfooter.ImageHFElement", "java.lang.StringBuilder", "java.text.DecimalFormatSymbols", "com.fr.swift.adaptor.log.SqlConverter$8", "java.util.Hashtable"])
return * limit 20
以上的limit 20为深度,可从1开始调节,逐渐去排除利用链中不相关的节点,
因此尝试利用tabby来绕某系统的黑名单,最主要是找到一条能触发到toString的链子,
利用tabby查询到中间的这条链子,上面的get肯定是行不通的,
因此调试以下链能走到hashtable.equals,
package org.example;
import com.fr.base.PaperSize;
import com.fr.base.Parameter;
import com.fr.chart.chartdata.JSONTableData;
import com.fr.esd.query.DSQueryEntity;
import com.fr.json.revise.EncodeException;
import com.fr.script.CalculatorMap;
import com.fr.serialization.JDKSerializer;
import com.fr.third.alibaba.druid.pool.DruidAbstractDataSource;
import com.fr.third.alibaba.druid.pool.DruidDataSource;
import com.fr.third.alibaba.druid.pool.xa.DruidXADataSource;
import com.fasterxml.jackson.databind.node.POJONode;
import com.fr.third.fasterxml.jackson.databind.ObjectMapper;
import com.fr.third.fasterxml.jackson.databind.SerializationFeature;
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 com.sun.org.apache.xpath.internal.objects.XString;
import javassist.*;
import oracle.jdbc.rowset.OracleCachedRowSet;
import org.apache.arrow.vector.util.JsonStringArrayList;
import org.apache.commons.collections4.FunctorException;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.InvokerTransformer;
import javax.swing.UIDefaults;
import javax.management.BadAttributeValueExpException;
import com.fr.json.JSONArray;
import org.jcodings.util.Hash;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Signature;
import java.security.SignedObject;
import java.sql.SQLException;
import java.util.*;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
public class Main {
public static void main(String[] args) throws NotSerializableException, EncodeException, IllegalAccessException, NoSuchFieldException, NotFoundException, CannotCompileException, IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, SQLException {
HashMap hashmap_c_1 = new HashMap();
hashmap_c_1.put("8", "8");
HashMap hashmap_c_2 = new HashMap();
hashmap_c_2.put("8", "8");
CalculatorMap calculatorMap_1 = CalculatorMap.create(hashmap_c_1);
CalculatorMap calculatorMap_2 = CalculatorMap.create(hashmap_c_2);
Hashtable<Object,Object> hashtable_a = new Hashtable<>();
Hashtable<Object,Object> hashtable_b = new Hashtable<>();
hashtable_a.put(calculatorMap_1, 3);
hashtable_b.put(calculatorMap_2, 3);
HashMap hashmap_1 = new HashMap();
HashMap hashmap_2 = new HashMap();
hashmap_1.put(hashtable_a, hashtable_a);
hashmap_2.put(hashtable_b, hashtable_b);
/*
HashMap hashmap = new HashMap<>();
hashmap.put(calculatorMap_1, 3);
hashmap.put(calculatorMap_2, 3);
*/
Hashtable<Object,Object> hashtable = new Hashtable<>();
hashtable.put(hashmap_1, 3);
hashtable.put(hashmap_2, 3);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(hashtable);
byte[] bytes = byteArrayOutputStream.toByteArray();
System.out.println(Arrays.toString(byteArrayOutputStream.toByteArray()));
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
objectInputStream.readObject();
}
}
不过因为m.get(key)这里的返回值一直为null,没调式出来,
通过触发hashtable的equals函数,
尝试控制传入equals函数的参数,如果能控制,则能走到t.containskey(key),
最终走到CalculatorMap的toString函数,
栈堆如下,
总结:结果是失败的,不过对Cypher的相关语法更加了解了,也对tabby有了了解,后面更加熟练利用相关审计工具
感谢【tq]
来源:【某bi V 6.0.19 尝试绕过黑名单 - https://xz.aliyun.com/t/15110】
原文始发于微信公众号(船山信安):某bi V 6.0.19 尝试绕过黑名单
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论