shellcode exit normally

前言

最近和jaguo在给南京大学软件安全课程出Buffer Overflow实验的时候,发现了出现shellcode exit normally的情况,但是并没有”发现”启动了新的shell。

漏洞程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// buf2.c
// gcc −z execstack −o buf buf2 -fno-stack-protector
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
void vul(char *str){
char buffer[36];
// buffer overflow
strcpy(buffer, str);
}

int main(int argc, char **argv){
char str[128];
int n = read(0, str, 128);
if(n < 0){
printf("Read Error\n");
exit(-1);
}
vul(str);
printf(”Returned Properly\n”);
return 0;
}

我们一开始的设计是漏洞程序如上所示,由于需要注入shellcode,有些是不可见字符,所以我们一开始设计将shellcode写入到一个文件attack_input中,然后通过重定位将输入定位到attack_input文件中,可以将shellcode传给输入。

1
./buf2 < attack_input

然而这样就导致虽然能够正确注入shellcode,但是只要执行shellcode中的execve(‘/bin//sh’, 0, 0),就立即退出/bin//sh程序,而不是给出bash的命令行窗口。

shell_exit

原因

经过查阅资料发现,我们在使用输入重定位的时候,就相当于将进程的输入重定位到文件中,而当程序将文件中的内容读完之后,会关闭该文件,此时相当于将程序的输入(stdin)关闭了。
当该进程启动一个shell进程时,shell进程是该进程的子进程,继承了父进程的文件描述符(包括已经关闭了的标准输入),此时shell发现标准输入已经关闭了,就会退出。

下面我们通过下面的实验来验证一下:

1
2
3
4
5
6

#include <stdio.h>
int main(){
fclose(stdin);
system("/bin/sh");
}

编译运行该程序,会发现shell也会正常退出。

解决方案

我们的解决方案就是使用文件读函数正常的从文件中读取shellcode。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25


// buf2.c
// gcc -z execstack -o buf2 buf2.c -fno-stack-protector

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

void vul(char *str){
char buffer[36];
// buffer overflow
strcpy(buffer, str);
}

int main(int argc, char **argv){
char str[128];
FILE *file;
file = fopen("attack_input2", "r");
fread(str, sizeof(char), 128, file);
vul(str);
printf("Returned Properly\n");
return 0;
}