-
Notifications
You must be signed in to change notification settings - Fork 0
/
Invoke-RouteBuster.ps1
111 lines (106 loc) · 5.36 KB
/
Invoke-RouteBuster.ps1
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
<#
.SYNOPSIS
URLs for RESTful APIs often follow a pattern of <object>/<action> or <object>/<identifier>. We might be able to discover more services by taking the list of endpoints we have already identified and iterating through a wordlist to find valid actions or identifiers. We also need to keep in mind that web APIs might respond differently based on which HTTP request method we use.
For example, a GET request to /auth might return an HTTP 404 response, while a POST request to the same URL returns an HTTP 200 OK on a valid login or an HTTP 401 Unauthorized on an invalid login attempt.
This script returns the URI, HTTP Status Code per method, and the Response object to STDOUT.
Therefore you easily do something like:
$test = Invoke-RouteBuster -ActionList ./actions-only-valid.txt -Wordlist ./wordlist-only-valid.txt -Target http://apigateway:8000 -Methods get,post
$test[0]
.Description
The purpose of this script is to enumerate microservices built with Restful API's via HTTP verb tampering
.PARAMETER ActionList
The actions list. For Instance take /password/reset. reset would be the action
.PARAMETER Wordlist
The actions list. For Instance take /password/reset. password would be from our wordlist
.PARAMETER Target
The full target URI
.PARAMETER Methods
A list of HTTP methods to use, i.e get,post,put,patch,delete
.PARAMETER DisplayFilter
A list to filter responses based on HTTP status codes.
.PARAMETER Verbosity
Valid values are
v
vv
vvv
v: returns just the status code
vv: returns StatusCode, StatusDescription, RawContent, Headers
vvv: returns StatusCode, StatusDescription, Content, RawContent, Headers, RawContentLength
.EXAMPLE
PS> Invoke-RouteBuster -ActionList /usr/share/wordlists/dirb/small.txt -Wordlist endpoints-stripped.txt -Target http://apigateway:8000
.NOTES
Version: 1.0
Author: Zinhart
Purpose/Change: Created while studying for OSWE certification
#>
function Invoke-RouteBuster() {
param(
[Parameter(Mandatory=$true, HelpMessage='A list of actions to try against known endpoints.')]
[string]$ActionList,
[Parameter(Mandatory=$true, HelpMessage='Target URI.')]
[string]$Target,
[Parameter(Mandatory=$true, HelpMessage='A list of preferrable known endpoints.')]
[string]$Wordlist,
[Parameter(Mandatory = $false, HelpMessage = 'HTTP Methods to Use With Verb Tampering.')]
[ValidateSet("GET","POST","PUT","PATCH","DELETE",ErrorMessage="HTTP verb not one of (GET,POST,PUT,PATCH,DELETE)", IgnoreCase=$true)]
[String[]] $Methods = @('GET', 'POST'),
[Parameter(Mandatory = $false, HelpMessage = 'Filter displayed status codes.')]
[Int32[]] $DisplayFilter = @(204,401,403,404),
[Parameter(Mandatory = $false, HelpMessage = 'Varying levels of output.')]
[ValidateSet("v","vv","vvv",ErrorMessage="Verbosity not one of (v,vv,vvv)", IgnoreCase=$true)]
[String] $Verbosity= "v"
)
$actions_list = Get-Content $ActionList
$word_list = Get-Content $Wordlist
for($i = 0; $i -lt $word_list.Length; ++$i ) {
$outer_percent_complete = [System.Math]::Round($i / $word_list.Length * 100)
Write-Progress -Id 1 -Activity "Current Word: $($word_list[$i])" -Status "$outer_percent_complete% Complete:" -PercentComplete $outer_percent_complete;
for($j = 0; $j -lt $actions_list.Length; ++$j ) {
$url = "$($target)/$($word_list[$i])/$($actions_list[$j])"
$inner_percent_complete = [System.Math]::Round($j / $actions_list.Length * 100,2)
Write-Progress -ParentId 1 -Activity "Url: $url" -Status "$inner_percent_complete% Complete:" -PercentComplete $inner_percent_complete;
$map = [ordered]@{
'GET' = $null
'POST' = $null
'PUT' = $null
'PATCH' = $null
'DELETE' = $null
}
# make requests
foreach($method in $Methods) {
$resp = Invoke-WebRequest -Uri $url -Method $method -SkipHttpErrorCheck
$map[$method] = $resp
}
# ignore all of the null values in map, which effectively are methods not chosen
$filtered_responses = $map.GetEnumerator() | ? { $null -ne $_.Value }
# when there is only one verb force $filtered_responses to be an array
if($filtered_responses -isnot [array]){
$filtered_responses = @($filtered_responses)
}
# even though certain requests maybe not be valid it's still interesting to see how the reponses that were not filtered out in comparison
$include = $false
foreach($iter in $filtered_responses.GetEnumerator()) {
if( $iter.Value.StatusCode -notin $DisplayFilter) {
$include = $true
break;
}
}
if($include) {
$props = [ordered]@{
URI = $url
}
# We do this separately to enforce ordering
foreach($resp in $filtered_responses.GetEnumerator()) {
$resp_obj = "$($resp.Key.toUpper())"
if ($Verbosity -eq 'v') {$props["$resp_obj"] = ($resp.Value | Select-Object -property StatusCode).StatusCode}
if ($Verbosity -eq 'vv') {$props["$resp_obj"] = $resp.Value | Select-Object -property StatusCode, StatusDescription, RawContent, Headers}
if ($Verbosity -eq 'vvv') {$props["$resp_obj"] = $resp.Value | Select-Object -property StatusCode, StatusDescription, Content, RawContent, Headers, RawContentLength}
}
if($include) {
$result = New-Object -TypeName PSObject -Property $props
write-output $result
}
}
}
}
}