手把手教你怎样找代码漏洞

2020 年 11 月 17 日

手把手教你怎样找代码漏洞

本文是关于如何查找代码漏洞文章系列的第一篇。从宏观来看,过程是这个样子:


  • 找到潜藏危险的功能

  • 找到从你控制的输入到这个危险功能的路径

  • 修正会导致程序出问题的输入


我们将从第一部分开始:如何找到潜藏危险的功能。以我的经验,80%的错误都藏在大约 20%的代码中。具体来说,这个比例更接近 90/10。由于我们通常需要彻底理解代码才能发现罕见的漏洞,因此找出需要重点关注的那 20%就变得至关重要。我使用的一种方法是关注“坏词(bad words)”的群集。


我将通过一个简短的故事告诉大家。最近在一次红队行动中,我浏览一个巨大的 terraform 仓库时看到一行看起来很正常的代码:


driver.raw_exec.enable = 1
复制代码

这个时候,我甚至都没有在尝试寻找漏洞,但是看到这行代码后,我就停下来弄清楚它在做什么。原来,它正在配置 Hashicorp 一个名为 Nomad 的作业调度程序。作为一名尽责的红队队员,我立刻查询了 Nomad 文档。在那里,我发现了一个不祥警告:


这让你可以无隔离地运行作业;出于安全原因,默认情况下将其禁用。


我马上精神了,迅速做出一个最简单的 Nomad 作业。几分钟后,我就有了对该集群的 root 访问权限和一大堆凭证。这次行动马上就可以完成了。


在此之前,我甚至从未听说过 Nomad,更不用说这个配置选项了。那么这行代码到底有什么特殊引起了我的关注,让我想要深入研究下去呢?其实是因为两个安全坏词的组合,它们流连在同一代码段,分别是“raw”和“exec”。这些坏词可以帮助你筛选出代码中最关键的安全部分,让你能高效地利用你的注意力。


常见的坏词(bad words)


raw


Raw 表示你正在访问较低级别的抽象。当在较高级别上实施安全控制时,这将成为一个问题,让这个“raw”界面的用户可以绕过它们。


例子:


  • CAP_NET_RAW是一个Linux功能,允许你创建raw socket,并使用它们来绕过典型的进程隔离限制。

  • Nomad中的raw_exec驱动程序允许你创建在容器外部运行的作业,拥有nomad代理的许可。

  • 许多ORM都有rawQueryrawSQL方法,让你可以直接执行查询。ORM生成的查询通常是不可注入的,但是要由用户决定使用“raw”界面时是否阻止SQLi。


eval|exec|run


一般来说,将用户输入与用动态语言(JavaScript、SQL、bash 等)编写的代码相结合,通常是注入攻击的好途径。攻击者可以提交代码作为输入,从而导致解释器执行不当行为。运行这种代码通常称为“executing”、“evaluating”或“running”。


例子:


  • raw_exec无隔离地运行Nomad作业

  • conn.cursor().execute(sql)在许多python数据库驱动程序中运行SQL查询

  • exec(code)是运行传递给它的代码的python方法

  • eval(code)是许多动态语言提供的一个函数,例如JavaScript,可以用它运行你传递的代码。Python也有一个eval函数,但仅用于表达式。


*这将返回很多误报,因为正如 Steve Yegge 预测的那样,似乎每个动词都通过run()execute()justDoIt()方法变成了一个名词。


process|system|popen|exec|spawn


这些词可以用来指示子进程的创建。如果子进程生成了一个外壳,那么你就可能注入外壳命令。即使它直接调用 execve syscall,你仍然可以在程序中添加/修改参数。


例子:


  • python中的subprocess模块

  • node中的child_process模块

  • golang中的os/exec

  • python中的os.system方法

  • ruby中的popen模块


privilege|permission|capability|role|rbac|policy|authorization|claims


这些单词可以帮助你找到负责向用户、容器、进程、文件、EC2 实例等授予特权的代码。你可以使用任何拥有高特权的实体来下手,甚至完全绕过 authz。


例子:


  • docker的--privileged标志为主机提供了容器的可用root特权。

  • linux内核将root用户权限划分为“capabilities”,你可以将其分配给一个程序,从而允许它执行创建raw socket、调试你不控制的进程或绕过文件ACL之类的操作。

  • Kubernetes使用一个称为RBAC(基于角色的访问控制)的api扩展来授权对K8s资源的访问。

  • 许多云提供商使用术语“role binding”向一个主体授予一组权限。

  • JWT拥有“claims”,可以告知消费者用户的特权,并且消费者可以使用jwt.ParseWithClaims之类的函数来验证它们。


