一、前言
好久没打ctf了,帕鲁杯第二届来了,应急响应环境需要70G,燃尽了,应急响应不打了,所以来看看Web题目。
二、解题过程
1、CatBank解题思路
第一步,启动题目环境,分别创建test1和test2两个账户
第二步,登陆test账户,直接向test2账户转账1000000
第三步,登陆test2账户,向Morscerta的猫猫转账1000000,得到flag
2、猫猫的秘密解题思路
第一步,启动题目环境,查看网页源码,发现如下js代码,从代码中得知存在get_secret接口,同时需要Authorization进行认证,Authorization一些常见的认证授权方案如:Basic认证、Digest认证、Beare认证、JWT认证等,经过测试这里为JWT认证
<script>
let token = '';
document.getElementById('loginBtn').addEventListener('click', async () => {
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;
try {
const response = await fetch('/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ username, password })
});
const data = await response.json();
if (response.ok) {
token = data.token;
document.getElementById('loginResult').textContent = `登录成功: ${data.message}`;
document.getElementById('loginResult').classList.remove('hidden');
document.getElementById('loginSection').classList.add('hidden');
document.getElementById('secretSection').classList.remove('hidden');
} else {
document.getElementById('loginResult').textContent = `错误: ${data.error}`;
document.getElementById('loginResult').classList.remove('hidden');
}
} catch (error) {
document.getElementById('loginResult').textContent = `发生错误: ${error.message}`;
document.getElementById('loginResult').classList.remove('hidden');
}
});
document.getElementById('getSecretBtn').addEventListener('click', async () => {
try {
const response = await fetch('/get_secret', {
method: 'GET',
headers: {
'Authorization': token
}
});
const data = await response.json();
if (response.ok) {
let resultText = `${data.message}\n\n`;
if (data.public) {
resultText += `${data.public}\n\n`;
}
if (data.confidential) {
resultText += `猫猫信息: ${data.confidential}\n\n`;
}
if (data.flag) {
resultText += `Flag: ${data.flag}`;
}
document.getElementById('secretResult').textContent = resultText;
} else {
document.getElementById('secretResult').textContent = `错误: ${data.error}`;
}
document.getElementById('secretResult').classList.remove('hidden');
} catch (error) {
document.getElementById('secretResult').textContent = `发生错误: ${error.message}`;
document.getElementById('secretResult').classList.remove('hidden');
}
});
document.getElementById('logoutBtn').addEventListener('click', () => {
token = '';
document.getElementById('username').value = '';
document.getElementById('password').value = '';
document.getElementById('loginResult').classList.add('hidden');
document.getElementById('secretResult').classList.add('hidden');
document.getElementById('secretSection').classList.add('hidden');
document.getElementById('loginSection').classList.remove('hidden');
});
</script>
第二步,发现报错“Invalid token: Invalid algorithm”,意思是说jwt的算法无效,jwt算法存在漏洞CVE-2015-9235,可以将header中签名算法改为none进行绕过
第三步,这里已经成功利用了漏洞,并且或得到了public数据,但是距离获得flag还差一步,既然是public那就是公共的,猜测可能是权限不够高,于是尝试构造jwt的payload部分,和权限相关的常见字符串如:role,account,isAdmin等,这里发现是role,于是构造jwt的payload部分如下所示,成功得到flag
3、CatNet解题思路
第一步,启动题目环境,使用dirsearch可以直接扫描出admin目录
第二步,访问admin目录发现无权限,并且提示只有本地可以访问,显而易见是xff伪造
第三步,点击Get Flag功能出线报错,报错提示同样需要xff伪造
第四步,xff伪造之后又提示Incorrect code,查看网页源码发现如下js代码,大概意思就是点击getflag功能会调用/admin/flag接口,同时设置请求头X-Internal-Auth: cateye-internal-000,根据提示Incorrect code猜测不是000
第五步,截取数据包,利用burp进行爆破,得到正确code为123
4、ezblog解题思路
第一步,启动题目环境,下载题目附件,使用反编译工具审计代码,在dashboard.class中有一个backdoor路由,realkey是不知道的,想要得到flag就必须得知道realkey
第二步,继续审计App.class文件,App.class中路由了一个/assets,FileStaticRepository设置了基础目录/app/assets
第三步,从App.class跟踪到FileStaticRepository.class文件,代码如图所示,这里的relativePath是一个可控参数,solon框架中这个参数是通过url路径传输过来的,relativePath就是/assets/后面的内容,如果构造恶意payload在url中表现为:http://x.x.x.x/assets/…/etc/passwd
第四步,在App.class中提到了基础目录为/app/assets,再结合backdoor中需要知道realkey,所以猜测/app目录下可能存在真实的app.jar,于是构造payload为:/assets/…/app.jar,这里需要注意,直接在url中访问会一直跳转,所以这里用burp截包forward之后下载,如下图所示
第五步,利用反编译工具打开下载后的app.jar得到realkey,利用realkey成功得到flag
5、catshell解题思路
太难了,我最讨厌绕过waf😄