作者:漂亮鼠
原文链接:https://mp.weixin.qq.com/s/3phgI8yaPns3Dx5oSkdeYg

0x00 引言

这些年看到几个很有灵性的年轻人从一个啥也不懂的脚本小子一年时间就成长为业内漏洞挖掘机,一路交流下来也有不少的想法。当然也有看到一些年轻人好像一直很努力的在学,但是半年一年了,学了又好像没有学还是停留在复现漏洞用脚本的水平。这一上一下的差距一直令我困惑不已,是真的天赋问题?答案肯定是NO的,因为我一直认为天赋只会造成时间效率差距,不会在一个有手就行的地方带来门槛。就在最近p??直播了一场,也看到不少弹幕的同学在问:“我学了好久java还是挖不到洞,到底要学到什么程度才能挖0day呢?”这么一看这个问题是一个共性的问题,有必要深度解读一下如何破局。我之前有写过关于如何学习的文章,也写过挖洞思维建设,如果这两篇没有看过的话可以提前看一看,一些学习方法和思维模型在这里面都提过了比如设置checklist、项目管理、复盘等就不再说了。

0x01 明确观点

今天和群友也讨论了下这个问题,大家都有提到一些点:

  1. 怕麻烦,觉得这个环境麻烦,那个操作麻烦
  2. 怕代码,不爱动手,害怕动手
  3. 机械式复现,无论是打payload,还是动手跟着调试,都处于一种机械复现
  4. 缺少自信,认为rce很高端
  5. 沉迷学习,缺少实践

上面这些点确实都是很多同学的毛病,可能还会有别的点,如果你真的有这些毛病就赶紧改掉。除了改掉毛病以外,还要树立以下几个核心观念:

  1. 挖洞有手就行,不一定需要很高超的技巧(不是开玩笑,认真理解这句话记在心里)
  2. 挖洞需要学习基础,但不能陷入到无限理论中
  3. 挖洞需要的不是天赋,需要的是专注、勇气、自信和努力

当然如果你改掉了还是挖不到,那么你就可以继续往下看了。

0x02 为什么漏洞复现很多却挖不到洞

先说一下漏洞挖掘和漏洞复现这两个流程在模式上的根本区别。当你需要去复现一个漏洞的时候,你获得了几个前提:

  1. xxx组件存在xxx漏洞这个信息提示
  2. 你可能有了一些泄漏部分的payload截图
  3. 你可能有了完整的复现文章

在这些前提下,你的目标会变得很明确,随着条件的完善复现的难度越来越低,当已经有完整复现文章的时候,你甚至不需要自己去思考跟着操作即可。那么你在复现的时候如果不进行反思和归纳就会沦为F8工具人,整个流程下来你只是知道了这回事。如果你长期从事漏洞复现,然后第一次接到一个漏洞挖掘项目的时候会发生什么?你失去了前面漏洞复现时候所说的几个前提条件,失去了这些条件给你框定的明确路径后,由于你从来没有真正的自我决策过所以你陷入了无法决策的思维恐慌中。在一个真正挖掘项目里,你需要独立的去规划自己的工作流程,对每一次测试方向做决策,如果你缺少这种能力就应该从复现工作中进行总结归纳锻炼自己这种思维。

0x03 漏洞利用的逻辑

我没学过什么程序分析或者乱七八糟的理论基础,我根据我自己的理解定义几个概念吧。

  1. 可控输入,大家喜欢叫source,我可以控制的输入点
  2. 目标输出,大家喜欢叫sink,我在意的输出点
  3. 程序机制,这个简单来说就是处于输入与输出之间对整个数据进行各种花式变换和转移的固有程序逻辑或者是系统机制
  4. trick,一些技巧类的集合,比如绕沙箱、利用技巧绕过过滤、溢出到执行命令的利用等

那么一个简单漏洞的利用可以看成这么一个图

图片

这里的输入1是我们可控的输入,机制1是整个程序流转的过程,输出1比如是一个命令执行函数,那么我们就可以注入命令做到RCE了。这很简单没什么好说的,那么复杂一点呢?

图片

这个图里输入1依旧是用户侧可控的输入,输出3可以认为是最终的命令执行函数,那么中间的输出1可能是写配置文件,输出2可能是发送请求到别的端口,通过机制4和机制5将这些中间输出进行转化与搬运,最终把几个点串联起来做到输入1到输出3的命令执行。上面这个图主要还是关注一个数据传播和转化,那么再加上各个流程中可能会用到的trick就最终得到了一个完整的利用

0x04 技能分类

有了整体的利用思路后,我们需要对漏洞进行一定的分类

