- 如何搜索一个变量是函数调用?
-
IDE 提供了 Control/Command + 鼠标左键点击跳转的功能,代码审计工具一般很难提供这种功能。 -
真实的漏洞往往跨越了很多个数据流,如何在不同数据流之间搜索?
这一段话非常抽象,如果阅读这个抽象描述有问题的话,可以阅读以下 ChatGPT-4 的解读。 这段话概述了使用符号执行和约束求解技术(特别是在 SMT 或 SAT 求解器上下文中)来进行代码分析的基本过程。这里提供了对这一技术的高层次描述,并说明了其在识别代码中的安全漏洞(如 source 到 sink 的数据流问题)方面的应用。以下是对这一技术描述的几个关键点的评价: 正确性和准确性 1. 转化代码问题为符号运算和定理证明问题:描述准确地反映了符号执行技术的核心理念,即将程序的执行路径转化为符号路径,然后通过逻辑约束来进行推理和验证。这是静态代码分析中常见的方法,用于分析程序可能的执行行为而无需实际运行程序。 2. 使用约束求解算法找到符号解:这正确地指出了在符号执行中的一个关键步骤,即利用如 SMT (Satisfiability Modulo Theories) 或 SAT (Boolean Satisfiability Problem) 求解器来解决这些约束。如果求解器能够找到满足所有约束的解,这意味着存在一种特定的输入或程序状态,可以使程序执行到某一特定路径。 应用的实用性 3. 把符号解转化成具体的代码位置:这一步骤非常关键,因为它将抽象的符号结果转化为可以操作的具体信息。例如,在安全性分析中,这可以帮助开发者准确地定位到可能存在漏洞的代码行或路径。 4. 找到 source 和 sink 的交汇点:在安全性分析中,识别数据从潜在的不安全源(source)流向敏感汇(sink)的路径是至关重要的。这种分析可以帮助识别例如 SQL 注入、跨站脚本(XSS)等常见的安全漏洞。 技术限制 5. 可能无法求解:这一点正确地指出了符号执行和约束求解中的一个主要挑战,即在某些情况下,由于路径爆炸问题、复杂的约束或资源限制,求解器可能无法找到解或在合理时间内完成求解。 结论 这段描述提供了一个对使用符号执行和约束求解进行代码分析的有效概述。它正确地捕捉了这种技术的工作原理和在实际代码安全性分析中的应用。同时,也简要提到了在实施这种分析时可能遇到的挑战,如复杂性和求解的可行性问题。这种技术是静态代码分析领域的重要组成部分,尤其是在寻求自动化安全审计和缺陷识别方面。
这两种理解不论是哪种都并不亲民,而且据我们所知,大部分漏洞并不需要约束求解,甚至很多就是普通的过滤,或者数据流到了危险函数中的参数了,如果有清晰的数据流可达性判断,就可以得到正确的结果,并不需求解什么内容。
-
可选的跨过程分析需要从某一个节点扩展出去。 -
OOP 实现中, object.method
和
object
往往应该被视为有某种关联的对象。 - 闭包噩梦:在闭包系统中,捕获变量(逃逸变量)可能并不是单纯数据流或者图可以表达得出来的。
-
...
@Controller
@RequestMapping("/home/rce")
public class RuntimeExec {
@RequestMapping("/runtime")
public String RuntimeExec(String cmd, Model model) {
StringBuilder sb = new StringBuilder();
String line;
try {
Process proc = Runtime.getRuntime().exec(cmd);
InputStream fis = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(fis, "GBK");
BufferedReader br = new BufferedReader(isr);
while ((line = br.readLine()) != null) {
sb.append(line).append(System.lineSeparator());
}
} catch (IOException e) {
e.printStackTrace();
sb.append(e);
}
model.addAttribute("results", sb.toString());
return "basevul/rce/runtime";
}
}
❯ tree /tmp/javatest
/tmp/javatest
└── a1
└── test.java
2 directories, 1 file
❯ yak ssa -t /tmp/javatest --program sf1
7| String line;
8|
9| try {
10| Process proc = Runtime.getRuntime().exec(cmd);
11|
12| InputStream fis = proc.getInputStream();
13| InputStreamReader isr = new InputStreamReader(fis, "GBK");
基础概念
❯ yak ssa --program sf1 --sf 'getRuntime()'
[INFO] 2024-06-13 15:04:18 [ssacli:86] using syntaxflow rule will skip compile
[INFO] 2024-06-13 15:04:18 [ssa:38] init ssa database: /Users/v1ll4n/yakit-projects/default-yakssa.db
......
......
......
[INFO] 2024-06-13 15:04:18 [ssacli:146] syntax flow query result:
[INFO] 2024-06-13 15:04:18 [ssacli:148] ===================== Variable:_ ===================
[INFO] 2024-06-13 15:04:18 [ssacli:174] /tmp/javatest/a1/test.java:10:35 - 10:47: getRuntime()
IR: 335234: Undefined-Runtime.getRuntime(valid)()
7| String line;
8|
9| try {
10| Process proc = Runtime.getRuntime().exec(cmd);
11|
12| InputStream fis = proc.getInputStream();
13| InputStreamReader isr = new InputStreamReader(fis, "GBK");
用法列表
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.getRuntime 表示所有成员包含 getRumtime 为名字的值.*Runtime 和 ./.*?Runtime/ 正则和 Glob 匹配也是符合要求的 |
|
|
foo.bar 表示寻找所有 foo 作为 object,bar 作为成员的调用情况 |
|
|
getRuntime() 表示所有名字为 getRuntime 的符号被调用的位置。 |
|
|
exec(*) 意思是把 exec 所有的参数都作为审计对象,嵌套从参数开始进行审计。 |
|
|
call(,*,) 表示call这个函数调用的第二个参数开始审计,从第几个逗号开始匹配说明是第几个参数。 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
getRumtime() -{depth: 3}-> 设置一个深度为 3 的 UD 链递归向下查询。 |
|
|
exec(* as $sink) 把所有 exec 的参数保存为 $sink 变量。 |
实战继续
❯ yak ssa --program sf1 --sf 'getRuntime().exec(*)'
[INFO] 2024-06-13 15:28:43 [ssacli:86] using syntaxflow rule will skip compile
[INFO] 2024-06-13 15:28:43 [ssa:38] init ssa database: /Users/v1ll4n/yakit-projects/default-yakssa.db
.........
.........
.........
[INFO] 2024-06-13 15:28:43 [ssacli:146] syntax flow query result:
[INFO] 2024-06-13 15:28:43 [ssacli:148] ===================== Variable:_ ===================
[INFO] 2024-06-13 15:28:43 [ssacli:174] /tmp/javatest/a1/test.java:5:30 - 5:40: String cmd
IR: 335223: Parameter-cmd
2| @RequestMapping("/home/rce")
3| public class RuntimeExec {
4| @RequestMapping("/runtime")
5| public String RuntimeExec(String cmd, Model model) {
6| StringBuilder sb = new StringBuilder();
7| String line;
8|
public class RuntimeExec {
@RequestMapping("/runtime")
public String RuntimeExec(
String cmd,
Model model) {
StringBuilder sb = new StringBuilder();
String line;
try {
any runtimeInstance = Runtime.getRuntime();
Process proc = runtimeInstance.exec(cmd);
InputStream fis = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(fis, "GBK");
BufferedReader br = new BufferedReader(isr);
while ((line = br.readLine()) != null) {
sb.append(line).append(System.lineSeparator());
}
❯ yak ssa --program sf3 --sf 'getRuntime().exec(*)'
[INFO] 2024-06-13 15:33:55 [ssacli:86] using syntaxflow rule will skip compile
[INFO] 2024-06-13 15:33:55 [ssa:38] init ssa database: /Users/v1ll4n/yakit-projects/default-yakssa.db
...
...
[INFO] 2024-06-13 15:33:55 [ssacli:146] syntax flow query result:
[INFO] 2024-06-13 15:33:55 [ssacli:148] ===================== Variable:_ ===================
[INFO] 2024-06-13 15:33:55 [ssacli:174] /tmp/javatest/a1/test.java:8:2 - 8:12: String cmd
IR: 335419: Parameter-cmd
5| public String RuntimeExec(
6|
7|
8| String cmd,
9|
10| Model model) {
11| StringBuilder sb = new StringBuilder();
END
原文始发于微信公众号(Yak Project):一种全新的代码审计技术:SyntaxFlow
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论