← Back to Cheat Sheets
kavklaw@llm ~ /cheatsheets/encoding-decoding

kavklaw@llm $ cat encoding-decoding.md

Encoding & Decoding Cheat Sheet

Base64, hex, URL encoding, ROT13, JWT, ASCII tables, and every CLI one-liner you need for CTFs.

Base64

Encodes binary data as ASCII text using 64 characters (A-Z, a-z, 0-9, +, /) with = padding.

# Encode
echo -n "Hello World" | base64
# SGVsbG8gV29ybGQ=

# Decode
echo "SGVsbG8gV29ybGQ=" | base64 -d
# Hello World

# Encode a file
base64 file.bin > file.b64
cat file.bin | base64 -w 0           # No line wrapping

# Decode a file
base64 -d file.b64 > file.bin

# Python
python3 -c "import base64; print(base64.b64encode(b'Hello World').decode())"
python3 -c "import base64; print(base64.b64decode('SGVsbG8gV29ybGQ=').decode())"

# Base64 URL-safe variant (used in JWTs)
python3 -c "import base64; print(base64.urlsafe_b64encode(b'Hello World').decode())"
# Uses - and _ instead of + and /

# OpenSSL
echo -n "Hello" | openssl base64
echo "SGVsbG8=" | openssl base64 -d

Detect Base64:
  - Charset: A-Za-z0-9+/=
  - Length is multiple of 4
  - Ends with 0-2 '=' padding characters
  - No spaces or special chars (unless line-wrapped)

Hex Encoding

# String to hex
echo -n "Hello" | xxd -p
# 48656c6c6f

# Hex to string
echo "48656c6c6f" | xxd -r -p
# Hello

# Full hex dump with offsets
echo -n "Hello World" | xxd
# 00000000: 4865 6c6c 6f20 576f 726c 64    Hello World

# Hex dump of a file
xxd file.bin | head -20

# Python hex
python3 -c "print(bytes.fromhex('48656c6c6f').decode())"
python3 -c "print('Hello'.encode().hex())"

# Hex to decimal
printf "%d\n" 0x41          # 65
echo "ibase=16; 41" | bc    # 65

# Decimal to hex
printf "%x\n" 65             # 41
printf "0x%02x\n" 65         # 0x41

# Using od (octal dump) for hex
echo -n "Hello" | od -A x -t x1z
# 000000 48 65 6c 6c 6f                                   >Hello<

ASCII Table (Printable Characters)

