General Tips

Core Tools to Know: ffuf

ffuf run logo version, from the GitHub Repoffuf (“Fuzz Faster U Fool”) is a powerful, open-source tool designed for web application enumeration and fuzzing. Whether you’re performing vhost, directory, page, or parameter enumeration, ffuf can help you identify and exploit vulnerabilities effectively. In this overview tutorial, we’ll cover how to install ffuf and use it for various enumeration tasks. Right off the bat, I want to stress that you should never run tools like ffuf against any machine, network, system, etc that you either don’t own and control or have explicit permission to run these sorts of programs on. If you venture outside of that boundary, you get in pretty murky legal territory and I’m officially suggesting that you don’t do that.

Installing ffuf

Before diving into its usage, let’s install ffuf on your system. ffuf works on Linux, macOS, and Windows. According to the ffuf room on TryHackMe, ffuf is already included in the following Linux distributions: BlackArch, Pentoo, Kali, and Parrot. If you’re on Windows, macOS, or a Linux version without ffuf preinstalled, the easiest thing to do is download one of the prebuilt releases from ffuf’s GitHub. If you want to install ffuf from source, you’ll need to install Go 1.16 (or higher) and follow the instructions on ffuf’s readme on their GitHub.

Once you’re sure you’ve got the program, let’s dig in. We can make sure that ffuf is in our path by running the following command and getting the help menu in response. If it fails and you’re sure that you’ve got it installed, add its location to your path, or use the fully qualified path when calling it from the command line (like /opt/ffuf/ffuf or c:\Tools\ffuf.exe instead of just ffuf).

So How Does it Work?

Let’s take a look at the built-in help to understand what all it can do. Like many security tools, ffuf is command-line only, so pop open a terminal and issue the following command (the output is really long, feel free to skim it or just scroll past this block to not be overwhelmed).

$ ffuf -h
Fuzz Faster U Fool - v2.1.0-dev

HTTP OPTIONS:
  -H                  Header `"Name: Value"`, separated by colon. Multiple -H flags are accepted.
  -X                  HTTP method to use
  -b                  Cookie data `"NAME1=VALUE1; NAME2=VALUE2"` for copy as curl functionality.
  -cc                 Client cert for authentication. Client key needs to be defined as well for this to work
  -ck                 Client key for authentication. Client certificate needs to be defined as well for this to work
  -d                  POST data
  -http2              Use HTTP2 protocol (default: false)
  -ignore-body        Do not fetch the response content. (default: false)
  -r                  Follow redirects (default: false)
  -raw                Do not encode URI (default: false)
  -recursion          Scan recursively. Only FUZZ keyword is supported, and URL (-u) has to end in it. (default: false)
  -recursion-depth    Maximum recursion depth. (default: 0)
  -recursion-strategy Recursion strategy: "default" for a redirect based, and "greedy" to recurse on all matches (default: default)
  -replay-proxy       Replay matched requests using this proxy.
  -sni                Target TLS SNI, does not support FUZZ keyword
  -timeout            HTTP request timeout in seconds. (default: 10)
  -u                  Target URL
  -x                  Proxy URL (SOCKS5 or HTTP). For example: http://127.0.0.1:8080 or socks5://127.0.0.1:8080

GENERAL OPTIONS:
  -V                  Show version information. (default: false)
  -ac                 Automatically calibrate filtering options (default: false)
  -acc                Custom auto-calibration string. Can be used multiple times. Implies -ac
  -ach                Per host autocalibration (default: false)
  -ack                Autocalibration keyword (default: FUZZ)
  -acs                Custom auto-calibration strategies. Can be used multiple times. Implies -ac
  -c                  Colorize output. (default: false)
  -config             Load configuration from a file
  -json               JSON output, printing newline-delimited JSON records (default: false)
  -maxtime            Maximum running time in seconds for entire process. (default: 0)
  -maxtime-job        Maximum running time in seconds per job. (default: 0)
  -noninteractive     Disable the interactive console functionality (default: false)
  -p                  Seconds of `delay` between requests, or a range of random delay. For example "0.1" or "0.1-2.0"
  -rate               Rate of requests per second (default: 0)
  -s                  Do not print additional information (silent mode) (default: false)
  -sa                 Stop on all error cases. Implies -sf and -se. (default: false)
  -scraperfile        Custom scraper file path
  -scrapers           Active scraper groups (default: all)
  -se                 Stop on spurious errors (default: false)
  -search             Search for a FFUFHASH payload from ffuf history
  -sf                 Stop when > 95% of responses return 403 Forbidden (default: false)
  -t                  Number of concurrent threads. (default: 40)
  -v                  Verbose output, printing full URL and redirect location (if any) with the results. (default: false)

