关键词:SAST,静态代码分析,漏洞分析
1. 引入
本想使用python-joern(参考1)进行测试,发现pip在python3.9、3.11都无法安装了,再看了一下python-joern的github(参考2),发现这个库已经是2016年就停止维护了。
后来找到官网中(参考3)使用cpgqls-client也可以做到通过python编程,连接joern server后进行扫描。这种方式也能实现自动化,本文记录该方法的测试过程。
2. 具体过程
- 安装Joern,参考5,本文在ubuntu22.04下进行
shell
wget https://github.com/joernio/joern/releases/latest/download/joern-install.sh
chmod +x ./joern-install.sh
sudo ./joern-install.sh
注意,如果网速慢,需要打开joern-install.sh,对其中curl命令加proxy(curl -x "http:xxxxyyyzzzeeeddd")。
本文使用的joern版本为Version: 4.0.388。
- 将如下有有缺陷的c语言代码保存为
/home/aaa/a.c
这段代码为doubao生成:
c
#include <stdio.h>
#include <stdlib.h>
// 计算两个整数的和
int add(int a, int b) {
return a + b;
}
// 打印欢迎信息
void greet(const char* name) {
printf("Hello, %s!\n", name);
}
// 潜在的空指针解引用
void unsafe_operation() {
int* ptr = NULL;
*ptr = 42; // 危险:空指针解引用
}
// 可能安全的内存操作
void safe_operation(size_t size) {
int* arr = (int*)malloc(size * sizeof(int));
if (arr != NULL) {
*arr = 100; // 安全
free(arr);
}
}
int main() {
int result = add(3, 5);
printf("3 + 5 = %d\n", result);
greet("World");
// 注释掉危险操作,实际测试时可取消注释
unsafe_operation();
safe_operation(10);
// 潜在的空指针解引用(没有检查malloc返回值)
int* data = (int*)malloc(5 * sizeof(int));
*data = 200; // 潜在危险:如果malloc失败,data为空指针
free(data);
return 0;
}
- 启动joern server
shell
joern --server --server-port 9000
在9000启动server。具体命令参数用法可参考 joern --help 输出。
- python编程调用cpgqls_client
在同一台服务器上,运行如下代码,注意代码路径要设置为绝对路径。
这段代码为doubao生成,多次实验、修复报错后,最终能在python3.9下成功运行:
python
from cpgqls_client import CPGQLSClient, import_code_query
import re
server = "localhost:9000"
client = CPGQLSClient(server)
# 导入代码
import_query = import_code_query("/home/aaa/", "my-c-project")
import_result = client.execute(import_query)
print("代码导入结果:", import_result)
# 函数列表
functions = client.execute("""
cpg.method.filter(!_.isExternal).name.l
""")
print("\n函数:", re.findall(r'"([^"]+)"', functions.get("stdout", "")))
# printf格式化字符串
printf = client.execute("""
cpg.call.name("printf").argument(1).code.l
""")
print("\nprintf格式化字符串:", re.findall(r'"([^"]+)"', printf.get("stdout", "")))
# 空指针解引用(修复转义)
null_deref = client.execute(r"""
cpg.call.name("malloc").argument(1).inAssignment.lhs.typeFullName(".*\\*").outE("REF").inNode.code(".*\\*.*").code.l
""")
print("\n空指针解引用:", re.findall(r'"([^"]+)"', null_deref.get("stdout", "")))
这段代码,分别运行了3条CPGQL语句,并输出其结果。
-
运行python代码后的输出结果
代码导入结果: {'success': True, 'uuid': '63b7b98c-1300-44af-b105-4c9ef5b2fe2c', 'stdout': '\x1b[33mval\x1b[0m \x1b[36mres36\x1b[0m: io.shiftleft.codepraph[208 nodes]]\n'}
函数: ['add', '<global>', 'greet', 'unsafe_operation', 'safe_operation', 'main', '<global>']
printf格式化字符串: ['Hello, %s!\n', ', ', '3 + 5 = %d\n']
空指针解引用: ['malloc', '.\\', 'REF', '.\\.*']
结果可以对照C语言代码进行理解。
3. 总结
用joern命令启动server后,就能在python编程中,调用cpgqls-client的接口,对代码使用CPGQL扫描,并输出结果。
4. 参考
- python-joern文档。https://joern.readthedocs.io/en/latest/access.html
- https://github.com/octopus-platform/joern/tree/master
- cpgqls-client。https://joern.io/integrate/
- joern官方查询语句说明,https://queries.joern.io/
- 深入浅出Joern(一)Joern与CPG是什么,https://lorexxar.cn/2023/08/21/joern-and-cpg/