Created on Sun. 05 Sep 2021
For the past year or so, I started working on this personal project that I dubbed XSS Bomb. I created this project in response to an issue I had during bug bounty is I didn't know when my XSS payloads where hitting now with a bit of retrospective I could have used something like XSS Hunter but back then I didn't know it existed :) so I decided to build this project. This blog post aims to explain the app's architecture my plans on improving upon it's architecture and how it works so that if anyone is interested they can contribute.
So this project is composed of two main parts that work together I'll go in depth on how they work later and go through their independent source code to outline their issues and strong points :)
This schema outlines the most basic usage of this project. The application for each user will create a unique identifier that can then be translated to a link with different functionality (I will go more in depth those later) for now let's focus on the picture functionality each user gets a 1px/1px picture basically invisible to the human eyes but inside of the html the victime browser(3) will see the link and call to get that picture so it will ping the server of XSS bomb(1) where the picture is located when that happens the server(1) issues a notification to the mobile client(2) with he can get the notifications from the server and inspect the request did by the original browser(3).
Understanding the underlying use case of the project we can now go more in depth on how the server actually works. Here is a handy scheme on how the docker compose work:
Inside of the current architecture the phone client (1) connects to the server (2) which is connected himself to the MongoDB database (3). There also is a Mongo Express (4) instance running on localhost inside of the server so that the administrator can manage the database and stuff. As shown by the square around the MongoDB database (3) and the Mongo Express instance (4) they both listen on localhost so they are not accessible by the public and should never be opened to the public ;) I achieved this by setting listening ports like this inside of the docker-compose.yml file.
During the development of the app I forgot to add this line honestly and one day after hosting the server I was greeted by the following result on the database :D
You live, you learn :D
So the mobile front-end I had a few ideas I originally wanted to write it in kotlin and I might do the kotlin migration one day but for now I just picked what I was the most comfortable with React-Native.
The architecture is pretty much classic for a react native app and is pretty easy to follow. It has a screens folder for the screens a navigation folder for the navigation components and such.
app/ ├── assets/ # All of the images and assets │ └── [Images] ├── components/ # The individual components │ └── [React Native Source Code] ├── navigation/ # The navigation classes to handle the screens │ └── [React Native Source Code] ├── screens/ # Folder containing the different screens │ └── [React Native Source Code] ├── App.js # The Docker file used to launch the database and back-end ├── app.json # config file for the app └── package.json # Dependencies for the app
The main gimmick for the front end is the ability to change the server it connects to, the app has to contact the server as seen previously and because this project is open source I didn't want to limit a user to use my own vps and if some one has different NDA's when they are doing a pentest they can just use their own server for protection.
There is one request that is always done on startup that cannot be changed and is the following:
This helps rendering the first page where all of the public instances are listed. When a instance is selected it is then sent to the rest of the apps through props.
For now the front-end is very basic and there isn't much to go in depth other than doing a full React Native tutorial but for now the main objective is to add a Refresh Token system so that it has a more secure login system right now its just a basic post request and the token is stored on the device so that if the token is compromised it would be a major security fault on an account. I also would like to redesign the main navigation instead of having a pane on the left have a bottom tab bar and I have a few ideas on how to make it as minimalist as possible.
The back-end also has a really basic architecture for what it is but does have a notable few aspects that would be great content for this post.
The API is divided in 3 main parts:
The /auth endpoints are obviously there to handle the authentication with the /user endpoints to handle the user interaction like inspecting the different notifications a user got and changing his/her password or username. The /api endpoint is where the main functionality of this project rests because this is where the payload/picture is going to send it's requests if an XSS hits. The :id is supposed to be replaced on the user side by their id and the server will search inside of the database what user matches to the given id.
I think for me the main trick that I had to handle inside of the API was the distinction between the routes where users would ping and the routes that would not need authentication. For that I basically just called the middleware on the api endpoints that needed login and I didn't call them inside of the public endpoints. You can see in the screenshot above after defining the route I would directly start coding the function that gets called at that moment. Compared to other routes where the middleware is obviously called to check if the jwt token sent is valid.
I hope this blog post was interesting if you need more information on this project I have it available on my github with a little wiki I wrote and a postman documentation on how the api endpoints work in practice, go have a look :)