CTF/picoCTF
[picoCTF] General Skills - flag_shop
j4ko
2022. 5. 1. 13:57
728x90
반응형
Description
There's a flag shop selling stuff, can you buy a flag? Source
Solve
Integer Overflow 에 관한 문제다. int는 4byte 크기이다 (-2,147,483,648 ~ 2,147,483,647)
Source Review
#include <stdio.h>
#include <stdlib.h>
int main()
{
setbuf(stdout, NULL);
int con;
con = 0;
int account_balance = 1100;
while(con == 0){
printf("Welcome to the flag exchange\n");
printf("We sell flags\n");
printf("\n1. Check Account Balance\n");
printf("\n2. Buy Flags\n");
printf("\n3. Exit\n");
int menu;
printf("\n Enter a menu selection\n");
fflush(stdin);
scanf("%d", &menu);
if(menu == 1){
printf("\n\n\n Balance: %d \n\n\n", account_balance);
}
else if(menu == 2){
printf("Currently for sale\n");
printf("1. Defintely not the flag Flag\n");
printf("2. 1337 Flag\n");
int auction_choice;
fflush(stdin);
scanf("%d", &auction_choice);
if(auction_choice == 1){
printf("These knockoff Flags cost 900 each, enter desired quantity\n");
int number_flags = 0;
fflush(stdin);
scanf("%d", &number_flags);
if(number_flags > 0){
int total_cost = 0;
total_cost = 900*number_flags;
printf("\nThe final cost is: %d\n", total_cost);
if(total_cost <= account_balance){
account_balance = account_balance - total_cost;
printf("\nYour current balance after transaction: %d\n\n", account_balance);
}
else{
printf("Not enough funds to complete purchase\n");
}
}
}
else if(auction_choice == 2){
printf("1337 flags cost 100000 dollars, and we only have 1 in stock\n");
printf("Enter 1 to buy one");
int bid = 0;
fflush(stdin);
scanf("%d", &bid);
if(bid == 1){
if(account_balance > 100000){
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);
}
else{
printf("\nNot enough funds for transaction\n\n\n");
}}
}
}
else{
con = 1;
}
}
return 0;
}
- 34 ~ 36번 라인을 보면 지역 변수 안에 int 형 선언한 뒤 그 밑에 scanf로 사용자 입력을 받아들여 초기화 하고 있다.
- 39 번 라인에서는 total_cost = 900 * number_flags 연산식을 통해 사용자 입력을 통해 받아 들인 number_flags 값을 계산해서 total_cost 값이 계산되고 있는 것을 확인할 수 있다.
- 41번 라인에서는 total_cost가 account_balance 보다 낮을 경우
- 42번 라인으로 분기한 뒤 account_balance = account_balance - total_count 연산식으로 account_balance를 초기화 시킨다.
Approach
소스 코드 상으로 flag얻으려면 3번 옵션을 통해서 flag를 얻을 수 있지만 그러려면 account_balance의 값을 조절해야된다. 조절할 수 있는 방법은 2번 옵션의 flow에서 account_balance를 초기화 시키는 라인에서 무언가를 해야될 듯 보인다.
Source Review에서 보았듯 integer overflow를 이용하면 39번 라인의 결과를 통해 42번 라인에 영향을 줄 수 있을 것 같아 보인다. 39번 라인에 total_cost 값을 integer overflow를 통해 최소 음수값으로 만들게 되면 42번 라인의 연산식에서 다음과 같이 동작할 것이다
account_balance = account_balance - (-total_cost)
위 식에서 알 수 있는 것은 -(-total_cost)가 양수가 된다는 점이다. 주의해야 될 점은 account_balance도 integer로 선언되어있다는 점이다.
즉 account_balance - (-total_cost)의 값이 integer overflow를 이용해 100,000 보다 큰 값으로 초기화 시키는 number_flags 값을 입력
예를 들어 다음과 같다
number_flags = 2386093
account_balance = 1100 - (-(900 * 2386093))
account_balance = 1100 + 2147483700
account_balance = -2147482600
- 위 계산 결과를 통해 보면 2386903을 입력해서는 account_balance를 100,000 보다 크게 만들 수는 없다
100,000 보다 크게 만드려면? 다음과 같은 계산을 통해 예측해봤다.
최소 음수값은 -2,147,483,648 이다. -100,001 만큼 더해준다. 결과는 -2147583649 이다.
앞서 언급했듯 -(-) 는 + 이기 때문에 부호는 크게 신경쓰지 않는다.
2147583649 / 900 로 나눈 뒤 반올림 한 값(2386204) 을 입력해준다
연산식은 다음과 같이 동작할 것이다
number_flags = 2386204
number_flags = 900 * 2386204 = 2147583600 // 2147583600 은 over flow의 결과는 -2147383696 이다
account_balance = 1100 -(-2147383696) = 2147384796
// 2147384796의 over flow 의 결과는 2147384796 이다
// int의 max 값이 2,147,483,648이기 떄문에 2,147,384,796 은 overflow가 일어나지 않는다.
account_balance는 2,147,384,796 로 초기화 된다.
Result
728x90
반응형