前言
一、pwn13
二、pwn14
三、pwn15(编译汇编代码到可执行文件,即可拿到flag)
四、pwn16(使用gcc将其编译为可执行文件)
五、pwn17
六、pwn18
七、pwn19(关闭了输出流,一定是最安全的吗?)
记录一下pwn13~pwn19,巩固一下学到的知识。
知识点:如何使用GCC
gcc main.c -o program
·gcc 是调用 GCC 编译器的命令。
·-o program 指定输出的可执行文件名为 program。
·main.c 是你的源代码文件。
┌──(kali㉿kali)-[/home/kali]
└─PS> gcc /home/kali/桌面/ctfshoww/flag.c -o flag
┌──(kali㉿kali)-[/home/kali]
└─PS> ./flag
ctfshow{hOw_t0_us3_GCC?}
查看源代码:
FILE *fp;
unsigned char buffer[BUFFER_SIZE];
size_t n;
fp = fopen("key", "rb");
if (fp == NULL) {
perror("Nothing here!");
return -1;
}
有一个文件存在检验
1.手动新建一个key文件再写入CTFsho
2.编译运行即可
ctfshow{01000011_01010100_01000110_01110011_01101000_01101111_01110111_00001010}
知识点(以文件ailian为例):
1.使用 nasm 将汇编代码编译为目标文件:
nasm -f elf64 ailian.asm -o ailian.o
-f elf64 指定目标文件格式为 64 位 ELF(适用于 x86_64 架构)。
-o ailian.o 指定输出文件名为 ailian.o。
2.链接目标文件
使用 ld 将目标文件链接成可执行文件:
ld ailian.o -o ailian
ailian.o 是编译后的目标文件。
-o ailian 指定输出的可执行文件名为 ailian。
3.
运行编译后的可执行文件:
./ailian
──(kali㉿kali)-[~/桌面/ctfshoww]
└─$ nasm -f elf64 flag.asm -o flag.o
┌──(kali㉿kali)-[~/桌面/ctfshoww]
└─$ ld flag.o -o flag
┌──(kali㉿kali)-[~/桌面/ctfshoww]
└─$ ./flag
ctfshow{@ss3mb1y_1s_3@sy}
总结:编译与链接的区别
编译:将汇编代码转换为目标文件,生成机器代码和符号表。
链接:将多个目标文件(和库文件)合并,解析符号引用,分配地址,生成可执行文件。
为什么不能直接运行目标文件?
目标文件是一个中间产物,它没有解决符号的最终地址,也没有包含程序运行所需的完整信息(如库函数代码)。只有经过链接,生成的可执行文件才是一个完整的程序,可以在操作系统中运行。
所以编译后需要通过链接器(这里是ld)链接。
gcc flag.s -o flag
./flag
ctfshow{daniuniuda}
输入1.2.3.4发现都不行,甚至陷入死循环,还有31小时的“广告”时间所以查看代码
dest是一个长度为4字节的字符数组,被赋值为790655852(十进制),对应的十六进制是0x2F6C6C64,反向字节序为dll/。
打印提示信息,要求用户输入一个命令选项(1、2、3、4或5)。
使用__isoc99_scanf读取用户输入的整数v3。
如果用户输入的值小于等于5,则退出循环。
如果输入的值大于5,则提示“command not found!”。
选2首先它是输出一行字符串,然后输入一行长度为0xA的字符串buf,也就是长度为10的字符串。接着把字符串buf赋给dest,然后使用system函数将dest作为参数传入进行命令执行。直接把/bin/sh传入。
输入2后传入/bin/sh执行cat ctfshow_flag即可getshell
ctfshow{5771629e-cc54-4ff3-a72f-d7698c5c6b31}
仔细看看源码,或许有惊喜
对的,应该执行fake。
分析一下代码:
if ( v5 == 9 )
fake();
else
real();
system("cat /ctfshow_flag");
result = 0;
v4 = *MK_FP(__FS__, 40LL) ^ v6;
return result;
无论怎样都会执行system("cat /ctfshow_flag")
跟进看看fake和real
int fake()
{
return system("echo 'flag is here'>>/ctfshow_flag");
}
fake方法在文件catfshow_flag的末尾追加内容"flag is here"
但是real
int real()
{
return system("echo 'flag is here'>/ctfshow_flag");
}
是用flag is here来覆盖了/ctfshow_flag文件
所以应该输入9
Which is the real flag?
9
ctfshow{911d6eff-31c1-47be-9f41-6543f840f118}
flag is here
这题当场傻眼的。。。
知识点:
流是一种数据传输的抽象模型,它将数据表示为一个有序的字节序列。流可以分为以下几种类型:
·输入流(Input Stream):用于从数据源读取数据。
·输出流(Output Stream):用于向数据目标写入数据。
·双向流(Duplex Stream):同时支持读取和写入操作。
(比如c语言中的FILE*类型用于表示文件流)
标准输入/输出流
标准输入流(stdin)和标准输出流(stdout)是与终端或控制台交互的流。它们分别用于从用户输入数据和向用户输出数据。在大多数编程语言中,stdin 和 stdout 是预定义的流。
C语言中的:
printf("Hello, World!"); // 写入到 stdout
scanf("%d", &num); // 从 stdin 读取数据
这段代码是一个典型的基于 fork() 和 system() 的程序,它的主要功能是创建一个子进程,并在子进程中执行用户输入的命令。
父进程:
if (fork())
{
wait(0LL); // 父进程等待子进程结束
sleep(3u); // 父进程休眠3秒等待子进程的进行
printf("flag is not here!", 0LL); // 输出提示信息
}
子进程:
else
{
puts("give you a shell! now you need to get flag!");
fclose(_bss_start); // 关闭一个文件指针
read(0, &buf, 0x20uLL); // 从标准输入读取最多32字节的数据到 buf
system(&buf); // 执行 buf 中的命令
}
它关闭了子进程的输出流,这可咋办,我也就没法了。
但父进程的输出任然是打开的。
根据题目的意思是子进程关闭了输出流,我们用1>&0将标准输出(stdout
)的内容重定向到标准输入(stdin
)。子进程中的输出会被发送到父进程中的输入,读取cat ctfshow_flag到buf,由system()调用
give you a shell! now you need to get flag!
cat /ctfshow_flag 1>&0
ctfshow{ee94a5a8-7edc-4451-a04c-c01962d371eb}
flag is not here!
继续学习中......