2023-第一届“帕鲁杯”CTF-wp
2023-第一届“帕鲁杯”CTF-wp
VVkladg0r第一届“帕鲁杯”-CTF应急响应挑战赛
应急响应的题根本做不来 还是学web吧
以后应该不会学密码、misc之类的了
现在的学习路线是先学蓝队这边java安全 溯源什么的
然后大二学红队这边 渗透 内网 re 武器开发之类的
Web-签到
进来
给了源码:
from flask import Flask, request, jsonify |
这段代码是一个使用 Flask 框架的 Python Web 应用。它定义了两个路由,一个是根路径 /
,另一个是 /flag
。以下是代码的详细解释:
- 导入模块和函数:
Flask
: Flask web 框架的核心。request
: 用于处理客户端请求数据的对象。jsonify
: 用于将字典转换为 JSON 格式响应。requests
: 用于发送 HTTP 请求的库。flag
: 从flag.py
文件中导入的函数或变量(代码中未给出flag.py
的内容,所以我们不知道flag
的具体内容和类型)。
- 初始化 Flask 应用:
app = Flask(__name__)
: 创建一个 Flask web 应用实例。
- 定义路由和对应的处理函数:
- 根路径
/
:url = request.args.get('url')
: 从 GET 请求的参数中获取url
。- 如果url存在:
- 使用
requests.get(url)
发送 GET 请求到这个url
。 - 获取响应的文本内容,并打印它。
- 检查响应内容中是否包含 “paluctf”。
- 如果包含,返回
flag
。 - 否则,返回响应的文本内容。
- 如果包含,返回
- 使用
- 如果url不存在:
- 返回一个 JSON 格式的响应,包含消息和提示数据。
- /flag 路由:
- 无论使用 GET 还是 POST 请求,都直接返回字符串 “paluctf”。
- 根路径
- 运行 Flask 应用:
if __name__ == '__main__':
: 确保只有在直接运行这个脚本时,下面的代码才会执行。app.run(debug=True, host="0.0.0.0", port=80)
: 在 debug 模式下运行 Flask 应用,监听所有可用的 IP 地址(0.0.0.0
),并使用默认的 HTTP 端口 80。
注意:
- 在生产环境中,通常不会使用
debug=True
和端口 80(因为端口 80 通常需要管理员权限),并且应该使用更安全的配置和措施。 - 如果
flag
是一个函数,那么return flag
实际上会返回函数的引用,而不是函数的执行结果。如果flag
应该是一个值或字符串,那么你可能需要确保从flag.py
中正确导入。 - 代码中的
print(content)
在生产环境中可能不是最佳实践,因为它会在控制台打印响应内容,这可能会导致敏感信息的泄露。
总之,这段代码是一个简单的 Flask 应用,用于接收一个 URL 作为输入,获取该 URL 的内容,并基于内容中是否包含 “paluctf” 来返回不同的响应。此外,它还提供了一个 /flag
路由,直接返回 “paluctf” 字符串。
访问路由flag:
所以存在一个ssrf
根据源码 随便提交一个url就行 还是要访问flag路由
R23
|
反序列化
明显要绕过__wekeup
最后执行在system
所以:xk–>a–>b
先把链子写出来 这里的类中没有属性 我们自己随便编一下属性就行:
|
O:1:"b":1:{s:1:"c";O:1:"a":1:{s:1:"b";O:2:"xk":0:{}}} |
再绕过一下__wekeup
序列化字符串中表示对象属性个数的值大于真实的属性个数时,会跳过__wakeup()的执行
所以:
O:1:"b":2:{s:1:"c";O:1:"a":1:{s:1:"b";O:2:"xk":0:{}}} |
但是这里:
还有一个绕过:
if(preg_match('/R:2|R:3/',$_GET['pop'])){ |
直接用改属性个数无法绕过 我这里直接没有回显
过滤了R? 没见过
我们需要知道R是怎么来的–>看反序列化的笔记,这里就不赘述了
法1:
根据r与R的来源
这里又禁用了R后的数字2 3
那么我们自然想到让R后面不是2或3就行
问下AI:
class outObject{ |
当然不是对这题来说,放到这题,思路就是我们本来要传的是对象b的序列化字符串,但是如果让b成为另一个类的属性,就会改变R后面的值。由于这里只有三个类,我们不能自己给它加一个类啊,这里我想到了php的原生类,可以直接用的那种,AI说:stdClass:一个空类,没有定义任何方法或属性。于是得到下面的poc:
|
O%3A8%3A%22stdClass%22%3A1%3A%7Bs%3A11%3A%22innerObject%22%3Ba%3A1%3A%7Bi%3A0%3BO%3A1%3A%22b%22%3A3%3A%7Bs%3A1%3A%22c%22%3BO%3A1%3A%22a%22%3A1%3A%7Bs%3A1%3A%22b%22%3BO%3A2%3A%22xk%22%3A0%3A%7B%7D%7Ds%3A1%3A%22b%22%3BR%3A4%3Bs%3A1%3A%22a%22%3Br%3A4%3B%7D%7D%7D |
再cat flag.php 就行
源码中找到flag
法2:
既然不能用改属性个数的方法来绕过 我们就需要一个新方法
利用点为$this->b = $this->a;
所以我们可以引用赋值绕过__wakeup()
注:$b->b = &$b->c;
意味着它们引用相同的内存地址,它们指向相同的值
|
O:1:"b":3:{s:1:"a";O:1:"a":1:{s:1:"b";O:2:"xk":0:{}}s:1:"c";N;s:1:"b";R:4;} |
然后就一样的cat flag.php 在源码中查看就行
法3:
有一个不知道怎么生成的序列化结果是:
O:1:“b”:3:{s:1:“c”;O:1:“a”:1:{s:1:“b”;O:2:“xk”:0:{}}s:1:“b”;R:2;s:1:“a”;r:2;} |
这个记过是一个正常绕过的一个
本来是不能绕过的 因为R:2
但是将这个payload改一下就行:
O:1:“b”:3:{s:1:“c”;O:1:“a”:1:{s:1:“b”;O:2:“xk”:0:{}}s:1:“b”;R:02;s:1:“a”;r:2;} |
将R:2改为R:02就行
宇宙召唤
来自宇宙深处的呼唤 似乎有个声音一直在你脑中重复 不要回复 不要回复 不要回复
又有一个距离你较近的声音重复 宇宙真理 42 42 42
你似乎想与它交流什么 你们的距离似乎很遥远 只能发送1024字节 不要让它失望 为
什么不理解它的爱
介绍中有提到我们只能传小于等于1024kb的文件 随便上传一个文件看看
随便传一个
并且只能上传文件
如果上传非图片文件提示
ok 只能小于1kb 那必然是上传文件拿webshell 但是我们又只能上传1kb 同时还只能
上传 jpg jpep png 三种格式
还是文件头检测
绕过
如果使用传统的绕过 什么截断啊 type 发现都不行
png里面隐藏图片马,绕过检测,后缀是**php.*png**因为电脑文件名不能出现星号,但是后端应该是把文件名当字符串处理,但是放进目录时因为检测到不合法字符就把星号及其后面的字符截断了,从而生成php文件,拿到flag
上传成功
连蚁剑
my love
|
直接给了phpinfo
session反序列化
有路径:
__wakeup绕过一样
pop链:
b->xk
b->a->end
if(preg_match("/N$/",$_GET['test'])){ |
传入的test要以N结尾
而$_SESSION也是以N结尾
因为没有session_star函数,然后看到($this->func)()可以调用session_star函数
然后看到反序列化可以写文件,不能有.
而session文件也没有
所以:
先将session反序列化写进去,然后反序列化调用session_star的同时插入test为$_SESSION,这样就能执行命令了
$$tmp['name']=='your are good!'
这步满足就能执行shell,其中tmp是可控变量,可以利用_SESSION包含session文件
所以主要问题是写入session,需要里面满足name
变量的值是your are good!
session默认是按照php的序列化方式,那么先生成一个base64编码过的session方便写入
|
然后利用file_put_contents写入session,根据phpinfo知道session保存的地址/var/lib/php/session
写入session 这里的链子与前面的R23类似,并且不需要绕过R:2 R:3所以直接写就行了
|
先提交一下pop将session写入
然后构造启用session的链,用session_start函数启用session
|
然后加上test参数和shell进行rce,在请求包里面加上cookie