Skip to content

WeeklyReads #90

Description

@xinali
作者: xina1i
建立: 2025.06.12
更新: 2025.12.12

阅读周报

--------------------------------------------------------------------
目录:
    ☆ 第001周(2025.06.12-2025.06.13)
    ☆ 第002周(2025.06.16-2025.06.20)
    ☆ 第003周(2025.06.23-2025.06.27)
    ☆ 第004周(2025.06.30-2025.07.04)
    ☆ 第005周(2025.07.07-2025.07.11)
    ☆ 第006周(2025.07.14-2025.07.18)
    ☆ 第007周(2025.07.21-2025.07.25)    
    ☆ 第008周(2025.07.28-2025.08.01)    
    ☆ 第009周(2025.08.04-2025.08.08)
    ☆ 第010周(2025.08.11-2025.08.15)
    ☆ 第011周(2025.08.18-2025.08.22)
    ☆ 第012周(2025.08.25-2025.08.29)
    ☆ 第013周(2025.09.01-2025.09.05)
    ☆ 第014周(2025.09.08-2025.09.12)
    ☆ 第015周(2025.09.15-2025.09.19)
    ☆ 第016周(2025.09.22-2025.09.26)
    ☆ 第017周(2025.09.27-2025.10.11)
    ☆ 第018周(2025.10.13-2025.10.17)
    ☆ 第019周(2025.10.20-2025.10.24)
    ☆ 第020周(2025.10.27-2025.10.31)
    ☆ 第021周(2025.11.03-2025.11.07)
    ☆ 第022周(2025.11.10-2025.11.11)
    ☆ 第023周(2025.12.08-2025.12.12)
--------------------------------------------------------------------

☆ 第001周(2025.06.12-2025.06.13)

1. How I used o3 to find CVE-2025-37899, a remote zeroday vulnerability \
    in the Linux kernel’s SMB implementation
  
    链接:https://sean.heelan.io/2025/05/22/how-i-used-o3-to-find-cve-2025-37899-\
        a-remote-zeroday-vulnerability-in-the-linux-kernels-smb-implementation/

    文章详细介绍了作者如何利用OpenAI的o3模型发现Linux内核ksmbd模块中的一个远程零日漏洞,
    其中使用到的prompt及相关资料在这里: https://github.com/SeanHeelan/o3_finds_cve-2025-37899。
    作者是把比如logoff整个处理路径发送给AI+部分基础信息的补充和适当的prompt,经过多次尝试,让AI去理解并发现漏洞。

    文章中的方法也是我最近在使用的方法,比如我会把windbg的详细调试过程+ida伪代码+一些注释信息+适当的prompt
    发送给gemini 2.5 pro preview, 然后让他分析漏洞的类型以及是否可利用,
    gemini目前处理效果我特别满意。根据该文章,我需要升级提供的信息,
    逆向出整个调用处理过程(整个调用栈)+注释,这种可能会更加的适合去发现漏洞并确定具体的漏洞类型。

2. Windows Remote Desktop Gateway (RD Gateway) CVE-2025-21297的介绍
    
    链接: https://v-v.space/2025/05/15/CVE-2025-21297

    CVE-2025-21297是一个由于全局变量初始化过程中的竞争条件(Race Condition)导致的释放后重用/UAF漏洞
    其实直接将如下代码,交给gemini分析,gemini也会完整的给出一个竞争条件的漏洞分析

    -----------------------------------------------------------------------
    struct CTsgMsgServer *CTsgMsgServer::GetCTsgMsgServerInstance(void)
    {
        v0 = CTsgMsgServer::m_pMsgSvrInstance;
        if ( CTsgMsgServer::m_pMsgSvrInstance )// a0
            goto LABEL_9;
        v1 = operator new(0x70ui64);
        if ( v1 )
        {
            v1->ref = 1;
            CTsgMsgServer::m_pMsgSvrInstance = v1; // a1
            ......
            v0 = CTsgMsgServer::m_pMsgSvrInstance;
        LABEL_9:
            v4 = (v0 + *(v0->_0_60h_0h + 4i64));
            (v4->f_0h->func_AddRef_CAAAuthenticateUserSink_180006ce0_0h)(v4);
            return CTsgMsgServer::m_pMsgSvrInstance;// a2
        }
    }
    -----------------------------------------------------------------------

    CTsgMsgServer::m_pMsgSvrInstance为单例模式,在单线程模式下不会出现问题,但是在多线程模式下就可能产生竞争条件

    a. 提供一个全局唯一的 CTsgMsgServer 对象实例。
    b. 在第一次调用该函数时,才创建这个实例(即“懒加载”)。
    c. 后续所有调用都返回这个已经创建好的实例。
    d. 代码中还包含了引用计数的逻辑(AddRef),这表明该实例的生命周期可能是通过引用计数来管理的。

    问题出现在检查实例是否存在和创建实例这两个操作是否是原子性的,如果不能保证原子性,那么就会造成单例模式被破坏,
    创建多个m_pMsgSvrInstance, 在m_pMsgSvrInstance某个被释放后再使用就会造成UAF


☆ 第002周(2025.06.16-2025.06.20)

1. 使用微软TTD API实现自定义跟踪(Trace)
    链接: https://www.52pojie.cn/thread-2039822-1-1.html

    根据四哥分享的内容阅读。

    我阅读了文章内容,ttd和detours我都用过,结合使用,目前还没有用过,感觉正常使用ttd就是大炮打,
    使用这种方式类似一种精准手术刀 没有实操过,用gemini总结了一下,做个记录,可能以后调试大项目会用到

    实现精确跟踪(Precision Tracing):
        允许开发者只录制他们真正关心的代码片段。例如,只在一个已知的、会触发 bug 的函数执行期间进行录制。
        大幅减小跟踪文件体积,便于存储和传输。

    提高调试和分析效率:
        由于跟踪文件只包含关键部分,调试器加载和分析的速度会快得多。
        开发者可以直奔主题,无需在时间线上来回寻找问题发生点。

    自动化和脚本化调试:
        通过 API,可以将 TTD 功能集成到自动化测试框架或自定义的诊断工具中。
        可以编写脚本,在满足特定条件时(例如,检测到某个错误日志、某个值异常)才自动启动 TTD 录制,捕获“犯罪现场”。

    解决复杂和偶发性 Bug:
        对于那些在程序运行了很长时间后才偶尔出现的 bug,不可能一直开着 TTD。利用这种技术,
        可以设置一个触发器,在 bug 即将发生前(例如,进入某个可疑模块时)才开始录制,极大地提高了捕获这类问题的成功率。

2. ZDI-25-310: Remote NULL Deref in Linux KSMBD
    链接: https://slavamoskvin.com/zdi-25-310-remote-null-deref-in-linux-ksmbd/

    其中漏洞分析内容,没啥意思,主要是

    -----------------------------------------------------------------------
    For obscure targets, the fuzzer choice doesn’t matter much.
    For high-profile targets, you have to demonastrate a novel approach:
        * find a new attack surface
        * combine fuzzers/fuzzing modes, craft a perfect input corpus, 
            and run a well-organized campaign or come up with a new fuzzer that does something different

    I wanted to avoid writing syscall/protocol definitions, 
    so the fuzzer had to be mutational. Sure, there were already plenty of 
    network fuzzers out there—united by their ease of use, 
    simplicity and probaly having zero chances to find anything in the kernel.

    BUT—there was one thing nobody had tried: 
    combining a network fuzzer with coverage-based feedback. 
    AND fuzzing over network had a huge advantage. 
    While being painfully slow, 
    it has the potential to walk through full state machines and hit proper network APIs, 
    potentially triggering side effects.
    -----------------------------------------------------------------------

    作者的理解是,对于非热门项目,选择什么fuzzer其实无所谓,选择热门项目的话,需要考虑

    - 找到新的攻击面
    - 创新的混合模糊测试方法/优化输入语料

    如果不能做到上面两点,对于热门项目,简单地重复使用现有工具难以产生突破

3. File Fuzzing: Easy and Really Fast with new AFL++ Features
    链接: https://slavamoskvin.com/file-fuzzing-easy-and-really-fast-with-new-afl-features/

    需要关注fuzzer的性能迭代

    1). Harness 1.0: 传统方法 (Fork Server):
        代码: FILE *fp = fopen(argv[1], "r");
        评价: 能用,但性能低下。每次测试都需要fork一个新进程并进行文件I/O,开销巨大。

    2). Harness 2.0: AFL++持久模式 (Persistent Mode):
        代码: while (__AFL_LOOP(...))
        评价: 速度大幅提升,因为它在同一进程内循环执行目标函数。但作者也坦言,AFL++原生的持久模式宏语法“有点笨拙”。
    
    3). Harness 3.0: 业界标准 (libFuzzer-style):
        代码: int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
        评价: 这是文章推荐的最佳范式。 语法更优雅。
        兼容性极强: 同一个Harness无需修改即可被AFL++、libFuzzer、honggfuzz三大主流Fuzzer使用,成本为零,收益巨大。
    
    4). Harness 4.0: 终极优化 (In-Memory with fmemopen):
        代码: FILE *fp = fmemopen(Data, Size, "r");
        评价: readconf需要一个FILE*指针,新手可能会通过fwrite将Fuzzer的内存数据写入临时文件再打开。
              而fmemopen函数可以直接将内存缓冲区(buffer)“伪装”成一个文件流,完全消除了文件系统的读写开销。


☆ 第003周(2025.06.23-2025.06.27)

1. ksmbd vulnerability research
    链接: http://blog.doyensec.com/2025/01/07/ksmbd-1.html

    跟上周的主题一样,上周注意的是使用新思路去找ksmbd的漏洞,这周主要集中在处理问题的方式上

    状态协议的模糊测试: 
        SMB 是一个有状态的协议,后续的请求依赖于前序请求(如 Session Setup)。
        syzkaller 原生更擅长无状态的 syscall 模糊测试。
        解决方案 (数据包标记): 研究者通过在第一个协商包中附加8字节的 procid (syzkaller 实例ID) 来标记连接,
            使得内核可以区分不同 fuzzer 实例的流量。这是一个非常实用且常见的解决思路,
            用于在基于套接字的 stateful 协议模糊测试中建立输入与 fuzzer 进程的关联。

    绕过身份验证: 
        为了测试认证后的代码路径,必须处理复杂的认证流程(如 NTLMv2)。
        解决方案 (内核补丁): 由于 syzkaller 的 pseudo-syscalls 中难以实现 malloc() 和复杂的加密逻辑,
            研究者选择直接修改内核代码,patch 掉认证和包签名校验。
            这是一个高效的工程决策,它极大地扩展了模糊测试能够触及的代码覆盖范围,
            使得 fuzzer 可以直接构造和发送需要认证会话才能处理的 SMB 命令。

    语法生成与语料库优化:
        解决方案 (Kaitai Struct & strace): 他们通过 strace 捕获合法的 SMB 客户端通信,
            并使用 Kaitai Struct(一个二进制格式解析工具)来分析和理解 SMB 协议数据单元 (PDU) 的结构。
            这帮助他们为 syzkaller 编写更精确的语法描述(grammar),从而生成更有效、更深入的测试用例。

    利用上述的方法,介绍了发现的三个漏洞:
    并发错误 (Concurrency): 忘记在共享数据结构的关键部分加锁。
    状态管理错误 (State Management): 错误的引用计数操作。
    资源管理错误 (Resource Management): “先分配,后验证”的逻辑顺序错误。

