我正在尝试创建一个非常基本的telnet服务器来练习内存破坏漏洞。当我尝试发出命令时,在第一次迭代中,什么也没有发生。第二次迭代,我在服务器端打印了多个错误的文件描述符错误。在客户端,一切似乎都还可以。我得到所有必需的提示。这是我的相关代码:
int piper[2];
pipe(piper);
...
while (1) {
n = write(newsockfd,"Enter a command...\n",21);
if (n < 0) error("ERROR writing to socket");
bzero(buffer,4096);
n = read(newsockfd,buffer,4095);
strcpy(command, buffer);
pid_t childpid;
childpid = fork();
if(childpid == -1) {
perror("Failed to fork");
return 1;
}
if(childpid == 0) { //child
printf("I am child %ld\n", (long)getpid());
if(dup2(piper[1], 1) < 0) {
perror("Failed to pipe in child process");
}
else {
close(piper[0]);
close(piper[1]);
char *args[] = {command, NULL};
execve(command, args, NULL);
}
}
else { // parent
if(dup2(piper[0], 0) < 0) {
perror("Failed to pipe in parent process");
}
else {
// read command output from child
while(fgets(command_out, sizeof(command_out), stdin)) {
printf("%s", command_out);
}
}
}
}
如果我在客户端中输入/bin/ls
,则会在服务器上输出以下内容:
I am child 26748
第二次这样做,我将以下内容输出到服务器:
Failed to pipe in parent process: Bad file descriptor
0I am child 26749
Failed to pipe in child process: Bad file descriptor
答案 0 :(得分:2)
有可能在子进程中关闭管道也会在父进程中关闭管道。考虑在while循环的开头移动piper(pipe)。为了安全起见,请在文件循环结束时关闭管道,不要忘记测试close的返回值。
实际上read
在输入的末尾添加了换行符,因此您的命令可以是testprog
,但实际上,当使用read()
时,它是testprog\n
,因此您必须摆脱添加的换行符,否则execve()
将期望其中包含换行符的程序名称。
#define STDIN 0
int n = read(STDIN, command, 4096);
command[n - 1] = '\0'; // get rid of newline
char *args = { command, NULL };
execve(buf, &args[0], NULL);