pwn0

1
ssh ctfshow@pwn.challenge.ctf.show -p28110

等待程序跑完

1
2
cat /ctfshow_flag
# 把ctfshow_flag这个文件里的内容输出到终端

获得flag

pwn1

010打开附件 是ELF文件

在虚拟机运行checksec pwn1

1
2
3
4
5
6
7
8
ctfshow@ubuntu:~/Desktop/pwn1wjj$ checksec pwn1
[*] '/home/ctfshow/Desktop/pwn1wjj/pwn1'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
ctfshow@ubuntu:~/Desktop/pwn1wjj$

checksec查看二进制启用了哪些安全机制。判断该走什么利用方式。

可以看到是64位仅关闭Canary保护

  • NX: 不能直接执行栈上的 shellcode,通常走 ROP/ret2libc。
  • Canary: 有金丝雀,溢出必须先泄露或绕过。
  • PIE: 程序地址随机化,需要先泄露地址。
  • RELRO: 影响 GOT 能否被写,用于判断能不能改 GOT

打开附件后反编译可直接看到关键命令:

  • cat /ctfshow_flag
  • 以及提示语:You only need to connect to the remote address with NC to get the flag!

表明连接后不用操作,程序会直接执行cat读取flag

checksec仅用于了解保护情况,但本题不需要利用链,发现 system("cat /ctfshow_flag") 后直接连接即可

直接在虚拟机nc连接即可获得flag

pwn2

反编译附件后看到

system("/bin/sh")直接启动一个后门。连上远程以后直接进入shell环境。然后自己执行cat /ctfshow_flag就可以读flag

pwn3

1
2
3
4
5
6
7
8
9
You can call the following function:
1._start
2.main
3.hello_ctfshow
4.ctfshow('echo /ctfshow_flag')
5.print('/ctfshow_flag')
6.system('cat /ctfshow_flag')
7.puts('/ctfshow_flag')
8.exit

4 5 7都是打印路径字符串

只有6是读取文件内容

pwn4

打开附件 反编译

字符串比较口令校验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int __fastcall main(int argc, const char **argv, const char **envp)
{
char s1[11];
char s2[12];
unsigned __int64 v6;

v6 = __readfsqword(0x28u);
setvbuf(_bss_start, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 2, 0LL);
strcpy(s1, "CTFshowPWN");
logo();
puts("find the secret !");
__isoc99_scanf("%s", s2);
if ( !strcmp(s1, s2) )
execve_func();
return 0;
}

C语言的反编译版本。IDA把机器代码“猜回”C,所以名字看上去奇怪。本质上还是C语言

1
int __fastcall main(int argc, const char **argv, const char **envp)

main是程序固定入口

intmain最后会返回一个整数(0表示正常结束)

argc/argv/envp是命令行参数(这里可以不用管

_fastcall是编译器用的调用方式,对题目逻辑没影响

1
2
3
char s1[11];
char s2[12];
unsigned __int64 v6;
  • char s1[11];
    开一块能放11个字符的空间
  • char s2[12];
    开一块能放12个字符的空间
  • unsigned __int64 v6;
    一个 64 位无符号整数。
    这个是栈保护值,暂时理解为安全锁
1
v6 = __readfsqword(0x28u);

读取栈保护值。是编译器加的,防止栈溢出攻击。和题目逻辑无关

1
2
setvbuf(_bss_start, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 2, 0LL);

让输入输出立刻显示,不等缓冲,这样交互更流畅

1
strcpy(s1, "CTFshowPWN");

strcpy是把右边字符串复制到左边的数组里

所以s1现在是CTFshowPWN

1
2
logo();
puts("find the secret !");

logo()是打印题目banner

puts()是打印一句话

1
__isoc99_scanf("%s", s2);

"%s"是“读入一个字符串”

你的输入会被存进s2

1
2
if ( !strcmp(s1, s2) )
execve_func();
  • strcmp(s1, s2)比较两个字符串。
    • 如果相同,返回0
    • 如果不同,返回非0
  • !strcmp(...) 的意思是“如果它们相同”
  • 如果相同,执行 execve_func()
1
return 0;

程序结束正常退出

因此这里要输入s1数值,你输入的内容就存入s2,与真实的s1比较,相同则执行execve_func()

反编译execve_func(),发现就是进入一个shell

1
2
CTFshowPWN
cat /ctfshow_flag