freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

初识Host注入及Burp插件开发
2021-08-09 23:11:35

初识Http Host:

http版本从开始的1.0到1.1以及以后的1.2经历三个版本, 在Http请求头中,Host头指定请求资源的Intenet主机和端口号。在1.1中host标头的主要功能将客户端请求分发到内部具体的域名中,当然如果存在nginx反向代理或负载均衡等情况下当流量到达服务器之前可能会更改host的值。

通常来说一台服务器会有多个web应用程序,当我们配置基于端口的虚拟主机,不同的web程序可以通过不同的端口来判断。但当我们配置基于域名的虚拟主机时,一个IP地址可以对应多个域名,比如有几个不同的域名:a.com、b.com、c.com,这几个域名通过A记录或者CNAME记录最终和虚拟主机IP相关联,当我们访问这几个域名最终会解析到同一个IP,但是服务端该如何区分不同域名以返回不同的内容呢?这时就可以通过Host字段区分出客户端具体访问的站点是哪一个,web服务器使用该头部的值来将请求分派到指定的网站或web应用程序之上。

Host被解析的大致流程如下:

客户端 --》请求 --》URL --》解析IP地址 --》服务器 --》解析Host值 --》转发具体域名

漏洞成因:

由于HTTP的Host头可以由用户所控制,如果服务器充分信任客户端所提交的数据,web应用程序仅通过Http的Host字段进行解读或者支持X-Forwarded-Host、X-Host等标头,就可能会产生一些安全风险,包括SSRF、XSS、未授权访问、缓存污染和密码重置等等。很多应用直接把Host值不做html编码便输出到了页面中,比如:

<link href=http://_SERVER["HTTP_HOST"]></link>    //触发一个get请求
<form method=”POST”></form>                       //触发POST请求

当Host字段被修改为攻击者构造的恶意地址,这时,就会触发恶意请求。

安全风险:

1.密码重置:

在很多实际场景中,为了获取网站的域名并拼接令牌作为重置密码的链接,获取正确的域名并不是一件很容易的事情, 而用一个固定的URI来作为域名可能会导致其他问题。

一种普遍的用来实现密码重置功能的方法是:生成一个密钥令牌,并且发送一封包含着该令牌的超级链接的电子邮件。程序员会采用request.getHeader("Host")或者$_SERVER['HTTP_HOST']的方式来获取域名。假设存在这样一个场景,当攻击者请求一个带有恶意Domain的Host头类型的密码重置,web应用程序使用攻击者所伪造的Host头来生成重置链接并发送给受害者,如果受害者点开了邮件中“带毒”的重置链接,那么攻击者将能获得密码重置的令牌,进而可以重置受害者的密码了。攻击者通过一个受他控制的链接来污染密码重置的邮件。

举个例子:
存在这样一个情景:访问目标网站xxx.com的忘记密码功能,在其中输入用户名信息请求获得重置密码链接:http://xxx.com/user/reset_password
攻击者从中修改Host字段或者添加X-Forwarded-Host字段的值未攻击者可控的一台主机地址,比如X-Forwarded-Host:evil.com,打开邮箱后发现重置链接为:https://evil.com/user/reset_password/xc456132xDzwE1FjX8RtIUc1DTcm1B5Kqb53j1fLEkzMW2GPgCpuEODDStpRaES,当用户去点击链接时,攻击者就可通过web服务器日志信息获取令牌,从而实现目标账户劫持。

2.XSS:

有些网站会根据HOST字段来进行加载css样式表。当域名发生改变时,站内所有的css即将失效。

另外,由于系统没有对 HTTP 头进行任何的特殊符号以及敏感字符串的过滤,攻击者可以利用此漏洞往 Web 页面里插入恶意 HTML 代码,当用户浏览该页之时,嵌入其中 Web 里面的 HTML 代码会被执行,从而达到恶意攻击用户的特殊目的,例如网络钓鱼攻击。

3.Web缓存投毒:

先简单介绍下web缓存的概念:通过减少延迟来加速页面加载,降低应用程序服务器上的负载。每当缓存服务收到对资源的请求时,它需要确定它是否已经保存了这个指定资源的副本,并且可以使用该副本进行响应,或者是否需要将请求转发给应用程序服务器。

Web缓存投毒的目的是发送导致有害响应的请求,将该响应将保存在缓存服务中并提供给其他用户。一般的缓存服务器都会识别hsot,所以一般直接替换host字段会被拦截,我们可以通过寻找由非缓存键导致的差异化响应,但是缓存的响应也有可能会掩盖住非缓存键的输入,因此我们需要去进行手动检测或发现非缓存键的输入,另外在输入非缓存键的同时可以配合XSS等辅助漏洞进一步造成危害。

另外,当web服务器的中间件为Nginx时,它只看最后一个请求,从而我们可以绕过缓存服务器的检查,形如:

GET / HTTP/1.1
Host: test.com
Host: vuln.com

感兴趣的师傅可以去阅读下面两篇文章:

实战web缓存中毒

浅谈http中的Cache-Control

4.补充:

当Host头部被修改为无效Host头时,大多数web服务器配置为将无法识别的Host头传送给列表中的第一台虚拟主机或者返回错误信息。因此,这使得把携带有任意Host头的请求发送到第一台虚拟主机上是可能的。
如果Apache接收到一个带有非法host header的请求,它会将此请求转发给在 httpd.conf 里定义的第一个虚拟主机。因此,Apache很有可能将带有任意host header的请求转发给应用

