阿里云「飞天发布时刻」2024来啦!新产品、新特性、新能力、新方案,等你来探~ 了解详情
写点什么

我用 GPT-3 在单个代码库中发现 213 个安全漏洞

  • 2023-03-30
    北京
  • 本文字数:4991 字

    阅读完需:约 16 分钟

我用GPT-3在单个代码库中发现 213个安全漏洞

本文最初发布于 Better Programming。


GPT-3 在这个Git代码库中发现了 213 个安全漏洞。相比之下,市场上一款比较好的商业工具(来自一家著名的网络安全公司)却只发现了 99 个问题,不过商业工具提供了更好的结构化上下文。我随机手动检查了 GPT-3 检测到的 213 个漏洞中的 50 个,只有一个是假阳性。这两种工具的假阴性都很多。


近年来,人工智能和机器学习领域取得了巨大的发展,并开辟了全新的可能性领域。其中一个备受关注的领域是基于人工智能的代码分析,特别是使用人工智能模型来检测代码中的安全漏洞。在这个实验中,我们使用 OpenAI 的 GPT-3 在代码库(包含 129 个有漏洞的文件)中查找安全漏洞。

工作原理


我使用的是 GPT-3 的一个变体(text-davinci-003),其上下文窗口有 4000 个词元,大约是 3000 个英语单词。这意味着每个请求最多只能处理几百行代码。很遗憾,GPT-3 的当前架构无法一次处理整个代码库。


为了解决这个问题,我必须用 GPT-3 单独扫描每个文件。也就是说,GPT-3 可能难以找到涉及多个代码文件交互的安全漏洞,除非 import/export 足够清楚,不需要具体查看代码就可以猜出那些函数的功能。


这种情况经常发生,特别是当源代码使用了常见的库时,如 express.js、Flask、Python 标准库、C 标准库等。GPT-3 很可能用到了许多最常见的库,有的是部分记忆的,有的是完全记忆的,有的是以其他方式编码的。在本文分析的代码中,GPT-3 对导入的库有足够的先验知识,因此能够准确检测安全漏洞,而不需要检查任何导入的库代码。


公平地讲,不只 GPT-3,我怀疑现在的许多商业漏洞扫描工具在进行静态分析时实际上并没有检查导入的库代码——所以与市场上已经存在的一些工具相比,它的工作方式并没有什么不同。

分析的代码


代码库中的每个文件夹都以一种类型的安全漏洞命名,其中的文件包含存在一个或多个漏洞的示例代码。这些文件中的代码有些没什么价值,但也有许多是你可能在生产代码库中遇到的很实际的代码片段(注意:它们不过是代码片段,并没有更大代码库的上下文信息)。代码库中每个文件夹下的 README.md 文件包含了 GPT-3 针对该文件夹中每个文件生成的安全漏洞分析。


接下来,让我们通过一些例子看看 GPT-3 是如何做到的!

示例 1


下面是一个容易受到格式字符串攻击的简单的C程序


#include <stdio.h> int main(int argc, char **argv) {    char *secret = "This is a secret!\n";     printf external link(argv[1]);     return 0;}
复制代码


下面是 GPT-3 的分析(它是对的):


检出的漏洞:

  1. 未验证用户输入:程序没有检查用户输入的长度,这可能导致缓冲区溢出攻击。

  2. 格式字符串漏洞:程序没有检查用户输入的格式,这可能导致格式字符串攻击。

示例 2


让我们看一个用高级语言编写的不那么简单的程序,比如下面这个包含 Log Forging 漏洞的C#程序。类似的代码,我在开源项目和生产代码库中都见过(不是那么没价值):


using Microsoft.AspNetCore.Http;using Microsoft.AspNetCore.Mvc;using Microsoft.Extensions.Logging;using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;
namespace WebFox.Controllers{ [Route("api/[controller]")] [ApiController] public class LogInjection : ControllerBase { private readonly ILogger<LogInjection> _logger;


public LogInjection(ILogger<LogInjection> logger) { _logger = logger; }
[HttpGet("{userInfo}")] public void injectLog(string userInfo) { _logger.LogError("error!! " + userInfo); } }}
复制代码


