The Empty Room: A Honeypot Has Nothing in Its Drawers
Do You Know You're a Honeypot? โ Part 3
Classification: MEDIUM ยท Confidence: HIGH (first-party command capture)
The first two letters climbed two rungs. The name check asks whether the machine is called like a honeypot, and a rename defeats it. The behavioral check asks whether the shell can act like a real one, and only implementing the behavior defeats it. This letter is the last rung, and it is the hardest of the three, because it does not probe the trap's disguise at all. It probes the trap's emptiness. A honeypot โ even a perfectly-named, perfectly-behaving one โ is almost always a furnished-looking room with nothing in the drawers: no real users' files, no real application deployed, no real secrets, often no real hardware underneath. A real, valuable machine is full of the debris of real use. The most sophisticated checkers do not ask what the room is called or whether the light switches work. They open the drawers.
The same discipline holds: what follows describes what attackers look for, not what they found on any particular sensor, and deliberately says nothing about the capturing sensor's own furnishing.
The hardware floor
The lowest question at this tier is whether there is any real machine under the shell at all. The probes are dmidecode, and the product_name and board_vendor reads that tools like neofetch perform under the hood โ all of which query the DMI/SMBIOS tables, the firmware's self-description of the hardware. A physical server reports a real manufacturer and board; a virtual machine reports its hypervisor โ QEMU, VMware, VirtualBox, KVM โ right there in the product name. To an attacker, a VirtualBox or bare-QEMU DMI string is a meaningful sandbox tell: analysis environments and casually-deployed honeypots very often run on exactly those desktop hypervisors.
The nuance the careful checker knows โ and the reason this is a floor and not a verdict โ is that virtualization alone proves nothing. Nearly the entire legitimate internet runs on virtual machines; every cloud instance is a VM, and a cloud-provider DMI string is the signature of a perfectly real, valuable target. So the hardware read is not conclusive by itself; it is one signal to be combined with the others. A bare-QEMU DMI plus an empty disk plus a freshly-booted uptime plus no real users is a sandbox; a cloud-provider DMI plus real application files plus real secrets is a production box worth taking. The hardware check establishes the floor โ is there plausibly real infrastructure here? โ and the furnishing checks decide the rest.
Opening the drawers
The furnishing check is where the tier earns its name, and its central specimen is a hunt for secrets:
find /home /root /var/www /opt /srv -name ".env" -o -name ".env.*" -o -name "*.env";
find /home /root /var/www /opt /srv -name "secrets" -o -name "secrets.json" -o -name "secrets.yml" -o -name "secrets.yaml";
find /home /root -name "*.json" -o -name "*.yml" -o -name "*.yaml" -o -name "*.conf" -o -name "*.cfg"
This is a search for the residue that only real use leaves. A working machine accumulates .env files holding database passwords and API keys, secrets.json and secrets.yml holding application credentials, .conf and .cfg files holding the settings of software that is actually deployed and actually run. These files are the sediment of a machine that does a job. A honeypot โ whose filesystem is a stage set, whether emulated or a freshly-imaged real system โ does not have them, because it has never done a job. It has never had a developer check out a repository with a .env in it, never had an application write its config, never accumulated the credential debris of production. The drawers are empty because no one has ever lived here.
So emptiness itself is the tell. The attacker does not need to catch the honeypot in a lie about its name or its arithmetic; it only needs to observe that a machine which claims to be a real server has none of the things a real server inevitably has. A believable name and a working shell get a honeypot past the first two rungs, but a machine with no secrets, no deployed applications, no lived-in home directories, and no accumulated configuration is suspicious no matter how convincingly it is named or how correctly it evaluates $((1337+1337)). The final check is not "are you disguised?" but "are you used?" โ and a trap, by its nature, is not.
The check that is also the payoff
Here is what makes the secrets hunt the smartest probe in the entire series, and the reason the most capable operators reach for it: it cannot be a wasted move, because a positive result is both the honeypot verdict and the objective. If the find for .env files comes back empty, the operator has learned the machine may be a honeypot or a worthless bare box, and can leave without spending a payload. If it comes back full โ a .env with live AWS keys, a secrets.yml with a database password, a config with a cloud token โ the operator has learned two things at once: that the machine is a real, used, valuable target, and exactly what the treasure is. The detection and the theft are the same command.
This collapses a cost that the earlier tiers pay. The name check and the arithmetic test are pure overhead โ probes that cost commands and reveal the operator's wariness but yield nothing of value themselves. The secrets hunt has no such overhead, because its output on a real machine is the loot. An operator running it is simultaneously vetting the environment and looting it, and the better the answer to "is this real?", the richer the answer to "what can I steal?". That is why the value hunt is where sophisticated honeypot-awareness and ordinary greed converge: the same find that catches the honeypot robs the real machine, so there is never a reason not to run it. The check pays for itself, and on a real target it pays a great deal.
It also reframes what the loot economy is actually after. A machine's CPU โ the thing the miners in this whole investigation fight over โ is worth a slow trickle. A machine's secrets โ one live cloud credential โ can be worth vastly more than its cycles, because a stolen AWS key is access to whatever that key can reach, which may be an entire cloud account. The secrets hunt is the behavior of an operator who is not counting CPUs but hunting credentials, and it sits at the top of this series' detection ladder for the same reason it sits near the top of the value ladder: the drawers are where the real money is, and opening them tells you whether the house is real in the same motion that empties it.
The shell that no human ever used
There is a furnishing check aimed at the shell's own history rather than the disk's, and it is a clean example of the "used or not?" question. A real account carries a ~/.bash_history โ the accumulated record of the commands a human actually typed over the life of the machine: package installs, edits, mistakes, the idiosyncratic mess of a person working. A honeypot account, even on a convincing filesystem, usually has an empty or synthetic history, because no human has ever sat at it and worked. So a glance at .bash_history โ is it there, is it long, does it read like a person or like nothing? โ is the shell-level version of opening the drawers.
This is also why the anti-forensics behavior catalogued elsewhere in this investigation cuts both ways here. Operators who run unset HISTFILE or export HISTFILE=/dev/null do it to keep their own commands out of the record โ but on a real victim, the very presence of a substantial prior history is part of what marks the machine as genuinely used, and its absence is part of what marks a trap. A machine whose only shell history is the attacker's own session, with nothing before it, is a machine no one lived on before the attacker arrived, which is the profile of a freshly-imaged trap far more often than that of a real server with a real administrator's years of accumulated commands. The lived-in shell is furniture too, and its absence is one more empty drawer.
Why emptiness is the hardest tell to fake
Each rung of this series is harder for the defender to satisfy than the last, and the furnishing tier is hardest by a wide margin, because faking it is not bounded work. Defeating the name check is a rename โ finite, one-time. Defeating the behavioral check is implementing features โ laborious, but a closed list you can grind down. Defeating the furnishing check means populating the machine with a convincing history of real use: home directories with plausible projects, .env files with credible-looking secrets, a believable application under /var/www, realistic logs with realistic timestamps, installed packages with modification dates that tell a coherent story of a machine that has been administered over time. That is not a task you finish; it is a stage-dressing effort that must be as rich and as internally consistent as an actual working system, which is to say it approaches the cost of just running an actual working system.
And it carries a danger the other tiers do not. Any fake secret convincing enough to fool a credential-hunting attacker is a secret the attacker will use. Plant a realistic-looking AWS key to furnish the room, and the operator who finds it will try it โ against your infrastructure, or against whatever account the key appears to belong to, or as a pivot into a third party. A decoy credible enough to pass the value hunt is, the moment it is stolen, a live credential loose in the world, and the defender has manufactured exactly the liability the honeypot was supposed to contain. The furnishing tier thus puts the defender in a bind the earlier tiers do not: an empty honeypot is detectable at this rung, but a furnished one is either an unbounded curation burden or a self-inflicted credential leak. There is no cheap way to have full drawers.
The forwarding check, and the texture of a used machine
Two more probes round out the tier. One reads the SSH configuration for restrictions: grep -iE 'AllowTcpForwarding|DisableForwarding|PermitTunnel|GatewayPorts|ForceCommand' /etc/ssh/sshd_config. This is dual-purpose in its own way. An attacker wants to know whether the box can be used as a proxy or pivot โ whether TCP forwarding is enabled โ so it can be turned into infrastructure; but the same read doubles as a honeypot tell, because honeypots frequently disable forwarding and tunneling to prevent exactly that abuse, and a ForceCommand or a hard DisableForwarding is both an obstacle to the attacker's plans and a suspicious sign that this machine has been deliberately locked against the ordinary uses a real server would permit. A machine configured to forbid the things real servers routinely allow is a machine configured by someone who did not want it used, which is a honeypot's configuration.
The other is the gestalt: full-profile dumps that read mount, ps -ef, free -m, uname -a, /etc/issue, and hostname in one sweep. No single line here is a verdict, but together they paint the texture of a machine, and real machines and traps have different textures. A real, working server has a lived-in profile โ many running processes doing real work, a messy set of real mounts, memory under real pressure, a hostname someone actually chose, a scatter of installed software with a history. A honeypot or fresh sandbox has a clean one โ few processes, minimal mounts, memory suspiciously idle, a default hostname, a filesystem with no accumulated mess. The attacker reading the whole profile is not checking any one fact; it is reading whether the machine has the accumulated disorder of use, or the eerie tidiness of a room prepared for a guest and otherwise unlived-in. Traps are tidy. Real machines are not.
The sensor cannot tell wary from greedy
The dual-use collapse has a consequence for the sensor's own understanding of what it is watching, and it is worth naming because it complicates the whole census. When the secrets hunt is both the honeypot check and the theft, the honeypot loses the ability to tell why an operator ran it. A find /home /root -name ".env" looks identical whether the operator is a wary professional vetting the environment before committing, or an ordinary credential thief who would have run the same command on any box, honeypot or not, out of simple greed. The command is the same; the intent behind it is invisible.
So at this tier the sensor cannot cleanly separate "an attacker who suspected a trap and was checking" from "an attacker who was just looting." Both open the drawers; both run the identical find. This means the honeypot cannot even reliably know whether it was detected. A wary operator who runs the secrets hunt, finds the drawers empty, concludes "honeypot," and leaves is indistinguishable, in the record, from a greedy operator who runs the same hunt, finds nothing worth taking, and leaves out of disappointment. The sensor sees a find and a departure in both cases. The earlier tiers were legible โ a grep '^phil:' or an echo $((1337+1337)) has no purpose except detection, so running it announces wariness. The value hunt has a second purpose, and that second purpose is camouflage: the smartest detection probe hides inside the most ordinary theft, and a honeypot watching it cannot be sure whether it just failed a test or merely came up empty for a thief. The deepest check is also the quietest, because it does not look like a check at all.
Defense: honeytokens, or accept the tell
The furnishing tier hands the defender the series' sharpest lesson, and the only good answer to it is a specific one. A bare honeypot is detectable at this rung, full stop; the operator who wants to observe the attackers who open the drawers cannot leave the drawers empty. But filling them with realistic secrets is the liability just described. The reconciliation is the honeytoken: a decoy credential that is deliberately, verifiably fake in a way the attacker cannot see but the defender fully controls โ a cloud key minted specifically as bait, valid enough to look real and to be tried, but wired so that any attempt to use it fires an alert and grants nothing. A honeytoken furnishes the room convincingly while inverting the danger: the fake secret is not a liability loose in the world but a tripwire, and the attacker's "find the secrets" becomes the defender's "tell me the instant someone takes the bait, and where they try to spend it."
This is the elegant resolution of the dual-use collapse. The value hunt made detection and theft the same command; the honeytoken makes furnishing and alerting the same object. The attacker who runs the secrets hunt to vet-and-loot the machine is, against a honeytoken-furnished sensor, vetting a machine that looks real and looting a credential that reports its own theft. The empty room is a detectable honeypot; the room furnished with honeytokens is a honeypot that turns the deepest detection probe into its best source of intelligence โ learning not just that the attacker checked the drawers, but which credential they took and the exact moment and place they tried to use it. The other tiers' gift was a hardening checklist. This tier's gift is a way to make the attacker's smartest probe answer to the defender.
Bounds and limits
DOCUMENTED, first-party: the DMI/hardware probes (dmidecode, product_name/board_vendor reads); the secrets hunt (find /home /root /var/www /opt /srv for .env, secrets.*, and *.json/*.yml/*.conf/*.cfg); the SSH-config forwarding/restriction check (AllowTcpForwarding|DisableForwarding|PermitTunnel|GatewayPorts|ForceCommand); and the full-profile gestalt dumps (mount, ps -ef, free -m, uname -a, /etc/issue, hostname).
INFERRED, high confidence: that these probe whether the environment is a real, used, valuable machine versus an empty trap (the specific targets โ secrets, deployed configs, real hardware, lived-in profile โ are the properties a honeypot lacks by nature); that the secrets hunt is dual-use, serving as both the honeypot verdict and the objective (a positive result is simultaneously "this is real" and "here is the loot"). INFERRED, general: that furnishing is the hardest tier to fake (populating a convincing history of use is unbounded, and convincing fake secrets are a real liability).
BOUNDED โ deliberately and importantly: emptiness is a signal, not proof โ a bare disk can also be a fresh or worthless real machine, so a careful attacker treats it as one input among several (hardware, behavior, profile), which is exactly why the hardware read is described as a floor rather than a verdict. Virtualization is not a honeypot proof, since the legitimate cloud is entirely virtualized. And this letter states nothing about the capturing sensor's own hardware, furnishing, secrets, or configuration; whether a given sensor's drawers are empty is precisely what the value hunt is built to learn, and there is no reason to answer it here.
None of these bounds change the finding. The final and hardest way an attacker checks for a trap is to ignore its disguise entirely and test whether it is used โ whether there is real hardware beneath it, real secrets in its drawers, real deployed software, the accumulated disorder of a machine that does a job. A honeypot can be renamed to pass the first rung and rebuilt to pass the second, but the third demands that it be lived in, and being lived in is the one thing a trap is not. The smartest probe of all is the one that catches the honeypot and robs the real machine with the same find โ which is why the deepest form of honeypot detection is indistinguishable from ordinary theft, and why the defender's only good answer is to fill the drawers with secrets that are traps of their own.
This is Part Three of Do You Know You're a Honeypot? Across three rungs the attackers escalated from checking the trap's name, to testing its behavior, to opening its drawers โ each rung harder to fake than the last. Part Four steps back from the individual probes to the whole encounter: the machine-parseable automation behind these checks, the selection bias they impose on everything a sensor records, and the strange symmetry by which the attacker's every attempt to unmask the honeypot is also the honeypot's clearest instruction on how to become harder to unmask.