Fun with DNS TXT Records

TXT Record Specification 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.

Compression #

Using python, base64, and zlib, we can naively compress the data then base64 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)
>>> import base64, zlib
>>> lorem_ipsum_compressed = base64.b64encode(zlib.compress(lorem_ipsum,9))
>>> len(lorem_ipsum_compressed)

A reduction of 118 characters, not bad.

Proof of Concept #

I created a TXT record on with the zlib + base64 method above

dig TXT +short

and to decompress it in one line

dig TXT +short  | python3 -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:

I stored the encrypted secret on the TXT record under

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

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

some thoughts and ideas