Skip to main content

A transport layer proxy which monitors the target server using ptrace

Project description

Ever wished you could just focus on data mutation and not fuzzing instrumentation? Fuzzmon let’s you do just that. It takes care of the instrumentation and tracking of fuzzed inputs and let’s you focus on building a good data model or fuzzing transform.

It’s an application layer proxy which attaches to the backend server to detect faults. It’s purpose is to record and proxy fuzzing traffic from clients, whilst gathering interesting crash information from the target using ptrace.

It tries to solve the problem of some network fuzzers: which input caused which crash? Since fuzzmon sees both the traffic in flight and the state of the application, it knows which input triggered which crash. It is also fast, since it does not require any form of fuzzing client/server synchronization.

Once a crash happens, it records interesting information as JSON blobs, and either exits or restarts the target process. The information within the JSON blob makes it easy to match the corresponding coredump. It also makes it easy to perform initial analysis on the recorded JSON.

Fuzzmon also provides fuzzreplay, which is able to replay a given JSON output against the server ## Installation #### From pypi

pip install fuzzmon

From github

git clone https://github.com/alexmgr/fuzzmon/

Fuzzmon usage

Get me started

Proxy all connections from tcp port 1234 to my target running on port 6666. Also start the process (vuln-server 6666)

» ./fuzzmon -d tcp:0.0.0.0:1234 -u tcp:127.0.0.1:6666 vuln-server 6666

Proxy all connections from udp port 1234 to my target running unix socket "/tmp/test". Also start the process (vuln-server /tmp/test). Follow fork() and execve()

» ./fuzzmon -f -e -d udp:0.0.0.0:1234 -u tcp:uds:/tmp/test vuln-server /tmp/test

Proxy all connections to tcp port 5555, restart process automatically on crash, but wait for 45 seconds before doing so. Also set logging to DEBUG, redirect target stdout/stderr and accept 10 client connections:

» ./fuzzmon -w 45 -l DEBUG -n -c 10 -u tcp:127.0.0.1:5555 vuln-server 5555

You get the idea. #### A bit more detail Fuzzmon requires only 2 mandatory arguments:

  1. The binary and arguments to run (or the pid (-p) to attach to)

  2. The upstream server (-u) to connect to. Since fuzzmon uses ptrace to monitor the target, both fuzzmon and the target server must run on the same host. The following protocols are supported:

  • IPv4 (TCP or UDP)

  • IPv6 (TCP or UDP)

  • Unix Domain Sockets (UDS) (TCP or UDP)

Detailed usage

usage: fuzzmon [-h] [-p PID] -u UPSTREAM [-d DOWNSTREAM] [-o OUTPUT]
               [-s SESSION] [-f] [-e] [-n] [-c CONNS] [-q | -w WAIT]
               [-l {DEBUG,INFO,WARNING,ERROR,CRITICAL}]
               ...

A proxy which monitors the backend application state

positional arguments:
  program               The command line to run and attach to

optional arguments:
  -h, --help            show this help message and exit
  -p PID, --pid PID     Attach running process specified by its identifier
  -u UPSTREAM, --upstream UPSTREAM
                        Upstream server to which to connect. Format is
                        proto:host:port or uds:proto:file for Unix Domain
                        Sockets
  -d DOWNSTREAM, --downstream DOWNSTREAM
                        IP and port to bind to, or UDS. Format is
                        proto:host:port or uds:proto:file. By default, listen
                        to TCP connections on port 25746
  -o OUTPUT, --output OUTPUT
                        Output folder where to store the crash metadata
  -s SESSION, --session SESSION
                        A session identifier for the fuzzing session
  -f, --fork            Trace fork and child process
  -e, --trace-exec      Trace execve() event
  -n, --no-stdout       Use /dev/null as stdout/stderr, or close stdout and
                        stderr if /dev/null doesn't exist
  -c CONNS, --conns CONNS
                        Number of downstream connections to accept in
                        parallel. Default is 1
  -q, --quit            Do not restart the program after a fault is detected.
                        Exit cleanly
  -w WAIT, --wait WAIT  How long to wait for before restarting the crashed
                        process
  -l {DEBUG,INFO,WARNING,ERROR,CRITICAL}, --log-level {DEBUG,INFO,WARNING,ERROR,CRITICAL}
                        Set the debugging level

