thoughts | THEDEN

DNS TXT Record Hacks

Specifications Primer

Reading through the RFC Using the Domain Name System To Store Arbitrary String Attributes to summarise the relevant part:

Any printable ASCII character is permitted for the attribute name.

More importantly, on the restrictions section

Some DNS server implementations place limits on the size or number of TXT records associated with a particular owner. Certain implementations may not support TXT records at all.

However in rfc4408 section-3.1.3 a limit is explicitly stated

SPF or TXT records containing multiple strings are useful in constructing records that would exceed the 255-byte maximum length of a string within a single TXT or SPF RR record.

Searching online about the 255-byte limit shows a lot of posts by people trying to bypass it in BIND after the error invalid rdata format: ran out of space.

So we want to stay below that byte limit for maximum compatibility.

Stuffing data in 255 bytes

One could naively chunk text into 255-byte chunks like this

lorem_ipsum="Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions"

offset=1
max_bytes=255

# Get first 255 bytes 
echo -n "${lorem_ipsum}" | cut -b "${offset-$max_bytes}" |  tr -d $'\n' | wc -c
     255
     
echo -n "${lorem_ipsum}" | cut -b "${offset-$max_bytes}"
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has su

offset=$((max_bytes+1))
max_bytes=$(( $max_bytes+255 ))

# Get next 255 bytes
echo -n "${lorem_ipsum}" | cut -b "${offset}"-"${max_bytes}" |  tr -d $'\n' | wc -c
     255
     
echo -n "${lorem_ipsum}" | cut -b "${offset}"-"${max_bytes}"
rvived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing

and make multiple TXT records to get data across, but we need to make the most of what we have.

Compression

Using python3, base64, and zlib, we can compress the data then bas64 encode it

>>> lorem_ipsum = b"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions"
>>> len(lorem_ipsum)
558 
>>> import base64, zlib
>>> lorem_ipsum_compressed = base64.b64encode(zlib.compress(lorem_ipsum,9))
>>> len(lorem_ipsum_compressed)
440

A reduction of 118 characters, not bad.

Proof of concept

I created a TXT record on message.theden.sh with the zlib + base64 method above

dig message.theden.sh TXT +short
"eNrzTFOozC9VL0pVKEpNTMnMS1coycgsVsgsUS9WKMnPV8hJLElVBAD3QAzt"

and to decompress it in one line

dig message.theden.sh TXT +short  | python -c "import sys, zlib, base64; print(zlib.decompress(base64.b64decode(sys.stdin.readlines()[0])))"
If you're reading this it's too late!

So it works as expected. Now we need an interesting use-case.

DNS as a password manager?

It feels wrong, but here it goes. Let’s encrypt a secret with a password

# encrypt secret
echo -n 'mySuperSecretPassword1!!1!!' | openssl enc -e -aes-256-cbc -a -salt -pbkdf2
enter aes-256-cbc encryption password:
Verifying - enter aes-256-cbc encryption password:
U2FsdGVkX1/6QtzsEgPSLYdsSmIeVdH/0t7Tcwfr7ixWyDGzHu/Saz8YrKQ84kGd

I stored the encrypted secret on the TXT record under pass.theden.sh

dig pass.theden.sh TXT +short | sed 's/^"\(.*\)"$/\1/' | openssl aes-256-cbc -a -d -salt -pbkdf2
enter aes-256-cbc decryption password:
mySuperSecretPassword1!!1!!

You can try it yourself, the password to decrypt is hackerman.

Some Thoughts and Ideas

Written January 2021.

← Useful Tricks & Lessons I've learned Managing a Kubernetes Cluster