《闭源系统下的漏洞自动化发现之旅.pdf》由会员分享,可在线阅读,更多相关《闭源系统下的漏洞自动化发现之旅.pdf(37页珍藏版)》请在三个皮匠报告上搜索。
1、闭源系统下的漏洞自动化发现之旅演讲人:秦策(Hearmen)关于我望潮实验室(南京)负责人专注移动安全、应用安全、二进制BlackHat、Defcon、HITB 等演讲者KCON2015 演讲者EvilParcel系统的银翼杀手01CodeQL打破源码限制02LLM模型助力漏洞挖掘03总结与展望04目录EvilParcelEvilparcel 漏洞是一类存在于 Android 系统中的漏洞,它们利用了 Parcelable 子类在序列化和反序列化过程中实现不匹配的问题Michalbednarski 首次发现此类漏洞并交给谷歌官方修复首次发现Michalbednarski 公开漏洞利用方法,研究
2、者开始陆续跟进,各大厂商的类此类漏洞也开始出现漏洞利用公开推出 LazyValue 机制,Bundle 中的每个 item 都会有单独的 lengthAndroid13 修复各个手机厂商自己的 ROM 并不能及时更新安卓官方依然接收此类漏洞安卓系统的碎片化EvilParcelEvilparcel 漏洞可以导致 Bundle 在多次序列化和反序列化过程中内容发生改变。结合 LAW 跳板,可以实现权限提升,严重影响系统安全将evilparcel放置在Bundle 中传给系统应用(settings)Bundle系统权限应用编写APK,实现添加账号回调bundle.getParcelable(“int
3、ent”)重新序列化sendResponse(bundle)攻击目的1:第一次序列化读让system_server找不到intent攻击目的2:第二次序列化读让settings可找到intent序列化读序列化读序列化写校验checkKeyIntent(intent)没有intentEvilParcelParcelable 类 writeToParcel 函数写入的数据在被 CREATOR.createFromParcel 读取时无法一一对应Parcel_key_namestringstringParcel_key_namestringstringstring序列化反序列化other_keyva
4、lueother_keyvalueparcel keyparcel keyparcel valueparcel valueother keyother valueanother keyanother valueParcel_key_namestringstringstring反序列化parcel keyparcel valueParcel_key_namestringstringstringother_keyvalue序列化parcel keyparcel valueother keyother valuestringother_keyvaluestringanother keyanother
5、 valueEvilParcel 分类writeToParcel 函数写入的数据被 createFromParcel 读取时不匹配漏洞原语01读和写均是顺序的,但是读和写的顺序或者类型不一致04读或写中存在分支语句,分支语言中包含 read 和 write,分支控制时考虑不当02写操作中存在 try-catch 且不抛出异常的情况03读操作中有读泛型的操作,且存在 try-catch 不抛出异常的情况05子类构造时调了父类的构造,用且父类构造函数调用了重载函数06对象序列化或者反序列化时对整个 parcel 进行了绝对位置操作EvilParcel Type#1!#$%&$()*+,-$./-%
6、0!$-0-/1)2(3&-$(#$-4!3%5(1-%/106(1(7/18 9.5-33%,-!#$%&5+%,:3%1-;+2(3&-$4!(3&-$?:3%1-+/A8B!#$%&5+%,3-(,C3+02(3&-$406(1(7/1D%/?3-(,7/18BB&$()*+,-$./-%0!$-0-/1)2(3&-$(#$-47/1-A-30E+1(1%+/8F+$-(/07)GH(3-,8!3+1-&1-,*+,-$./-40E+1(1%+/D%/?3-(,7/18B!#$%&)1(1%&I%/($J3-(1+3K*+,-$./-LJEMN;.ED/-:J3-(1+3K*+,-$./
7、-L49.5-33%,-!#$%&6-0+&3-(1-C3+02(3&-$43-13/-:*+,-$./-8BB89.5-33%,-!#$%&5+%,:3%1-;+2(3&-$4!(3&-$?:3%1-7/18!(3&-$?:3%1-7/18BB 读和写均是顺序的,但是读和写的顺序或者类型不一致EviParcel Type#2&$()*+,-$;:+-S1-/,)2(3&-$#($-4!3%5(1-C%$-0C%$-8!#$%&*+,-$;:+&3-(1-C3+02(3&-$4*+,-$;:+0D/-:*+,-$;:+80?0C%$-D/-:C%$-)+3&-?3-(,G13%/A83-13/
8、08B9.5-33%,-!#$%&5+%,:3%1-;+2(3&-$413T4,-)1?:3%1-G13%/A1H%)?0C%$-?A-1J(/+/%&($2(1H8B&(1&H4+A?-8BBB 写操作中存在 trycatch 且不抛出异常的情况EvilParcel Type#3&$()*+,-$;H3-S1-/,)2(3&-$#($-4!#$%&*+,-$;H3-&3-(1-C3+02(3&-$413T4*+,-$;H3-0D/-:*+,-$;H3-80?1PDJ$()?I+3X(0-)+3&-?3-(,G13%/A80?1YD)+3&-?3-(,7/183-13/08B&(1&H4+A?
9、-83-13/$8BBB 读操作中有读泛型的操作,且存在 try-catch 捕获异常不抛出Parcel_key_name!PackageManagerException!parcel keyparcel valuesystem_servertarget appPackageManagerException EvilParcel Type#4&$()*+,-$C+3-S1-/,)2(3&-$#($-4!3%5(1-7/1-A-30X08!3%5(1-N33(T%)1KL0JH(%/)8Z+3G+3&-41H%)?0X0D%/?3-(,7/18%/1/0JH(%/)D%/?3-(,7/18%I4
10、N33(T%)1KZ+3JH(%/L(33(T%)1D/-:N33(T%)1KL81H%)?0JH(%/)D(33(T%)18%/?3-(,2(3&-$(#$-%)1(33(T%)1=Z+3JH(%/?&$()?A-1J$()+(,-383-13/8B1H%)?0JH(%/)D/$8B!#$%&5+%,:3%1-;+2(3&-$4,-)1?:3%1-7/18N33(T%)1KZ+3JH(%/L(33(T%)1D1H%)?0JH(%/)8%I4,-)1?:3%1-7/183-13/8B,-)1?:3%1-7/1(33(T%)1?)%-8,-)1?:3%1-2(3&-$(#$-%)18BB 读或写
11、中存在分支语句,且分支语言中包含 read 和 write需要注意 createByteArray、readByteArray 和 readXXXXList 这种序列化时自动带上长度信息,且未作限制的情况!3%5(1-K;L%)1K;L3-(,2(3&-$(#$-%)17/1-3/($4I%/($%/1/D3-(,7/18%I4$%)1?&$-(383-13/$%)18BB!3%5(1-K;L%)1K;L3-(,2(3&-$(#$-%)17/1-3/($4%/1XD5($?)%-8%/1%DR8:3%1-7/18BEvilParcel Type#5class ModelFive extends
12、 Father CREATORpublic Client createFromParcel(Parcel source)return new ModelFive(source);public ModelFive(Parcel source)super(source);readFromParcel(source);#$%&()&public void readFromParcel(Parcel source)this.mProcessName=source.readInt();this.mPkgName=source.readInt();public void writeToParcel(Par
13、cel dest,int flag)super.writeToParcel(source);dest.WriteInt(this.mProcessName);dest.WriteInt(this.mPkgName);子类构造时调了父类的构造,用且父类构造函数调用了重写函数class Father implements Parcelable public Father(Parcel source)readFromParcel(source);public void readFromParcel(Parcel source)this.mEvent=source.readInt();public v
14、oid writeToParcel(Parcel dest,int flags)dest.writeInt(this.mEvent);1234EvilParcel Type#6&$()*+,-$G%S%0!$-0-/1)2(3&-$(#$-4!#$%&5+%,3-(,C3+02(3&-$41H%)?0M5-/1 D)+3&-?3-(,7/18B!#$%&5+%,:3%1-;+2(3&-$4,-)1?)-16(1(2+)%1%+/8,-)1?:3%1-7/18BB对象序列化或者反序列化时对整个 parcel 进行了绝对位置操作CodeQLCODEQL 是 GITHUB 开发的用于自动化安全检查的
15、代码分析引擎。CODEQL 可以根据已有漏洞快速查找相似问题CodeQL 简介CODEQL 中代码被作为数据进行存储,按照代码的逻辑组织成一个关系型数据库数据库中包含有代码的原始信息,抽象语法树信息,数据流信息,控制流信息CodeQL 原理CODEQL 针对编译型语言需要完整的可编译工程且由于静态分析的天然缺陷,查询结果会存在漏报和误报CodeQL 不足CODEQL 的使用可以分为三个步骤:1.根据源码工程创建数据库2.在数据库上运行QL 代码3.人工分析查询结果CodeQL 使用CodeQL构建JAVA数据库过程大多数 ROM 都是闭源的,我们无法获取厂商的源代码“For compiled
16、languages,extraction works by monitoring the normal build process.”codeql database create java-database-language=java-command=gradle-no-daemon clean testexec$CODEQL_JAVA_HOME/bin/java#执行构建$jvmArgs-add-modules jdk.unsupported-cp$CODEQL_DIST/tools/codeql.jar com.semmle.cli2.CodeQL$CodeQL构建JAVA数据库过程Ini
17、t1.将 codeql-java-agent.jar 注入到 maven javac 运行环境中2.hook javac 编译入口获取参数交给 semmle-extractor-java.jar 3.正常运行 javac 编译工程,编译过程不做侵入,且编译结果不做记录4.使用魔改的 javac 编译工程,忽略编译异常,并提取过程参数(AST,CFG,DFG)codeql.jar 初始化数据库空间,生成 log 和 yml 文件,并初始化一些环境配置finalizetrace中间文件和源码打包成codeql数据库环境清理CodeQL构建JAVA数据库过程构建环境初始化构建extractor选择j
18、avaagent 注入日志记录构建中间文件打包环境清理codeql.jarInterceptor 拦截器获取 javac 编译参数完成 javac 编译流程准备 extractor 环境调用 extractorcodeql-java-agent.jar自实现的 java 编译器模拟 javac 编译抽取编译过程信息生成中间数据semmle-extractor-java.jar codeql并不需要目标工程真正的可编译,只需要获取构建过程中的源码和依赖并不需要目标工程真正的可编译,只需要获取构建过程中的源码和依赖CodeQL构建JAVA数据库过程-Xprefer:source-source1.8
19、-target1.8-extdirsC:Program FilesJavajdk1.8.0_311jrelibext;C:WINDOWSSunJavalibext-endorseddirsC:Program FilesJavajdk1.8.0_311jrelibendorsed-bootclasspathC:Program FilesJavajdk1.8.0_311jrelibresources.jar;.-sourcepathD:/Projects/analyzeCodeql/src/main/java;D:/Projects/analyzeCodeql/target/generated-s
20、ources/annotations;D:/Projects/analyzeCodeql/src/main/java/Hearmen/Hello.javaextractor-java.jarcodeql.jarmaven注入 agent.jar无源码构建Java数据库1.反编译目标程序#jadx-d test-src-r app-debug.apk2.拷贝依赖到 bootclasspath 路径(android.jar、core-lambda-stubs.jar)3.拆解 codeql 构建工具逻辑1.初始化数据库#codeql database init db-name-l java-sou
21、rce-root source2.调用 extractor 传入编译过程参数(源码,依赖)#java-Xmx1024M-Xms256M-cp semmle-extractor-java.jar com.semmle.extractor.java.JavaExtractor-javac-args javac.args3.调用finalize 生成数据库#codeql database finalize db-nameCodeQL构建过程模拟流程图JADXcodeql.jarextractor.jarcodeql.jarFramework.jarcodeql-dbAndroid.jarlambda
22、.jarSource.javaQL 查询语句#1&$()2(3&-$(#$-J$()-S1-/,)J$()42(3&-$(#$-J$()41H%)?A-1N/N/&-)1+3?H()_($%I%-,X(0-BB 查询所有实现 Parcelable 接口的类保证类在当前的源码库中I3+02(3&-$(#$-J$()1T!-P:H-3-1T!-P?I3+0G+3&-)-$-&11T!-PCodeQL 查询语句#2&$()X+;H3+:*-1H+,-S1-/,)J($(#$-4X+;H3+:*-1H+,4-S%)1);3TG10113T-S%)1)J(1&HJ$()-&113T?A-1NJ(1&HJ
23、$()-D&1(/,/+1-S%)1);H3+:G1011-1-?A-1M/&$+)%/AG101D13T?A-1NJ(1&HJ$()-?A-1F()%&F$+&13T?A-1M/&$+)%/AJ($(#$-D1H%)BB&$()EZ2(3&-$(#$-*-1H+,-S1-/,)J($(#$-4EZ2(3&-$(#$-*-1H+,4aa2(3&-$(#$-,-)-3%($%-0-1H+,?aa用!+$TJ($)会有很多误报-S%)1)X+;H3+:*-1H+,/*-1H+,1H%)?!+$TJ($)+3/*-1H+,D1H%)BB 查询所有不会抛出异常的 try-catch 语句查询写操作中不
24、抛出异常的 Parcelable类&$()Z3%1-;+2(3&-$X+J(1&H*-1H+,-S1-/,)EZ2(3&-$(#$-*-1H+,4Z3%1-;+2(3&-$X+J(1&H*-1H+,4aa2(3&-$(#$-,-)-3%($%-0-1H+,?1H%)?A-1X(0-DV:3%1-;+2(3&-$V(/,1H%)?A-16-&$(3%/A;T!-?A-1NG+3&-G!-31T!-%/)1(/&-+I2(3&-$(#$-J$()BBCodeQL 查询语句#3&$()J3-(1-C3+02(3&-$X+J(1&H*-1H+,-S1-/,)EZ2(3&-$(#$-*-1H+,4J3-
25、(1-C3+02(3&-$X+J(1&H*-1H+,4aa2(3&-$(#$-,-)-3%($%-0-1H+,?aa&3-(1-C3+02(3&-$一般是2(3&-$(#$-类的内置类的方法1H%)?A-1X(0-DV&3-(1-C3+02(3&-$V(/,1H%)?A-16-&$(3%/A;T!-?A-1NG+3&-G!-31T!-?A-1M/&$+)%/A;T!-%/)1(/&-+I2(3&-$(#$-J$()+31H%)?A-16-&$(3%/A;T!-%/)1(/&-+I2(3&-$(#$-J$()BB&$()J+/13&1+3Z%1H2(3&-$-S1-/,)J+/)13&1+34J
26、+/13&1+3Z%1H2(3&-$41H%)?A-1N2(3(0;T!-?1+G13%/A?0(1&H-)(/,1H%)?A-16-&$(3%/A;T!-%/)1(/&-+I2(3&-$(#$-J$()BBaa查找所有调用到X+;H3+:*-1H+,的构造函数I3+0J+/13&1+3Z%1H2(3&-$&+/)13&1+3:H-3-S%)1)X+;H3+:*-1H+,/*-1H+,&+/)13&1+3?!+$TJ($)+3/*-1H+,D&+/)13&1+3)-$-&1&+/)13&1+3 查询所有不会抛出异常的 try-catch 语句编写构造函数中不会抛出异常的 try-catch编写
27、createFromParcel 中不会抛出异常的 try-catch更好的办法是使用全局污点分析来查找污点分析速度慢,且误报高实际并未发现长调用链情况CodeQL 查询语句#4&$()F3(/&HEZJ($)-S1-/,)2(3&-$(#$-J$()4F3(/&HEZJ($)4aa2(3&-$(#$-,-)-3%($%-0-1H+,?-S%)1)J($(#$-00?A-1X(0-DV:3%1-;+2(3&-$V+30?A-1X(0-DV&3-(1-C3+02(3&-$V+30%/)1(/&-+IJ+/)13&1+3(/,0?A-16-&$(3%/A;T!-D1H%)+30?A-1X(0-DV
28、&3-(1-C3+02(3&-$V(/,0?A-16-&$(3%/A;T!-?A-1NG+3&-G!-31T!-?A-1M/&$+)%/A;T!-D1H%)-S%)1)7IG101%I)=J($&?A-1J($-?A-1X(0-?3-A-S!*(1&H%I)?A-1M/&$+)%/AJ($(#$-D0(/,%I)?A-1M$)-D&?A-1M/&$+)%/AG101?A-1F()%&F$+&+3%I)?A-1;H-/D&?A-1M/&$+)%/AG101?A-1F()%&F$+&+3-S%)1)6(/A-3+)E-(,3 0?!+$TJ($)B查询所有读或写中存在分支控制,且分支语言中包含 P
29、arcel.readxxx 和 Parcel.writexxx 的查询类本身没有实现Parcelable 接口但是,在其他 parcelable 类函数中被调用的情况&$()6(/A-3+)E-(,-S1-/,)J($(#$-46(/A-3+)E-(,4-S%)1)7IG101%I)=J($&?A-1J($-?A-1X(0-?3-A-S!*(1&H%I)?A-1M/&$+)%/AJ($(#$-D1H%)(/,&?A-1J($-3D1H%)BB CodeQL 查询语句#5查询所有父类重写函数调用有误的情况查找所有重载函数,此函数在父类构造中被调用,且参数为 Parcel 或者 Parcel 的子
30、类过滤掉一些明显的误报&$()7/H-3%12(3&-$(#$-*-1H+,-S1-/,)J($(#$-47/H-3%12(3&-$(#$-*-1H+,4-S%)1)J+/13&1+3Z%1H2(3&-$&+/&+/?!+$TJ($)(/,1H%)?A-1N/N/+1(1%+/?1+G13%/ADV.5-33%,-V(/,1H%)?A-1N2(3(0;T!-?1+G13%/A?0(1&H-)(/,/+11H%)?A-1X(0-?3-A-S!*(1&HBB CodeQL 查询语句#6查询所有在 read/write 中直接调用 setDataPosition 进行常量操作的情况&$()G-16(
31、1(2+)%1%+/J($)-S1-/,)2(3&-$(#$-J$()4G-16(1(2+)%1%+/J($)4-S%)1)J($(#$-00?A-1X(0-DV:3%1-;+2(3&-$V+30?A-1X(0-DV&3-(1-C3+02(3&-$V+30%/)1(/&-+IJ+/)13&1+3(/,0?A-16-&$(3%/A;T!-D1H%)+30?A-1X(0-DV&3-(1-C3+02(3&-$V(/,0?A-16-&$(3%/A;T!-?A-1NG+3&-G!-31T!-?A-1M/&$+)%/A;T!-D1H%)-S%)1)*-1H+,N&-)0(0(?A-1J($-?A-1X(0
32、-DV)-16(1(2+)%1%+/V(/,0(?A-1N/N3A0-/1?%)J+0!%$-;%0-J+/)1(/10(?A-1J($-3D0BB CodeQL 查询语句#7JADX 反编译时有可能会失败(出现 goto)需要考虑反编译出错的情况,查询所有反编译失败,且出现在模式调用链中的情况6-&+0!%$-C(%$-,*-1H+,-S1-/,)*-1H+,46-&+0!%$-C(%$-,*-1H+,4-S%)1)G13%/A%1-3($)?A-1c($-?0(1&H-)?A-1N/M/&$+)%/AG101?A-1M/&$+)%/AJ($(#$-D1H%)(/,-S%)1)*-1H+,0
33、0?A-1X(0-DV:3%1-;+2(3&-$V+30?A-1X(0-DV&3-(1-C3+02(3&-$“0?!+$TJ($)+30D1H%)BB QL 查询结果大语言模型文本生成、文本分类、文本翻译、文本总结、对话问答 强大的文本理解能力大模型的能力缺乏获取外部信息能力缺乏实际执行运算能力模型幻觉大模型的局限在上下文中为模型提供必要的知识为模型提供可调用的工具提升模型的能力通过提示工程技术,让模型的给出更有质量的回答激发模型的潜能ChatGPT for EvilParcel编写具体而清晰的指令使用分隔符来表示输入的不同部分要求模型进行结构化的输出让模型有思考的时间指定模型完成任务所需要的
34、步骤PromptEngineer激发模型潜能要求模型先对输入进行校验在模型开始执行任务前提供样例要求模型先进行思考再输出结果If a machine answer every question,the winner is who asked the bestChain Of Thought模型输入模型输出问:罗杰有 5个网球。他又买了两盒网球,每盒有3个网球。他现在有多少网球?答:罗杰一开始有 5 个网球,2盒 3 个网球,一共就是2*3=6个网球。5+6-11。答案是 11。问:食堂有 23 个苹果,如果他们用掉20个后又买了6个。他们现在有多少个苹果?答:食堂原来有23个苹果,他们用掉20
35、个,所以还有23-20-3个。他们又买了6个,所以现在有6+3-9个 答案是9 Prompt for EvilParcel ROLE规定大模型的角色、场景、任务CONTEXT为大模型输入必要的领域知识EXAMPLE引入思维链将漏洞的分析过程输入给大模型PromptQUESTION规定大模型的任务以及输出格式CODE输入要进行检查的全量代码你是一个安卓安全专家,精通JAVA语言。我是一个安卓安全研究者。现在请你协助我进行安卓的源码审计,发现代码中的安全漏洞。EvilParcel 是指存在类 ClassA,其成员函数 writeToParcel 写入的值与内置类 ClassA$CREATOR 的成
36、员函数 createFromParcel 读取的值不匹配。下面我将给出一些实例和解释以帮你更好的理解 EvilParcel请一步一步分析下面的代码是否存在 EvilParcel,如果存在,则输出类名,并给出分析过程Prompt for EvilParcel class Demo implements Parcelable/writeToParcel:类 Demo 的成员函数 writeToParcel 写入时写入了4个 Int 类型数据:mRotation、mSurfaceGroupId、mSurfaceType 以及根据 mIsShared 写入的 0 或者 1;createFromParc
37、el:类 Demo 的内置类的成员函数 Demo$CREATOR.createFromParcel 读取数据时读取了三个 Int 类型:mRotation,mSurfaceGroupId,mSurfaceType;,会出现读写不匹配。因此上述代码中存在 EvilParcel 类 DemocreateFromParcel 和 writeToParcel相比少读了一个 int 类型writeToParcelcreateFromparcelwriteToParcel VS createFromparcel特殊语法的说明(try-catch、readXXXList)Prompt for EvilPar
38、cel 13 个 EvilParcel2 天为什么是 EvilParcelEvilParcel 特点非常明显,且大多情况下仅涉及某一个具体的类而无需分析数据流CodeQL 和 LLM 在针对局部问题点的分析上效果非常好技术延申本议题中的技术不仅可以用在闭源安卓系统中挖掘 EvilParcel,还可以应用到其他 Java 场景的其他漏洞中只需要给定依赖就可以生成数据库,通过定制化的规则提升审计效率可以更进一步,使用 LLM 写 exploit总结和展望目前的局限LLM 辅助漏洞挖掘需要大量前置知识和上下文信息,token 限制 LangChain 拆解分析过程LLM 也会有幻觉情况出现(误报)迭代 prompt,近义词替换致谢感谢 舒超michael 对工作的支持和信任,以及对技术知识的认可和鼓励感谢 周全昌 在漏洞学习过程中的指导和在文档撰写过程中的帮助感谢 招财大土豆wnagzihxa1n 的分享与思路提供感谢 杜培 在AI领域的指导感谢 马卓感谢您的观看!T H A N KY O UF O RY O U RW A T C H I N G