Recording crashes

When a crash is detected, the following elements are extracted on compatible OS: * pip: pid * stream: packets causing the crash (as well as previous packets within the stream) in hex format. Each packet is tagged with the direction is has been seen in (“upstream” or “downstream”) * stream_count: stream count since beginning of fuzzing in hex format * history: history of previous streams (up to 10) * backtrace: backtrace * disassembly: instruction causing the crash, as well as the 10 following instructions * maps: memory mappings * stack: state of the stack * time: time of the crash * signal: signal * session_id: fuzzing session identifier

All output is written to a JSON blob which is identified by the process pid. Example output from a test run:

 » fuzzmon -q -n -l WARNING -f -e -s a_session_id -d tcp:0.0.0.0:1234 -u tcp:127.0.0.1:6666 vuln-server 6666
 ....
 » nc 127.0.0.1 1234
abcdefgh
1234567890
qwertyuiop
^C
 » nc 127.0.0.1 1234
i'm going to crash soon
it's coming
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 »
WARNING:DebuggingHooks:Received signal 11 from process: 13223. Gathering crash information
WARNING:DebuggingHooks:Propagating signal 11 to child process: 13223
WARNING:PtraceDbg:Detached from process: 13223
WARNING:PtraceDbg:Terminated process: 13223
WARNING:DebuggingHooks:Stopped debugger. Exiting now
WARNING:DebuggingHooks:Upstream server crashed!
WARNING:Downstream:Upstream server appears to be dead: <socket._socketobject object at 0x1bfb600>
WARNING:Downstream:Stopped downstream server

 » cat metadata/14612.json
{
    "stream": [
        [
            "downstream",
            "547970652051554954206f6e2061206c696e6520627920697473656c6620746f20717569740a"
        ],
        [
            "upstream",
            "69276d20676f696e6720746f20637261736820736f6f6e0a"
        ],
        [
            "downstream",
            "6e6f6f73206873617263206f7420676e696f67206d27690a"
        ],
        [
            "upstream",
            "6974277320636f6d696e670a"
        ],
        [
            "downstream",
            "676e696d6f6320732774690a"
        ],
        [
            "upstream",
            "41414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424343434343434343434343434343434343434343434343434343434343434343434343434343434344444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444440a"
        ]
    ],
    "backtrace": {
        "0x400ea1L": [
            "???",
            []
        ]
    },
    "pid": 13223,
    "registers": {
        "gs": "0x0000000000000000",
        "gs_base": "0x0000000000000000",
        "rip": "0x0000000000400ea1",
        "rdx": "0x0000000000000000",
        "fs": "0x0000000000000000",
        "cs": "0x0000000000000033",
        "rax": "0x00007fffd7ab84c0",
        "rsi": "0x0000000000000000",
        "rcx": "0x00000000000000fb",
        "es": "0x0000000000000000",
        "r14": "0x0000000000000000",
        "r15": "0x0000000000000000",
        "r12": "0x0000000000400a80",
        "r13": "0x00007fffd7ab8850",
        "r10": "0x0000000000000000",
        "r11": "0x00007f26a52e09a8",
        "orig_rax": "0xffffffffffffffff",
        "fs_base": "0x00007f26a57eb700",
        "rsp": "0x00007fffd7ab8778",
        "ds": "0x0000000000000000",
        "rbx": "0x0000000000000000",
        "ss": "0x000000000000002b",
        "r8": "0x0000000000000074",
        "r9": "0x0000000000c00000",
        "rbp": "0x4141414141414141",
        "eflags": "0x0000000000010206",
        "rdi": "0x00007fffd7ab86b4"
    },
    "disassembly": {
        "0x400ea1L": "RET",
        "0x400ea2L": "PUSH RBP",
        "0x400ea3L": "MOV RBP, RSP",
        "0x400ea6L": "SUB RSP, 0x140",
        "0x400eadL": "MOV [RBP-0x134], EDI",
        "0x400eb3L": "MOV [RBP-0xa0], RDX",
        "0x400ebaL": "MOV [RBP-0x98], RCX",
        "0x400ec1L": "MOV [RBP-0x90], R8",
        "0x400ec8L": "MOV [RBP-0x88], R9",
        "0x400ecfL": "TEST AL, AL"
    },
    "stack": {
        "STACK": "0x00007fffd7a99000-0x00007fffd7aba000 => [stack] (rwxp)",
        "STACK-40": "0x4242424242424242",
        "STACK-32": "0x4242424242424242",
        "STACK-24": "0x4142424242424242",
        "STACK-16": "0x4141414141414141",
        "STACK -8": "0x4141414141414141",
        "STACK +0": "0x4141414141414141",
        "STACK +8": "0x4141414141414141",
        "STACK+16": "0x4141414141414141",
        "STACK+24": "0x4141414141414141",
        "STACK+32": "0x4141414141414141",
        "STACK+40": "0x4141414141414141"
    },
    "stream_count": 1,
    "signal": "SIGSEGV",
    "session_id": "a_session_id",
    "maps": [
        [
            [
                "0x0000000000400000",
                "0x0000000000402000"
            ],
            "vuln-server",
            "r-xp"
        ],
        [
            [
                "0x0000000000601000",
                "0x0000000000602000"
            ],
            "vuln-server",
            "rwxp"
        ],
        [
            [
                "0x000000000162e000",
                "0x000000000164f000"
            ],
            "[heap]",
            "rwxp"
        ],
        [
            [
                "0x00007f26a525d000",
                "0x00007f26a53df000"
            ],
            "/lib/x86_64-linux-gnu/libc-2.13.so",
            "r-xp"
        ],
        [
            [
                "0x00007f26a53df000",
                "0x00007f26a55df000"
            ],
            "/lib/x86_64-linux-gnu/libc-2.13.so",
            "---p"
        ],
        [
            [
                "0x00007f26a55df000",
                "0x00007f26a55e3000"
            ],
            "/lib/x86_64-linux-gnu/libc-2.13.so",
            "r-xp"
        ],
        [
            [
                "0x00007f26a55e3000",
                "0x00007f26a55e4000"
            ],
            "/lib/x86_64-linux-gnu/libc-2.13.so",
            "rwxp"
        ],
        [
            [
                "0x00007f26a55e4000",
                "0x00007f26a55e9000"
            ],
            "",
            "rwxp"
        ],
        [
            [
                "0x00007f26a55e9000",
                "0x00007f26a5609000"
            ],
            "/lib/x86_64-linux-gnu/ld-2.13.so",
            "r-xp"
        ],
        [
            [
                "0x00007f26a57ea000",
                "0x00007f26a57ed000"
            ],
            "",
            "rwxp"
        ],
        [
            [
                "0x00007f26a5805000",
                "0x00007f26a5808000"
            ],
            "",
            "rwxp"
        ],
        [
            [
                "0x00007f26a5808000",
                "0x00007f26a5809000"
            ],
            "/lib/x86_64-linux-gnu/ld-2.13.so",
            "r-xp"
        ],
        [
            [
                "0x00007f26a5809000",
                "0x00007f26a580a000"
            ],
            "/lib/x86_64-linux-gnu/ld-2.13.so",
            "rwxp"
        ],
        [
            [
                "0x00007f26a580a000",
                "0x00007f26a580b000"
            ],
            "",
            "rwxp"
        ],
        [
            [
                "0x00007fffd7a99000",
                "0x00007fffd7aba000"
            ],
            "[stack]",
            "rwxp"
        ],
        [
            [
                "0x00007fffd7ad4000",
                "0x00007fffd7ad6000"
            ],
            "[vvar]",
            "r--p"
        ],
        [
            [
                "0x00007fffd7ad6000",
                "0x00007fffd7ad8000"
            ],
            "[vdso]",
            "r-xp"
        ],
        [
            [
                "0xffffffffff600000",
                "0xffffffffff601000"
            ],
            "[vsyscall]",
            "r-xp"
        ]
    ],
    "time": 1437179338.290207,
    "history": [
        [
            [
                "downstream",
                "547970652051554954206f6e2061206c696e6520627920697473656c6620746f20717569740a"
            ],
            [
                "upstream",
                "61626364656667680a"
            ],
            [
                "downstream",
                "68676665646362610a"
            ],
            [
                "upstream",
                "313233343536373839300a"
            ],
            [
                "downstream",
                "303938373635343332310a"
            ],
            [
                "upstream",
                "71776572747975696f700a"
            ],
            [
                "downstream",
                "706f69757974726577710a"
            ]
        ]
    ]
}