burp被动检测插件设计思路:

1.利用Burp的CollaboratorClient,使用generatePayload方法生成了一个dnslog的地址

2.监听响应包,过滤掉状态码为403和404的数据包

3.获取请求头部,将Host字段替换为第一步生成的dnslog地址

4.构造请求包并发送,获取其响应包的请求头部、body和状态码

5.当状态码为301或者302时,判断第一步生成的dnslog地址是否在响应包的Location

6.判断第一步生成的dnslog地址是否在响应包的body部分

7.利用fetchCollaboratorInteractionsFor()方法判断是否有接收到dns或者http请求

IBurpExtender接口类是Burp插件的入口,所有Burp的插件均需要实现此接口,并且类命名为 BurpExtender。

class BurpExtender(IBurpExtender, IScannerCheck, IBurpCollaboratorClientContext):
    # registerExtenderCallbacks 方法在插件被加载后会被调用,在所有扩展插件中必须实现这个接口
    def registerExtenderCallbacks(self, callbacks):
        # Required for easier debugging:
        sys.stdout = callbacks.getStdout()

        # keep a reference to our callbacks object (Burp Extensibility Feature)
        self._callbacks = callbacks

        # 用于获取IExtensionHelpers对象,扩展可以使用该对象执行许多有用的任务。返回:包含许多帮助器方法的对象,用于构建和分析HTTP请求等任务。
        self._helpers = callbacks.getHelpers()

        # 设置当前扩展的显示名称
        callbacks.setExtensionName('Host Scan')

        # 利用Burp的CollaboratorClient,使用generatePayload方法生成了一个dnslog的地址
        self.collaboratorContext = callbacks.createBurpCollaboratorClientContext()
        self.payload = self.collaboratorContext.generatePayload(True)
        print str(self.payload)

        # 注册扫描
        callbacks.registerScannerCheck(self)
# 获取请求头部
self.baseRequestResponse = baseRequestResponse
request = self.baseRequestResponse.getRequest()
analyzedRequest = self._helpers.analyzeRequest(request)
request_header = analyzedRequest.getHeaders()
# 构造请求并发送,对响应包的头部和body进行匹配
newMessage = self._helpers.buildHttpMessage(new_req_header, request_bodys)
newIHttpRequestResponse = self._callbacks.makeHttpRequest(httpService, newMessage)
newResponse = newIHttpRequestResponse.getResponse()
newResponseInfo = self._helpers.analyzeResponse(newResponse)
newResponseBody = newResponse[newResponseInfo.getBodyOffset():].tostring()
newResponseStatus = newResponseInfo.getStatusCode()
newResponseHeader = newResponseInfo.getHeaders()
match_result = re.search(r'(http|https)(://|%3A%2F%2F)' + str(self.payload).strip(), newResponseBody)
if str(newResponseStatus) in ['301', '302'] and str(self.payload).strip() in str(newResponseHeader):
    issues.append(CustomScanIssue(
        newIHttpRequestResponse.getHttpService(),
        self._helpers.analyzeRequest(newIHttpRequestResponse).getUrl(),
        [newIHttpRequestResponse],
        "Host injection in Header!",
        "Found Fake Host In Header",
        "Medium"))
match_result = re.search(r'(http|https)(://|%3A%2F%2F)' + str(self.payload).strip(), newResponseBody)
if match_result:
    issues.append(CustomScanIssue(
        newIHttpRequestResponse.getHttpService(),
        self._helpers.analyzeRequest(newIHttpRequestResponse).getUrl(),
        [newIHttpRequestResponse],
        "Host injection in Body!",
        "Found Fake Host In Body",
        "Medium"))
    # return issues
if self.collaboratorContext.fetchCollaboratorInteractionsFor(self.payload):
    issues.append(CustomScanIssue(
        newIHttpRequestResponse.getHttpService(),
        self._helpers.analyzeRequest(newIHttpRequestResponse).getUrl(),
        [newIHttpRequestResponse],
        "Host injection!",
        "Found HTTP Request/DNS Query!",
        "High"))
return issues

最终实现效果如下,当发现生成的dnslog地址出现在响应包头或者body中时:

当发现服务端主动发送dns或者http请求到dnslog时(SSRF):

另外还可以在请求头中添加X-Forwarded-Host、X-Host等标头进一步进行测试。

防范建议:

不要信任host头,只要是能被客户端修改的值,都是不可信任的。

当必须使用host头作为一种识别web服务器位置的机制的话,在web框架中以白名单方式验证,只允许在白名单中的域

在后端配置文件中结合业务情况禁用绝对路径的url,采用相对路径如/test/1.php

如必须绝对路径,应手动添加绝对路径并指定域名如https://xxxx.com/test/1.php,在配置文件中引用此值,而不是host值

禁用不需要的标头如XFH,XH等,一些中间件默认可能支持XFH标头

参考如下:

http host头攻击风险分析

重新认识被人遗忘的HTTP头注入

技术干货 | Web漏洞:Host头部攻击

在密码重置请求包中添加X-Forwarded-Host实现受害者账户完全劫持

# 渗透测试 # web安全
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录