Home avatar

PAWNYABLE kernel stack overflow 笔记

PAWNYABLE 中的第一节 stack overflow 的学习笔记。( 觉得这个教程好细致,而且封面好可爱… 这一节讨论内核的栈溢出,分成了不同防护程度的情况来讨论不同的情况下面,攻击应该如何进行。

在 module_write 里面,copy_from_user 的大小是用户控制,大小没有检查的。可以在这里发生溢出。read 也有这个漏洞,可以读取更多的数据(

网鼎杯 2024 玄武 pwn2 (kernel)

c

void unshare_setup() {
    char edit[0x100];
    int tmp_fd;

    // from lib pthread
    unshare(CLONE_NEWNS | CLONE_NEWUSER | CLONE_NEWNET);

    // from lib fcntl
    tmp_fd = open("/proc/self/setgroups", O_WRONLY);
    write(tmp_fd, "deny", strlen("deny"));
    close(tmp_fd);

    tmp_fd = open("/proc/self/uid_map", O_WRONLY);
    sprintf(edit, "0 %d 1", getuid());
    write(tmp_fd, edit, strlen(edit));

    tmp_fd = open("/proc/self/gid_map", O_WRONLY);
    snprintf(edit, sizeof(edit), "0 %d 1", getgid());
    write(tmp_fd, edit, strlen(edit));
    close(tmp_fd);
}

这个函数的目的是为当前进程配置新的名字空间,尤其是 mountusernetwork 名字空间,确保进程在新的名字空间中有隔离的环境。此外,它通过设置 UID 和 GID 映射来确保进程在新的用户名字空间中以 root 用户身份 (UID 0) 运行,但在主机系统中仍保持原有的 UID 和 GID。这种做法通常用于容器技术或者其他需要进程隔离的场景。

L3HCTF 信じてください、先輩!!复现

这题与 OPTEE 有关。可以理解成,这个机器上同时运行有两个 OS:一个是正常的 OS 来处理不需要保密的内容,一个是安全的 OS (OPTEE),涉及保密的内容在这个安全 OS 里面操作。通过 trusted firmware 来启动这两个 OS,相当于这两个 OS 的 bootloader。这两个系统之间的交互通过一些可信应用 trusted application 完成。

ta 必须要实现一些入口点

asisctf 2023 pwn nightjs 复现记录

asisctf2023 nightjs 附件 一道 js 引擎题目,基于 serenityOS 上做的改编。(感觉 serenity 作者很 强迫症 善良得写了很多注释,连一行赋值语句都有注释,读起来超级愉悦)。

b84496fab7ea760b061328fc6169713e

偷看了别人的wp来复现。给了 patch 文件之后,查看修改处的函数被什么函数引用,漏洞点就很明了了。攻击流程不难,不记录了。不过第一次见到脚本语言引擎的题目,有一些磕磕绊绊,这里总结一下收获。

serenity js (和一般的脚本语言类似的)执行过程大概分为两个阶段:

  • parce souce code to bytecode
  • run bytecode 。

主要的处理部分在 parse_and_run 中。把源码解析成一个个字节码之后 run 的过程,其实就是找到每个 bytecode 对应的函数执行。

JS::Bytecode::Instruction::execute () 涉及从 bytecode 找到对应 function 的逻辑(感觉写的好优雅哇)。以 bytecode CALL 来举例,其类型是 Instruction::Type::Call 所对应的函数是 JS::Bytecode::Op::Call::execute_impl()

tsctf-j2023 strange_code_runner e_order wp

这是一个可以执行 shellcode 的小程序,三个选项依次是edit、load、run,运行一下简单了解一下这个可执行文件的功能:

bash

1. edit code
2. load code
3. run code
>>>1
>>>AAAAA

>>>2
load success

>>>3
unable to pass the check

我们仔细看这三个功能:edit 读取输入写进名为 code 的文件

cpu 3 模式

参考 blog

按照 CPU 功能升级迭代的顺序,CPU 的工作模式有实模式、保护模式、长模式。他们的主要区别是寻址方式和指令权限。下文以 x86_64 为例

每个 16 bit 大小,可以分成 H 和 L 两个。下图的右半边的寄存器。

寄存器

  • 寻址范围 8086 cpu 的地址总线有 20 位,所以寻址范围 2**20 = 1 MB(后续的 cpu 兼容了实模式的寻址方法)

  • 寻址方式 寄存器 16 位,地址有 20 位,为了访问更高的内存引入了段式内存管理——8086CPU将1MB存储空间分成许多逻辑段,每个段最大限长为64KB(但不一定就是64KB)。这样每个存储单元就可以用“段基地址+段内偏移地址”表示段基地址由16位段寄存器值左移4位表达,段内偏移表示相对于某个段起始位置的偏移量。

            段机制              分页机制

逻辑地址———->线性地址————–>物理地址

和实模式直接把段基址放在寄存器当中的做法不一样。保护模式设置了 GDT 段描述符表,寄存器里面存放了段的序号。

保护模式新增了对段落的权限检查,比如读写权限等等:

保护模式的中断同理,也增加了权限检查

x 86-64 体系结构在长模式(64 位模式)下不使用分段。其中四个段寄存器:CS、SS、DS 和 ES 强制为 0,限制为 2^64。长模式访存

dasctf2023 june toka garden and bios-mbr os 启动流程

被纯真拉来看题楽。

日常忏悔没有学好操作系统。借着 dasctf 6 toka garden 了解了下操作系统 bios-mbr 的启动流程。

启动(boot)一词来自于一句谚语 “pull oneself up by one’s bootstraps” (“拽着鞋带把自己拉起来”)这当然是不可能的事情。最早的时候,工程师们用它来比喻,计算机启动是一个很矛盾的过程:必须先运行程序,然后计算机才能启动,但是计算机不启动就无法运行程序

必须想尽各种办法,把一小段程序装进内存,然后计算机才能正常运行。所以,工程师们把这个过程叫做"拉鞋带",久而久之就简称为boot了。

参考文章 os 如何启动

计算机通电后,CPU中的执行地址会初始化为BIOS的地址,然后开始加载执行BIOS程序。

全称 Basic Input/Output System,用于检查硬件,而跟操作系统关系不大,因此电脑可以适应多种操作系统。BIOS 程序存放在 ROM 中,它的启动地址也是根据标准制定的。

  • POST (poser-on self-test)检查硬件,如果有故障会发出 哔 的声音
  • 启动设备 会找到第一个设备的第一个扇区内容(MBR)加载到内存,并跳转执行

参考 启动设备的第一个扇区的内容称为主引导记录(MBR,Master Boot Record),由三个部分组成

  1. bootloader,主引导程序(446个字节)
  2. Dpt(Disk Partition table),硬盘分区表(64个字节)
  3. 扇区结尾标志(55aa)标志当前扇区是否合法,不合法(不是55AA),会跳回BIOS寻找下一个启动设备

BIOS 把主引导程序加载到了内存中的固定位置 0x7c00,这个有 历史遗留原因的。而主引导程序负责把扇区中的操作系统代码加载到内存,然后执行操作系统代码。对于不同的操作系统,这一加载过程可能会有所不同。

如果启动过程足够简单,仅仅 MBR 的代码就足以加载 os,那么 MBR 中的代码就可以成为 bootloader。如果启动过程复杂,MBR 会调用一些启动管理器软件来加载 os

那就是 os 自己的事情了…吧

以 dasctf 6 toka garden 为例,用到了一个简单的 bootloader