美文网首页工具介绍Web攻防
Host注入小结及BP插件开发

Host注入小结及BP插件开发

作者: book4yi | 来源:发表于2021-08-23 09:16 被阅读0次

本文首发于Freebuf,写得比较水了,没能骗到金币或者稿费:
初识Host注入及Burp插件开发 - FreeBuf网络安全行业门户

前言:


毕业工作以后,学习效率明显比之前在校低了一大截,然后工作以后人也胖了一圈,生活总是这样吗

初识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

  • 补充:

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

防范建议:


  • 不要信任host头,只要是能被客户端修改的值,都是不可信任的。
  • 当必须使用host头作为一种识别web服务器位置的机制的话,在web框架中以白名单方式验证,只允许在白名单中的域
  • 在后端配置文件中结合业务情况禁用绝对路径的url,采用相对路径如/test/1.php
  • 如必须绝对路径,应手动添加绝对路径并指定域名如https://xxxx.com/test/1.php,在配置文件中引用此值,而不是host值
  • 禁用不需要的标头如XFH,XH等,一些中间件默认可能支持XFH标头

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等标头进一步进行测试。

参考如下:


http host头攻击风险分析
重新认识被人遗忘的HTTP头注入
技术干货 | Web漏洞:Host头部攻击
在密码重置请求包中添加X-Forwarded-Host实现受害者账户完全劫持

相关文章

网友评论

    本文标题:Host注入小结及BP插件开发

    本文链接:https://www.haomeiwen.com/subject/gcsvvltx.html