2. Tickling ksmbd: fuzzing SMB in the Linux kernel 
    链接: https://pwning.tech/ksmbd-syzkaller/

    算是上一篇文章的前序,详细介绍了如何使用syzkaller fuzz ksmbd

    介绍了如下几个技术亮点

    SMB 协议语法定义 (ksmbd.txt): 
        为 Syzkaller 编写了 SMB 请求的数据结构定义。
        强调使用 [packed] 属性是关键的一步,这完全符合二进制网络协议的规范,可以防止编译器插入填充字节,
        确保生成的测试用例在协议层面是有效的。

    伪系统调用 syz_ksmbd_send_req: 
        将Syzkaller从一个系统调用fuzzer扩展为网络协议 fuzzer 的核心。
        作者实现的 syz_ksmbd_send_req 函数逻辑清晰:
            a. 建立一个标准的 TCP 客户端套接字,连接到本地的 127.0.0.1:445。
            b. 关键操作: 
                在发送 Syzkaller 生成的 SMB 数据包 (payload) 之前,
                在数据包头部预置 (prepend) 了8字节的 procid(进程ID)。
                这个看似简单的操作,是后续实现 KCOV 覆盖率跟踪的基石。
            c. 发送数据包并尝试读取响应。
    
    网络命名空间 (Namespace) 的处理: 
        Syzkaller 默认会为 fuzzer 进程启用新的网络命名空间以实现沙箱隔离。
        这导致 fuzzer 进程无法访问在根命名空间中监听的 ksmbd 服务。
        作者的解决方案是直接修改 Syzkaller 源码,注释掉 unshare(CLONE_NEWNET) 的调用。
    
    KCOV 覆盖率收集
        收集问题: 
            内核网络栈通过软中断 (softirq) 来处理接收到的数据包。
            中断上下文没有关联的进程上下文 (process context),因此标准的 KCOV 无法工作,
            导致 fuzzer 无法获取 ksmbd 处理逻辑的覆盖率反馈,退化为随机的“黑盒”测试。
        解决方案 (Remote KCOV): 
            作者放弃了修改复杂网络子系统的想法,转而采用了更精巧的 Remote KCOV 机制。实现步骤堪称经典:
        传递句柄: 
            在用户态的 syz_ksmbd_send_req 中将 procid 作为 KCOV 句柄附加到每个数据包的开头。
        接收并存储句柄: 
            修改 ksmbd 内核代码,在连接处理主循环 ksmbd_conn_handler_loop 的起始处,
            首先读取这8字节的句柄,并将其存储在 struct ksmbd_conn 结构体中。
            这确保了在整个 TCP 连接的生命周期内,KCOV 句柄都是可用的。
        在正确的位置启动/停止 KCOV:
            作者发现,ksmbd 使用工作队列 (workqueue) 来异步处理具体的 SMB 请求 (handle_ksmbd_work)。
            如果只在连接建立时启动 KCOV,那么在工作队列调度后,上下文同样会丢失。
            精髓之处: 作者在两个层面都进行了 KCOV 的启动/停止操作:
            一是在 ksmbd_conn_handler_loop 的外层循环,
            二是在 handle_ksmbd_work 函数内部。这确保了无论是连接层面的代码,
            还是具体请求处理的代码,其执行路径都能被正确地关联到最初的 fuzzer 进程,从而收集到完整的代码覆盖率。


☆ 第004周(2025.06.30-2025.07.04)

1. linux内核fuzz三部曲

    来源于x上的一个博文:https://x.com/0xor0ne/status/1939942255789314401
    正好跟我上周看的内容以及我最近正在学习的内容一致,所以一口气把三个都看了

    1). Hunting Bugs in Linux Kernel With KASAN: How to Use it & What's the Benefit?
        链接: https://slavamoskvin.com/hunting-bugs-in-linux- \
            kernel-with-kasan-how-to-use-it-whats-the-benefit/

        这篇文章比较简单,作者在挖掘内核漏洞时,举一个TOCTOU的例子,来论证使用KASAN能够帮助更好的发现漏洞,
        两次fetch之间的时间窗口通常只有几十到几百个CPU周期。简单的多线程PoC很难稳定地在该窗口内完成内存修改
        作者发现他的越界读“不足以让内核崩溃”。可能只是读取到了相邻对象的元数据或填充字节,并未访问到未映射或受保护的页面,
        因此不会立即触发Page Fault。然而,这依然是一个严重的安全漏洞,可能导致信息泄露
        在他开启KASAN从而帮助复现漏洞的过程。主要就是推荐了一波在内核漏洞挖掘时开启KASAN

    2). Finding Bugs in Kernel. Part 1: Crashing a Vulnerable Driver with Syzkaller (*)
        链接: http://slavamoskvin.com/finding-bugs-in-kernel.-part-1-\
            crashing-a-vulnerable-driver-with-syzkaller/

        这篇文章算是上一个文章的具体实践和升级版,以实践为导向的Syzkaller入门教程。
        作者通过一个精心设计的、包含已知漏洞的自定义内核模块,系统性地演示了将一个“未知”目标(out-of-tree模块)
        集成到Syzkaller模糊测试框架的全过程 

        a. 编写一个存在溢出漏洞的内核驱动

            --------------------------------------------------------------------------------
            static long vuln_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {
                char buf[256]; 
                struct ioctl_arg to; 
                int res;

                switch (cmd) {
                    case IOCTL_CMD:
                        // 第一次拷贝:从用户空间获取ioctl_arg结构体
                        res = copy_from_user(&to, (int32_t*) arg, sizeof(to));
                        if (res != 0) { return -1337; }

                        // 第二次拷贝:使用用户提供的长度(to.size)
                        res = copy_from_user(buf, (int32_t*) arg, to.size);
                        if (res != 0) { return -1338; }

                        // ... 后续代码 ...
                        break;
                }
                return 0;
            }
            --------------------------------------------------------------------------------

            编译为vuln_ioctl.ko

        b. 实现模块自动加载
            为了确保每次Syzkaller启动一个新的VM实例时,我们的目标驱动都能被加载,
            作者采取了一个非常直接有效的方法:修改VM的启动脚本。
            在VM的/etc/init.d/S50sshd(或者其他等效的启动脚本)中,添加了一行命令:

            insmod /vuln_ioctl.ko

            作者通过重启VM并执行lsmod命令,确认了vuln_ioctl模块已成功加载,证明了这一自动化步骤的有效性

        c. 创建定向Fuzzing的Syzkaller配置文件
        
            根据syzlang编写配置文件

            --------------------------------------------------------------------------------
            // syzkaller/sys/linux/vuln_ioctl.txt

            // 1. 定义一种新的资源类型
            resource fd_vuln_ioctl[fd]

            // 2. 告诉Syzkaller如何获取这个资源
            //    定义一个openat的变体,专门用于打开我们的设备
            openat$vuln_ioctl(fd const[AT_FDCWD], file ptr[in, string["/dev/vuln_ioctl"]], ...) \
            fd_vuln_ioctl

            // 3. 描述我们自定义的ioctl
            ioctl$IOCTL_CMD(fd fd_vuln_ioctl, cmd const[IOCTL_CMD], arg ptr[in, ioctl_arg])

            // 4. 描述ioctl的参数结构体
            ioctl_arg {
                size    len[data, int64]
                data    array[int8]
            } 
            --------------------------------------------------------------------------------

        d. 启动syz-manager并监控运行

        整个文章我会跟着操作一遍,会单独写一篇文章来进行syzkaller的入门


    3). Finding Bugs in Kernel. Part 2: Fuzzing the Actual Kernel (*)
        链接: https://slavamoskvin.com/finding-bugs-in-kernel.-part-2-fuzzing-the-actual-kernel/

        算是上一篇的实战版本,上一篇是自己写一个存在漏洞的驱动,这一篇直接在linux内核中寻找漏洞
        
        a. 选择挖掘漏洞目标模块
            选择的条件:syzbot 中的模块 0 < linux module < 15-20
            候选模块:jffs2, bcachefs, net/atm, net/tipc ...
            确定模块:TIPC和SMC
            解释原因:
                标准化接口: 网络协议栈大多遵循BSD Socket API,接口(socket, bind, connect, setsockopt)
                高度标准化,易于被Fuzzer理解和操作。
                无物理硬件依赖: 大多数网络协议(特别是像TIPC这种集群间通信协议)可以在虚拟网络环境中被完全模拟和测试,
                无需特定网卡。
                状态机复杂: 网络协议内部充满了复杂的状态机(连接建立、关闭、数据传输、错误处理等),
                这些复杂的状态转换正是滋生逻辑漏洞的温床。
        
        b. 深入分析代码,选择攻击面
            攻击面主要有两个 tipc具体实现和socket对于tipc的处理
        
        c. 理解攻击面的基础上,进行差异分析
            比对现有syzlang描述与真实攻击面之间的差距。
            现有描述: 作者发现Syzkaller已经有了socket_tipc.txt和socket_tipc_netlink.txt,
                覆盖了大部分TIPC接口。
            发现的差距: 作者发现了一个setsockopt选项TIPC_NODELAY在syzlang中没有被描述。
        
        d. 针对差异编写syzlang并开始挖掘测试

        同样我也会对该文章进行操作复现


☆ 第005周(2025.07.07-2025.07.11)

1. How to Avoid Procrastinating in Bug Bounty
    链接: https://trieulieuf9.blogspot.com/2025/07/how-to-avoid-procrastinating-in-bug.html

    很有意思的一篇文章,说的不是技术,而是挖洞的感觉
    如果你在挖洞的过程中,有如下信仰/感觉

    ----------------------------------------------------------------------------------
    - Bug bounty is very hard, only top hunters success.
    - Bug bounty is very hard, now is 2025, most of bugs are found already.
    - Bug bounty is very hard, mass automation and AI will find most of the bugs soon.
    - Bug bounty is very hard, these websites are built by top programmers, 
        their code are very solid, I will have no chance to find bug here.
    - Bug bounty is very hard, there are people spend 100+ hours in it and found nothing.
    - Bug bounty is very hard, developers are using programming frameworks, 
        they code properly now, no chance for bug.
    ------------------------------------------------------------------------------------

    说明你在等待某个"完美时刻",为了这个完美时刻,你可能会有如何行为/想法

    - I need to watch many videos, read many articles about IDOR, b
        efore I can start hunting for IDORs.
    - I need to do all easy and medium labs on PortSwigger before I can start.
    - I need to do some CTFs to gain skills, before I can start.
    - I need to learn web development skills, 
        so that I understand how the target websites work, before I can start.
    - I need to master Linux terminal, before I can start.
    - I need to read this book about bug bounty, before I can start.
    - I need to spend a month to learn Python (or Go), before I can start.

    其实浅显一点意思就是不要把漏洞挖掘看的过于的高深,你需要学习大量的基础知识之后才开始,干就完了
    漏洞挖掘跟我们生活中的做饭,锻炼身体等等的事都是一样的,你大概率不会为了做好饭去看大量的做饭视频
    更多的是直接上手干,边实践边总结,边成长。
    对漏洞挖掘很有教育意义的一篇文章。就跟茧房经常说的一句话:等没有用,干就完了!

