├── .gitignore ├── Dockerfile ├── LICENSE.md ├── README.md ├── cmd └── wafme0w │ ├── main.go │ └── resources │ └── waf-fingerprints.json ├── go.mod ├── go.sum └── pkg ├── utils ├── http │ ├── httputil.go │ └── httputil_test.go └── strings │ ├── strings.go │ └── strings_test.go └── wafme0w ├── banner.go ├── generic_detection.go ├── http.go ├── identify.go ├── options.go ├── output.go ├── request.go └── runner.go /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | vendor/ 3 | .idea 4 | .devcontainer 5 | 6 | 7 | # Binaries for programs and plugins 8 | *.exe 9 | *.exe~ 10 | *.dll 11 | *.so 12 | *.dylib 13 | 14 | # Test binary, built with `go test -c` 15 | *.test 16 | 17 | # Output of the go coverage tool, specifically when used with LiteIDE 18 | *.out -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.19.5-alpine as build-env 2 | RUN apk add build-base 3 | RUN go install -v github.com/Lu1sDV/wafme0w/cmd/wafme0w@latest 4 | 5 | FROM alpine:3.17.1 6 | RUN apk add --no-cache bind-tools ca-certificates 7 | COPY --from=build-env /go/bin/wafme0w /usr/local/bin/wafme0w 8 | ENTRYPOINT ["wafme0w"] 9 | 10 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Luis Di Vittorio 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |

3 | Wafme0w 4 |

5 | 6 |

Fast and lightweight Web Application Firewall fingerprinting tool.

