After creating my vulnerable django web app I was looking to further my knowledge by creating a vulnerable REST API based on Node, Express, TypeScript and MongoDB.
This app consists of the functionalities:
- Register and Login
- List all of the users after Log-in as some user
- Delete a user (only ourselves)
- Make adjustments to our user
- Request money to our user
- Add an item that we will be able to buy or sell
- Buy an item
- Sell an Item
During the building of this app I inserted for fun several inbuilt Business logic vulnerabilities that one can look up for them.
I will also explain in this note how to exploit the Business logic vulnerabilities I inserted in purpose to the app and how to patch them, have fun!
In this repository you will be able to find the the Postman Collection for easy interaction with the API.
Start by cloning the repository:
git clone https://github.com/nirzaaa/vulnerableAPI.git
cd vulnerableAPI
Then we will have to download and install the specified packages and their dependencies:
npm install
Then, all is left for us is to start the application:
npm start
After log-in as nirza
and trying to see the data of all of the users, I will be able to see their salt, password and sessionToken:
This way I will be able to log-in as them and also to crack their password.
In order to patch this we will have to go to src -> db -> users.ts
and adjust select: false
:
password: { type: String, required: true, select: false },
Without the select: false
, it will show the data to all of the API users.
After leaking the hashes of the others api users, we are able to crack their password quiet easily:
In order to fix it, we are able to use SECRET
and also salt
to make the cracking of the hashes much more difficult by going to src -> helpers -> index.ts
:
import crypto from 'crypto';
const SECRET = 'NIRZA-REST-API';
export const random = () => crypto.randomBytes(128).toString('base64');
export const authentication = (salt: string, password: string) => {
// return crypto.createHash('md5').update(password).digest('hex');
return crypto.createHmac('sha256', [salt, password].join('/')).update(SECRET).digest('hex');
};
While trying to request money we will get to this:
if ( money_to_add > 99 || existingUser.requested_money == 1 ) {
return res.sendStatus(400);
}
existingUser.money += money_to_add;
existingUser.requested_money = 1;
await existingUser.save()
We can try to send several requests in parallel in order to bypass the restriction of the amount of money that we are able to have.