以下是 GPT-3 的输出:


检出的漏洞:

日志注入漏洞:代码容易受到日志注入攻击,因为用户输入直接被记录,没做任何消毒处理。


GPT-3 的评价是对的——这段代码中有一个日志注入漏洞。

示例 3


下面的C程序读取并操作一幅图像。它包含许多安全漏洞,包括越界(Out Of Bounds)读写:


#include<stdio.h>#include<stdlib.h>#include<string.h>
struct Image{ char header[4]; int width; int height; char data[10];};
int ProcessImage(char* filename){
FILE *fp; char ch; struct Image img;
fp = fopen(filename,"r");
if(fp == NULL) { printf("\nCan't open file or file doesn't exist."); exit(0); }
printf("\n\tHeader\twidth\theight\tdata\t\r\n");
while(fread(&img,sizeof(img),1,fp)>0){ printf("\n\t%s\t%d\t%d\t%s\r\n",img.header,img.width,img.height,img.data); int size1 = img.width + img.height; char* buff1=(char*)malloc(size1);
memcpy(buff1,img.data,sizeof(img.data)); free(buff1); if (size1/2==0){ free(buff1); } else{ if(size1 == 123456){ buff1[0]='a'; } }
int size2 = img.width - img.height+100; //printf("Size1:%d",size1); char* buff2=(char*)malloc(size2);
memcpy(buff2,img.data,sizeof(img.data));
int size3= img.width/img.height; //printf("Size2:%d",size3);
char buff3[10]; char* buff4 =(char*)malloc(size3); memcpy(buff4,img.data,sizeof(img.data));
char OOBR_stack = buff3[size3+100]; char OOBR_heap = buff4[100];
buff3[size3+100]='c'; buff4[100]='c';
if(size3>10){ buff4=0; } else{ free(buff4); }
free(buff2); } fclose(fp);}
int main(int argc,char **argv){ ProcessImage(argv[1]);}
复制代码


GPT-3 的输出:


检出的漏洞:

  1. 未检查返回值:未检查 fopen()函数的返回值,这可能导致空指针解引用。

  2. 越界读取:使用 memcpy()函数将数据从 img.data 复制到 buff1 和 buff2,而不检查目标缓冲区的大小,这可能导致越界读取。3.越界写入:在写入 buff3 和 buff4 数组时未检查源缓冲区大小,这可能导致越界写入。

  3. 未初始化内存访问:在未初始化的情况下访问 OOBR_stack 和 OOBR_heap 变量,这可能导致未定义的行为。

  4. 内存泄漏:如果 size3 变量大于 10,则 buff4 数组不会释放,这可能导致内存泄漏。


GPT-3 再次判断正确!

示例 4


最后一个Java示例是我最喜欢的,因为很遗憾,在第一次阅读这段代码时,我没有发现它有任何问题。对我来说,它看起来完全无害且很常见——我实际见过类似的代码,但从未有过任何其他的想法。


class Utils{    // 该函数序列化一个对象,并将其写入一个文件    public static void SerializeToFile(Object obj, String filename)    {        try        {            FileOutputStream file = new FileOutputStream(filename);            ObjectOutputStream out = new ObjectOutputStream(file);
// 将对象序列化到文件中 System.out.println("Serializing " + obj.toString() + " to " + filename); out.writeObject(obj);
out.close(); file.close(); } catch(Exception e) { System.out.println("Exception: " + e.toString()); } }
// 该函数从文件反序列化对象 public static Object DeserializeFromFile(String filename) { Object obj = new Object();
try { FileInputStream file = new FileInputStream(filename); ObjectInputStream in = new ObjectInputStream(file);
// 从文件反序列化对象 System.out.println("Deserializing from " + filename); obj = in.readObject();
in.close(); file.close(); } catch(Exception e) { System.out.println("Exception: " + e.toString()); }
return obj; }}
复制代码


GPT-3 的输出:


检出的漏洞:

  1. 不安全的反序列化:反序列化不受信任的数据可能导致远程代码执行。

  2. 不安全的文件权限:正在写入或读取的文件可能具有不安全的权限,从而导致未经授权的访问。


GPT-3 再次判断正确。

