$ ./rce.sh
[+] Checking credentials: Anders Kusk
[+] OSCP Cert loaded
[+] OSCE Cert loaded
[+] Parsing cv.bin
0x00002007: 4461 6e69 7368 2050 6f6c 6963 652c 204f 6666 6963 6572 2020 2020 2020 2020 200a Danish Police, Officer .
0x00002018: 5444 432c 2049 6e74 6572 6e61 6c20 5065 6e74 6573 7465 7220 2020 2020 2020 200a TDC, Internal Pentester .
0x00002019: 496d 7072 6f73 6563 2c20 5365 6375 7269 7479 2041 6476 6973 6f72 2020 2020 200a Improsec, Security Advisor .
[=] Loading externals
-> mutt -s "Hello" a@rce.sh < /dev/null
-> curl -v https://www.linkedin.com/in/anders-kusk
-> curl -v https://github.com/kusk/
-> curl -v https://twitter.com/anderskusk
^C
$ echo return to root
$ cat ./ctf/HackTheBox.eu – Jail.md

HackTheBox.eu – Jail

> 06/01/18

Created by n0decaf

Software used: nmap, gdb, netcat

As always, nmap first.

One http-server running on the standard port, a NFS-server and one weird unknown service running on port 7411. Lets take a look at the http-server first.

Running dirbuster against the http-server gave the folder “jailuser” and the subfolder “dev”. In this folder a binary, a shellscript and some C sourcecode was found. The shellscript compiled the sourcecode and ran it as a service. The sourcecode was the following:

#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <time.h>

int debugmode;
int handle(int sock);
int auth(char *username, char *password);

int auth(char *username, char *password) {
    char userpass[16];
    char *response;
    if (debugmode == 1) {
        printf("Debug: userpass buffer @ %p\n", userpass);
        fflush(stdout);
    }
    if (strcmp(username, "admin") != 0) return 0;
    strcpy(userpass, password);
    if (strcmp(userpass, "1974jailbreak!") == 0) {
        return 1;
    } else {
        printf("Incorrect username and/or password.\n");
        return 0;
    }
    return 0;
}

int handle(int sock) {
int n;
int gotuser = 0;
int gotpass = 0;
char buffer[1024];
char strchr[2] = "\n\x00";
char *token;
char username[256];
char password[256];
debugmode = 0;
memset(buffer, 0, 256);
dup2(sock, STDOUT_FILENO);
dup2(sock, STDERR_FILENO);
printf("OK Ready. Send USER command.\n");
fflush(stdout);

while(1) {
    n = read(sock, buffer, 1024);
    if (n < 0) {
        perror("ERROR reading from socket");
    return 0;
    }
    token = strtok(buffer, strchr);
    while (token != NULL) {
        if (gotuser == 1 && gotpass == 1) {
        break;
    }
    if (strncmp(token, "USER ", 5) == 0) {
        strncpy(username, token+5, sizeof(username));
        gotuser=1;
        if (gotpass == 0) {
            printf("OK Send PASS command.\n");
            fflush(stdout);
        }
    } else if (strncmp(token, "PASS ", 5) == 0) {
        strncpy(password, token+5, sizeof(password));
        gotpass=1;
        if (gotuser == 0) {
            printf("OK Send USER command.\n");
            fflush(stdout);
        }
    } else if (strncmp(token, "DEBUG", 5) == 0) {
        if (debugmode == 0) {
            debugmode = 1;
            printf("OK DEBUG mode on.\n");
            fflush(stdout);
        } else if (debugmode == 1) {
            debugmode = 0;
            printf("OK DEBUG mode off.\n");
            fflush(stdout);
        }
    }
    token = strtok(NULL, strchr);
}
if (gotuser == 1 && gotpass == 1) {
break;
}
}
if (auth(username, password)) {
printf("OK Authentication success. Send command.\n");
fflush(stdout);
n = read(sock, buffer, 1024);
if (n < 0) {
perror("Socket read error");
return 0;
}
if (strncmp(buffer, "OPEN", 4) == 0) {
printf("OK Jail doors opened.");
fflush(stdout);
} else if (strncmp(buffer, "CLOSE", 5) == 0) {
printf("OK Jail doors closed.");
fflush(stdout);
} else {
printf("ERR Invalid command.\n");
fflush(stdout);
return 1;
}
} else {
printf("ERR Authentication failed.\n");
fflush(stdout);
return 0;
}
return 0;
}