By setting the proper sysctls, you can record the pid in the coredump name. You should then have all the information needed to automatically triage your crashes!

Fuzzreplay usage

fuzzreplay allows to replay crashes recorded by fuzzmon. Provide the target server address as well as the JSON dump, and fuzzreplay will reproduce the crash. The last stream can be replayed or all streams (-a) in history can be replayed. That way it is possible to reproduce crashes which take a specific set of requests to trigger. ####Get me started Just provide the target upstream server (-u) and the JSON to replay. Note that you can replay crashes directly to the server, or through fuzzmon if you wish to leverage application layer translation

./fuzzreplay tests/integration/replay-test.json -a -u tcp:10.212.223.52:1234
WARNING:root:Sleeping for 3 seconds before sending alive test
WARNING:root:Performing alive test against target
Replay of stream 0 did not crash the server
WARNING:root:Sleeping for 3 seconds before sending alive test
WARNING:root:Performing alive test against target
WARNING:root:Stream replay failed: [Errno 61] Connection refused
Successfully crashed server by replaying stream 1:
[[u'downstream', u'547970652051554954206f6e2061206c696e6520627920697473656c6620746f20717569740a'], [u'upstream', u'3131313131313131313131313131313131323332343334330a'], [u'downstream', u'3334333432333231313131313131313131313131313131310a'], [u'upstream', u'333235313435333235323335323532333534323532330a'], [u'downstream', u'333235323435333235323533323532333534313532330a'], [u'upstream', u'414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434444444444444444444444444444444444444444444444444444444444444444444444444444444444444545454545454545454545454545454545454545454545454545454545454545454545454545450a']]

