Projects STRLCPY Taipan Commits e0d1ee25
🤬
  • Src/10passwords.txt
    Diff is too large to be displayed.
  • ■ ■ ■ ■ ■ ■
    Src/ES.Taipan.Crawler/CrawlerLogger.fs
    skipped 88 lines
    89 89   [<Log(13, Message = "Start re-crawling", Level = LogLevel.Informational)>]
    90 90   member this.StartReCrawling() =
    91 91   this.WriteLog(13, [||])
     92 + 
     93 + [<Log(14, Message = "Crawler navigation scope: {0}", Level = LogLevel.Informational)>]
     94 + member this.CrawlerScope(scope: NavigationScope) =
     95 + this.WriteLog(14, [|scope|])
  • ■ ■ ■ ■ ■ ■
    Src/ES.Taipan.Crawler/DefaultCrawler.fs
    skipped 238 lines
    239 239   messageBroker.Subscribe<ExtractWebLinksMessage>(handleExtractWebLinksMessage)
    240 240   messageBroker.Subscribe<GetSettingsMessage>(handleGetSettings)
    241 241   messageBroker.Subscribe<RequestMetricsMessage>(handleRequestMetricsMessage)
     242 +
    242 243   logProvider.AddLogSourceToLoggers(_logger)
     244 + _logger.CrawlerScope(settings.Scope)
    243 245   
    244 246   // load only enabled addOn
    245 247   addOnManager.LoadAddOns()
    skipped 155 lines
  • ■ ■ ■ ■ ■ ■
    Src/ES.Taipan.Infrastructure/ES.Taipan.Infrastructure.fsproj
    skipped 122 lines
    123 123   <Compile Include="Common\BinarySerializer.fs" />
    124 124   <Compile Include="Text\RegexUtility.fs" />
    125 125   <Compile Include="Text\ConverterUtility.fs" />
     126 + <Compile Include="Text\TextUtility.fs" />
    126 127   <Compile Include="Messaging\Envelope.fs" />
    127 128   <Compile Include="Messaging\IMessageBroker.fs" />
    128 129   <Compile Include="Messaging\ResultMessage.fs" />
    skipped 128 lines
    257 258   <ItemGroup>
    258 259   <Reference Include="Brotli.NET">
    259 260   <HintPath>..\packages\Brotli.NET\lib\net40\Brotli.NET.dll</HintPath>
     261 + <Private>True</Private>
     262 + <Paket>True</Paket>
     263 + </Reference>
     264 + </ItemGroup>
     265 + </When>
     266 + </Choose>
     267 + <Choose>
     268 + <When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v3.5' Or $(TargetFrameworkVersion) == 'v4.0' Or $(TargetFrameworkVersion) == 'v4.0.3')">
     269 + <ItemGroup>
     270 + <Reference Include="DiffLib">
     271 + <HintPath>..\packages\difflib\lib\net35\DiffLib.dll</HintPath>
     272 + <Private>True</Private>
     273 + <Paket>True</Paket>
     274 + </Reference>
     275 + </ItemGroup>
     276 + </When>
     277 + <When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.5' Or $(TargetFrameworkVersion) == 'v4.5.1' Or $(TargetFrameworkVersion) == 'v4.5.2' Or $(TargetFrameworkVersion) == 'v4.5.3')">
     278 + <ItemGroup>
     279 + <Reference Include="DiffLib">
     280 + <HintPath>..\packages\difflib\lib\net45\DiffLib.dll</HintPath>
     281 + <Private>True</Private>
     282 + <Paket>True</Paket>
     283 + </Reference>
     284 + </ItemGroup>
     285 + </When>
     286 + <When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.6' Or $(TargetFrameworkVersion) == 'v4.6.1' Or $(TargetFrameworkVersion) == 'v4.6.2' Or $(TargetFrameworkVersion) == 'v4.6.3')">
     287 + <ItemGroup>
     288 + <Reference Include="DiffLib">
     289 + <HintPath>..\packages\difflib\lib\net46\DiffLib.dll</HintPath>
     290 + <Private>True</Private>
     291 + <Paket>True</Paket>
     292 + </Reference>
     293 + </ItemGroup>
     294 + </When>
     295 + <When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.7' Or $(TargetFrameworkVersion) == 'v4.7.1')">
     296 + <ItemGroup>
     297 + <Reference Include="DiffLib">
     298 + <HintPath>..\packages\difflib\lib\net47\DiffLib.dll</HintPath>
     299 + <Private>True</Private>
     300 + <Paket>True</Paket>
     301 + </Reference>
     302 + </ItemGroup>
     303 + </When>
     304 + <When Condition="($(TargetFrameworkIdentifier) == 'WindowsPhoneApp') Or ($(TargetFrameworkIdentifier) == 'MonoAndroid' And ($(TargetFrameworkVersion) == 'v7.0' Or $(TargetFrameworkVersion) == 'v7.1' Or $(TargetFrameworkVersion) == 'v8.0')) Or ($(TargetFrameworkIdentifier) == 'MonoTouch') Or ($(TargetFrameworkIdentifier) == '.NETCoreApp' And ($(TargetFrameworkVersion) == 'v1.0' Or $(TargetFrameworkVersion) == 'v1.1' Or $(TargetFrameworkVersion) == 'v2.0')) Or ($(TargetFrameworkIdentifier) == '.NETStandard' And ($(TargetFrameworkVersion) == 'v1.0' Or $(TargetFrameworkVersion) == 'v1.1' Or $(TargetFrameworkVersion) == 'v1.2' Or $(TargetFrameworkVersion) == 'v1.3' Or $(TargetFrameworkVersion) == 'v1.4' Or $(TargetFrameworkVersion) == 'v1.5' Or $(TargetFrameworkVersion) == 'v1.6' Or $(TargetFrameworkVersion) == 'v2.0')) Or ($(TargetFrameworkIdentifier) == '.NETCore' And $(TargetFrameworkVersion) == 'v5.0') Or ($(TargetFrameworkIdentifier) == 'WindowsPhone' And ($(TargetFrameworkVersion) == 'v8.0' Or $(TargetFrameworkVersion) == 'v8.1')) Or ($(TargetFrameworkIdentifier) == 'Xamarin.iOS') Or ($(TargetFrameworkIdentifier) == 'Xamarin.Mac') Or ($(TargetFrameworkIdentifier) == 'Xamarin.tvOS') Or ($(TargetFrameworkIdentifier) == 'Xamarin.watchOS')">
     305 + <ItemGroup>
     306 + <Reference Include="DiffLib">
     307 + <HintPath>..\packages\difflib\lib\netstandard1.0\DiffLib.dll</HintPath>
    260 308   <Private>True</Private>
    261 309   <Paket>True</Paket>
    262 310   </Reference>
    skipped 2182 lines
  • ■ ■ ■ ■ ■
    Src/ES.Taipan.Infrastructure/Network/HeuristicPageNotFoundIdentifier.fs
    skipped 92 lines
    93 93  
    94 94   for i=0 to 3 do
    95 95   yield! [
     96 + extension
    96 97   Guid.NewGuid().ToString("N")
    97 98   Guid.NewGuid().ToString("N") + ".ini"
    98 99   Guid.NewGuid().ToString("N") + ".txt"
    skipped 99 lines
  • ■ ■ ■ ■ ■ ■
    Src/ES.Taipan.Infrastructure/Text/TextUtility.fs
     1 +namespace ES.Taipan.Infrastructure.Text
     2 + 
     3 +open System
     4 +open DiffLib
     5 + 
     6 +module TextUtility =
     7 + let computeDifferenceRatio(text1: String, text2: String) =
     8 + let sections = Diff.CalculateSections(text1.ToCharArray(), text2.ToCharArray()) |> Seq.toList
     9 + let lengthMatched =
     10 + sections
     11 + |> List.filter(fun section -> section.IsMatch)
     12 + |> List.sumBy(fun section -> section.LengthInCollection1)
     13 + 
     14 + let totalLength =
     15 + sections
     16 + |> List.sumBy(fun section -> section.LengthInCollection1)
     17 +
     18 + float lengthMatched / float totalLength
     19 + 
     20 + 
  • ■ ■ ■ ■ ■
    Src/ES.Taipan.Infrastructure/paket.references
    skipped 4 lines
    5 5  Selenium.WebDriver
    6 6  SharpZipLib
    7 7  Brotli.NET
     8 +difflib
  • ■ ■ ■ ■ ■ ■
    Src/ES.Taipan.Inspector.AddOns/ES.Taipan.Inspector.AddOns.fsproj
    skipped 81 lines
    82 82   <Compile Include="VCSInformationDisclosure\GitDownloader.fs" />
    83 83   <Compile Include="VCSInformationDisclosure\VCSInformationDisclosureAddOn.fs" />
    84 84   <Compile Include="WebApplicationVulnerability\WebApplicationVulnerabilityAddOn.fs" />
     85 + <Compile Include="WebFormBruteforcer\BruteforceHelper.fs" />
     86 + <Compile Include="WebFormBruteforcer\WebFormBruteforcerAddOn.fs" />
    85 87   <None Include="paket.references" />
    86 88   </ItemGroup>
    87 89   <ItemGroup>
    skipped 2189 lines
  • ■ ■ ■ ■ ■ ■
    Src/ES.Taipan.Inspector.AddOns/HttpBruteforcer/HttpBruteforcerAddOn.fs
    skipped 28 lines
    29 29   log "HttpBruteforcerAddOn"
    30 30   |> info "BruteforceUsername" "Start to identify password for username: {0}"
    31 31   |> info "UpdateStatus" "Bruteforce of {0}, username {1} at {2}% [{3}/{4}]"
    32  - |> info "TestForCombination" "Test for combination on directory: {0}"
     32 + |> info "TestForCombination" "Test for username/password combination on directory: {0}"
    33 33   |> build
    34 34   
    35 35   let reportSecurityIssue(username: String, password: String, webRequest: WebRequest, webResponse: WebResponse) =
    skipped 24 lines
    60 60   let authHeader = new HttpHeader(Name="Authorization", Value=String.Format("Basic {0}", toAsciiBase64(token)))
    61 61   request.Headers.Add(authHeader)
    62 62   
    63  - let initLogStatus(directory: String, username: String, totalReq: Int32) =
    64  - lock _progressIndexes (fun _ -> _progressIndexes.[directory] <- (username, 0, totalReq, 0))
     63 + let initLogStatus(index: String, username: String, totalReq: Int32) =
     64 + lock _progressIndexes (fun _ -> _progressIndexes.[index] <- (username, 0, totalReq, 0))
    65 65   
    66  - let logStatus(directory: String) =
     66 + let logStatus(index: String) =
    67 67   lock _progressIndexes (fun _ ->
    68  - if _progressIndexes.ContainsKey(directory) then
    69  - let (username, currentIndex, totalCount, lastPercentage) = _progressIndexes.[directory]
     68 + if _progressIndexes.ContainsKey(index) then
     69 + let (username, currentIndex, totalCount, lastPercentage) = _progressIndexes.[index]
    70 70   let percentage = (float currentIndex / float totalCount) * 100. |> int32
    71  - _progressIndexes.[directory] <- (username, currentIndex+1, totalCount, lastPercentage)
     71 + _progressIndexes.[index] <- (username, currentIndex+1, totalCount, lastPercentage)
    72 72   
    73 73   if lastPercentage < percentage && percentage % 5 = 0 then
    74  - _progressIndexes.[directory] <- (username, currentIndex, totalCount, percentage)
    75  - _logger?UpdateStatus(directory, username, percentage, currentIndex, totalCount)
     74 + _progressIndexes.[index] <- (username, currentIndex, totalCount, percentage)
     75 + _logger?UpdateStatus(index, username, percentage, currentIndex, totalCount)
    76 76   )
    77 77   
    78 78   let testUsernameAndPassword(username: String, password: String, testRequest: TestRequest, serviceStateController: ServiceStateController) =
    skipped 97 lines
  • ■ ■ ■ ■ ■ ■
    Src/ES.Taipan.Inspector.AddOns/SqlInjection/BlindSqliChecker.fs
    skipped 4 lines
    5 5  open ES.Fslog
    6 6  open ES.Taipan.Inspector
    7 7  open ES.Taipan.Infrastructure.Network
    8  -open DiffLib
     8 +open ES.Taipan.Infrastructure.Text
    9 9   
    10 10  type BlindSqliChecker(webRequestor: IWebPageRequestor, logProvider: ILogProvider) =
    11 11  
    skipped 36 lines
    48 48   let webResponse = webRequestor.RequestWebPage(webRequest)
    49 49   parameter.AlterValue(originalValue)
    50 50   (webRequest, webResponse)
    51  -
    52  - let computeDifferenceRatio(text1: String, text2: String) =
    53  - let sections = Diff.CalculateSections(text1.ToCharArray(), text2.ToCharArray()) |> Seq.toList
    54  - let matchingSections = sections |> List.filter(fun section -> section.IsMatch)
    55  - float matchingSections.Length / float sections.Length
    56 51   
    57 52   let testProbeRequest(parameter: ProbeParameter, trueQuery: String, falseQuery: String, probeRequest: ProbeRequest, ratio: Double) =
    58 53   let mutable result: AttackDetails option = None
    skipped 4 lines
    63 58   // verify result
    64 59   if box(trueWebResponse.HttpResponse) <> null && box(falseWebResponse.HttpResponse) <> null then
    65 60   probeRequest.WebResponse <- Some trueWebResponse
    66  - let attackRatio = computeDifferenceRatio(trueWebResponse.HttpResponse.Html, falseWebResponse.HttpResponse.Html)
     61 + let attackRatio = TextUtility.computeDifferenceRatio(trueWebResponse.HttpResponse.Html, falseWebResponse.HttpResponse.Html)
    67 62   
    68 63   if attackRatio < ratio then
    69 64   result <- Some {
    skipped 24 lines
    94 89   parameter.AlterValue(originalValue)
    95 90   let alteredHtml = webResponse.HttpResponse.Html
    96 91   
    97  - let ratio = computeDifferenceRatio(originalHtml, alteredHtml)
     92 + let ratio = TextUtility.computeDifferenceRatio(originalHtml, alteredHtml)
    98 93   ratio >= RatioThreshold
    99 94  
    100 95   member this.VulnName
    skipped 11 lines
    112 107   let newResponse = webRequestor.RequestWebPage(probeRequest.TestRequest.WebRequest)
    113 108   if box(newResponse.HttpResponse) <> null && not(String.IsNullOrEmpty(newResponse.HttpResponse.Html)) then
    114 109   // verify that the page is stable
    115  - let ratio = computeDifferenceRatio(probeRequest.TestRequest.WebResponse.HttpResponse.Html, newResponse.HttpResponse.Html)
     110 + let ratio = TextUtility.computeDifferenceRatio(probeRequest.TestRequest.WebResponse.HttpResponse.Html, newResponse.HttpResponse.Html)
    116 111   
    117 112   if ratio < RatioThreshold then
    118 113   if parameter.Type = ProbeParameterType.DATA || parameter.Type = ProbeParameterType.QUERY
    skipped 29 lines
  • ■ ■ ■ ■ ■ ■
    Src/ES.Taipan.Inspector.AddOns/WebFormBruteforcer/BruteforceHelper.fs
     1 +namespace ES.Taipan.Inspector.AddOns.WebFormBruteforcer
     2 + 
     3 +open System
     4 +open ES.Taipan.Inspector
     5 +open ES.Taipan.Infrastructure.Network
     6 +open ES.Taipan.Crawler
     7 +open ES.Taipan.Infrastructure.Text
     8 + 
     9 +module internal BruteforceHelper =
     10 + let private sendRequest(webRequest: WebRequest, webRequestor: IWebPageRequestor) =
     11 + webRequest.HttpRequest.AllowAutoRedirect <- Some false
     12 + webRequestor.RequestWebPage(webRequest)
     13 + 
     14 + let sendProbe(testRequest: TestRequest, usernameInputs: String list, passwordInputs: String list, username: String, password: String, webRequestor: IWebPageRequestor)=
     15 + // create the probe request and set each input password and username
     16 + let probeRequest = new ProbeRequest(testRequest)
     17 + probeRequest.GetParameters()
     18 + |> Seq.filter(fun parameter -> parameter.Type = ProbeParameterType.DATA || parameter.Type = ProbeParameterType.QUERY)
     19 + |> Seq.iter(fun parameter ->
     20 + if usernameInputs |> List.contains(parameter.Name) then
     21 + parameter.AlterValue(username)
     22 + parameter.IsUnderTest <- true
     23 + elif passwordInputs |> List.contains(parameter.Name) then
     24 + parameter.AlterValue(password)
     25 + parameter.IsUnderTest <- true
     26 + )
     27 + 
     28 + // send the probe
     29 + let webRequest = new WebRequest(probeRequest.BuildHttpRequest(true))
     30 + probeRequest.WebResponse <- Some <| sendRequest(webRequest, webRequestor)
     31 + (webRequest, probeRequest.WebResponse.Value)
     32 + 
     33 + let getUsernameandPasswordInputs(testRequest: TestRequest) =
     34 + // get all inputs that are password and (possible) username types
     35 + let webLink = testRequest.GetData<WebLink>()
     36 + let inputs = RegexUtility.getAllHtmlTagsWithName(webLink.ParsedHtmlCode, "input")
     37 + let passwordInputs =
     38 + inputs
     39 + |> Seq.filter(fun input ->
     40 + RegexUtility
     41 + .getHtmlInputValue(input, "type")
     42 + .Equals("password", StringComparison.OrdinalIgnoreCase)
     43 + )
     44 + |> Seq.map(fun html -> RegexUtility.getHtmlInputValue(html, "name"))
     45 + |> Seq.toList
     46 + 
     47 + let usernameInputs =
     48 + inputs
     49 + |> Seq.filter(fun input ->
     50 + let name = RegexUtility.getHtmlInputValue(input, "name").ToLower()
     51 + [
     52 + "username"; "usrn"; "user"; "login"; "email"
     53 + ] |> List.exists(name.Contains)
     54 + )
     55 + |> Seq.map(fun html -> RegexUtility.getHtmlInputValue(html, "name"))
     56 + |> Seq.toList
     57 + 
     58 + (usernameInputs, passwordInputs)
  • ■ ■ ■ ■ ■ ■
    Src/ES.Taipan.Inspector.AddOns/WebFormBruteforcer/WebFormBruteforcerAddOn.fs
     1 +namespace ES.Taipan.Inspector.AddOns.WebFormBruteforcer
     2 + 
     3 +open System
     4 +open System.Collections.Generic
     5 +open ES.Taipan.Inspector
     6 +open ES.Taipan.Inspector.AddOns
     7 +open ES.Taipan.Infrastructure.Service
     8 +open ES.Taipan.Infrastructure.Text
     9 +open ES.Taipan.Infrastructure.Network
     10 +open ES.Taipan.Infrastructure.Messaging
     11 +open ES.Fslog
     12 +open System.Collections.Concurrent
     13 +open ES.Taipan.Infrastructure.Threading
     14 +open ES.Taipan.Infrastructure.Text
     15 +open ES.Taipan.Crawler
     16 +open DiffLib
     17 +open System.Threading.Tasks
     18 +open System.Linq
     19 +open System.Threading
     20 + 
     21 +type WebFormBruteforcerAddOn() as this =
     22 + inherit BaseStatelessAddOn("Web Form Bruteforcer AddOn", string WebFormBruteforcerAddOn.Id, 1)
     23 + let _progressIndexes = new Dictionary<String, String * Int32 * Int32 * Int32>()
     24 + 
     25 + let _numOfConcurrentTasks = 5
     26 + let _analyzedPages = new HashSet<String>()
     27 + let _scanLock = new Object()
     28 + let _testRequests = new BlockingCollection<TestRequest>()
     29 + 
     30 + let mutable _taskManager: TaskManager option = None
     31 + let mutable _usernames = List.empty<String>
     32 + let mutable _passwords = List.empty<String>
     33 + let mutable _combinations = List.empty<String * String>
     34 + 
     35 + let _logger =
     36 + log "WebFormBruteforcerAddOn"
     37 + |> info "BruteforceUsername" "Start to identify password for username: {0}"
     38 + |> info "BruteforceOnlyPasswords" "No suitable username input field found, bruteforce only password fields"
     39 + |> info "UpdateStatus" "Bruteforce of {0}, username {1} at {2}% [{3}/{4}]"
     40 + |> info "TestForCombination" "Test for username/password combination on directory: {0}"
     41 + |> build
     42 + 
     43 + let reportSecurityIssue(username: String, password: String, webRequest: WebRequest, webResponse: WebResponse) =
     44 + let securityIssue =
     45 + new SecurityIssue(
     46 + WebFormBruteforcerAddOn.Id,
     47 + Name = "Weak Web Form Credentials",
     48 + Uri = webRequest.HttpRequest.Uri,
     49 + EntryPoint = EntryPoint.Header,
     50 + Note = String.Format("Account {0}:{1}", username, password)
     51 + )
     52 + 
     53 + securityIssue.Transactions.Add(webRequest, webResponse)
     54 + securityIssue.Details.Properties.Add("Username", username)
     55 + securityIssue.Details.Properties.Add("Password", password)
     56 + this.Context.Value.AddSecurityIssue(securityIssue)
     57 + 
     58 + let initLogStatus(index: String, username: String, totalReq: Int32) =
     59 + lock _progressIndexes (fun _ -> _progressIndexes.[index] <- (username, 0, totalReq, 0))
     60 + 
     61 + let logStatus(index: String, forcePrint: Boolean) =
     62 + lock _progressIndexes (fun _ ->
     63 + if _progressIndexes.ContainsKey(index) then
     64 + let (username, currentIndex, totalCount, lastPercentage) = _progressIndexes.[index]
     65 + let percentage = (float currentIndex / float totalCount) * 100. |> int32
     66 + _progressIndexes.[index] <- (username, currentIndex+1, totalCount, lastPercentage)
     67 + 
     68 + if forcePrint || lastPercentage < percentage && percentage % 5 = 0 then
     69 + _progressIndexes.[index] <- (username, currentIndex, totalCount, percentage)
     70 + _logger?UpdateStatus(index, username, percentage, currentIndex, totalCount)
     71 + )
     72 + 
     73 + let testUsernameAndPassword(testRequest: TestRequest, usernameInputs: String list, passwordInputs: String list, username: String, password: String, resultVerifier: WebResponse -> Boolean, serviceStateController: ServiceStateController)=
     74 + let mutable isVulnerable = false
     75 + if not serviceStateController.IsStopped then
     76 + serviceStateController.WaitIfPauseRequested()
     77 + let (sentWebRequest, receivedWebResponse) =
     78 + BruteforceHelper.sendProbe(
     79 + testRequest,
     80 + usernameInputs,
     81 + passwordInputs,
     82 + username,
     83 + password,
     84 + this.WebRequestor.Value
     85 + )
     86 + 
     87 + // verify test
     88 + if resultVerifier(receivedWebResponse) then
     89 + reportSecurityIssue(username, password, sentWebRequest, receivedWebResponse)
     90 + isVulnerable <- true
     91 + isVulnerable
     92 +
     93 + let bruteforceUriWithCombinations(testRequest: TestRequest, usernameInputs: String list, passwordInputs: String list, resultVerifier: WebResponse -> Boolean, serviceStateController: ServiceStateController) =
     94 + if not usernameInputs.IsEmpty then
     95 + _logger?TestForCombination(testRequest.WebRequest.HttpRequest.Uri.AbsolutePath)
     96 + _combinations
     97 + |> List.exists(fun (username, password) ->
     98 + testUsernameAndPassword(
     99 + testRequest,
     100 + usernameInputs,
     101 + passwordInputs,
     102 + username,
     103 + password,
     104 + resultVerifier,
     105 + serviceStateController
     106 + )
     107 + )
     108 + else
     109 + false
     110 + 
     111 + let getTaskManager(serviceStateController: ServiceStateController) =
     112 + match _taskManager with
     113 + | None ->
     114 + _taskManager <- Some <| new TaskManager(serviceStateController, true, false, _numOfConcurrentTasks)
     115 + _taskManager.Value
     116 + | Some tm -> tm
     117 + 
     118 + let bruteforcePasswordList(testRequest: TestRequest, username: String, usernameInputs: String list, passwordInputs: String list, resultVerifier: WebResponse -> Boolean, serviceStateController: ServiceStateController) =
     119 + // run in parallels all the instantiated workers
     120 + let queue = new BlockingCollection<String>()
     121 + let tasks = new List<Task>()
     122 + let taskManager = getTaskManager(serviceStateController)
     123 + let passwordFound = ref 0
     124 + for _ in Enumerable.Range(0, 10) do
     125 + if not serviceStateController.IsStopped then
     126 + serviceStateController.WaitIfPauseRequested()
     127 + 
     128 + // run the parallel task
     129 + taskManager.RunTask(fun serviceStateController ->
     130 + for password in queue.GetConsumingEnumerable() do
     131 + if not serviceStateController.IsStopped then
     132 + serviceStateController.WaitIfPauseRequested()
     133 + 
     134 + // check if the password was already found for this username
     135 + if Interlocked.CompareExchange(passwordFound, 1, 1) = 0 then
     136 + 
     137 + // bruteforce password
     138 + logStatus(testRequest.WebRequest.HttpRequest.Uri.AbsolutePath, false)
     139 + let pwdFoundTmp =
     140 + testUsernameAndPassword(
     141 + testRequest,
     142 + usernameInputs,
     143 + passwordInputs,
     144 + username,
     145 + password,
     146 + resultVerifier,
     147 + serviceStateController
     148 + )
     149 +
     150 + if pwdFoundTmp then
     151 + // password found set exit flag
     152 + Interlocked.Increment(passwordFound) |> ignore
     153 + , true) |> tasks.Add
     154 + 
     155 + // add all password and set the queue to completed
     156 + _passwords |> List.iter(queue.Add)
     157 + queue.CompleteAdding()
     158 + 
     159 + // wait for all task completed
     160 + let counter = ref 0
     161 + while not(Task.WaitAll(tasks |> Seq.toArray, 1000)) do
     162 + incr counter
     163 + 
     164 + let bruteforceUriWithUsernameAndPassword(testRequest: TestRequest, usernameInputs: String list, passwordInputs: String list, resultVerifier: WebResponse -> Boolean, serviceStateController: ServiceStateController) =
     165 + if not usernameInputs.IsEmpty then
     166 + // if the username list to use is empty just add an
     167 + // empty username to check for password only auth
     168 + if _usernames |> List.isEmpty
     169 + then [String.Empty]
     170 + else _usernames
     171 + |> List.iter(fun username ->
     172 + _logger?BruteforceUsername(username)
     173 + initLogStatus(testRequest.WebRequest.HttpRequest.Uri.AbsolutePath, username, _passwords.Length)
     174 + bruteforcePasswordList(
     175 + testRequest,
     176 + username,
     177 + usernameInputs,
     178 + passwordInputs,
     179 + resultVerifier,
     180 + serviceStateController
     181 + )
     182 + )
     183 + logStatus(testRequest.WebRequest.HttpRequest.Uri.AbsolutePath, true)
     184 + else
     185 + // No username in form so I'll just bruteforce password input.
     186 + // I'm sure there are password inputs otherwise I'll not be at this code point
     187 + _logger?BruteforceOnlyPasswords()
     188 + initLogStatus(testRequest.WebRequest.HttpRequest.Uri.AbsolutePath, "N/A", _passwords.Length)
     189 + bruteforcePasswordList(
     190 + testRequest,
     191 + "N/A",
     192 + usernameInputs,
     193 + passwordInputs,
     194 + resultVerifier,
     195 + serviceStateController
     196 + )
     197 + logStatus(testRequest.WebRequest.HttpRequest.Uri.AbsolutePath, true)
     198 + 
     199 + let resultVerifier(falseResponse: WebResponse) (testResponse: WebResponse) =
     200 + if falseResponse.HttpResponse.StatusCode = testResponse.HttpResponse.StatusCode then
     201 + if HttpUtility.isRedirect(falseResponse.HttpResponse.StatusCode) then
     202 + // if it is a relocation, check if the destinations are different
     203 + let templateLocation = HttpUtility.tryGetHeader("Location", falseResponse.HttpResponse.Headers)
     204 + let testLocation = HttpUtility.tryGetHeader("Location", testResponse.HttpResponse.Headers)
     205 + 
     206 + match (templateLocation, testLocation) with
     207 + | (Some templateLocation, Some testLocation) ->
     208 + not <| templateLocation.Value.Equals(testLocation.Value, StringComparison.OrdinalIgnoreCase)
     209 + | _ ->
     210 + // one of the two response doesn't have Location header, pass found (may cause FPs)
     211 + true
     212 + else
     213 + // check change on HTML page
     214 + let ratio = TextUtility.computeDifferenceRatio(falseResponse.HttpResponse.Html, testResponse.HttpResponse.Html)
     215 + ratio < 0.80
     216 + else
     217 + true
     218 + 
     219 + let bruteforceWoker(serviceStateController: ServiceStateController) =
     220 + for testRequest in _testRequests.GetConsumingEnumerable() do
     221 + let (usernameInputs, passwordInputs) = BruteforceHelper.getUsernameandPasswordInputs(testRequest)
     222 + 
     223 + // send a not valid username and password to identify form behaviour
     224 + let (_, webResponse) =
     225 + BruteforceHelper.sendProbe(
     226 + testRequest,
     227 + usernameInputs,
     228 + passwordInputs,
     229 + Guid.NewGuid().ToString("N"),
     230 + Guid.NewGuid().ToString("N"),
     231 + this.WebRequestor.Value
     232 + )
     233 + 
     234 + // run the bruteforce
     235 + let bruteforceWithCombinationResult =
     236 + bruteforceUriWithCombinations(
     237 + testRequest,
     238 + usernameInputs,
     239 + passwordInputs,
     240 + resultVerifier webResponse,
     241 + serviceStateController
     242 + )
     243 + 
     244 + if not bruteforceWithCombinationResult && not _passwords.IsEmpty then
     245 + // combination didn't give any result, try an exhaustive approach
     246 + bruteforceUriWithUsernameAndPassword(
     247 + testRequest,
     248 + usernameInputs,
     249 + passwordInputs,
     250 + resultVerifier webResponse,
     251 + serviceStateController
     252 + )
     253 +
     254 + let runAllWorkers(taskManager: TaskManager) =
     255 + for i=0 to _numOfConcurrentTasks-1 do
     256 + taskManager.RunTask(fun serviceStateController ->
     257 + bruteforceWoker(serviceStateController)
     258 + , true) |> ignore
     259 + 
     260 + let bruteforcePage(testRequest: TestRequest, taskManager: TaskManager) =
     261 + if taskManager.Count() = 0 then
     262 + // no worker running, instantiace all workers
     263 + runAllWorkers(taskManager)
     264 + _testRequests.Add(testRequest)
     265 + 
     266 + let completePasswordList() =
     267 + // all the usernames also as passowrd and the empty string
     268 + _passwords <- String.Empty::_usernames@_passwords |> List.distinct
     269 + 
     270 + let hasWebFormAuthentication(testRequest: TestRequest) =
     271 + if testRequest.RequestType = TestRequestType.CrawledPage then
     272 + let webLink = testRequest.GetData<WebLink>()
     273 + let inputs = RegexUtility.getAllHtmlTagsWithName(webLink.ParsedHtmlCode, "input")
     274 + inputs
     275 + |> Seq.exists(fun input ->
     276 + RegexUtility
     277 + .getHtmlInputValue(input, "type")
     278 + .Equals("password", StringComparison.OrdinalIgnoreCase)
     279 + )
     280 + else
     281 + false
     282 + 
     283 + static member Id = Guid.Parse("65B5E32A-D952-4A51-93FC-B1A97B590886")
     284 + override this.IsBackgroundService with get() = true
     285 + 
     286 + default this.Initialize(context: Context, webRequestor: IWebPageRequestor, messageBroker: IMessageBroker, logProvider: ILogProvider) =
     287 + let initResult = base.Initialize(context, webRequestor, messageBroker, logProvider)
     288 + logProvider.AddLogSourceToLoggers(_logger)
     289 + 
     290 + webRequestor.HttpRequestor.Settings.AllowAutoRedirect <- false
     291 + _usernames <- defaultArg (this.Context.Value.AddOnStorage.ReadProperty<List<String>>("Usernames")) (new List<String>()) |> Seq.distinct |> Seq.toList
     292 + _passwords <- defaultArg (this.Context.Value.AddOnStorage.ReadProperty<List<String>>("Passwords")) (new List<String>()) |> Seq.distinct |> Seq.toList
     293 + _combinations <- defaultArg (this.Context.Value.AddOnStorage.ReadProperty<List<String * String>>("Combinations")) (new List<String * String>()) |> Seq.distinct |> Seq.toList
     294 + completePasswordList()
     295 + initResult
     296 + 
     297 + override this.RunToCompletation(stateController: ServiceStateController) =
     298 + _testRequests.CompleteAdding()
     299 + let taskManager = getTaskManager(stateController)
     300 + while not <| taskManager.AreAllTaskCompleted() do
     301 + Async.Sleep(1000) |> Async.RunSynchronously
     302 +
     303 + default this.Scan(testRequest: TestRequest, stateController: ServiceStateController) =
     304 + if hasWebFormAuthentication(testRequest) then
     305 + lock _scanLock (fun _ ->
     306 + if _analyzedPages.Add(testRequest.WebRequest.HttpRequest.Uri.AbsolutePath) then
     307 + let taskManager = getTaskManager(stateController)
     308 + bruteforcePage(testRequest, taskManager)
     309 + )
     310 +
  • ■ ■ ■ ■ ■ ■
    Src/EndToEndTests/EndToEndTests.fsproj
    skipped 1123 lines
    1124 1124   </When>
    1125 1125   </Choose>
    1126 1126   <Choose>
    1127  - <When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And $(TargetFrameworkVersion) == 'v4.6'">
    1128  - <ItemGroup>
    1129  - <Reference Include="System.IO.Compression">
    1130  - <HintPath>..\packages\System.IO.Compression\lib\net46\System.IO.Compression.dll</HintPath>
    1131  - <Private>True</Private>
    1132  - <Paket>True</Paket>
    1133  - </Reference>
    1134  - </ItemGroup>
    1135  - </When>
    1136 1127   <When Condition="$(TargetFrameworkIdentifier) == '.NETStandard' And ($(TargetFrameworkVersion) == 'v1.1' Or $(TargetFrameworkVersion) == 'v1.2')">
    1137 1128   <ItemGroup>
    1138 1129   <Reference Include="System.IO.Compression">
    skipped 16 lines
    1155 1146   <Choose>
    1156 1147   <When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And $(TargetFrameworkVersion) == 'v4.6'">
    1157 1148   <ItemGroup>
    1158  - <Reference Include="System.IO.Compression.FileSystem">
    1159  - <Paket>True</Paket>
    1160  - </Reference>
    1161 1149   <Reference Include="System.IO.Compression.ZipFile">
    1162 1150   <HintPath>..\packages\System.IO.Compression.ZipFile\lib\net46\System.IO.Compression.ZipFile.dll</HintPath>
    1163 1151   <Private>True</Private>
    skipped 1433 lines
  • ■ ■ ■ ■ ■
    Src/EndToEndTests/InspectorTests.fs
    skipped 215 lines
    216 216   let ``ASP.NET error``(grovieraUrl: Uri) = errorTests(grovieraUrl, "/inspector/test16/")
    217 217   let ``500 Internal server error``(grovieraUrl: Uri) = errorTests(grovieraUrl, "/inspector/test17/")
    218 218   
    219  - let writeHttpBasicBruteforceData(usernames: String list, passwords: String list, combinations: (String * String) list) =
    220  - let addOn = new ES.Taipan.Inspector.AddOns.HttpBruteforcer.HttpBruteforcerAddOn() :> IVulnerabilityScannerAddOn
    221  - let context = new ES.Taipan.Inspector.Context(new FilesystemAddOnStorage(addOn), new ServiceMetrics(String.Empty), fun _ -> ())
    222  - context.AddOnStorage.SaveProperty("Usernames", new List<String>(usernames))
    223  - context.AddOnStorage.SaveProperty("Passwords", new List<String>(passwords))
    224  - context.AddOnStorage.SaveProperty("Combinations", new List<String * String>(combinations))
     219 + let writeBruteforceData(usernames: String list, passwords: String list, combinations: (String * String) list) =
     220 + [
     221 + new ES.Taipan.Inspector.AddOns.HttpBruteforcer.HttpBruteforcerAddOn() :> IVulnerabilityScannerAddOn
     222 + new ES.Taipan.Inspector.AddOns.WebFormBruteforcer.WebFormBruteforcerAddOn() :> IVulnerabilityScannerAddOn
     223 + ]
     224 + |> List.iter(fun addOn ->
     225 + let context = new ES.Taipan.Inspector.Context(new FilesystemAddOnStorage(addOn), new ServiceMetrics(String.Empty), fun _ -> ())
     226 + context.AddOnStorage.SaveProperty("Usernames", new List<String>(usernames))
     227 + context.AddOnStorage.SaveProperty("Passwords", new List<String>(passwords))
     228 + context.AddOnStorage.SaveProperty("Combinations", new List<String * String>(combinations))
     229 + )
    225 230   
    226 231   let writeXssData(data: (String * String list) list) =
    227 232   let storageData = new Dictionary<String, List<String>>()
    skipped 430 lines
    658 663   let usernames = ["root"; "admin"; "Administrator"]
    659 664   let passwords = ["password"; "123456"; "secret"; "admin"]
    660 665   let combinations = [("root", "toor")]
    661  - writeHttpBasicBruteforceData(usernames, passwords, combinations)
     666 + writeBruteforceData(usernames, passwords, combinations)
    662 667   
    663 668   // run the scan
    664 669   Utility.runScan(scanContext)
    665 670   |> Utility.verifyInspector [
    666 671   ("Weak HTTP Basic Credentials", "/inspector/test39/")
    667 672   ]
     673 + 
     674 + let ``Web Form password only bruteforced page``(grovieraUrl: Uri) =
     675 + let scanContext =
     676 + new ScanContext(
     677 + StartRequest = new WebRequest(new Uri(grovieraUrl, "/inspector/test40/")),
     678 + Template = Templates.``Website inspector``()
     679 + )
     680 +
     681 + // enable basic addOns
     682 + scanContext.Template.CrawlerSettings.ActivateAllAddOns <- false
     683 + scanContext.Template.CrawlerSettings.AddOnIdsToActivate.AddRange([
     684 + ES.Taipan.Crawler.WebScrapers.FormLinkScraper.AddOnId
     685 + ES.Taipan.Crawler.WebScrapers.HyperLinkScraper.AddOnId
     686 + ])
     687 + scanContext.Template.HttpRequestorSettings.UseJavascriptEngineForRequest <- false
     688 + 
     689 + // activate plugin
     690 + activatePlugin(scanContext, string WebFormBruteforcer.WebFormBruteforcerAddOn.Id)
     691 + 
     692 + // set usernames and passwords
     693 + let usernames = List.empty<String>
     694 + let combinations = List.empty<String * String>
     695 + let passwords = ["password"; "123456"; "secret"; "admin"]
     696 + writeBruteforceData(usernames, passwords, combinations)
     697 + 
     698 + // run the scan
     699 + Utility.runScan(scanContext)
     700 + |> Utility.verifyInspector [
     701 + ("Weak Web Form Credentials", "/inspector/test40/index.php")
     702 + ]
  • ■ ■ ■ ■ ■
    Src/EndToEndTests/Program.fs
    skipped 96 lines
    97 97   <@ InspectorTests.``Avoid to raise a FP when encounter an email pattern with invalid TLD`` @>
    98 98   <@ InspectorTests.``RXSS on a user registration form with password and repassword check`` @>
    99 99   <@ InspectorTests.``HTTP Basic bruteforced page`` @>
     100 + <@ InspectorTests.``Web Form password only bruteforced page`` @>
    100 101  
    101 102   // Composed tests
    102 103   <@ ComposedTests.``Identify an hidden directory and discover a know web application`` @>
    skipped 77 lines
  • ■ ■ ■ ■ ■ ■
    Src/Groviera/InspectorPages.fs
    skipped 80 lines
    81 81   <li>TEST37: <a href="/inspector/test37/">/inspector/test37/</a> Regression: Avoid a FP when found an email with invalid TLD</li>
    82 82   <li>TEST38: <a href="/inspector/test38/">/inspector/test38/</a> RXSS on a password type parameter which implements check on password and retype password</li>
    83 83   <li>TEST39: <a href="/inspector/test39/">/inspector/test39/</a> An HTTP Basic protected page (admin:admin)</li>
     84 + <li>TEST40: <a href="/inspector/test40/">/inspector/test40/</a> A Web Form only password protected page (admin)</li>
    84 85   </ul><br/>
    85 86   </body>
    86 87  </html>""" ctx
    skipped 335 lines
    422 423   let webPart = OK "Welcome to the authenticated part of the website!!! You can also visit <a href='/inspector/test39/newPage'>this page!</h1>"
    423 424   Authentication.authenticateBasic ((=) ("admin", "admin")) webPart
    424 425   )
     426 + 
     427 + path "/inspector/test40/" >=> fun (ctx: HttpContext) ->
     428 + let html = """
     429 + <html>
     430 + <head>
     431 + <title>.::amz</title>
     432 + <link rel="stylesheet" href="html/css/main.css" type="text/css"/>
     433 + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
     434 + </head>
     435 + <body>
     436 + <table width=100% height=100% style="border:0px;background:#FFFFFF">
     437 + <tr>
     438 + <td style="vertical-align:center;" align=center>
     439 + <form name=loginform action="index.php" method=post>
     440 + <input type="hidden" name="action" value="do_login">
     441 + <table style="border: 8px solid #E1E3F4;" cellspacing=0 cellpadding=0>
     442 + <tr>
     443 + <td style="border: 1px solid #83B6EF;">
     444 + <table cellspacing=0 cellpadding=0 style="border:0px;padding:0px">
     445 + <tr style="height:10px">
     446 + <td align=center style="font-weight:bold;text-align:left;border-bottom:1px dotted #83B6EF;padding:5px;font-size:15px">
     447 + 
     448 + .::amz@AmazonCCGrab </td>
     449 + </tr>
     450 + <tr>
     451 + <td align=center style="padding:10px">
     452 + Password:
     453 + <input type=password name=password>&nbsp;<input type=submit value="Sign in">
     454 + </td>
     455 + </tr>
     456 + </td>
     457 + </tr>
     458 + </table>
     459 + </table>
     460 + </form>
     461 + </td>
     462 + </tr>
     463 + </table>
     464 + <script>document.loginform.password.focus();</script>
     465 + </body>
     466 + </html>
     467 + """
     468 + OK html ctx
     469 + 
     470 + path "/inspector/test40/dashboard.php" >=> okContent "Welcome authenticated user"
    425 471   ]
    426 472  
    427 473   // *************************
    skipped 100 lines
    528 574   if password1.Equals(password2) then
    529 575   let data = String.Join(", ", [username; password1])
    530 576   OK ("Thanks for subscription, find below your details: " + data) ctx
     577 + else
     578 + OK "Sorry but the password that you inserted are not equals" ctx
     579 + 
     580 + path "/inspector/test40/index.php" >=> fun (ctx: HttpContext) ->
     581 + let action =
     582 + match ctx.request.formData "action" with
     583 + | Choice1Of2 v -> v
     584 + | _ -> String.Empty
     585 + 
     586 + let password =
     587 + match ctx.request.formData "password" with
     588 + | Choice1Of2 v -> v
     589 + | _ -> "bla"
     590 + 
     591 + if password.Equals("admin") && action.Equals("do_login") then
     592 + Redirection.redirect "/inspector/test40/dashboard.php" ctx
    531 593   else
    532 594   OK "Sorry but the password that you inserted are not equals" ctx
    533 595   ]
    skipped 3 lines
  • ■ ■ ■ ■ ■
    Src/TaipanSln.sln
    skipped 4 lines
    5 5  MinimumVisualStudioVersion = 10.0.40219.1
    6 6  Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{E58CD0A9-4D33-45C3-AE59-F65C692F7495}"
    7 7   ProjectSection(SolutionItems) = preProject
     8 + 10passwords.txt = 10passwords.txt
    8 9   addOnData.fsx = addOnData.fsx
    9 10   build.fsx = build.fsx
    10 11   paket.dependencies = paket.dependencies
    skipped 220 lines
  • ■ ■ ■ ■ ■ ■
    Src/addOnData.fsx
    skipped 165 lines
    166 166   Writer.writeAddOnData(sqliAddOn, sqliErrors, "Errors", buildDir)
    167 167   
    168 168  let writeUsernameAndPassword(buildDir: String) =
    169  - let bruteforceAddOn = new ES.Taipan.Inspector.AddOns.HttpBruteforcer.HttpBruteforcerAddOn()
     169 + let httpBruteforceAddOn = new ES.Taipan.Inspector.AddOns.HttpBruteforcer.HttpBruteforcerAddOn()
     170 + let webFormBruteforceAddOn = new ES.Taipan.Inspector.AddOns.WebFormBruteforcer.WebFormBruteforcerAddOn()
    170 171   
    171 172   // credit to: https://github.com/danielmiessler/SecLists/blob/master/Usernames/top-usernames-shortlist.txt
    172  - let usernames = new List<String>(["root"; "admin"; "test"; "guest"; "info"; "adm"; "mysql"; "user"; "administrator"])
    173  - Writer.writeAddOnData(bruteforceAddOn, usernames, "Usernames", buildDir)
     173 + Writer.writeAddOnData(httpBruteforceAddOn, new List<String>(["root"; "admin"; "test"; "guest"; "info"; "adm"; "mysql"; "user"; "administrator"]), "Usernames", buildDir)
     174 + Writer.writeAddOnData(webFormBruteforceAddOn, new List<String>(["root"; "admin"]), "Usernames", buildDir)
    174 175  
    175 176   // credit to: https://github.com/danielmiessler/SecLists/blob/master/Passwords/Common-Credentials/500-worst-passwords.txt
    176  - let passwords = new List<String>([
     177 + let passwordsSmall = new List<String>([
    177 178   "123456"; "password"; "12345678"; "1234"; "pussy"; "12345"; "dragon"; "qwerty"; "696969"; "mustang"; "letmein"; "baseball"; "master"; "michael";
    178 179   "football"; "shadow"; "monkey"; "abc123"; "pass"; "fuckme"; "6969"; "jordan"; "harley"; "ranger"; "iwantu"; "jennifer"; "hunter"; "fuck"; "2000";
    179 180   "test"; "batman"; "trustno1"; "thomas"; "tigger"; "robert"; "access"; "love"; "buster"; "1234567"; "soccer"; "hockey"; "killer"; "george"; "sexy";
    skipped 29 lines
    209 210   "enjoy"; "girl"; "apollo"; "parker"; "qwert"; "time"; "sydney"; "women"; "voodoo"; "magnum"; "juice"; "abgrtyu"; "777777"; "dreams"; "maxwell"; "music";
    210 211   "rush2112"; "russia"; "scorpion"; "rebecca"; "tester"; "mistress"; "phantom"; "billy"; "6666"; "albert"
    211 212   ])
    212  - Writer.writeAddOnData(bruteforceAddOn, passwords, "Passwords", buildDir)
     213 + Writer.writeAddOnData(httpBruteforceAddOn, passwordsSmall, "Passwords", buildDir)
     214 + Writer.writeAddOnData(webFormBruteforceAddOn, new List<String>(File.ReadAllLines("10passwords.txt")), "Passwords", buildDir)
    213 215   
    214 216   let combinations = new List<String * String>([
    215 217   ("admin", "1"); ("admin", "123"); ("admin", "0000"); ("admin", "00000000"); ("admin", "12345"); ("admin", "123456"); ("admin", "1234567");
    skipped 15 lines
    231 233   ("admin", "lord"); ("admin", "fdpm0r"); ("admin", "15011974"); ("admin", "s15011974"); ("admin", "vr10vr10tajn1pa55"); ("admin", "Polkilo44");
    232 234   ("admin", "celkirulyat")
    233 235   ])
    234  - Writer.writeAddOnData(bruteforceAddOn, combinations, "Combinations", buildDir)
     236 + Writer.writeAddOnData(httpBruteforceAddOn, combinations, "Combinations", buildDir)
     237 + Writer.writeAddOnData(webFormBruteforceAddOn, combinations, "Combinations", buildDir)
    235 238   
    236 239  let createAddOnData(buildDir: String) =
    237 240   ensureDirectory (buildDir + "/Taipan/Data")
    skipped 13 lines
  • ■ ■ ■ ■ ■
    Src/templates.fsx
    skipped 45 lines
    46 46   defaultProfile.ResourceDiscovererSettings.BlackListedWords.Add("Rate Limit Exceeded") |> ignore
    47 47   defaultProfile.ResourceDiscovererSettings.ForbiddenDirectories.AddRange(
    48 48   [
    49  - "manual/"; "icons/"; "icon/"
     49 + "manual/"; "icons/"; "icon/"; "doc/"
    50 50   ])
    51 51   [
    52 52   ".tmp"; ".zip"; ".bak"
    skipped 42 lines
    95 95   ])
    96 96   defaultProfile.CrawlerSettings.BlacklistedPattern.AddRange(
    97 97   [
    98  - "/logout.[a-z]+"; "/manual/"
     98 + "/logout.[a-z]+"; "/manual/"; "doc/"
    99 99   ]
    100 100   )
    101 101   
    skipped 179 lines
    281 281   template
    282 282   
    283 283  let bruteforce() =
    284  - let template = createTemplate("Http Auth Bruteforce", "876C650C-D864-4EDF-B3DC-901945CE49C8")
    285  - template.Description <- "Perform an HTTP bruteforce if an authentication request is found"
     284 + let template = createTemplate("Auth Bruteforce", "876C650C-D864-4EDF-B3DC-901945CE49C8")
     285 + template.Description <- "Perform an account bruteforce on HTTP or WebForm"
    286 286   
    287 287   template.RunVulnerabilityScanner <- true
     288 + template.RunCrawler <- true
    288 289   template.VulnerabilityScannerSettings.ActivateAllAddOns <- false
    289 290   template.VulnerabilityScannerSettings.AddOnIdsToActivate.Clear()
    290 291   template.VulnerabilityScannerSettings.AddOnIdsToActivate.Add(HttpBruteforcer.HttpBruteforcerAddOn.Id)
     292 + template.VulnerabilityScannerSettings.AddOnIdsToActivate.Add(WebFormBruteforcer.WebFormBruteforcerAddOn.Id)
    291 293   
    292  - // disable Javascript for request
     294 + // disable Javascript for requests
    293 295   template.HttpRequestorSettings.UseJavascriptEngineForRequest <- false
     296 + 
     297 + // disable the Javascript Crawler parser
     298 + template.CrawlerSettings.ActivateAllAddOns <- false
     299 + template.CrawlerSettings.AddOnIdsToActivate.Clear()
     300 + template.CrawlerSettings.AddOnIdsToActivate.AddRange
     301 + ([
     302 + FormLinkScraper.AddOnId
     303 + HeaderRedirectLinkScraper.AddOnId
     304 + HyperLinkScraper.AddOnId
     305 + MetadataLinkScraper.AddOnId
     306 + ])
    294 307   
    295 308   template
    296 309   
    skipped 24 lines
Please wait...
Page is in error, reload to recover