Mục | Nội dung |
---|---|
Tên bài | flag_shop |
Thể loại | General Skills |
Link | https://play.picoctf.org/practice/challenge/49?originalEvent=1&page=3 |
📚 Lý thuyết
Khái niệm | Giải thích |
---|---|
Integer Overflow | Khi một biến số nguyên vượt quá giới hạn của kiểu dữ liệu, nó sẽ “quay vòng” thành số âm (trong two's complement). |
Two’s Complement | Cách biểu diễn số âm phổ biến trong máy tính. Số lớn vượt ngưỡng sẽ bị hiểu nhầm là số âm. |
Vấn đề ở đây | Biến số dư balance có thể bị overflow nếu cộng thêm số lớn, khiến ta vượt qua kiểm tra balance >= FLAG_PRICE . |
Hậu quả | Người dùng có thể “mua” flag mà không đủ tiền, nhờ lỗi logic từ overflow. |
🛡️ Thực hành
Source code:
#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; }
🔎 Phân tích
Ban đầu người dùng có số dư 1100. Flag "xịn" (1337 Flag) có giá 100000, nên về logic bình thường thì không thể mua được.
💡 Ý tưởng
- Lổ hổng:
int total_cost = 900 * number_flags;
- Biến
total_cost
là kiểuint
. Nếunumber_flags
lớn,total_cost
sẽ bị overflow ==> có thể biếntotal_cost
thành số âm → bypass điều kiệnif(total_cost <= account_balance)
Điều này làm cho account_balance sau khi trừ tiền có thể trở thành số rất lớn, dù người dùng nhập số cực lớn. Sau đó quay lại mua 1337 Flag, kiểm tra account_balance > 100000 được thoả mãn!
🧪 Bước 2: Thực hiện
==> DONEEEE!
Cần kiểm tra cẩn thận input và dùng kiểu dữ liệu an toàn (long long, unsigned long,...) nếu cần.
✍️ Write-up by tRavOndAtrACk – Happy hacking!
Top comments (0)