2. ZDI-24-821: A Remote UAF in The Kernel's net/tipc
    链接: https://sam4k.com/zdi-24-821-a-remote-use-after-free-in-the-kernels-net-tipc/

    这篇文章跟上周看到的使用syzkaller测试TIPC一样,它也是使用syzkaller测试的,但是文章没有把方法漏出来
    文章只是重点描写了漏洞分析的过程。值得看一看,主要是想通过该描述看看是否能够通过AI将该方法给勾出来

    该UAF漏洞的根本原因是在net/tipc/msg.c的tipc_buf_append()函数的错误处理路径中,存在一个逻辑缺陷导致的

    漏洞成因由如下几个过程:
    1) 在分片重组过程中,一个新到达的分片(由struct sk_buff *frag代表,并通过struct sk_buff **buf传入)
    的内存管理所有权会从调用者转移到头部分片(struct sk_buff *head)。
    一旦该分片被成功地合并(coalesce)或链接(chain)到head的frag_list中,head就全权负责其生命周期管理。

    2) 在处理最后一个分片(LAST_FRAGMENT)时,代码会先将其链接到head,然后调用tipc_msg_validate()
    对重组后的完整消息进行验证。如果验证失败,程序将跳转到err:标签处执行清理。

    3) err:标签下的代码块执行了以下两个关键操作:
        kfree_skb(*buf); // 释放当前分片(即最后一个分片)
        kfree_skb(*headbuf); // 释放头部分片
        其中*buf指向最后一个分片,*headbuf指向第一个分片(即分片链表的头)。
        在跳转到err:之前,最后一个分片已经被加入到headbuf的frag_list中。

    4) 第一个kfree_skb(*buf)调用将最后一个分片的sk_buff结构体及其数据区释放,
            内存被返还给内核的slab分配器。
       第二个kfree_skb(*headbuf)调用在释放头部分片时,会遵循sk_buff的规范,
       遍历并释放其frag_list中的所有分片。skb_release_data()函数会检查到frag_list非空,
       并调用kfree_skb_list_reason()来遍历这个链表。由于frag_list的第一个(也可能是唯一一个)
       节点就是刚刚被释放的最后一个分片,kfree_skb_list_reason()会尝试从这块已经释放的内存
       中读取next指针(segs->next),从而导致了Use-After-Free。

    结论: 
    直接原因是err:代码块错误地对一个已经转移了管理所有权并即将由其父对象(headbuf)
    统一释放的子对象(buf)进行了独立的、过早的释放,从而导致父对象在后续的清理流程中访问了已被释放的子对象内存。

    文章也详细分析了TIPC message的组装和分发流程,这个可以和上周的文章一起看,
    上周的是etsockopt选项TIPC_NODELAY没有被syzkaller官方测试,这周在复现上周内容时可以一起看


☆ 第006周(2025.07.14-2025.07.18)

    本周请年假

    年假简单记录,想到什么就写点什么

    2025.07.12下午的飞机,从合肥新桥机场飞长春龙嘉机场,落地龙嘉后,从龙嘉站出来去坐高铁,
    出机场能够明显感到非常的热,我的感觉是比以前我在东北上学热多了,之后坐动车到吉林站,
    从吉林站西站台出来直接打车回家了。这次打的是新能源出租车,去年因为请假的时间短,
    而且主要的目的是安葬岳母,所以很多事都忽略了。今年心态不一样所以可以细细观察出租车,
    吉林的出租车整体是真的脏啊,但是新能源给我的感觉是越来越多了。

    家里接近一年没有住人了,当时媳妇走的时候撒的除虫剂,地上"尸体斑斑",简单逗留一下把东西放下,就出门了,
    我和媳妇心情都还不错,不想现在就收拾屋子,先去浪一圈再回去不迟,哈哈哈。

    从家里出来直接打车去了我们以前住的那个家(房子已卖)的附近,基本每年回来都会来这里找找以前的回忆,
    这里回忆太多了,媳妇是从9岁左右一直在这里生活到接近30岁,搬家之后就随我来合肥了。
    在这里吃了很多东西
    1. 鸡汤豆腐串,貌似从我媳妇小学就开了,一直开到现在,但是我吃了几次都觉得一般:)
    2. 四川麻辣烫,目前为止我最喜欢吃的麻辣烫,一对安徽淮北夫妻开的店,味道没话说,真的好吃
    3. 小馋嘴烧烤,在我的记忆中,应该是从我上研究生开始开的,一个叔叔开的路边摊,叔叔明显也老了,
        头发比我在的时候要白了很多,在没来之前心里会觉得不卫生,不太想吃,但还是坐下来点了很多出串,
        等真正吃上了,心里还是很开心,真的很好吃,自己和媳妇喝了一瓶啤酒,吃着打包的麻辣烫,
        内心真的很满足。还是上学的味道,没有因为自己经济好点了而损失那种心情
    4. 小狮同学,东北平替版蜜雪冰城,连很多单品都跟蜜雪冰城基本一致,价格也很良心,整体喝着还行

    吃完喝完,接近晚上9点多了,我们就打车去了江边,吹着江边的冷风(虽然还是有点热),觉得心情很放松。
    在江边和媳妇儿子溜达了很久,顺便又吃了这边的特色冰糕,冰糕我很少吃,以前吃过但是味道基本已经忘了。
    这次吃,认真体会其中的味道才发现跟我们小时候用啤酒瓶换的雪糕原来是一个味道。
    一直走到了大概10点多一点,打车回家,回家就是不停的收拾收拾,忙到了11点才休息,
    但是失误了,没有想到吉林晚上会有这么热,即使我家是在半山上,依然热的整宿睡不好。
    在这种情况下,媳妇难得同意买了个风扇,因为她也被热的睡不好,哈哈哈:)

    接下来的几天基本就是在吉林吃吃吃+玩玩玩,然后顺便把目前住的房子的房本办了。
    又吃了很多东西
    1. 樱花墅,吉林特色的韩食,吃了朝鲜族大冷面、拌面、还有一个什么鱼,除了拌面觉得一般,其他都很好吃
    2. 喜家德水饺,酸菜肉的一绝,真的好吃,但是感觉没有媳妇做的好吃,真心的
    3. 就是火烤肉,吃了两次,一次和媳妇儿子,一次请客,他家的招牌肉筋很好吃,还有特色老式拌饭很好吃
    4. 常源烤肉非常面,我和媳妇吃着还行,不如就是火,但是我儿子特别特别喜欢吃他家的特色罗底,
        吃完之后嚷嚷了好多次要再去,但是太忙了,始终也没再去(可以考虑明年年假再去),
        还有他家的手擀面不错,媳妇挺喜欢吃
    5. 勾里家韩式料理,整个假期吃的最差的一顿,点了一份烤鳗鱼+一份八爪鱼+一份拌饭+一份小菜,花了200多,
        价格还可以,但是是真不好吃啊,鳗鱼和八爪鱼腥味很重,吃到嘴里会让人觉得恶心,
        拌饭又没入味,小菜给的又少,服务人员态度也一般,真是体验感特别差的一次
    
    带儿子和媳妇玩了很多
    1. 带儿子玩了VR,以前是他和妈妈玩过蜡笔小新的VR,但是没有交互,场景是固定的,这次玩的是一个抓猫猫的VR游戏,
        儿子觉得挺好玩,挺新奇的
    2. 带儿子第一次玩攀岩和高处行走,大人不给玩,只能他一个人玩,儿子一开始玩,直接吓哭了,
        我这个老父亲一个人安慰了好半天,给了很多很多鼓励才哄好,不哭后开始慢慢单子大了,
        先在蹦蹦床跟很多小朋友跳了半天,然后开始玩一个悬垂的网兜玩了很久,慢慢往上爬,
        爬完之后下来,我又给了很多的鼓励,胆子慢慢变大了,找叔叔帮了安全带,直接开始高处行走,总共三层,
        第一层还有点害怕,要我一直在下面跟着看,等他走到第二层,身后来了3个小朋友,叽叽喳喳的,
        儿子开始适应了,速度也快了,几个后面的孩子一直催儿子,最后别超过了,但是儿子也没有气馁,
        也没有太多的想法,就一个人慢慢的走完了,然后顺利下来,整个人比刚上去自信了很多,也开心的不行。
    3. 抓活鱼,这个有点像抓娃娃,但是是抓活鱼,机器手臂的夹子换成了一个小网兜,每次伸下去挖一下,然后上来
        没有在南方的景点看到过,很有意思,开始没有经验,就是看哪里鱼多就呼啦一下下去然后碰运气,
        后来玩的多了就有经验了,先把鱼赶到鱼缸的一个拐角,然后快速的移动到拐角,很容易就能抓住,
        是一次不错的体验。
    4. 游戏机
    5. 踩虫子

    图们之行/中朝边境
    在延吉打车的时候,一位司机师傅说图们很有意思,有个中朝边界口岸。我和媳妇都想去看看
    在延吉的最后一天上午包那个司机师傅的车就去了图们。
    去图们的路上,沿路风光特别好看。各种山山水水,山而且连绵不断,给人一种很渺小的感觉。
    我和媳妇讨论山上有啥,东北虎啦,各种各样的小动物啦,动物在冬天如何存活等等。
    这一路比在南方走高速有意思的多,这种类型的风景,我和媳妇都很少见,所以也很新奇。
    到了图们之后,师傅停车,我们就在中国边境这边溜达了。
    买了个门票,在86->87号国界碑之间穿梭了一下,然后在口岸大桥上使用望远镜看了图们江对面
    朝鲜人的很多物和人,很多游客很有意思,感觉我们像在看动物园一样在看朝鲜人。
    拍了很多照片,也上到了口岸最高处俯瞰,看到了两颗"大太阳"。
    在那边溜达了大概一个半小时,就跟司机师傅回延吉了。
    回来的时候,师傅问去哪里,正好我媳妇有点想试试师傅说的那个海鲜。
    所以直接让师傅把我们送到秦大个海鲜。
    海鲜是真新鲜,而且是我吃过的最干净的海鲜,海鲜尝不出一丁点的沙味。
    味道也比较满意,点了一个海鲜拼盘,很多海鲜烧烤,都很好吃。
    两大一小花了400大洋,吃的很满足,很饱。

    长春之行/吉大校园
    最后一天的上午媳妇想回吉大看看,所以早晨七点就起床,急急忙忙买动车票就出发了。
    先坐了以前一起坐的轻轨3号线,到了前进大街站,发现站点变了,原先是硅谷大街,
    然后走致远路,再入北门进学校,下车走了一圈,才发现都变了,随即打车去了吉大商场。
    到了之后发现北门装修,不给进,在距离很远的地方又开了一个门而且还需要预约。
    折腾了好大一会,成功预约进入。
    天气又突然下雨,我骑车在吉大溜达,整的湿一身,最后去日新楼吃个饭,
    吃了从我们那时就开的五谷渔粉,之后简单带孩子逛逛。
    吉大很多都改变了,在新建一个特别大的教学楼。慢慢悠悠去东门打车去了车站。
    吉大之行因为天气的原因,逛的很没有意思。

    大学校园
    回顾整个学生时代,大学是给我留下印象最深刻的时光。大学也有好多年没有回去看了。
    这次正好有九天的假期,就回去看了一下。大学不是一个好的大学,所以跟研究生的学校比
    的话,基本多年没有任何变化。还是那么的破,那么的小。
    宿舍楼下小卖部的大叔从以前听广播变成了刷抖音,男生寝室变为了女生寝室,想进去看看也不现实了。
    去2/3教学楼看了看,2教有些学的变化,教室的门都换成了能够锁上的了。不再让人能够随意进出。
    当年的自习室变为了电气学院的自习室,当年的考研自习室变为了老师办公室。
    厕所也安装了热水管道和设备。不用学生再自己带水喝了。
    去操场和小假山上溜达了一圈,在操场旁边的花园竟然发现了感觉有百年的书,我双手环抱都抱不过来。
    这么大的树真是第一次注意,以前上学的时候,根本没有发现。
    还有一个小插曲,我们溜达的过程中,遇到了很多流浪狗,哎,这些学生真是造孽啊。
    有一只狗就是单纯的跟着我们,给它买的火腿也不吃,不知道为啥。
    
    延吉之行
    在吉林市呆了几天之后,我和媳妇觉得无聊了,所以就想着去延吉溜达溜达,去年我媳妇就去过,
    说是那边这个好吃,那个好吃的,所以就早起直接买车票过去了。
    动车不到两个小时就到了,到了之后直接打车去了网红墙。这个墙真没有啥意思,
    也就是各种各样的店铺,然后很多店铺在墙的外立面安装了很多的广告牌,算是人为偶然创造的景点。
    对面就是延边大学,看着挺壮观的,但是因为懒就没有进去看,也是因为当天天气着实有点热。
    看完网红墙就和媳妇闹了一个大矛盾,矛盾持续了得有两个小时,最后给媳妇打电话才解决。
    解决完矛盾也下午一点多了,大家都饿了,直接找了个延大旁边的朴大叔烤肉,
    烤肉挺好吃,其中的奶油米酒真是一绝,后来我们特定去延边西市场找了一下,
    找到了专门卖这个的很多商家,找了其中一家,直接买了8瓶,回来后,我一周就喝完了。
    之后又买了5瓶,我实在是太喜欢喝这个了。

    吃完之后大家就累的不行,原先和媳妇闹矛盾是打算吃完就回去的,但是吃开心了,
    直接订了个酒店休息一会,打算晚上继续玩,并且明天去图们看看中朝边界。
    下午因为下雨,并且都累了,直接睡了一下午。
    起床后,天气挺好的,很凉爽,我们就又打车去了一个新建的明珠塔。
    看抖音上说挺好玩的,但是我们到了已经是晚上了,买个票等了大概20分钟电梯,
    大概七点半才上去,上去之后天也彻底黑了,上面分为3层,一层喝咖啡,一层介绍民俗,
    一层是观光层,也就这层有点意思,能够俯瞰整个延吉市的夜景,延吉市很小。一眼就能看完。
    但是最高层的观光效果因为夜晚的原因,效果一般。但是有几个很逗的管理人员,
    把探照灯打开了,并且放了嗨歌,我儿子乐坏了,跟着一直跳,跳了得有10多分钟。
    累的不行了,他才停下,然后我们准备下楼。
    下来之后,我们打算去啤酒节逛逛,但是太晚了,很难打车,等了得有15分钟才等到一个车。
    去了啤酒节发现,也就是简单的类似于夜市的地方,而且音乐特别的吵,
    这个噪音对我儿子的耳朵不好,我们进去之后很快就出来了。
    出来之后发现时间还早,就想着还有哪里有啥好玩的,正好打车的时候师傅说过有一家叫
    惊叹号的店,听说是地道的韩食,地图一搜附近就有一家,然后我们就跟着地图走过去了。
    店铺很有意思,在地上二楼,一楼是饺子铺,这种结构在南方不多见。
    一个小男生服务员,特别热情,服务特别周到,可能是我目前遇到的最周到的一个服务员。
    点了一个啤酒火锅,一个鱼皮饺子之类的,记不清了,几个菜都觉得很一般。
    完全就是吃了个服务。


