{"id":13806548,"url":"https://github.com/thomas-maurice/dnsbin2","last_synced_at":"2025-06-11T07:10:42.693Z","repository":{"id":44486670,"uuid":"289304686","full_name":"thomas-maurice/dnsbin2","owner":"thomas-maurice","description":"I have literally no idea why I did that - Pastebin over DNS ","archived":false,"fork":false,"pushed_at":"2021-04-29T12:52:40.000Z","size":39,"stargazers_count":38,"open_issues_count":1,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-13T21:46:23.303Z","etag":null,"topics":["dns","golang","shitposting"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thomas-maurice.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-08-21T15:35:39.000Z","updated_at":"2023-05-07T14:03:01.000Z","dependencies_parsed_at":"2022-09-15T03:32:16.422Z","dependency_job_id":null,"html_url":"https://github.com/thomas-maurice/dnsbin2","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomas-maurice%2Fdnsbin2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomas-maurice%2Fdnsbin2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomas-maurice%2Fdnsbin2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomas-maurice%2Fdnsbin2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thomas-maurice","download_url":"https://codeload.github.com/thomas-maurice/dnsbin2/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomas-maurice%2Fdnsbin2/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259219728,"owners_count":22823578,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dns","golang","shitposting"],"created_at":"2024-08-04T01:01:13.156Z","updated_at":"2025-06-11T07:10:42.666Z","avatar_url":"https://github.com/thomas-maurice.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"# dnsbin2 - Pastebin over DNS\n\u003e Because [dnsbin](https://github.com/thomas-maurice/dnsbin) was not stupid enough.\n\n# TL;DR\nThis is a (slightly) improved re-implementation of my already embarassingly stupid and useless [dnsbin](https://github.com/thomas-maurice/dnsbin) written in Go.\n\nThe main advantages are:\n* I does not embed a f*cking BIND server inside the docker image\n* It can delete uploaded files (I don't know if the previous version was able to but tbh my eyes started bleeding when I read the code so we'll never know)\n* You can make the retrieving of the files concurrent, so it can be both utterly useless and very fast, just like the software equivalent of [sanic](https://knowyourmeme.com/memes/sanic-hegehog)\n\nIn terms of features it is fairly simple, it allows you to:\n* Upload a file for storage using a simple cURL command\n* Delete the file with the generated signed token\n* Retrieves this file using a state of the art base64-over-DNS-TXT-fields API\n\nAt this moment you are probably rightfully wondering these three things:\n1. Why would I ever use something like that ?\n2. Why did you commit such attrocity ?\n3. u ok dude ?\n\nTo which I would answer\n1. Because you want to sneakily get files on a monitored network that unexpicably allows yolo DNS traffic, or more likely because you either hate your self or are high as f*ck.\n2. Because I can, there is nothing you can do about it and I exist to spite God.\n3. Writing this code gave me brain damage.\n\n*Disclaimer*: The code **IS** horrendous, untested and bad, and I don't care the slightest.\n\n# Cool story bro, how do I use it ?\n## Compile it\n```bash\n$ make\nif ! [ -d bin ]; then mkdir bin; fi\ngo build -v -o ./bin/server ./server\ngo build -v -o ./bin/cli ./cli\n\n```\n## Run the server\n```\n$ ./bin/server -listen :5354\nINFO[0000] creating the files directory\nINFO[0000] you can upload a file doing something like curl -F 'file=@some-file.txt' http://localhost:8080/upload\nINFO[0000] creating the keys directory\nINFO[0000] generating new ed25519 signing keys\n```\n\nAll the data will live in a new `./data` directory.\n\n## Upload some file\n```json\n$ curl -sF 'file=@server/main.go' http://localhost:8080/upload | jq .\n{\n  \"error\": false,\n  \"error_msg\": \"\",\n  \"uuid\": \"755c6d53-6fee-4221-bfa7-b9f76aa79f8e\",\n  \"size\": 12152,\n  \"sha1\": \"40cb4c5136e045bfac72b90ca43f097a8ed32823\",\n  \"delete_token\": \"eyJzaWduYXR1cmUiOiI2MWQ3NzVlMmU5ZWE1ODk4ZjVhYzk1NjM5MGU2MWU0NWNmN2ViODYyOWJhNjdmZDE1MTZiYTcxMjQ3YmExMDE5YTMyMTA0MjI5YzlhMGFiNDJmZDdhYjU2MGY0NjU3OGEzMGM2MWRlNzFkYmM4MTM2MDRhN2Q0MzAzYWQyZmUwYyIsImZpbGVfaWQiOiI3NTVjNmQ1My02ZmVlLTQyMjEtYmZhNy1iOWY3NmFhNzlmOGUifQ==\"\n}\n```\nNote the `uuid` and `delete_tokens` you will need for later, you can also store the sha1 to check for file integrity.\n\n## Retrieve some file\n```bash\n$ ./bin/cli -resolver 127.0.0.1:5354 -domain does.not.matter.if.locally -uuid 755c6d53-6fee-4221-bfa7-b9f76aa79f8e\n...\n[the content of the file so if it binary i strongly suggest to pipe it somewhere otherwise it will fuck up your terminal]\n...\n```\n\nFunnily enough you can also achieve the same exact thing using a bash script that would go something like that\n```bash\n#!/bin/bash\n\nif [ -n \"${DBG}\" ]; then\n    set -x\nfi;\n\nif [ -z \"${1}\" ]; then\n    echo \"You should provide an UUID\"\nfi;\n\nlet \"i=0\"\n\necho -n '' \u003e ${1}.b64\n\nwhile [ 1 ]; do\n    data=\"$(dig @127.0.0.1 -p 5354 ${i}.${1}.foo.com TXT +short | tr -d \\\")\"\n    if [ -z \"${data}\" ]; then break; fi;\n    echo ${data} \u003e\u003e ${1}.b64\n    let \"i=i+1\"\ndone;\n\nbase64 -d \u003c ${1}.b64 \u003e ${1}\nrm ${1}.b64\n```\n\nYou can also do it in parallel with something like that (needs GNU/parallel)\n```bash\n#!/bin/bash\n\n_jobs=${JOBS:-50}\n\nif [ -n \"${DBG}\" ]; then set -x; fi;\nif [ -z \"${1}\" ]; then echo \"You should provide an UUID\"; exit 1; fi;\nif [ -f \"${1}.b64\" ]; then rm \"${1}.b64\"; fi;\n\nhash=\"$(dig @127.0.0.1 -p 5354 hash.${1}.foo.com TXT +short | tr -d \\\")\"\nchunks=\"$(dig @127.0.0.1 -p 5354 chunks.${1}.foo.com TXT +short | tr -d \\\")\"\n\necho \"Downloading ${1} with ${_jobs} concurent jobs\"\n\nparallel --jobs ${_jobs} -a \u003c(seq 0 $(( ${chunks} - 1)) ) -a \u003c(echo ${1}) 'echo {1} $(dig @127.0.0.1 -p 5354 {1}.{2}.foo.com TXT +short | tr -d \\\")' | sort -n | cut -d\\  -f2 | tr -d '\\n' \u003e ${1}.b64\n\nsum=$(sha1sum \"${1}.b64\" | awk '{print $1}')\nif [ \"${sum}\" != \"${hash}\" ]; then\n    echo \"WARNING the sha1sum of the retrieved file does not match the one from the server\";\n    echo \"Got ${sum} wanted ${hash}\"\nfi;\n\nbase64 -d \u003c ${1}.b64 \u003e ${1} \u0026\u0026 rm ${1}.b64\nif [ -n \"${2}\" ]; then mv \"${1}\" \"${2}\"; fi;\n```\n\n## Delete some file\nDo a `curl` call to the `/delete` endpoint using the `delete_token` value you got previously. This is a signed token that will allow you to delete whatever stuff you uploaded.\n\n```bash\n$ curl 'http://localhost:8080/delete?token=eyJzaWduYXR1cmUiOiI2MWQ3NzVlMmU5ZWE1ODk4ZjVhYzk1NjM5MGU2MWU0NWNmN2ViODYyOWJhNjdmZDE1MTZiYTcxMjQ3YmExMDE5YTMyMTA0MjI5YzlhMGFiNDJmZDdhYjU2MGY0NjU3OGEzMGM2MWRlNzFkYmM4MTM2MDRhN2Q0MzAzYWQyZmUwYyIsImZpbGVfaWQiOiI3NTVjNmQ1My02ZmVlLTQyMjEtYmZhNy1iOWY3NmFhNzlmOGUifQ=='\n{\"error\":false,\"error_msg\":\"\",\"ok\":true}\n```\n\n# How does it work ?\n## Uploading\nThe uploading is straightforward. The server accepts a file, base64 encodes it, hashes it, assigns it an ID (UUID in our case) then signes its UUID (to create the deletion token) with an ed25519 key generated by the server and returns all of that to the user. The signed UUID is here used as a token to ensure that only the user that uploaded the file can delete it via the API (otherwise a goode ole `rm` works fine too)\n\n## Retrieving the file\nThis is the funniest part. As you might know if you attended school one day in your life, DNS is trash, yet I am leveraging the TXT records of the protocol to make transit arbitrary data over the wire, however these fields are limited to a length of 255 bytes.\n\nTo manage to retrieve the file entirely the cli will retrieve small chunks of 255 bytes each and reassemble them. This is done by querying sequentially the following domain `\u003cchunkID\u003e.\u003cfileUUID\u003e.domain.wtf` and getting the value of the TXT field, until the servers sends us an `NXDOMAIN` error, that we use here as the good olde `EOF`.\n\nThen concatenate all that and base64-decode it and bam you have your original file.\n\n# Getting file infos\nYou can query the special `chunks` and `hash` subdomains to fetch the SHA1 of the file and the number of chunks that will be required to download it.\n```bash\n$ dig @127.0.0.1 -p 5354 chunks.04927d90-1c30-4e15-bdde-6b714ea1326c.foo.com. TXT +short\n\"27522\"\n$ dig @127.0.0.1 -p 5354 hash.04927d90-1c30-4e15-bdde-6b714ea1326c.foo.com. TXT +short\n\"b27c33435ebf8313104fe6fdf757ef0a56a2a5c5\"\n```\n\n# How about the performance\nI'm so glad you asked. Let us demonstrate with a simple 5Mb file.\n\nLet's start by generating a file\n```bash\n$ dd if=/dev/urandom of=file bs=1M count=5\n5+0 records in\n5+0 records out\n5242880 bytes (5.2 MB, 5.0 MiB) copied, 0.0572735 s, 91.5 MB/s\n```\n\nLet's upload it\n```bash\n$ time ( curl -sF 'file=@file' http://localhost:8080/upload | jq . )\n{\n  \"error\": false,\n  \"error_msg\": \"\",\n  \"uuid\": \"bbeff5b7-f0bb-49ef-ab90-e65fb83fa66b\",\n  \"size\": 6990508,\n  \"sha1\": \"af575237058e95514080a662c3c0abd41abca3a8\",\n  \"delete_token\": \"eyJzaWduYXR1cmUiOiIyN2FmZGEyZjRjZjQyYzkyMDU2Y2Q0ZTIwYzU2N2Q4NzFkMTlhNGVhNmRlYjc1YzQ0ZTk0ODg1ZDcwZmJiNmYwNTU0NmUyODkxNWU5MWM1OWFhZWJiYTFmNWExYzZiZDdiZWRkNjdmZmE4M2NmYTMyYzIxNzMzYWQ5YTdlZTIwMCIsImZpbGVfaWQiOiJiYmVmZjViNy1mMGJiLTQ5ZWYtYWI5MC1lNjVmYjgzZmE2NmIifQ==\"\n}\n\nreal    0m0.088s\nuser    0m0.077s\nsys     0m0.029s\n```\n\nAnd now let's retrieve it :)))))\n```bash\ntime ( ./bin/cli -resolver 127.0.0.1:5354 -domain does.not.matter -uuid bbeff5b7-f0bb-49ef-ab90-e65fb83fa66b \u003e /dev/null )\n\nreal    0m19.979s\nuser    0m37.066s\nsys     0m6.089s\n```\n\nYep, that's shit alright.\n\n**EDIT**: You can now make the cli retrieve the file chunks in a parallel way. With a concurency of 30 (`-workers 30`) it downloads\nthe 5M of data in less than a second locally.\n\n# In conclusion\nBeing able to do something does **NOT** mean that you should do it.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthomas-maurice%2Fdnsbin2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthomas-maurice%2Fdnsbin2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthomas-maurice%2Fdnsbin2/lists"}