MATCHER OPTIONS:
  -mc                 Match HTTP status codes, or "all" for everything. (default: 200-299,301,302,307,401,403,405,500)
  -ml                 Match amount of lines in response
  -mmode              Matcher set operator. Either of: and, or (default: or)
  -mr                 Match regexp
  -ms                 Match HTTP response size
  -mt                 Match how many milliseconds to the first response byte, either greater or less than. EG: >100 or <100
  -mw                 Match amount of words in response

FILTER OPTIONS:
  -fc                 Filter HTTP status codes from response. Comma separated list of codes and ranges
  -fl                 Filter by amount of lines in response. Comma separated list of line counts and ranges
  -fmode              Filter set operator. Either of: and, or (default: or)
  -fr                 Filter regexp
  -fs                 Filter HTTP response size. Comma separated list of sizes and ranges
  -ft                 Filter by number of milliseconds to the first response byte, either greater or less than. EG: >100 or <100
  -fw                 Filter by amount of words in response. Comma separated list of word counts and ranges

INPUT OPTIONS:
  -D                  DirSearch wordlist compatibility mode. Used in conjunction with -e flag. (default: false)
  -e                  Comma separated list of extensions. Extends FUZZ keyword.
  -enc                Encoders for keywords, eg. 'FUZZ:urlencode b64encode'
  -ic                 Ignore wordlist comments (default: false)
  -input-cmd          Command producing the input. --input-num is required when using this input method. Overrides -w.
  -input-num          Number of inputs to test. Used in conjunction with --input-cmd. (default: 100)
  -input-shell        Shell to be used for running command
  -mode               Multi-wordlist operation mode. Available modes: clusterbomb, pitchfork, sniper (default: clusterbomb)
  -request            File containing the raw http request
  -request-proto      Protocol to use along with raw request (default: https)
  -w                  Wordlist file path and (optional) keyword separated by colon. eg. '/path/to/wordlist:KEYWORD'

OUTPUT OPTIONS:
  -debug-log          Write all of the internal logging to the specified file.
  -o                  Write output to file
  -od                 Directory path to store matched results to.
  -of                 Output file format. Available formats: json, ejson, html, md, csv, ecsv (or, 'all' for all formats) (default: json)
  -or                 Don't create the output file if we don't have results (default: false)

EXAMPLE USAGE:
  Fuzz file paths from wordlist.txt, match all responses but filter out those with content-size 42.
  Colored, verbose output.
    ffuf -w wordlist.txt -u https://example.org/FUZZ -mc all -fs 42 -c -v

  Fuzz Host-header, match HTTP 200 responses.
    ffuf -w hosts.txt -u https://example.org/ -H "Host: FUZZ" -mc 200

  Fuzz POST JSON data. Match all responses not containing text "error".
    ffuf -w entries.txt -u https://example.org/ -X POST -H "Content-Type: application/json" \
      -d '{"name": "FUZZ", "anotherkey": "anothervalue"}' -fr "error"

  Fuzz multiple locations. Match only responses reflecting the value of "VAL" keyword. Colored.
    ffuf -w params.txt:PARAM -w values.txt:VAL -u https://example.org/?PARAM=VAL -mr "VAL" -c

  More information and examples: https://github.com/ffuf/ffuf

That's quite a bit and everything that's there is what is output. Fortunately, you don't often need all of that. I'm going to go over some of the biggest use cases that you're likely to encounter. Honestly, anything that you can think of swapping out just one part of for another part works great, but these are the highlights.

Using ffuf for Enumeration

Vhost Enumeration

