In this Sherlock, players will investigate a compromised jumpbox where an attacker gained access via an authentication bypass vulnerability, allowing them to reach an internal subnet.
An attacker reached a developer jumpbox by abusing an OpenSSH authentication bypass that affects musl-based systems without PAM, logging in as a service account whose password hash is locked. From that shell they swept the internal developer subnet with a netcat loop, then ran a remote setup script that dropped a staging file in /tmp. The file was posted to an external HTTPS endpoint with wget and shredded afterwards. The whole story sits in the jumpbox’s messages syslog and the service account’s shell history; there are no per-command audit logs.
SSHole/ → a copy of the jumpbox root (etc/, var/log/, home/). Browse with cat and grepvar/log/messages → BusyBox syslog; sshd authentication events with no yearhome/adminsvc/.ash_history → the abused account’s shell history, with no timestampsTimestamp note:
messageshas no year or timezone. The year comes from the case timeline; the answer format isYYYY-MM-DD hh:mm:ss, so prepend the year and keep the log’s clock as is.
etc/os-release is the quickest source. The pretty name and VERSION_ID give distribution and version in the exact shape the format mask asks for. Alpine matters later: it ships musl and BusyBox, which explains why the host has no PAM and why logs land in a single messages file.
cat SSHole/etc/os-release
The telltale in the evidence is a successful password login for an account that cannot have a valid password. adminsvc has * in the hash field of etc/shadow, so no password can match, yet messages shows Accepted password for it. A password login accepted against a locked hash on a musl/no-PAM OpenSSH points to the SSHole bypass. The CVE ID itself was not read from an artifact: it comes from the vendor advisory at https://www.stepsecurity.io/blog/cve-2026-123158-sshhole-openssh-musl-password-bypass, which matches the behaviour seen here.
grep '^adminsvc' SSHole/etc/shadow
Search messages for sshd-session authentication lines from the external client. A Failed password for adminsvc at 11:27:05 is followed three seconds later by Accepted password for the same account, same source and port. The accepted line is the exploitation moment.
grep -E 'Failed|Accepted' SSHole/var/log/messages
Gotcha:
rootalso logs in from192.168.72.131several times that day. That is a different source and a different account, not the bypass.
Same line as Q3. The format mask asks for the username without a domain, so take the account name as sshd logged it.
grep 'Accepted password' SSHole/var/log/messages
The jumpbox logs record that a password was accepted, never the password itself, so the trigger value cannot be read from messages, the shell history or anything else in the triage. What the evidence does give is the mechanism. musl’s crypt() fails on a password over 256 characters and returns * instead of a hash. A locked account has * in the hash field of etc/shadow, so sshd compares the two, finds an exact match and lets the login through. That is why adminsvc authenticated with a locked hash.
Note: This answer is not in the provided files. It came from outside research on the CVE and was confirmed by HTB accepting it, not derived from the artifacts.
With a shell as adminsvc, read home/adminsvc/.ash_history. The second entry is a one-line loop that runs nc -zvw 1 over all ports of every host in 192.168.18.0/24 and keeps only the lines containing succeeded or open. Right after it the attacker edits and reads scanreport.txt, which is where that output was kept.
cat SSHole/home/adminsvc/.ash_history
Tip: Copy the line exactly as it appears in the history, including the
{1..254}brace range and the quoting in thegrep. The format mask matches the shell syntax.
Later in the same history the attacker runs a remote script through bash <(wget -qO- ...), lists /tmp and /tmp/.devenv, then posts that file with wget --post-file to an external HTTPS endpoint and runs shred -u on it. The POST target is the exfiltration URI. The staged file name and the shred are a deliberate clean-up, so the history is the only place the destination survives.
grep -E 'post-file|shred' SSHole/home/adminsvc/.ash_history
| Phase | Action |
|---|---|
| Initial Access | SSH password login as adminsvc accepted despite a locked hash, via the musl OpenSSH bypass |
| Discovery | nc port sweep of the internal 192.168.18.0/24 developer subnet, results saved to scanreport.txt |
| Execution | Remote setup.sh fetched with wget and run through bash |
| Collection | Staging file left in /tmp/.devenv |
| Exfiltration | File posted to an external HTTPS endpoint with wget --post-file |
| Defense Evasion | Staging file destroyed with shred -u |
| Type | Value |
|---|---|
| Account | adminsvc |
| Source IP (bypass login) | 192.168.72[.]1 |
| URL (exfiltration) | hxxps[://]devv[.]coding[.]eu/process |
| URL (script) | hxxps[://]raw[.]githubusercontent[.]com/papinyurii33/devscripts/refs/heads/main/setup.sh |
| File | /tmp/.devenv |
| File | scanreport.txt |
| Technique | ID | Description |
|---|---|---|
| Exploit Public-Facing Application | T1190 | OpenSSH authentication bypass on the jumpbox |
| Valid Accounts: Local Accounts | T1078.003 | Login as adminsvc |
| Network Service Discovery | T1046 | nc sweep of the internal subnet |
| Command and Scripting Interpreter: Unix Shell | T1059.004 | bash <(wget ...) of a remote script |
| Ingress Tool Transfer | T1105 | setup.sh pulled from GitHub |
| Exfiltration Over Alternative Protocol | T1048.003 | wget --post-file to an external HTTPS endpoint |
| Indicator Removal: File Deletion | T1070.004 | shred -u on the staging file |
Patch OpenSSH on musl and no-PAM hosts. The bypass worked against an account with a locked hash, so password policy and account locking gave no protection. Update the package and, where possible, set PasswordAuthentication no so a password-length bug cannot grant a session at all.
Alert on a success that follows a failure for an account that should never log in. Failed password then Accepted password three seconds apart for a service account with a * hash is an impossible event. A correlation rule on logins to accounts with locked hashes would have caught this on the first attempt.
A jumpbox needs to be a dead end. nc could sweep every port of the developer subnet because the host had unrestricted routing into it. Segmentation with per-destination allow lists limits what a compromised jumpbox can reach.
Ship shell history and egress logs off the host. .ash_history was the only record of the scan and the upload, and it carries no timestamps. Command auditing forwarded to a central store, plus egress filtering on a box that has no reason to POST to arbitrary HTTPS hosts, would have given dates and a block.
A single oversized-password login turned a locked service account into a shell on the jumpbox, and the attacker used it to map the developer network and post a file out before shredding it. The authentication logs show the impossible login clearly; the gap was that nobody was looking for it and the box could reach everywhere.