原创 | JavaWeb中常见的信息泄漏—Hystrix面板

  • A+
所属分类:安全文章
原创 | JavaWeb中常见的信息泄漏—Hystrix面板
点击上方“蓝字”关注我们了解更多精彩








关于Hystrix




在微服务的应用场景中,通常会有很多层的服务调用。应用程序有数十个依赖关系,每个依赖关系在某些时候不可避免的会出现问题(例如调用响应时间过长或不可用)。


如果一个底层服务出现问题,由于服务与服务之间的依赖性,故障会被向上传播给用户。那么就需要一种机制,当底层服务不可用时,可以阻断故障的传播。

在SpringCloud中提供这个机制的组件就是断路器Hystrix。大致的工作流程如下图:


原创 | JavaWeb中常见的信息泄漏—Hystrix面板


在微服务架构下,通常会有多个层次的服务调用。上图是微服架构下, 浏览器端通过API访问后台微服务的一个示意图,服务B因为某些原因失败,变得不可用,所有对服务B的调用都会超时。

当对B的调用失败达到一个特定的阀值(5秒之内发生20次失败是Hystrix定义的缺省值), 链路就会被处于open状态,之后所有所有对服务B的调用都不会被执行,取而代之的是由断路器提供的一个表示链路open的Fallback消息。

Hystrix提供了相应机制,可以让开发者定义这个Fallbak消息。Fallback可以是另一个由Hystrix保护的服务调用,也可以是固定的值。Fallback也可以设计成链式调用,先执行某些逻辑,再返回Fallback。

简单来说类似电闸,当电路中出现过载时就会断电保证安全。Hystrix可以检测到服务的可用性,但是不够直观。使用HystrixDashboard会提供一个监控平台,方便查看服务的可用性。


原创 | JavaWeb中常见的信息泄漏—Hystrix面板





具体实现




Dashboard是一个统一的断路器监控平台,一般会新建一个项目,引入相关依赖:

<dependency>  <groupId>org.springframework.cloud</groupId>  <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId></dependency>

然后用@EnableHystrixDashboard注解Spingboot启动类,开启hystrixDashboard:
@SpringBootApplication@EnableHystrixDashboardpublic class EurekaHystrixMonitorApplication {   public static void main(String[] args) {     SpringApplication.run(EurekaHystrixMonitorApplication.class, args);   } }


启动项目后访问/hystrix即可访问Hystrix Dashboard:


原创 | JavaWeb中常见的信息泄漏—Hystrix面板


Hystrix Dashboard共支持三种不同的监控方式:
1.默认的集群监控:通过URL:
turbine-hostname:port/turbine.stream开启,实现对默认集群的监控。
2.指定的集群监控:通过URL:
turbine-hostname:port/turbine.stream?cluster=[clusterName]开启,实现对clusterName集群的监控。
3.单体应用的监控:通过URL
/hystrix-app:port/hystrix.stream开启,实现对具体某个服务实例的监控。(从springboot2开始,actuator都是要在请求路径加上/actuator,也就是hystrix-app:port/actuator/hystrix.stream)。




利用思路




不考虑Hystrix的底层实现以及数据生成,HystrixDashboard实际上是通过一系列的js解析实现的。首先是可以通过监控面板去查看一些敏感信息的,再者可以进行ssrf的利用:

可以通过相关接口配置监控:


/hystrix/monitor?stream=/proxy.stream?origin=


填入被监控的服务地址(这里是dnslog地址),填写title,点击Monitor Stream进行监控:

原创 | JavaWeb中常见的信息泄漏—Hystrix面板


可以看到成功在dnslog接收到相关请求:

原创 | JavaWeb中常见的信息泄漏—Hystrix面板


简单查看下相关的源代码,点击MonitorStream按钮后触发的是如下的js function:


原创 | JavaWeb中常见的信息泄漏—Hystrix面板


