Metro Lottery


Conduct a security audit on the city's lottery system.

Scope: This challenge is limited to HTTPS in scope, please do not attack any other ports on this server and do not brute force attack this web server.

Tutorial Video


This challenge involves exploiting trusted client input. The objective of the challenge is to “win the lottery” which is not possible with the balance of money allotted to each user. Using all the allotted money will only yield a 3.85% chance of winning. The conditions for winning the lottery were to have a win percentage greater than 80%.


The vulnerability with this website is that the server will blindly trust the values supplied by the user when a request is being made. Specifically, when a request to purchase tickets is made, the cost and the number of tickets being purchased is provided in the request. It is possible for an attacker to adjust these values so that they can purchase more tickets than would normally be possible with the funds that they have. This behavior can be discovered by reviewing the source code of the page, specifically the main.js script.

By using the developer tools in Google Chrome, it is possible to see the specific HTTP request which purchases the codes and to see the values for the number of tickets purchased and the cost of the purchase. To do this, open the developer tools and navigate to the “Network” tab before making a purchase. Then, make a purchase. A request to the “purchase” page should appear. Click on the request to view additional details.


In the “Request Payload” section, the cost and the number of tickets can be clearly seen. A quick way to exploit the vulnerability is to copy the code that the purchase form uses and to make some modifications.

$('#purchase').on('click', function(e) {
    if (!session) {
      window.alert('loading, please wait');
    var box = $('#num-purchase');
    var tickets = parseInt(box.val()) || 0;

    if ( >= session.cost * tickets) {
        method : 'POST',
        url : '/purchase' +, 
        data : JSON.stringify({
        cost : session.cost * tickets,
        tickets : tickets
        dataType : 'json',
        contentType : 'application/json',
        complete: getUpdate,
    } else {
      alert('You do not have enough money.');

An analysis of this code will show that when the purchase button is clicked, the number of tickets is obtained from the form and then the cost is calculated by multiplying the cost saved in the “session” variable and number of tickets. The form then uses AJAX to send the data to the web server.

Copy the code where the AJAX request is made and paste it into the “Console” in developer tools. Then, adjust the values in the “data” field. You should also remove the “complete” field as that indicates the function that should be called after the server responds, which is not necessary for this exploit. By adjusting the data to indicate a small cost and a large number of tickets, it is possible to rig the odds of winning the lottery, triggering the flag to appear.


After waiting a few seconds for the end of the round, the flag should appear.


What is the flag obtained after winning the lottery?

The flag is randomly generated so the correct flag for you will be different.

©️ 2024 Cyber Skyline. All Rights Reserved. Unauthorized reproduction or distribution of this copyrighted work is illegal.