pwn13
题目说编译运行这个flag.c文件即可获得flag。那我们先把flag.c文件下载下来,然后托到虚拟机里使用gcc编译一下,运行看看是否能够拿到flag。
gcc -o flag -flag.c
./flag
ok,果然拿到了flag。flag为:ctfshow{hOw_t0_us3_GCC?}。
pwn14
本题是让我们阅读flag.c文件的源码,给定key为"CTFshow",编译运行之后即可获得flag。其中呢,给定key为CTFshow是个啥子意思我们现在不是很清楚。那我们就先下载flag.c文件查看一下源码吧!
flag.c文件源码:
// flag.c
#include <stdio.h>
#include <stdlib.h>
#define BUFFER_SIZE 1024
int main() {
FILE *fp;
unsigned char buffer[BUFFER_SIZE];
size_t n;
fp = fopen("key", "rb");
if (fp == NULL) {
perror("Nothing here!");
return -1;
}
char output[BUFFER_SIZE * 9 + 12];
int offset = 0;
offset += sprintf(output + offset, "ctfshow{");
while ((n = fread(buffer, sizeof(unsigned char), BUFFER_SIZE, fp)) > 0) {
for (size_t i = 0; i < n; i++) {
for (int j = 7; j >= 0; j--) {
offset += sprintf(output + offset, "%d", (buffer[i] >> j) & 1);
}
if (i != n - 1) {
offset += sprintf(output + offset, "_");
}
}
if (!feof(fp)) {
offset += sprintf(output + offset, " ");
}
}
offset += sprintf(output + offset, "}");
printf("%s\n", output);
fclose(fp);
return 0;
}
代码的大致逻辑就是读取一个名为"key"的文件,然后根据该文件的内容通过一个while循环再嵌套两个for循环,具体的代码就不分析了,之后就可以输出flag了。
大家注意这个key文件是从我们本地读取的,所以我们在运行之前需要先手动创建一个key文件,根据题目的提示,key文件的内容应该为CTFshow。这样我们再编译运行flag.c文件就可以获得flag了。
echo CTFshow > key # 创建内容为CTFshow的key文件
gcc -o flag ./flag.c # 编译flag.c
./flag #运行flag文件那flag
pwn15
本题目是让我们将flag.asm汇编代码编译成可执行文件再运行即可拿到flag。那我们就下载flag.asm文件编译运行呗。
nasm -f elf64 flag.asm # 将flag.asm编译成64为.o文件
ld -s -o flag flag.o # 将flag.o链接成flag可执行文件
./flag # 运行flag可执行文件拿到flag
pwn16
本题是让我们使用gcc将flag.s文件编译成可执行文件。那我们就下载flag.s文件将其编译成可执行文件。
gcc -o flag flag.s # 将flag.s编译成flag可执行文件
./flag # 运行flag可执行文件拿到flag
pwn17
我们先将这个pwn文件拖进虚拟机,给它加上个可执行的权限。然后再使用checksec命令查看该文件的信息。
chmod +x pwn
checksec ./pwn
可以看到,pwn文件是一个64为的可执行文件,那我们直接拖进ida64反编译下看一看里边有什么东西。
反编译出的代码:
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [rsp+4h] [rbp-1Ch] BYREF
char dest[4]; // [rsp+Ah] [rbp-16h] BYREF
char buf[10]; // [rsp+Eh] [rbp-12h] BYREF
unsigned __int64 v7; // [rsp+18h] [rbp-8h]
v7 = __readfsqword(0x28u);
setvbuf(_bss_start, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 1, 0LL);
puts(asc_D48);
puts(asc_DC0);
puts(asc_E40);
puts(asc_ED0);
puts(asc_F60);
puts(asc_FE8);
puts(asc_1080);
puts(" * ************************************* ");
puts(aClassifyCtfsho);
puts(" * Type : Linux_Security_Mechanisms ");
puts(" * Site : https://ctf.show/ ");
puts(" * Hint : You should understand the basic command usage of Linux! ");
puts(" * ************************************* ");
*(_DWORD *)dest = 790655852;
v4 = 0;
puts("\nHow much do you know about Linux commands? \n");
while ( 1 )
{
menu();
v4 = 0;
puts("\nEnter the command you want choose:(1.2.3.4 or 5)\n");
__isoc99_scanf("%d", &v4);
switch ( v4 )
{
case 1:
system("id");
break;
case 2:
puts("Which directory?('/','./' or the directiry you want?)");
read(0, buf, 0xAuLL);
strcat(dest, buf);
system(dest);
puts("Execution succeeded!");
break;
case 3:
sleep(1u);
puts("$cat /ctfshow_flag");
sleep(1u);
puts("ctfshow{");
sleep(2u);
puts("... ...");
sleep(3u);
puts("Your flag is ...");
sleep(5u);
puts("ctfshow{flag is not here!}");
sleep(0x14u);
puts("wtf?You haven't left yet?\nOk~ give you flag:\nflag is loading......");
sleep(0x1BF52u);
system("cat /ctfshow_flag");
break;
case 4:
sleep(2u);
puts("su: Authentication failure");
break;
case 5:
puts("See you!");
exit(-1);
default:
puts("command not found!");
break;
}
}
}
我们先来分析一下代码的逻辑,首先是进入一个while循环打印出menu也就是菜单。然后是一个switch-case语句,根据我们输入的选项来执行分支语句。
我们分析源码看到case 3中有一个system(“cat /ctfshow_flag”)的语句,也就是可以读取flag的语句。但是!!!
我们来看!!!
这条sleep(0x1BF52u)语句是我们读取flag的障碍!因为这条语句它要睡眠0x1BF52秒啊,换算成10进制就是114514秒,那就是31个小时啊!!!这怎么等的了!
所以另求他法。
我们再看case 2:
case 2:
puts("Which directory?('/','./' or the directiry you want?)");
read(0, buf, 0xAuLL);
strcat(dest, buf);
system(dest);
puts("Execution succeeded!");
break;
如果我们选择的case2,首先它是输出一行字符串,然后让我们输入一行长度为0xA的字符串buf,也就是长度为9的字符串。接着把我们输入的字符串buf赋给dest,然后使用system函数将dest作为参数传入进行命令执行。
选项2的功能总的来说就是,将我们输入的字符串当作参数传入system()函数!那我们就可以直接传入cat /ctfshow_flag吗?
那当然不行的,因为代码已经限制了我们输入字符串的长度为9,所以我们得换个命令想办法读取flag。我们知道system(“/bin/sh”);是可以获得Linux的交互式shell的,正好/bin/sh的长度也没有超过9,所以我们就可以传入/bin/sh来获取交互式shell,进而手动执行cat /ctfshow_flag来get flag了!
nc 连接,开干!!!
输入2 ->输入/bin/sh->执行cat /ctfshow_flag
OK,成功拿到flag!
pwn18
首先我们还是下载pwn文件拖进虚拟机加上可执行权限再使用checksec命令查看文件信息。
chmod +x pwn
checksec pwn
64位的文件,并且题目也提示我们要看源码,那我们就将pwn这个文件拉到ida64反编译下看看源码是什么。
源码:
// main
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v5; // [rsp+8h] [rbp-8h]
v5 = __readfsqword(0x28u);
setvbuf(_bss_start, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 1, 0LL);
puts(s);
puts(asc_B10);
puts(asc_B90);
puts(asc_C20);
puts(asc_CB0);
puts(asc_D38);
puts(asc_DD0);
puts(" * ************************************* ");
puts(aClassifyCtfsho);
puts(" * Type : Linux_Security_Mechanisms ");
puts(" * Site : https://ctf.show/ ");
puts(" * Hint : Do you know redirect output ? ");
puts(" * ************************************* ");
puts("Which is the real flag?");
__isoc99_scanf("%d", &v4);
if ( v4 == 9 )
fake();
else
real();
system("cat /ctfshow_flag");
return 0;
}
// fake
int fake()
{
return system("echo 'flag is here'>>/ctfshow_flag");
}
// real
int real()
{
return system("echo 'flag is here'>/ctfshow_flag");
}
我们先来分析一下代码逻辑,大概流程就是需要我们输入一个值v4,看这个值v4是否等于9,如果等于9就执行fake()函数,然后再执行system函数打印出flag;如果不等于9就先执行real()函数,然后再执行system函数打印出flag。
查看源码我们可以发现啊,real()函数跟fake()函数里的内容一样,都会执行
echo ‘flag is here’>/ctfshow_flag 这条命令。这条命令的作用就是将"flag is here"这个字符串追加道/ctfshow_flag文件中,这就代表system函数最后输出flag的时候,屁股后面一定会有flag is here这条字符串,之后我们再把这条字符串从输出的flag删掉就是真正的flag了!
nc连接,开干!!!
OK,成功拿到flag!
pwn19
OK,我们还是先下载pwn文件托到虚拟机里加上可执行权限再使用checksec命令查看文件信息。
chmod +x pwn
checksec pwn
pwn文件依旧是64位的,直接拖进ida64看一下源码。
// main
int __cdecl 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);
setvbuf(_bss_start, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 1, 0LL);
puts(s);
puts(asc_BF0);
puts(asc_C70);
puts(asc_D00);
puts(asc_D90);
puts(asc_E18);
puts(asc_EB0);
puts(" * ************************************* ");
puts(aClassifyCtfsho);
puts(" * Type : Linux_Security_Mechanisms ");
puts(" * Site : https://ctf.show/ ");
puts(" * Hint : Turn off output, how to get flag? ");
puts(" * ************************************* ");
if ( fork() )
{
wait(0LL);
sleep(3u);
printf("flag is not here!");
}
else
{
puts("give you a shell! now you need to get flag!");
fclose(_bss_start);
read(0, buf, 0x20uLL);
system(buf);
}
return 0;
}
// fork
// attributes: thunk
__pid_t fork(void)
{
return fork();
}
这道题目前还没有想出来办法解决,因为它把输出流给关掉了,也就是我们执行命令得不到回显了,而且ping命令也没有也不能用dns带外,nc命令也没有,也不能反弹到外网服务器!哎,。。。。我再想想办法~ _ ~