7 | 8 | # Features 9 | 10 | Based on Wafw00f, its features are: 11 | 12 | - Can detect **153** different Firewalls 13 | - Concurrent fingerprinting 14 | - **STDIN** supported 15 | - Fast detection mode for huge target lists 16 | - Multiple output formats supported (JSON, file, stdout) 17 | 18 | # Benchmark 19 | 20 | Scanned Alexa top 100 domains. Running on i7-7700K CPU @ 4.20GHz × 4 (8 Threads) 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 |
toolflagsTime elapsedWafs foundGeneric Wafs foundDiff
wafme0w--fast --concurrency 301min 37s (Best)2011+0%
wafme0w--concurrency 303min 51s22 (Best)16+138%
wafw00f13min 3s2016+707%
wafw00f-a15min 8s2023 (Best)+836%
70 | 71 | # Getting started 72 | ## Installation 73 | `wafme0w` requires **go >= 1.19** to install successfully. Run the following command to install the latest version: 74 | 75 | ```sh 76 | go install -v github.com/Lu1sDV/wafme0w/cmd/wafme0w@latest 77 | ``` 78 | ## Building Docker image 79 | ```sh 80 | git clone https://github.com/Lu1sDV/wafme0w.git 81 | cd wafme0w 82 | docker build -t wafme0w:latest . 83 | ``` 84 | 85 | ## Running Docker container 86 | ``` 87 | docker run --rm -it wafme0w:latest -t https://canva.com 88 | 89 | 90 | /\_/\ ___ 91 | = o_o =_______ \ \ 92 | __^ __( \.__) ) 93 | <_____>__(_____)____/ 94 | 95 | Wafme0w v1.0.0 96 | 97 | Fast Web Application Firewall Fingerprinting tool 98 | 99 | [+] https://canva.com is behind Cloudflare (Cloudflare Inc.) 100 | 101 | ``` 102 | 103 | ## Running Wafme0w 104 | 105 | To run the tool on a target, just use the following command. 106 | 107 | ```console 108 | cat /tmp/alexa-top-30.txt | wafme0w --concurrency 30 --no-warning --no-generic 109 | 110 | 111 | /\_/\ ___ 112 | = o_o =_______ \ \ 113 | __^ __( \.__) ) 114 | <_____>__(_____)____/ 115 | 116 | Wafme0w v1.0.0 117 | 118 | Fast Web Application Firewall Fingerprinting tool 119 | 120 | [~] https://microsoftonline.com no WAFs have been found 121 | [~] https://reddit.com no WAFs have been found 122 | [+] https://canva.com is behind Cloudflare (Cloudflare Inc.) 123 | [~] https://whatsapp.com no WAFs have been found 124 | [~] https://microsoft.com no WAFs have been found 125 | [~] https://live.com no WAFs have been found 126 | [~] https://163.com no WAFs have been found 127 | [~] https://yandex.ru no WAFs have been found 128 | [~] https://zhihu.com no WAFs have been found 129 | [~] https://taobao.com no WAFs have been found 130 | [~] https://wikipedia.org no WAFs have been found 131 | [~] https://qq.com no WAFs have been found 132 | [~] https://bilibili.com no WAFs have been found 133 | [~] https://bing.com no WAFs have been found 134 | [~] https://vk.com no WAFs have been found 135 | [~] https://facebook.com no WAFs have been found 136 | [~] https://twitch.tv no WAFs have been found 137 | [~] https://google.com no WAFs have been found 138 | [~] https://yahoo.com no WAFs have been found 139 | [~] https://linkedin.com no WAFs have been found 140 | [~] https://twitter.com no WAFs have been found 141 | [~] https://office.com no WAFs have been found 142 | [+] https://zoom.us is behind Cloudflare (Cloudflare Inc.) 143 | [~] https://csdn.net no WAFs have been found 144 | [~] https://github.com no WAFs have been found 145 | [~] https://baidu.com no WAFs have been found 146 | [~] https://netflix.com no WAFs have been found 147 | [+] https://amazon.com is behind Cloudfront (Amazon) 148 | [~] https://instagram.com no WAFs have been found 149 | [~] https://youtube.com no WAFs have been found 150 | 151 | ``` 152 | 153 | 154 | 198 | 199 |
155 | 156 | ## Wafme0w Go library 157 | 158 | Usage Example: 159 | ```go 160 | package main 161 | 162 | import ( 163 | "bytes" 164 | "fmt" 165 | "github.com/Lu1sDV/wafme0w/pkg/wafme0w" 166 | "os" 167 | ) 168 | 169 | func main() { 170 | targets := []byte("https://google.com\nhttps://paypal.com\n") 171 | targetsReader := bytes.NewReader(targets) 172 | /* 173 | Otherwise you can also load your targets from a file 174 | targetsReader, err := os.Open("/tmp/alexa-top-20.txt") 175 | if err != nil { 176 | panic(err) 177 | } 178 | */ 179 | fingerPrintsFile, err := os.Open("/PATH/TO/wafme0w/cmd/wafme0w/resources/waf-fingerprints.json") 180 | //fingerprints at https://github.com/Lu1sDV/wafme0w/blob/main/cmd/wafme0w/resources/waf-fingerprints.json 181 | opts := &wafme0w.Options{Inputs: targetsReader, 182 | FingerPrints: fingerPrintsFile, 183 | Silent: true, 184 | Concurrency: 10, 185 | //FastMode: true, 186 | //OutputFile: "myout.json", 187 | } 188 | runner := wafme0w.NewRunner(opts) 189 | result, err := runner.Scan() 190 | if err != nil { 191 | panic(err) 192 | } 193 | fmt.Printf("%#v\n", result) 194 | } 195 | 196 | ``` 197 |
200 | 201 | # Thanks 202 | People who contributed 203 | 204 | [@Fibonaccispiralz](https://github.com/Fibonaccispiralz) 205 | 206 | # Contact 207 | 208 | divittorioluis **AT** gmail **DOT** com 209 | 210 | Project Link: [https://github.com/Lu1sDV/wafme0w](https://github.com/Lu1sDV/wafme0w) 211 | 212 | 213 | -------------------------------------------------------------------------------- /cmd/wafme0w/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | _ "embed" 6 | "github.com/Lu1sDV/wafme0w/pkg/wafme0w" 7 | "github.com/jessevdk/go-flags" 8 | "github.com/logrusorgru/aurora/v4" 9 | "os" 10 | "strings" 11 | ) 12 | 13 | //go:embed resources/waf-fingerprints.json 14 | var embeddedFingerPrints []byte 15 | 16 | func main() { 17 | opts := wafme0w.NewOptions() 18 | 19 | args := os.Args 20 | 21 | _, err := flags.ParseArgs(opts, args) 22 | if err != nil { 23 | os.Exit(0) 24 | } 25 | 26 | if hasStdin() { 27 | opts.StdIn = true 28 | opts.Inputs = os.Stdin 29 | } 30 | 31 | if !opts.StdIn && len(args) < 2 { 32 | args = []string{"--help"} 33 | } 34 | 35 | au := aurora.New(aurora.WithColors(!opts.NoColors)) 36 | if !opts.Silent { 37 | wafme0w.PrintBanner() 38 | } 39 | 40 | if opts.Silent && opts.OutputFile == "" { 41 | wafme0w.PrintError("You must provide a valid output file when Silent mode is enabled", au) 42 | os.Exit(1) 43 | } 44 | 45 | //check if target input has been provided 46 | if opts.InputFile == "" && opts.Target == "" && !opts.StdIn && !opts.ListWAFS { 47 | wafme0w.PrintError("No targets provided", au) 48 | os.Exit(1) 49 | } 50 | 51 | //parse inputs if provided by command line arguments 52 | if !opts.StdIn { 53 | if opts.Target != "" { 54 | opts.Inputs = strings.NewReader(opts.Target) 55 | } 56 | if opts.InputFile != "" { 57 | //input file shadows target option 58 | file, err := os.Open(opts.InputFile) 59 | if err != nil { 60 | errText := "error reading input file: " + err.Error() 61 | wafme0w.PrintError(errText, au) 62 | } 63 | opts.Inputs = file 64 | } 65 | } 66 | fingerPrints, err := readFingerPrints(opts.FingerPrintFile) 67 | if err != nil { 68 | errText := "Error reading fingerprints: " + err.Error() 69 | wafme0w.PrintError(errText, au) 70 | } 71 | opts.FingerPrints = bytes.NewReader(fingerPrints) 72 | 73 | runner := wafme0w.NewRunner(opts) 74 | runner.Aurora = au 75 | 76 | if opts.ListWAFS { 77 | wafs, err := runner.GetAllWAFs() 78 | if err != nil { 79 | wafme0w.PrintError("Error displaying firewalls", au) 80 | os.Exit(1) 81 | } 82 | wafme0w.PrintAllWafs(wafs, au) 83 | os.Exit(0) 84 | } 85 | 86 | _, err = runner.Scan() 87 | if err != nil { 88 | errorString := "Scan error: " + err.Error() 89 | wafme0w.PrintError(errorString, au) 90 | os.Exit(1) 91 | } 92 | } 93 | 94 | func hasStdin() bool { 95 | stat, err := os.Stdin.Stat() 96 | if err != nil { 97 | return false 98 | } 99 | 100 | isPipedFromChrDev := (stat.Mode() & os.ModeCharDevice) == 0 101 | isPipedFromFIFO := (stat.Mode() & os.ModeNamedPipe) != 0 102 | 103 | return isPipedFromChrDev || isPipedFromFIFO 104 | } 105 | 106 | func readFingerPrints(fingerPrintsFile string) ([]byte, error) { 107 | if fingerPrintsFile == "" { 108 | return embeddedFingerPrints, nil 109 | } 110 | 111 | dat, err := os.ReadFile(fingerPrintsFile) 112 | if err != nil { 113 | return nil, err 114 | } 115 | return dat, nil 116 | } 117 | -------------------------------------------------------------------------------- /cmd/wafme0w/resources/waf-fingerprints.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Expression Engine (EllisLab)", 4 | "schemas": [ 5 | { 6 | "fingerprints": [ 7 | { 8 | "type": "Cookie", 9 | "pattern": "(?i)^exp_track.+?=" 10 | }, 11 | { 12 | "type": "Cookie", 13 | "pattern": "(?i)^exp_last_.+?=", 14 | "attack": true 15 | }, 16 | { 17 | "type": "Content", 18 | "pattern": "(?i)invalid get data" 19 | } 20 | ], 21 | "any": true 22 | } 23 | ] 24 | }, 25 | { 26 | "name": "NetScaler AppFirewall (Citrix Systems)", 27 | "schemas": [ 28 | { 29 | "fingerprints": [ 30 | { 31 | "type": "Header", 32 | "header_key": "Via", 33 | "header_value": "(?i)NS\\-CACHE" 34 | }, 35 | { 36 | "type": "Cookie", 37 | "pattern": "(?i)^(ns_af=|citrix_ns_id|NSC_)" 38 | }, 39 | { 40 | "type": "Content", 41 | "pattern": "(?i)(NS Transaction|AppFW Session) id" 42 | }, 43 | { 44 | "type": "Content", 45 | "pattern": "(?i)Violation Category.{0,5}?APPFW_" 46 | }, 47 | { 48 | "type": "Content", 49 | "pattern": "(?i)Citrix\\|NetScaler" 50 | }, 51 | { 52 | "type": "Header", 53 | "header_key": "Cneonction", 54 | "header_value": "(?i)^(keep alive|close)", 55 | "attack": true 56 | }, 57 | { 58 | "type": "Header", 59 | "header_key": "nnCoection", 60 | "header_value": "(?i)^(keep alive|close)", 61 | "attack": true 62 | } 63 | ], 64 | "any": true 65 | } 66 | ] 67 | }, 68 | { 69 | "name": "Beluga CDN (Beluga)", 70 | "schemas": [ 71 | { 72 | "fingerprints": [ 73 | { 74 | "type": "Header", 75 | "header_key": "Server", 76 | "header_value": "(?i)Beluga" 77 | }, 78 | { 79 | "type": "Cookie", 80 | "pattern": "(?i)^beluga_request_trail=" 81 | } 82 | ], 83 | "any": true 84 | } 85 | ] 86 | }, 87 | { 88 | "name": "Shieldon Firewall (Shieldon.io)", 89 | "schemas": [ 90 | { 91 | "fingerprints": [ 92 | { 93 | "type": "Content", 94 | "pattern": "(?i)Please solve CAPTCHA" 95 | }, 96 | { 97 | "type": "Content", 98 | "pattern": "(?i)shieldon_captcha" 99 | }, 100 | { 101 | "type": "Content", 102 | "pattern": "(?i)Unusual behavior detected" 103 | }, 104 | { 105 | "type": "Content", 106 | "pattern": "(?i)status-user-info" 107 | } 108 | ] 109 | }, 110 | { 111 | "fingerprints": [ 112 | { 113 | "type": "Content", 114 | "pattern": "(?i)Access denied" 115 | }, 116 | { 117 | "type": "Content", 118 | "pattern": "(?i)The IP address you are using has been blocked." 119 | }, 120 | { 121 | "type": "Content", 122 | "pattern": "(?i)status-user-info" 123 | } 124 | ] 125 | }, 126 | { 127 | "fingerprints": [ 128 | { 129 | "type": "Content", 130 | "pattern": "(?i)Please line up" 131 | }, 132 | { 133 | "type": "Content", 134 | "pattern": "(?i)This page is limiting the number of people online. Please wait a moment." 135 | } 136 | ] 137 | } 138 | ] 139 | }, 140 | { 141 | "name": "RequestValidationMode (Microsoft)", 142 | "schemas": [ 143 | { 144 | "fingerprints": [ 145 | { 146 | "type": "Content", 147 | "pattern": "(?i)Request Validation has detected a potentially dangerous client input" 148 | }, 149 | { 150 | "type": "Content", 151 | "pattern": "(?i)ASP\\.NET has detected data in the request" 152 | }, 153 | { 154 | "type": "Content", 155 | "pattern": "(?i)HttpRequestValidationException" 156 | } 157 | ], 158 | "any": true 159 | } 160 | ] 161 | }, 162 | { 163 | "name": "URLMaster SecurityCheck (iFinity/DotNetNuke)", 164 | "schemas": [ 165 | { 166 | "fingerprints": [ 167 | { 168 | "type": "Header", 169 | "header_key": "X-UrlMaster-Debug", 170 | "header_value": "(?i).+" 171 | }, 172 | { 173 | "type": "Header", 174 | "header_key": "X-UrlMaster-Ex", 175 | "header_value": "(?i).+" 176 | } 177 | ], 178 | "any": true 179 | }, 180 | { 181 | "fingerprints": [ 182 | { 183 | "type": "Content", 184 | "pattern": "(?i)Ur[li]RewriteModule" 185 | }, 186 | { 187 | "type": "Content", 188 | "pattern": "(?i)SecurityCheck" 189 | } 190 | ] 191 | } 192 | ] 193 | }, 194 | { 195 | "name": "Teros (Citrix Systems)", 196 | "schemas": [ 197 | { 198 | "fingerprints": [ 199 | { 200 | "type": "Cookie", 201 | "pattern": "(?i)^st8id=" 202 | } 203 | ], 204 | "any": true 205 | } 206 | ] 207 | }, 208 | { 209 | "name": "CdnNS Application Gateway (CdnNs/WdidcNet)", 210 | "schemas": [ 211 | { 212 | "fingerprints": [ 213 | { 214 | "type": "Content", 215 | "pattern": "(?i)cdnnswaf application gateway" 216 | } 217 | ], 218 | "any": true 219 | } 220 | ] 221 | }, 222 | { 223 | "name": "Cloudbric (Penta Security)", 224 | "schemas": [ 225 | { 226 | "fingerprints": [ 227 | { 228 | "type": "Content", 229 | "pattern": "(?i)\u003ctitle\u003eCloudbric.{0,5}?ERROR!" 230 | }, 231 | { 232 | "type": "Content", 233 | "pattern": "(?i)Your request was blocked by Cloudbric" 234 | }, 235 | { 236 | "type": "Content", 237 | "pattern": "(?i)please contact Cloudbric Support" 238 | }, 239 | { 240 | "type": "Content", 241 | "pattern": "(?i)cloudbric\\.zendesk\\.com" 242 | }, 243 | { 244 | "type": "Content", 245 | "pattern": "(?i)Cloudbric Help Center" 246 | }, 247 | { 248 | "type": "Content", 249 | "pattern": "(?i)malformed request syntax.{0,4}?invalid request message framing.{0,4}?or deceptive request routing" 250 | } 251 | ], 252 | "any": true 253 | } 254 | ] 255 | }, 256 | { 257 | "name": "Incapsula (Imperva Inc.)", 258 | "schemas": [ 259 | { 260 | "fingerprints": [ 261 | { 262 | "type": "Cookie", 263 | "pattern": "(?i)^incap_ses.*?=" 264 | }, 265 | { 266 | "type": "Cookie", 267 | "pattern": "(?i)^visid_incap.*?=" 268 | }, 269 | { 270 | "type": "Content", 271 | "pattern": "(?i)incapsula incident id" 272 | }, 273 | { 274 | "type": "Content", 275 | "pattern": "(?i)powered by incapsula" 276 | }, 277 | { 278 | "type": "Content", 279 | "pattern": "(?i)/_Incapsula_Resource" 280 | } 281 | ], 282 | "any": true 283 | } 284 | ] 285 | }, 286 | { 287 | "name": "Reblaze (Reblaze)", 288 | "schemas": [ 289 | { 290 | "fingerprints": [ 291 | { 292 | "type": "Cookie", 293 | "pattern": "(?i)^rbzid" 294 | }, 295 | { 296 | "type": "Header", 297 | "header_key": "Server", 298 | "header_value": "(?i)Reblaze Secure Web Gateway" 299 | } 300 | ], 301 | "any": true 302 | }, 303 | { 304 | "fingerprints": [ 305 | { 306 | "type": "Content", 307 | "pattern": "(?i)current session has been terminated" 308 | }, 309 | { 310 | "type": "Content", 311 | "pattern": "(?i)do not hesitate to contact us" 312 | }, 313 | { 314 | "type": "Content", 315 | "pattern": "(?i)access denied \\(\\d{3}\\)" 316 | } 317 | ] 318 | } 319 | ] 320 | }, 321 | { 322 | "name": "Yunjiasu (Baidu Cloud Computing)", 323 | "schemas": [ 324 | { 325 | "fingerprints": [ 326 | { 327 | "type": "Header", 328 | "header_key": "Server", 329 | "header_value": "(?i)Yunjiasu(.+)?" 330 | } 331 | ], 332 | "any": true 333 | } 334 | ] 335 | }, 336 | { 337 | "name": "Sitelock (TrueShield)", 338 | "schemas": [ 339 | { 340 | "fingerprints": [ 341 | { 342 | "type": "Content", 343 | "pattern": "(?i)SiteLock will remember you" 344 | }, 345 | { 346 | "type": "Content", 347 | "pattern": "(?i)Sitelock is leader in Business Website Security Services" 348 | }, 349 | { 350 | "type": "Content", 351 | "pattern": "(?i)sitelock[_\\-]shield([_\\-]logo|[\\-_]badge)?" 352 | }, 353 | { 354 | "type": "Content", 355 | "pattern": "(?i)SiteLock incident ID" 356 | } 357 | ], 358 | "any": true 359 | } 360 | ] 361 | }, 362 | { 363 | "name": "NinjaFirewall (NinTechNet)", 364 | "schemas": [ 365 | { 366 | "fingerprints": [ 367 | { 368 | "type": "Content", 369 | "pattern": "(?i)\u003ctitle\u003eNinjaFirewall.{0,10}?\\d{3}.forbidden" 370 | }, 371 | { 372 | "type": "Content", 373 | "pattern": "(?i)For security reasons?.{0,10}?it was blocked and logged" 374 | } 375 | ] 376 | } 377 | ] 378 | }, 379 | { 380 | "name": "eEye SecureIIS (BeyondTrust)", 381 | "schemas": [ 382 | { 383 | "fingerprints": [ 384 | { 385 | "type": "Content", 386 | "pattern": "(?i)SecureIIS is an internet security application" 387 | }, 388 | { 389 | "type": "Content", 390 | "pattern": "(?i)Download SecureIIS Personal Edition" 391 | }, 392 | { 393 | "type": "Content", 394 | "pattern": "(?i)https?://www\\.eeye\\.com/Secure\\-?IIS" 395 | } 396 | ], 397 | "any": true 398 | } 399 | ] 400 | }, 401 | { 402 | "name": "Secure Entry (United Security Providers)", 403 | "schemas": [ 404 | { 405 | "fingerprints": [ 406 | { 407 | "type": "Header", 408 | "header_key": "Server", 409 | "header_value": "(?i)Secure Entry Server" 410 | } 411 | ], 412 | "any": true 413 | } 414 | ] 415 | }, 416 | { 417 | "name": "Jiasule (Jiasule)", 418 | "schemas": [ 419 | { 420 | "fingerprints": [ 421 | { 422 | "type": "Header", 423 | "header_key": "Server", 424 | "header_value": "(?i)jiasule\\-waf" 425 | }, 426 | { 427 | "type": "Cookie", 428 | "pattern": "(?i)^jsl_tracking(.+)?=" 429 | }, 430 | { 431 | "type": "Cookie", 432 | "pattern": "(?i)__jsluid=" 433 | }, 434 | { 435 | "type": "Content", 436 | "pattern": "(?i)notice\\-jiasule" 437 | }, 438 | { 439 | "type": "Content", 440 | "pattern": "(?i)static\\.jiasule\\.com" 441 | } 442 | ], 443 | "any": true 444 | } 445 | ] 446 | }, 447 | { 448 | "name": "DDoS-GUARD (DDOS-GUARD CORP.)", 449 | "schemas": [ 450 | { 451 | "fingerprints": [ 452 | { 453 | "type": "Cookie", 454 | "pattern": "(?i)^__ddg1.*?=" 455 | }, 456 | { 457 | "type": "Cookie", 458 | "pattern": "(?i)^__ddg2.*?=" 459 | }, 460 | { 461 | "type": "Cookie", 462 | "pattern": "(?i)^__ddgid.*?=" 463 | }, 464 | { 465 | "type": "Cookie", 466 | "pattern": "(?i)^__ddgmark.*?=" 467 | }, 468 | { 469 | "type": "Header", 470 | "header_key": "Server", 471 | "header_value": "(?i)ddos-guard" 472 | } 473 | ], 474 | "any": true 475 | } 476 | ] 477 | }, 478 | { 479 | "name": "TransIP Web Firewall (TransIP)", 480 | "schemas": [ 481 | { 482 | "fingerprints": [ 483 | { 484 | "type": "Header", 485 | "header_key": "X-TransIP-Backend", 486 | "header_value": "(?i).+" 487 | }, 488 | { 489 | "type": "Header", 490 | "header_key": "X-TransIP-Balancer", 491 | "header_value": "(?i).+" 492 | } 493 | ], 494 | "any": true 495 | } 496 | ] 497 | }, 498 | { 499 | "name": "Tencent Cloud Firewall (Tencent Technologies)", 500 | "schemas": [ 501 | { 502 | "fingerprints": [ 503 | { 504 | "type": "Content", 505 | "pattern": "(?i)waf\\.tencent\\-?cloud\\.com/" 506 | } 507 | ], 508 | "any": true 509 | } 510 | ] 511 | }, 512 | { 513 | "name": "NetContinuum (Barracuda Networks)", 514 | "schemas": [ 515 | { 516 | "fingerprints": [ 517 | { 518 | "type": "Cookie", 519 | "pattern": "(?i)^NCI__SessionId=" 520 | } 521 | ], 522 | "any": true 523 | } 524 | ] 525 | }, 526 | { 527 | "name": "Fastly (Fastly CDN)", 528 | "schemas": [ 529 | { 530 | "fingerprints": [ 531 | { 532 | "type": "Header", 533 | "header_key": "X-Fastly-Request-ID", 534 | "header_value": "(?i)\\w+" 535 | } 536 | ], 537 | "any": true 538 | } 539 | ] 540 | }, 541 | { 542 | "name": "Astra (Czar Securities)", 543 | "schemas": [ 544 | { 545 | "fingerprints": [ 546 | { 547 | "type": "Cookie", 548 | "pattern": "(?i)^cz_astra_csrf_cookie" 549 | }, 550 | { 551 | "type": "Content", 552 | "pattern": "(?i)astrawebsecurity\\.freshdesk\\.com" 553 | }, 554 | { 555 | "type": "Content", 556 | "pattern": "(?i)www\\.getastra\\.com/assets/images" 557 | } 558 | ], 559 | "any": true 560 | } 561 | ] 562 | }, 563 | { 564 | "name": "ASP.NET Generic (Microsoft)", 565 | "schemas": [ 566 | { 567 | "fingerprints": [ 568 | { 569 | "type": "Content", 570 | "pattern": "(?i)iis (\\d+.)+?detailed error" 571 | }, 572 | { 573 | "type": "Content", 574 | "pattern": "(?i)potentially dangerous request querystring" 575 | }, 576 | { 577 | "type": "Content", 578 | "pattern": "(?i)application error from being viewed remotely (for security reasons)?" 579 | }, 580 | { 581 | "type": "Content", 582 | "pattern": "(?i)An application error occurred on the server" 583 | } 584 | ], 585 | "any": true 586 | } 587 | ] 588 | }, 589 | { 590 | "name": "Oracle Cloud (Oracle)", 591 | "schemas": [ 592 | { 593 | "fingerprints": [ 594 | { 595 | "type": "Content", 596 | "pattern": "(?i)\u003ctitle\u003efw_error_www" 597 | }, 598 | { 599 | "type": "Content", 600 | "pattern": "(?i)src=\\\"/oralogo_small\\.gif\\\"" 601 | }, 602 | { 603 | "type": "Content", 604 | "pattern": "(?i)www\\.oracleimg\\.com/us/assets/metrics/ora_ocom\\.js" 605 | } 606 | ], 607 | "any": true 608 | } 609 | ] 610 | }, 611 | { 612 | "name": "Trafficshield (F5 Networks)", 613 | "schemas": [ 614 | { 615 | "fingerprints": [ 616 | { 617 | "type": "Cookie", 618 | "pattern": "(?i)^ASINFO=" 619 | }, 620 | { 621 | "type": "Header", 622 | "header_key": "Server", 623 | "header_value": "(?i)F5-TrafficShield" 624 | } 625 | ], 626 | "any": true 627 | } 628 | ] 629 | }, 630 | { 631 | "name": "Shadow Daemon (Zecure)", 632 | "schemas": [ 633 | { 634 | "fingerprints": [ 635 | { 636 | "type": "Content", 637 | "pattern": "(?i)\u003ch\\d{1}\u003e\\d{3}.forbidden\u003c.h\\d{1}\u003e" 638 | }, 639 | { 640 | "type": "Content", 641 | "pattern": "(?i)request forbidden by administrative rules" 642 | } 643 | ] 644 | } 645 | ] 646 | }, 647 | { 648 | "name": "ISA Server (Microsoft)", 649 | "schemas": [ 650 | { 651 | "fingerprints": [ 652 | { 653 | "type": "Content", 654 | "pattern": "(?i)The.{0,10}?(isa.)?server.{0,10}?denied the specified uniform resource locator \\(url\\)" 655 | } 656 | ], 657 | "any": true 658 | } 659 | ] 660 | }, 661 | { 662 | "name": "StackPath (StackPath)", 663 | "schemas": [ 664 | { 665 | "fingerprints": [ 666 | { 667 | "type": "Content", 668 | "pattern": "(?i)\u003ctitle\u003eStackPath[^\u003c]+\u003c/title\u003e" 669 | }, 670 | { 671 | "type": "Content", 672 | "pattern": "(?i)Protected by \u003ca href=\"https?:\\/\\/(?:www\\.)?stackpath\\.com\\/\"[^\u003e]+\u003eStackPath" 673 | } 674 | ], 675 | "any": true 676 | }, 677 | { 678 | "fingerprints": [ 679 | { 680 | "type": "Content", 681 | "pattern": "(?i)is using a security service for protection against online attacks" 682 | }, 683 | { 684 | "type": "Content", 685 | "pattern": "(?i)An action has triggered the service and blocked your request" 686 | } 687 | ] 688 | } 689 | ] 690 | }, 691 | { 692 | "name": "HyperGuard (Art of Defense)", 693 | "schemas": [ 694 | { 695 | "fingerprints": [ 696 | { 697 | "type": "Cookie", 698 | "pattern": "(?i)^WODSESSION=" 699 | } 700 | ], 701 | "any": true 702 | } 703 | ] 704 | }, 705 | { 706 | "name": "Qrator (Qrator)", 707 | "schemas": [ 708 | { 709 | "fingerprints": [ 710 | { 711 | "type": "Header", 712 | "header_key": "Server", 713 | "header_value": "(?i)QRATOR" 714 | } 715 | ], 716 | "any": true 717 | } 718 | ] 719 | }, 720 | { 721 | "name": "SecKing (SecKing)", 722 | "schemas": [ 723 | { 724 | "fingerprints": [ 725 | { 726 | "type": "Header", 727 | "header_key": "Server", 728 | "header_value": "(?i)secking(.?waf)?" 729 | } 730 | ], 731 | "any": true 732 | } 733 | ] 734 | }, 735 | { 736 | "name": "WebARX (WebARX Security Solutions)", 737 | "schemas": [ 738 | { 739 | "fingerprints": [ 740 | { 741 | "type": "Content", 742 | "pattern": "(?i)WebARX.{0,10}?Web Application Firewall" 743 | }, 744 | { 745 | "type": "Content", 746 | "pattern": "(?i)www\\.webarxsecurity\\.com" 747 | }, 748 | { 749 | "type": "Content", 750 | "pattern": "(?i)/wp\\-content/plugins/webarx/includes/" 751 | } 752 | ], 753 | "any": true 754 | } 755 | ] 756 | }, 757 | { 758 | "name": "BIG-IP AP Manager (F5 Networks)", 759 | "schemas": [ 760 | { 761 | "fingerprints": [ 762 | { 763 | "type": "Cookie", 764 | "pattern": "(?i)^LastMRH_Session" 765 | }, 766 | { 767 | "type": "Cookie", 768 | "pattern": "(?i)^MRHSession" 769 | } 770 | ] 771 | }, 772 | { 773 | "fingerprints": [ 774 | { 775 | "type": "Cookie", 776 | "pattern": "(?i)^MRHSession" 777 | }, 778 | { 779 | "type": "Header", 780 | "header_key": "Server", 781 | "header_value": "(?i)Big([-_])?IP", 782 | "attack": true 783 | } 784 | ] 785 | }, 786 | { 787 | "fingerprints": [ 788 | { 789 | "type": "Cookie", 790 | "pattern": "(?i)^F5_fullWT" 791 | }, 792 | { 793 | "type": "Cookie", 794 | "pattern": "(?i)^F5_fullWT" 795 | }, 796 | { 797 | "type": "Cookie", 798 | "pattern": "(?i)^F5_HT_shrinked" 799 | } 800 | ], 801 | "any": true 802 | } 803 | ] 804 | }, 805 | { 806 | "name": "Qcloud (Tencent Cloud)", 807 | "schemas": [ 808 | { 809 | "fingerprints": [ 810 | { 811 | "type": "Content", 812 | "pattern": "(?i)腾讯云Web应用防火墙" 813 | }, 814 | { 815 | "type": "Status", 816 | "pattern": "403" 817 | } 818 | ] 819 | } 820 | ] 821 | }, 822 | { 823 | "name": "NevisProxy (AdNovum)", 824 | "schemas": [ 825 | { 826 | "fingerprints": [ 827 | { 828 | "type": "Cookie", 829 | "pattern": "(?i)^Navajo" 830 | }, 831 | { 832 | "type": "Cookie", 833 | "pattern": "(?i)^NP_ID" 834 | } 835 | ], 836 | "any": true 837 | } 838 | ] 839 | }, 840 | { 841 | "name": "Comodo cWatch (Comodo CyberSecurity)", 842 | "schemas": [ 843 | { 844 | "fingerprints": [ 845 | { 846 | "type": "Header", 847 | "header_key": "Server", 848 | "header_value": "(?i)Protected by COMODO WAF(.+)?" 849 | } 850 | ], 851 | "any": true 852 | } 853 | ] 854 | }, 855 | { 856 | "name": "NexusGuard Firewall (NexusGuard)", 857 | "schemas": [ 858 | { 859 | "fingerprints": [ 860 | { 861 | "type": "Content", 862 | "pattern": "(?i)Powered by Nexusguard" 863 | }, 864 | { 865 | "type": "Content", 866 | "pattern": "(?i)nexusguard\\.com/wafpage/.+#\\d{3};" 867 | } 868 | ], 869 | "any": true 870 | } 871 | ] 872 | }, 873 | { 874 | "name": "Chuang Yu Shield (Yunaq)", 875 | "schemas": [ 876 | { 877 | "fingerprints": [ 878 | { 879 | "type": "Content", 880 | "pattern": "(?i)www\\.365cyd\\.com" 881 | }, 882 | { 883 | "type": "Content", 884 | "pattern": "(?i)help\\.365cyd\\.com/cyd\\-error\\-help.html\\?code=403" 885 | } 886 | ], 887 | "any": true 888 | } 889 | ] 890 | }, 891 | { 892 | "name": "Safedog (SafeDog)", 893 | "schemas": [ 894 | { 895 | "fingerprints": [ 896 | { 897 | "type": "Cookie", 898 | "pattern": "(?i)^safedog\\-flow\\-item=" 899 | }, 900 | { 901 | "type": "Header", 902 | "header_key": "Server", 903 | "header_value": "(?i)Safedog" 904 | }, 905 | { 906 | "type": "Content", 907 | "pattern": "(?i)safedogsite/broswer_logo\\.jpg" 908 | }, 909 | { 910 | "type": "Content", 911 | "pattern": "(?i)404\\.safedog\\.cn/sitedog_stat.html" 912 | }, 913 | { 914 | "type": "Content", 915 | "pattern": "(?i)404\\.safedog\\.cn/images/safedogsite/head\\.png" 916 | } 917 | ], 918 | "any": true 919 | } 920 | ] 921 | }, 922 | { 923 | "name": "Approach (Approach)", 924 | "schemas": [ 925 | { 926 | "fingerprints": [ 927 | { 928 | "type": "Content", 929 | "pattern": "(?i)approach.{0,10}?web application (firewall|filtering)" 930 | }, 931 | { 932 | "type": "Content", 933 | "pattern": "(?i)approach.{0,10}?infrastructure team" 934 | } 935 | ], 936 | "any": true 937 | } 938 | ] 939 | }, 940 | { 941 | "name": "Azure Front Door (Microsoft)", 942 | "schemas": [ 943 | { 944 | "fingerprints": [ 945 | { 946 | "type": "Header", 947 | "header_key": "X-Azure-Ref", 948 | "header_value": "(?i).+?" 949 | } 950 | ], 951 | "any": true 952 | } 953 | ] 954 | }, 955 | { 956 | "name": "BlockDoS (BlockDoS)", 957 | "schemas": [ 958 | { 959 | "fingerprints": [ 960 | { 961 | "type": "Header", 962 | "header_key": "Server", 963 | "header_value": "(?i)blockdos\\.net" 964 | } 965 | ], 966 | "any": true 967 | } 968 | ] 969 | }, 970 | { 971 | "name": "SEnginx (Neusoft)", 972 | "schemas": [ 973 | { 974 | "fingerprints": [ 975 | { 976 | "type": "Content", 977 | "pattern": "(?i)SENGINX\\-ROBOT\\-MITIGATION" 978 | } 979 | ], 980 | "any": true 981 | } 982 | ] 983 | }, 984 | { 985 | "name": "UEWaf (UCloud)", 986 | "schemas": [ 987 | { 988 | "fingerprints": [ 989 | { 990 | "type": "Header", 991 | "header_key": "Server", 992 | "header_value": "(?i)uewaf(/[0-9\\.]+)?" 993 | }, 994 | { 995 | "type": "Content", 996 | "pattern": "(?i)/uewaf_deny_pages/default/img/" 997 | }, 998 | { 999 | "type": "Content", 1000 | "pattern": "(?i)ucloud\\.cn" 1001 | } 1002 | ], 1003 | "any": true 1004 | } 1005 | ] 1006 | }, 1007 | { 1008 | "name": "URLScan (Microsoft)", 1009 | "schemas": [ 1010 | { 1011 | "fingerprints": [ 1012 | { 1013 | "type": "Content", 1014 | "pattern": "(?i)Rejected[-_]By[_-]UrlScan" 1015 | }, 1016 | { 1017 | "type": "Content", 1018 | "pattern": "(?i)A custom filter or module.{0,4}?such as URLScan" 1019 | } 1020 | ], 1021 | "any": true 1022 | } 1023 | ] 1024 | }, 1025 | { 1026 | "name": "NAXSI (NBS Systems)", 1027 | "schemas": [ 1028 | { 1029 | "fingerprints": [ 1030 | { 1031 | "type": "Header", 1032 | "header_key": "X-Data-Origin", 1033 | "header_value": "(?i)^naxsi(.+)?" 1034 | }, 1035 | { 1036 | "type": "Header", 1037 | "header_key": "Server", 1038 | "header_value": "(?i)naxsi(.+)?" 1039 | }, 1040 | { 1041 | "type": "Content", 1042 | "pattern": "(?i)blocked by naxsi" 1043 | }, 1044 | { 1045 | "type": "Content", 1046 | "pattern": "(?i)naxsi blocked information" 1047 | } 1048 | ], 1049 | "any": true 1050 | } 1051 | ] 1052 | }, 1053 | { 1054 | "name": "ACE XML Gateway (Cisco)", 1055 | "schemas": [ 1056 | { 1057 | "fingerprints": [ 1058 | { 1059 | "type": "Header", 1060 | "header_key": "Server", 1061 | "header_value": "(?i)ACE XML Gateway" 1062 | } 1063 | ], 1064 | "any": true 1065 | } 1066 | ] 1067 | }, 1068 | { 1069 | "name": "SonicWall (Dell)", 1070 | "schemas": [ 1071 | { 1072 | "fingerprints": [ 1073 | { 1074 | "type": "Header", 1075 | "header_key": "Server", 1076 | "header_value": "(?i)SonicWALL" 1077 | }, 1078 | { 1079 | "type": "Content", 1080 | "pattern": "(?i)\u003c(title|h\\d{1})\u003eWeb Site Blocked" 1081 | }, 1082 | { 1083 | "type": "Content", 1084 | "pattern": "(?i)\\+?nsa_banner" 1085 | } 1086 | ], 1087 | "any": true 1088 | } 1089 | ] 1090 | }, 1091 | { 1092 | "name": "Squarespace (Squarespace)", 1093 | "schemas": [ 1094 | { 1095 | "fingerprints": [ 1096 | { 1097 | "type": "Header", 1098 | "header_key": "Server", 1099 | "header_value": "(?i)Squarespace" 1100 | }, 1101 | { 1102 | "type": "Cookie", 1103 | "pattern": "(?i)^SS_ANALYTICS_ID=" 1104 | }, 1105 | { 1106 | "type": "Cookie", 1107 | "pattern": "(?i)^SS_MATTR=" 1108 | }, 1109 | { 1110 | "type": "Cookie", 1111 | "pattern": "(?i)^SS_MID=" 1112 | }, 1113 | { 1114 | "type": "Cookie", 1115 | "pattern": "(?i)SS_CVT=" 1116 | }, 1117 | { 1118 | "type": "Content", 1119 | "pattern": "(?i)status\\.squarespace\\.com" 1120 | }, 1121 | { 1122 | "type": "Content", 1123 | "pattern": "(?i)BRICK\\-\\d{2}" 1124 | } 1125 | ], 1126 | "any": true 1127 | } 1128 | ] 1129 | }, 1130 | { 1131 | "name": "VirusDie (VirusDie LLC)", 1132 | "schemas": [ 1133 | { 1134 | "fingerprints": [ 1135 | { 1136 | "type": "Content", 1137 | "pattern": "(?i)cdn\\.virusdie\\.ru/splash/firewallstop\\.png" 1138 | }, 1139 | { 1140 | "type": "Content", 1141 | "pattern": "(?i)copy.{0,10}?Virusdie\\.ru" 1142 | } 1143 | ], 1144 | "any": true 1145 | } 1146 | ] 1147 | }, 1148 | { 1149 | "name": "SiteGuard (Sakura Inc.)", 1150 | "schemas": [ 1151 | { 1152 | "fingerprints": [ 1153 | { 1154 | "type": "Content", 1155 | "pattern": "(?i)Powered by SiteGuard" 1156 | }, 1157 | { 1158 | "type": "Content", 1159 | "pattern": "(?i)The server refuse to browse the page" 1160 | } 1161 | ], 1162 | "any": true 1163 | } 1164 | ] 1165 | }, 1166 | { 1167 | "name": "SecuPress WP Security (SecuPress)", 1168 | "schemas": [ 1169 | { 1170 | "fingerprints": [ 1171 | { 1172 | "type": "Content", 1173 | "pattern": "(?i)\u003c(title|h\\d{1})\u003eSecuPress" 1174 | } 1175 | ], 1176 | "any": true 1177 | } 1178 | ] 1179 | }, 1180 | { 1181 | "name": "GoDaddy Website Protection (GoDaddy)", 1182 | "schemas": [ 1183 | { 1184 | "fingerprints": [ 1185 | { 1186 | "type": "Content", 1187 | "pattern": "(?i)GoDaddy (security|website firewall)" 1188 | } 1189 | ], 1190 | "any": true 1191 | } 1192 | ] 1193 | }, 1194 | { 1195 | "name": "Varnish (OWASP)", 1196 | "schemas": [ 1197 | { 1198 | "fingerprints": [ 1199 | { 1200 | "type": "Content", 1201 | "pattern": "(?i)Request rejected by xVarnish\\-WAF" 1202 | } 1203 | ], 1204 | "any": true 1205 | } 1206 | ] 1207 | }, 1208 | { 1209 | "name": "Airlock (Phion/Ergon)", 1210 | "schemas": [ 1211 | { 1212 | "fingerprints": [ 1213 | { 1214 | "type": "Cookie", 1215 | "pattern": "(?i)^al[_-]?(sess|lb)=" 1216 | }, 1217 | { 1218 | "type": "Content", 1219 | "pattern": "(?i)server detected a syntax error in your request" 1220 | } 1221 | ], 1222 | "any": true 1223 | } 1224 | ] 1225 | }, 1226 | { 1227 | "name": "SquidProxy IDS (SquidProxy)", 1228 | "schemas": [ 1229 | { 1230 | "fingerprints": [ 1231 | { 1232 | "type": "Header", 1233 | "header_key": "Server", 1234 | "header_value": "(?i)squid(/[0-9\\.]+)?" 1235 | }, 1236 | { 1237 | "type": "Content", 1238 | "pattern": "(?i)Access control configuration prevents your request" 1239 | } 1240 | ] 1241 | } 1242 | ] 1243 | }, 1244 | { 1245 | "name": "Huawei Cloud Firewall (Huawei)", 1246 | "schemas": [ 1247 | { 1248 | "fingerprints": [ 1249 | { 1250 | "type": "Cookie", 1251 | "pattern": "(?i)^HWWAFSESID=" 1252 | }, 1253 | { 1254 | "type": "Header", 1255 | "header_key": "Server", 1256 | "header_value": "(?i)HuaweiCloudWAF" 1257 | }, 1258 | { 1259 | "type": "Content", 1260 | "pattern": "(?i)hwclouds\\.com" 1261 | }, 1262 | { 1263 | "type": "Content", 1264 | "pattern": "(?i)hws_security@" 1265 | } 1266 | ], 1267 | "any": true 1268 | } 1269 | ] 1270 | }, 1271 | { 1272 | "name": "Profense (ArmorLogic)", 1273 | "schemas": [ 1274 | { 1275 | "fingerprints": [ 1276 | { 1277 | "type": "Header", 1278 | "header_key": "Server", 1279 | "header_value": "(?i)Profense" 1280 | }, 1281 | { 1282 | "type": "Cookie", 1283 | "pattern": "(?i)^PLBSID=" 1284 | } 1285 | ], 1286 | "any": true 1287 | } 1288 | ] 1289 | }, 1290 | { 1291 | "name": "LiteSpeed (LiteSpeed Technologies)", 1292 | "schemas": [ 1293 | { 1294 | "fingerprints": [ 1295 | { 1296 | "type": "Header", 1297 | "header_key": "Server", 1298 | "header_value": "(?i)LiteSpeed" 1299 | }, 1300 | { 1301 | "type": "Status", 1302 | "pattern": "403" 1303 | } 1304 | ] 1305 | }, 1306 | { 1307 | "fingerprints": [ 1308 | { 1309 | "type": "Content", 1310 | "pattern": "(?i)Proudly powered by litespeed web server" 1311 | }, 1312 | { 1313 | "type": "Content", 1314 | "pattern": "(?i)www\\.litespeedtech\\.com/error\\-page" 1315 | } 1316 | ], 1317 | "any": true 1318 | } 1319 | ] 1320 | }, 1321 | { 1322 | "name": "KeyCDN (KeyCDN)", 1323 | "schemas": [ 1324 | { 1325 | "fingerprints": [ 1326 | { 1327 | "type": "Header", 1328 | "header_key": "Server", 1329 | "header_value": "(?i)KeyCDN" 1330 | } 1331 | ], 1332 | "any": true 1333 | } 1334 | ] 1335 | }, 1336 | { 1337 | "name": "Yunsuo (Yunsuo)", 1338 | "schemas": [ 1339 | { 1340 | "fingerprints": [ 1341 | { 1342 | "type": "Cookie", 1343 | "pattern": "(?i)^yunsuo_session=" 1344 | }, 1345 | { 1346 | "type": "Content", 1347 | "pattern": "(?i)class=\\\"yunsuologo\\\"" 1348 | } 1349 | ], 1350 | "any": true 1351 | } 1352 | ] 1353 | }, 1354 | { 1355 | "name": "AppWall (Radware)", 1356 | "schemas": [ 1357 | { 1358 | "fingerprints": [ 1359 | { 1360 | "type": "Content", 1361 | "pattern": "(?i)CloudWebSec\\.radware\\.com" 1362 | }, 1363 | { 1364 | "type": "Header", 1365 | "header_key": "X-SL-CompState", 1366 | "header_value": "(?i).+" 1367 | } 1368 | ], 1369 | "any": true 1370 | }, 1371 | { 1372 | "fingerprints": [ 1373 | { 1374 | "type": "Content", 1375 | "pattern": "(?i)because we have detected unauthorized activity" 1376 | }, 1377 | { 1378 | "type": "Content", 1379 | "pattern": "(?i)\u003ctitle\u003eUnauthorized Request Blocked" 1380 | }, 1381 | { 1382 | "type": "Content", 1383 | "pattern": "(?i)if you believe that there has been some mistake" 1384 | }, 1385 | { 1386 | "type": "Content", 1387 | "pattern": "(?i)\\?Subject=Security Page.{0,10}?Case Number" 1388 | } 1389 | ] 1390 | } 1391 | ] 1392 | }, 1393 | { 1394 | "name": "WP Cerber Security (Cerber Tech)", 1395 | "schemas": [ 1396 | { 1397 | "fingerprints": [ 1398 | { 1399 | "type": "Content", 1400 | "pattern": "(?i)your request looks suspicious or similar to automated" 1401 | }, 1402 | { 1403 | "type": "Content", 1404 | "pattern": "(?i)our server stopped processing your request" 1405 | }, 1406 | { 1407 | "type": "Content", 1408 | "pattern": "(?i)We.re sorry.{0,10}?you are not allowed to proceed" 1409 | }, 1410 | { 1411 | "type": "Content", 1412 | "pattern": "(?i)requests from spam posting software" 1413 | }, 1414 | { 1415 | "type": "Content", 1416 | "pattern": "(?i)\u003ctitle\u003e403 Access Forbidden" 1417 | } 1418 | ] 1419 | } 1420 | ] 1421 | }, 1422 | { 1423 | "name": "ChinaCache Load Balancer (ChinaCache)", 1424 | "schemas": [ 1425 | { 1426 | "fingerprints": [ 1427 | { 1428 | "type": "Header", 1429 | "header_key": "Powered-By-ChinaCache", 1430 | "header_value": "(?i).+" 1431 | } 1432 | ], 1433 | "any": true 1434 | } 1435 | ] 1436 | }, 1437 | { 1438 | "name": "BIG-IP Local Traffic Manager (F5 Networks)", 1439 | "schemas": [ 1440 | { 1441 | "fingerprints": [ 1442 | { 1443 | "type": "Cookie", 1444 | "pattern": "(?i)^bigipserver" 1445 | }, 1446 | { 1447 | "type": "Header", 1448 | "header_key": "X-Cnection", 1449 | "header_value": "(?i)close", 1450 | "attack": true 1451 | } 1452 | ], 1453 | "any": true 1454 | } 1455 | ] 1456 | }, 1457 | { 1458 | "name": "AnYu (AnYu Technologies)", 1459 | "schemas": [ 1460 | { 1461 | "fingerprints": [ 1462 | { 1463 | "type": "Content", 1464 | "pattern": "(?i)anyu.{0,10}?the green channel" 1465 | }, 1466 | { 1467 | "type": "Content", 1468 | "pattern": "(?i)your access has been intercepted by anyu" 1469 | } 1470 | ], 1471 | "any": true 1472 | } 1473 | ] 1474 | }, 1475 | { 1476 | "name": "CrawlProtect (Jean-Denis Brun)", 1477 | "schemas": [ 1478 | { 1479 | "fingerprints": [ 1480 | { 1481 | "type": "Cookie", 1482 | "pattern": "(?i)^crawlprotecttag=" 1483 | }, 1484 | { 1485 | "type": "Content", 1486 | "pattern": "(?i)\u003ctitle\u003ecrawlprotect" 1487 | }, 1488 | { 1489 | "type": "Content", 1490 | "pattern": "(?i)this site is protected by crawlprotect" 1491 | } 1492 | ], 1493 | "any": true 1494 | } 1495 | ] 1496 | }, 1497 | { 1498 | "name": "WebLand (WebLand)", 1499 | "schemas": [ 1500 | { 1501 | "fingerprints": [ 1502 | { 1503 | "type": "Header", 1504 | "header_key": "Server", 1505 | "header_value": "(?i)protected by webland" 1506 | } 1507 | ], 1508 | "any": true 1509 | } 1510 | ] 1511 | }, 1512 | { 1513 | "name": "Open-Resty Lua Nginx (FLOSS)", 1514 | "schemas": [ 1515 | { 1516 | "fingerprints": [ 1517 | { 1518 | "type": "Header", 1519 | "header_key": "Server", 1520 | "header_value": "(?i)^openresty/[0-9\\.]+?" 1521 | }, 1522 | { 1523 | "type": "Status", 1524 | "pattern": "403" 1525 | } 1526 | ] 1527 | }, 1528 | { 1529 | "fingerprints": [ 1530 | { 1531 | "type": "Content", 1532 | "pattern": "(?i)openresty/[0-9\\.]+?" 1533 | }, 1534 | { 1535 | "type": "Status", 1536 | "pattern": "406" 1537 | } 1538 | ] 1539 | } 1540 | ] 1541 | }, 1542 | { 1543 | "name": "Kona SiteDefender (Akamai)", 1544 | "schemas": [ 1545 | { 1546 | "fingerprints": [ 1547 | { 1548 | "type": "Header", 1549 | "header_key": "Server", 1550 | "header_value": "(?i)AkamaiGHost" 1551 | }, 1552 | { 1553 | "type": "Header", 1554 | "header_key": "Server", 1555 | "header_value": "(?i)AkamaiGHost", 1556 | "attack": true 1557 | } 1558 | ], 1559 | "any": true 1560 | } 1561 | ] 1562 | }, 1563 | { 1564 | "name": "Wordfence (Defiant)", 1565 | "schemas": [ 1566 | { 1567 | "fingerprints": [ 1568 | { 1569 | "type": "Header", 1570 | "header_key": "Server", 1571 | "header_value": "(?i)wf[_\\-]?WAF" 1572 | }, 1573 | { 1574 | "type": "Content", 1575 | "pattern": "(?i)Generated by Wordfence" 1576 | }, 1577 | { 1578 | "type": "Content", 1579 | "pattern": "(?i)broke one of (the )?Wordfence (advanced )?blocking rules" 1580 | }, 1581 | { 1582 | "type": "Content", 1583 | "pattern": "(?i)/plugins/wordfence" 1584 | } 1585 | ], 1586 | "any": true 1587 | } 1588 | ] 1589 | }, 1590 | { 1591 | "name": "Sucuri CloudProxy (Sucuri Inc.)", 1592 | "schemas": [ 1593 | { 1594 | "fingerprints": [ 1595 | { 1596 | "type": "Header", 1597 | "header_key": "X-Sucuri-ID", 1598 | "header_value": "(?i).+?" 1599 | }, 1600 | { 1601 | "type": "Header", 1602 | "header_key": "X-Sucuri-Cache", 1603 | "header_value": "(?i).+?" 1604 | }, 1605 | { 1606 | "type": "Header", 1607 | "header_key": "Server", 1608 | "header_value": "(?i)Sucuri(\\-Cloudproxy)?" 1609 | }, 1610 | { 1611 | "type": "Header", 1612 | "header_key": "X-Sucuri-Block", 1613 | "header_value": "(?i).+?", 1614 | "attack": true 1615 | }, 1616 | { 1617 | "type": "Content", 1618 | "pattern": "(?i)Access Denied.{0,6}?Sucuri Website Firewall" 1619 | }, 1620 | { 1621 | "type": "Content", 1622 | "pattern": "(?i)\u003ctitle\u003eSucuri WebSite Firewall.{0,6}?(CloudProxy)?.{0,6}?Access Denied" 1623 | }, 1624 | { 1625 | "type": "Content", 1626 | "pattern": "(?i)sucuri\\.net/privacy\\-policy" 1627 | }, 1628 | { 1629 | "type": "Content", 1630 | "pattern": "(?i)cdn\\.sucuri\\.net/sucuri[-_]firewall[-_]block\\.css" 1631 | }, 1632 | { 1633 | "type": "Content", 1634 | "pattern": "(?i)cloudproxy@sucuri\\.net" 1635 | } 1636 | ], 1637 | "any": true 1638 | } 1639 | ] 1640 | }, 1641 | { 1642 | "name": "Sabre Firewall (Sabre)", 1643 | "schemas": [ 1644 | { 1645 | "fingerprints": [ 1646 | { 1647 | "type": "Content", 1648 | "pattern": "(?i)dxsupport\\.sabre\\.com" 1649 | } 1650 | ], 1651 | "any": true 1652 | }, 1653 | { 1654 | "fingerprints": [ 1655 | { 1656 | "type": "Content", 1657 | "pattern": "(?i)\u003ctitle\u003eApplication Firewall Error" 1658 | }, 1659 | { 1660 | "type": "Content", 1661 | "pattern": "(?i)add some important details to the email for us to investigate" 1662 | } 1663 | ] 1664 | } 1665 | ] 1666 | }, 1667 | { 1668 | "name": "Bekchy (Faydata Technologies Inc.)", 1669 | "schemas": [ 1670 | { 1671 | "fingerprints": [ 1672 | { 1673 | "type": "Content", 1674 | "pattern": "(?i)Bekchy.{0,10}?Access Denied" 1675 | }, 1676 | { 1677 | "type": "Content", 1678 | "pattern": "(?i)bekchy\\.com/report" 1679 | } 1680 | ], 1681 | "any": true 1682 | } 1683 | ] 1684 | }, 1685 | { 1686 | "name": "BitNinja (BitNinja)", 1687 | "schemas": [ 1688 | { 1689 | "fingerprints": [ 1690 | { 1691 | "type": "Content", 1692 | "pattern": "(?i)Security check by BitNinja" 1693 | }, 1694 | { 1695 | "type": "Content", 1696 | "pattern": "(?i)Visitor anti-robot validation" 1697 | } 1698 | ], 1699 | "any": true 1700 | } 1701 | ] 1702 | }, 1703 | { 1704 | "name": "WTS-WAF (WTS)", 1705 | "schemas": [ 1706 | { 1707 | "fingerprints": [ 1708 | { 1709 | "type": "Header", 1710 | "header_key": "Server", 1711 | "header_value": "(?i)wts/[0-9\\.]+?" 1712 | }, 1713 | { 1714 | "type": "Content", 1715 | "pattern": "(?i)\u003c(title|h\\d{1})\u003eWTS\\-WAF" 1716 | } 1717 | ], 1718 | "any": true 1719 | } 1720 | ] 1721 | }, 1722 | { 1723 | "name": "Greywizard (Grey Wizard)", 1724 | "schemas": [ 1725 | { 1726 | "fingerprints": [ 1727 | { 1728 | "type": "Header", 1729 | "header_key": "Server", 1730 | "header_value": "(?i)greywizard" 1731 | }, 1732 | { 1733 | "type": "Content", 1734 | "pattern": "(?i)\u003c(title|h\\d{1})\u003eGrey Wizard" 1735 | }, 1736 | { 1737 | "type": "Content", 1738 | "pattern": "(?i)contact the website owner or Grey Wizard" 1739 | }, 1740 | { 1741 | "type": "Content", 1742 | "pattern": "(?i)We.ve detected attempted attack or non standard traffic from your ip address" 1743 | } 1744 | ], 1745 | "any": true 1746 | } 1747 | ] 1748 | }, 1749 | { 1750 | "name": "Puhui (Puhui)", 1751 | "schemas": [ 1752 | { 1753 | "fingerprints": [ 1754 | { 1755 | "type": "Header", 1756 | "header_key": "Server", 1757 | "header_value": "(?i)Puhui[\\-_]?WAF" 1758 | } 1759 | ], 1760 | "any": true 1761 | } 1762 | ] 1763 | }, 1764 | { 1765 | "name": "Cloudfloor (Cloudfloor DNS)", 1766 | "schemas": [ 1767 | { 1768 | "fingerprints": [ 1769 | { 1770 | "type": "Header", 1771 | "header_key": "Server", 1772 | "header_value": "(?i)CloudfloorDNS(.WAF)?" 1773 | }, 1774 | { 1775 | "type": "Content", 1776 | "pattern": "(?i)\u003c(title|h\\d{1})\u003eCloudfloorDNS.{0,6}?Web Application Firewall Error" 1777 | }, 1778 | { 1779 | "type": "Content", 1780 | "pattern": "(?i)www\\.cloudfloordns\\.com/contact" 1781 | } 1782 | ], 1783 | "any": true 1784 | } 1785 | ] 1786 | }, 1787 | { 1788 | "name": "RSFirewall (RSJoomla!)", 1789 | "schemas": [ 1790 | { 1791 | "fingerprints": [ 1792 | { 1793 | "type": "Content", 1794 | "pattern": "(?i)com_rsfirewall_(\\d{3}_forbidden|event)?" 1795 | } 1796 | ], 1797 | "any": true 1798 | } 1799 | ] 1800 | }, 1801 | { 1802 | "name": "Safe3 Web Firewall (Safe3)", 1803 | "schemas": [ 1804 | { 1805 | "fingerprints": [ 1806 | { 1807 | "type": "Header", 1808 | "header_key": "Server", 1809 | "header_value": "(?i)Safe3 Web Firewall" 1810 | }, 1811 | { 1812 | "type": "Header", 1813 | "header_key": "X-Powered-By", 1814 | "header_value": "(?i)Safe3WAF/[\\.0-9]+?" 1815 | }, 1816 | { 1817 | "type": "Content", 1818 | "pattern": "(?i)Safe3waf/[0-9\\.]+?" 1819 | } 1820 | ], 1821 | "any": true 1822 | } 1823 | ] 1824 | }, 1825 | { 1826 | "name": "Zenedge (Zenedge)", 1827 | "schemas": [ 1828 | { 1829 | "fingerprints": [ 1830 | { 1831 | "type": "Header", 1832 | "header_key": "Server", 1833 | "header_value": "(?i)ZENEDGE" 1834 | }, 1835 | { 1836 | "type": "Header", 1837 | "header_key": "X-Zen-Fury", 1838 | "header_value": "(?i).+?" 1839 | }, 1840 | { 1841 | "type": "Content", 1842 | "pattern": "(?i)/__zenedge/" 1843 | } 1844 | ], 1845 | "any": true 1846 | } 1847 | ] 1848 | }, 1849 | { 1850 | "name": "Newdefend (NewDefend)", 1851 | "schemas": [ 1852 | { 1853 | "fingerprints": [ 1854 | { 1855 | "type": "Header", 1856 | "header_key": "Server", 1857 | "header_value": "(?i)Newdefend" 1858 | }, 1859 | { 1860 | "type": "Content", 1861 | "pattern": "(?i)www\\.newdefend\\.com/feedback" 1862 | }, 1863 | { 1864 | "type": "Content", 1865 | "pattern": "(?i)/nd\\-block/" 1866 | } 1867 | ], 1868 | "any": true 1869 | } 1870 | ] 1871 | }, 1872 | { 1873 | "name": "pkSecurity IDS (pkSec)", 1874 | "schemas": [ 1875 | { 1876 | "fingerprints": [ 1877 | { 1878 | "type": "Content", 1879 | "pattern": "(?i)pk.?Security.?Module" 1880 | }, 1881 | { 1882 | "type": "Content", 1883 | "pattern": "(?i)Security.Alert" 1884 | } 1885 | ] 1886 | }, 1887 | { 1888 | "fingerprints": [ 1889 | { 1890 | "type": "Content", 1891 | "pattern": "(?i)As this could be a potential hack attack" 1892 | }, 1893 | { 1894 | "type": "Content", 1895 | "pattern": "(?i)A safety critical (call|request) was (detected|discovered) and blocked" 1896 | }, 1897 | { 1898 | "type": "Content", 1899 | "pattern": "(?i)maximum number of reloads per minute and prevented access" 1900 | } 1901 | ], 1902 | "any": true 1903 | } 1904 | ] 1905 | }, 1906 | { 1907 | "name": "DOSarrest (DOSarrest Internet Security)", 1908 | "schemas": [ 1909 | { 1910 | "fingerprints": [ 1911 | { 1912 | "type": "Header", 1913 | "header_key": "X-DIS-Request-ID", 1914 | "header_value": "(?i).+" 1915 | }, 1916 | { 1917 | "type": "Header", 1918 | "header_key": "Server", 1919 | "header_value": "(?i)DOSarrest(.*)?" 1920 | } 1921 | ], 1922 | "any": true 1923 | } 1924 | ] 1925 | }, 1926 | { 1927 | "name": "Qiniu (Qiniu CDN)", 1928 | "schemas": [ 1929 | { 1930 | "fingerprints": [ 1931 | { 1932 | "type": "Header", 1933 | "header_key": "X-Qiniu-CDN", 1934 | "header_value": "(?i)\\d+?" 1935 | } 1936 | ], 1937 | "any": true 1938 | } 1939 | ] 1940 | }, 1941 | { 1942 | "name": "BinarySec (BinarySec)", 1943 | "schemas": [ 1944 | { 1945 | "fingerprints": [ 1946 | { 1947 | "type": "Header", 1948 | "header_key": "Server", 1949 | "header_value": "(?i)BinarySec" 1950 | }, 1951 | { 1952 | "type": "Header", 1953 | "header_key": "x-binarysec-via", 1954 | "header_value": "(?i).+" 1955 | }, 1956 | { 1957 | "type": "Header", 1958 | "header_key": "x-binarysec-nocache", 1959 | "header_value": "(?i).+" 1960 | } 1961 | ], 1962 | "any": true 1963 | } 1964 | ] 1965 | }, 1966 | { 1967 | "name": "WebTotem (WebTotem)", 1968 | "schemas": [ 1969 | { 1970 | "fingerprints": [ 1971 | { 1972 | "type": "Content", 1973 | "pattern": "(?i)The current request was blocked.{0,8}?\u003eWebTotem" 1974 | } 1975 | ], 1976 | "any": true 1977 | } 1978 | ] 1979 | }, 1980 | { 1981 | "name": "Imunify360 (CloudLinux)", 1982 | "schemas": [ 1983 | { 1984 | "fingerprints": [ 1985 | { 1986 | "type": "Header", 1987 | "header_key": "Server", 1988 | "header_value": "(?i)imunify360.{0,10}?" 1989 | }, 1990 | { 1991 | "type": "Content", 1992 | "pattern": "(?i)protected.by.{0,10}?imunify360" 1993 | }, 1994 | { 1995 | "type": "Content", 1996 | "pattern": "(?i)powered.by.{0,10}?imunify360" 1997 | }, 1998 | { 1999 | "type": "Content", 2000 | "pattern": "(?i)imunify360.preloader" 2001 | } 2002 | ], 2003 | "any": true 2004 | } 2005 | ] 2006 | }, 2007 | { 2008 | "name": "Anquanbao (Anquanbao)", 2009 | "schemas": [ 2010 | { 2011 | "fingerprints": [ 2012 | { 2013 | "type": "Header", 2014 | "header_key": "X-Powered-By-Anquanbao", 2015 | "header_value": "(?i).+?" 2016 | }, 2017 | { 2018 | "type": "Content", 2019 | "pattern": "(?i)aqb_cc/error/" 2020 | } 2021 | ], 2022 | "any": true 2023 | } 2024 | ] 2025 | }, 2026 | { 2027 | "name": "AliYunDun (Alibaba Cloud Computing)", 2028 | "schemas": [ 2029 | { 2030 | "fingerprints": [ 2031 | { 2032 | "type": "Content", 2033 | "pattern": "(?i)error(s)?\\.aliyun(dun)?\\.(com|net)?" 2034 | }, 2035 | { 2036 | "type": "Cookie", 2037 | "pattern": "(?i)^aliyungf_tc=" 2038 | }, 2039 | { 2040 | "type": "Content", 2041 | "pattern": "(?i)cdn\\.aliyun(cs)?\\.com" 2042 | }, 2043 | { 2044 | "type": "Status", 2045 | "pattern": "405" 2046 | } 2047 | ] 2048 | } 2049 | ] 2050 | }, 2051 | { 2052 | "name": "PowerCDN (PowerCDN)", 2053 | "schemas": [ 2054 | { 2055 | "fingerprints": [ 2056 | { 2057 | "type": "Header", 2058 | "header_key": "Via", 2059 | "header_value": "(?i)(.*)?powercdn.com(.*)?" 2060 | }, 2061 | { 2062 | "type": "Header", 2063 | "header_key": "X-Cache", 2064 | "header_value": "(?i)(.*)?powercdn.com(.*)?" 2065 | }, 2066 | { 2067 | "type": "Header", 2068 | "header_key": "X-CDN", 2069 | "header_value": "(?i)PowerCDN" 2070 | } 2071 | ], 2072 | "any": true 2073 | } 2074 | ] 2075 | }, 2076 | { 2077 | "name": "Distil (Distil Networks)", 2078 | "schemas": [ 2079 | { 2080 | "fingerprints": [ 2081 | { 2082 | "type": "Content", 2083 | "pattern": "(?i)cdn\\.distilnetworks\\.com/images/anomaly\\.detected\\.png" 2084 | }, 2085 | { 2086 | "type": "Content", 2087 | "pattern": "(?i)distilCaptchaForm" 2088 | }, 2089 | { 2090 | "type": "Content", 2091 | "pattern": "(?i)distilCallbackGuard" 2092 | } 2093 | ], 2094 | "any": true 2095 | } 2096 | ] 2097 | }, 2098 | { 2099 | "name": "West263 CDN (West263CDN)", 2100 | "schemas": [ 2101 | { 2102 | "fingerprints": [ 2103 | { 2104 | "type": "Header", 2105 | "header_key": "X-Cache", 2106 | "header_value": "(?i)WS?T263CDN" 2107 | } 2108 | ], 2109 | "any": true 2110 | } 2111 | ] 2112 | }, 2113 | { 2114 | "name": "Instart DX (Instart Logic)", 2115 | "schemas": [ 2116 | { 2117 | "fingerprints": [ 2118 | { 2119 | "type": "Header", 2120 | "header_key": "X-Instart-Request-ID", 2121 | "header_value": "(?i).+" 2122 | }, 2123 | { 2124 | "type": "Header", 2125 | "header_key": "X-Instart-Cache", 2126 | "header_value": "(?i).+" 2127 | }, 2128 | { 2129 | "type": "Header", 2130 | "header_key": "X-Instart-WL", 2131 | "header_value": "(?i).+" 2132 | } 2133 | ], 2134 | "any": true 2135 | }, 2136 | { 2137 | "fingerprints": [ 2138 | { 2139 | "type": "Content", 2140 | "pattern": "(?i)the requested url was rejected" 2141 | }, 2142 | { 2143 | "type": "Content", 2144 | "pattern": "(?i)please consult with your administrator" 2145 | }, 2146 | { 2147 | "type": "Content", 2148 | "pattern": "(?i)your support id is" 2149 | } 2150 | ] 2151 | } 2152 | ] 2153 | }, 2154 | { 2155 | "name": "PerimeterX (PerimeterX)", 2156 | "schemas": [ 2157 | { 2158 | "fingerprints": [ 2159 | { 2160 | "type": "Content", 2161 | "pattern": "(?i)www\\.perimeterx\\.(com|net)/whywasiblocked" 2162 | }, 2163 | { 2164 | "type": "Content", 2165 | "pattern": "(?i)client\\.perimeterx\\.(net|com)" 2166 | }, 2167 | { 2168 | "type": "Content", 2169 | "pattern": "(?i)denied because we believe you are using automation tools" 2170 | } 2171 | ], 2172 | "any": true 2173 | } 2174 | ] 2175 | }, 2176 | { 2177 | "name": "XLabs Security WAF (XLabs)", 2178 | "schemas": [ 2179 | { 2180 | "fingerprints": [ 2181 | { 2182 | "type": "Header", 2183 | "header_key": "X-CDN", 2184 | "header_value": "(?i)XLabs Security" 2185 | }, 2186 | { 2187 | "type": "Header", 2188 | "header_key": "Secured", 2189 | "header_value": "(?i)^By XLabs Security" 2190 | }, 2191 | { 2192 | "type": "Header", 2193 | "header_key": "Server", 2194 | "header_value": "(?i)XLabs[-_]?.?WAF", 2195 | "attack": true 2196 | } 2197 | ], 2198 | "any": true 2199 | } 2200 | ] 2201 | }, 2202 | { 2203 | "name": "YXLink (YxLink Technologies)", 2204 | "schemas": [ 2205 | { 2206 | "fingerprints": [ 2207 | { 2208 | "type": "Cookie", 2209 | "pattern": "(?i)^yx_ci_session=" 2210 | }, 2211 | { 2212 | "type": "Cookie", 2213 | "pattern": "(?i)^yx_language=" 2214 | }, 2215 | { 2216 | "type": "Header", 2217 | "header_key": "Server", 2218 | "header_value": "(?i)Yxlink([\\-_]?WAF)?" 2219 | } 2220 | ], 2221 | "any": true 2222 | } 2223 | ] 2224 | }, 2225 | { 2226 | "name": "Armor Defense (Armor)", 2227 | "schemas": [ 2228 | { 2229 | "fingerprints": [ 2230 | { 2231 | "type": "Content", 2232 | "pattern": "(?i)blocked by website protection from armor" 2233 | }, 2234 | { 2235 | "type": "Content", 2236 | "pattern": "(?i)please create an armor support ticket" 2237 | } 2238 | ], 2239 | "any": true 2240 | } 2241 | ] 2242 | }, 2243 | { 2244 | "name": "wpmudev WAF (Incsub)", 2245 | "schemas": [ 2246 | { 2247 | "fingerprints": [ 2248 | { 2249 | "type": "Content", 2250 | "pattern": "(?i)href=\"http(s)?.\\/\\/wpmudev.com\\/.{0,15}?" 2251 | }, 2252 | { 2253 | "type": "Content", 2254 | "pattern": "(?i)Click on the Logs tab, then the WAF Log." 2255 | }, 2256 | { 2257 | "type": "Content", 2258 | "pattern": "(?i)Choose your site from the list" 2259 | }, 2260 | { 2261 | "type": "Status", 2262 | "pattern": "403" 2263 | } 2264 | ] 2265 | }, 2266 | { 2267 | "fingerprints": [ 2268 | { 2269 | "type": "Content", 2270 | "pattern": "(?i)\u003ch1\u003eWhoops, this request has been blocked!" 2271 | }, 2272 | { 2273 | "type": "Content", 2274 | "pattern": "(?i)This request has been deemed suspicious" 2275 | }, 2276 | { 2277 | "type": "Content", 2278 | "pattern": "(?i)possible attack on our servers." 2279 | }, 2280 | { 2281 | "type": "Status", 2282 | "pattern": "403" 2283 | } 2284 | ] 2285 | } 2286 | ] 2287 | }, 2288 | { 2289 | "name": "SecureSphere (Imperva Inc.)", 2290 | "schemas": [ 2291 | { 2292 | "fingerprints": [ 2293 | { 2294 | "type": "Content", 2295 | "pattern": "(?i)\u003c(title|h2)\u003eError" 2296 | }, 2297 | { 2298 | "type": "Content", 2299 | "pattern": "(?i)The incident ID is" 2300 | }, 2301 | { 2302 | "type": "Content", 2303 | "pattern": "(?i)This page can't be displayed" 2304 | }, 2305 | { 2306 | "type": "Content", 2307 | "pattern": "(?i)Contact support for additional information" 2308 | } 2309 | ] 2310 | } 2311 | ] 2312 | }, 2313 | { 2314 | "name": "Eisoo Cloud Firewall (Eisoo)", 2315 | "schemas": [ 2316 | { 2317 | "fingerprints": [ 2318 | { 2319 | "type": "Header", 2320 | "header_key": "Server", 2321 | "header_value": "(?i)EisooWAF(\\-AZURE)?/?" 2322 | }, 2323 | { 2324 | "type": "Content", 2325 | "pattern": "(?i)\u003clink.{0,10}?href=\\\"/eisoo\\-firewall\\-block\\.css" 2326 | }, 2327 | { 2328 | "type": "Content", 2329 | "pattern": "(?i)www\\.eisoo\\.com" 2330 | }, 2331 | { 2332 | "type": "Content", 2333 | "pattern": "(?i)\u0026copy; \\d{4} Eisoo Inc" 2334 | } 2335 | ], 2336 | "any": true 2337 | } 2338 | ] 2339 | }, 2340 | { 2341 | "name": "DataPower (IBM)", 2342 | "schemas": [ 2343 | { 2344 | "fingerprints": [ 2345 | { 2346 | "type": "Header", 2347 | "header_key": "X-Backside-Transport", 2348 | "header_value": "(?i)(OK|FAIL)" 2349 | } 2350 | ], 2351 | "any": true 2352 | } 2353 | ] 2354 | }, 2355 | { 2356 | "name": "WatchGuard (WatchGuard Technologies)", 2357 | "schemas": [ 2358 | { 2359 | "fingerprints": [ 2360 | { 2361 | "type": "Header", 2362 | "header_key": "Server", 2363 | "header_value": "(?i)WatchGuard" 2364 | }, 2365 | { 2366 | "type": "Content", 2367 | "pattern": "(?i)Request denied by WatchGuard Firewall" 2368 | }, 2369 | { 2370 | "type": "Content", 2371 | "pattern": "(?i)WatchGuard Technologies Inc\\." 2372 | } 2373 | ], 2374 | "any": true 2375 | } 2376 | ] 2377 | }, 2378 | { 2379 | "name": "Safeline (Chaitin Tech.)", 2380 | "schemas": [ 2381 | { 2382 | "fingerprints": [ 2383 | { 2384 | "type": "Content", 2385 | "pattern": "(?i)safeline|\u003c!\\-\\-\\sevent id:" 2386 | } 2387 | ], 2388 | "any": true 2389 | } 2390 | ] 2391 | }, 2392 | { 2393 | "name": "Mission Control Shield (Mission Control)", 2394 | "schemas": [ 2395 | { 2396 | "fingerprints": [ 2397 | { 2398 | "type": "Header", 2399 | "header_key": "Server", 2400 | "header_value": "(?i)Mission Control Application Shield" 2401 | } 2402 | ], 2403 | "any": true 2404 | } 2405 | ] 2406 | }, 2407 | { 2408 | "name": "AireeCDN (Airee)", 2409 | "schemas": [ 2410 | { 2411 | "fingerprints": [ 2412 | { 2413 | "type": "Header", 2414 | "header_key": "Server", 2415 | "header_value": "(?i)Airee" 2416 | }, 2417 | { 2418 | "type": "Header", 2419 | "header_key": "X-Cache", 2420 | "header_value": "(?i)(\\w+\\.)?airee\\.cloud" 2421 | }, 2422 | { 2423 | "type": "Content", 2424 | "pattern": "(?i)airee\\.cloud" 2425 | } 2426 | ], 2427 | "any": true 2428 | } 2429 | ] 2430 | }, 2431 | { 2432 | "name": "Viettel (Cloudrity)", 2433 | "schemas": [ 2434 | { 2435 | "fingerprints": [ 2436 | { 2437 | "type": "Content", 2438 | "pattern": "(?i)Access Denied.{0,10}?Viettel WAF" 2439 | }, 2440 | { 2441 | "type": "Content", 2442 | "pattern": "(?i)cloudrity\\.com\\.(vn)?/" 2443 | }, 2444 | { 2445 | "type": "Content", 2446 | "pattern": "(?i)Viettel WAF System" 2447 | } 2448 | ], 2449 | "any": true 2450 | } 2451 | ] 2452 | }, 2453 | { 2454 | "name": "AWS Elastic Load Balancer (Amazon)", 2455 | "schemas": [ 2456 | { 2457 | "fingerprints": [ 2458 | { 2459 | "type": "Header", 2460 | "header_key": "X-AMZ-ID", 2461 | "header_value": "(?i).+?" 2462 | }, 2463 | { 2464 | "type": "Header", 2465 | "header_key": "X-AMZ-Request-ID", 2466 | "header_value": "(?i).+?" 2467 | }, 2468 | { 2469 | "type": "Cookie", 2470 | "pattern": "(?i)^aws.?alb=" 2471 | }, 2472 | { 2473 | "type": "Header", 2474 | "header_key": "Server", 2475 | "header_value": "(?i)aws.?elb", 2476 | "attack": true 2477 | } 2478 | ], 2479 | "any": true 2480 | } 2481 | ] 2482 | }, 2483 | { 2484 | "name": "UTM Web Protection (Sophos)", 2485 | "schemas": [ 2486 | { 2487 | "fingerprints": [ 2488 | { 2489 | "type": "Content", 2490 | "pattern": "(?i)www\\.sophos\\.com" 2491 | }, 2492 | { 2493 | "type": "Content", 2494 | "pattern": "(?i)Powered by.?(Sophos)? UTM Web Protection" 2495 | } 2496 | ], 2497 | "any": true 2498 | }, 2499 | { 2500 | "fingerprints": [ 2501 | { 2502 | "type": "Content", 2503 | "pattern": "(?i)\u003ctitle\u003eAccess to the requested URL was blocked" 2504 | }, 2505 | { 2506 | "type": "Content", 2507 | "pattern": "(?i)Access to the requested URL was blocked" 2508 | }, 2509 | { 2510 | "type": "Content", 2511 | "pattern": "(?i)incident was logged with the following log identifier" 2512 | }, 2513 | { 2514 | "type": "Content", 2515 | "pattern": "(?i)Inbound Anomaly Score exceeded" 2516 | }, 2517 | { 2518 | "type": "Content", 2519 | "pattern": "(?i)Your cache administrator is" 2520 | } 2521 | ] 2522 | } 2523 | ] 2524 | }, 2525 | { 2526 | "name": "Malcare (Inactiv)", 2527 | "schemas": [ 2528 | { 2529 | "fingerprints": [ 2530 | { 2531 | "type": "Content", 2532 | "pattern": "(?i)firewall.{0,15}?powered.by.{0,15}?malcare.{0,15}?pro" 2533 | }, 2534 | { 2535 | "type": "Content", 2536 | "pattern": "(?i)blocked because of malicious activities" 2537 | } 2538 | ], 2539 | "any": true 2540 | } 2541 | ] 2542 | }, 2543 | { 2544 | "name": "NullDDoS Protection (NullDDoS)", 2545 | "schemas": [ 2546 | { 2547 | "fingerprints": [ 2548 | { 2549 | "type": "Header", 2550 | "header_key": "Server", 2551 | "header_value": "(?i)NullDDoS(.System)?" 2552 | } 2553 | ], 2554 | "any": true 2555 | } 2556 | ] 2557 | }, 2558 | { 2559 | "name": "Bluedon (Bluedon IST)", 2560 | "schemas": [ 2561 | { 2562 | "fingerprints": [ 2563 | { 2564 | "type": "Header", 2565 | "header_key": "Server", 2566 | "header_value": "(?i)BDWAF" 2567 | }, 2568 | { 2569 | "type": "Content", 2570 | "pattern": "(?i)bluedon web application firewall" 2571 | } 2572 | ], 2573 | "any": true 2574 | } 2575 | ] 2576 | }, 2577 | { 2578 | "name": "Shield Security (One Dollar Plugin)", 2579 | "schemas": [ 2580 | { 2581 | "fingerprints": [ 2582 | { 2583 | "type": "Content", 2584 | "pattern": "(?i)You were blocked by the Shield" 2585 | }, 2586 | { 2587 | "type": "Content", 2588 | "pattern": "(?i)remaining transgression\\(s\\) against this site" 2589 | }, 2590 | { 2591 | "type": "Content", 2592 | "pattern": "(?i)Something in the URL.{0,5}?Form or Cookie data wasn\\'t appropriate" 2593 | } 2594 | ], 2595 | "any": true 2596 | } 2597 | ] 2598 | }, 2599 | { 2600 | "name": "Cloudflare (Cloudflare Inc.)", 2601 | "schemas": [ 2602 | { 2603 | "fingerprints": [ 2604 | { 2605 | "type": "Header", 2606 | "header_key": "server", 2607 | "header_value": "(?i)cloudflare" 2608 | }, 2609 | { 2610 | "type": "Header", 2611 | "header_key": "server", 2612 | "header_value": "(?i)cloudflare[-_]nginx" 2613 | }, 2614 | { 2615 | "type": "Header", 2616 | "header_key": "cf-ray", 2617 | "header_value": "(?i).+?" 2618 | }, 2619 | { 2620 | "type": "Cookie", 2621 | "pattern": "(?i)__cfduid" 2622 | } 2623 | ], 2624 | "any": true 2625 | } 2626 | ] 2627 | }, 2628 | { 2629 | "name": "Barikode (Ethic Ninja)", 2630 | "schemas": [ 2631 | { 2632 | "fingerprints": [ 2633 | { 2634 | "type": "Content", 2635 | "pattern": "(?i)\u003cstrong\u003ebarikode\u003c.strong\u003e" 2636 | } 2637 | ], 2638 | "any": true 2639 | } 2640 | ] 2641 | }, 2642 | { 2643 | "name": "DynamicWeb Injection Check (DynamicWeb)", 2644 | "schemas": [ 2645 | { 2646 | "fingerprints": [ 2647 | { 2648 | "type": "Header", 2649 | "header_key": "X-403-Status-By", 2650 | "header_value": "(?i)dw.inj.check", 2651 | "attack": true 2652 | }, 2653 | { 2654 | "type": "Content", 2655 | "pattern": "(?i)by dynamic check(.{0,10}?module)?" 2656 | } 2657 | ], 2658 | "any": true 2659 | } 2660 | ] 2661 | }, 2662 | { 2663 | "name": "PT Application Firewall (Positive Technologies)", 2664 | "schemas": [ 2665 | { 2666 | "fingerprints": [ 2667 | { 2668 | "type": "Content", 2669 | "pattern": "(?i)\u003ch1.{0,10}?Forbidden" 2670 | }, 2671 | { 2672 | "type": "Content", 2673 | "pattern": "(?i)\u003cpre\u003eRequest.ID:.{0,10}?\\d{4}\\-(\\d{2})+.{0,35}?pre\u003e" 2674 | } 2675 | ] 2676 | } 2677 | ] 2678 | }, 2679 | { 2680 | "name": "OnMessage Shield (BlackBaud)", 2681 | "schemas": [ 2682 | { 2683 | "fingerprints": [ 2684 | { 2685 | "type": "Header", 2686 | "header_key": "X-Engine", 2687 | "header_value": "(?i)onMessage Shield" 2688 | }, 2689 | { 2690 | "type": "Content", 2691 | "pattern": "(?i)Blackbaud K\\-12 conducts routine maintenance" 2692 | }, 2693 | { 2694 | "type": "Content", 2695 | "pattern": "(?i)onMessage SHEILD" 2696 | }, 2697 | { 2698 | "type": "Content", 2699 | "pattern": "(?i)maintenance\\.blackbaud\\.com" 2700 | }, 2701 | { 2702 | "type": "Content", 2703 | "pattern": "(?i)status\\.blackbaud\\.com" 2704 | } 2705 | ], 2706 | "any": true 2707 | } 2708 | ] 2709 | }, 2710 | { 2711 | "name": "LimeLight CDN (LimeLight)", 2712 | "schemas": [ 2713 | { 2714 | "fingerprints": [ 2715 | { 2716 | "type": "Cookie", 2717 | "pattern": "(?i)^limelight" 2718 | }, 2719 | { 2720 | "type": "Cookie", 2721 | "pattern": "(?i)^l[mg]_sessid=" 2722 | } 2723 | ], 2724 | "any": true 2725 | } 2726 | ] 2727 | }, 2728 | { 2729 | "name": "Janusec Application Gateway (Janusec)", 2730 | "schemas": [ 2731 | { 2732 | "fingerprints": [ 2733 | { 2734 | "type": "Content", 2735 | "pattern": "(?i)janusec application gateway" 2736 | } 2737 | ], 2738 | "any": true 2739 | } 2740 | ] 2741 | }, 2742 | { 2743 | "name": "WebSEAL (IBM)", 2744 | "schemas": [ 2745 | { 2746 | "fingerprints": [ 2747 | { 2748 | "type": "Header", 2749 | "header_key": "Server", 2750 | "header_value": "(?i)WebSEAL" 2751 | }, 2752 | { 2753 | "type": "Content", 2754 | "pattern": "(?i)This is a WebSEAL error message template file" 2755 | }, 2756 | { 2757 | "type": "Content", 2758 | "pattern": "(?i)WebSEAL server received an invalid HTTP request" 2759 | } 2760 | ], 2761 | "any": true 2762 | } 2763 | ] 2764 | }, 2765 | { 2766 | "name": "Palo Alto Next Gen Firewall (Palo Alto Networks)", 2767 | "schemas": [ 2768 | { 2769 | "fingerprints": [ 2770 | { 2771 | "type": "Content", 2772 | "pattern": "(?i)Download of virus.spyware blocked" 2773 | }, 2774 | { 2775 | "type": "Content", 2776 | "pattern": "(?i)Palo Alto Next Generation Security Platform" 2777 | } 2778 | ], 2779 | "any": true 2780 | } 2781 | ] 2782 | }, 2783 | { 2784 | "name": "PentaWAF (Global Network Services)", 2785 | "schemas": [ 2786 | { 2787 | "fingerprints": [ 2788 | { 2789 | "type": "Header", 2790 | "header_key": "Server", 2791 | "header_value": "(?i)PentaWaf(/[0-9\\.]+)?" 2792 | }, 2793 | { 2794 | "type": "Content", 2795 | "pattern": "(?i)Penta.?Waf/[0-9\\.]+?.server" 2796 | } 2797 | ], 2798 | "any": true 2799 | } 2800 | ] 2801 | }, 2802 | { 2803 | "name": "BIG-IP AppSec Manager (F5 Networks)", 2804 | "schemas": [ 2805 | { 2806 | "fingerprints": [ 2807 | { 2808 | "type": "Content", 2809 | "pattern": "(?i)the requested url was rejected" 2810 | }, 2811 | { 2812 | "type": "Content", 2813 | "pattern": "(?i)please consult with your administrator" 2814 | } 2815 | ] 2816 | }, 2817 | { 2818 | "fingerprints": [ 2819 | { 2820 | "type": "Cookie", 2821 | "pattern": "(?i)^TS.+?" 2822 | } 2823 | ] 2824 | } 2825 | ] 2826 | }, 2827 | { 2828 | "name": "ZScaler (Accenture)", 2829 | "schemas": [ 2830 | { 2831 | "fingerprints": [ 2832 | { 2833 | "type": "Header", 2834 | "header_key": "Server", 2835 | "header_value": "(?i)ZScaler" 2836 | }, 2837 | { 2838 | "type": "Content", 2839 | "pattern": "(?i)Access Denied.{0,10}?Accenture Policy" 2840 | }, 2841 | { 2842 | "type": "Content", 2843 | "pattern": "(?i)policies\\.accenture\\.com" 2844 | }, 2845 | { 2846 | "type": "Content", 2847 | "pattern": "(?i)login\\.zscloud\\.net/img_logo_new1\\.png" 2848 | }, 2849 | { 2850 | "type": "Content", 2851 | "pattern": "(?i)Zscaler to protect you from internet threats" 2852 | }, 2853 | { 2854 | "type": "Content", 2855 | "pattern": "(?i)Internet Security by ZScaler" 2856 | }, 2857 | { 2858 | "type": "Content", 2859 | "pattern": "(?i)Accenture.{0,10}?webfilters indicate that the site likely contains" 2860 | } 2861 | ], 2862 | "any": true 2863 | } 2864 | ] 2865 | }, 2866 | { 2867 | "name": "AzionCDN (AzionCDN)", 2868 | "schemas": [ 2869 | { 2870 | "fingerprints": [ 2871 | { 2872 | "type": "Header", 2873 | "header_key": "Server", 2874 | "header_value": "(?i)Azion([-_]CDN)?" 2875 | } 2876 | ], 2877 | "any": true 2878 | } 2879 | ] 2880 | }, 2881 | { 2882 | "name": "BulletProof Security Pro (AITpro Security)", 2883 | "schemas": [ 2884 | { 2885 | "fingerprints": [ 2886 | { 2887 | "type": "Content", 2888 | "pattern": "(?i)\\+?bpsMessage" 2889 | }, 2890 | { 2891 | "type": "Content", 2892 | "pattern": "(?i)403 Forbidden Error Page" 2893 | }, 2894 | { 2895 | "type": "Content", 2896 | "pattern": "(?i)If you arrived here due to a search" 2897 | } 2898 | ] 2899 | } 2900 | ] 2901 | }, 2902 | { 2903 | "name": "FortiWeb (Fortinet)", 2904 | "schemas": [ 2905 | { 2906 | "fingerprints": [ 2907 | { 2908 | "type": "Cookie", 2909 | "pattern": "(?i)^FORTIWAFSID=" 2910 | }, 2911 | { 2912 | "type": "Content", 2913 | "pattern": "(?i).fgd_icon" 2914 | } 2915 | ], 2916 | "any": true 2917 | }, 2918 | { 2919 | "fingerprints": [ 2920 | { 2921 | "type": "Content", 2922 | "pattern": "(?i)fgd_icon" 2923 | }, 2924 | { 2925 | "type": "Content", 2926 | "pattern": "(?i)web.page.blocked" 2927 | }, 2928 | { 2929 | "type": "Content", 2930 | "pattern": "(?i)url" 2931 | }, 2932 | { 2933 | "type": "Content", 2934 | "pattern": "(?i)attack.id" 2935 | }, 2936 | { 2937 | "type": "Content", 2938 | "pattern": "(?i)message.id" 2939 | }, 2940 | { 2941 | "type": "Content", 2942 | "pattern": "(?i)client.ip" 2943 | } 2944 | ] 2945 | } 2946 | ] 2947 | }, 2948 | { 2949 | "name": "DotDefender (Applicure Technologies)", 2950 | "schemas": [ 2951 | { 2952 | "fingerprints": [ 2953 | { 2954 | "type": "Header", 2955 | "header_key": "X-dotDefender-denied", 2956 | "header_value": "(?i).+?", 2957 | "attack": true 2958 | }, 2959 | { 2960 | "type": "Content", 2961 | "pattern": "(?i)dotdefender blocked your request" 2962 | }, 2963 | { 2964 | "type": "Content", 2965 | "pattern": "(?i)Applicure is the leading provider of web application security" 2966 | } 2967 | ], 2968 | "any": true 2969 | } 2970 | ] 2971 | }, 2972 | { 2973 | "name": "KS-WAF (KnownSec)", 2974 | "schemas": [ 2975 | { 2976 | "fingerprints": [ 2977 | { 2978 | "type": "Content", 2979 | "pattern": "(?i)/ks[-_]waf[-_]error\\.png" 2980 | } 2981 | ], 2982 | "any": true 2983 | } 2984 | ] 2985 | }, 2986 | { 2987 | "name": "Cloud Protector (Rohde \u0026 Schwarz CyberSecurity)", 2988 | "schemas": [ 2989 | { 2990 | "fingerprints": [ 2991 | { 2992 | "type": "Content", 2993 | "pattern": "(?i)Cloud Protector.*?by Rohde.{3,8}?Schwarz Cybersecurity" 2994 | }, 2995 | { 2996 | "type": "Content", 2997 | "pattern": "(?i)\u003ca href='https?:\\/\\/(?:www\\.)?cloudprotector\\.com\\/'\u003eR.{1,6}?S.Cloud Protector" 2998 | } 2999 | ], 3000 | "any": true 3001 | } 3002 | ] 3003 | }, 3004 | { 3005 | "name": "ServerDefender VP (Port80 Software)", 3006 | "schemas": [ 3007 | { 3008 | "fingerprints": [ 3009 | { 3010 | "type": "Header", 3011 | "header_key": "X-Pint", 3012 | "header_value": "(?i)p(ort\\-)?80" 3013 | } 3014 | ], 3015 | "any": true 3016 | } 3017 | ] 3018 | }, 3019 | { 3020 | "name": "Alert Logic (Alert Logic)", 3021 | "schemas": [ 3022 | { 3023 | "fingerprints": [ 3024 | { 3025 | "type": "Content", 3026 | "pattern": "(?i)\u003c(title|h\\d{1})\u003erequested url cannot be found" 3027 | }, 3028 | { 3029 | "type": "Content", 3030 | "pattern": "(?i)we are sorry.{0,10}?but the page you are looking for cannot be found" 3031 | }, 3032 | { 3033 | "type": "Content", 3034 | "pattern": "(?i)back to previous page" 3035 | }, 3036 | { 3037 | "type": "Content", 3038 | "pattern": "(?i)proceed to homepage" 3039 | }, 3040 | { 3041 | "type": "Content", 3042 | "pattern": "(?i)reference id" 3043 | } 3044 | ] 3045 | } 3046 | ] 3047 | }, 3048 | { 3049 | "name": "Cloudfront (Amazon)", 3050 | "schemas": [ 3051 | { 3052 | "fingerprints": [ 3053 | { 3054 | "type": "Header", 3055 | "header_key": "Server", 3056 | "header_value": "(?i)Cloudfront" 3057 | }, 3058 | { 3059 | "type": "Header", 3060 | "header_key": "Via", 3061 | "header_value": "(?i)([0-9\\.]+?)? \\w+?\\.cloudfront\\.net \\(Cloudfront\\)" 3062 | }, 3063 | { 3064 | "type": "Header", 3065 | "header_key": "X-Amz-Cf-Id", 3066 | "header_value": "(?i).+?", 3067 | "attack": true 3068 | }, 3069 | { 3070 | "type": "Header", 3071 | "header_key": "X-Cache", 3072 | "header_value": "(?i)Error from Cloudfront", 3073 | "attack": true 3074 | }, 3075 | { 3076 | "type": "Content", 3077 | "pattern": "(?i)Generated by cloudfront \\(CloudFront\\)" 3078 | } 3079 | ], 3080 | "any": true 3081 | } 3082 | ] 3083 | }, 3084 | { 3085 | "name": "Xuanwudun (Xuanwudun)", 3086 | "schemas": [ 3087 | { 3088 | "fingerprints": [ 3089 | { 3090 | "type": "Content", 3091 | "pattern": "(?i)admin\\.dbappwaf\\.cn/(index\\.php/Admin/ClientMisinform/)?" 3092 | }, 3093 | { 3094 | "type": "Content", 3095 | "pattern": "(?i)class=.(db[\\-_]?)?waf(.)?([\\-_]?row)?\u003e" 3096 | } 3097 | ], 3098 | "any": true 3099 | } 3100 | ] 3101 | }, 3102 | { 3103 | "name": "Wallarm (Wallarm Inc.)", 3104 | "schemas": [ 3105 | { 3106 | "fingerprints": [ 3107 | { 3108 | "type": "Header", 3109 | "header_key": "Server", 3110 | "header_value": "(?i)nginx[\\-_]wallarm" 3111 | } 3112 | ], 3113 | "any": true 3114 | } 3115 | ] 3116 | }, 3117 | { 3118 | "name": "DenyALL (Rohde \u0026 Schwarz CyberSecurity)", 3119 | "schemas": [ 3120 | { 3121 | "fingerprints": [ 3122 | { 3123 | "type": "Status", 3124 | "pattern": "200" 3125 | }, 3126 | { 3127 | "type": "Reason", 3128 | "pattern": "(?i)Condition Intercepted" 3129 | } 3130 | ] 3131 | } 3132 | ] 3133 | }, 3134 | { 3135 | "name": "Yundun (Yundun)", 3136 | "schemas": [ 3137 | { 3138 | "fingerprints": [ 3139 | { 3140 | "type": "Header", 3141 | "header_key": "Server", 3142 | "header_value": "(?i)YUNDUN" 3143 | }, 3144 | { 3145 | "type": "Header", 3146 | "header_key": "X-Cache", 3147 | "header_value": "(?i)YUNDUN" 3148 | }, 3149 | { 3150 | "type": "Cookie", 3151 | "pattern": "(?i)^yd_cookie=" 3152 | }, 3153 | { 3154 | "type": "Content", 3155 | "pattern": "(?i)Blocked by YUNDUN Cloud WAF" 3156 | }, 3157 | { 3158 | "type": "Content", 3159 | "pattern": "(?i)yundun\\.com/yd[-_]http[_-]error/" 3160 | }, 3161 | { 3162 | "type": "Content", 3163 | "pattern": "(?i)www\\.yundun\\.com/(static/js/fingerprint\\d{1}?\\.js)?" 3164 | } 3165 | ], 3166 | "any": true 3167 | } 3168 | ] 3169 | }, 3170 | { 3171 | "name": "360WangZhanBao (360 Technologies)", 3172 | "schemas": [ 3173 | { 3174 | "fingerprints": [ 3175 | { 3176 | "type": "Header", 3177 | "header_key": "Server", 3178 | "header_value": "(?i)qianxin\\-waf" 3179 | }, 3180 | { 3181 | "type": "Header", 3182 | "header_key": "WZWS-Ray", 3183 | "header_value": "(?i).+?" 3184 | }, 3185 | { 3186 | "type": "Header", 3187 | "header_key": "X-Powered-By-360WZB", 3188 | "header_value": "(?i).+?" 3189 | }, 3190 | { 3191 | "type": "Content", 3192 | "pattern": "(?i)wzws\\-waf\\-cgi/" 3193 | }, 3194 | { 3195 | "type": "Content", 3196 | "pattern": "(?i)wangshan\\.360\\.cn" 3197 | }, 3198 | { 3199 | "type": "Status", 3200 | "pattern": "493" 3201 | } 3202 | ], 3203 | "any": true 3204 | } 3205 | ] 3206 | }, 3207 | { 3208 | "name": "ModSecurity (SpiderLabs)", 3209 | "schemas": [ 3210 | { 3211 | "fingerprints": [ 3212 | { 3213 | "type": "Header", 3214 | "header_key": "Server", 3215 | "header_value": "(?i)(mod_security|Mod_Security|NOYB)" 3216 | }, 3217 | { 3218 | "type": "Content", 3219 | "pattern": "(?i)This error was generated by Mod.?Security" 3220 | }, 3221 | { 3222 | "type": "Content", 3223 | "pattern": "(?i)rules of the mod.security.module" 3224 | }, 3225 | { 3226 | "type": "Content", 3227 | "pattern": "(?i)mod.security.rules triggered" 3228 | }, 3229 | { 3230 | "type": "Content", 3231 | "pattern": "(?i)Protected by Mod.?Security" 3232 | }, 3233 | { 3234 | "type": "Content", 3235 | "pattern": "(?i)/modsecurity[\\-_]errorpage/" 3236 | }, 3237 | { 3238 | "type": "Content", 3239 | "pattern": "(?i)modsecurity iis" 3240 | } 3241 | ], 3242 | "any": true 3243 | }, 3244 | { 3245 | "fingerprints": [ 3246 | { 3247 | "type": "Reason", 3248 | "pattern": "(?i)ModSecurity Action" 3249 | }, 3250 | { 3251 | "type": "Status", 3252 | "pattern": "403" 3253 | } 3254 | ] 3255 | }, 3256 | { 3257 | "fingerprints": [ 3258 | { 3259 | "type": "Reason", 3260 | "pattern": "(?i)ModSecurity Action" 3261 | }, 3262 | { 3263 | "type": "Status", 3264 | "pattern": "406" 3265 | } 3266 | ] 3267 | } 3268 | ] 3269 | }, 3270 | { 3271 | "name": "RayWAF (WebRay Solutions)", 3272 | "schemas": [ 3273 | { 3274 | "fingerprints": [ 3275 | { 3276 | "type": "Header", 3277 | "header_key": "Server", 3278 | "header_value": "(?i)WebRay\\-WAF" 3279 | }, 3280 | { 3281 | "type": "Header", 3282 | "header_key": "DrivedBy", 3283 | "header_value": "(?i)RaySrv.RayEng/[0-9\\.]+?" 3284 | } 3285 | ], 3286 | "any": true 3287 | } 3288 | ] 3289 | }, 3290 | { 3291 | "name": "Barracuda (Barracuda Networks)", 3292 | "schemas": [ 3293 | { 3294 | "fingerprints": [ 3295 | { 3296 | "type": "Cookie", 3297 | "pattern": "(?i)^barra_counter_session=" 3298 | }, 3299 | { 3300 | "type": "Cookie", 3301 | "pattern": "(?i)^BNI__BARRACUDA_LB_COOKIE=" 3302 | }, 3303 | { 3304 | "type": "Cookie", 3305 | "pattern": "(?i)^BNI_persistence=" 3306 | }, 3307 | { 3308 | "type": "Cookie", 3309 | "pattern": "(?i)^BN[IE]S_.*?=" 3310 | }, 3311 | { 3312 | "type": "Content", 3313 | "pattern": "(?i)Barracuda.Networks" 3314 | } 3315 | ], 3316 | "any": true 3317 | } 3318 | ] 3319 | }, 3320 | { 3321 | "name": "aeSecure (aeSecure)", 3322 | "schemas": [ 3323 | { 3324 | "fingerprints": [ 3325 | { 3326 | "type": "Header", 3327 | "header_key": "aeSecure-code", 3328 | "header_value": "(?i).+?" 3329 | }, 3330 | { 3331 | "type": "Content", 3332 | "pattern": "(?i)aesecure_denied\\.png" 3333 | } 3334 | ], 3335 | "any": true 3336 | } 3337 | ] 3338 | }, 3339 | { 3340 | "name": "FirePass (F5 Networks)", 3341 | "schemas": [ 3342 | { 3343 | "fingerprints": [ 3344 | { 3345 | "type": "Cookie", 3346 | "pattern": "(?i)^VHOST" 3347 | }, 3348 | { 3349 | "type": "Header", 3350 | "header_key": "Location", 3351 | "header_value": "(?i)\\/my\\.logon\\.php3" 3352 | } 3353 | ] 3354 | }, 3355 | { 3356 | "fingerprints": [ 3357 | { 3358 | "type": "Cookie", 3359 | "pattern": "(?i)^F5_fire.+?" 3360 | }, 3361 | { 3362 | "type": "Cookie", 3363 | "pattern": "(?i)^F5_passid_shrinked" 3364 | } 3365 | ] 3366 | } 3367 | ] 3368 | }, 3369 | { 3370 | "name": "CacheWall (Varnish)", 3371 | "schemas": [ 3372 | { 3373 | "fingerprints": [ 3374 | { 3375 | "type": "Header", 3376 | "header_key": "Server", 3377 | "header_value": "(?i)Varnish" 3378 | }, 3379 | { 3380 | "type": "Header", 3381 | "header_key": "X-Varnish", 3382 | "header_value": "(?i).+" 3383 | }, 3384 | { 3385 | "type": "Header", 3386 | "header_key": "X-Cachewall-Action", 3387 | "header_value": "(?i).+?" 3388 | }, 3389 | { 3390 | "type": "Header", 3391 | "header_key": "X-Cachewall-Reason", 3392 | "header_value": "(?i).+?" 3393 | }, 3394 | { 3395 | "type": "Content", 3396 | "pattern": "(?i)security by cachewall" 3397 | }, 3398 | { 3399 | "type": "Content", 3400 | "pattern": "(?i)403 naughty.{0,10}?not nice!" 3401 | }, 3402 | { 3403 | "type": "Content", 3404 | "pattern": "(?i)varnish cache server" 3405 | } 3406 | ], 3407 | "any": true 3408 | } 3409 | ] 3410 | }, 3411 | { 3412 | "name": "ASPA Firewall (ASPA Engineering Co.)", 3413 | "schemas": [ 3414 | { 3415 | "fingerprints": [ 3416 | { 3417 | "type": "Header", 3418 | "header_key": "Server", 3419 | "header_value": "(?i)ASPA[\\-_]?WAF" 3420 | }, 3421 | { 3422 | "type": "Header", 3423 | "header_key": "ASPA-Cache-Status", 3424 | "header_value": "(?i).+?" 3425 | } 3426 | ], 3427 | "any": true 3428 | } 3429 | ] 3430 | }, 3431 | { 3432 | "name": "Nemesida (PentestIt)", 3433 | "schemas": [ 3434 | { 3435 | "fingerprints": [ 3436 | { 3437 | "type": "Content", 3438 | "pattern": "(?i)@?nemesida(\\-security)?\\.com" 3439 | }, 3440 | { 3441 | "type": "Content", 3442 | "pattern": "(?i)Suspicious activity detected.{0,10}?Access to the site is blocked" 3443 | }, 3444 | { 3445 | "type": "Content", 3446 | "pattern": "(?i)nwaf@" 3447 | }, 3448 | { 3449 | "type": "Status", 3450 | "pattern": "222" 3451 | } 3452 | ], 3453 | "any": true 3454 | } 3455 | ] 3456 | }, 3457 | { 3458 | "name": "Edgecast (Verizon Digital Media)", 3459 | "schemas": [ 3460 | { 3461 | "fingerprints": [ 3462 | { 3463 | "type": "Header", 3464 | "header_key": "Server", 3465 | "header_value": "(?i)^ECD(.+)?" 3466 | }, 3467 | { 3468 | "type": "Header", 3469 | "header_key": "Server", 3470 | "header_value": "(?i)^ECS(.*)?" 3471 | } 3472 | ], 3473 | "any": true 3474 | } 3475 | ] 3476 | }, 3477 | { 3478 | "name": "CacheFly CDN (CacheFly)", 3479 | "schemas": [ 3480 | { 3481 | "fingerprints": [ 3482 | { 3483 | "type": "Header", 3484 | "header_key": "BestCDN", 3485 | "header_value": "(?i)Cachefly" 3486 | }, 3487 | { 3488 | "type": "Cookie", 3489 | "pattern": "(?i)^cfly_req.*=" 3490 | } 3491 | ], 3492 | "any": true 3493 | } 3494 | ] 3495 | }, 3496 | { 3497 | "name": "WebKnight (AQTRONIX)", 3498 | "schemas": [ 3499 | { 3500 | "fingerprints": [ 3501 | { 3502 | "type": "Status", 3503 | "pattern": "999" 3504 | }, 3505 | { 3506 | "type": "Reason", 3507 | "pattern": "(?i)No Hacking" 3508 | }, 3509 | { 3510 | "type": "Status", 3511 | "pattern": "404" 3512 | }, 3513 | { 3514 | "type": "Reason", 3515 | "pattern": "(?i)Hack Not Found" 3516 | } 3517 | ] 3518 | }, 3519 | { 3520 | "fingerprints": [ 3521 | { 3522 | "type": "Content", 3523 | "pattern": "(?i)WebKnight Application Firewall Alert" 3524 | }, 3525 | { 3526 | "type": "Content", 3527 | "pattern": "(?i)What is webknight\\?" 3528 | }, 3529 | { 3530 | "type": "Content", 3531 | "pattern": "(?i)AQTRONIX WebKnight is an application firewall" 3532 | }, 3533 | { 3534 | "type": "Content", 3535 | "pattern": "(?i)WebKnight will take over and protect" 3536 | }, 3537 | { 3538 | "type": "Content", 3539 | "pattern": "(?i)aqtronix\\.com/WebKnight" 3540 | }, 3541 | { 3542 | "type": "Content", 3543 | "pattern": "(?i)AQTRONIX.{0,10}?WebKnight" 3544 | } 3545 | ], 3546 | "any": true 3547 | } 3548 | ] 3549 | }, 3550 | { 3551 | "name": "ArvanCloud (ArvanCloud)", 3552 | "schemas": [ 3553 | { 3554 | "fingerprints": [ 3555 | { 3556 | "type": "Header", 3557 | "header_key": "Server", 3558 | "header_value": "(?i)ArvanCloud" 3559 | } 3560 | ], 3561 | "any": true 3562 | } 3563 | ] 3564 | }, 3565 | { 3566 | "name": "MaxCDN (MaxCDN)", 3567 | "schemas": [ 3568 | { 3569 | "fingerprints": [ 3570 | { 3571 | "type": "Header", 3572 | "header_key": "X-CDN", 3573 | "header_value": "(?i)maxcdn" 3574 | } 3575 | ], 3576 | "any": true 3577 | } 3578 | ] 3579 | }, 3580 | { 3581 | "name": "SiteGround (SiteGround)", 3582 | "schemas": [ 3583 | { 3584 | "fingerprints": [ 3585 | { 3586 | "type": "Content", 3587 | "pattern": "(?i)Our system thinks you might be a robot!" 3588 | }, 3589 | { 3590 | "type": "Content", 3591 | "pattern": "(?i)access is restricted due to a security rule" 3592 | } 3593 | ], 3594 | "any": true 3595 | } 3596 | ] 3597 | }, 3598 | { 3599 | "name": "NSFocus (NSFocus Global Inc.)", 3600 | "schemas": [ 3601 | { 3602 | "fingerprints": [ 3603 | { 3604 | "type": "Header", 3605 | "header_key": "Server", 3606 | "header_value": "(?i)NSFocus" 3607 | } 3608 | ], 3609 | "any": true 3610 | } 3611 | ] 3612 | }, 3613 | { 3614 | "name": "IndusGuard (Indusface)", 3615 | "schemas": [ 3616 | { 3617 | "fingerprints": [ 3618 | { 3619 | "type": "Header", 3620 | "header_key": "Server", 3621 | "header_value": "(?i)IF_WAF" 3622 | }, 3623 | { 3624 | "type": "Content", 3625 | "pattern": "(?i)This website is secured against online attacks. Your request was blocked" 3626 | } 3627 | ], 3628 | "any": true 3629 | } 3630 | ] 3631 | } 3632 | ] -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/Lu1sDV/wafme0w 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/jessevdk/go-flags v1.5.0 7 | github.com/logrusorgru/aurora/v4 v4.0.0 8 | ) 9 | 10 | require golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4 // indirect 11 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= 3 | github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= 4 | github.com/logrusorgru/aurora/v4 v4.0.0 h1:sRjfPpun/63iADiSvGGjgA1cAYegEWMPCJdUpJYn9JA= 5 | github.com/logrusorgru/aurora/v4 v4.0.0/go.mod h1:lP0iIa2nrnT/qoFXcOZSrZQpJ1o6n2CUf/hyHi2Q4ZQ= 6 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 7 | github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= 8 | golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4 h1:EZ2mChiOa8udjfp6rRmswTbtZN/QzUQp4ptM4rnjHvc= 9 | golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 10 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 11 | -------------------------------------------------------------------------------- /pkg/utils/http/httputil.go: -------------------------------------------------------------------------------- 1 | package httputil 2 | 3 | import ( 4 | strutils "github.com/Lu1sDV/wafme0w/pkg/utils/strings" 5 | "net/http" 6 | "net/url" 7 | "strings" 8 | ) 9 | 10 | func ParseURI(uri string) (*url.URL, error) { 11 | 12 | lowerUri := strings.ToLower(uri) 13 | hasScheme := strings.HasPrefix(lowerUri, "http://") || strings.HasPrefix(lowerUri, "https://") 14 | if !hasScheme { 15 | lowerUri = "https://" + lowerUri 16 | } 17 | 18 | parsed, err := url.ParseRequestURI(lowerUri) 19 | if err != nil { 20 | return &url.URL{}, err 21 | } 22 | return parsed, nil 23 | } 24 | 25 | func IsValidHTTPURL(uri string) bool { 26 | var allowedSchemes = []string{"http", "https"} 27 | 28 | if uri == "" { 29 | return false 30 | } 31 | 32 | splitScheme := strings.Split(uri, "://") 33 | if len(splitScheme) > 1 { 34 | scheme := splitScheme[0] 35 | if !strutils.StringInSlice(scheme, allowedSchemes) { 36 | return false 37 | } 38 | } else { 39 | uri = "https://" + uri 40 | } 41 | 42 | _, err := url.ParseRequestURI(uri) 43 | return err == nil 44 | } 45 | 46 | // GetHTTPHeaderByName returns the value of provided header. 47 | // It accepts headers list (http.Header) and header's name 48 | // It returns the value if header is found. Otherwise, returns an empty string 49 | func GetHTTPHeaderByName(headers http.Header, headerName string) string { 50 | if headerName == "" { 51 | return "" 52 | } 53 | for header, headerValue := range headers { 54 | if strings.EqualFold(header, headerName) { 55 | return headerValue[0] 56 | } 57 | } 58 | return "" 59 | } 60 | -------------------------------------------------------------------------------- /pkg/utils/http/httputil_test.go: -------------------------------------------------------------------------------- 1 | package httputil 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestIsValidURI(t *testing.T) { 8 | 9 | tests := []struct { 10 | name string 11 | args string 12 | want bool 13 | }{ 14 | {"Valid www.google.it", "google.it", true}, 15 | {"Valid localhost", "localhost", true}, 16 | {"Invalid scheme", "wisjj://localhost", false}, 17 | {"Invalid scheme", "ftp://localhost", false}, 18 | {"Invalid empty", "", false}, 19 | //{"InValid url", "!", false}, TODO 20 | // {"InValid url", "http:::/not.valid/a//a", false}, TODO 21 | } 22 | for _, tt := range tests { 23 | t.Run(tt.name, func(t *testing.T) { 24 | if got := IsValidHTTPURL(tt.args); got != tt.want { 25 | t.Errorf("IsValidURI() = %v, want %v", got, tt.want) 26 | } 27 | }) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /pkg/utils/strings/strings.go: -------------------------------------------------------------------------------- 1 | package strutil 2 | 3 | import ( 4 | "strings" 5 | "unicode" 6 | ) 7 | 8 | func SubStringBetweenDelimiters(s string, firstDelimiter string, secondDelimiter string) string { 9 | i := strings.Index(s, firstDelimiter) 10 | if i >= 0 { 11 | j := strings.Index(s, secondDelimiter) 12 | if j >= 0 { 13 | return s[i+1 : j] 14 | } 15 | } 16 | return "" 17 | } 18 | 19 | func StringInSlice(str string, list []string) bool { 20 | for _, b := range list { 21 | if b == str { 22 | return true 23 | } 24 | } 25 | return false 26 | } 27 | 28 | // SplitAtUpperCases splits a string every time it finds an uppercase 29 | func SplitAtUpperCases(str string) []string { 30 | var words []string 31 | l := 0 32 | for s := str; s != ""; s = s[l:] { 33 | l = strings.IndexFunc(s[1:], unicode.IsUpper) + 1 34 | if l <= 0 { 35 | l = len(s) 36 | } 37 | words = append(words, s[:l]) 38 | } 39 | return words 40 | } 41 | -------------------------------------------------------------------------------- /pkg/utils/strings/strings_test.go: -------------------------------------------------------------------------------- 1 | package strutil 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | func TestStringInSlice(t *testing.T) { 9 | type args struct { 10 | str string 11 | list []string 12 | } 13 | tests := []struct { 14 | name string 15 | args args 16 | want bool 17 | }{ 18 | {name: "Match", args: args{str: "foo", list: []string{"foo", "bar"}}, want: true}, 19 | {name: "No match", args: args{str: "foo", list: []string{"ez", "bar"}}, want: false}, 20 | } 21 | for _, tt := range tests { 22 | t.Run(tt.name, func(t *testing.T) { 23 | if got := StringInSlice(tt.args.str, tt.args.list); got != tt.want { 24 | t.Errorf("StringInSlice() = %v, want %v", got, tt.want) 25 | } 26 | }) 27 | } 28 | } 29 | 30 | func TestSubStringBetweenDelimiters(t *testing.T) { 31 | type args struct { 32 | s string 33 | firstDelimiter string 34 | secondDelimiter string 35 | } 36 | tests := []struct { 37 | name string 38 | args args 39 | want string 40 | }{ 41 | {name: "Get \"Bar\" substring", args: args{s: "Foo(Bar)", firstDelimiter: "(", secondDelimiter: ")"}, want: "Bar"}, 42 | {name: "No substring found", args: args{s: "Foo[Bar]", firstDelimiter: "(", secondDelimiter: ")"}, want: ""}, 43 | } 44 | for _, tt := range tests { 45 | t.Run(tt.name, func(t *testing.T) { 46 | if got := SubStringBetweenDelimiters(tt.args.s, tt.args.firstDelimiter, tt.args.secondDelimiter); got != tt.want { 47 | t.Errorf("SubStringBetweenDelimiters() = %v, want %v", got, tt.want) 48 | } 49 | }) 50 | } 51 | } 52 | 53 | func TestSplitAtUpperCases(t *testing.T) { 54 | type args struct { 55 | str string 56 | } 57 | tests := []struct { 58 | name string 59 | args args 60 | want []string 61 | }{ 62 | {name: "Split MyString", args: args{str: "MyString"}, want: []string{"My", "String"}}, 63 | {name: "Nothing to split", args: args{str: "alllowercase"}, want: []string{"alllowercase"}}, 64 | } 65 | for _, tt := range tests { 66 | t.Run(tt.name, func(t *testing.T) { 67 | if got := SplitAtUpperCases(tt.args.str); !reflect.DeepEqual(got, tt.want) { 68 | t.Errorf("SplitAtUpperCases() = %v, want %v", got, tt.want) 69 | } 70 | }) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /pkg/wafme0w/banner.go: -------------------------------------------------------------------------------- 1 | package wafme0w 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | const version = "v0.2.0" 8 | 9 | const cat = ` 10 | /\_/\ ___ 11 | = o_o =_______ \ \ 12 | __^ __( \.__) ) 13 | <_____>__(_____)____/` + "\n" 14 | 15 | const whatIs = ` 16 | Wafme0w ` + version + "\n" 17 | const explain = ` 18 | Fast Web Application Firewall Fingerprinting tool` 19 | 20 | func PrintBanner() { 21 | 22 | banner := cat + whatIs + explain + "\n\n" 23 | fmt.Print(banner) 24 | } 25 | -------------------------------------------------------------------------------- /pkg/wafme0w/generic_detection.go: -------------------------------------------------------------------------------- 1 | package wafme0w 2 | 3 | import ( 4 | "fmt" 5 | strutil "github.com/Lu1sDV/wafme0w/pkg/utils/strings" 6 | "strings" 7 | ) 8 | 9 | var genericWAFHeaders = []string{"X-WAF-Protection", 10 | "X-Web-Application-Firewall"} 11 | 12 | type GenericDetection struct { 13 | Reason string 14 | Mode GenericDetectionMode 15 | BeforeStatus int 16 | AfterStatus int 17 | BeforeHeader string 18 | AfterHeader string 19 | RequestType string 20 | GenericWAFHeader string 21 | GenericWAFHeaderValue string 22 | } 23 | 24 | type GenericDetectionMode int 25 | 26 | const ( 27 | ChangeInHeader GenericDetectionMode = iota 28 | ChangeInStatus 29 | WAFHeaderDetected 30 | ) 31 | 32 | func (g GenericDetectionMode) String() string { 33 | return [...]string{"header changed", 34 | "status changed", 35 | "generic WAF header detected"}[g] 36 | } 37 | 38 | func (g *GenericDetection) generateReason() { 39 | 40 | var tmplTxt string 41 | 42 | //prettify RequestType for output 43 | //eg. From XssAttack to Xss Attack 44 | splitRequestType := strutil.SplitAtUpperCases(g.RequestType) 45 | prettyRequestType := strings.Join(splitRequestType, " ") 46 | 47 | switch g.Mode { 48 | case ChangeInHeader: 49 | tmplTxt = fmt.Sprintf(`The server header is different when the following request was tried: %s 50 | Normal Server header is: "%s" while response's header is: "%s"`, prettyRequestType, g.BeforeHeader, g.AfterHeader) 51 | 52 | case ChangeInStatus: 53 | tmplTxt = fmt.Sprintf(`Server returned a different response when the following request was tried: %s 54 | Normal response code is "%d" while response's status code is "%d"`, prettyRequestType, g.BeforeStatus, g.AfterStatus) 55 | 56 | case WAFHeaderDetected: 57 | tmplTxt = fmt.Sprintf(`The Web Application has a Generic WAF header when the following request was tried: %s 58 | The header is: "%s" and its value is: "%s"`, prettyRequestType, g.GenericWAFHeader, g.GenericWAFHeaderValue) 59 | 60 | } 61 | g.Reason = tmplTxt 62 | } 63 | -------------------------------------------------------------------------------- /pkg/wafme0w/http.go: -------------------------------------------------------------------------------- 1 | package wafme0w 2 | 3 | import ( 4 | "compress/flate" 5 | "compress/gzip" 6 | "fmt" 7 | "io" 8 | "net/http" 9 | "net/url" 10 | "time" 11 | ) 12 | 13 | var defaultHeaders = map[string]string{ 14 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", 15 | "Accept-Encoding": "gzip, deflate", 16 | "Accept-Language": "en-US,en;q=0.9", 17 | "DNT": "1", // Do Not Track request header 18 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36", 19 | "Upgrade-Insecure-Requests": "1", 20 | "Referer": "https://www.google.com/", 21 | } 22 | 23 | const timeOut = 5 * time.Second 24 | 25 | type RequestResponse struct { 26 | Target string 27 | Type string 28 | Data *http.Response 29 | Body []byte 30 | Error error 31 | } 32 | 33 | type HTTPRequest struct { 34 | Options RequestOpts 35 | Client http.Client 36 | } 37 | 38 | func NewHTTPRequest(options RequestOpts, client http.Client) HTTPRequest { 39 | return HTTPRequest{Options: options, Client: client} 40 | } 41 | 42 | func NewHTTPClient() http.Client { 43 | return http.Client{ 44 | Timeout: timeOut, 45 | } 46 | } 47 | 48 | func (h HTTPRequest) Send() (response RequestResponse, err error) { 49 | var reader io.ReadCloser 50 | endPoint := h.Options.Target + h.Options.Path 51 | 52 | if len(h.Options.Params) != 0 { 53 | baseUrl, err := url.Parse(endPoint) 54 | if err != nil { 55 | return RequestResponse{}, fmt.Errorf("error parsing endpoint. %w", err) 56 | } 57 | 58 | params := url.Values{} 59 | 60 | for param, value := range h.Options.Params { 61 | params.Add(param, value) 62 | } 63 | baseUrl.RawQuery = params.Encode() 64 | endPoint = baseUrl.String() 65 | } 66 | 67 | req, err := http.NewRequest(h.Options.Method, endPoint, h.Options.PostBody) 68 | if err != nil { 69 | return RequestResponse{}, fmt.Errorf("error creating request: %w", err) 70 | } 71 | 72 | //set headers 73 | for header, value := range h.Options.Headers { 74 | req.Header.Set(header, value) 75 | } 76 | 77 | resp, err := h.Client.Do(req) 78 | if err != nil { 79 | return RequestResponse{}, fmt.Errorf("error sending request to endpoint. %w", err) 80 | } 81 | switch resp.Header.Get("Content-Encoding") { 82 | case "gzip": 83 | reader, err = gzip.NewReader(resp.Body) 84 | if err != nil { 85 | return RequestResponse{}, fmt.Errorf("error reading body: %w", err) 86 | } 87 | case "deflate": 88 | reader = flate.NewReader(resp.Body) 89 | default: 90 | reader = resp.Body 91 | } 92 | 93 | body, err := io.ReadAll(reader) 94 | 95 | if err != nil { 96 | return RequestResponse{}, fmt.Errorf("error reading body: %w", err) 97 | } 98 | defer reader.Close() 99 | 100 | return RequestResponse{Target: h.Options.Target, Data: resp, Body: body}, nil 101 | } 102 | -------------------------------------------------------------------------------- /pkg/wafme0w/identify.go: -------------------------------------------------------------------------------- 1 | package wafme0w 2 | 3 | import ( 4 | httputil "github.com/Lu1sDV/wafme0w/pkg/utils/http" 5 | "regexp" 6 | "strconv" 7 | ) 8 | 9 | type WAF struct { 10 | Name string `json:"name"` //WAF NAME 11 | Schemas []Scheme `json:"schemas"` 12 | } 13 | 14 | type Scheme struct { 15 | FingerPrints []FingerPrint `json:"fingerprints,omitempty"` 16 | Any bool `json:"any,omitempty"` //If any fingerprint should be present or if all of them 17 | } 18 | 19 | type FingerPrint struct { 20 | Type string `json:"type,omitempty"` // Header or Content or Cookie or Status or Reason 21 | HeaderKey string `json:"header_key,omitempty"` // Only for header type 22 | HeaderValue string `json:"header_value,omitempty"` // Only for header type 23 | Pattern string `json:"pattern,omitempty"` // Fingerprint for other types 24 | Attack bool `json:"attack,omitempty"` 25 | } 26 | 27 | type FingerPrintDetection struct { 28 | WafName string 29 | } 30 | 31 | type Identify struct { 32 | Responses []RequestResponse 33 | Wafs []WAF 34 | } 35 | 36 | func NewIdentifier(responses []RequestResponse, wafs []WAF) *Identify { 37 | return &Identify{Responses: responses, Wafs: wafs} 38 | } 39 | 40 | // DoAll does WAF fingerprint on all received http responses 41 | func (i *Identify) DoAll() []FingerPrintDetection { 42 | var fingerPrintPattern string 43 | var responseHeader string 44 | var responses = i.Responses 45 | emptyRequest := &RequestResponse{} 46 | var results []FingerPrintDetection 47 | 48 | WAFSLOOP: 49 | for _, waf := range i.Wafs { 50 | for _, schema := range waf.Schemas { 51 | matchingFingerPrints := 0 52 | fingerPrintsCount := len(schema.FingerPrints) 53 | FINGERLOOP: 54 | for _, fingerPrint := range schema.FingerPrints { 55 | for _, r := range responses { 56 | requestName := r.Type 57 | response := getResponseByType(&responses, requestName) 58 | 59 | if response == emptyRequest { 60 | continue 61 | } 62 | 63 | if response.Data == nil { 64 | continue 65 | } 66 | switch fingerPrint.Type { 67 | case "Cookie": 68 | fingerPrintPattern = fingerPrint.Pattern 69 | for _, cookie := range response.Data.Cookies() { 70 | if matched, _ := regexp.MatchString(fingerPrintPattern, cookie.String()); matched { 71 | //add to waf 72 | matchingFingerPrints++ 73 | continue FINGERLOOP 74 | } 75 | } 76 | 77 | case "Header": 78 | fingerPrintPattern = fingerPrint.HeaderValue 79 | responseHeader = response.Data.Header.Get(fingerPrint.HeaderKey) 80 | if matched, _ := regexp.MatchString(fingerPrintPattern, responseHeader); matched { 81 | //add to waf 82 | matchingFingerPrints++ 83 | continue FINGERLOOP 84 | } 85 | case "Content": 86 | if matched, _ := regexp.MatchString(fingerPrint.Pattern, string(response.Body)); matched { 87 | //add to waf 88 | matchingFingerPrints++ 89 | continue FINGERLOOP 90 | } 91 | case "Status": 92 | responseStatusCode := response.Data.StatusCode 93 | fingerPrintStatusCode, err := strconv.Atoi(fingerPrint.Pattern) 94 | if err != nil { 95 | continue 96 | } 97 | if responseStatusCode == fingerPrintStatusCode { 98 | matchingFingerPrints++ 99 | continue FINGERLOOP 100 | } 101 | case "Reason": 102 | //TODO 103 | } 104 | } 105 | } 106 | 107 | if matchingFingerPrints != 0 { 108 | if !schema.Any { 109 | //All fingerprints in schema must match 110 | if matchingFingerPrints != fingerPrintsCount { 111 | continue 112 | } 113 | } 114 | results = append(results, FingerPrintDetection{WafName: waf.Name}) 115 | continue WAFSLOOP 116 | } 117 | } 118 | } 119 | return results 120 | } 121 | 122 | // GenericDetect detects generic firewall activities 123 | func (i *Identify) GenericDetect() GenericDetection { 124 | responses := i.Responses 125 | var detection GenericDetection 126 | emptyDetection := GenericDetection{} 127 | 128 | normalResponse := getResponseByType(&responses, "Normal") 129 | if normalResponse.Data == nil { 130 | return emptyDetection 131 | } 132 | normalStatusCode := normalResponse.Data.StatusCode 133 | normalServerHeader := normalResponse.Data.Header.Get("Server") 134 | 135 | OUTERLOOP: 136 | for _, resp := range responses { 137 | if resp.Type == "Normal" || resp.Data == nil { 138 | continue 139 | } 140 | responseServerHeader := resp.Data.Header.Get("Server") 141 | responseStatusCode := resp.Data.StatusCode 142 | //check if any generic WAF header is thrown 143 | for _, wafHeader := range genericWAFHeaders { 144 | headerValue := httputil.GetHTTPHeaderByName(resp.Data.Header, wafHeader) 145 | if headerValue == "" { 146 | //header not found 147 | continue 148 | } 149 | detection = GenericDetection{Mode: WAFHeaderDetected, 150 | GenericWAFHeader: wafHeader, 151 | GenericWAFHeaderValue: headerValue, 152 | RequestType: resp.Type, 153 | } 154 | break OUTERLOOP 155 | } 156 | //check if any different status code is thrown 157 | if normalStatusCode != responseStatusCode { 158 | //skip not found 159 | if responseStatusCode == 404 { 160 | continue 161 | } 162 | detection = GenericDetection{Mode: ChangeInStatus, 163 | BeforeStatus: normalStatusCode, 164 | AfterStatus: responseStatusCode, 165 | RequestType: resp.Type, 166 | } 167 | break OUTERLOOP 168 | } 169 | //check any change in Server Header 170 | if normalServerHeader != responseServerHeader { 171 | //skip not found 172 | detection = GenericDetection{Mode: ChangeInHeader, 173 | BeforeHeader: normalServerHeader, 174 | AfterHeader: responseServerHeader, 175 | RequestType: resp.Type, 176 | } 177 | break OUTERLOOP 178 | } 179 | } 180 | 181 | if detection != emptyDetection { 182 | detection.generateReason() 183 | return detection 184 | } 185 | return emptyDetection 186 | } 187 | -------------------------------------------------------------------------------- /pkg/wafme0w/options.go: -------------------------------------------------------------------------------- 1 | package wafme0w 2 | 3 | import "io" 4 | 5 | type Options struct { 6 | Inputs io.Reader 7 | FingerPrints io.Reader 8 | Headers []string 9 | StdIn bool 10 | Target string `short:"t" long:"target" description:"Your Web Application target"` 11 | InputFile string `short:"I" long:"input" description:"Your input file with a list of targets"` 12 | OutputFile string `short:"O" long:"output" description:"Output file, will be JSON CSV or TXT depending on extension"` 13 | HeadersFile string `short:"H" long:"headers" description:"File containing custom headers, will replace default ones"` 14 | FingerPrintFile string `long:"fingerprints" description:"File containing the JSON-formatted fingerprints"` 15 | Concurrency int `short:"c" long:"concurrency" description:"Number of concurrent workers" default:"20"` 16 | FastMode bool `long:"fast" description:"Enable Fast Mode, blazing fast but less precise. Sends less requests more concurrently"` 17 | ExcludeGeneric bool `long:"no-generic" description:"Exclude generic WAF check"` 18 | ListWAFS bool `long:"list" description:"List all detectable WAFs"` 19 | Silent bool `long:"silent" description:"Enable silent mode to disable console output"` 20 | NoColors bool `long:"no-colors" description:"Disable colored output"` 21 | SuppressWarnings bool `long:"no-warning" description:"Suppress console scan warnings"` 22 | //Verbose bool `short:"v" long:"verbose" description:"Show verbose debug information"` TODO 23 | //Payload string `long:"payload" description:"Payload to send along with default attack vectors"` TODO 24 | 25 | } 26 | 27 | func NewOptions() *Options { 28 | return &Options{} 29 | } 30 | -------------------------------------------------------------------------------- /pkg/wafme0w/output.go: -------------------------------------------------------------------------------- 1 | package wafme0w 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/logrusorgru/aurora/v4" 7 | "strings" 8 | ) 9 | 10 | func printResult(result Result, au *aurora.Aurora) { 11 | var wafs []string 12 | var foundBrackets = "[" + au.Bold(au.BrightGreen("+")).String() + "]" 13 | var informativeBrackets = "[" + au.Bold(au.BrightBlue("*")).String() + "]" 14 | var notFoundBrackets = "[" + au.Bold(au.Yellow("~")).String() + "]" 15 | var colouredTarget = au.BrightCyan(result.Target).Hyperlink(result.Target).String() 16 | //var line string 17 | 18 | for _, finger := range result.FingerPrint { 19 | if finger.WafName != "" { 20 | colouredWafName := au.Bold(au.BrightMagenta(finger.WafName)).String() 21 | wafs = append(wafs, colouredWafName) 22 | } 23 | } 24 | 25 | if len(wafs) > 0 { 26 | fingerResult := colouredTarget + " is behind " + strings.Join(wafs, " AND ") 27 | line := foundBrackets + " " + fingerResult 28 | fmt.Println(line) 29 | } 30 | 31 | if result.Generic.Reason != "" { 32 | formattedReason := strings.Replace(result.Generic.Reason, "\n", "\n ", -1) 33 | genericResult := foundBrackets + " " + colouredTarget + " seems to be behind a WAF or some sort of security solution" 34 | genericReason := informativeBrackets + " Reason: " + formattedReason 35 | line := genericResult + "\n" + genericReason 36 | fmt.Println(line) 37 | } 38 | 39 | if len(wafs) == 0 && result.Generic.Reason == "" { 40 | line := notFoundBrackets + " " + colouredTarget + " no WAFs have been found" 41 | fmt.Println(line) 42 | } 43 | } 44 | 45 | func prepareJSONOutput(results []Result) ([]byte, error) { 46 | var validResults []Result 47 | var jsonOutput []byte 48 | 49 | for _, res := range results { 50 | if res.Generic.Reason != "" || len(res.FingerPrint) != 0 { 51 | validResults = append(validResults, res) 52 | } 53 | } 54 | 55 | if len(validResults) == 0 { 56 | return jsonOutput, nil 57 | } 58 | 59 | jsonOutput, err := json.MarshalIndent(validResults, "", "\t") 60 | if err != nil { 61 | return nil, err 62 | } 63 | 64 | return jsonOutput, nil 65 | } 66 | 67 | func prepareTXTOutput(results []Result) []byte { 68 | var output string 69 | var emptyGeneric = GenericDetection{} 70 | 71 | for _, res := range results { 72 | var line = res.Target 73 | 74 | fingerPrintsFound := len(res.FingerPrint) 75 | var fingerPrints []string 76 | 77 | if fingerPrintsFound == 0 && res.Generic == emptyGeneric { 78 | continue 79 | } 80 | if fingerPrintsFound > 0 { 81 | for _, f := range res.FingerPrint { 82 | fingerPrints = append(fingerPrints, f.WafName) 83 | } 84 | line = line + ":" + strings.Join(fingerPrints, ", ") 85 | } 86 | 87 | if res.Generic != emptyGeneric { 88 | genericNoNewline := strings.Replace(res.Generic.Reason, "\n", " ", -1) 89 | line = line + ":" + genericNoNewline 90 | } 91 | 92 | line = line + "\n" 93 | output = output + line 94 | } 95 | 96 | return []byte(output) 97 | } 98 | 99 | func PrintError(error string, au *aurora.Aurora) { 100 | var errorBrackets = "[" + au.Bold(au.BrightRed("!!")).String() + "]" 101 | line := errorBrackets + " " + error 102 | fmt.Println(line) 103 | } 104 | 105 | func PrintWarning(warning string, au *aurora.Aurora) { 106 | var warningBrackets = "[" + au.Bold(au.BrightYellow("!")).String() + "]" 107 | line := warningBrackets + " " + warning 108 | fmt.Println(line) 109 | } 110 | 111 | func PrintAllWafs(wafs map[string]string, au *aurora.Aurora) { 112 | for waf, manufacturer := range wafs { 113 | colouredWaf := au.Bold(au.BrightMagenta(waf)).String() 114 | colouredManufacturer := au.BrightCyan(manufacturer).String() 115 | 116 | line := "\t" + colouredWaf + " BY " + colouredManufacturer 117 | fmt.Println(line) 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /pkg/wafme0w/request.go: -------------------------------------------------------------------------------- 1 | package wafme0w 2 | 3 | import ( 4 | "errors" 5 | "io" 6 | "math/rand" 7 | "net/http" 8 | "reflect" 9 | "strconv" 10 | "sync" 11 | "time" 12 | ) 13 | 14 | const ( 15 | xssString = "" 16 | sqliString = "UNION SELECT ALL FROM information_schema AND ' or SLEEP(5) or '" 17 | lfiString = "../../../../etc/passwd" 18 | rceString = "/bin/cat /etc/passwd; ping 127.0.0.1; curl google.com" 19 | xxeString = "]>&hack;" 20 | ) 21 | 22 | const requestsDelay = 50 * time.Millisecond 23 | 24 | var basicRequestsTypes = []string{"Normal", "NoUserAgent", "CentralAttack"} 25 | 26 | type RequestOpts struct { 27 | Method string 28 | Target string 29 | Path string 30 | Headers map[string]string 31 | Params map[string]string 32 | Type string 33 | PostBody io.Reader 34 | } 35 | 36 | type RequestTypes struct { 37 | Normal RequestOpts 38 | NoUserAgent RequestOpts 39 | NonExistent RequestOpts 40 | XssAttack RequestOpts 41 | XxeAttack RequestOpts 42 | LfiAttack RequestOpts 43 | CentralAttack RequestOpts 44 | SqliAttack RequestOpts 45 | RceAttack RequestOpts 46 | } 47 | 48 | func newTypeOptions(target string) RequestTypes { 49 | 50 | //create random path 51 | rand.Seed(time.Now().UnixNano()) 52 | minInt := 100000 53 | maxInt := 1000000 54 | randomInt := rand.Intn(maxInt-minInt+1) + minInt 55 | randomPath := "/" + strconv.Itoa(randomInt) + ".html" 56 | 57 | headersNoUA := make(map[string]string, 5) 58 | for key, value := range defaultHeaders { 59 | if key == "User-Agent" { 60 | continue 61 | } 62 | headersNoUA[key] = value 63 | } 64 | 65 | var normal = RequestOpts{ 66 | Method: "GET", 67 | Target: target, 68 | Path: "/", 69 | Headers: defaultHeaders, 70 | } 71 | 72 | var noUserAgent = RequestOpts{ 73 | Method: "GET", 74 | Target: target, 75 | Path: "/", 76 | Headers: headersNoUA, 77 | } 78 | 79 | var nonExistent = RequestOpts{ 80 | Method: "GET", 81 | Target: target, 82 | Path: randomPath, 83 | Headers: defaultHeaders, 84 | } 85 | var xssAttack = RequestOpts{ 86 | Method: "GET", 87 | Target: target, 88 | Path: "/", 89 | Params: map[string]string{"p": xssString}, 90 | Headers: defaultHeaders, 91 | } 92 | var xxeAttack = RequestOpts{ 93 | Method: "GET", 94 | Target: target, 95 | Path: "/", 96 | Params: map[string]string{"p": xxeString}, 97 | Headers: defaultHeaders, 98 | } 99 | var sqliAttack = RequestOpts{ 100 | Method: "GET", 101 | Target: target, 102 | Path: "/", 103 | Params: map[string]string{"p": sqliString}, 104 | Headers: defaultHeaders, 105 | } 106 | var centralAttack = RequestOpts{ 107 | Method: "GET", 108 | Target: target, 109 | Path: "/", 110 | Params: map[string]string{ 111 | "l": lfiString, 112 | "d": xssString, 113 | "v": sqliString, 114 | }, 115 | Headers: defaultHeaders, 116 | } 117 | var lfiAttack = RequestOpts{ 118 | Method: "GET", 119 | Target: target, 120 | Path: "/", 121 | Headers: defaultHeaders, 122 | Params: map[string]string{"p": lfiString}, 123 | } 124 | var rceAttack = RequestOpts{ 125 | Method: "GET", 126 | Target: target, 127 | Path: "/", 128 | Params: map[string]string{"p": rceString}, 129 | Headers: defaultHeaders, 130 | } 131 | 132 | return RequestTypes{ 133 | Normal: normal, 134 | NoUserAgent: noUserAgent, 135 | NonExistent: nonExistent, 136 | XssAttack: xssAttack, 137 | XxeAttack: xxeAttack, 138 | LfiAttack: lfiAttack, 139 | CentralAttack: centralAttack, 140 | SqliAttack: sqliAttack, 141 | RceAttack: rceAttack, 142 | } 143 | } 144 | 145 | func (t RequestTypes) GetByType(requestType string) (*RequestOpts, error) { 146 | reqOpts := &RequestOpts{} 147 | 148 | s := reflect.ValueOf(&t).Elem() 149 | typeField := s.FieldByName(requestType).Addr() 150 | 151 | rv := reflect.ValueOf(&reqOpts).Elem() 152 | rv.Set(typeField) 153 | 154 | reqOpts.Type = requestType 155 | 156 | return reqOpts, nil 157 | } 158 | 159 | func getResponseByType(responses *[]RequestResponse, requestType string) *RequestResponse { 160 | for _, request := range *responses { 161 | if request.Type == requestType { 162 | return &request 163 | } 164 | } 165 | return &RequestResponse{} 166 | } 167 | 168 | func sendBasicRequests(target string) []RequestResponse { 169 | var wg sync.WaitGroup 170 | 171 | client := NewHTTPClient() 172 | 173 | basicRequestsLen := len(basicRequestsTypes) 174 | responses := make([]RequestResponse, basicRequestsLen) 175 | wg.Add(basicRequestsLen) 176 | 177 | for i, requestType := range basicRequestsTypes { 178 | if i != 0 { 179 | time.Sleep(requestsDelay) 180 | } 181 | go func(i int, requestType string) { 182 | defer wg.Done() 183 | resp := sendRequest(target, requestType, client) 184 | if requestType == "Normal" && resp.Data == nil { 185 | errText := target + " does not seem to be alive" 186 | err := errors.New(errText) 187 | resp.Error = err 188 | } 189 | responses[i] = resp 190 | }(i, requestType) 191 | } 192 | 193 | wg.Wait() 194 | return responses 195 | } 196 | 197 | func sendAllTypesRequests(target string) []RequestResponse { 198 | var responses []RequestResponse 199 | 200 | client := NewHTTPClient() 201 | typeOpts := newTypeOptions(target) 202 | 203 | val := reflect.ValueOf(&typeOpts).Elem() 204 | 205 | for i := 0; i < val.NumField(); i++ { 206 | typeName := val.Type().Field(i).Name 207 | resp := sendRequest(target, typeName, client) 208 | if typeName == "Normal" && resp.Data == nil { 209 | errText := target + " does not seem to be alive" 210 | err := errors.New(errText) 211 | resp.Error = err 212 | responses = []RequestResponse{resp} 213 | break 214 | } 215 | responses = append(responses, resp) 216 | } 217 | 218 | return responses 219 | } 220 | 221 | func sendRequest(target string, requestType string, client http.Client) RequestResponse { 222 | typeOpts := newTypeOptions(target) 223 | requestOpts, err := typeOpts.GetByType(requestType) 224 | if err != nil { 225 | return RequestResponse{Error: err} 226 | } 227 | httpRequest := NewHTTPRequest(*requestOpts, client) 228 | 229 | resp, err := httpRequest.Send() 230 | if err != nil { 231 | return RequestResponse{Error: err} 232 | } 233 | resp.Type = requestType 234 | return resp 235 | } 236 | 237 | // ConcurrentSendAllTypesRequests TODO may be implemented, very fast, very intrusive 238 | func concurrentSendAllTypesRequests(target string) []RequestResponse { 239 | var responses []RequestResponse 240 | var wg sync.WaitGroup 241 | 242 | client := NewHTTPClient() 243 | typeOpts := newTypeOptions(target) 244 | 245 | val := reflect.ValueOf(&typeOpts).Elem() 246 | 247 | for i := 0; i < val.NumField(); i++ { 248 | wg.Add(1) 249 | go func(val reflect.Value, i int) { 250 | defer wg.Done() 251 | typeName := val.Type().Field(i).Name 252 | requestOpts, err := typeOpts.GetByType(typeName) 253 | if err != nil { 254 | return 255 | } 256 | httpRequest := NewHTTPRequest(*requestOpts, client) 257 | 258 | req, err := httpRequest.Send() 259 | if err != nil { 260 | return 261 | } 262 | req.Type = typeName 263 | 264 | responses = append(responses, req) 265 | }(val, i) 266 | } 267 | wg.Wait() 268 | 269 | return responses 270 | } 271 | -------------------------------------------------------------------------------- /pkg/wafme0w/runner.go: -------------------------------------------------------------------------------- 1 | package wafme0w 2 | 3 | import ( 4 | "bufio" 5 | "context" 6 | "encoding/json" 7 | "errors" 8 | "fmt" 9 | httputil "github.com/Lu1sDV/wafme0w/pkg/utils/http" 10 | strutils "github.com/Lu1sDV/wafme0w/pkg/utils/strings" 11 | "github.com/logrusorgru/aurora/v4" 12 | "io" 13 | "os" 14 | "path/filepath" 15 | "strings" 16 | "sync" 17 | ) 18 | 19 | type Runner struct { 20 | Options *Options 21 | Wafs []WAF 22 | Aurora *aurora.Aurora 23 | } 24 | 25 | func NewRunner(options *Options) *Runner { 26 | return &Runner{Options: options, Aurora: aurora.New(aurora.WithColors(false))} 27 | } 28 | 29 | type Result struct { 30 | Target string 31 | FingerPrint []FingerPrintDetection 32 | Generic GenericDetection 33 | Errors []error 34 | } 35 | 36 | func (r *Runner) Scan() ([]Result, error) { 37 | var results []Result 38 | 39 | if r.Options.InputFile == "" && r.Options.Target == "" && r.Options.Inputs == nil { 40 | return results, errors.New("no target provided") 41 | } 42 | 43 | if r.Options.HeadersFile != "" { 44 | var headers []string 45 | headersFileName := r.Options.HeadersFile 46 | 47 | headersFile, err := os.Open(headersFileName) 48 | if err != nil { 49 | return []Result{}, err 50 | } 51 | 52 | scanner := bufio.NewScanner(headersFile) 53 | for scanner.Scan() { 54 | headers = append(headers, scanner.Text()) 55 | } 56 | r.Options.Headers = headers 57 | } 58 | 59 | if err := r.getWAFsFromFingerPrints(); err != nil { 60 | return []Result{}, err 61 | } 62 | 63 | if r.Options.Concurrency > 1 { 64 | //concurrent 65 | ctx, cancel := context.WithCancel(context.Background()) 66 | defer cancel() 67 | 68 | urls := urlStream(ctx, r.Options.Inputs) 69 | 70 | workers := make([]<-chan Result, r.Options.Concurrency) 71 | for i := 0; i < r.Options.Concurrency; i++ { 72 | workers[i] = concurrentScan(ctx, urls, i, &r.Wafs, r.Options) 73 | } 74 | 75 | for result := range mergeResults(ctx, workers...) { 76 | if !r.Options.Silent { 77 | r.outputResult(result) 78 | } 79 | results = append(results, result) 80 | } 81 | } else { 82 | //non concurrent 83 | scanner := bufio.NewScanner(r.Options.Inputs) 84 | for scanner.Scan() { 85 | target := scanner.Text() 86 | result := sequentialFingerPrint(target, r.Wafs, r.Options.FastMode, !r.Options.ExcludeGeneric) 87 | if !r.Options.Silent { 88 | r.outputResult(result) 89 | } 90 | results = append(results, result) 91 | } 92 | } 93 | 94 | //Eventually, write results to output 95 | if r.Options.OutputFile != "" && len(results) > 0 { 96 | var output []byte 97 | fileExt := strings.ToLower(filepath.Ext(r.Options.OutputFile)) 98 | 99 | if fileExt == ".json" { 100 | var err error 101 | output, err = prepareJSONOutput(results) 102 | if err != nil { 103 | return []Result{}, err 104 | } 105 | } else { 106 | output = prepareTXTOutput(results) 107 | } 108 | if len(output) != 0 { 109 | err := os.WriteFile(r.Options.OutputFile, output, 0644) 110 | if err != nil { 111 | return []Result{}, err 112 | } 113 | } 114 | } 115 | return results, nil 116 | } 117 | 118 | func (r *Runner) getWAFsFromFingerPrints() error { 119 | var wafs []WAF 120 | 121 | if r.Options.FingerPrints == nil { 122 | return errors.New("no JSON-formatted fingerprints provided") 123 | } 124 | 125 | byt, err := io.ReadAll(r.Options.FingerPrints) 126 | if err != nil { 127 | return err 128 | } 129 | if err := json.Unmarshal(byt, &wafs); err != nil { 130 | return err 131 | } 132 | r.Wafs = wafs 133 | return nil 134 | } 135 | 136 | // GetAllWAFs gets all wafs and returns a map waf=>manufacturer 137 | func (r *Runner) GetAllWAFs() (map[string]string, error) { 138 | 139 | r.getWAFsFromFingerPrints() 140 | result := make(map[string]string, len(r.Wafs)) 141 | 142 | for _, waf := range r.Wafs { 143 | wafName := strings.Split(waf.Name, " (")[0] 144 | manufacturer := strutils.SubStringBetweenDelimiters(waf.Name, "(", ")") 145 | result[wafName] = manufacturer 146 | } 147 | return result, nil 148 | } 149 | 150 | func (r *Runner) outputResult(result Result) { 151 | if !r.Options.SuppressWarnings { 152 | if len(result.Errors) > 0 { 153 | for _, err := range result.Errors { 154 | PrintWarning(err.Error(), r.Aurora) 155 | } 156 | } 157 | } 158 | printResult(result, r.Aurora) 159 | } 160 | 161 | func sequentialFingerPrint(target string, wafs []WAF, fastMode bool, withGeneric bool) Result { 162 | 163 | var fingErrors []error 164 | var responses []RequestResponse 165 | var generic = GenericDetection{} 166 | 167 | if !httputil.IsValidHTTPURL(target) { 168 | err := fmt.Errorf("invalid url: %v", target) 169 | fingErrors = append(fingErrors, err) 170 | return Result{Target: target, Errors: fingErrors} 171 | } 172 | 173 | parsedUrl, _ := httputil.ParseURI(target) 174 | urlNoPath := parsedUrl.Scheme + "://" + parsedUrl.Host 175 | 176 | if fastMode { 177 | responses = sendBasicRequests(parsedUrl.String()) 178 | } else { 179 | responses = sendAllTypesRequests(parsedUrl.String()) 180 | } 181 | 182 | for _, resp := range responses { 183 | if resp.Error != nil { 184 | fingErrors = append(fingErrors, resp.Error) 185 | } 186 | } 187 | identify := NewIdentifier(responses, wafs) 188 | results := identify.DoAll() 189 | 190 | if withGeneric && len(results) == 0 { 191 | generic = identify.GenericDetect() 192 | } 193 | 194 | return Result{Target: urlNoPath, FingerPrint: results, Generic: generic, Errors: fingErrors} 195 | } 196 | 197 | // read urls from buffered file and send them to channel 198 | func urlStream(ctx context.Context, reader io.Reader) <-chan string { 199 | 200 | scanner := bufio.NewScanner(reader) 201 | stream := make(chan string) 202 | go func() { 203 | for scanner.Scan() { 204 | uri := scanner.Text() 205 | select { 206 | case <-ctx.Done(): 207 | return 208 | case stream <- uri: 209 | } 210 | } 211 | close(stream) 212 | }() 213 | return stream 214 | } 215 | 216 | func concurrentScan(ctx context.Context, urls <-chan string, workerID int, wafs *[]WAF, options *Options) <-chan Result { 217 | 218 | results := make(chan Result) 219 | go func() { 220 | for url := range urls { 221 | result := sequentialFingerPrint(url, *wafs, options.FastMode, !options.ExcludeGeneric) 222 | select { 223 | case <-ctx.Done(): 224 | return 225 | case results <- result: 226 | } 227 | } 228 | close(results) 229 | }() 230 | return results 231 | } 232 | 233 | func mergeResults(ctx context.Context, channels ...<-chan Result) <-chan Result { 234 | var wg sync.WaitGroup 235 | 236 | wg.Add(len(channels)) 237 | outgoingResults := make(chan Result) 238 | multiplex := func(c <-chan Result) { 239 | defer wg.Done() 240 | for i := range c { 241 | select { 242 | case <-ctx.Done(): 243 | return 244 | case outgoingResults <- i: 245 | } 246 | } 247 | } 248 | for _, c := range channels { 249 | go multiplex(c) 250 | } 251 | go func() { 252 | wg.Wait() 253 | close(outgoingResults) 254 | }() 255 | return outgoingResults 256 | } 257 | --------------------------------------------------------------------------------