Detailed usage

usage: fuzzreplay [-h] -u UPSTREAM [-a] [-w WAIT]
                  [-l {DEBUG,INFO,WARNING,ERROR,CRITICAL}]
                  filename

Replay streams captured by fuzzmon

positional arguments:
  filename              JSON test case to replay

optional arguments:
  -h, --help            show this help message and exit
  -u UPSTREAM, --upstream UPSTREAM
                        Upstream server to which to connect. Format is
                        proto:host:port or uds:proto:file for Unix Domain
                        Sockets
  -a, --all             Also replay all packets from history
  -w WAIT, --wait WAIT  Time to wait before performing alive test. Default is
                        3 seconds
  -l {DEBUG,INFO,WARNING,ERROR,CRITICAL}, --log-level {DEBUG,INFO,WARNING,ERROR,CRITICAL}
                        Set the debugging level

Project details


Release history Release notifications | RSS feed

This version

0.4

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fuzzmon-0.4.tar.gz (15.5 kB view details)

Uploaded Source

File details

Details for the file fuzzmon-0.4.tar.gz.

File metadata

  • Download URL: fuzzmon-0.4.tar.gz
  • Upload date:
  • Size: 15.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No

File hashes

Hashes for fuzzmon-0.4.tar.gz
Algorithm Hash digest
SHA256 becb51ac4c74030df436be0fa417fdc02c977c96f7268ae905e4b890a51e1411
MD5 69982644945c740d558b319dc8eacba9
BLAKE2b-256 d7917af8da8dc6da355e168c8ca7263770a801aace51bfd1b98b3952584356c3

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page