[2021铁人赛 Day21] General Skills 18

  • 引言
    今天是我们 General Skills 最後一题,光是基础技能我们就花了 21 天呢...
    毕竟是入门,我们就慢慢来吧!
    明天开始会花一天介绍一下 2019 的游戏,之後就是六个领域各选一至两题来解罗!

    这题算是 General Skills 中技术含量较高的,也需要一点点 C 语言基础,
    非常适合当压轴~/images/emoticon/emoticon12.gif我们开始吧!

  • General Skills / flag_shop
    https://ithelp.ithome.com.tw/upload/images/20211006/20111429QhuxjB3MFU.png
    这题的情境是说有个商店会贩卖 flag ,买到你就有 flag 了~
    题目给的材料除了商店程序所在服务器以外,还罕见地给了商店程序的原始码,用 C 语言写的!
    总之我们先把原始码下载下来等等备用,档案名称是 store.c

    我们先不看原始码,先用 nc 玩玩 flag 商店是怎麽运作的:

    $ nc jupiter.challenges.picoctf.org 4906
    

    连上後程序输出:

    Welcome to the flag exchange
    We sell flags
    
    1. Check Account Balance
    
    2. Buy Flags
    
    3. Exit
    
     Enter a menu selection
    

    看起来是 menu 形式的界面,可以输入 1,2,3 来决定需要什麽服务。
    1 是查看帐户余额, 2 是买 flag , 3 是离开,
    总之我们先看看目前的余额,输入 1 按下 Enter :

    
    
    
     Balance: 1100 
    
    
    Welcome to the flag exchange
    We sell flags
    
    1. Check Account Balance
    
    2. Buy Flags
    
    3. Exit
    
     Enter a menu selection
    

    可以看到余额是 1100 ,再来我们试着购买 flag 看看,输入 2 :

    Currently for sale
    1. Defintely not the flag Flag
    2. 1337 Flag
    

    它贩卖两种 flag ,一个是「绝对不是 flag 的 flag 」,另一个是「 1337 flag 」,
    先看看 1337 flag 吧:

    1337 flags cost 100000 dollars, and we only have 1 in stock
    Enter 1 to buy one
    

    居然需要十万,而且只有一个,想必这就是解答 flag 了,我们看另一个 flag 是什麽:

    These knockoff Flags cost 900 each, enter desired quantity
    

    它说仿冒品只要 900 ,输入你要的数量。如果你真的买了什麽事都不会发生~
    先 ctrl-C 或是第三个选项离开程序吧,等等找到方法後要重开。

    总结来说目前正常使用是买不到十万 flag 的,我们看看原始码有什麽,
    这是 C 语言程序,我等一下只讲一下关键部份,大家可以先自己找找看突破点在哪里,
    提示是「条件、上限」。


    
    解
    
    答
    
    在
    
    下
    
    面
    
    

    其实关键在 C 语言 int 的数值上限 ,最高是 2147483647 ,也就是 2 的 31 次方 - 1 ,
    最高的正数只能到这,一旦再 + 1 ,你会发现变数内容变成 -2147483648 ,这两数可是天差地远的!
    这个程序的漏洞在:

    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");
        }
    
    
    }
    

    当你输入了 number_flag ,虽然有个 if(number_flags > 0) 让你无法输入负数,
    但是在我标注漏洞的地方,它把这个数字乘以 900 ,所以如果你 number_flag 很大,
    大到一定程度但不会超过上限,这时 if(number_flags > 0) 你可以顺利通过,
    但下面会乘以 900 ,如果你输入的数乘以 900 超过 2147483647 , bug 就出现了,
    total_cost 会变成负的,那我标注的地方就可以穿过去,下面就会帮你加钱!

    所以我们破解的方法,就是输入一个很大的数,
    大概就是乘以 900 後超出 2147483647 一两千的程度,
    因为超出范围後会从 -2147483648 开始往上加,
    -2147483647,
    -2147483646,
    ...
    而原本余额有 1100 ,所以我们要抓超出上限大概 1000 多,
    才能加上去以後不至於又爆掉:

    account_balance = account_balance - total_cost;
    

    看上面的那句,如果 total_cost 变成 -2147482000 左右 (大概超出上限一两千会变这样)
    那 1100 - (-2147482000) = 2147483100 ,很刚好不超过 account_balance 的上限。

    因此,我们的目标就是「 900 x 输入的值 = 2147483647大概再超出2000 」,
    定量来说,我把输入的值取: 2147485647 / 900 ~= 2386095 ,估计会得到几乎最多的钱,
    试试看:

    Currently for sale
    1. Defintely not the flag Flag
    2. 1337 Flag
    1
    These knockoff Flags cost 900 each, enter desired quantity
    2386095
    

    输入我要买 2386095 个冒牌货 flag :

    
    The final cost is: -2147481796
    
    Your current balance after transaction: 2147482896
    

    厉害了,你花了 -2147481796 个钱,余额剩下 2147482896 ,
    真的相当接近最大值。

    我们可以买 flag 啦,而且钱绰绰有余呢:

    Currently for sale
    1. Defintely not the flag Flag
    2. 1337 Flag
    2
    1337 flags cost 100000 dollars, and we only have 1 in stock
    Enter 1 to buy one1
    YOUR FLAG IS: picoCTF{m0n3y_bag5_9c5fac9b}
    

    购买 1337 flag ,输入 1 买一个,
    就得到 flag 啦!


<<:  [Day21] Remote Code Execution

>>:  [Day21] 第二十一章 - 使用Ajax来做登入API界接

(DAY 29) MS Teams另类应用:视讯切换器

每星期及每个月都会有一次固定的会议,加上其他大大小小的会议,一个月至少有6次以上的会议,每次会议看到...

聊聊structure concurrency 结构化并发

前面我们谈了,coroutine的coroutineScope、继承、异常处理和取消,也在文中提到了...

JavaScript DOM | createElement()

接续昨天的 DOM 方法,JavaScript 常会出现:按一下某按钮,页面上会生出新的区块,这是怎...

如何把D槽空间分给C槽

询问各位大大,我在网路上看到要转移空间,就是按下延伸磁碟机。 但是我的的C槽却一直无法出现,延伸磁...

每日挑战,从Javascript面试题目了解一些你可能忽略的概念 - Day17

tags: ItIron2021 Javascript 前言 前两天这样搞下来,相信你们对this已...