网络安全“终极”左移


左移是在开发过程早期应用安全实践的过程——比如在将代码部署到生产环境之前测试安全漏洞。


人工智能代码分析代表了网络安全领域的终极左移,它通过应用最佳安全实践,在开发人员编写和提交代码时为他们提供网络安全指导。这可以真正地在组织内部培养起强大的网络安全文化,甚至可以防止下一次大规模黑客攻击,但是……


不可否认,这项技术还不完美,它会遗漏一些事情,而一个有经验的网络安全专业人士在审计时就不会遗漏。尽管如此,作为一种通用的大型语言模型,它还是非常不错的,而且成本比其他替代方案低很多。


目前,GPT-4 的发布日期还不确定,但我相信,随着这些大型语言模型的功能越来越多,它们会继续向前发展。

假阳性


在手动检查 GPT-3 检出的 213 个漏洞中的约 50 个后,我唯一发现的假阳性是在这个JavaScript程序的第 13 行:


var express = require('express');var cookieParser = require('cookie-parser');var escape = require('escape-html');var serialize = require('node-serialize');var app = express();app.use(cookieParser()) app.get('/', function(req, res) { if (req.cookies.profile) {   var str = new Buffer(req.cookies.profile, 'base64').toString();   var obj = serialize.unserialize(str);   if (obj.username) {     res.send("Hello " + escape(obj.username)); // <--- GPT-3在这里犯了一个错误   } } else {     res.cookie('profile', "eyJ1c2VybmFtZSI6ImFqaW4iLCJjb3VudHJ5IjoiaW5kaWEiLCJjaXR5IjoiYmFuZ2Fsb3JlIn0=", {       maxAge: 900000,       httpOnly: true     }); } res.send("Hello World");});app.listen(3000);
复制代码


GPT-3 的输出:


检出的漏洞:

  • 不安全的 cookie 设置(未设置安全标志)

  • 未验证的用户输入(cookie)反序列化

  • 未对用户输入(用户名)进行转义,可能存在 XSS 漏洞 GPT-3 对于前 2 个漏洞的判断是正确的,但第 3 个漏洞是假阳性—— obj.username 已经进行了编码,但 GPT-3 说没有。

GPT-3 检测结果


实验结果表明,经过扫描,GPT-3 在 129 个文件的到 86 个中检出了安全漏洞。这真是令人印象深刻!


以下是脚本summarize_results.py生成的 GPT-3 检测结果的完整摘要:


在129个文件中,有86个检出了漏洞。总共检出了213个漏洞。
GPT-3回复中使用的介绍性句子的出现频率(每个扫描的文件一个回复):{'vulnerabilities detected': 73, 'no vulnerabilities detected.': 43, 'vulnerability detected': 6, 'answer': 2, 'potential vulnerabilities detected': 2, 'analysis': 1, 'security vulnerabilities detected': 1, 'no response given': 1}
扫描的文件类型的分布:总计129个代码文件(不包括markdown和平面文件){'.php': 50, '.js': 20, '.cs': 16, '.c': 14, '.java': 9, '.py': 8, '.rb': 5, '.asp': 3, '.ts': 2, '.go': 1, '.html': 1}
复制代码

与商业产品的对比


为了完善这个实验,我将 GPT-3 的结果与商用代码漏洞扫描工具Snyk Code(由 Snyk 公司开发)做了比较。我认为,Snyk 公司开发的安全产品非常出色。通过扫描,Snyk Code 从这个代码库中发现了 99 个安全漏洞,而 GPT-3 发现了 213 个安全漏洞。



其中一个原因是 Snyk Code 只支持其中部分编程语言,并且只能扫描大约 103 个文件,而 GPT-3 扫描了 129 个文件。


此代码库中存在漏洞的代码片段来自snoopysecurity/Vulnerable-Code-Snippets,这是一个很棒的资源。我试着删除了嵌入在代码段中的注释,从中可以看出这个代码段中包含哪些安全漏洞。这些需要删除的注释中包含指向这些示例片段出处的博文链接。要查看它们在原代码库中的位置,可以查看attributions.md文件。


原文链接:https://betterprogramming.pub/i-used-gpt-3-to-find-213-security-vulnerabilities-in-a-single-codebase-cc3870ba9411

公众号推荐:

跳进 AI 的奇妙世界,一起探索未来工作的新风貌!想要深入了解 AI 如何成为产业创新的新引擎?好奇哪些城市正成为 AI 人才的新磁场?《中国生成式 AI 开发者洞察 2024》由 InfoQ 研究中心精心打造,为你深度解锁生成式 AI 领域的最新开发者动态。无论你是资深研发者,还是对生成式 AI 充满好奇的新手,这份报告都是你不可错过的知识宝典。欢迎大家扫码关注「AI前线」公众号,回复「开发者洞察」领取。

2023-03-30 07:003766

评论 1 条评论

发布
用户头像
一些代码检查工具不行吗,sonarqube的插件,比如findbugs也是根据模式发现bug的
2023-03-31 09:29 · 辽宁
回复
没有更多了
发现更多内容

逻辑回归与评分卡-二元回归与多元回归:重要参数solver & multi_class & class_weight

烧灯续昼2002

Python 机器学习 算法 sklearn 11月月更

在使用Note.js的过程中对于tty对于终端的运用、加密模块以及Assert的事件驱动程序的深入运用理解

恒山其若陋兮

前端 11月月更

React源码分析(一)Fiber

goClient1992

React

信息论与编码:恒参信道特性

timerring

11月月更 信息论与编码

Baklib|知识库应用场景:制作员工培训手册

Baklib

团队管理 知识管理

极客时间运维进阶训练营第五周作业

Starry

【Node.js 】开发中遇到的多进程‘keylog‘ 事件以及TLS/SSL的解决学习方案实战

恒山其若陋兮

前端 11月月更

CDH5部署三部曲之二:部署和设置

程序员欣宸

大数据 hadoop 11月月更

React Context源码是怎么实现的呢

flyzz177

React

「Go实战」基于Prometheus+Grafana搭建完整的监控系统

Go学堂

golang 程序员 个人成长 监控 11月月更

C++学习---类型萃取---is_function

桑榆

C++ STL 11月月更

React源码分析(三):useState,useReducer

goClient1992

React

Python 项目工程化最佳实践指南

Andy

Python 项目管理 代码规范 代码风格

互联网大厂必问面试合集,助你跳槽拿高薪--Java篇

钟奕礼

Java java面试 java编程 程序员java

我与梅西粉丝们的世界杯观球日常

ZEGO即构

音视频开发

一种基于 Apache Hive 的元数据智能发现方案

移动云大数据

hive

FCOS论文复现:通用物体检测算法

华为云开发者联盟

人工智能 华为云 论文复现

企业级项目开发中的交互式解释器以及global全局定义、Stream流的合理运用和实战【Note.js】

恒山其若陋兮

前端 11月月更

vivo大数据日志采集Agent设计实践

vivo互联网技术

大数据 数据采集 日志采集 agent

面试官:介绍一下 Redis 三种集群模式

程序员小毕

redis 程序员 后端 java面试 redis集群

Python: 你所不知道的星号 * 用法

eng八戒

Python 编程

Mobtech短信验证 for Flutter

MobTech袤博科技

深入react源码看setState究竟做了什么?

flyzz177

React

重构了一个服务的健康检查组件

Java永远的神

Java 程序员 面试 后端 架构师

一文熟悉 Go 的循环结构 —— for 循环

陈明勇

Go golang for 11月月更 for-range

【web 开发基础】PHP类静态函数和对象方法的回调 (37)

迷彩

对象 回调函数 11月月更 静态方法 成员方法

「Go实战」记一次降低30%的CPU使用率的优化

Go学堂

golang redis 程序员 个人成长 11月月更

React源码分析(二)渲染机制

goClient1992

React

细说react源码中的合成事件

flyzz177

React

企业网络“卫生”实用指南(上)

SEAL安全

网络安全 企业安全

项目经理和Scrum Master之间的不同(译)

Bruce Talk

Scrum 敏捷开发 Agile

我用GPT-3在单个代码库中发现 213个安全漏洞_开源_Chris Koch_InfoQ精选文章