Focus. Speed. I am speed.
Welcome to Radiator Springs' finest store, where every car enthusiast's dream comes true! But remember, in the world of racing, precision matters—so tread carefully as you navigate this high-octane experience. Ka-chow!
Autor do desafio: @Octaviusss
Autor do writeup: @jackskelt
Você pode acessar os arquivos do desafio no nosso repositório https://github.com/HawkSecUnifei/Writeups
O desafio consiste em NoSQL Injection (MongoDB) e Racing Condition. Ao acessar o site, nos deparamos com a página inicial de uma loja de produtos do filme Carros. Podemos ver que temos autenticação, já que tem a presença de registro.

Analisando o código, encontramos essa parte do código que lista os produtos, e podemos perceber que a flag está presente na chave FLAG do produto de id 4 "Lightning McQueen's Secret Text" que custa 50 pontos.
Para ver a loja, é preciso fazer login. Assim que fazemos login, podemos acessar a "Official Store", onde estão listados os produtos. E nela podemos perceber que temos um botão para resgatar um Gift Card.

Observando um pouco mais o código, achamos essa função que faz a criação dos gift cards, porém é de forma aleatória, então vai ser muito difícil adivinhar.
A rota de resgate dos gift cards tem coisas interessantes. O usuário só pode resgatar um giftcard por dia, e considerando o giftcard criado anteriormente, só poderiamos resgatar 20 pontos se soubessemos o código, mas precisamos de 50 pontos para comprar o produto que contem a flag.
Um outro detalhe é em como o código que estamos enviando é processado. Ele é somente jogado em um objeto para fazer a query no Mongoose, sem qualquer sanitização. Logo, podemos explorar a vulnerabilidade de NoSQL Injection.
Só precisamos fazer a request GET /redeem?discountCode[$gt]=, que quando chegar na parte da query, seria traduzida no código abaixo. Explicando o que acontece: O discountCode[$gt]= na query será traduzido para um objeto contendo a chave $gt com um valor vazio. O $gt é um operador de comparação do MongoDB que faz uma comparação de "maior que". Nesse caso, procura qualquer string maior do que uma string vazia, assim retornando um resultado válido no findOne.
Com isso conseguimos usar o código de desconto que nos dá 20 pontos, porém precisamos de 50. Voltando a analisar o código, tem um comentário, juntamente com uma parte do código, interessantes:
Esse código me parece vulnerável a race condition. Uma race condition ocorre quando dois ou mais processos ou threads tentam acessar e modificar um recurso compartilhado (nesse caso um banco de dados) ao mesmo tempo, e o resultado final depende da ordem de execução desses processos. Isso pode causar comportamentos imprevisíveis e erros, como dados incorretos ou inconsistentes.
Logo, se eu enviar várias requisições ao mesmo tempo para a mesma informação, pode ser que eu saia com mais saldo do que o que era pra ser computado.
Então decidi utilizar o Burp Suite para fazer essas requisições (pode ser feito em código também). Para isso, peguei uma request para resgate e mandei para o Repeater. Nisso, fiz um grupo de requisições e adicionei várias, mudei o modo de envio para Send Group (parallel), para enviar todas as requisições ao mesmo tempo em paralelo e consegui adicionar mais saldo que esperado.

Recarreguei a página e agora estou com um saldo de 80 pontos, assim podendo comprar o produto que contém a flag e depois ir para a página de Orders buscar a flag

E finalmente obtendo a flag

Atualizado