警告
本文最后更新于 2022-09-01 ,文中内容可能已过时。
ByteCodeDL也是一款java字节码静态分析工具,它借助了soot-fact-generator + Souffle 两个工具实现了一款声明式的静态分析工具。
声明式和命令式概念参见 https://www.aqee.net/post/imperative-vs-declarative/
其中soot-fact-generator的作用在于为souffle生成fact事实,也就是生成数据集。
souffle根据facts以及我们给定的规则语句(以.dl
为后缀的文件)来进行查询。
ByteCodeDL为我们编写了一些已经写好的规则,比如callgraph/cha(Class hierarchy analysis)/PTA指针分析及P/Taint
污点分析等,可以根据自己需求编写相应dl文件实现静态分析。规则文件移步 https://github.com/BytecodeDL/ByteCodeDL/tree/main/logic
关于Datalog-Based Program Analysis这部分的原理应该先看李樾和谭添老师的ppt https://pascal-group.bitbucket.io/lectures/Datalog.pdf
本文只是根据文档过一遍,带读者简单了解bytecodedl。
安装souffle 见https://souffle-lang.github.io/install
1
2
3
4
sudo wget https://souffle-lang.github.io/ppa/souffle-key.public -O /usr/share/keyrings/souffle-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/souffle-archive-keyring.gpg] https://souffle-lang.github.io/ppa/ubuntu/ stable main" | sudo tee /etc/apt/sources.list.d/souffle.list
sudo apt update
sudo apt install souffle
然后下载BytecodeDL打包好的soot-fact-generator.jar
以官方给的例子来看 https://souffle-lang.github.io/simple
给定一个edge.facts如下
再给定一个example.dl
1
2
3
4
5
6
7
8
.decl edge(x:number, y:number)
.input edge
.decl path(x:number, y:number)
.output path
path(x, y) :- edge(x, y).
path(x, y) :- path(x, z), edge(z, y).
其中两个.decl
分别表示input、output传入传出关系,这表示从磁盘读入edge.facts并将path.csv结果集写入磁盘。
path(x, y) :- edge(x, y).
表示:如果存在x->y的一条edge边,那么就存在x->y的一条path路径。
path(x, y) :- path(x, z), edge(z, y).
则表示:如果x到z有条路径,并且z到y有条边,那么就可以推理出x到y也有路径。
我们使用souffle查询一下看看结果。
1
2
3
4
5
6
7
8
ubuntu@ubuntu:~$ cat edge.facts
1 2
2 3
ubuntu@ubuntu:~$ souffle -F. -D. example.dl
ubuntu@ubuntu:~$ cat path.csv
1 2
2 3
1 3
输出了三条路径
这是最简单的一个demo,而soot-fact-generator则是用来生成facts的。
ByteCodeDL提供的soot-fact-generator是来自于另一个静态分析框架 https://bitbucket.org/yanniss/doop/src/master/generators/
doop本身就是使用souffle来做Java Pointer and Taint Analysis的工具,并且其本身有一些分析规则https://bitbucket.org/yanniss/doop/src/master/souffle-logic/
ByteCodeDL将doop的generator提取了出来,用doop的代码来生成facts。
然后自己写规则实现功能。
这节我们用 https://github.com/BytecodeDL/Benchmark 来生成facts数据集。
下载https://github.com/BytecodeDL/Benchmark 然后maven package。
运行soot-fact-generator
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
ubuntu@ubuntu:~$ java -jar soot-fact-generator.jar -i Benchmark-1.0-SNAPSHOT.jar -l /usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/rt.jar --generate-jimple --allow-phantom --full -d out
No logs directory set, using: out/logs
Logging initialized, using directory: out/logs
WARNING: 'file.encoding' property missing or not UTF8, please pass: -Dfile.encoding= UTF-8
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder" .
SLF4J: Defaulting to no-operation ( NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
WARNING: SSA not enabled, generating Jimple instead of Shimple
Preprocessing application: Benchmark-1.0-SNAPSHOT.jar
Preprocessing platform library: /usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/rt.jar
Adding archive: Benchmark-1.0-SNAPSHOT.jar
Adding archive for resolving: /usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/rt.jar
Classes in input ( application) jar( s) : 85
Total classes in Scene: 3695
Retrieved all bodies ( time: 11)
Fact generation cores: 16
WARNING: some classes were not resolved, consider using thorough fact generation or adding them manually via --also-resolve: [ sun.util.locale.provider.HostLocaleProviderAdapterImpl, java.lang.annotation.Inherited]
Found 74 phantom references. Rerun with '--report-phantoms' for more details.
Total classes ( application, dependencies and SDK) to generate Jimple for : 3695
Soot: hierarchy_dirs set.
Methods without active bodies encountered ( and reset) : 0
在out目录下会生成facts文件
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
ubuntu@ubuntu:~$ find out/*.facts
out/Activity.facts
out/ActualParam.facts
out/AndroidApplication.facts
out/AndroidCallbackMethodName.facts
out/AndroidEntryPoint.facts
out/AndroidId.facts
out/AndroidIncludeXML.facts
out/AnnotationElement.facts
out/ApplicationClass.facts
out/ApplicationPackage.facts
out/ArrayAllocationConstSize.facts
out/ArrayAllocation.facts
out/ArrayInitialValueFromConst.facts
out/ArrayInitialValueFromLocal.facts
out/ArrayInsnIndex.facts
out/ArrayNumIndex.facts
out/ArrayType.facts
out/AssignBinop.facts
out/AssignCast.facts
out/AssignCastNull.facts
out/AssignCastNumConstant.facts
out/AssignHeapAllocation.facts
out/AssignInstanceOf.facts
out/AssignLocal.facts
out/AssignNull.facts
out/AssignNumConstant.facts
out/AssignOperFromConstant.facts
out/AssignOperFrom.facts
out/AssignPhantomInvoke.facts
out/AssignReturnValue.facts
out/AssignUnop.facts
out/BootstrapParam.facts
out/BreakpointStmt.facts
out/BroadcastReceiver.facts
out/Class-Artifact.facts
out/ClassHeap.facts
out/ClassModifier.facts
out/ClassType.facts
out/ComponentType.facts
out/ContentProvider.facts
out/DexInstructionAddressMap.facts
out/DirectSuperclass.facts
out/DirectSuperinterface.facts
out/DummyIfVar.facts
out/DynamicMethodInvocation.facts
out/DynamicMethodInvocation-ParamType.facts
out/EmptyArray.facts
out/EnterMonitor.facts
out/ExceptionHandler.facts
out/ExceptionHandler-FormalParam.facts
out/ExceptionHandler-Previous.facts
out/ExitMonitor.facts
out/Field-Annotation.facts
out/Field.facts
out/FieldInitialValue.facts
out/Field-Modifier.facts
out/FormalParam.facts
out/GenericField.facts
out/GenericType-ErasedType.facts
out/GenericTypeParameters.facts
out/Goto.facts
out/IfConstant.facts
out/If.facts
out/IfVar.facts
out/InterfaceType.facts
out/LayoutControl.facts
out/LoadArrayIndex.facts
out/LoadInstanceField.facts
out/LoadStaticField.facts
out/LookupSwitch-Default.facts
out/LookupSwitch.facts
out/LookupSwitch-Target.facts
out/Method-Annotation.facts
out/Method-DeclaresException.facts
out/Method.facts
out/MethodHandleConstant.facts
out/MethodInvocation-Line.facts
out/Method-Modifier.facts
out/MethodTypeConstant.facts
out/MethodTypeConstantParam.facts
out/NativeLibEntryPoint.facts
out/NativeMethodId.facts
out/NativeMethodTypeCandidate.facts
out/NativeNameCandidate.facts
out/NativeReturnVar.facts
out/NativeXRef.facts
out/NormalHeap.facts
out/NumConstantRaw.facts
out/OperatorAt.facts
out/Param-Annotation.facts
out/PhantomBasedMethod.facts
out/PhantomMethod.facts
out/PhantomType.facts
out/PolymorphicInvocation.facts
out/Properties.facts
out/Return.facts
out/ReturnVoid.facts
out/SensitiveLayoutControl.facts
out/Service.facts
out/SpecialMethodInvocation.facts
out/StatementType.facts
out/StaticMethodInvocation.facts
out/StoreArrayIndex.facts
out/StoreInstanceField.facts
out/StoreStaticField.facts
out/StringConstant.facts
out/StringRaw.facts
out/SuperMethodInvocation.facts
out/TableSwitch-Default.facts
out/TableSwitch.facts
out/TableSwitch-Target.facts
out/ThisVar.facts
out/Throw.facts
out/ThrowNull.facts
out/Type-Annotation.facts
out/Type-SimpleName.facts
out/UnsupportedInstruction.facts
out/Var-DeclaringMethod.facts
out/Var-SimpleName.facts
out/Var-Type.facts
out/VirtualMethodInvocation.facts
out/XMLNodeAttribute.facts
out/XMLNodeData.facts
out/XMLNode.facts
其中每个facts文件对应了不同的关系,比如Method.facts
1
2
3
4
5
6
7
8
9
10
11
ubuntu@ubuntu:~$ cat out/Method.facts| head -10
<java.net.ProxySelector: void <init>() > <init> java.net.ProxySelector void () V 0
<java.lang.invoke.MethodHandleImpl$CountingWrapper : void <init>( java.lang.invoke.MethodHandle,java.lang.invoke.LambdaForm,java.util.function.Function,java.util.function.Function,int) > <init> java.lang.invoke.MethodHandle,java.lang.invoke.LambdaForm,java.util.function.Function,java.util.function.Function,int java.lang.invoke.MethodHandleImpl$CountingWrapper void ( Ljava/lang/invoke/MethodHandle; Ljava/lang/invoke/LambdaForm; Ljava/util/function/Function; Ljava/util/function/Function; I) V 5
<sun.text.normalizer.UBiDiProps$IsAcceptable : void <init>( sun.text.normalizer.UBiDiProps) > <init> sun.text.normalizer.UBiDiProps sun.text.normalizer.UBiDiProps$IsAcceptable void ( Lsun/text/normalizer/UBiDiProps; ) V 1
<java.lang.UNIXProcess$Platform : java.lang.UNIXProcess$Platform [] values() > values java.lang.UNIXProcess$Platform java.lang.UNIXProcess$Platform [] ()[ Ljava/lang/UNIXProcess$Platform ; 0
<sun.invoke.util.VerifyAccess: void <init>() > <init> sun.invoke.util.VerifyAccess void () V 0
<java.util.WeakHashMap$KeySpliterator : void <init>( java.util.WeakHashMap,int,int,int,int) > <init> java.util.WeakHashMap,int,int,int,int java.util.WeakHashMap$KeySpliterator void ( Ljava/util/WeakHashMap; IIII) V 5
<java.util.stream.Tripwire: void <init>() > <init> java.util.stream.Tripwire void () V 0
<java.util.BitSet: int wordIndex( int) > wordIndex int java.util.BitSet int ( I) I 1
<sun.invoke.util.VerifyAccess: boolean isMemberAccessible( java.lang.Class,java.lang.Class,int,java.lang.Class,int) > isMemberAccessible java.lang.Class,java.lang.Class,int,java.lang.Class,int sun.invoke.util.VerifyAccess boolean ( Ljava/lang/Class; Ljava/lang/Class; ILjava/lang/Class; I) Z 5
<java.net.ProxySelector: java.net.ProxySelector getDefault() > getDefault java.net.ProxySelector java.net.ProxySelector () Ljava/net/ProxySelector; 0
facts默认用\t
做分隔符,抽出一行来看
1
<sun.invoke.util.VerifyAccess: boolean isMemberAccessible(java.lang.Class,java.lang.Class,int,java.lang.Class,int)> isMemberAccessible java.lang.Class,java.lang.Class,int,java.lang.Class,int sun.invoke.util.VerifyAccess boolean (Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class;I)Z 5
这行对应sun.invoke.util.VerifyAccess#isMemberAccessible
,以\t
分隔每一列又对应到函数的不同属性。
再者说MethodInvocation-Line.facts
1
2
3
4
5
6
7
8
9
10
11
ubuntu@ubuntu:~$ cat out/MethodInvocation-Line.facts |head -10
<sun.invoke.util.VerifyAccess: void <init>()>/java.lang.Object.<init>/0 38
<java.net.ProxySelector: void <init>()>/java.lang.Object.<init>/0 60
<java.util.stream.Tripwire: void <init>()>/java.lang.Object.<init>/0 55
<java.util.WeakHashMap$KeySpliterator: void <init>(java.util.WeakHashMap,int,int,int,int)>/java.util.WeakHashMap$WeakHashMapSpliterator.<init>/0 1102
<sun.text.normalizer.UBiDiProps$IsAcceptable: void <init>(sun.text.normalizer.UBiDiProps)>/java.lang.Object.<init>/0 107
<java.lang.UNIXProcess$Platform: java.lang.UNIXProcess$Platform[] values()>/java.lang.Object.clone/0 81
<java.net.ProxySelector: java.net.ProxySelector getDefault()>/java.lang.System.getSecurityManager/0 92
<java.lang.invoke.MethodHandleImpl$CountingWrapper: void <init>(java.lang.invoke.MethodHandle,java.lang.invoke.LambdaForm,java.util.function.Function,java.util.function.Function,int)>/java.lang.invoke.MethodHandle.type/0 810
<java.lang.invoke.MethodHandleImpl$CountingWrapper: void <init>(java.lang.invoke.MethodHandle,java.lang.invoke.LambdaForm,java.util.function.Function,java.util.function.Function,int)>/java.lang.invoke.DelegatingMethodHandle.<init>/0 810
<java.net.ProxySelector: java.net.ProxySelector getDefault()>/java.lang.SecurityManager.checkPermission/0 94
记录了method call的行号。
那么通过facts文件我们就有了静态软件分析中所需要的东西。
soot-fact-generator.jar 为我们提供了各种所需要的结果集
我们一步一步来实现静态分析。
从基本的Class Hierarchy开始,我们需要构建一个类型层次图,用于寻找某个类的子类、父类,或者用于判断两个类之间是否有继承关系。
generator为我们生成了facts结果集
1
2
3
4
5
6
7
8
9
10
11
ubuntu@ubuntu:~$ cat out/DirectSuperclass.facts | head -10
java.lang.UNIXProcess$Platform java.lang.Enum
sun.text.normalizer.UBiDiProps$IsAcceptable java.lang.Object
java.net.ProxySelector java.lang.Object
java.lang.invoke.MethodHandleImpl$CountingWrapper java.lang.invoke.DelegatingMethodHandle
java.util.WeakHashMap$KeySpliterator java.util.WeakHashMap$WeakHashMapSpliterator
java.util.BitSet java.lang.Object
sun.invoke.util.VerifyAccess java.lang.Object
java.util.stream.Tripwire java.lang.Object
sun.text.normalizer.ReplaceableString java.lang.Object
java.net.StandardSocketOptions java.lang.Object
可以看到具体的继承关系。extend对应的是DirectSuperclass.facts,implement对应的是DirectSuperinterface.facts。
1
2
3
4
5
6
7
.type Class <: symbol
.decl DirectSuperclass(child:Class, parent:Class)
.input DirectSuperclass
.decl DirectSuperinterface(child:Class, parent:Class)
.input DirectSuperinterface
递归判断子类关系
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
.type Class <: symbol
.decl ClassModifier(mod:symbol, class:Class)
.input ClassModifier
.decl ClassType(class:Class)
.input ClassType
.decl InterfaceType(interface:Class)
.input InterfaceType
.decl DirectSuperclass(child:Class, parent:Class)
.input DirectSuperclass
.decl DirectSuperinterface(child:Class, parent:Class)
.input DirectSuperinterface
.decl SubClass(subclass:Class, class:Class)
.output SubClass
SubClass(subclass, class) :- DirectSuperclass(subclass, class).
SubClass(subclass, class) :- DirectSuperinterface(subclass, class).
SubClass(subclass, class) :-
(
DirectSuperclass(subclass, tmp);
DirectSuperinterface(subclass, tmp)
),
SubClass(tmp, class).
运行并且查看输出结果
1
2
3
4
5
6
7
8
9
10
11
ubuntu@ubuntu:~$ souffle -F out/ -D . example.dl ; cat SubClass.csv |head -n 10
java.lang.UNIXProcess$Platform java.lang.Enum
java.lang.UNIXProcess$Platform java.lang.Object
java.lang.UNIXProcess$Platform java.io.Serializable
java.lang.UNIXProcess$Platform java.lang.Comparable
java.lang.Enum java.lang.Object
java.lang.Enum java.io.Serializable
java.lang.Enum java.lang.Comparable
sun.text.normalizer.UBiDiProps$IsAcceptable java.lang.Object
sun.text.normalizer.UBiDiProps$IsAcceptable sun.text.normalizer.ICUBinary$Authenticate
java.net.ProxySelector java.lang.Object
对于static call和special call都是在编译时就确定调用者的具体类型的,而virtual call需要在实际运行时根据obj的实际类型判断函数调用。由此一来如何确定obj的运行时类型,成为了调用图构造的关键。
对于cha算法而言
receiver在实际运行的过程中的类型可以是其声明类型的任意非abstract子类。所以我们需要一个Dispatch来进行method dispatch。
这里直接贴ByteCodeDL的文档 https://github.com/BytecodeDL/ByteCodeDL/blob/main/docs/utils.md#method-dispatch
1
2
3
4
5
6
7
8
9
Dispatch(simplename, descriptor, class, method) :-
MethodInfo(method, simplename, _, class, _, descriptor, _),
!MethodModifier("abstract", method).
Dispatch(simplename, descriptor, class, method) :-
!MethodInfo(_, simplename, _, class, _, descriptor, _),
DirectSuperclass(class, superclass),
Dispatch(simplename, descriptor, superclass, method),
!MethodModifier("abstract", method).
第一个Dispatch表示如果class中有签名相对并且修饰符不为abstract的method则返回method,第二个Dispatch表示如果没从当前class中找到method则去从该class的superclass中寻找对应签名并且不是abstract的method。
有了dispatch之后就可以实现cha调用图了,代码还是直接看https://github.com/BytecodeDL/ByteCodeDL/blob/main/logic/cha.dl
还有一个rta算法,不在这里写了,直接看文档 ,ByteCodeDL也实现了。
针对不同的需求,我们需要找特定类,那么这个时候cha调用图就比较有用了。
官方文档以ezchain hfctf2022为例,讲解了cha的实际使用。该ctf给了一个getter,禁用已知链,让自己找getter来rce。
那么有了如下代码
用SinkDesc声明我们要的sink
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
#define MAXSTEP 5
#define CHAO 2
#include "../logic/cha.dl"
. decl NonParamPublicMethod ( method : Method , class : Class )
. output NonParamPublicMethod
SinkDesc ( "exec" , "java.lang.Runtime" ) .
SinkDesc ( "<init>" , "java.lang.ProcessBuilder" ) .
SinkDesc ( "start" , "java.lang.ProcessImpl" ) .
SinkDesc ( "loadClass" , "java.lang.ClassLoader" ) .
SinkDesc ( "defineClass" , "java.lang.ClassLoader" ) .
SinkDesc ( "readObject" , "java.io.ObjectInputStream" ) .
SinkDesc ( "readExternal" , "java.io.ObjectInputStream" ) .
EntryMethod ( method ),
Reachable ( method , 0 ),
NonParamPublicMethod ( method , class ) : -
MethodInfo ( method , simplename , _ , class , _ , _ , arity ),
MethodModifier ( "public" , method ),
contains ( "get" , simplename ),
arity = 0.
. output SinkMethod
找到entry为<java.security.SignedObject: java.lang.Object getObject()>
的method
可以将结果导入到neo4j中进行可视化。
1
bash importOutput2Neo4j.sh neoImportCall.sh dbname
不演示了
这里提一嘴,相对tabby来讲,ByteCodeDL使用souffle减少了输入源,更快。用了指针分析,更准。
缺点也很明显,语法更变态,自定义规则头发直接掉完,文档少、规则库不够完善,门槛比tabby高太多。
这里算法我讲不明白了,直接看ByteCodeDL文档把。
指针分析的一个简单例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "inputDeclaration.dl"
#include "utils.dl"
#include "pt-noctx.dl"
// 实例化 component
.init cipt = ContextInsensitivePt
// 初始化readchable
cipt.Reachable(method) :-
MethodInfo(method, simplename, _, _, _, descriptor, _),
simplename = "main",
descriptor = "([Ljava/lang/String;)V".
.output cipt.VarPointsTo
这样可以查询出method name为main并且函数签名是([Ljava/lang/String;)V
的函数,可以传播到的点结果集。
截出一部分结果集来看
1
2
3
4
5
6
7
8
9
10
<com.bytecodedl.benchmark.demo.TaintDemo1: void main(java.lang.String[])>/new com.bytecodedl.benchmark.demo.TaintDemo1/0 <com.bytecodedl.benchmark.demo.TaintDemo1: void <init>()>/@this
<com.bytecodedl.benchmark.demo.TaintDemo1: void main(java.lang.String[])>/new com.bytecodedl.benchmark.demo.TaintDemo1/0 <com.bytecodedl.benchmark.demo.TaintDemo1: void <init>()>/this#_0
<com.bytecodedl.benchmark.demo.TaintDemo1: void main(java.lang.String[])>/new com.bytecodedl.benchmark.demo.TaintDemo1/0 <com.bytecodedl.benchmark.demo.TaintDemo1: void main(java.lang.String[])>/demo#_8
<com.bytecodedl.benchmark.demo.TaintDemo1: void main(java.lang.String[])>/new com.bytecodedl.benchmark.demo.TaintDemo1/0 <com.bytecodedl.benchmark.demo.TaintDemo1: void test1(java.lang.String)>/@this
<com.bytecodedl.benchmark.demo.TaintDemo1: void main(java.lang.String[])>/new com.bytecodedl.benchmark.demo.TaintDemo1/0 <com.bytecodedl.benchmark.demo.TaintDemo1: void test1(java.lang.String)>/this#_0
<com.bytecodedl.benchmark.demo.TaintDemo1: void main(java.lang.String[])>/new com.bytecodedl.benchmark.demo.TaintDemo1/0 <com.bytecodedl.benchmark.demo.TaintDemo1: void Sink(java.lang.String)>/@this
<com.bytecodedl.benchmark.demo.TaintDemo1: void main(java.lang.String[])>/new com.bytecodedl.benchmark.demo.TaintDemo1/0 <com.bytecodedl.benchmark.demo.TaintDemo1: void Sink(java.lang.String)>/this#_0
<com.bytecodedl.benchmark.demo.TaintDemo1: void Sink(java.lang.String)>/new java.lang.StringBuilder/0 <com.bytecodedl.benchmark.demo.TaintDemo1: void Sink(java.lang.String)>/builder#_19
<com.bytecodedl.benchmark.demo.TaintDemo1: void main(java.lang.String[])>/new com.bytecodedl.benchmark.demo.TaintDemo1/0 <com.bytecodedl.benchmark.demo.TaintDemo1: java.lang.String Source()>/@this
<com.bytecodedl.benchmark.demo.TaintDemo1: void main(java.lang.String[])>/new com.bytecodedl.benchmark.demo.TaintDemo1/0 <com.bytecodedl.benchmark.demo.TaintDemo1: java.lang.String Source()>/this#_0
对应的代码为
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.bytecodedl.benchmark.demo ;
public class TaintDemo1 {
public static void main ( String [] args ) {
TaintDemo1 demo = new TaintDemo1 ();
String name = demo . Source ();
demo . test1 ( name );
}
public void test1 ( String name ){
String sql = "select * from user where name='" + name + "'" ;
Sink ( sql );
}
public void Sink ( String param ){
StringBuilder builder = new StringBuilder ();
builder . append ( param );
}
public String Source (){
return "tainted name" ;
}
}
没啥问题。
这里不详细写了,直接贴我在官方GitHub的discussions
使用ByteCodeDL分析长城杯CTF b4bycoffee 我只是给官方作者提需求,规则还是作者写的。
文笔垃圾,措辞轻浮,内容浅显,操作生疏。不足之处欢迎大师傅们指点和纠正,感激不尽。