堆漏洞在二进制中是非常常见的,之前一直觉得CTF-Pwn的堆题没有任何实战价值,之后开始实战漏洞挖掘后发现大部分挖出来的奔溃样本都是堆内存相关的,这就引发了思考,堆内存触发的奔溃大部分都只能触发溢出到底该如何利用呢?但是我觉得这个应该是我自己的知识范围不够,之后去分析了很多其他的堆相关漏洞利用,但往往利用思路都不能够通用,所以出了这篇文章记一次sudo堆溢出如何逆向分析出提权思路,旨在以 sudo 提权漏洞为例,进行从漏洞挖掘到提权思路的全链路分析,为漏洞研究与防护提供更全面的参考。
本文只在提供一个在实战中堆溢出漏洞的可利用思路,网上的其他文章都只是零散的将 POC 进行分析,并没有解析出其中可以通用的堆操作手法,比如利用setlocale构造堆风水等等。分析和编写过程中可能有疏漏,如有问题请各位读者不吝指正一,文章概述
二,sudo调研与Fuzz方式考察
三,修改sudo源码与进行AFL++模糊测试:主要是学习命令行参数fuzz
四,收集奔溃样本与分析奔溃原因:使用pwngdb动态调试定位堆溢出漏洞成因
五,奔溃样本逆向分析进行可利用性评估:通过分析整个程序的堆操作,思考提权和堆构造思路
六,劫持NSS服务用户对象实现提权原理:有思路后具体分析提权原理
七,解析setlocale能够进行堆布局原理:整理调试弄清setlocale的堆构造规则
八,基于已有的思路构造可以利用的POC
CTF-Pwn的堆题和实战堆漏洞的相关联系:Pwn的堆题提供了,操控堆结构的明确接口增删改查都有,但是在实际漏洞利用的时候是不会提供这些接口的,但是程序中必然会有堆操作,需要了解整个Linux机制,和逆向分析程序中的每一个堆操作,来筛选出可以控制的增删改查的堆操作!进而提升堆漏洞的可用性和实际价值!
sudo(superuser do)是 Linux 和 Unix 系统中常用的命令,可以让普通用户以root权限执行命令 。它通过配置文件 /etc/sudoers 来管理用户权限。普通用户需要安装软件包,就可以通过 sudo 命令以 root 权限调用apt,无需切换到 root 账户,非常便捷。
当用户执行 sudo 命令时,会检查用户是否在 sudoers 文件中有相应的权限配置。有权限,sudo 会提示用户输入自己的密码,验证通过后,sudo 会切换到root身份,执行后续命令。执行完毕后,再恢复到原用户身份。而常规的Fuzz测试是通过向程序输入大量随机或变异数据,检测程序是否会出现崩溃、内存泄漏等异常情况。一般的输入方式是通过stdin或者文件输入,但是sudo的使用方式大部分是通过命令行参数实现的,且sudo的常规使用逻辑也会和Fuzz 存在诸多冲突之处:
1.密码输入问题:sudo 执行需要输入密码,在自动化的 Fuzz 测试过程中,若等待密码输入,程序会挂起,导致测试中断。
2.命令行参数处理:向 sudo 导入模糊测试数据时,需要考虑如何正确传递参数,避免因参数格式错误导致 sudo 无法执行或执行错误。
3.参数控制难题:sudo 测试过程中的第一个参数(通常是要执行的命令)需要精准控制,若参数错误,可能无法触发有效测试或引发系统错误。
4.程序内部实现复杂性:sudo 内部不仅实现了 sudo 功能,sudoedit 工具的代码实现也在 sudo 程序内部,通过软链接替换启动程序名称来区分功能。因此,进行 Fuzz 测试时,必须指定正确的启动程序名称,才能对 sudo 及其相关功能进行全面检测。一、argv_fuzz 功能概述
传统的 AFL 工具支持对文件输入或标准输入进行模糊测试,而 AFL++ 的argv_fuzz工具,位于官方 GitHub 仓库的utils/argv_fuzzing目录下AFLplusplus/utils/argv_fuzzing at stable · AFLplusplus/AFLplusplus (github.com),专注于对通过命令行界面传递给程序的参数进行模糊测试。这意味着它能够模拟各种不同的命令行参数组合,帮助我们发现程序在处理参数过程中可能存在的漏洞.
在实际应用中,例如在对 Curl 程序的审核中,通过对argv的模糊测试,成功挖掘出了程序中的重大安全隐患 ,案例:Curl 审核:一句玩笑话引出的重大发现_测试_参数_argv当我们拥有目标程序的源代码时,可以借助argv-fuzz-inl.h头文件中的宏,改变程序的行为,使其从标准输入构建argv,进而实现对命令行参数的模糊测试。
准备工作:首先,在源文件中包含argv-fuzz-inl.h头文件,即添加#include "argv-fuzz-inl.h"语句。接着,找到程序中负责解析参数的主函数,通常形式为int main(int argc, char **argv) 。宏的使用:在主函数开头附近,根据需求选择合适的宏来初始化argv。若无需保留argv[0](程序名称),可使用AFL_INIT_ARGV();;若希望保留argv[0],则使用AFL_INIT_SET0("prog_name");,其中"prog_name"需替换为实际的程序名称。具体使用示例可参考argv_fuzz_demo.c文件(argv_fuzz_demo.c)。在进行针对 sudo 的 Fuzz 测试前,对 sudo 源码的修改以及相关准备工作起着关键作用。能让后续测试流程更为顺畅地开展,另一方面,合理地准备如控制测试过程中的参数、准备模糊测试种子样本以及搭建好合适的测试环境(像 Docker 容器环境、配置编译开启 Asan 模式等),都是为了能更全面、高效且准确地对 sudo 及其相关功能进行模糊测试,从而提高目标程序的覆盖率以及获取更多有价值的测试样本。为解决 sudo 密码输入导致程序挂起问题,直接将sudo的密码验证函数patch掉,想要利用sudo的漏洞肯定是要站在无密码的角度来的,不然漏洞价值不高,将verify_user的返回值为0,表示密码错误!默认返回0确保密码错误!通过编写测试用例,明确规定 sudo 测试过程中第一个参数的取值范围和格式。在 Fuzz 测试工具中设置参数生成规则,确保生成的参数符合要求。可以结合正则表达式等方式,对参数进行合法性校验,保证测试的有效性。添加头文件:#include "/AFLplusplus/utils/argv_fuzzing/argv-fuzz-inl.h"在进行 Fuzz 测试前,需要根据测试目标,明确指定启动程序名称。可以在测试脚本中设置变量,根据不同的测试场景切换启动程序名称,如sudo或sudoedit,从而实现对 sudo 及其相关功能的全面测试。AFL_INIT_ARGV和AFL_INIT_SET0为了限制sudo的参数来触发漏洞!
AFL++生成的数据将输出生成到文件或stdout中,但是需要模糊测试命令行参数。需要自行修补sudo源码,使用这两个宏都可以忽略实际的argv并将其改为从stdin。该函数会将输入的程序如果为sudoedit的话,在该函数会被修改为sudo,所以也需要patch掉!
小技巧,在修改argv的参数后,直接在程序结束
...(已截断)
---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-286757.htm
[原创]Fuzz挖掘sudo提权漏洞:一次堆溢出如何逆向分析出提权思路
174 浏览
2 回复
好文章,很少见到有能对整个fuzz全流程进行如此细致分析的文章。
有大佬可以找回被骗的钱吗,现在实在坚持不住了,报酬好说