Virtual host (vhost) enumeration is essential for identifying additional subdomains or services hosted on the same server. Public servers can be discovered by DNS queries, but if you're fuzzing an internal application that you may not have access to full DNS, this is great.

I set up a stupid little node script to be a simple web server to work out some of these examples. So, some may seem a little contrived, but I also wanted to respect the rule about not fuzzing where you aren't supposed to. Also, ffuf is verbose when providing output (banner, parameter restatement, etc) and I will show it the first time, but subsequent samples will omit it. Just know that you'll see the banner et al every time when you're using the tool.

Our command is ffuf -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt -u http://ffuf.hack:8000 -H "Host: FUZZ.ffuf.hack"

In this case, -w represents the wordlist to use when fuzzing. -u is the URL to hit (I just put ffuf.hack in my /etc/hosts pointed at my local machine), and -H is the HTTP header to send along, in this case, the Host that I'm trying to hit. Note that I put FUZZ in the spot where I'd like each word from the wordlist to go: foo.ffuf.hack, bar.ffuf.hack, baz.ffuf.hack, etc.

$ ffuf -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt -u http://ffuf.hack:8000 -H "Host: FUZZ.ffuf.hack"

        /'___\  /'___\           /'___\
       /\ \__/ /\ \__/  __  __  /\ \__/
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
         \ \_\   \ \_\  \ \____/  \ \_\
          \/_/    \/_/   \/___/    \/_/

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://ffuf.hack:8000
 :: Wordlist         : FUZZ: /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt
 :: Header           : Host: FUZZ.ffuf.hack
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________

ns1                     [Status: 403, Size: 23, Words: 3, Lines: 1, Duration: 6ms]
mail                    [Status: 403, Size: 23, Words: 3, Lines: 1, Duration: 7ms]
// ****** SNIP ******
support                 [Status: 403, Size: 23, Words: 3, Lines: 1, Duration: 5ms]

I hit control-c here to break since we have our file size. One of the first tricks to learn about ffuf is to realize what it is going to consider a success or failure. You can see from the "Matcher" section that it will accept any of those response codes. For instance, 400 and 404 won't be returned. You can add additional codes or you can limit by file size (this version is the majority of the time for me). I snipped some out, but you can see that every negative response is 23 bytes. So, I then reissued the command with -fs 23 to filter size of 23 bytes and got the correct results. I left part of the header in this time so you can see that the response codes were the same, but a Filter was added for Response size.

$ ffuf -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt -u http://ffuf.hack:8000 -H "Host: FUZZ.ffuf.hack" -fs 23

 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
 :: Filter           : Response size: 23
________________________________________________

www                     [Status: 200, Size: 103732, Words: 14137, Lines: 948, Duration: 27ms]
lms                     [Status: 200, Size: 103732, Words: 14137, Lines: 948, Duration: 9ms]
:: Progress: [4989/4989] :: Job [1/1] :: 0 req/sec :: Duration: [0:00:00] :: Errors: 0 ::

This is the correct result. I had set up my script to serve pages based on going to either ffuf.hack, www.ffuf.hack, or lms.ffuf.hack.

Directory Enumeration

Directory enumeration uncovers hidden directories on a web server. This one is even a more important use case for fuzzing, since there is nothing like DNS to otherwise find these directories. There are no new surprises with flags, just where I moved the FUZZ position to be replaced. I already knew the file size for a bad request and confirmed it, so that's included here right off the bat, too. In regular situations, you likely wouldn't even need the -H flag, but I'm using a janky simple web server script that I didn't want to keep changing, so I had to tag the Host header along, too. I'm also just enumerating the ffuf.hack domain itself, not any of the other vhosts. I am using a different word list, too. The correct wordlist to use is more art than science. You kind of get a feel for it, or you'll build up some favorites that always come through for you. All of the lists that I'm using come in the base Kali Linux install that I'm using.

$ ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-small-words-lowercase.txt -u http://ffuf.hack:8000/FUZZ -H "Host: ffuf.hack" -fs 23

________________________________________________

images                  [Status: 500, Size: 25, Words: 4, Lines: 1, Duration: 38ms]
.                       [Status: 500, Size: 25, Words: 4, Lines: 1, Duration: 26ms]
:: Progress: [38267/38267] :: Job [1/1] :: 3846 req/sec :: Duration: [0:00:10] :: Errors: 0 ::