Dec  Hex  Char    Dec  Hex  Char    Dec  Hex  Char
───────────────────────────────────────────────────
 32  20   (space)  64  40   @       96  60   `
 33  21   !        65  41   A       97  61   a
 34  22   "        66  42   B       98  62   b
 35  23   #        67  43   C       99  63   c
 36  24   $        68  44   D      100  64   d
 37  25   %        69  45   E      101  65   e
 38  26   &        70  46   F      102  66   f
 39  27   '        71  47   G      103  67   g
 40  28   (        72  48   H      104  68   h
 41  29   )        73  49   I      105  69   i
 42  2a   *        74  4a   J      106  6a   j
 43  2b   +        75  4b   K      107  6b   k
 44  2c   ,        76  4c   L      108  6c   l
 45  2d   -        77  4d   M      109  6d   m
 46  2e   .        78  4e   N      110  6e   n
 47  2f   /        79  4f   O      111  6f   o
 48  30   0        80  50   P      112  70   p
 49  31   1        81  51   Q      113  71   q
 50  32   2        82  52   R      114  72   r
 51  33   3        83  53   S      115  73   s
 52  34   4        84  54   T      116  74   t
 53  35   5        85  55   U      117  75   u
 54  36   6        86  56   V      118  76   v
 55  37   7        87  57   W      119  77   w
 56  38   8        88  58   X      120  78   x
 57  39   9        89  59   Y      121  79   y
 58  3a   :        90  5a   Z      122  7a   z
 59  3b   ;        91  5b   [      123  7b   {
 60  3c   <        92  5c   \      124  7c   |
 61  3d   =        93  5d   ]      125  7d   }
 62  3e   >        94  5e   ^      126  7e   ~
 63  3f   ?        95  5f   _      127  7f   DEL

Key Control Characters:
  0   00  NUL  (null byte β€” string terminator in C)
  9   09  TAB  (horizontal tab)
 10   0a  LF   (line feed β€” Unix newline)
 13   0d  CR   (carriage return β€” Windows newline = CR+LF)
 27   1b  ESC  (escape)

# Quick lookup
man ascii
python3 -c "print(ord('A'))"     # char β†’ decimal: 65
python3 -c "print(chr(65))"      # decimal β†’ char: A
printf "\\x41\n"                 # hex β†’ char: A

URL Encoding (Percent Encoding)

Character   Encoded    Purpose / Notes
───────────────────────────────────────────────
(space)     %20        (or + in form data)
!           %21        Sometimes reserved
"           %22        HTML attribute delimiter
#           %23        Fragment identifier
$           %24        Reserved
%           %25        Encoding escape character itself
&           %26        Parameter separator
'           %27        XSS vector
(           %28        Grouping
)           %29        Grouping
+           %2B        Space in form data
,           %2C        List delimiter
/           %2F        Path separator
:           %3A        Port / scheme separator
;           %3B        Parameter delimiter
<           %3C        HTML tag β€” XSS
=           %3D        Key-value separator
>           %3E        HTML tag β€” XSS
?           %3F        Query string start
@           %40        Userinfo separator
[           %5B        IPv6 / bracket
]           %5D        IPv6 / bracket
\           %5C        Directory traversal
{           %7B        Template injection
|           %7C        Command injection
}           %7D        Template injection

# CLI encode/decode
python3 -c "from urllib.parse import quote; print(quote('hello world&foo=bar'))"
# hello%20world%26foo%3Dbar

python3 -c "from urllib.parse import unquote; print(unquote('hello%20world%26foo%3Dbar'))"
# hello world&foo=bar

# Double URL encoding (bypass WAFs)
<   β†’  %3C   β†’  %253C
'   β†’  %27   β†’  %2527

HTML Entities

Character   Named Entity    Numeric       Hex Entity
─────────────────────────────────────────────────────
<           &lt;            &#60;         &#x3C;
>           &gt;            &#62;         &#x3E;
&           &amp;           &#38;         &#x26;
"           &quot;          &#34;         &#x22;
'           &apos;          &#39;         &#x27;
(space)     &nbsp;          &#160;        &#xA0;
/           (none)          &#47;         &#x2F;

XSS Bypass via HTML Entities:
  &#x3C;script&#x3E;alert(1)&#x3C;/script&#x3E;
  &#60;img src=x onerror=alert(1)&#62;

# Python encode/decode
python3 -c "import html; print(html.escape('<script>alert(1)</script>'))"
python3 -c "import html; print(html.unescape('&lt;script&gt;'))"

ROT13 / Caesar Cipher

ROT13: Shift each letter 13 positions. Applying twice returns original.

A↔N  B↔O  C↔P  D↔Q  E↔R  F↔S  G↔T
H↔U  I↔V  J↔W  K↔X  L↔Y  M↔Z

# ROT13 in CLI
echo "Hello World" | tr 'A-Za-z' 'N-ZA-Mn-za-m'
# Uryyb Jbeyq

# ROT13 decode (same command β€” it's symmetric!)
echo "Uryyb Jbeyq" | tr 'A-Za-z' 'N-ZA-Mn-za-m'
# Hello World

# Python ROT13
python3 -c "import codecs; print(codecs.encode('Hello', 'rot_13'))"

# General Caesar cipher (shift N)
# ROT-N: replace 13 with desired shift
echo "Hello" | tr 'A-Za-z' 'D-ZA-Cd-za-c'     # ROT3 (classic Caesar)

# Brute force all 26 rotations
for i in $(seq 0 25); do echo "ROT-$i: $(echo 'Uryyb' | python3 -c "
import sys; s=sys.stdin.read().strip()
print(''.join(chr((ord(c)-97+$i)%26+97) if c.islower() else chr((ord(c)-65+$i)%26+65) if c.isupper() else c for c in s))
")"; done

JWT (JSON Web Token)

Structure:  HEADER.PAYLOAD.SIGNATURE
            xxxxx.yyyyy.zzzzz

Each part is Base64URL-encoded JSON (no padding =).

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ HEADER (algorithm & type)                           β”‚
β”‚ {"alg": "HS256", "typ": "JWT"}                      β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ PAYLOAD (claims / data)                             β”‚
β”‚ {"sub": "1234567890", "name": "admin", "iat": ...}  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ SIGNATURE                                           β”‚
β”‚ HMACSHA256(base64url(header) + "." +                β”‚
β”‚            base64url(payload), secret)              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Common Claims:
  iss    Issuer
  sub    Subject (user ID)
  aud    Audience
  exp    Expiration time (Unix timestamp)
  iat    Issued at
  nbf    Not before
  jti    JWT ID (unique identifier)

# Decode JWT (without verification)
echo "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0In0.xxx" | \
  cut -d. -f2 | base64 -d 2>/dev/null; echo

# Python decode
python3 -c "
import base64, json, sys
token = sys.argv[1]
for part in token.split('.')[:2]:
    padded = part + '=' * (4 - len(part) % 4)
    print(json.dumps(json.loads(base64.urlsafe_b64decode(padded)), indent=2))
" "YOUR_JWT_HERE"

JWT Attack Vectors:
  alg:none        Set algorithm to "none" β†’ skip signature verification
  alg:HS256β†’RS256 Confusion: sign with public key as HMAC secret
  Weak secret     Brute force HMAC key: hashcat -m 16500 jwt.txt wordlist
  kid injection   Key ID header β†’ path traversal / SQL injection
  jwk injection   Embed attacker's key in JWT header
  exp bypass      Modify expiration claim

# jwt_tool (all-in-one JWT testing)
python3 jwt_tool.py JWT_TOKEN -T          # Tamper mode
python3 jwt_tool.py JWT_TOKEN -C -d wordlist.txt  # Crack secret

Unicode

# Unicode code point to character
python3 -c "print('\u0041')"           # A
python3 -c "print('\U0001F600')"       # πŸ˜€

# Character to code point
python3 -c "print(hex(ord('A')))"      # 0x41
python3 -c "print(f'U+{ord(\"A\"):04X}')"  # U+0041

# UTF-8 encoding (bytes)
python3 -c "print('A'.encode('utf-8'))"       # b'A'      (1 byte)
python3 -c "print('Γ©'.encode('utf-8').hex())"  # c3a9      (2 bytes)
python3 -c "print('€'.encode('utf-8').hex())"  # e282ac    (3 bytes)
python3 -c "print('πŸ˜€'.encode('utf-8').hex())" # f09f9880  (4 bytes)

Unicode Security Issues:
  Homoglyph attacks     β†’ Π°dmin (Cyrillic 'Π°') vs admin (Latin 'a')
  Right-to-left override β†’ U+202E reverses text display
  Null byte             β†’ %00 / \x00 truncation
  Overlong UTF-8        β†’ Encode / as C0 AF to bypass filters
  Case mapping          β†’ ß β†’ SS (German sharp S), Δ± β†’ I (Turkish)
  Normalization         β†’ NFC vs NFD β†’ bypasses that compare strings

# Detect non-ASCII in a file
grep -P "[^\x00-\x7F]" file.txt

# Show Unicode info
python3 -c "import unicodedata; print(unicodedata.name('€'))"
# EURO SIGN

Common CTF Encoding Chains

Typical multi-layer encodings found in CTFs:

1. Base64 β†’ Hex β†’ ROT13
   Decode: ROT13 β†’ hex decode β†’ base64 decode

2. Hex β†’ Base64 β†’ URL encoding
   Decode: URL decode β†’ base64 decode β†’ hex decode

3. Binary β†’ Decimal β†’ Hex β†’ Base64
   Decode: base64 β†’ hex β†’ decimal β†’ binary

4. Base32 β†’ Base64 β†’ Reverse string
   Decode: reverse β†’ base64 β†’ base32

# Detection hints:
  Base64      Charset A-Za-z0-9+/= , length % 4 == 0
  Base32      Charset A-Z2-7= , length % 8 == 0
  Hex         Charset 0-9a-fA-F, even length
  Binary      Only 0 and 1, groups of 8
  Octal       Only 0-7, groups of 3
  URL         Contains %XX patterns
  HTML ent.   Contains &# or &name;
  Morse       Contains . - / spaces
  Decimal     Space-separated numbers 0-127 (ASCII range)
  Base85      Charset 0-9A-Za-z!#$%&()*+-;<=>?@^_`{|}~