reflect|klass|constantize|forName


许多编程语言都允许你通过名称来查找函、类、方法、变量等(甚至实例化/调用它们)。这通常称为“reflection”。如果用户可以控制要调用方法的名称或要返回变量的名称,则可能会导致程序行为异常。


例子:


  • JavaScript中的Reflect对象

  • ruby中的String#constantize方法

  • java的Class.forName方法

  • klass是通过反射查找类的一个通用变量名称(因为“class”往往是保留字)


pickle|yaml|serialize|marshal|objectinput


这些词表示程序可能正在使用支持复杂对象的格式对数据进行反序列化。这可以让攻击者读取文件、发送 HTTP 请求甚至执行任意代码,具体取决于序列化格式以及运行时可用的对象(JVM 类路径上的类、python 中sys.path上的包等)。


例子:


  • python的pickle格式

  • node-serialize包

  • 大多数YAML parser

  • Java的ObjectInputStream

  • php的unserialzie函数


parse|open|request


这些单词可能很有趣,原因和eval()之类差不多:攻击者可以输入有问题的 parser 识别的元字符来更改其行为。主要区别在于,你不是在动态语言中运行代码,而是利用 parser 来访问文件或 URL 等资源。


例子:


  • 控制URL parser的输入可能会导致SSRF、绕过代理限制、off-by-slash等问题。

  • 控制文件路径parser的输入可能导致LFI、RFI和本地文件读/写。


unsafe|insecure|dangerous


有时,API 开发人员喜欢在名称中包含“insecure”或“unsafe”来引起开发人员对危险 API 的关注。


例子:


  • Rust中的unsafe {}

  • Go的TLS包中的InsecureSkipVerify

  • React中的dangerouslySetInnerHtml()

  • Go中的unsafe软件包


todo|fixme|xxx


随着代码的发展,开发人员会添加注释,以提醒自己要实现功能、修复错误或清理一些自己不喜欢的代码。有时,这些注释可能会帮助你发现重要的错误、缺少的功能等,可以利用它们。


例子:


  • 有一次,我在Apache服务器的Web根目录中找到一个todos.txt文件。它包含一长串未修补的安全漏洞。

  • 还有一次,我发现了一个FIXME注释,其中提到了一个性能问题。这个问题很难发现,但是利用它来暴露ReDoS漏洞却很简单。


merge|clone


这些词通常表示一个对象、字典、映射等正在与另一个对象合并或克隆到一个新对象中。这可能会导致有趣的安全问题,例如 JavaScript 原型污染漏洞、大规模分配漏洞等。


例子:


  • LoDash里的_.merge

  • LoDash里的_.clone


alloc|free


它们是发生手动内存管理的一个很好的线索。众所周知,这很难解决,并且可能导致诸如缓冲区溢出、释放后使用、双重释放等漏洞。


例子:


  • malloc()

  • free()

  • Objective C中的[object alloc]消息


AES|RSA|DSA|DES|CBC|ECB|HMAC|GCM


这些是加密原语,可以表明作者正在使用自己的密码系统,而不是使用更高级别的抽象。有许多不起眼的细节可以让它们变得不够安全,因此请仔细阅读代码并咨询加密专家。


例子:


  • aes.NewCipher(key)

  • new RSAPrivateKey(keyBytes)

  • HMAC.new(secret, digestmod=SHA256)


JWT|JKS|JWK|JKU……


JSON Web 令牌是安全传输数据的标准,在现代应用程序栈中非常常用。有很多不安全地使用它们的途径,因此值得关注处理 JWT 的代码。


常见的 JWT 问题:


  • none算法

  • 操纵alg标头

  • 不验证aud或iss claim

  • 未验证有效期(exp和nbf claim)

  • 签名但不加密敏感数据


例子:


  • JWTVerifier

  • jwt.ParseWithClaims

  • jwt.verify


password|provate|token|secret|key|Authorization


这些词是很好的指示,表明你可能已经将一些秘密硬编码到了存储库中,例如 API 密钥、数据库密码、加密密钥等。


例子:


  • BEGIN RSA PRIVATE KEY

  • AWS的“secret access key”

  • Django的SECRET_KEY设置


validate|verify


这些词通常表示代码正在执行业务/安全规则。请仔细检查这些内容,以获取通过了验证,但也可能导致漏洞的输入。他们试图禁止的输入类型也可以为你提供有关潜在漏洞的线索。