In this case, this is also correct. I only made one directory in this pretend website and it was /images. If this was a penetration test, we'd probably wonder if the list was bad depending on what kind of site this was and how complex it seemed to be.

Page Enumeration

Page enumeration targets specific files or pages on the server. In this case, we use the -e flag (extension) and give it a comma-separated list of extensions for ffuf to tack onto our list. Here, I'm telling it to try .html, .jpg, and .js. I left the new part of the header in to show that ffuf has correctly understood what we're doing. Here, I used the same word list that I used for the directory enumeration.

$ ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-small-words-lowercase.txt -u http://ffuf.hack:8000/FUZZ -H "Host: ffuf.hack" -e ".html,.jpg,.js" -fs 23

 :: Extensions       : .html .jpg .js
________________________________________________

images                  [Status: 500, Size: 25, Words: 4, Lines: 1, Duration: 31ms]
index.html              [Status: 200, Size: 103732, Words: 14137, Lines: 948, Duration: 27ms]
main.js                 [Status: 200, Size: 59, Words: 8, Lines: 3, Duration: 22ms]
.                       [Status: 500, Size: 25, Words: 4, Lines: 1, Duration: 21ms]
server.js               [Status: 200, Size: 2294, Words: 594, Lines: 70, Duration: 30ms]
:: Progress: [153068/153068] :: Job [1/1] :: 4878 req/sec :: Duration: [0:00:41] :: Errors: 0 ::

Again, this is all correct. In fact, because I don't have this set up like a real node app or anything, it also found my server.js web server script. In a penetration test, if you could download this, you could read the source code for the application. It would be a huge finding as it should be excluded by web server configuration or by the way the application is set up.

Parameter Enumeration

Parameter enumeration identifies potential GET or POST parameters. ffuf can be used to find both parameter names and values. Which one you are trying to isolate depends on where you put the FUZZ. I'll show two examples here, first where I FUZZ where the parameter name is (with a junk value) and then fuzzing the values once I've identified the names. In this case, I'm fuzzing GET parameters. If you were fuzzing POST parameters, you'd just have the -u url be normal, and include a new flag of -d (data) like -d "param1=FUZZ" and then also add -X POST to the command for POST parameter fuzzing.

$ ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-small-words-lowercase.txt -H "Host: www.ffuf.hack" -u "http://ffuf.hack:8000/?FUZZ=foobar"
________________________________________________

first                   [Status: 200, Size: 119, Words: 20, Lines: 1, Duration: 12ms]
username                [Status: 200, Size: 119, Words: 20, Lines: 1, Duration: 8ms]
:: Progress: [38267/38267] :: Job [1/1] :: 904 req/sec :: Duration: [0:00:47] :: Errors: 0 ::

In this value fuzzing example, I made a short list to try it out. When fuzzing parameter values, you'll almost always want to have a "smart list" that you use. That could just be a list of numbers (like fuzzing an id parameter), a list of known usernames, a list of LFI escapes, etc. So in my case, I made a list of 14 values that would make sense to try to hack into an app written by the egotistical author of this blog 😉

// First Parameter Value Fuzzing
$ ffuf -w curated_values.txt -H "Host: www.ffuf.hack" -u "http://ffuf.hack:8000?username=FUZZ"
________________________________________________

peteonsoftware          [Status: 200, Size: 52, Words: 7, Lines: 1, Duration: 11ms]
:: Progress: [14/14] :: Job [1/1] :: 0 req/sec :: Duration: [0:00:00] :: Errors: 0 ::
// Second Parameter Value Fuzzing
$ ffuf -w curated_values.txt -H "Host: www.ffuf.hack" -u "http://ffuf.hack:8000?first=FUZZ"
________________________________________________

pete                    [Status: 200, Size: 42, Words: 7, Lines: 1, Duration: 10ms]
:: Progress: [14/14] :: Job [1/1] :: 0 req/sec :: Duration: [0:00:00] :: Errors: 0 ::

