Semtex 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!
semtex12.authd.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <dirent.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include "server.h"
#include "sem.h"
#define PATH "/path"
#define SHM_SIZE 4096
#define SHM_KEY 0xbadc0ded
#define AUTH_PORT 24012
#define BUFSIZE 512
#define super_pass "insert-your-semtex11-password-here"
int new_connection(unsigned int addr, int super, struct sharea *auth_array);
int main(int argc, char **argv)
{
int sockfd, connfd;
unsigned int sin_size;
struct sockaddr_in my_addr, remote_addr;
key_t key = SHM_KEY;
int shmid;
struct sharea *auth_array;
struct sigaction reap_zombies;
char sendbuf[BUFSIZE], recvbuf[BUFSIZE];
/*Set up the shared memory authorization array */
if((shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0666)) == -1) {
perror("Shared");
exit(1);
}
if((auth_array = shmat(shmid, NULL, 0)) == (void *)-1) {
perror("Share attach");
exit(1);
}
memset(auth_array, 0, sizeof(*auth_array));
memset(&reap_zombies, 0, sizeof(reap_zombies));
reap_zombies.sa_flags = SA_NOCLDWAIT;
if((sigaction(SIGCHLD, &reap_zombies, 0)) == -1) {
perror("Sighandler");
exit(1);
}
/* Lets set up the listening socket */
if((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
perror("Socket");
exit(1);
}
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(AUTH_PORT);
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
memset(&(my_addr.sin_zero), '\0', 8);
if((bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))) == -1) {
perror("Bind");
exit(1);
}
listen(sockfd, 5); /* Error checks... nah! */
while(1) {
pid_t pid;
sin_size = sizeof(struct sockaddr_in);
if((connfd = accept(sockfd, (struct sockaddr*)&remote_addr, &sin_size)) == -1) {
perror("Accept");
exit(1);
}
pid = fork();
if(pid < 0) {
perror("fork");
exit(EXIT_FAILURE);
}
if(pid > 0) {
close(connfd);
continue;
}
strcpy(sendbuf, "Authd login - Send Pass");
send(connfd, sendbuf, strlen(sendbuf), 0);
recv(connfd, recvbuf, BUFSIZE - 1, 0);
recvbuf[BUFSIZE - 1] = '\0';
if(!new_connection(remote_addr.sin_addr.s_addr, strcmp(recvbuf, super_pass), auth_array)) {
strcpy(sendbuf, "Failed - try again later");
send(connfd, sendbuf, strlen(sendbuf), 0);
}
close(connfd);
exit(EXIT_SUCCESS);
}
}
int new_connection(unsigned int addr, int super, struct sharea *auth_array)
{
int i, found = 0;
/* Insert new entry with correct perms */
down(&auth_array->sem);
for(i = 0; i < 32; i++) {
if(auth_array->list[i].token == 0) {
found++;
auth_array->list[i].token = addr;
auth_array->list[i].timestamp = time(NULL);
if(super)
auth_array->list[i].perms = 1; /* 1 = ordinary user */
break;
}
}
up(&auth_array->sem);
/* Expire old connections */
down(&auth_array->sem);
for(i = 0; i < 32; i++) {
if((auth_array->list[i].timestamp + 300) < time(NULL))
memset(&auth_array->list[i], 0, sizeof(struct auth));
}
up(&auth_array->sem);
return found;
} semtex12.daemon.c
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#define _GNU_SOURCE
#include <unistd.h>
#define TARGET_UID 1998
int daemonize()
{
int ret = -1;
if((daemon(0, 0)) == -1)
return ret;
if((setresgid(TARGET_UID, TARGET_UID, TARGET_UID)) == -1)
return ret;
if((setresuid(TARGET_UID, TARGET_UID, TARGET_UID)) == -1)
return ret;
ret = 0;
return ret;
} semtex12.reader.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <dirent.h>
#include <unistd.h>
#include <signal.h>
#include <wait.h>
#include "server.h"
#include "sem.h"
#define PATH "/path"
#define SHM_SIZE 4096
#define SHM_KEY 0xbadc0ded
#define AUTH_PORT 24013
#define BUFSIZE 512
int daemonize();
void list_dir(int fd)
{
DIR *dirp;
struct dirent *dp;
if((dirp = opendir(PATH)) == NULL)
return;
while((dp = readdir(dirp)) != NULL) {
send(fd, dp->d_name, strlen(dp->d_name), 0);
}
return;
}
void filedump(const char *name, int fd)
{
FILE *filp;
char buf[2048];
int ret;
chdir(PATH);
if((filp = fopen(name, "rb")) == NULL) {
strcpy(buf, "File not found.");
send(fd, buf, strlen(buf), 0);
return;
}
do {
ret = fread(buf, 1, 2048, filp);
if(ret > 0)
send(fd, buf, ret, 0);
send(fd, "\n", 1, 0);
} while(ret >= 2048);
}
int main(int argc, char **argv)
{
if(argc > 1) {
if(argv[1][0] == 'D') {
if(daemonize())
exit(EXIT_SUCCESS);
}
}
int sockfd, connfd;
unsigned int sin_size;
struct sockaddr_in my_addr, remote_addr;
key_t key = SHM_KEY;
int shmid;
struct sharea *auth_array;
struct sigaction reap_zombies;
char sendbuf[BUFSIZE], recvbuf[BUFSIZE], filename[BUFSIZE];
/*Set up the shared memory authorization array */
if((shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0666)) == -1) {
perror("Shared");
exit(1);
}
if((auth_array = shmat(shmid, NULL, 0)) == (void *)-1) {
perror("Share attach");
exit(1);
}
/* Lets set up the listening socket */
memset(&reap_zombies, 0, sizeof(reap_zombies));
reap_zombies.sa_flags = SA_NOCLDWAIT;
if((sigaction(SIGCHLD, &reap_zombies, 0)) == -1) {
perror("Sighandler");
exit(1);
}
if((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
perror("Socket");
exit(1);
}
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(AUTH_PORT);
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
memset(&(my_addr.sin_zero), '\0', 8);
if((bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))) == -1) {
perror("Bind");
exit(1);
}
listen(sockfd, 5); /* Error checks... nah! */
while(1) {
int i, len, pid, found = 0;
sin_size = sizeof(struct sockaddr_in);
if((connfd = accept(sockfd, (struct sockaddr*)&remote_addr, &sin_size)) == -1) {
perror("Accept");
exit(1);
}
if((pid = fork()) < 0) {
perror("fork");
exit(EXIT_FAILURE);
}
if(pid) {
close(connfd);
continue;
}
strcpy(sendbuf, "File Transfer: Enter 'l' for list or type a filename:");
send(connfd, sendbuf, strlen(sendbuf), 0);
len = recv(connfd, recvbuf, BUFSIZE - 1, 0);
if(len <= 0)
break;
strncpy(filename, recvbuf, len < BUFSIZE ? len : BUFSIZE);
filename[BUFSIZE - 1] = '\0';
down(&auth_array->sem); /* Take semaphore for reading auth list */
for(i = 0; i < 32; i++) {
if(auth_array->list[i].token == remote_addr.sin_addr.s_addr) {
found++;
break;
}
}
up(&auth_array->sem); /* Release semaphore to wait on user replies next... avoid deadlock */
if(!found) {
strcpy(sendbuf, "Not recognized, use authd first.");
send(connfd, sendbuf, strlen(sendbuf), 0);
close(connfd);
continue;
}
if(filename[0] == 'l') {
list_dir(connfd);
}
else {
strcpy(sendbuf, "Display file? (y/n)");
/*check perm and display file*/
send(connfd, sendbuf, strlen(sendbuf), 0);
recv(connfd, recvbuf, BUFSIZE - 1, 0);
recvbuf[BUFSIZE - 1] = '\0';
if(recvbuf[0] == 'y') {
down(&auth_array->sem);
if(auth_array->list[i].perms == 0) {/* 0 is superuser, 1 is user */
filedump(filename, connfd);
}
else {
strcpy(sendbuf, "Insufficient permissions.");
send(connfd, sendbuf, strlen(sendbuf), 0);
}
up(&auth_array->sem);
}
}
close(connfd);
exit(EXIT_SUCCESS);
}
} semtex12.sem.c
#include <unistd.h>
/* Get the semaphore and busy wait if held already */
void down(int *sem)
{
retry:
while(*sem)
sleep(5);
(*sem)++;
if(*sem > 1) {
(*sem)--;
goto retry;
}
return;
}
/* Try and get the semaphore, but return 0 if held */
int try_down(int *sem)
{
if(*sem)
return 0;
(*sem)++;
if(*sem > 1) {
(*sem)--;
return 0;
}
return *sem;
}
/* Release the semaphore */
void up(int *sem)
{
*sem = 0;
} semtex12.sem.h
int down(int *sem);
int try_down(int *sem);
void up(int *sem); semtex12.server.h
struct auth {
unsigned int token;
unsigned int perms;
unsigned int timestamp;
};
struct sharea {
int sem;
unsigned int bitmap;
struct auth list[32];
};