How to use the Request Rewrite plugin to modify requests with Mayhem for API

Welcome to Mayhem Tips and Tricks series! Our goal is to help you learn about the best features of Mayhem in small bite-size chunks. Today, we’ll show you how to monitor fuzzed requests generated by Mayhem for API using the Request Rewrite plugin.

So you’ve prepared your API for fuzzing and passed your specification and all of your headers to mAPI, but something isn’t quite working the way you had hoped. The first thing you should do is check the API logs. It’s worth noting that there are many ways to inspect traffic between your API and Mayhem. While mAPI itself logs traffic for failing requests, one of the easiest ways to capture all traffic is to use tcpdump, or Wireshark.

In this post, we’ll use an example echo server provided by the grpc-web base: grpc-web/net/grpc/gateway/examples/echo at master · grpc/grpc-web · GitHub

First, let’s start the server:

$ docker run -d --rm -p 9090:9090 --name node-server grpcweb/node-server
$ docker run -d --rm -p 8080:8080 --name envoy-proxy --link node-server:node-server grpcweb/envoy
$ docker run -d --rm -p 8081:8081 --name commonjs-client grpcweb/commonjs-client

There are three parts to this server: the node backend, the grpc-web proxy (envoy), and the commonjs-client (the webpage we see when we connect). Let’s go to localhost:8081/echotest.html and see it in action.

Neat, it works. Now, let’s naively try and fuzz this target. Since the JS client is just the front end, we need to point mAPI to the actual API, at port 8080, (we could have also figured this out by looking at the port traffic):

$ mapi run grpc-web-echo-example 10 --url http://localhost:8080 "../net/grpc/gateway/examples/echo/echo.swagger.json" --har out.har

I added the .har output just in case something goes wrong. Oh no, something went wrong!

Alright, let’s check that .har output and see what’s going on:

Hmm, 415. According to the internet, that means Unsupported Media Type. But why? Well, if we look at our headers, we also notice that we’re sending a content-type of “application/json”. However, if I look at the same network capture I shared above:

It looks like a successful connection is sending a grpc-web-text content type. That shouldn’t be hard to fix!

First, you’ll want to clone the Mayhem for API examples Github Repository (we’ll be using Python for this example):

$ git clone https://github.com/ForAllSecure/mapi-examples.git
$ cd mapi-examples/plugins/python-auth-plugin/

Then, let’s modify the plugin.py to modify our headers. Open up the file src/plugin.py in your favorite text editor, and edit your Rewrite() function to look like this:

def Rewrite(self, request, context):
   iter = 0
   for h in request.headers:
      if h.name == b'content-type':
         request.headers[iter].value = b'application/grpc-web-text'
      iter += 1

Here, we’re looking through all of the request headers in our message, and if we notice that any of them say ‘content-type’, we replace the value of that header with ‘application/grpc-web-text’.

Next, let’s build and run our plugin:

$ docker build -t mapi-python-rewrite-plugin .
$ docker run -it --rm --name mapi-plugin -p 9001:9001 mapi-python-rewrite-plugin

Then, in another terminal, lets run mAPI with the plugin:

$ mapi run grpc-web-echo-example 10 --url http://localhost:8080 "../net/grpc/gateway/examples/echo/echo.swagger.json" --har out.har --experimental-rewrite-plugin http://localhost:9001

Better! But we’re still getting a lot of 400s. Let’s look at our .har again

Ah, so it’s expecting base64 data. That shouldn’t be too hard either. Let’s modify our plugin.py again. First, we’ll import a base64 encoding/decoding library:

from base64 import b64encode

Then, let’s encode the request body:

def Rewrite(self, request, context):
   iter = 0
   for h in request.headers:
      if h.name == b'content-type':
         request.headers[iter].value = b'application/grpc-web-text'
      iter += 1
   newBody = b64encode(request.body)
   request.body = newBody
   return request

Ok, let’s try this one more time:

$ docker build -t mapi-python-rewrite-plugin .
$ docker run -it --rm --name mapi-plugin -p 9001:9001 mapi-python-rewrite-plugin

$ mapi run grpc-web-echo-example 10 --url http://localhost:8080 "../net/grpc/gateway/examples/echo/echo.swagger.json" --har out.har --experimental-rewrite-plugin http://localhost:9001

That looks much better. Now, there’s more to do here (gRPC-web by default returns 200s even if the grpc-code is not “all good”; we should “classify” those response codes somehow…), but that’s for another article.

And that’s it! Now you’ve got your request content being converted to b64 encoded grpc-web-text via the Request Rewrite plugin. There’s a lot more that can be done with the plugin - this is just to get you started using it!

We hope that you found this Tips and Tricks article helpful. If you have any questions, please email us at support@forallsecure.com.