☆ 第007周(2025.07.21-2025.07.25)

1. Sheep Year Kernel Heap Fengshui: Spraying in the Big Kids’ Pool
    链接: https://www.alex-ionescu.com/\
        kernel-heap-spraying-like-its-2015-swimming-in-the-big-kids-pool/
    
    文章主要说的是windows内核堆喷射,喷射的方法主要是两种
    1) Sockets (AFD.SYS): 向一个套接字写入大量数据(>4KB)但不读取,
        会导致网络驱动在内核中为这些数据分配一个缓冲区
    2) 命名管道 (Named Pipe / NPFS.SYS): 创建一个命名管道,并向其写入大量数据(>4KB)但不读取。
        命名管道文件系统驱动(NPFS.SYS)会在内核的非分页池 (Nonpaged Pool) 中分配一个大缓冲区来存放这些数据。
    
    这两种方式生效需要两个条件
    1). 在Windows7及更早版本中
    2). 非分页池内存可执行,比如HEVD的UAF NonPaged Pool这种理想化条件

    在windows8后上述办法失效,主要原因有两个
    1). 执行向量被阻断:非分页池变为不可执行 (Kernel DEP/NX)
        攻击前的状态 (Windows 7及更早版本): 攻击的精髓在于,通过命名管道(NPFS.SYS)
        喷射到非分页池 (Nonpaged Pool) 的数据(Shellcode)默认位于一块可执行 (Executable) 的内存区域。
        因此,一旦攻击者获得执行流并跳转到这块内存的地址,代码就会被CPU直接执行。
        升级后的状态 (Windows 8及更高版本): 微软为内核池内存全面启用了数据执行保护(DEP),硬件层面由NX位支持。
        即便攻击者成功地将Shellcode放置到了非分页池,该内存区域也被标记为“仅数据,不可执行”。
        如果程序试图跳转到这个地址并执行代码,CPU会立即触发一个访问冲突异常,导致攻击失败。
    2). 地址发现向量被限制:API调用权限收紧
        攻击依赖于调用NtQuerySystemInformation并使用SystemBigPoolInformation来泄露所有大池分配的内核地址,
        从而绕过KASLR。在旧版本中,任何程序,无论其权限高低,都可以调用这个API。
        windows8之后,微软为这个API调用添加了完整性级别检查 (Integrity Level Check)。
        只有中等或更高完整性级别的进程才能成功调用它。


2. Bugs on the Windshield: Fuzzing the Windows Kernel

    链接:https://research.checkpoint.com/2020/bugs-on-the-windshield-fuzzing-the-windows-kernel/

    在文章刚出来的时候,我已经看过了,最近在学习windows hevd时,在找相关内容时,又看到了,所以就复习一下

    文章开始是想使用kAFL去测试windows kernel,随着研究的深入,研究人员想要专门去测试windows syscall,
    而google开发的Syzkaller正是用于测试linux syscall的模糊测试框架,但它却不适用于WSL。
    所以作者打算移植Syzkaller到windows平台,用于去测试wsl和win32k。

    最开始他们打算先使用Syzkaller去测试WSL,主要是因为WSL和linux系统相似,其将linux syscall转化为了windows syscall。

    移植中,他们遇到h很多题:

    windows没有KCOV,无法查看代码覆盖率:
    可能的解决方案:
    Using an emulator like QEMU / BOCHS and adding coverage instrumentation.
    Using static binary instrumentation like in pe-afl.
    Using a hypervisor with coverage sampling like in apple-pie.
    Using hardware support for coverage like Intel-PT.

    迭代解决:
    #1 : 像kAFL一样通过Hypercall捕获BugCheck事件,并打印原始堆栈地址。这种方法难以区分不同崩溃。
    #2 : 尝试通过网络连接到一台运行WinDbg的远程调试机。但在大规模Fuzzing时,此方案速度太慢且连接不稳定。
    #3 : 受Bochspwn启发,让QEMU在崩溃时提取寄存器、堆栈和模块信息,通过网络发送给一台专门的Windows“符号化服务器”,
        该服务器调用DbgHelp.dll来生成调用栈。
    #4 : 为了追求极致性能和集成度,作者直接用Go语言(Syzkaller的开发语言)实现了一个迷你的内核调试器,
        包含PDB文件解析、x64堆栈回溯和KDNET网络调试协议支持,并将其直接集成到Syzkaller中

    最难的地方在于处理win32k子系统,不像linux有完整的syscall可以查看
    Win32k语法(Grammar)问题解决:
        MSDN文档
        泄露的Windows NT/2000源代码
        ReactOS的开源代码
        使用IDA和WinDbg进行逆向工程
    
    文章还有很多值得学习的地方,但是这套测试windows syscall的系统更加值得学习和利用


☆ 第008周(2025.07.28-2025.08.01)    

1. My `Blind Date` with CVE-2025-29824
    链接: https://starlabs.sg/blog/2025/07-my-blind-date-with-cve-2025-29824/

    文章通过一个在野的CLFS漏洞进行逆向分析,分析前没有任何poc,只能纯逆向分析漏洞形成的真实原因。
    漏洞的原因在于CLFS没有正确处理FsContext2结构体计数,其在CClfsLogCcb::Release中释放。

    具体释放路径:
    老的
    CClfsRequest::Cleanup()
        CClfsLogCcb::Release(FsContext2)
    新的
    CClfsRequest::Close()
        CClfsLogCcb::Release(FsContext2)
    
    IRP_MJ_CLEANUP 在与目标设备对象关联的文件对象的最后一个用户模式句柄被关闭时发送,
        但由于可能存在未完成的I/O请求,该文件对象本身可能尚未被释放
    IRP_MJ_CLOSE 在对文件对象的最后一个引用被释放,并且所有未完成的I/O请求都已完成或取消时发送。

    老的情况是,在Cleanup中过早的释放FsContext2,但是别的线程可能还在使用该信息,导致UAF。
    新的情况是,使用Close可以保证所有未完成的IO请求都被处理了,然后再释放该信息。

    在补丁之后,当 FsContext2 在 CClfsRequest::Close() 中被释放时,应当已没有任何其他请求正在使用它。

    触发的逻辑
        一个线程能够触发Cleanup->时间窗口->Close
        一个线程能够使用FsContext2或者其中的部分结构
    需要找到使用FsContext2的IO请求
    找到了3个能够通过IO请求触发的
        CClfsRequest::ReserveAndAppendLog():
            可通过调用用户函数ReserveAndAppendLog()或直接通过DeviceIoControl()发送控制码0x8007A827c触发
        CClfsRequest::WriteRestart():
            可通过调用用户函数WriteLogRestartArea()或直接发送控制码0x8007281F来触达。
        CClfsRequest::ReadArchiveMetadata():
            可通过发送控制码0x80076856来触达。
    只有最后一个调用最简单,所以使用最后一个

    其给出的PoC代码:
    线程1启动 CloseHandle:
        CloseHandle()导致I/O管理器发送IRP_MJ_CLEANUP。
        clfs.sys收到后调用CClfsRequest::Cleanup()。
        在有漏洞的版本中,Cleanup()函数过早地、错误地调用CClfsLogCcb::Release(),
        将FsContext2指向的内存释放了。
        Cleanup()函数执行完毕并返回。
    攻击窗口打开:
        在Cleanup执行完毕后,到Close被调用前,存在一个时间窗口。在这个窗口期,
        FsContext2指向的内存已经被释放,但 FILE_OBJECT 本身可能还存在,
        因为它可能还有来自其他I/O操作的引用。
    线程2的攻击:
        与此同时,线程2正在另一个CPU核心上疯狂地调用DeviceIoControl()。
        它的某一次调用,其对应的IRP恰好在上述的“攻击窗口”内被clfs.sys处理。
        clfs.sys开始执行CClfsRequest::ReadArchiveMetadata()。
        这个函数的第一步就是要从 FILE_OBJECT 中获取 FsContext2 指针,然后去访问它指向的内存。

