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

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:281902
用户头像

发布了 489 篇内容, 共 175.3 次阅读, 收获喜欢 1010 次。

关注

评论

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

想不出来问题的你

escray

学习 面试 面试现场

想问面试官什么问题么?

escray

学习 面试 面试现场

6. 二十不惑,ObjectMapper使用也不再迷惑

YourBatman

json Jackson ObjectMapper

“深化产教融合·共育数字人才”全国产教融合信息化高峰论坛·江苏站成功举办

InfoQ_967a83c6d0d7

ARTS打卡 第13周

引花眠

微服务 ARTS 打卡计划

架构师训练营 - 第 8 周学习总结

红了哟

MacOS抓包工具Charles

叉叉敌

ios charles 抓包

Python代码调试指南

王坤祥

Python Python基础

ARTS打卡Week 11

teoking

要刷LeetCode了,才发现自己连时间复杂度都不懂

海星

算法 LeetCode

Java中的一些限制

xiaoxi666

浅谈 GET 和 POST 区别

叉叉敌

面试题 post GET

一家估值20亿美元的公司,竟然没有办公室?

Atlassian速递

远程办公 Atlassian Jira

大数据技术思想入门(三):分布式文件存储的流程

抖码算法

Java 大数据 hadoop 分布式

Docker 安装及配置镜像加速

哈喽沃德先生

Docker 容器 微服务 容器技术 容器化

从Vessel到二代裸金属容器,云原生的新一波技术浪潮涌向何处?

华为云开发者社区

Docker 容器 云原生 k8s Vessel

Java ForEach语句判断是否为空

引花眠

bug

【Elasticsearch 技术分享】—— ES 常用名词及结构

程序员小航

Java 搜索引擎 elastic ES Lucene Elastic Search

你期待的薪酬是多少?

escray

学习 面试 面试现场

看智微智能互动录播系统如何建设“三个课堂”

InfoQ_967a83c6d0d7

1.Flink任务之间通信开销-6

小知识点

scala 大数据 flink

disruptor 高性能队列最佳选择

柿子

队列 disruptoer 高性能队列

速看!今天我才知道,UUID还分五个版本

麦叔

Java uuid

ARTS打卡(20.08.17-20.08.23)

小王同学

架构师训练营第十一周作业

Melo

utf8字符集下的比较规则

Simon

MySQL 字符集

顺时针遍历矩阵,提高系统高并发350倍,React Native原理浅析 组件设计原则 安全架构 防火墙ModSecurity John 易筋 ARTS 打卡 Week 14

John(易筋)

ARTS 打卡计划 组件设计原则 React Native 高并发优化

我与游戏相伴【自我访谈2】

叶阳夏烟

系列 游戏 访谈录 剧情游戏 仙剑奇侠传

Newbe.Claptrap 框架入门,第三步 —— 定义 Claptrap,管理商品库存

newbe36524

Docker 云计算 微服务 .net core ASP.NET Core

rockchip的yocto编译环境搭建

良知犹存

Linux yocto rockchip

关于Aborted connection告警日志的分析

Simon

MySQL MySQL错误日志

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