当前位置: 首页 > 科技观察

对两个D-Link路由器身份验证绕过漏洞的分析

时间:2023-03-16 22:20:38 科技观察

D-Link路由器的两个认证绕过漏洞分析这些漏洞影响D-LinkDIR-882、DIR-878和DIR-867路由器。这些漏洞存在于HNAP协议的处理过程中。https://supportannouncement.us.dlink.com/announcement/publication.aspx?name=SAP10157我们先研究CVE-2020-8863,熟悉HNAP的认证方案。之后我们再分析写着“后门”二字的怪人CVE-2020-8864。0x01什么是HNAPHNAP,即家庭网络管理协议,是一种基于SOAP的专有协议,由PureNetworks,Inc.发明,后来被Cisco收购。该协议可追溯到2007年,可被视为UPnP的直接竞争对手。该协议的主要用户是Cisco和D-Link。然而,两者分别在2012年和2016年停止使用该协议。此功能通常隐藏在管理面板中,因此无法禁用。如果您的路由器仍然支持HNAP,则可能意味着您的路由器需要升级。作为一个过时的专有协议,网上的相关文档很少。HNAP提供两种认证方案:Basic和HMAC-based。我能找到的关于基于HMAC的身份验证方案的最佳文档来自反向项目的Githubwiki页面。0x02HNAP认证过程服务器(路由器)的认证需要两次事务。首先,客户端发送请求消息并从服务器获取身份验证质询。requestadmin服务器用三个值响应请求:Challenge、Cookie和PublicKeyOKrEmNZG3LUDFUSMJHU55PuidpiK0+vq1w3gFhoIAlc38rEVLO0客户端必须首先将PublicKey和用户密码结合起来创建一个PrivateKey。请注意这一点,因为它稍后会变得很重要。然后客户端将使用新生成的PrivateKey和Challenge来生成新的值。客户端将这个值放在消息的LoginPassword字段中,登录作为对服务器发出的质询的响应:loginadmin.。服务器可以使用记录的用户帐户密码独立计算PrivateKey和LoginPassword来计算质询。预期响应并将其与LoginPassword客户端提供的密码进行比较,从而对客户端进行身份验证。如果值匹配,则客户端已成功验证自己。0x03CVE-2020-8864此身份验证绕过漏洞是由于不当使用strncmp()将服务器计算值LoginPassword与LoginPassword客户端提供的值进行比较造成的。下面是易受攻击函数的控制流图:查看全图图1-CVE-2020-8864易受攻击函数的控制流图从本质上讲,控制流图的上述部分描述了以下常见的易受攻击的代码模式:strncmp(db_password,attacker_provided_pa??ssword,strlen(attacker_provided_pa??ssword));当attacker_provided_pa??ssword为空字符串时,strlen()返回0。然后,由于调用strncmp()时使用的长度参数为0,因此它根本不比较任何字符。相反,返回值0,表示相等。在CVE-2020-8864中,如果攻击者提供一个空的LoginPassword值,strncmp()将返回0并遵循成功验证的代码路径。0x04CVE-2020-8863漏洞标题为:D-LinkMultipleRoutersHNAPPrivateLoginAuthenticationAlgorithmIncorrectImplementationAuthenticationBypassVulnerability“PrivateLogin”这个词比较有意思。我们来看看路由器是如何处理HNAP登录请求的,看看这个PrivateLogin后门是如何用几行代码实现的。通过HNAP认证时,服务器通常会根据用户的密码生成一个PrivateKey。但是,当攻击者请求AdminUsername时,以下是Ghidra对生成研究人员提供的身份验证质询值的函数的反编译器输出:char*验证码;char*PrivateLogin;size_tsize;undefined4uVar2;undefined*Uid;char*__nptr;intlocal_1a8;charChallenge[64];undefinedUuid[64];charPublickey[64];charPassword[64];charPrivateKey[132];memset(挑战,0,0x40);memset(Uuid,0,0x40);memset(公钥,0,0x40);memset(密码,0,0x40);uVar2=0x80;memset(PrivateKey,0,0x80);iVar1=FUN_00421a44(param_1);if(iVar1==0){webGetVarString(param_1,"/Login/Action",uVar2,param_4);Username=(char*)webGetVarString(param_1,"/Login/Username",uVar2,param_4);webGetVarString(param_1,"/Login/LoginPassword",uVar2,param_4);Captcha=(char*)webGetVarString(param_1,"/Login/Captcha",uVar2,param_4);PrivateLogin=(char*)webGetVarString(param_1,"/Login/PrivateLogin",uVar2,param_4);//获取PrivateLoginelement__nptr=(char*)nvram_safe_get("CAPTCHA");iVar1=atoi(__nptr);if((iVar1!=0)||(*Captcha!='')){local_1a8=0;while((local_1a8