# Quick decode chain (Python one-liner)
python3 -c "
import base64
s = 'VlhCaGJHbGtJVDA9'          # double base64
s = base64.b64decode(s).decode()  # first decode
s = base64.b64decode(s).decode()  # second decode
print(s)
"

CyberChef Quick Reference

CyberChef: https://gchq.github.io/CyberChef/

Essential Operations (drag into Recipe):
──────────────────────────────────────────────────────
From Base64 / To Base64        Standard base64
From Hex / To Hex              Hex encode/decode
URL Decode / URL Encode        Percent encoding
HTML Entity decode/encode      Named and numeric entities
ROT13                          Caesar shift 13
ROT47                          Shifts printable ASCII
XOR                            XOR with key (brute force option)
AES Decrypt / AES Encrypt      Symmetric crypto
From Binary / To Binary        Binary strings
From Decimal / To Decimal      Decimal values
From Morse Code                Dots and dashes
Magic                          Auto-detect encoding (try this first!)
Entropy                        Measure randomness
Strings                        Extract printable strings
Gunzip / Gzip                  Compression
JWT Decode                     Parse JWT tokens
Parse X.509 certificate        Examine SSL certs
Regular expression             Grep/extract patterns
Find / Replace                 String manipulation
Fork / Merge                   Split input, process separately

