护网杯ltshop引发的思考
题目描述
题目开始需要注册账号,登陆进去后是一个商场,每个账号初始有20RMB,5RMB可以买1包大辣条,5包大辣条换1包辣条之王,9999999包辣条之王可以换Flag
做题思路
全页面就一个输入点,选择你需要越换辣条之王的数量,发现我们的钱连一个辣条之王都买不了,联想到之前CTFtime上的某个比赛(忘了),第一步条件竞争,Burp200线程买大辣条,成功买到16包大辣条!!!,但是因为要9999999包辣条之王才能换flag
思路1:查看此题有没有换回去的方法,如果存在可以通过条件竞争一直来回换辣条和RMB,导致RMB或辣条越来越多从而买到Flag,遗憾的是并没有反向兑换
思路2:查看是否可以通过注册账号功能或者其他功能,让每个账号的资产全部移植到同一个账号上去。Burp抓全部包,一一查看,发现逻辑全部在后台处理,除了cookie没有任何输入点,放弃
思路3:可以通过php弱类型类似于0.999999=1的方法,发现小数点被过滤,放弃
然后我就被卡在这了,常规思路走不通,走不常规思路,首先Fuzz输入框,发现除了数字几乎全部被过滤,但是;(分号)并没有被过滤,但也没有利用的方法,扫目录扫文件泄露没有任何发现,cookie发现后台是用golang写的,百度一波golang的漏洞,看了一波文章没有任何发现。。。
然后后面几乎一直都在人肉Fuzz了,啥字符啥payload都输了一遍,没有任何反应,然后突然刘师傅说了一句会不会是数值溢出因为go是强类型。发现新大陆,查看go数据类型最大值准备fuzz poc。
但打到比赛结束都没有做出来,赛后看wp发现要除以5才能拿,之前Web没做过溢出的题目,研究了一会儿,大概推测后台代码大致如下(不会Go用伪代码代替一下)
#伪代码
uint64 number = input() //用户输入的兑换辣条之王的数字
uint64 max = math.uint64max //无符号整型的最大值
uint64 biglt = 16 //用户的大辣条包数,如上假如为16包
uint64 kinglt = 0 //用户拥有的辣条之王
if(number不是数字){
error
}
else if(number > max){
error
}
else if( (biglt - 5 * number) < 0 ){
print 买不起那么多
}
else if( (biglt - 5 * number) >= 0 ){
print 购买成功
biglt = biglt - 5 * number
kinglt = number
}
Go的64位无符号整型最大值为18446744073709551615(简称max)
对于无符号整型的溢出,我们知道
- max + 1 = 0
- max + 2 = 1
- max + n = n -1
- max * 2 = max - 1
- max * 3 = max - 2
- max * n = max - n
此时我们需要绕过判断让我们购买超多的辣条之王,所以上诉代码
biglt - 5 * number必须大于0
此时5 * number必须小于16
如上公示得知直接输入max是行不通的(比赛时候疯狂输入max,max-1,max+1......),我们需要变换一下思路,比如(max + 1) / 5, (max + 2) / 5, (max + 3) / 5……
只要max+n是5的倍数就行,我们选用(max+5) / 5, 此时biglt - 5 * number,等价于16 - max+5 等价于 16 - 4 等价于12,绕过了之前的所有判断,kinglt被赋值为(max+5)/5,大于9999999,我们成功买到了flag
后记
没做出来有点可惜,本来其实可以想到的,但由于最后做出来的人太多了:) 可能有点慌一直在Fuzz了,没有想到去猜后台代码。归根结底还是自己太菜了,膜师傅们
0 条评论