2. Exploit Development: Swimming In The (Kernel) Pool - 
    Leveraging Pool Vulnerabilities From Low-Integrity Exploits, Part 1

    链接: https://connormcgarr.github.io/swimming-in-the-kernel-pool-part-1/

    这篇文章是我在学习UAF利用的过程中找到的,具有非常高的实用及利用价值,我非常喜欢的一篇文章

    文章主要就是通过HEVD的几个漏洞样例并使用kLFH获取内核基址

    在windows 19H1之后,windows的内核内存分配使用了Segment Heap(段堆),类似于用户空间的内存管理

    内存管理和分配主要有以下几种
        低碎片堆 (kLFH)
        可变大小 (VS)
        段分配 (Segment Alloc)
        大块分配 (Large Alloc)
    
    其中VS使用_HEAP_VS_CHUNK_HEADER作为头部前缀,kLFH使用_POOL_HEADER作为头部前缀
    kLFH为每种分配大小都设置了“桶(buckets)”。想触发kLFH,需要对相同大小的桶连续发出16次分配请求。
    总共有128个桶,每个桶都有一个“粒度(granularity)”。粒度指的是能否分配的最小字节数,
    +-----------+----------------------------------------+-------------+
    | Bucket    | Allocation Size                        | Granularity |
    +-----------+----------------------------------------+-------------+
    | 1 – 64    |     1 – 1,024 bytes (0x1 – 0x400)      | 16 bytes    |
    | 65 – 80   | 1,025 – 2,048 bytes (0x401 – 0x800)    | 64 bytes    |
    | 81 – 96   | 2,049 – 4,096 bytes (0x801 – 0x1000)   | 128 bytes   |
    | 97 – 112  | 4,097 – 8,192 bytes (0x1001 – 0x2000)  | 256 bytes   |
    | 113 – 128 | 8,193 – 16,368 bytes (0x2001 – 0x3FF0) | 512 bytes   |
    +-----------+----------------------------------------+-------------+

    详细解释:
    一个Bucket可以有多个SubSegment,当一个Bucket中的所有现有SubSegment都满了(没有空闲Block)时,
    如果又有新的分配请求进来,LFH就会向其后端分配器(Segment Backend)申请一个新的、更大的内存块,
    并将其初始化为一个新的SubSegment,然后加入到这个Bucket的管理列表中。
    因此,一个繁忙的Bucket会随着时间的推移累积多个SubSegment。
    Subegment是Block的“母体”。它是一块被分配的、较大的连续内存区域,
    其主要部分被均匀地切割成多个大小相同的Block。
    同一个SubSegment内的Block是物理连续的,这种设计使得通过索引(Block Index)
    和块大小(Block Size)来计算任意一个Block的地址变得非常简单和快速。
    不同的SubSegment之间是不连续的,每个SubSegment都是一次独立的内存分配请求的结果。


☆ 第009周(2025.08.04-2025.08.08)

1. CVE-2018-8611 Exploiting Windows KTM Part 1/5 – Introduction

    链接: https://www.nccgroup.com/research-blog/
        cve-2018-8611-exploiting-windows-ktm-part-15-introduction/

    本文是系列的第一篇,详细介绍了KTM的运作机制和基本概念。
    KTM用于实现跨多个资源的原子操作。其核心对象包括:
        事务管理器 (Transaction Manager, TM): 
            KTM体系的顶层控制器。作者特别指出,为避免日志文件问题,利用时应选择易失性 (Volatile) TM。
        资源管理器 (Resource Manager, RM): 
            管理具体资源(如文件、注册表)的实体。
        事务 (Transaction, Tx): 
            一个需要原子性完成的工作单元。
        登记 (Enlistment, En): 核心概念,代表一个RM承诺参与到一个Tx中。它是连接RM和Tx的桥梁。
    关键操作与概念
        恢复 (Recovery) vs. 回滚 (Rollback): 回滚是中止并撤销事务,而恢复是尝试同步状态以继续事务。
        通知 (Notifications): RM可以接收关于其登记状态变化的通知。
            这是利用过程中进行调试和判断竞争条件是否成功的重要机制。
        API与内核结构: 文章介绍了用于创建和管理上述对象的关键用户态API, 
            如 CreateTransactionManager, CreateResourceManager, CreateEnlistment,
            并展示了与之对应的内核数据结构(如_KTM, _KRESOURCEMANAGER, _KENLISTMENT)。


☆ 第010周(2025.08.11-2025.08.15)

1. Windows内核:虚拟内存分页系统与自我引用技术
    链接: https://forum.butian.net/share/3806

    x86-64架构下48位虚拟地址的Canonical Form(规范形式)布局,即
    16 (Reserved) + 9 (PML4) + 9 (PDPT) + 9 (PD) + 9 (PT) + 12 (Offset)
    最后是12位长度,2^12 => 4 * 1024 => 4K,每个长度是8字节,也就是4KB
    高16位reserved,更准确地说是符号扩展位。地址的第47位必须被复制到第48至63位。
    任何不遵循此规则的地址都被视为非规范地址,会导致硬件产生通用保护故障(#GP)。

    寻址的流程是: CR3 -> PML4 -> PDPT -> PD -> PT -> Physical Page

    为了更好的理解,我让AI画了一个图来展示

    ------------------------------------------------------------------------------------
    64-bit Virtual Address (Canonical Form: bits 63-48 are a sign-extension of bit 47)
    +-----------------------------------------------------------------------------+
    |                                    Virtual Address                          |
    +=============================================================================+
    | Bits 63-48 | Bits 47-39 | Bits 38-30 | Bits 29-21 | Bits 20-12 | Bits 11-0  |
    +------------+------------+------------+------------+------------+------------+
    |  Sign-Ext  |   PML4_idx |  PDPT_idx  |   PD_idx   |   PT_idx   |   Offset   |
    | (16 bits)  |  (9 bits)  |  (9 bits)  |  (9 bits)  |  (9 bits)  | (12 bits)  |
    +------------+------------+------------+------------+------------+------------+
    ^            ^            ^            ^            ^            ^
    |            |            |            |            |            |
    |            |            |            |            |         [Page Offset]
    |            |            |            |            |         - 12 bits -> 2^12 = 4096 bytes (4KB)
    |            |            |            |            |         - the final 4KB physical page
    |            |            |            |            |
    |            |            |            |      [Page Table (PT) Index]
    |            |            |            |      - 9 bits -> 2^9 = 512 entries
    |            |            |            |      - Selects an entry (PTE) in the Page Table.
    |            |            |            |
    |            |            |     [Page Directory (PD) Index]
    |            |            |     - 9 bits -> 2^9 = 512 entries
    |            |            |     - Selects an entry (PDE) in the Page Directory.
    |            |            |
    |            |      [Page Directory Pointer Table (PDPT) Index]
    |            |      - 9 bits -> 2^9 = 512 entries
    |            |      - Selects an entry (PDPTE) in the PDPT.
    |            |
    |     [Page-Map Level 4 (PML4) Index]
    |     - 9 bits -> 2^9 = 512 entries
    |     - Selects an entry (PML4E) in the top-level PML4 table.
    |
    [Sign Extension]
    - Must be all 0s for addresses 0x0000_0000_0000_0000 to 0x0000_7FFF_FFFF_FFFF
    - Must be all 1s for addresses 0xFFFF_8000_0000_0000 to 0xFFFF_FFFF_FFFF_FFFF
    - Any other value makes the address "non-canonical" and causes a fault.
    ------------------------------------------------------------------------------------

    计算的过程大概是这样的:
    PML4E 地址: PML4E_Addr = CR3_Base + PML4_idx * 8
    PDPT 基地址: PDPT_Base = (*(uint64_t*)PML4E_Addr) & ~0xFFF
    PDPTE 地址: PDPTE_Addr = PDPT_Base + PDPT_idx * 8
    PD 基地址: PD_Base = (*(uint64_t*)PDPTE_Addr) & ~0xFFF
    PDE 地址: PDE_Addr = PD_Base + PD_idx * 8
    PT 基地址: PT_Base = (*(uint64_t*)PDE_Addr) & ~0xFFF
    PTE 地址: PTE_Addr = PT_Base + PT_idx * 8
    物理页基地址: Phys_Page_Base = (*(uint64_t*)PTE_Addr) & ~0xFFF
    最终物理地址: Final_Phys_Addr = Phys_Page_Base + (Virtual_Address & 0xFFF)

    其中前3个的基址需要& ~0xFFF,可以这么理解

    63  62-52       51-12         11-9       8   7   6   5   4    3    2   1   0
    +-----+------+----------------+----------+---+---+---+---+----+----+---+---+---+
    | NX  | Avail| Phys Addr Base | Ignored  | G |PAT| D | A |PCD |PWT |U/S|R/W| P |
    +-----+------+----------------+----------+---+---+---+---+----+----+---+---+---+

    后12位只有在页帧地址才能用到,其他都是作为标志位来说明

    上述是4次寻址的详细过程,是正常的流程,如果是使用自我引用技术(Self-Referencing Technique)
    可以更加快速的获取到一个TargetVA地址的PTE_VA
    其原理是将PML4表中的一个特定条目(PML4E)不指向下一级的PDPT,而是指向PML4表自身的物理基地址(该地址存储在CR3寄存器中)。
    这使得访问一个特定构造的虚拟地址时,MMU会进行一次“递归”的页表查询,从而将整个页表层级结构映射到虚拟地址空间中。

    当MMU解析一个以自我引用索引开头的虚拟地址时,第一步(PML4索引)会定位到指向PML4自身的PML4E。
    因此,MMU会把PML4表的物理地址当作下一级PDPT的基地址。接下来,虚拟地址中的PDPT索引就会被用作PML4表的索引,
    从而定位到真正的PML4E,该条目指向一个PDPT。如此循环,最终将PML4、PDPT、PD、PT都“线性”地暴露在一段连续的虚拟地址空间内,
    方便内核代码进行遍历和修改,而无需每次都去操作物理地址或读取CR3。
    
    可以使用如下公式来理解:
    VA_PTE = (Sign_Ext) | (SelfRef_idx << 39) | (PML4_idx(TargetVA) << 30) | (PDPT_idx(TargetVA) << 21) 
            | (PD_idx(TargetVA) << 12) | (PT_idx(TargetVA) * 8)
    
    相当于系统上官方给留了一个从TargetVA到PTE_VA的后门,在漏洞利用中有很大的作用
    权限提升: 将内核代码或数据页的PTE修改为用户态可写(设置U/S位为User,R/W位为Write),
        从而在用户态直接修改内核数据(如进程Token的权限字段)实现提权。
    代码执行: 将一个只读的内核代码页(如.text段)的PTE修改为可写,然后覆写内核函数以劫持控制流。
    物理内存访问: 通过不断修改同一个虚拟地址对应的PTE中的PFN,攻击者可以遍历整个物理内存,绕过所有操作系统层面的安全限制。

2. Windows SMEP Bypass
    链接: https://www.coresecurity.com/sites/default/files/private-files\
    /publications/2016/05/Windows%20SMEP%20bypass%20U%3DS.pdf

    上面的文章就是为了利用PTE来绕过SMEP的
    SMEP: 当CPU处于内核态(Ring-0)时,禁止执行用户态(Ring-3)内存页中的代码。
    页表项(PTE)中包含了权限控制位,其中 U/S 位(User/Supervisor)至关重要。
    U/S=1 表示用户页,U/S=0 表示内核页。SMEP 正是依据此位来判断目标页是否为用户页。
    Windows 为了方便内核自身访问和修改任何进程的页表,在PML4表中使用了一个固定的索引(0x1ED)指向PML4表自身的物理基址。
    设计导致了一个后果:所有进程的页表结构(PML4, PDPT, PD, PT)都被映射到了内核空间的一段固定、可预测的虚拟地址范围内。

    具体的绕过步骤:
    a. 在用户空间分配一块内存并放入shellcode。
    b. 利用上述公式,计算出存放shellcode的内存页对应的PTE在内核中的虚拟地址。
    c. 使用任意地址写原语,修改PTE。具体操作是将其中的U/S位从1(User)翻转为0(Supervisor)。
    d. (关键步骤) 修改 PTE 后,必须刷新 TLB (Translation Lookaside Buffer),
        否则 CPU 可能会使用缓存中旧的、错误的页表信息。这通常通过invlpg指令或wbinvd等可以刷新缓存的指令实现。
    f. 当漏洞触发,内核执行流跳转到这块shellcode内存时,SMEP检查其PTE,
        发现U/S位为0,判定其为内核页,因此不会触发保护,允许执行。



☆ 第011周(2025.08.18-2025.08.22)

1. FortiGuard Labs Threat Research Microsoft Windows Remote Kernel Crash Vulnerability
    链接: https://www.fortinet.com/blog/threat-research/ \
            microsoft-windows-remote-kernel-crash-vulnerability
    
    文章关于CVE-2018-1040漏洞的描述
    根源在于: ci.dll在处理PE文件的IMAGE_OPTIONAL_HEADER中的SizeOfHeaders字段时,
    未能对其进行充分的有效性验证。一个恶意的、极小的值(如0x06)会导致后续在计算待哈希数据的大小时发生整数下溢,
    产生一个被解释为极大正数的负值。这个无效的、巨大的长度值被传递给底层的哈希计算函数(SymCryptSha1AppendBlocks),
    导致一个巨大的循环,最终在循环内发生越界内存读取,触发内核页错误(Page Fault),引发系统崩溃。

    漏洞的触发可以通过调用GetFileVersionInfoSizeExW,其会调用LoadLibraryExW,其标志位dwFlags为0x22,
    即: LOAD_LIBRARY_AS_DATAFILE (0x02) | LOAD_LIBRARY_AS_IMAGE_RESOURCE (0x20)
    然后会进入内核
    nt!MiValidateSectionCreate -> nt!SeValidateImageHeader
    最终调用windows 代码完整性检查模块ci.dll,其主要是通过CI!CiValidateImageHeader来检查PE文件的头部信息。
    PE文件的头部信息被破坏,但是ci.dll没有做好边界检查,从而导致后续漏洞发生。

    远程利用方式:使用浏览器下载任意的被破坏的poc.dll文件,浏览器会对下载文件进行检查,从而导致系统崩溃。


☆ 第012周(2025.08.25-2025.08.29)

1. Trip in da TCP/IP
    链接: https://www.ivanlef0u.tuxfamily.org/?p=60

    07年用法语写的一篇关于windows TCP/IP数据包从用户空间到内核再到硬件的整个流程分析

    1) 用户应用层:
       应用程序调用 send() 函数,将数据交给 ws2_32.dll (Winsock API)。
    2) Winsock 服务层:
       ws2_32.dll 将请求转发给 mswsock.dll。后者是真正的服务提供者,负责将这个高级请求转换为一个底层的I/O操作。
    3) 系统调用 (进入内核):
       mswsock.dll 通过 ntdll.dll 发起系统调用,使CPU从用户模式切换到内核模式。控制权正式移交给操作系统内核。
    4) AFD 驱动:
       请求首先到达 afd.sys (Winsock辅助功能驱动)。它在内核中模拟Socket行为,管理连接和缓冲区,
       并将请求翻译成更底层的网络协议操作。
    5) TCP/IP 协议栈:
       afd.sys 将请求转发给 tcpip.sys。在这里,数据被真正处理:
       TCP层: 添加TCP头部(端口号等)。
       IP层: 添加IP头部(IP地址等),形成一个完整的IP包。
    6) NDIS 与网卡驱动:
       tcpip.sys 通过 NDIS (一个标准的驱动接口) 将IP包交给 网卡驱动程序。该驱动添加最后的以太网头部(MAC地址),
       形成数据帧,并直接与网卡硬件通信。
    7) 物理硬件:
       网卡驱动将数据帧写入网卡硬件的缓冲区,并命令它将数据作为电子信号发送到网络上。