int main(int argc, char *argv[]) {
int sockfd;
int newsockfd;
int port;
int clientlen;
char buffer[256];
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
int n;
int pid;
int sockyes;
sockyes = 1;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("Socket error");
exit(1);
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &sockyes, sizeof(int)) == -1) {
perror("Setsockopt error");
exit(1);
}
memset((char*)&server_addr, 0, sizeof(server_addr));
port = 7411;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(port);
if (bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
perror("Bind error");
exit(1);
}
listen(sockfd, 200);
clientlen = sizeof(client_addr);
while (1) {
newsockfd = accept(sockfd, (struct sockaddr*)&client_addr, &clientlen);
if (newsockfd < 0) {
perror("Accept error");
exit(1);
}
pid = fork();
if (pid < 0) {
perror("Fork error");
exit(1);
}
if (pid == 0) {
close(sockfd);
exit(handle(newsockfd));
} else {
close(newsockfd);
}
}
}

Looking at the code, the code at line 21 seem vulnable to buffer overflow since there was no boundary checks.

Check the filetypes showed that the binary was compiled on a 32bit machine.

Connecting to the service showed the userpass buffer location at 0xffffd610. This leak of information was enough to write the following exploit using pwntools.

The exploit in python. A padding of 28 chars was choosen and the EIP-address was set to 0xffffd638. A NOP-slide of 100 to ensure a reasonable big margin to hit. I tested a lot of different shellcodes that didn’t work, but after some help I was provided with a working one, which were a reuse-socket shellcode.

Running the exploit gave me a shell as the user “nobody”. Browsering around showed, that a user called “frank” had the only userdirectory in /home.

Browsering around som more I found two interesting folders with interesting user rights in /var. /var/adm owned by the user adm and /var/nfsshare owned by frank. The nfsshare folder I remembered from looking at the NFS-service. NFS is an old technology that in some situation has some massive security flaws. Since the user frank on Jail is uid 1000, I can create a user on my workstation with same uid, mount the share and write to the folder as frank. This will create a opportunity to upload a binary to /var/nfsshare, give that file setuid rights for all users(including “nobody”). This can potentially give any user the same rights as frank.

First I mounted the nfsshare folder to a local folder.

To retrieve the user-flag I created a small program in C which changed its effective setuid to 1000(frank) and then read and printed the user-flag file. I then compiled it with gcc user.c -o user

Afterwards I created the user frank which automatically were given a uid of 1000. I could then copy my program(user) to the mounted folder as frank. Furthermore I gave setuid rights for all users so the user “nobody” could run the program as the user frank.

Running it gave me the user flag! But to go further we need to escalate from “nobody” to frank. One way is to write my publickey for ssh to /home/frank.ssh/authorized_keys

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
    remove("/home/frank/.ssh/authorized_keys");
    char str[500] = "the public key";
    FILE *fptr;
    fptr = fopen("/home/frank/.ssh/authorized_keys", "w");
    fprintf(fptr,"%s", str);
    fclose(fptr);
    return 0;
}

I wrote the above program in C and again uploaded it to /var/nfsshare, set permissions and executed it with “nobody”.

And then there were no problems ssh’ing directly to Jail as frank.

Checking for sudo rights for the user frank I saw that he is allowed to run rvim(a restricted version of Vim) as the user adm. I then remembered that the folder /var/adm was owned by adm. Could be interesting to use vim/rvim’s filebrowser to view the files in that folder.

Running sudo -u adm /usr/bin/rvim /var/www/html/jailuser/dev/jail.c and then using the builtin filebrowser with :e /var/adm/ gave me access to the folder as the user “adm”. In the folder the files keys.rar(password protected, saved by opening it and typing :w /tmp/keys.rar), the textfile note.txt and in the folder “.local” another textfile called “.frank” was found.

“note.txt” contained a short description.

In the /var/adm/.keys/.local/ there file “.frank” was found. It contained what looked like a simple substition cipher which could be solved by using quipqiup.com. So I ended up with the following sentence: “Hahaha! Nobody will quess my new password! Only a few lucky souls have Escaped from Alcatraz alive like I did!!”

Since I visited Alcatraz a couple of months ago the first part, “Morris”, of the password was easy to guess. I could have bruteforced the rest, but a single guess got as “Morris1962!”. Using that with unrar extracted a public RSA-key.

Looking at the publickey showed that it was pretty short and therefore maybe could be cracked using rsactftool. And that turned out to be true. So by rsactftool I was able to create a private key and use it to login as root and grab the root flag. Finally!