https://zeroday.hitcon.org/vulnerability/ZD-2023-00143
这次比起上次的绕过注册验证码又更没有实际危害
虽然可以洗P币,但条件非常多
必须是能开盘的板主才能稳定达成
而且赌盘都会留纪录,就算真的发生了也可以事后追讨
PTT 站方到最后都没有回应,可能是觉得不值得修吧
不过我自己是觉得蛮好玩的
因为是三月回报的,其实我也忘了有这一回事
早上收到状态变成公开的信才想起来
总之,在我找到能无限验证 PTT 帐号的方法之后
我开始无聊翻翻 PTT 的程式码
之后找到了 PTT 处理乐透的部份
对于乐透,在看板的资料夹下会有两个档案:
分别是纪录各选项数目的 FN_TICKET_OUTCOME
以及纪录使用者选什么选项的 FN_TICKET_USER
当使用者买了 A 选项共 X 张时
会读取 FN_TICKET_OUTCOME 并把 A 选项总数增加 X
并在 FN_TICKET_USER 纪录使用者某某买了 X 张 A
等到开奖时,用 FN_TICKET_OUTCOME 计算赔率
并用 FN_TICKET_USER 对每个中奖的纪录发放相应的P币
最后把这两个档案删除
假如我刻意卡在购买彩券的页面,等开奖之后才购买会发生什么事?
答案是 PTT 会检查档案存不存在所以会没办法购买
但一个很明显的问题就出现了:
假如我卡在购买页面,等待开奖之后继续等
等到下一次赌盘又开启时再按 ENTER 会发生什么事
答案是可以购买,会直接写到下一次的赌盘纪录 ^_^
到这里就有一个可以洗钱的方案了
条件是必须是有开盘权限的人
首先板主开一个单价 10 元的乐透
另一个使用者 A 停在购买页面后
板主重新开一个单价 10000 元的乐透
使用者 A 此时再购买
最后板主取消赌盘退钱
就可以每张花 10p 买然后退 10000p 回来
直接翻 1000 倍
其实还有另一个增长更为快速的方法:
1. 板主开启有两个选项的乐透
2. 使用者A 停留在购买页面
3. 板主结束乐透并开启新的有三个选项的乐透
4. 使用者B 购买 Y-1 份乐透(选项3)
5. 使用者A 购买 X 份乐透(选项2)
6. 使用者B 购买 1 份乐透(选项3)
7. 板主开奖(选项3)
关键在第 5 步时
使用者 A 会因为只写入前两个选项的结果而造成
选项 3 在 FN_TICKET_OUTCOME 中归零
到板主开奖时,赔率会是 X/1 = 1:X
但在发放奖金时使用的 FN_TICKET_USER 仍然有使用者B的纪录
因此使用者B可以拿到 ((Y-1)X + 1X) * 0.95 = 0.95XY
其实不管是哪一个方法,增长速度都是非常快的
连续来个几次就能突破 INT_MAX 上限了
P币溢出成负的也不成问题
但因为我不是板主,没办法在站上测试
所以我只好拿原始码自己架在我电脑上实验
实验后发现的确可以成功:
https://i.imgur.com/P12z68K.png
可以看到上方选项3 只有1份,但下方发奖金时发了23+1份
另外,若板主先开启四个选项的乐透再开二个选项的乐透的话
便能让使用者在后者下出不存在的第四个选项
在开奖印出选项名称时,此时 betname[mybet] 是未初始化的 char[30]
因此可以 leak 出 stack 上的资讯
我有试过先Q一个人,把他的使用者资讯包含 hash 过的密码 load 到 stack 上
看看有没有办法印出来
但排了好一阵子之后排不太出来,都会被洗掉
就放弃了
如果不是板主的话,就没有办法稳定洗钱
但想要恶搞系统还是挺容易的
譬如现在赌盘只有两个选项
我们卡在购买界面
等到新的有三个选项的赌盘开启之后再购买
就可以把选项三的纪录洗掉
如果最后开前两个选项赔率会减少
而如果最后开三赔率会暴增
甚至如果我们是最后下的,选项三会没人中奖直接吞光
上次等到 HITCON ZeroDay 平台公开了之后才又跑来跟我说要退回不公开
这次不知道会不会也是这样
不过反正我现在就要发文
都快三个月前的事了,时间应该够了吧