☆ 第013周(2025.09.01-2025.09.05)

1. Patch Tuesday → Exploit Wednesday: Pwning Windows ancillary function driver 
    for WinSock (afd.sys) in 24 hours
    链接: https://www.ibm.com/think/x-force/patch-tuesday-exploit-\
            wednesday-pwning-windows-ancillary-function-driver-winsock

    文章分析为分析CVE-2023-21768漏洞信息,漏洞存在于afd.sys驱动中。afd.sys是Windows Sockets API的辅助功能驱动程序,
    处理网络套接字相关的大量内核操作。

    具体操作: 
       补丁比对,比较修复漏洞前后的afd.sys文件,找出代码差异,从而精确定位漏洞
       工具:Ghidra和BinDiff
       发现:只有一个函数发生了改变 afd!AfdNotifyRemoveIoCompletion
       关键差异(漏洞根源):
         修复前(有漏洞版本): 代码在写入一个由用户传入的指针时,缺少了必要的安全检查
         修复后(已打补丁版本): 代码中增加了一个关键的函数调用 ProbeForWrite
    ProbeForWrite函数的作用是验证一个内存地址是否位于用户空间,并且是可写的。
    在内核编程中,当内核需要向用户模式传入的地址写入数据时,必须先调用此函数进行检查,
    否则可能导致内核向一个非法的、甚至被攻击者精心构造的内核地址写入数据,从而引发严重的安全问题

    漏洞的本质在于,afd!AfdNotifyRemoveIoCompletion函数会根据一个名为PreviousMode的变量来决定是否进行检查。
    如果请求来自内核(PreviousMode==KernelMode),则系统信任该指针;
    如果请求来自用户模式(PreviousMode == UserMode),
    则必须检查。有漏洞的版本缺少了这个检查逻辑,无论请求来自哪里,都直接进行写操作。

    构建PoC:
    寻找调用链:
        研究人员通过交叉引用分析发现,漏洞函数AfdNotifyRemoveIoCompletion由另一个函数 AfdNotifySock 调用的。
    定位IOCTL控制码:
        内核驱动通常通过IOCTL请求与用户模式程序交互。
        研究人员分析发现AfdNotifySock函数位于一个名为AfdIoctlTable的函数指针表中。
        通过计算它在该表中的偏移,研究人员确定了用于调用此函数的IOCTL控制码。
        这表明,攻击者可以通过向afd.sys设备发送一个特定IOCTL请求来触发漏洞路径。
    构造输入数据: 
        触发漏洞需要传递一个精心构造的数据结构。研究人员通过逆向AfdNotifySock函数,
        分析了其内部的各种检查,逐步还原了这个未公开的输入结构(在文中被称为 AFD_NOTIFYSOCK_STRUCT)。
        为了成功到达漏洞代码,他们必须绕过一系列检查,
        包括:
        大小检查: 输入缓冲区的大小必须是 0x30 字节。
        句柄检查: 
            结构中的第一个成员必须是一个有效的内核对象句柄。
            研究人员通过调用一个未公开的函数NtCreateIoCompletion创建了一个符合要求的I/O完成对象。
        循环检查: 
            函数内部有一个循环,会对输入结构中的指针进行读写。攻击者需要提供有效的指针以避免程序崩溃。
        阻塞等待: 
            函数会调用IoRemoveIoCompletion,该函数会阻塞,直到一个I/O操作完成。
            攻击者需要通过 NtSetIoCompletion 函数来“手动”完成一个 I/O 操作,使程序继续执行。

    这个漏洞的“任意地址写”原语是受限的:它只能向一个任意地址写入一个固定的、较小的值(分析得出是1)。
    如何将这个“写 1”的能力,升级为完全的任意内核读写,并最终提权呢?
    他们选择了一种非常巧妙且强大的技术:攻击 Windows I/O Ring。
    I/O Ring 简介: I/O Ring是Windows11中引入的一种新的、高性能的异步I/O机制。
    它在内核中对应一个名为_IORING_OBJECT的数据结构。 

    攻击思路:
    _IORING_OBJECT 结构中有两个关键字段:
        RegBuffersCount (偏移 +0x0b0): 一个计数器,表示已注册的缓冲区数量。
        RegBuffers (偏移 +0x0b8): 一个指针,指向一个包含所有已注册缓冲区信息的数组。
    这两个字段在 I/O Ring 初始化时都被设置为 0。攻击分为两步:

    第一次触发漏洞:
        攻击者首先获取到其创建的_IORING_OBJECT对象的内核地址。
        利用漏洞,向该地址的 RegBuffersCount 字段(_IORING_OBJECT + 0x0b0)写入1。
        效果:内核现在认为这个 I/O Ring已经注册了1个缓冲区,尽管RegBuffers指针仍然是NULL。
    第二次触发漏洞: 
        攻击者再次利用漏洞,向RegBuffers指针字段(_IORING_OBJECT + 0x0b8)写入一个由攻击者 
        在用户空间控制的地址(例如 0x100000000)。
        效果:此时,I/O Ring的内核状态被完全破坏。内核认为缓冲区的列表位于一个用户可以随意读写的地址。
    获得任意内核读写能力:
    完成上述两步后,攻击者就在用户空间的那个地址上伪造了一个缓冲区信息结构数组。
    通过调用I/O Ring相关的API(如BuildIoRingReadFile和BuildIoRingWriteFile),他们可以欺骗内核:
    任意读: 让内核从任意一个指定的 内核地址 读取数据,并将其写入到一个文件中(攻击者可以再从文件中读出数据)。
    任意写: 让内核从一个文件中读取数据,并将其写入到任意一个指定的 内核地址。
    至此,攻击者已经从一个受限的“写 1”原语,升级到了完全的、强大的任意内核地址读写原语。
    最后一步:提权



☆ 第014周(2025.09.08-2025.09.12)
1. Under the Hood of AFD.sys Part 1: Investigating Undocumented Interfaces
    链接: https://leftarcode.com/posts/afd-reverse-engineering-part1/

    文章详细记录了在Windows11环境下,通过逆向工程绕过Winsock API,
    直接与内核驱动AFD.sys交互以创建一个原生TCP套接字的过程。

    入口点: 
        确认了创建AFD套接字的根本操作是调用ntdll!NtCreateFile,
        而非NtDeviceIoControlFile。目标设备对象为\\Device\\Afd\\Endpoint。
    通信机制: 
        参数传递的核心是利用NtCreateFile的扩展属性 (Extended Attributes, EA)。
        一个名为AFD_OPEN_PACKET_EA的自定义结构被打包在EaBuffer参数中,由AFD.sys的IRP_MJ_CREATE派遣例程解析。
    关键数据结构:
        EA名称: 结构内部包含一个EaName字段,用于AFD.sys内部的请求分发。
        EA值: EaValue部分包含了创建套接字所需的全部参数
    
