├── .gitignore ├── LICENSE.txt ├── README.md ├── build.xml ├── clients └── client.py └── src └── burp ├── BurpExtender.java └── ClientHandler.java /.gitignore: -------------------------------------------------------------------------------- 1 | src/burp/I*.java 2 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Andras Veres-Szentkiralyi 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Collaborator gateway for Burp Suite 2 | =================================== 3 | 4 | Simple socket-based gateway to the Burp Collaborator. 5 | 6 | Protocol 7 | -------- 8 | 9 | - The gateway listens on TCP port 8452 of the loopback interface. 10 | - The protocol uses [MessagePack][1] serialization without additional framing. 11 | - Sending `0` or `1` to the gateway results in a string reply containing 12 | a new payload, which includes the Collaborator location if the number 13 | sent is `1`. 14 | - Sending `2` to the gateway results in a string reply containing the 15 | Collaborator location, this can be used to construct FQDNs if the 16 | payload was requested with the number `0`. 17 | - Sending a string to the gateway results in the string being interpreted 18 | as a payload and the gateway will reply with an array of the interactions 19 | with the specified payload. Elements of the array will be maps with 20 | string keys, the values will be almost always strings, except for 21 | DNS raw queries, HTTP requests and responses and client IP addresses, 22 | which will be represented as binaries. 23 | 24 | A sample client in Python is provided for easier understanding of the above 25 | in the `clients` directory of this repository, in depends only on the 26 | [msgpack-python][2] library, run `pip install msgpack-python` to install it. 27 | 28 | [1]: http://msgpack.org/ 29 | [2]: https://github.com/msgpack/msgpack-python 30 | 31 | Building 32 | -------- 33 | 34 | - Install the dependencies, in case of libraries, put the JARs into `lib` 35 | - Save the Burp Extender API from Burp and unpack it into `src` 36 | - Execute `ant`, and you'll have the plugin ready in `burp-collab-gw.jar` 37 | 38 | Dependencies 39 | ------------ 40 | 41 | - JDK 1.7+ (tested on OpenJDK `1.8.0_91`, Debian/Ubuntu package: `openjdk-7-jdk`) 42 | - Apache ANT (Debian/Ubuntu package: `ant`) 43 | - MessagePack for Java https://github.com/msgpack/msgpack-java/ 44 | 45 | License 46 | ------- 47 | 48 | The whole project is available under MIT license, see `LICENSE.txt`. 49 | -------------------------------------------------------------------------------- /build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /clients/client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import socket 4 | import msgpack 5 | 6 | class Client(object): 7 | def __init__(self): 8 | sock = socket.socket() 9 | sock.connect(('localhost', 8452)) 10 | self.sock = sock 11 | 12 | def get_collaborator_server_location(self): 13 | return self._exchange_packet(2) 14 | 15 | def generate_payload(self, include_location=True): 16 | return self._exchange_packet(int(include_location)) 17 | 18 | def fetch_collaborator_interactions_for(self, payload): 19 | return self._exchange_packet(payload) 20 | 21 | def _exchange_packet(self, data): 22 | s = self.sock 23 | s.send(msgpack.packb(data)) 24 | unpacker = msgpack.Unpacker() 25 | while True: 26 | unpacker.feed(s.recv(1)) 27 | for value in unpacker: 28 | return value 29 | 30 | 31 | if __name__ == '__main__': 32 | from urllib2 import urlopen 33 | c = Client() 34 | print repr(c.get_collaborator_server_location()) 35 | print repr(c.generate_payload(False)) 36 | payload = c.generate_payload(True) 37 | print repr(payload) 38 | print repr(urlopen('http://{0}/'.format(payload)).read()) 39 | print repr(c.fetch_collaborator_interactions_for(payload)) 40 | -------------------------------------------------------------------------------- /src/burp/BurpExtender.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | import java.util.*; 4 | import java.io.*; 5 | import java.net.*; 6 | import java.util.concurrent.CopyOnWriteArrayList; 7 | 8 | public class BurpExtender extends Thread implements IBurpExtender, IExtensionStateListener 9 | { 10 | private final static String NAME = "Collaborator gateway"; 11 | private IBurpCollaboratorClientContext ccc; 12 | private IExtensionHelpers helpers; 13 | private final List sockets = new CopyOnWriteArrayList(); 14 | 15 | @Override 16 | public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) 17 | { 18 | callbacks.setExtensionName(NAME); 19 | callbacks.registerExtensionStateListener(this); 20 | ccc = callbacks.createBurpCollaboratorClientContext(); 21 | helpers = callbacks.getHelpers(); 22 | start(); 23 | } 24 | 25 | @Override 26 | public void extensionUnloaded() { 27 | for (Closeable s : sockets) try { s.close(); } catch (IOException ioe) {} 28 | } 29 | 30 | @Override 31 | public void run() { 32 | try { 33 | ServerSocket ss = new ServerSocket(8452, 50, InetAddress.getLoopbackAddress()); 34 | sockets.add(ss); 35 | ss.setReuseAddress(true); 36 | while (true) { 37 | Socket cs = ss.accept(); 38 | sockets.add(cs); 39 | new ClientHandler(cs, ccc, helpers).start(); 40 | 41 | } 42 | } catch (SocketException se) { 43 | if (!se.getMessage().equals("Socket closed")) se.printStackTrace(); 44 | } catch (IOException ioe) { 45 | ioe.printStackTrace(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/burp/ClientHandler.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | import java.util.*; 4 | import java.io.*; 5 | import java.net.*; 6 | 7 | import org.msgpack.core.*; 8 | import org.msgpack.value.*; 9 | 10 | public class ClientHandler extends Thread { 11 | private final Socket s; 12 | private final IBurpCollaboratorClientContext ccc; 13 | private final IExtensionHelpers helpers; 14 | 15 | public ClientHandler(Socket s, IBurpCollaboratorClientContext ccc, 16 | IExtensionHelpers helpers) { 17 | this.s = s; 18 | this.ccc = ccc; 19 | this.helpers = helpers; 20 | } 21 | 22 | @Override 23 | public void run() { 24 | try { 25 | OutputStream os = s.getOutputStream(); 26 | final MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(s.getInputStream()); 27 | while (unpacker.hasNext()) { 28 | final Value v = unpacker.unpackValue(); 29 | final MessagePacker mbp = MessagePack.newDefaultPacker(os); 30 | switch (v.getValueType()) { 31 | case INTEGER: 32 | switch (v.asIntegerValue().toInt()) { 33 | case 0: mbp.packString(ccc.generatePayload(false)); break; 34 | case 1: mbp.packString(ccc.generatePayload(true)); break; 35 | case 2: mbp.packString(ccc.getCollaboratorServerLocation()); break; 36 | } 37 | mbp.flush(); 38 | break; 39 | case STRING: 40 | handleQuery(mbp, v.asStringValue().asString()); 41 | break; 42 | } 43 | } 44 | } catch (IOException ioe) { 45 | ioe.printStackTrace(); 46 | } 47 | } 48 | 49 | private void handleQuery(MessagePacker mbp, String payload) throws IOException { 50 | final List bci = 51 | ccc.fetchCollaboratorInteractionsFor(payload); 52 | mbp.packArrayHeader(bci.size()); 53 | for (IBurpCollaboratorInteraction interaction : bci) { 54 | final Map props = interaction.getProperties(); 55 | mbp.packMapHeader(props.size() - (props.containsKey("interaction_id") ? 1 : 0)); 56 | for (final Map.Entry entry : props.entrySet()) { 57 | final String k = entry.getKey(); 58 | if (k.equals("interaction_id")) continue; 59 | mbp.packString(k); 60 | final String v = entry.getValue(); 61 | if (k.equals("request") || k.equals("response") || k.equals("raw_query")) { 62 | final byte[] buf = helpers.base64Decode(v); 63 | mbp.packBinaryHeader(buf.length); 64 | mbp.writePayload(buf); 65 | } else if (k.equals("client_ip")) { 66 | final byte[] buf = InetAddress.getByName(v).getAddress(); 67 | mbp.packBinaryHeader(buf.length); 68 | mbp.writePayload(buf); 69 | } else { 70 | mbp.packString(v); 71 | } 72 | } 73 | } 74 | mbp.flush(); 75 | } 76 | } 77 | --------------------------------------------------------------------------------