So ffuf identified that my application takes two parameters: username and first. Valid values for username seem to only be peteonsoftware and the only valid value for the first parameter is pete. I can confirm that that's correct.

Parting Tips

If you don't care about how "loud" you are, you can increase how many threads that ffuf uses to bang on the server with -t. Also, if you're fuzzing an https URL and there are certificate issues, you use use -k to ignore the certificate problems.

As I touched on earlier, wordlists are key here, just like they are for password cracking and just about everything else. Daniel Miessler's SecLists can be a good place to get started.

Lastly, you are basically only limited by your imagination when using ffuf. If you can think of a creative way to build a request where you isolate one piece to constantly be replaced, you can use ffuf to do it. This overview only just gets you started. A good next place to go might be the TryHackMe ffuf room. It is a free room and anyone can do it (you don't have to have a paid subscription!). While I've had a paid subscription to TryHackMe for about a year and a half, they offer a ton of content for free and it is worth checking out!

Happy Fuzzing!

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.

Offensive Security

What are Cryptographic Hashes?

Frying PotatoesThis post is the first of three posts that I have planned in a little mini-series. I want to post about What are Cryptographic Hashes?, then Identifying Hashes, and finally Cracking Hashes.

So, what is a Cryptographic Hash? At its core, a cryptographic hash function is a mathematical algorithm that takes an input and returns a fixed-size string of characters, which is typically a hexadecimal number. The output is called a hash or digest. Cryptographic hash functions are designed to be secure and resistant to tampering, which makes them highly useful in a variety of security-related contexts. The key features of cryptographic hashes are:

  1. Deterministic: The same input will always produce the same hash.
  2. Fixed Length: Regardless of the size of the input, the hash produced will always be of a fixed size (e.g., SHA-256 always produces a 256-bit hash).
  3. Efficient: Computing the hash for any input is relatively fast.
  4. Pre-image Resistance: It should be computationally infeasible to reverse the process and determine the original input from the hash.
  5. Collision Resistance: Two different inputs should not produce the same hash.
  6. Avalanche Effect: Even a small change to the input should drastically change the output hash.

That Avalanche Effect part is actually really important and easier to understand with a demonstration. If a hashing of similar words resulted in similar hashes, you could actually figure out the original message very easily as you got closer and closer. Instead, abcd, abcdd, abcdD, and abcde actually hash to wildly different SHA256 Hashes, for example. Pretty smart, I think.

$ echo "abcd" | sha256sum
fc4b5fd6816f75a7c81fc8eaa9499d6a299bd803397166e8c4cf9280b801d62c

$ echo "abcdd" | sha256sum
2fc0920b01e12a239cac49f999c641dafaa841da88428c08632ec1fa9860920f

$ echo "abcdD" | sha256sum
f71367ae3183ad102b186748aba1a2132c73168b79a3e2612199f2d74ae9d9b0

$ echo "abcde" | sha256sum
0283da60063abfb3a87f1aed845d17fe2d9ba8c780b478dc4ae048f5ee97a6d5

Where do we use Cryptographic Hashes? Well, I’m writing about this under the banner of Offensive Security, so some logical guesses could be made. One thing they are used for is for storing passwords. Instead of storing the passwords directly in a database or even storing an encrypted version that can be decrypted, it is a good practice to store a Cryptographic Hash. Then when someone tries to log in, you hash the input and then compare the hashes. That way, the passwords are harder to determine from the hash alone. Another use is for data integrity. If a hash is taken of a file or a message and that hash is published, you can confirm that you have the exact same file or message by calculating the hash yourself and comparing.

What are the dangers here? Why are there so many kinds of hashes? Well – like a lot of things – this is actually a hard problem. If the hash algorithm isn’t very good, it could have collisions. That means two or more messages hash to the same value, so if apple and orange both hash to ABCDEF and ABCDEF is stored in the database as the password hash, then providing either a password of apple or orange at login would let you in. That’s not great. Also, if it is possible for multiple inputs to have the same output, then a file with a hash of AAABBBCCC is published, but someone also makes a version of a file full of viruses that also hashes out to AAABBBCCC, then we’ve lost trust in the process.

Here are just four examples of hash algorithms that had been trusted, but aren’t anymore.

MD4 (Message Digest Algorithm 4)
Discovered Collisions: Yes (1995)
Details: MD4 is an earlier version of MD5 and was found to be insecure in the mid-1990s. Collisions were discovered in MD4 as early as 1995, and since then, the hash function has been considered broken and insecure. MD4 was eventually replaced by more secure algorithms like SHA and MD5, though MD5 also suffered from its own weaknesses.
Examples: MD4 is largely obsolete but might still be found in legacy systems.

MD5 (Message Digest Algorithm 5)
Discovered Collisions: Yes (2004)
Details: MD5 is one of the most famous cryptographic hash functions with widely known collisions. It produces a 128-bit hash value. In 2004, researchers demonstrated a practical method to find collisions in MD5. Since then, the hash function has been considered broken and unsuitable for security purposes like digital signatures and certificates.
Examples: In 2008, an attack was demonstrated that allowed attackers to create a rogue Certificate Authority (CA) certificate, which undermined the trust model of SSL certificates.

SHA-0 (Secure Hash Algorithm 0)
Discovered Collisions: Yes (2004)
Details: SHA-0 is the predecessor of SHA-1 and was withdrawn from use due to its vulnerability to collisions. Researchers found theoretical weaknesses, and in 2004, they were able to demonstrate actual collisions in the function. As a result, SHA-0 was deprecated early in its life.
Examples: SHA-0 is no longer used in any modern cryptographic system due to these vulnerabilities.

SHA-1 (Secure Hash Algorithm 1)
Discovered Collisions: Yes (2017)
Details: SHA-1, which produces a 160-bit hash value, was long considered secure but began to show theoretical weaknesses in the early 2000s. In 2017, Google and the CWI Institute in Amsterdam successfully generated a practical collision using the “SHAttered” attack. This discovery showed that SHA-1 was vulnerable to collision attacks and should no longer be used in critical security applications.
Examples: SHA-1 has been deprecated for use in SSL certificates, and major browsers no longer accept SHA-1-signed certificates.

Understanding these foundational concepts is critical as we move forward in our offensive security series. In our next post, we will dive into how to identify a hash you find in the wild—whether it’s from a password dump, a malware sample, or part of an intercepted communication.

General Tips

Core Tools to Know: CyberChef

CyberChef LogoLast month, I started a series about tools and utilities that are good to know with a post about curl. In my most recent CTF post, I had to use CyberChef to help me with one of my steps. That post was already going to be very long, so I didn’t have a lot of time to explain what CyberChef was or how it worked if a reader was unfamiliar. It did, however, seem like a good topic for my next “Core Tools to Know” post, so here we are.

As some background, CyberChef was created by an anonymous worker at GCHQ (Government Communications Headquarters) in England. GCHQ is an intelligence agency and is the current version of the organization (then called GC&CS) that was at Bletchley Park and broke the Enigma Codes. So.. smart folks. Like a lot of high-tech places, GCHQ gives their employees 10% “Innovation Time” and this worker created this tool during that time. They shared it with their colleagues and eventually decided to open source it on GitHub for the world to benefit. So what is it? Let’s take a look.

The CyberChef UI

There is a lot going on here, but think of it like a factory or assembly line. In the upper right is where you put the input to the process. In the bottom right is the output. The center column is where you drag the “recipes”, which are the operations that you are going to conduct on the input. The left side shows all of the available recipes/operations that you can choose from. In the upper left is a search box to help you easily find what you were looking for. Let’s say you came across this string: UGV0ZSBvbiBTb2Z0d2FyZQ%3D%3D. If you recognize the end as looking to be URL encoded, let’s set up CyberChef to try to handle it. First, I put UGV0ZSBvbiBTb2Z0d2FyZQ%3D%3D in the input. It will immediately appear – unchanged – in the output because “Auto Bake” is selected at the bottom of the center column. If it isn’t, either check it or click Bake! to see something in the output. Next, let’s search for URL Decode in the search box and drag URL Decode to the Recipe column. After baking, you see that the output now says UGV0ZSBvbiBTb2Z0d2FyZQ== because each %3D was converted to an =. We now see that this looks like a base64 string.

Our input with the URL Decode Recipe Only

What is interesting is that CyberChef figured that out, too! You’ll notice that a magic wand appeared by the Output header and if you hover on it, it tells you that this is a Base64 string and what the decoding is.

Output Magic Suggestion

If you click it, it adds From Base64 to the recipe and our output now shows Pete on Software.

Our decoded string

It is important to note that order matters. You can drag the recipe steps up and down to perform them in a different order. If I From Base64 first and URL Decode second, we don’t get the exact right answer. If this was a more complicated recipe, small errors get compounded and might make this fail entirely.

Recipe Order Matters

As we move forward, it is important to note that you can remove a recipe step by either clicking and dragging it to the trash can in the upper right portion of the Recipe column, or by clicking the ⊘ on the operation. That will disable it. Clicking that symbol again will re-enable it.

By now, you can imagine all of the things you can do to text. CyberChef has encryption, hashing, encoding, and much, much more. However, you aren’t limited to text. You can perform network operations and even operate on Files. If you don’t enter text in the Input section, you have other options for input. If you hover on each of the icons, you can see that you can also open a Folder or a File as input.

CyberChef Input Options

I’m going to use CyberChef to remove EXIF data from an image of a moped. To start, here is the EXIF data that is on the image.

$ exif moped.jpg
EXIF tags in 'moped.jpg' ('Motorola' byte order):
--------------------+----------------------------------------------------------
Tag                 |Value
--------------------+----------------------------------------------------------
X-Resolution        |72
Y-Resolution        |72
Resolution Unit     |Inch
Date and Time (Origi|2018:11:08 19:49:33
User Comment        |Screenshot
Pixel X Dimension   |640
Pixel Y Dimension   |641
Exif Version        |Exif Version 2.1
FlashPixVersion     |FlashPix Version 1.0
Color Space         |Internal error (unknown value 65535)
--------------------+----------------------------------------------------------

I selected my file as input, added the Remove EXIF operation to the Recipe, made sure it Baked and I have file data in the output. If you click the Floppy Disk icon, you can save that output to a file. (Note: CyberChef didn’t blur the image. I did for privacy reasons)

CyberChef Remove EXIF Save File

$ exif moped_cyberchef.jpg
Corrupt data
The data provided does not follow the specification.
ExifLoader: The data supplied does not seem to contain EXIF data.

I will note that I was using a Linux utility to read that EXIF data, but CyberChef could have read the data in the first place. There is an Extract EXIF operation that you can add to the recipe.

As we wrap up, there are some things to consider. First, CyberChef is a client-side application. When you enter input (text, file, folder, etc), your data does not leave the browser. All of the recipes are written in JavaScript and are executed on the client. You don’t have to worry that some agency is getting your encryption keys, pictures, or other sensitive data. As a reminder, the code is open source and can be viewed and reviewed. Also, you don’t have to be online to use CyberChef. There is a download link at the top left that will let you download a ZIP file of the application to run locally. When you click the link, you get a popup that provides this message. It is important to note that this isn’t an installed application and there is no provision for keeping it updated unless you create those means.

CyberChef runs entirely within your browser with no server-side component, meaning that your Input data and Recipe configuration are not sent anywhere, whether you use the live, official version of CyberChef or a downloaded, standalone version (assuming it is unmodified).

There are three operations that make calls to external services, those being the 'Show on map' operation which downloads map tiles from wikimedia.org, the 'DNS over HTTPS' operation which resolves DNS requests using either Google or Cloudflare services, and the 'HTTP request' operation that calls out to the configured URL you enter. You can confirm what network requests are made using your browser's developer console (F12) and viewing the Network tab.

If you would like to download your own standalone copy of CyberChef to run in a segregated network or where there is limited or no Internet connectivity, you can get a ZIP file containing the whole web app below. This can be run locally or hosted on a web server with no configuration required.

Be aware that the standalone version will never update itself, meaning it will not receive bug fixes or new features until you re-download newer versions manually.

That’s it! I hope you got a good introduction to CyberChef and keep it in mind when you have little needs to manipulate data. If there is anything that you have found very handy to use it for or any good tips and tricks, I’d love to hear about it in the comments.