├── README.md └── unpack-burp.php /README.md: -------------------------------------------------------------------------------- 1 | # unpack-burp 2 | 3 | This is a small tool created by [Frans Rosén](https://twitter.com/fransrosen). For unpacking base64:ed "Save items"-content from Burp. 4 | 5 | This allows you to extract certain parts of the requests which allows you do to things like: 6 | 7 | * Take all request to target X and extract all parameters from the request body 8 | * Get the request body for all requests that responded with header X 9 | * Collect all browsed javascript-files and merge them locally into one large JS to then prettify them together. 10 | * Create wordlists based on all responses and/or request params/headers 11 | 12 | The JSON-option below is helpful if you need to create more complex logic later on in the pipeline, such as "If request header X then extract response body param Y". The regular plain-text outputs are simpler if you are just looking for extracting the raw data for additional grep:ing or similar. 13 | 14 | ### Usage 15 | 16 | In Burp, in the search-popups as well as the proxy you are able to select multiple requests and select "Save items". This will save a XML-file with request and response as base64. Make sure you have the "Base64-encode requests and responses"-checkbox selected. 17 | 18 | ``` 19 | php unpack-burp.php [reqb,resb,...] 20 | ``` 21 | 22 | Options, can be combined using a comma-separated list (ie `reqp,resb`): 23 | 24 | * `reqp` - Request path (ie: `GET / HTTP/1.1`) 25 | * `reqh` - Request headers (excluding method+path) 26 | * `reqb` - Request body 27 | * `resc` - Response code (ie: `HTTP/1.1 200 OK`) 28 | * `resh` - Response headers (excluding status code) 29 | * `resb` - Response body (default) 30 | * `jsonh` - Request/Response headers in a compact JSON as `reqp` `reqh`, `resc` and `resh` 31 | * `jsonb` - Request/Response body in a compact JSON as `reqb` and `resb` 32 | * `jsonreq` - Request in a compact JSON as `reqp`, `reqh` and `reqb` 33 | * `jsonres` - Response in a compact JSON as `resc`, `resh` and `resb` 34 | * `all` - compact JSON with all props from above 35 | 36 | ### Examples: 37 | 38 | Request and response headers: 39 | 40 | ``` 41 | php unpack-burp.php target.xml reqh,resh 42 | 43 | POST / HTTP/1.1 44 | Host: example.com 45 | Content-Length: 96 46 | Sec-Ch-Ua: "Chromium";v="118", "Google Chrome";v="118", "Not=A?Brand";v="99" 47 | Sec-Ch-Ua-Mobile: ?0 48 | User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_19_7) AppleWebKit/531.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/531.36 49 | Content-Type: application/json 50 | Accept: */* 51 | HTTP/1.1 200 OK 52 | Access-Control-Allow-Origin: * 53 | Content-Type: application/json 54 | Content-Length: 31546 55 | Date: Mon, 06 Nov 2023 22:58:24 GMT 56 | Connection: close 57 | 58 | POST / HTTP/1.1 59 | Host: example.com 60 | HTTP/1.1 200 OK 61 | Access-Control-Allow-Origin: * 62 | ... 63 | ``` 64 | 65 | Request and response body: 66 | 67 | ``` 68 | php unpack-burp.php target.xml reqb,resb 69 | {"requestData":{}} 70 | {"data":{"items":[{... 71 | 72 | body=xxx¶m_id=111 73 | Test 74 | 75 | body=xxx¶mId=222 76 | Test 77 | ... 78 | ``` 79 | 80 | Request and response headers as JSON: 81 | 82 | ``` 83 | php unpack-burp.php target.xml jsonh 84 | {"reqp":"POST / HTTP/1.1","reqh":"Host: example.com\r\nContent-Length: 96\r\nSec-Ch-Ua: \"Chromium\";v=\"118\", \"Google Chrome\";v=\"118\", \"Not=A?Brand\";v=\"99\"\r\nSec-Ch-Ua-Mobile: ?0\r\n...","reqb":"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: 31546\r\nDate: Mon, 06 Nov 2023 22:58:34 GMT\r\nConnection: close"} 85 | {"reqp":"POST / HTTP/1.1","reqh":"Host: example2.com\r\nContent-Length: 96\r\nSec-Ch-Ua: \"Chromium\";v=\"118\", \"Google Chrome\";v=\"118\", \"Not=A?Brand\";v=\"99\"\r\nSec-Ch-Ua-Mobile: ?0\r\n...","reqb":"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: 31546\r\nDate: Mon, 06 Nov 2023 22:58:34 GMT\r\nConnection: close"} 86 | ``` 87 | 88 | Use it to get a list of all unique response headers from a bunch of requests: 89 | 90 | ``` 91 | php unpack-burp.php target.xml resh | \ 92 | cut -d ":" -f 1 | sort -uf 93 | Access-Control-Allow-Credentials 94 | Access-Control-Allow-Headers 95 | Access-Control-Allow-Methods 96 | Access-Control-Allow-Origin 97 | Access-Control-Expose-Headers 98 | Connection 99 | Content-Length 100 | Content-Type 101 | Date 102 | Server 103 | Strict-Transport-Security 104 | Vary 105 | X-Path 106 | ``` 107 | 108 | Or, list all paths where `Access-Control-Allow-Origin`-header is returned: 109 | 110 | ``` 111 | php unpack-burp.php target.xml jsonh | \ 112 | jq -r '. | select(.resh | test("\naccess-control-allow-origin:"; "i")) | .reqp' | \ 113 | cut -d ' ' -f 2 | sort -u 114 | /api/items 115 | /api/users 116 | ``` 117 | -------------------------------------------------------------------------------- /unpack-burp.php: -------------------------------------------------------------------------------- 1 | #', $item, $matches); 18 | preg_match_all('##', $item, $reqmatches); 19 | preg_match_all('##', $item, $urlmatches); 20 | if (!$matches[1]) { return; } 21 | foreach ($matches[1] as $key => $res) { 22 | $req = base64_decode($reqmatches[1][$key]); 23 | $req = explode("\r\n\r\n", $req); 24 | $reqheaders = array_shift($req); 25 | $reqheaders = explode("\r\n", $reqheaders); 26 | $reqline = array_shift($reqheaders); 27 | $reqiheaders = []; 28 | foreach($reqheaders as $headerval) { 29 | $headerval = explode(': ', $headerval); 30 | $reqhkey = strtolower(trim(array_shift($headerval))); 31 | $reqiheaders[$reqhkey] = implode(': ', $headerval); 32 | } 33 | $reqpathpart = explode(' ', $reqline); 34 | $reqmethod = array_shift($reqpathpart); 35 | array_pop($reqpathpart); 36 | $reqpath = implode(' ', $reqpathpart); 37 | $reqheaders = implode("\r\n", $reqheaders); 38 | $req = implode("\r\n\r\n", $req); 39 | $res = base64_decode($res); 40 | $res = explode("\r\n\r\n", $res); 41 | $resheaders = array_shift($res); 42 | $resheaders = explode("\r\n", $resheaders); 43 | $rescode = array_shift($resheaders); 44 | $resiheaders = []; 45 | foreach($resheaders as $headerval) { 46 | $headerval = explode(': ', $headerval); 47 | $reshkey = strtolower(trim(array_shift($headerval))); 48 | $resiheaders[$reshkey] = implode(': ', $headerval); 49 | } 50 | $resheaders = implode("\r\n", $resheaders); 51 | $res = implode("\r\n\r\n", $res); 52 | $rawoutput = preg_match('#re[qs][a-z]#', $extract); 53 | 54 | if (strpos($extract, 'reqp') !== false) { 55 | echo "\n"; 56 | echo $reqpath; 57 | } 58 | if (strpos($extract, 'reqm') !== false) { 59 | echo "\n"; 60 | echo $reqmethod; 61 | } 62 | if (strpos($extract, 'reql') !== false) { 63 | echo "\n"; 64 | echo $reqline; 65 | } 66 | if (strpos($extract, 'reqh') !== false) { 67 | echo "\n"; 68 | echo $reqheaders; 69 | } 70 | if (strpos($extract, 'reqb') !== false) { 71 | echo "\n"; 72 | echo $req; 73 | } 74 | if (strpos($extract, 'resc') !== false) { 75 | echo "\n"; 76 | echo $rescode; 77 | } 78 | if (strpos($extract, 'resh') !== false) { 79 | echo "\n"; 80 | echo $resheaders; 81 | } 82 | if (strpos($extract, 'resi') !== false) { 83 | echo "\n"; 84 | echo $resiheaders; 85 | } 86 | if (strpos($extract, 'resb') !== false) { 87 | echo "\n"; 88 | echo $res; 89 | } 90 | $json = []; 91 | if (strpos($extract, 'jsonh') !== false || strpos($extract, 'all') !== false) { 92 | $json['reqm'] = $reqmethod; 93 | $json['reqp'] = $reqpath; 94 | $json['reql'] = $reqline; 95 | $json['reqh'] = $reqheaders; 96 | $json['reqi'] = $reqiheaders; 97 | $json['resc'] = $rescode; 98 | $json['resh'] = $resheaders; 99 | $json['resi'] = $resiheaders; 100 | } 101 | if (strpos($extract, 'jsonb') !== false || strpos($extract, 'all') !== false) { 102 | $json['reqb'] = $req; 103 | $json['resb'] = $res; 104 | } 105 | if (strpos($extract, 'jsonreq') !== false) { 106 | $json['reqm'] = $reqmethod; 107 | $json['reqp'] = $reqpath; 108 | $json['reql'] = $reqline; 109 | $json['reqh'] = $reqheaders; 110 | $json['reqi'] = $reqiheaders; 111 | $json['reqb'] = $req; 112 | } 113 | if (strpos($extract, 'jsonres') !== false) { 114 | $json['resc'] = $rescode; 115 | $json['resh'] = $resheaders; 116 | $json['resi'] = $resiheaders; 117 | $json['resb'] = $res; 118 | } 119 | if ($json) { 120 | if ($rawoutput) { 121 | echo "\n"; 122 | } 123 | echo json_encode($json, JSON_UNESCAPED_SLASHES); 124 | } 125 | print("\n"); 126 | print("\n"); 127 | } 128 | } 129 | 130 | $handle = fopen($file, "r"); 131 | if ($handle) { 132 | $currentitem = ''; 133 | while (($line = fgets($handle)) !== false) { 134 | if (strpos($line, ' ') === 0) { 135 | handleItem($currentitem, $extract); 136 | $currentitem = ''; 137 | continue; 138 | } 139 | $currentitem .= $line; 140 | } 141 | handleItem($currentitem, $extract); 142 | fclose($handle); 143 | } 144 | --------------------------------------------------------------------------------