Pro Tips:
  - Use "Magic" operation first β€” it auto-detects encoding layers
  - Chain operations: drag multiple into Recipe
  - Use "Fork" to split on delimiter and process each piece
  - Save recipes for reuse
  - Breakpoint: pause recipe mid-chain to inspect
  - Input can be file, text, or URL

CLI One-Liners for Encoding/Decoding

# ──────── Base64 ────────
echo -n "text" | base64                    # Encode
echo "dGV4dA==" | base64 -d               # Decode
openssl base64 -in file.bin               # Encode file
openssl base64 -d -in file.b64            # Decode file

# ──────── Hex ────────
echo -n "text" | xxd -p                   # Encode (plain hex)
echo "74657874" | xxd -r -p               # Decode
echo -n "text" | od -A n -t x1 | tr -d ' \n'  # Alternative encode
printf '\x74\x65\x78\x74'                 # Hex bytes to string

# ──────── URL Encoding ────────
python3 -c "from urllib.parse import quote; print(quote('<script>'))"
python3 -c "from urllib.parse import unquote; print(unquote('%3Cscript%3E'))"
curl -s -o /dev/null -w "%{url_effective}" --get --data-urlencode "q=hello world" ""

# ──────── HTML Entities ────────
python3 -c "import html; print(html.escape('<b>test</b>'))"
python3 -c "import html; print(html.unescape('&lt;b&gt;test&lt;/b&gt;'))"
php -r 'echo htmlspecialchars_decode("&lt;b&gt;");'

# ──────── ROT13 ────────
echo "text" | tr 'A-Za-z' 'N-ZA-Mn-za-m'
python3 -c "import codecs; print(codecs.encode('text','rot_13'))"

# ──────── Binary ────────
echo -n "A" | xxd -b | awk '{print $2}'    # Char to binary
echo "01000001" | perl -lpe '$_=pack"B*",$_'  # Binary to char
python3 -c "print(bin(65))"                # Decimal to binary: 0b1000001
python3 -c "print(int('1000001',2))"       # Binary to decimal: 65

# ──────── Hash Generation ────────
echo -n "password" | md5sum                 # MD5
echo -n "password" | sha1sum                # SHA-1
echo -n "password" | sha256sum              # SHA-256
echo -n "password" | sha512sum              # SHA-512
openssl dgst -md5 file.bin                 # File hash
echo -n "password" | openssl dgst -sha256 -hmac "key"  # HMAC

# ──────── XOR ────────
python3 -c "
data = b'Hello'
key  = b'K'
xored = bytes([b ^ key[0] for b in data])
print(xored.hex())
# Decode: XOR again with same key
print(bytes([b ^ key[0] for b in xored]).decode())
"

# ──────── String Conversions ────────
echo -n "Hello" | rev                       # Reverse string
echo "SGVsbG8=" | base64 -d | rev          # Decode then reverse
echo "48 65 6c 6c 6f" | tr -d ' ' | xxd -r -p  # Spaced hex to string

# ──────── File Type Detection ────────
file unknown_file                           # Detect file type
xxd unknown_file | head -5                 # Check magic bytes
binwalk unknown_file                       # Find embedded files

Encoding Detection Cheat Sheet

Pattern                               Likely Encoding
───────────────────────────────────────────────────────────
Ends with = or ==                     Base64
Only A-Z, 2-7, =                      Base32
Only 0-9, a-f (even length)          Hex
Only 0 and 1 (groups of 8)           Binary
Contains %XX                          URL encoded
Contains &amp; &lt; &#xx;              HTML entities
Starts with eyJ                       JWT (base64 of {"...)
Three dot-separated base64 chunks     JWT
Looks readable but shifted            ROT13 / Caesar
Has . - and spaces/slashes            Morse code
Starts with PK                        ZIP archive (hex: 504B)
Starts with MZ                        Windows PE (hex: 4D5A)
Starts with \x89PNG                   PNG image
Starts with \xff\xd8\xff              JPEG image
Starts with GIF8                      GIF image
Starts with %PDF                      PDF document
Starts with \x1f\x8b                  Gzip compressed