2. Under the Hood of AFD.sys Part 2: TCP handshake
    链接: https://leftarcode.com/posts/afd-reverse-engineering-part2/

    本文在上一部分创建原生AFD套接字句柄的基础上,成功逆向并复现了通过NtDeviceIoControlFile API
    执行bind和connect操作的未文档化IOCTL接口。

    主要有以下关注点
    交互模型: 从NtCreateFile创建句柄,转为使用NtDeviceIoControlFile发送IOCTLs与驱动进行后续通信。
    IOCTL_AFD_BIND (0x12003):
        输入结构 (AFD_BIND_SOCKET): 
            一个封装了flags(控制绑定行为,如复用地址)和标准SOCKADDR(或SOCKADDR_IN / SOCKADDR_IN6)的结构体。
            其内存布局与Winsock API层的数据结构直接兼容。
    IOCTL_AFD_CONNECT (0x12007):
        输入结构 (AFD_CONNECT_SOCKET): 一个更为复杂的结构。
        前导字段: 包含SanActive、RootEndpoint、ConnectEndpoint等多个句柄/标志位。
                 这些字段与特定高级功能(如System Area Network直通)或服务端操作相关。
        关键发现: 作者通过实验验证,在标准的客户端连接场景中,将这些前导字段全部置零即可成功。
                 AFD.sys为此类常规请求提供了默认处理路径。
        地址信息: 结构末尾包含目标服务器的SOCKADDR信息。
    
    在内核调试时,在特定进程设置内核断点
    .foreach /pS 1 (ep { !process 0 0 afd_re.exe }) { bp /p ${ep} afd!AfdBind}

    逆向分析的逻辑值得学习


☆ 第015周(2025.09.15-2025.09.19)

这周因为基本都在出差,这些文章都是我在宾馆的床上看的,没有电脑,写起来不方便
后期2025.09.22编写

1. Fuzzing Modern UDP Game Protocols With Snapshot-based Fuzzers
    链接: https://blog.ret2.io/2021/07/21/wtf-snapshot-fuzzing/

    最近在挖掘yuange在微博上提到的windows server 2003的那个漏洞,通过源码阅读没有找到漏洞,
    所以现在想着是否可以通过fuzz的方式找到,所以把wtf库上列出的几个文章全过一遍

    文章是一个使用wtf的样例,前面的部分很简单,在开始处理游戏数据的函数设置断点,在结束代码上设置结束断点,并分别设置快照,
    之后注入变异的数据进行测试。

    需要注意的就是作者扩展了wtf的功能,使其能够生成Tenet traces文件,在漏洞复现上特别有用
    可以将wtf产生的tenet traces文件导入到IDA中,这样可以使用TTD的方式对崩溃进行调试,
    这种方式没有用过,目前只用过windbg TTD。这种方式便于分析文章中这种网络请求的。


2. Building a new snapshot fuzzer & fuzzing IDA
    链接: https://doar-e.github.io/blog/2021/07/15/\
            building-a-new-snapshot-fuzzer-fuzzing-ida/
    
    这篇文章是我这几年反复读的一篇文章,以前没有学过内核相关漏洞时,基本看不懂,
    这次在学习和hevd的几个漏洞之后,再来看这个,发现很多内容都可以看懂了,
    真正的原理也基本懂了,打算利用该工具来实操,具体总结如下

    快照Fuzzing工作流:
    1). 选择快照点: 在目标(IDA)即将处理输入文件前,使用内核调试器暂停。
    2). 捕获状态: 生成内核崩溃转储(.dmp),从中提取完整的 CPU 状态 (寄存器, MSRs) 和 物理内存。
    3). 执行与监控: 在隔离环境(模拟器/虚拟机)中加载状态并执行,同时收集代码覆盖率、检测崩溃。
    4). 快速恢复: 每次执行后,仅恢复被修改过的脏页 (Dirty Pages) 和CPU寄存器,而非重启整个系统。

    目前支持的后端:
    ----------------------------------------------------------------------
    执行后端的演进
    后端            类型        覆盖率收集   脏页跟踪       超时机制        性能
    BochsCPU       模拟器       指令级Hook  内存访问Hook   指令计数(精确)   极慢
    WHV(Windows)   Hypervisor  int3断点    API->EPT模拟  定时器(不精确)   中等
    KVM(Linux)     Hypervisor  int3断点    EPT写保护     PMU中断(精确)    快速
    ----------------------------------------------------------------------

    遇到的主要问题:
    问题: 文件I/O (Fuzzer在无盘环境运行)
    解决: Hook 文件系统相关系统调用,从内存中提供文件内容。
    问题: 内存分页 (Guest内存被交换到磁盘)
    解决: 快照前使用 lockmem 工具将目标进程内存锁定在物理RAM中。
    问题: 向未映射的Guest缓冲区写入
    解决: 写入前检查页表。若无效,则向Guest注入一个缺页异常 (#PF),让Guest内核处理并建立映射后,再次尝试写入。
    问题: KVA Shadow (阻止在用户态设置内核断点)
    解决: 修改注册表关闭该Windows安全缓解措施。

    核心Fuzzer组件
    内存访问:
        提供了读写Guest物理地址(GPA)和虚拟地址(GVA)的接口。
        写GVA需要手动遍历页表进行地址翻译。
    变异器(Mutator):
        直接复用libfuzzer和honggfuzz变异策略
    语料库(Corpus):
        采用覆盖率导向(Coverage-guided)的策略。任何能产生新代码覆盖的测试用例都会被添加到语料库中。
    上下文切换检测:
        通过TlbControlHook监控CR3寄存器的变化,一旦发生进程切换(如从ida64.exe切换到explorer.exe),
        则立即停止当前执行,避免在不相关的代码上浪费时间。


☆ 第016周(2025.09.22-2025.09.26)

1. A Syzkaller Summer: Fixing False Positive Soft Lockups in net/sched Fuzzing
    链接: https://www.willsroot.io/2025/09/syz-summer-2025.html

    这篇文章主要是作者在使用syzkaller fuzz netsch时发现的假阳性漏洞报告进行延伸处理而来

    问题: Fuzzing网络调度器 (net/sched) 时,出现大量伪阳性的“软死锁”报告。
    根源: Fuzzer向fq队列提供了极端参数组合:巨大的开销和极小的quantum。
         这导致内核为恢复信用而陷入一个超长时间的合法循环,触发了看门狗。
    解决: 修改Fuzzer 的语法规则 (Syzlang),限制overhead等参数的生成范围,从源头避免极端输入。
    成果: 提高了Fuzzing效率,最终发现了8个真实 CVE 并获得漏洞赏金。


☆ 第017周(2025.09.27-2025.10.11)   

中间国庆假期,假期就在家陪孩子父母了,没有相关的阅读内容 :)

1. Adobe, Me and an Arbitrary Free :: Analyzing the CVE-2018-4990 Zero-Day Exploit

    链接: https://srcincite.io/blog/2018/05/21/adobe-me-and-a-double-free.html

    这是一篇主要讲CVE-2018-4990漏洞利用的文章,最主要的是其中的利用过程

    越界读取 → 用后释放 (UAF)
        堆布局 (Heap Feng Shui): 
            攻击者首先在内存中大量分配(喷射)ArrayBuffer对象, 然后交替释放,制造出特定大小的内存“空洞”。
        精确释放: 
            触发漏洞,使存在缺陷的对象被分配到“空洞”中,其缓冲区恰好与攻击者之前喷射的某个ArrayBuffer相邻。
            越界读取会读到并释放这个ArrayBuffer,但JavaScript中依然保留着对它的引用,从而制造出用后释放(UAF)漏洞。
    UAF → 相对地址读写
        内存重用: 攻击者分配一个大对象,占用刚刚被释放的内存区域。
        长度伪造: 
            利用UAF的悬垂指针,可以访问并修改相邻ArrayBuffer对象的元数据,
            特别是将其byteLength(长度)字段改写成一个非常大的值。
        能力获得: 对这个被修改长度的ArrayBuffer进行操作,即可读写其原始边界之外的大片内存,获得相对地址读写能力。
    相对读写 → 任意地址读写
        原语升级: 
            利用相对读写能力,在内存中找到另一个TypedArray对象的内部数据指针。
            通过改写这个指针,就可以让该TypedArray指向进程内存的任意位置。
        最终能力: 基于此构造出read(address)和write(address, value)函数,获得任意地址读写的终极原语。
    任意地址读写 → 代码执行 (RCE)
        信息泄露: 使用任意读,获取关键DLL(如EScript.api)的基地址。
        ROP链部署: 使用任意写,将ROP链(用于调用系统API执行代码)写入内存。
        劫持控制流: 
            找到一个JavaScript对象(如bookmarkRoot),
            使用任意写将其函数指针(如execute方法)覆盖为ROP链的起始地址。
        触发: 调用该JavaScript方法,执行流被劫持,最终执行Shellcode。


☆ 第018周(2025.10.13-2025.10.17)

1. Denial of Fuzzing: Rust in the Windows kernel

    链接: https://research.checkpoint.com/2025/denial-of-fuzzing-rust-in-the-windows-kernel/

    这周本来是没时间写的,因为正好领导要求国密后量子课题开发的最后一周,非常忙。
    这是后来补充的:

    该篇文章是CPR发现并分析的Windows操作系统内核中首个公开披露的、影响Rust语言组件的安全漏洞
    触发路径:
    恶意输入: 变异后的EMF+文件,其核心是一个畸形的EmfPlusDrawBeziers记录。
        畸形特征: 记录中声明的点数量 (Count 字段) 与实际提供的点数据 (PointData 数组) 不匹配,
        且坐标值能触发代码中的边缘计算逻辑。
    执行入口: 通过用户态 GDI+ 的 API 误用。
        调用 Graphics::FromImage() 时,传递一个 Metafile 对象,而非文档预期的 Bitmap 对象。
        该误用将执行流导向一个特殊的内核处理路径。
    调用链:
    DrawImage() 
        -> 回放EmfPlusDrawBeziers记录 
            -> NtGdiSelectClipPath系统调用 
                -> 内核win32k.sys 
                    -> win32kbase_rs.sys::region_from_path_mut() 
                        -> 触发越界与 Panic。

    发现方法的创新点 (The Discovery)
        问题: 内核Fuzzing触发系统崩溃后,难以确定是哪个输入样本导致的。
        解决方案: 修改 Fuzzing 测试桩 (Harness),在将每个变异样本送入目标API之前,
        通过网络 (send_data 函数) 将其副本发送到一台远程归档服务器。系统崩溃时,
        服务器上最后一个接收到的文件即为触发样本。


☆ 第019周(2025.10.20-2025.10.24)

1. Crafting a Full Exploit RCE from a Crash in Autodesk Revit RFA File Parsing 

    链接: https://www.zerodayinitiative.com/blog/2025/10/6/
            \crafting-a-full-exploit-rce-from-a-crash-in-autodesk-revit-rfa-file-parsing

1). 漏洞核心 (CVE-2025-5037)
    类型: 类型混淆 (Type Confusion)。
    根源: RFA 文件反序列化器被诱导将一个不含虚函数表的C++对象(std::pair)当作一个含有vtable的对象进行处理。
    崩溃点: 程序尝试调用对象的析构函数,错误地将对象偏移量0x0处的数据(值为 -1)当作vtable指针,
    执行 call qword ptr [rax] (rax=-1),导致访问冲突。