获取用户输入的内容#stream后进行相关的URI编码,然后通过location.href进行跳转,跳转到/hystrix/monitor页面。查看相关源代码,这里重新对用户的输入stream进行了组装,将其作为/proxy.stream接口的origin参数的值,也就是说,访问/hystrix/monitor?stream=接口实际上最终调度的是/proxy.stream?origin=接口

原创 | JavaWeb中常见的信息泄漏—Hystrix面板


在一系列的非空判断后,使用EventSource对象来实现服务器的推送:


原创 | JavaWeb中常见的信息泄漏—Hystrix面板


因为在使用EventSource对象实现服务器推送时,服务器端响应的类型为 text/event-stream 类型,那么也就是说正常访问/proxy.stream?origin=结果应该返回如下:

原创 | JavaWeb中常见的信息泄漏—Hystrix面板


proxy.stream接口其实是一个简单的servlet实现,origin参数就是前面我们输入的dnslog地址,相关的web.xml配置:

<servlet-mapping>  <servlet-name>ProxyStreamServlet</servlet-name>  <url-pattern>/proxy.stream</url-pattern></servlet-mapping>

查看相关的Java代码:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        String origin = request.getParameter("origin");        String authorization = request.getParameter("authorization");        if (origin == null) {            response.setStatus(500);            response.getWriter().println("Required parameter 'origin' missing. Example: 107.20.175.135:7001");            return;        }        origin = origin.trim();
HttpGet httpget = null; InputStream is = null; boolean hasFirstParameter = false; StringBuilder url = new StringBuilder(); if (!origin.startsWith("http")) { url.append("http://"); } url.append(origin); if (origin.contains("?")) { hasFirstParameter = true; } @SuppressWarnings("unchecked") Map<String, String[]> params = request.getParameterMap(); for (String key : params.keySet()) { if (!key.equals("origin") && !key.equals("authorization")) { String[] values = params.get(key); String value = values[0].trim(); if (hasFirstParameter) { url.append("&"); } else { url.append("?"); hasFirstParameter = true; } url.append(key).append("=").append(value); } } String proxyUrl = url.toString(); logger.info("nnProxy opening connection to: {}nn", proxyUrl); try { httpget = new HttpGet(proxyUrl); if (authorization != null) { httpget.addHeader("Authorization", authorization); } HttpClient client = ProxyConnectionManager.httpClient; HttpResponse httpResponse = client.execute(httpget); int statusCode = httpResponse.getStatusLine().getStatusCode(); if (statusCode == HttpStatus.SC_OK) {......


简单的对origin进行校验,例如不允许为空,且仅允许http/https协议等,最后EventSource根据HttpClient发起的请求返回的内容进行渲染,完成监控页面的展示。

因为整个过程是通过HttpClient发起HTTP请求的,同时也缺少进一步的安全限制。也就是说可以简单的进行ssrf攻击,但没有相应的返回,为blindssrf。例如尝试监控本地不存在的端口1234,返回Unable to connect to Command Metric Stream:

原创 | JavaWeb中常见的信息泄漏—Hystrix面板


尝试监控存在的端口9999,会返回相关的监控面板:


原创 | JavaWeb中常见的信息泄漏—Hystrix面板


这里就可以简单的利用ssrf枚举出当前localhost的端口开放情况了。那么也就是说在满足Hystrix面板自身监控任务的同时,类似访问控制等安全措施就显得十分必要了。




参考资料



https://projects.spring.io/spring-cloud/spring-cloud.html#_circuit_breaker_hystrix_dashboard

原创 | JavaWeb中常见的信息泄漏—Hystrix面板
原创 | JavaWeb中常见的信息泄漏—Hystrix面板
原创 | JavaWeb中常见的信息泄漏—Hystrix面板

原创 | JavaWeb中常见的信息泄漏—Hystrix面板
点分享
原创 | JavaWeb中常见的信息泄漏—Hystrix面板
点点赞
原创 | JavaWeb中常见的信息泄漏—Hystrix面板
点在看

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: