OverTheWire.org
Hacker Community
Contribute to OverTheWire ?
Click here!
News (2012-01-07):
Best wishes for 2012 ! We released the HES2010 wargame ! Read more...
Discuss this level on the forum

Level 12

Authentication Daemon
There is an authentication daemon waiting on brebera port 24012. You connect to it, supply your password and get authenticated. The semtex 12 password will give you user access, the admin password will give you administrator access...

After authentication you connect to the remote file system reader on port 24013. Depending on your access level you can list files and show them. The semtex 13 password has been located in one of the files on this remote file system. Brebera is fast, can you be faster?
Thanks to bk for this level!
Code listing (level12.authd.c)
  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 #include <sys/ipc.h>
  5 #include <sys/shm.h>
  6 #include <sys/types.h>
  7 #include <netinet/in.h>
  8 #include <arpa/inet.h>
  9 #include <sys/socket.h>
 10 #include <sys/stat.h>
 11 #include <fcntl.h>
 12 #include <unistd.h>
 13 #include <time.h>
 14 #include <signal.h>
 15 #include <wait.h>
 16 
 17 
 18 #include "server.h"
 19 #include "sem.h"
 20 
 21 #define PATH "/path"
 22 #define SHM_SIZE 4096
 23 #define SHM_KEY 0xbadc0ded
 24 #define AUTH_PORT 24012
 25 #define BUFSIZE 512
 26 
 27 int new_connection(unsigned int addr, int pass, struct sharea* auth_array);
 28 int daemonize();
 29 
 30 int main(int argc, char **argv)
 31 {
 32         if(argc > 1) {
 33                 if((argv[1][0] == 'D')) {
 34                         if((daemonize()) == -1)
 35                                 exit(EXIT_FAILURE);
 36                 }
 37         }
 38         
 39         int                     fd, sockfd, connfd;
 40         unsigned int            sin_size;
 41         struct sockaddr_in      my_addr, remote_addr;
 42         struct sigaction        reap_zombies;
 43 
 44         key_t           key = SHM_KEY;
 45         int             shmid;
 46         struct sharea   *auth_array;
 47 
 48         char            sendbuf[BUFSIZE], recvbuf[BUFSIZE], super_pass[BUFSIZE];        
 49 
 50         fd = open(PATH, O_RDONLY);
 51         if(fd < 0) {
 52                 perror("open");
 53                 exit(EXIT_FAILURE);
 54         }
 55 
 56         if((read(fd, super_pass, BUFSIZE)) < 0) {
 57                 perror("pass");
 58                 exit(EXIT_FAILURE);
 59         }
 60         close(fd);
 61 
 62         /*Set up the shared memory authorization array */
 63 
 64         if((shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0666)) == -1) {
 65                 perror("Shared");
 66                 exit(1);
 67         }
 68         
 69         if((auth_array = shmat(shmid, NULL, 0)) == (void *)-1) {
 70                 perror("Share attach");
 71                 exit(1);
 72         }
 73 
 74         memset(auth_array, 0, sizeof(*auth_array));
 75         
 76         memset(&reap_zombies, 0, sizeof(reap_zombies));
 77         reap_zombies.sa_flags = SA_NOCLDWAIT;
 78 
 79         if((sigaction(SIGCHLD, &reap_zombies, 0)) == -1) {
 80                 perror("Sighandler");
 81                 exit(1);
 82         }
 83         
 84         /* Lets set up the listening socket */
 85 
 86         if((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
 87                 perror("Socket");
 88                 exit(1);
 89         }
 90         my_addr.sin_family = AF_INET;
 91         my_addr.sin_port = htons(AUTH_PORT);
 92         my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
 93         memset(&(my_addr.sin_zero), '\0', 8);
 94 
 95         if((bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))) == -1) {
 96                 perror("Bind");
 97                 exit(1);
 98         }
 99 
100         
101         listen(sockfd, 5);      /* Error checks... nah! */
102         
103         while(1) {
104 
105                 pid_t   pid;
106                 
107                 sin_size = sizeof(struct sockaddr_in);
108                 if((connfd = accept(sockfd, (struct sockaddr*)&remote_addr, &sin_size)) == -1) {
109                         perror("Accept");
110                         exit(1);
111                 }
112                 
113                 pid = fork();
114                 if(pid < 0) {
115                         perror("fork");
116                         exit(EXIT_FAILURE);
117                 }
118                 if(pid > 0) {
119                         close(connfd);
120                         continue;
121                 }               
122                 
123                 strcpy(sendbuf, "Authd login - Send Pass");
124                 send(connfd, sendbuf, strlen(sendbuf), 0);
125                 recv(connfd, recvbuf, BUFSIZE - 1, 0);
126                 recvbuf[BUFSIZE - 1] = '\0';
127                 
128                 if(!new_connection(remote_addr.sin_addr.s_addr, strcmp(recvbuf, super_pass), auth_array)) {
129                         strcpy(sendbuf, "Failed - try again later");
130                         send(connfd, sendbuf, strlen(sendbuf), 0);
131                 }
132                 close(connfd);
133                 exit(EXIT_SUCCESS);
134         }
135 }
136 
137 int new_connection(unsigned int addr, int super, struct sharea *auth_array)
138 {
139         int i, found = 0;
140 
141         /* Insert new entry with correct perms */
142         
143         down(&auth_array->sem);
144         for(i = 0; i < 32; i++) {
145                 if(auth_array->list[i].token == 0) {
146                         found++;
147                         auth_array->list[i].token = addr;
148                         auth_array->list[i].timestamp = time(NULL);
149                         if(super)
150                                 auth_array->list[i].perms = 1;  /* 1 = ordinary user */
151                         break;
152                 }
153                                                 
154         }
155         up(&auth_array->sem);
156 
157         /* Expire old connections */
158         down(&auth_array->sem);
159         for(i = 0; i < 32; i++) {
160                 if((auth_array->list[i].timestamp + 300) < time(NULL)) 
161                         memset(&auth_array->list[i], 0, sizeof(struct auth));
162         }
163         up(&auth_array->sem);
164         
165         return found;
166 }

Code listing (level12.daemon.c)
 1 #include <sys/types.h>
 2 #include <sys/stat.h>
 3 #include <stdio.h>
 4 #include <stdlib.h>
 5 #include <fcntl.h>
 6 #include <errno.h>
 7 #define _GNU_SOURCE
 8 #include <unistd.h>
 9 
10 
11 #define TARGET_UID 1998
12 
13 int daemonize()
14 {
15         int ret = -1;
16 
17         if((daemon(0, 0)) == -1)
18                 return ret;
19 
20         if((setresgid(TARGET_UID, TARGET_UID, TARGET_UID)) == -1)
21                 return ret;
22         if((setresuid(TARGET_UID, TARGET_UID, TARGET_UID)) == -1)
23                 return ret;
24 
25         ret = 0;
26 
27         return ret;
28         
29 }

Code listing (level12.reader.c)
  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 #include <sys/ipc.h>
  5 #include <sys/shm.h>
  6 #include <sys/types.h>
  7 #include <netinet/in.h>
  8 #include <arpa/inet.h>
  9 #include <sys/socket.h>
 10 #include <dirent.h>
 11 #include <unistd.h>
 12 #include <signal.h>
 13 #include <wait.h>
 14 
 15 
 16 #include "server.h"
 17 #include "sem.h"
 18 
 19 #define PATH "/path"
 20 #define SHM_SIZE 4096
 21 #define SHM_KEY 0xbadc0ded
 22 #define AUTH_PORT 24013
 23 #define BUFSIZE 512
 24 
 25 int daemonize();
 26 
 27 void list_dir(int fd)
 28 {
 29         DIR             *dirp;
 30         struct dirent   *dp;
 31                 
 32         if((dirp = opendir(PATH)) == NULL)
 33                         return;
 34         while((dp = readdir(dirp)) != NULL) {
 35                 send(fd, dp->d_name, strlen(dp->d_name), 0);
 36         }
 37         return;
 38 }
 39 
 40 void filedump(const char *name, int fd)
 41 {
 42         FILE            *filp;
 43         char            buf[2048];
 44         int             ret;
 45         
 46         chdir(PATH);
 47         if((filp = fopen(name, "rb")) == NULL) {
 48                 strcpy(buf, "File not found.");
 49                 send(fd, buf, strlen(buf), 0);
 50                 return;
 51         }
 52         do {
 53                 ret = fread(buf, 1, 2048, filp);
 54                 if(ret > 0)
 55                         send(fd, buf, ret, 0);
 56                         send(fd, "\n", 1, 0);
 57         } while(ret >= 2048);
 58 }
 59 
 60 int main(int argc, char **argv)
 61 {
 62 
 63         if(argc > 1) {
 64                 if(argv[1][0] == 'D') {
 65                         if(daemonize())
 66                                 exit(EXIT_SUCCESS);
 67                 }
 68         }
 69         
 70         int                     sockfd, connfd;
 71         unsigned int            sin_size;
 72         struct sockaddr_in      my_addr, remote_addr;
 73 
 74         key_t           key = SHM_KEY;
 75         int             shmid;
 76         struct sharea   *auth_array;
 77         struct sigaction        reap_zombies;
 78         
 79         char            sendbuf[BUFSIZE], recvbuf[BUFSIZE], filename[BUFSIZE];
 80 
 81         /*Set up the shared memory authorization array */
 82 
 83         if((shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0666)) == -1) {
 84                 perror("Shared");
 85                 exit(1);
 86         }
 87 
 88         if((auth_array = shmat(shmid, NULL, 0)) == (void *)-1) {
 89                 perror("Share attach");
 90                 exit(1);
 91         }
 92 
 93         /* Lets set up the listening socket */
 94 
 95         memset(&reap_zombies, 0, sizeof(reap_zombies));
 96         reap_zombies.sa_flags = SA_NOCLDWAIT;
 97 
 98         if((sigaction(SIGCHLD, &reap_zombies, 0)) == -1) {
 99                 perror("Sighandler");
100                 exit(1);
101         }
102 
103         if((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
104                 perror("Socket");
105                 exit(1);
106         }
107         my_addr.sin_family = AF_INET;
108         my_addr.sin_port = htons(AUTH_PORT);
109         my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
110         memset(&(my_addr.sin_zero), '\0', 8);
111 
112         if((bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))) == -1) {
113                 perror("Bind");
114                 exit(1);
115         }
116 
117         listen(sockfd, 5);      /* Error checks... nah! */
118         
119         while(1) {
120 
121                 int i, len, pid, found = 0;
122 
123                 sin_size = sizeof(struct sockaddr_in);
124                 if((connfd = accept(sockfd, (struct sockaddr*)&remote_addr, &sin_size)) == -1) {
125                         perror("Accept");
126                         exit(1);
127                 }
128                 
129                 if((pid = fork()) < 0) {
130                         perror("fork");
131                         exit(EXIT_FAILURE);
132                 }
133                 if(pid) {
134                         close(connfd);
135                         continue;
136                 }
137                 
138                 strcpy(sendbuf, "File Transfer: Enter 'l' for list or type a filename:");
139                 send(connfd, sendbuf, strlen(sendbuf), 0);
140                 len = recv(connfd, recvbuf, BUFSIZE - 1, 0);
141                 
142                 if(len <= 0)
143                         break;
144                 
145                 strncpy(filename, recvbuf, len < BUFSIZE ? len : BUFSIZE);
146                 filename[BUFSIZE - 1] = '\0';
147 
148                 down(&auth_array->sem); /* Take semaphore for reading auth list */
149                 for(i = 0; i < 32; i++) {
150                         if(auth_array->list[i].token == remote_addr.sin_addr.s_addr) {
151                                 found++;
152                                 break;
153                         }
154                 }
155                 up(&auth_array->sem); /* Release semaphore to wait on user replies next... avoid deadlock */
156 
157                 if(!found) {
158                         strcpy(sendbuf, "Not recognized, use authd first.");
159                         send(connfd, sendbuf, strlen(sendbuf), 0);
160                         close(connfd);
161                         continue;
162                 }
163                 
164                 if(filename[0] == 'l') {
165                         list_dir(connfd);
166                 }
167                 else {
168                         strcpy(sendbuf, "Display file? (y/n)");
169                         /*check perm and display file*/
170                         
171                         send(connfd, sendbuf, strlen(sendbuf), 0);
172                         recv(connfd, recvbuf, BUFSIZE - 1, 0);
173                         recvbuf[BUFSIZE - 1] = '\0';
174                         
175                         if(recvbuf[0] == 'y') {
176                                 down(&auth_array->sem);
177                                 if(auth_array->list[i].perms == 0) {/* 0 is superuser, 1 is user */
178                                         filedump(filename, connfd);
179                                 }
180                                 else {
181                                         strcpy(sendbuf, "Not Authorized");
182                                         send(connfd, sendbuf, strlen(sendbuf), 0);
183                                 }
184                                 up(&auth_array->sem);
185                         }
186 
187                 }
188                 close(connfd);
189                 exit(EXIT_SUCCESS);
190         }
191         return 0;
192 }

Code listing (level12.sem.c)
 1 #include <unistd.h>
 2 
 3 
 4 /* Get the semaphore and busy wait if held already */
 5 
 6 void down(int *sem)
 7 {
 8 retry:
 9         while(*sem)
10                 sleep(5);
11         (*sem)++;
12         if(*sem > 1) {
13                 (*sem)--;
14                 goto retry;
15         }
16         return;
17 }
18 
19 /* Try and get the semaphore, but return 0 if held */
20 
21 int try_down(int *sem)
22 {
23         if(*sem)
24                 return 0;
25         (*sem)++;
26         if(*sem > 1) {
27                 (*sem)--;
28                 return 0;
29         }
30         return *sem;
31 }
32 
33 /* Release the semaphore */
34 
35 void up(int *sem)
36 {
37         *sem = 0;
38 }

Code listing (level12.sem.h)
1 int down(int *sem);
2 int try_down(int *sem);
3 void up(int *sem);

Code listing (level12.server.h)
 1 struct auth {
 2         unsigned int    token;
 3         unsigned int    perms;
 4         unsigned int    timestamp;
 5 };
 6 
 7 
 8 struct sharea {
 9         int             sem;
10         unsigned int    bitmap;
11         struct auth     list[32];
12 };