2). 攻击原语构建
    目标文件格式: OLE 复合文件 (.rfa)。
    关键数据流: Global\Latest。
    数据编码障碍: 数据流内容为 gzip 压缩 + 错误校正码 (ECC) 尾部。必须能够重新生成ECC才能构造有效载荷。
    利用对象: 篡改类型索引,强制反序列化为 AString 类。
        AString 内存布局: 在偏移量 0x0 处是一个 wchar_t* data 指针。
        控制能力: data 指针指向一个从文件中读取的、攻击者完全控制的堆缓冲区。
    获得的原语: 当程序尝试调用 AString 的“析构函数”时,会将 data 指针(位于偏移量 0x0)
    当作 vtable 指针。call qword ptr [rax] 中的 rax 此时指向该 data 指针,
    最终的 call 目标地址由 data 指向的缓冲区内容决定。
    这构成了受控的任意地址调用 (Controlled Arbitrary Call)。

3). 核心利用技术
    ASLR 绕过:
        利用未启用 ASLR 的模块 RWUXThemeSU2015.dll 作为 ROP gadgets 的稳定基地址。
    栈迁移 (Stack Pivot):
        Windows 10 (32-bit Heap): 使用 "怪兽 Gadget" (Monster Gadget)。
            方法: 直接在 .text 段中搜索 mov esp, eax 的机器码 (8B E0)。
            实现: 找到一个位于函数体中间的非典型指令序列。该序列虽包含大量 GDI 调用,
            但因其线性执行、无害的失败路径和最终的 ret,成功将栈指针切换到 eax 指向的攻击者缓冲区。
        Windows 11 (64-bit Heap): 使用 "奇异机" (Weird Machine)。
            方法: 利用对象数组析构的循环 (for (obj : array) { call [obj->vtable]; }) 
                  来串联执行多个单步 gadget。
            步骤 1: 构造第一个 AString,其 data 指向 push rax; pop rbp; ret。效果: rax -> rbp。
            步骤 2: 构造第二个 AString,其 data 指向 leave; ret (mov rsp, rbp; pop rbp; ret)。
                    效果: rbp -> rsp。
            结果: 通过两次循环迭代,完成了一个可靠的 64 位栈迁移。

    x64 ROP 参数加载:
        挑战: Microsoft x64 调用约定下,pop rdx; ret 这类加载易失性寄存器的 gadgets 极其稀少。
        解决方案: "基因改造 Gadget" (Genetically Modified Gadget)。
            目标: 创造一个为 rdx 赋值的 gadget。
            步骤 1: 定位一段现有代码:mov rdx, rsi; ... ; call [fptr_address]。
                   其中 rsi 是非易失性寄存器,易于通过 pop rsi; ret 控制。
            步骤 2: 发现 fptr_address 指向的函数指针位于一个可写内存页。
            步骤 3: 在 ROP 链前期,使用写原语将 fptr_address 处的值覆盖为 pop rax; ret gadget 的地址。
            效果: 执行流到达 call 时,实际跳转到 pop rax; ret。pop rax 消耗了 call 压栈的返回地址,
            ret 则无缝返回 ROP 链。此技术将一段不相关的代码动态地改造成了一个可用的 
            mov rdx, rsi; ... ; ret gadget。

4). 最终载荷
    ROP 链: LoadLibraryW("ucrtbase.dll") -> GetProcAddress("system")。
    执行: 调用 system("powershell.exe -c ...")。


☆ 第020周(2025.10.27-2025.10.31)

1. Reverse Engineering Windows AFD.sys
    链接: https://recon.cx/2015/slides/\
            recon2015-20-steven-vittitoe-Reverse-Engineering-Windows-AFD-sys.pdf

    因为我最近正在研究afd.sys的历史漏洞,所以看到了该篇文章,文章很浅显,
    主要是关于如何分析一个驱动,从哪些方面入手,其相关的供给面等,有参考价值:
    研究对象: AFD.sys,Windows核心网络驱动,处理用户模式的网络请求。
    核心动机: AFD.sys是沙箱进程(如Chrome)能直接访问的关键内核组件,使其成为高价值攻击目标。
    攻击面: 复杂、历史漏洞多、拥有约70个可从用户模式调用的IOCTL接口。
    技术方法:
        静态分析: 逆向其IOCTL派发表,审计代码以寻找整数溢出、TOCTOU等常见漏洞。
        动态分析: 对其所有IOCTL接口进行结构化模糊测试(Fuzzing)。
    结论: AFD.sys是重要的安全审计目标,结合静态与动态分析是挖掘其漏洞的有效途径。

2. How to get started in vulnerability research
    链接: https://github.com/udunadan/notes/blob/main/\
            How%20to%20Get%20Started%20In%20Vulnerability%20Research.md

    这篇文章不是说的技术,跟第五周的类似,这个说的是如何开始漏洞的研究

    漏洞研究的经验:
    ----------------------------------------------------------
    learning to read patch diffs quickly
    identifying suspicious changes and their context
    tracing execution paths in the kernel
    building small testcases and debugging crashing the target
    ----------------------------------------------------------
    举了一个具体的样例,分析漏洞 CVE-2022-34707
    第一步:确定目标信息
    CVE编号:CVE-2022-34707
    目标文件:ntoskrnl.exe (Windows内核)
    补丁版本:
        修复后: KB5016616
        修复前: KB5015878
    第二步:获取文件
        使用Winbindex网站,根据上述两个KB号,分别下载“修复前”和“修复后”的 ntoskrnl.exe 文件。
    第三步:比对与定位
        加载文件: 将两个 ntoskrnl.exe 文件导入二进制比对工具 (如 Diaphora, BinDiff)。
        寻找差异: 查看工具生成的、存在代码差异的函数列表。
        锁定可疑函数: 在列表中找到一个命名可疑的函数:CmpCheckAndFixSecurityCellsRefcount。
        函数名暗示了它与安全和内存管理有关。

    第四步:分析与验证
        分析代码变更: 深入查看 CmpCheckAndFixSecurityCellsRefcount 函数,
        发现补丁修复了一个微小的比较逻辑错误。
        理解触发条件: 研究如何通过用户操作(如操作注册表)来调用到这个存在漏洞的内核函数。
        尝试复现: 编写一个简单的概念验证程序(PoC),触发该漏洞,以证实自己的分析。

☆ 第021周(2025.11.03-2025.11.07)

    这周看了很多文章,但是没有特别值得记录的,空一周

☆ 第022周(2025.11.10-2025.11.11)

1. Unleash the Fuzzer: How MS-RPC Fuzzing Exposes Hidden Windows Vulnerabilities 
    
    链接: https://undercodetesting.com/\
        unleash-the-fuzzer-how-ms-rpc-fuzzing-exposes-hidden-windows-vulnerabilities/

    文章主要说的是如何使用powershell来挖掘windows RPC的漏洞,利用其程序能够极大的降低挖掘rpc
    漏洞的难度,我自己对这部分的内容不是很熟悉,就当扩展知识面了
    主要的攻击和发现流程:
    发现接口:
        目的: 枚举目标服务器上开放的RPC接口(UUID),作为Fuzzing的目标。
        工具:
            PowerShell RpcTools 模块 (Get-RpcClient)。
            Impacket工具集中的 rpcdump.py。
    执行Fuzzing:
        关键技术: 采用“上下文感知”(Context-Aware)的Fuzzing模式,它比随机测试更智能、更高效。
        工具: 使用基于PowerShell的MS-RPC Fuzzer模块 (Start-RpcFuzz)。
    分析崩溃:
        目的: 当Fuzzing导致服务崩溃后,分析崩溃转储文件(Crash Dump)以确定漏洞是否可被利用。

2. Exploiting the NT Kernel in 24H2: New Bugs in Old Code & Side Channels Against KASLR

    链接: https://exploits.forsale/24h2-nt-exploit/

    近期看到的最佳文章
    关键技术点:

    新漏洞的成因:
        24H2内核将用户模式内存视为volatile,引入了新函数 RtlCopyVolatileMemory。
        此举阻止了编译器将源代码中对同一内存地址的两次读取优化为一次,
        从而暴露了潜藏的“双取”漏洞(一种 TOCTOU 竞争条件漏洞)。
    发现的两个关键漏洞:
        CVE-2024-26218 (栈溢出): 在PspBuildCreateProcessContext函数中,
            对进程属性的Size字段进行双取,可在两次读取间隙修改Size值,导致栈缓冲区溢出。
        CVE-2024-21345 (任意地址写入): 在NtQueryInformationThread函数中,
            对BytesToRead字段进行双取。利用此漏洞可通过一个巧妙的技巧绕过ProbeForWrite的地址检查,
            实现向任意内核地址写入可控数据,这是后续利用链的核心原语。

    KASLR绕过新方法:
        由于24H2修复了传统的内核地址泄露,作者采用了一种基于prefetch指令的时间侧信道攻击来定位内核基地址。
        该方法利用了现代 Windows 11 默认禁用 KVA Shadowing 的特性,使得整个内核地址空间都被映射,
        通过测量prefetch指令的执行时间差异,可以判断一个地址是否有效映射,从而暴力破解出内核基地址。

    完整利用链 (Exploit Chain):
        步骤 1 (绕过 KASLR): 使用prefetch侧信道攻击找到内核基地址。
        步骤 2 (获得任意写原语): 利用NtQueryInformationThread的双取漏洞 (CVE-2024-21345)。
        步骤 3 (构建任意读原语): 利用已有的任意写原语,篡改内核全局变量ExpManufacturingInformation的指针和长度,
            将NtQuerySystemInformation系统调用变为一个通用的任意地址读工具。
        步骤 4 (提权): 使用读写原语,执行经典的令牌交换攻击。通过遍历 PsActiveProcessHead 进程列表,
            找到 SYSTEM 进程的令牌,并将其替换到当前进程上,最终以 SYSTEM 权限启动一个新的命令行窗口。



☆ 第023周(2025.12.08-2025.12.12)

前几周一方面因为忙,另一方面读了很多文章,但是不值得记录,
所以这几周就没有更新内容

1. Enhanced Vulnerability Hunting in WDM Drivers with Symbolic Execution and Taint Analysis
    链接: https://github.com/zeze-zeze/ioctlance

    库中包含其中文章链接以及ioctlance的源码
    结合其pdf文档,该工具主要是通过符号执行 (Angr) + 污点分析的方式,
    无环境依赖(无需虚拟机),直接分析二进制,

    分析可以简单的分为以下几步: 
    
    1. 预处理: 静态扫描特权指令 (wrmsr/out) 并 Hook;识别内联 memcpy 以加速分析。
    2. 找入口: 模拟运行 DriverEntry -> 监控内存写入 -> 捕获 IOCTL 分发函数地址。
    3. 挖漏洞: 构造全符号化 IRP(输入/长度/控制码均为符号)-> 传入分发函数 -> 污点追踪数据流向危险操作。

    主要是寻找如下几种漏洞形式:
    任意地址读写、缓冲区溢出、物理内存映射、提权句柄、空指针、Shellcode执行、任意MSR/端口写、任意文件删除。

    其中可以参考的地方在于模拟执行和污点分析的部分,针对windows系统驱动分析大概率没有作用


待阅读: 



待复现:
https://exploits.forsale/24h2-nt-exploit/

https://github.com/MrAle98/CVE-2025-21333-POC
https://github.com/encrypter15/CVE-2025-29824

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions