Dev.to Security 🔐 Cybersecurity 👁 0 📖 10 min read

A pentest lab on Apple Silicon (and what a frontend dev did with root)

In the first post of this series I said the lab and the language came next: how to build a sealed environment where you can break things freely. This is the lab. I built it, ran a full engagement through it against a del

A pentest lab on Apple Silicon (and what a frontend dev did with root)

In the first post of this series I said the lab and the language came next: how to build a sealed environment where you can break things freely. This is the lab. I built it, ran a full engagement through it against a deliberately vulnerable target, took the box to root two different ways, and wrote the whole thing up as a guide anyone on an Apple Silicon Mac can follow. Then, because old habits die hard, I defaced the server with a pure-CSS animation. More on that at the end.

If you own an M1, M2, M3, M4, or in my case an M5, this is the write-up I wish I had found before I lost an afternoon to it.

The problem nobody warns you about

Most pentest lab guides quietly assume you are on an Intel machine running VirtualBox. Follow one on an Apple Silicon Mac and it breaks at step one, for a reason that is rarely stated plainly.

The vulnerable machines the whole training ecosystem is built around are x86. Metasploitable, most of VulnHub, the classic teaching targets, all of them. Your Mac is ARM. VirtualBox virtualises, it does not emulate a different processor architecture, so an x86 image simply will not boot on it. Parallels and VMware Fusion are more polished, but they are built to virtualise too: they run guests that share your CPU's architecture, which is great for ARM Linux or Windows on ARM and no help at all for an old x86 target. Parallels also costs money.

So the real obstacle has nothing to do with hacking. It is that an ARM host and an x86 target speak different instruction sets, and the entire learning ecosystem lives on the far side of that gap.

The one insight the whole lab hangs on

The fix is a single tool that does two different jobs:

  • Virtualise ARM-native guests, so they run at near-native speed. Perfect for Kali Linux, the attacking machine, which ships an official ARM64 build.
  • Emulate x86 guests, translating a foreign architecture one instruction at a time. Slower, but the only way to boot an old x86 target like Metasploitable 2 on an ARM Mac.

UTM, a free and open-source front-end for QEMU, does both. That single capability is the entire reason this lab works, and every other setup decision follows from it.

Role Guest UTM mode Why
Attacker Kali Linux (ARM64) Virtualize Native speed, snappy
Target Metasploitable 2 (x86) Emulate The only way to boot x86 on ARM

Pick the wrong mode and the VM will not boot. That is the number-one beginner mistake, and once the virtualise-versus-emulate split is in your head the rest is mechanical. Kali is ARM, so you virtualise it. The target is x86, so you emulate it. Both sit on one isolated Shared Network, and the whole thing runs comfortably on a 16 GB laptop. The emulated target is slower than real hardware, but for running scans and shells rather than compiling kernels, it is perfectly usable.

One Apple Silicon Mac running UTM, with a virtualised ARM Kali attacker and emulated x86 targets on a shared, isolated 192.168.64.0/24 network.

No paid software, no Intel hardware, no cloud bill.

The phases of a pentest, walked end to end

A lab is only worth building if you run a real process through it, and hacking is not random. In the first post I laid out the seven stages a real engagement follows. This lab was my chance to walk all seven against a live target instead of reading about them, so here is what each one actually looked like.

1. Pre-engagement. The target is mine. It runs on a self-owned, isolated network with nothing else in scope, and I took a clean disk snapshot before touching anything so I could reset to a known state. On a client engagement this stage is the written permission and the rules of engagement. In a lab it is still the first thing you do, because "I own this and nobody else can reach it" is the whole reason the rest is legal.

2. Reconnaissance and 3. Scanning. nmap -sV mapped the open ports and the version behind each service. Two jumped out: an ancient file-transfer service on port 21, and an equally ancient SSH on 22. searchsploit then checked those versions against Kali's offline copy of Exploit-DB, and an OpenVAS scan produced the kind of severity-ranked report a client actually expects. The discipline here is the lesson: you let the tools surface the attack surface first, then you decide what is worth pursuing, rather than reaching straight for an exploit.

4. Gaining access and 5. Maintaining access. This is where the lab earns its keep, because I did it two completely different ways. The patient way and the instant way, which I will come back to in the next section. Once I was root I established persistence with a hidden account, so a foothold would survive even if the original hole were patched. In an ethical context that persistence is proof of impact, not a place to hide.

6. Covering tracks. A real attacker clears the logs to stay invisible. The ethical version is to study exactly how that is done, then describe it, because the defensive lesson is the valuable half. I truncated auth logs, web logs and shell history, and the point of writing it up is the opposite of hiding: if a server's auth.log can be wiped from the box itself, that is the argument for shipping logs off to a SIEM in real time, where the attacker cannot reach them.

7. Reporting. The exploit is not the product. The report is. I wrote the findings up twice over in effect: a plain executive summary a manager with no security background can act on, and the engineer-level detail underneath it, with a fix and a verification step for every finding. Stages two through six are indistinguishable from a breach. The first stage and the last, permission before and explanation after, are the entire difference between a penetration test and a crime with good documentation.

Two ways in, and why I did both

I deliberately walked the target two different routes, because they teach opposite lessons.

The manual path is the honest picture of how most real compromises start. I pointed Hydra at SSH with a small custom wordlist and it found four accounts where the password was just the username, which is one of the most common findings in real engagements. I logged in as an ordinary user, enumerated the box, and then climbed to administrator three separate ways: a sloppy sudo rule, an old nmap binary with an interactive mode that drops to a shell, and a world-writable /etc/passwd. Slower, noisier, and every step maps cleanly to a control that would have stopped it.

