Post

Proving Grounds Twiggy: Backport

Proving Grounds Twiggy: Backport

Imagined a forest.
It was a twig.

Lesson: Don’t overthink. Think in primitives.

Twiggy 1labdescrb

Twiggy (PG Lab) revolves around a backport regression. A fix from a newer version was applied to an older codebase, but architectural differences introduced unintended exposure. When code is transplanted without full context, assumptions break.

The machine is rated easy and community-rated intermediate. It should be easy. I made it harder than it needed to be.

Initial Enumeration

Sometimes -p- is necessary depending on scope. The first nmap scan did not reveal ports 4505 and 4506. A full port scan did.

2nmap

Ports 80 and 8000 were also open. The website had a lot of links to click on and offered nothing immediately useful.

webpage

Ports 4505 and 4506 were open. I was not familiar with them. Googled “port 4505 4506 ZeroMQ ZMTP 2.0”. Led to this stackoverflow link, hinting at SaltStack.

3goole1

A quick searchsploit saltstack confirmed public exploits.

4searchsploit

Inside the exploit script were two commented GitHub references. The first github link pointed to SaltStack checker scripts introduced as part of a security backport.

checker

Exploit usage options were listed.

5source

Removed comments in the top of exploit script to make it executable.

6saltypy

There was a requirement, pip3 install salt.

7saltreq

A missing module error appeared.

8pyyml

More ModuleNotFoundErrors followed, I installed each dependency as it appeared.

1
2
3
4
pip install pyyaml
pip install looseversion
pip install packaging
pip install tornado

A different error message surfaced, NameError name 'msgpack' is not defined. Same solution, install the missing module. Additional ModuleNotFoundErrors messages required packages.

1
2
3
pip install distro
pip install jinja2
pip install zmq

Finally the exploit script executed successfully! The root key was exposed, but not leverageable yet.

9installs

This is where I overthought the problem. The exploit usage referenced uploading a evilcrontab, which I interpreted as a direct hint to pivot through cron. Instead of pausing to think, I jumped straight into it.

11evilcrontab

I reviewed /etc/crontab to understand the format and confirmed I could overwrite it.

14verifycrontab

I attempted to trigger a reverse shell through crontab with an active listener. Nothing happened. I double-checked the syntax to ensure the command was correct.

13revshelcron

Every attempts returned Successfully scheduled job: ......

10schjob

At that point, I stepped back. Using -r, I confirmed I could read /etc/shadow. That should have been the pivot. Instead of chasing persistence or reverse shells, I already had root-level file access.

mkpasswd

The solution was simple: generate a SHA-512 hash with mkpasswd, append a new UID 0 user, and overwrite /etc/passwd and upload it. That was it.

upload proof

Remedies

  1. Harden backport and patch validation
    1. perform security regression testing before releasing backported fixes
    2. review authentication and authorization flows after modifying privileged components
    3. validate that new security features do not expose internal functions externally
  2. Restrict exposure of management services
    1. bind administrative services to localhost or private interfaces only
    2. restrict access to management ports (e.g., 4505/4506) using firewall rules
    3. enforce network segmentation between management services and untrusted networks
  3. Enforce strict authentication on control APIs
    1. require authentication and authorization checks before executing privileged functions
    2. avoid exposing diagnostic or checker endpoints without access control
    3. implement monitoring and logging for all administrative API interactions
This post is licensed under CC BY 4.0 by the author.