例子:

app.get('/signup', (req, res) => {    // verify! this probably means that only users with certain    // emails are allowed to sign up. I wonder what it's    // verifying?	if (!verifyEmail(req.body.email)) {    	res.send('unauthorized');        return;    }        register(req.body.email);        res.redirect('/dashboard');});// looks like it's verifying the email belongs to a user// on company.com. can you think of a way to make this return// true without having a @company.com email address?//// what about will@company.com.btlr.dev?function verifyEmail(email) {	return email.includes('@company.com');}
复制代码


XML|xerces|SAX|etree|xpath|DocumentBuilder


解析攻击者控制的 XML 可能会导致许多安全问题,从本地文件读取到拒绝服务攻击等等。


例子:


  • DocumentBuilderFactory.newInstance();

  • SAXParserFactory.newInstance();

  • xml.etree.elementtree


原文链接:

https://btlr.dev/blog/how-to-find-vulnerabilities-in-code-bad-words

2020 年 11 月 17 日 16:281672
用户头像

发布了 461 篇内容, 共 169.5 次阅读, 收获喜欢 969 次。

关注

评论

发布
暂无评论
发现更多内容

Redis-技术专题-Redis知识体系

李浩宇/Alex

2020年史诗级‘面试宝典’横空而出,金九银十就靠“它”涨薪了

云流

程序员 架构师 java面试 程序员求职 编程学习

甲方日常 12

大橘子

工作 随笔杂谈 日常

虚拟币永续合约系统开发app源码,交易所开发

WX13823153201

永续合约系统开发

话题讨论 | 程序员们来说一说,你们从编程开始到现在共使用过多少种语言?

InfoQ写作平台

写作平台 话题讨论 语言

随笔文,关于”中台“ 的一些“小偏论”

松子(李博源)

数据中台 中台 大数据处理 数据平台 大数据平台

Flink SQL 1.11 新功能与最佳实践

Apache Flink

flink

GaussDB(DWS)应用实战:对被视图引用的表进行DDL操作

华为云开发者社区

数据库 dll postgre

为了面个好公司!拼了!3.5W字的Java面试题整理(答案+学习路线)上!

Java架构师迁哥

编程的修养

紫枫

读书笔记

金九银十:搞定这两个GitHub标星50K开源项目,拿个30k轻松吧?

云流

编程 程序员 算法 架构师 java面试

记一次前端vue相关面试题目和简答案

靖仙

面试 Vue MVVM

MySQL中my.cnf的配置说明

Matrix Chan

运维 MySQ MySQL 运维 数据库运维

Elasticsearch之文档操作

北漂码农有话说

如何基于 Flink 生成在线机器学习的样本?

Apache Flink

flink

探路人与解题者:腾讯数字生态大会上AI语音助手+X的无限可能

脑极体

前端 10 问之 TypeScript (第一篇)

局外人

typescript 前端进阶

Mac搭建本地koa2项目

靖仙

koa2 本地环境搭建

机器学习及信息与认知的逻辑

superman

机器学习 认知提升 个人提升

大厂面试爱问的「调度算法」,20 张图一举拿下

Java架构师迁哥

Spring 5 中文解析核心篇-集成测试之TestContext(下)

青年IT男

单元测试 Spring5

MySQL8.0大表秒加字段,是真的吗?

Simon

MySQL MySQL DDL

中国移动张浩:AMQP on Pulsar 的设计与应用一览

Apache Pulsar

Apache 云原生 Apache Pulsar 消息中间件 AMQP

Apache Pulsar 社区周报|08-22 ~ 09-04

Apache Pulsar

开源 云原生 Apache Pulsar 消息系统 消息中间件

面经手册 · 第10篇《扫盲java.util.Collections工具包,学习排序、二分、洗牌、旋转算法》

小傅哥

Java 数据结构 算法 归并排序 洗牌算法

CDN百科11 | 如何用CDN加速OSS源站资源

巨侠说

这13道面试题,哪怕背你也要背过来。别说我没提醒你

小Q

Java 源码 架构 面试 多线程

第13周总结+作业

林毋梦

5G加速商用,云通信如何推动企业营销数智化

巨侠说

Git 中submodule的使用,终于有人说明白了

Java架构师迁哥

科普:Java 后端开发常用的 10 种第三方服务

沉默王二

Java 后端开发 第三方服务

AI如何在普惠金融的探索中发挥作用?

AI如何在普惠金融的探索中发挥作用?

手把手教你怎样找代码漏洞-InfoQ