漏洞类型 分类标签 效果
SQL注入 代码执行 执行部分SQL语句,可能造成命令执行、数据获取、读写文件
XSS 代码执行 有限或无限的Javascript代码执行,可能获取cookie凭证
命令注入 命令执行 直接拼接命令执行系统命令
反序列化 代码执行 有限或无限的执行java代码,或根据gadget的不同执行各类操作,比如读写文件、发起请求等
SSRF 网络请求 有限制或无限制的发起各类请求转发,将部分可控数据通过网络进行转发
加密缺陷 伪造 加解密的问题可以统一归为各类伪造,包括伪造凭证、数据包签名等
任意读 敏感信息获取 读取各类敏感信息
任意写 写文件 写各种文件,通常配合系统机制或者框架机制,任意写文件大概率可以串代码执行或者命令执行
未授权访问 权限校验缺失 权限校验缺失,可以访问各类需要鉴权的接口
内存溢出 代码执行 内存溢出后如果利用成功通常可以造成任意代码执行、改变程序判断条件

当然漏洞类型不止这些,这里只是示意的举了例子,大家可以参考owasp的所有漏洞类型然后列一个类似的表格,把每一个类型的漏洞所能达到的效果给列举一下。列举完成后我们就可以开始组合RCE的combo了,比如常见的连招:

  1. 未授权访问+命令执行
  2. 未授权访问+反序列化
  3. 未授权访问+任意写+系统机制(PHP的webshell或者Linux的crontab)
  4. 未授权访问+SSRF+本地进程未授权+命令注入
  5. 加密缺陷可构造凭证+后台命令执行功能
  6. 未授权访问+SSRF+内存溢出

还有一些特定场景的连招:

  1. XSS+electron
  2. 未授权+fastjson
  3. 人工点击+XSS+electron

当然不止这些combo,你能想象到的组合都可以试一试,一般来说要实现RCE,最后一个终结技都是要跟上代码执行或者命令执行或者是写文件的漏洞类别,而在终结技前面的漏洞类别通常选各类未授权以及各类数据搬运如SSRF,甚至于XXE也能作为SSRF来用。这也是为什么我们需要把每种漏洞类型所能造成的效果都罗列一下,这种罗列有助于组合combo。(一旦你思路打开,受限制的反序列化也可以是一种SSRF) 在我们罗列各类漏洞类型和他们所能造成的影响时,我们不应该过多的关注自己是否实际掌握具体的利用方式,比如学web的通常不懂内存溢出,那么他们可能就不会考虑内存溢出作为其中一个RCE的终结技。但实际上,你就算是不会,你在寻找整个利用链路的时候都应该把它考虑进去,如果链路能走通再考虑实际的利用。

0x05 决策路径

有了前面的铺垫,我们在拿到一个全新的项目的时候就可以开始为RCE做规划了。可以分为几个步骤:

  1. 搜集信息,对功能和三方组件进行了解,大致对可能的combo有个预测
  2. 根据预测的combo搜寻对应的sink,找出几个可能的独立的漏洞片段
  3. 尝试进行简单的片段串联,如果能够快速串联那么很有可能就已经RCE了
  4. 如果几个漏洞片段无法串联,那么需要深入学习整个程序的内在运作机制包括所在系统的一些机制
  5. 利用各种机制曲线的将几个漏洞片段串联到一起
  6. 串联完毕后,深入到解决具体的细节问题,比如利用一些trick来绕过过滤、穿透沙箱等
  7. 期间可以配合黑盒测试的一些方式来进行调试,避免纯白盒的单步跟进
  8. 最终完成RCE

0x06 学习别人RCE的时候我们关注什么

我们学习各种漏洞复现技巧的时候,我们应该关注什么?根据我前面说的,我们应该重点看这个文章里运用了哪些技巧,比如如何绕过过滤、用了哪些偏门gadget。其次关注这个产品、这个组件它的整体框架逻辑是什么样的,他有哪些有趣的功能机制是可以拿来串联链。我们可以忽略什么?繁琐的各种函数跟进,根本毫无意义,随便看看就行了,除非你也专门研究这个产品的0day挖掘那么你可以细致的看一看,如果你想用它来挖别的产品那么你可以直接忽略掉很多没有用的函数跟进,只看那些对数据有一定复杂过滤操作的典型函数就行了。

0x07 结语

由于是半夜写的,有点困写的有点乱,如果展开讲其实还有很多其他经验可以再讲讲,这里重要的还是3、4、5章所讲的几个概念,看过了自己再去实施就行了。不要总是想着基础差就挖不到,我之前复现jumpserver和grafana的时候,我压根就不懂Go语法,就纯粹的按照上述的方法论来走,即使我不懂Go,我知道我需要找到什么、需要去串联什么,剩下的不过是百度百度看不懂的语法罢了。总之就是一句话:just do it


Paper 本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/1809/