jellyCTF
Phase_coffee_2 [487 pts]
Writeup author: lolmenow
Difficulty: medium
Provided files: phase_coffee_2.zip
Description: Surely all the bugs have been fixed…
Following the same steps as the first edition of this challenge, lets take a look at the source code. Fortunately, the C source file is provided.
#include <stdio.h>
#include <stdlib.h>
// Surely there won't be any more bugs
int main(int argc, char **argv) {
int coin_balance = 100;
int con = 0;
while (con == 0){
printf("\nWelcome to the Phase Connect coffee shop v2.0\n");
printf("We sell coffee! \n");
printf("Please buy our coffee... \n");
printf("or else... \n");
printf("1. Check Account Balance\n");
printf("2. Purchase Coffee\n");
printf("3. Exit\n");
printf("Enter a menu selection \n");
fflush(stdin);
int menu;
scanf("%d", &menu);
if(menu == 1)
{
printf("\n\nCurrent account balance: %d \n\n", coin_balance);
}
else if (menu == 2)
{
printf("\n\nCurrently on sale\n");
printf("1. Chisaka Airi Inspired - $35 each\n");
printf("2. Rie Himemiya Inspired - $35 each\n");
printf("3. Jelly Hoshiumi Inspired (Limited Edition) - $1,000,000 each\n");
printf("Please make a selection: ");
int choice;
fflush(stdin);
scanf("%d", &choice);
if (choice == 1 | choice == 2)
{
printf("\nEnter desired quantity: ");
int quantity = 0;
fflush(stdin);
scanf("%d", &quantity);
printf("\n");
if (quantity > 0)
{
int total_cost = 35 * quantity;
int coin_balance_after_purchase = coin_balance - total_cost;
printf("Current balance: %d\n", coin_balance);
printf("Total cost: %d\n", total_cost);
printf("Balance after purchase: %d\n", coin_balance_after_purchase);
if (coin_balance_after_purchase < 0)
{
printf("Insufficient funds to purchase! Please try again!\n\n");
}
else
{
coin_balance = coin_balance_after_purchase;
printf("%d coffees purchased! Your coffee is being packaged and will be delivered in 2028!\n\n", quantity);
printf("Current balance: %d\n", coin_balance);
}
}
else
{
// Stupid bugs... Fixed negative coffee quantity input validation
printf("Invalid coffee quantity\n");
}
}
else if (choice == 3)
{
printf("You have chosen the deluxe, premium, limited edition seiso idol princess Jelly Hoshiumi inspired coffee.\n");
printf("This coffee costs $1,000,000. Press 1 to confirm purchase: ");
int bid = 0;
fflush(stdin);
scanf("%d", &bid);
if (bid == 1)
{
if (coin_balance >= 1000000)
{
FILE *f = fopen("flag.txt", "r");
if(f == NULL){
printf("Flag not found: please run this on the server\n");
exit(0);
}
char buf[64];
fgets(buf, 63, f);
printf("YOUR FLAG IS: %s\n", buf);
break;
}
else
{
printf("Insufficient funds to purchase! Please try again!\n\n");
}
}
}
}
else
{
con = 1;
}
}
return 0;
}
With the last vulnerability in mind, lets see if its similar to this problem.
And this time, we have an integer underflow vulnerability!
int total_cost = 35 * quantity;
int coin_balance_after_purchase = coin_balance - total_cost;
The coin_balance_after_purchase
could underflow if total_cost
is greater than coin_balance
. In C, if you subtract a larger int from a smaller one, the result wraps around and becomes a very large positive number.
But, what exactly do we have to input so it can wrap around and become a very large positive number? Simply putting in the integer limit number from the first edition of this challenge won’t work.
In this case, we would need to input a very large quantity that, when multiplied by 35, causes an integer overflow resulting in a negative total_cost
. This negative total_cost
would then, when subtracted from coin_balance
, effectively add to it, giving us a high balance.
Simple arithmetic math can help us find the value.
2147483647 / 35 + 1 = 61356676
Lets try inputting 61356676
Hmmm, that does not seem to work.
Lets try it with a slightly higher number so we can be sure it wraps around. Lets try 61356680
It successfully underflowed and now we have a high balance! We can now buy the “flag” coffee.
There is our flag!
Final flag: jellyCTF{dud3_y0u_m1ss3d_4n0th3r_bug}