引言
今天是我们 General Skills 最後一题,光是基础技能我们就花了 21 天呢...
毕竟是入门,我们就慢慢来吧!
明天开始会花一天介绍一下 2019 的游戏,之後就是六个领域各选一至两题来解罗!
这题算是 General Skills 中技术含量较高的,也需要一点点 C 语言基础,
非常适合当压轴~我们开始吧!
General Skills / flag_shop
这题的情境是说有个商店会贩卖 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界接
每星期及每个月都会有一次固定的会议,加上其他大大小小的会议,一个月至少有6次以上的会议,每次会议看到...
前面我们谈了,coroutine的coroutineScope、继承、异常处理和取消,也在文中提到了...
接续昨天的 DOM 方法,JavaScript 常会出现:按一下某按钮,页面上会生出新的区块,这是怎...
询问各位大大,我在网路上看到要转移空间,就是按下延伸磁碟机。 但是我的的C槽却一直无法出现,延伸磁...
tags: ItIron2021 Javascript 前言 前两天这样搞下来,相信你们对this已...