The automated path is the other extreme. Metasploit fired a single module at that old file-transfer service, which shipped with a backdoor baked into its source (vsftpd 2.3.4, CVE-2011-2523), and handed me a root session in seconds with no password at all. Fast, but brittle: it depends on one specific flaw being present and unpatched.

Both end in the same place, full control, which is exactly the point. One is a patient chain of small mistakes, the other a single unpatched service, and knowing both is the difference between running a tool and understanding what it does. Once you have root, the post-exploitation steps are identical, so in the guide the automated path just points back to the manual one for the shared work rather than repeating it.

Two independent paths to root: a slow manual credential chain and a one-shot automated backdoor, converging on the same full control.

What happens when you give a frontend developer an exploit

Here is the part I did not expect to enjoy as much as I did.

The loudest thing an attacker can do to a web server is deface it, replace the homepage with their own. It is the one action that guarantees incident response gets called, which is exactly why, in a real attack, it comes last: after persistence, after the credential theft, after the logs are wiped. By then the quiet work is done and the attacker is either leaving a calling card or does not care about being seen.

In real attacks that calling card is usually crude. A black background, some green text, a logo, done. But I did not come to security from nowhere. I came from building interfaces, and when I had root on a web server and a blank page to fill, I could not bring myself to paste in ugly HTML.

So the defacement became a small, slightly ridiculous demonstration of exactly the skill I was pivoting away from. I backed up the original page first, because preserving it is both professional practice and my rollback path, and then I replaced it with a page that types out "I AM LAWAL" letter by letter in a bold Orbitron display face with a neon glow, mirrors each character of my name backwards one at a time, closes the gap between "I" and "AM" so it resolves into "IAM", and settles into a compromise banner over CRT scanlines. No JavaScript. The entire sequence is @keyframes driven by per-character CSS custom properties, every beat tunable from a single block at the top, and it collapses gracefully to the finished state for anyone with reduced-motion turned on.

The pure-CSS defacement animation:

The pure-CSS defacement, no JavaScript: "I AM LAWAL" types out, each letter mirrors backwards, and the gap closes into "IAM" over a compromise banner.

It is, objectively, far too much effort for a proof-of-concept nobody asked to look nice. That is also the point. The defacement reads as a joke about my own background, but writing it was the same instinct that runs underneath the whole lab: wanting to know how the machine actually works. Re-enabling precisely the legacy SSH algorithms a 2008-era server needs without the one that newer OpenSSH has removed, choosing UTM because of a virtualise-versus-emulate distinction most guides skip, and hand-building a pure-CSS animation to announce a compromise are all the same habit. Understand the mechanism, and you find both where it breaks and how to fix it.

Then I restored the original page, because an ethical hacker undoes what he changed and hides nothing he found.

The four things that cost me the most time

A good lab guide is not the happy path, it is the gotchas. These four are the ones worth saving you.

  • UTM has no snapshot button. Coming from VirtualBox I went hunting for a Snapshots menu that does not exist in the GUI. The answer lives one layer down in QEMU's own disk tooling (qemu-img snapshot), and a crucial detail: UTM's "run without saving" discards only the VM's memory, not changes written to disk. If you deface the web server, "run without saving" will not bring it back. You restore the snapshot.
  • Modern SSH refuses to talk to a 2008-era server. Current OpenSSH disables the old key-exchange and host-key algorithms the target offers, so every SSH tool fails until you re-enable them in a host-scoped ~/.ssh/config block. Leave ssh-dss out, because newer OpenSSH has removed DSA entirely and including it throws a different error.
  • The privilege-escalation trick needs a space. The old SUID nmap route is ! sh with a space on this build. The no-space form silently does nothing. Small detail, twenty-minute time sink.
  • Old Ubuntu uses the admin group, not sudo. On Ubuntu 8.04 the sudo-granting group is admin, so -G sudo when creating a persistence account fails silently because that group does not exist yet. Always check: grep -E '^(sudo|admin)' /etc/group.

Anyone can run nmap. The value in a guide is the twenty-minute problems that the guides skip.

Every attack step has a defensive mirror

I wrote the whole engagement so that each offensive action ends with the control that would have stopped it, because that is the half that matters once you are back at work.

The seven findings are not seven unrelated problems. Default passwords, a backdoored service, trivial escalation, plaintext secrets, reversible password hashing, erasable logs, they mostly exist because the software was frozen in time on an operating system years past end of life. Fix the age and the neglect and whole classes of finding vanish at once. The defensive mirror writes itself from there: remove default accounts and require strong unique passwords with lockout and MFA, patch or remove the vulnerable service and keep a patch schedule, enforce least-privilege sudo and drop needless SUID bits, move secrets into a manager, use a modern slow hash with a locked-down shadow file, and ship logs off-box to a SIEM with tamper alerting.

Seven findings by severity and fix effort, all resolving to one root cause: an unsupported, unpatched operating system.

If you want to try it

The full step-by-step lab, the environment build, scanning, both attack paths, every gotcha, and the matching defensive lessons, is written up as a complete guide you can follow command by command, and the findings report I wrote from it shows the other half: the same engagement turned into something a manager and an engineer can both act on. The challenge target, DevGuru, is next.

If you are on an Apple Silicon Mac and you have been putting this off because the guides do not fit your hardware, they do not have to. Reach for UTM, keep the virtualise-versus-emulate split in your head, and you are past the part that stops most people. The rest is just process, and the process is the profession.

📰 Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.