0x01 前言

最近Tenable 披露了Arcadyna 网络设备身份验证绕过漏洞,并且很多的厂商都采用产生漏洞的组件,由于Arcadyan 设备固件厂商并没有开源出来,在官网支持里面下载的文件是window和linux 下和设备连接的客户端软件,无法对漏洞点开展分析,这里我们使用同样受影响的华硕产品DSL-AC3100 的固件来进行设备分析。并且复现在网络设备中网络检测ping 功能的远程命令执行漏洞,从而开启设备telentd。

0x02 华硕DSL-AC3100 固件

我们从华硕的官网中下载固件。
设备名称: DSL-AC3100
固件版本: DSL-AC3100_v1.10.05_build503

0x03 身份验证绕过漏洞分析

提取固件包

从华硕的官网下载到固件包DSL-AC3100_v1.10.05_build503.w ,这是一个是用.w 为后缀的固件文件,使用binwalk 可以提取出来。根据漏洞信息,可以确定这是一个在http服务中存在的漏洞,可以确定到httpd 文件,本固件的httpd 文件在 /usr/sbin/httpd 中。

httpd 二进制文件分析

在ghidra 导入httpd 文件,自动对文件进行分析,识别文件的各种函数。

由于漏洞是身份认证绕过漏洞,因此首先要确定设备的身份验证相关的函数有哪些,在ghidra对httpd文件中的字符串进行搜寻,根据字符串 “check_auth” ,定位到函数 FUN_0001d0c0(),

undefined4 FUN_0001d0c0(int iParm1){int iVar1;undefined4 uVar2;int iVar3;undefined4 local_52c;undefined4 local_528;undefined4 local_524;undefined4 uStack1312;undefined4 local_51c;char acStack1304 [1024];char acStack280 [260];memset(acStack280,0,0x100);memset(acStack1304,0,0x400);local_52c = 0;local_528 = 0;local_524 = 0;uStack1312 = 0;local_51c = 0;iVar1 = FUN_00017df0();if (iVar1 == -1) {uVar2 = 1;}else {iVar3 = mapi_ccfg_match_str(iVar1,"ARC_SYS_LogEnable",&DAT_00046b48);iVar1 = mapi_ccfg_match_str(iVar1,"ARC_SYS_MPTEST",&DAT_00046b48);if (iVar1 == 0) {if (iVar3 != 0) {iVar3 = 1;}if (iVar3 != 0) {FUN_00017738(iParm1 + 0x76f0,&local_52c);}if (*(int *)(iParm1 + 0x774c) == 0) {uVar2 = FUN_0001b6f4(iParm1 + 0x771e,*(undefined4 *)(iParm1 + 0x76ec));FUN_0001b8c8(iParm1,uVar2);}iVar1 = FUN_0001ce8c(*(undefined4 *)(iParm1 + 0x774c),*(undefined4 *)(iParm1 + 0x76b0),*(undefined4 *)(iParm1 + 0x76b4),*(undefined4 *)(iParm1 + 0x76b8),*(undefined4 *)(iParm1 + 0x76bc),*(undefined4 *)(iParm1 + 0x76c0),*(undefined4 *)(iParm1 + 0x76c4),*(undefined4 *)(iParm1 + 0x76c8),*(undefined4 *)(iParm1 + 0x7b34));if (iVar1 == 1) {printf("[%s] %s login time out, reauth\n","check_auth",iParm1 + 0x76f0);FUN_00039088(1);snprintf(acStack1304,0x400,"Location: /relogin.htm\n\n");}else {if (iVar1 == 2) {printf("[%s] new user %s(%s) comes to login, check user and auth\n","check_auth",iParm1 + 0x76f0,iParm1 + 0x4c);snprintf(acStack1304,0x400,"Location: /relogin.htm\n\n");}else {if (iVar1 == 0) {printf("[%s] %s has already granted, pass\n","check_auth",iParm1 + 0x76f0);return 0;}}}if (iVar3 != 0) {snprintf(acStack280,0x100,"User from %s(%s) authentication fail.",&local_52c,iParm1 +0x76f0);append_to_file("/tmp/security_log.txt",acStack280);}FUN_00015338(iParm1,acStack1304);uVar2 = 1;}else {uVar2 = 0;}}return uVar2;
}

根据函数代码的一些细节,可以看出这个函数检查认认证是否符合的功能函数,其中FUN_0001ce8c 函数的返回值iVar1,在函数中 iVar1 的值为2 时,说明是新用户登录,需要检查用户名和验证。iVar1 的值为 0 的时候,则显示验证通过。iVar1 的值为 1 的时候,则表示说明验证超时,并且重新返回到登录界面。

接下来,查看FUN_0001d0c0() 函数在FUN_0001d578() 中被引用。而FUN_0001d0c0() 函数就是漏洞的evaluate_access() 函数。

// evaluate_access()
undefined4 FUN_0001d578(undefined4 uParm1,undefined4 uParm2,int iParm3){int iVar1;undefined4 uVar2;if (iParm3 == 0) {return 0;}iVar1 = FUN_0001d2e0(iParm3);if (iVar1 != 0) {if (*(int *)(iParm3 + 0x76a8) != 0) {return 0;}uVar2 = FUN_0001d0c0(iParm3); return uVar2;}FUN_00014510(iParm3,0x193,"Unauthorized.");return 1;
}

FUN_0001d578() 函数中的 FUN_0001d2e0() 是使用正则表达式来校验URL中的IP,端口是否符合规范。以及FUN_0001d0c0() 函数也在其中,因此这个函数是httpd 中来做身份验证的函数,也就是漏洞分析中的evaluate_access()。

接下来我们来查看调用evaluate_access() 函数的地方,真正的漏洞点在这个函数,我们来看漏洞点是如何绕过身份验证的。我们来到了FUN_00015058函数,这就是process_request 的函数。

void FUN_00015058(int iParm1){undefined4 uVar1;char *pcVar2;char *__src;int iVar3;char *__dest;iVar3 = iParm1 + 0xd5;uVar1 = FUN_00016a84(iVar3,0xd);*(undefined4 *)(iParm1 + 0x27f0) = uVar1;*(undefined4 *)(iParm1 + 0x76a4) = 0xffffffff;*(undefined4 *)(iParm1 + 0x76ac) = 0xffffffff;__src = (char *)FUN_00016a84(iVar3,0x20);*(int *)(iParm1 + 0x7b18) = iVar3;pcVar2 = (char *)FUN_00016a84(__src,0x20);uVar1 = FUN_00016a84(__src,0x3f);*(undefined4 *)(iParm1 + 0x7b14) = uVar1;__dest = (char *)(iParm1 + 0x7994);strncpy(__dest,__src,0xff);*(undefined *)(iParm1 + 0x7a93) = 0;FUN_00016e3c(__dest);printf("[%s] url=[%s], args=[%s], method=[%s]\n","process_request",__dest,*(undefined4 *)(iParm1 + 0x7b14),*(undefined4 *)(iParm1 + 0x7b18));iVar3 = FUN_00018c70(iParm1);if (iVar3 < 0) {return;}if (*pcVar2 == '\0') {*(undefined4 *)(iParm1 + 0x7988) = 1;}else {*(undefined4 *)(iParm1 + 0x7988) = 0;iVar3 = FUN_00018cb8(iParm1);if (iVar3 < 0) {return;}iVar3 = strncasecmp(*(char **)(iParm1 + 0x7620),"multipart/form-data",0x13);if ((((iVar3 != 0) && (*(char **)(iParm1 + 0x7b24) != (char *)0x0)) &&(__src = strcasestr(*(char **)(iParm1 + 0x7b24),"FirmwareUpload"), __src == (char *)0x0))&&(0 < (int)(*(int *)(iParm1 + 0x7984) + (uint)(64000 < *(uint *)(iParm1 + 0x7980))))) {FUN_0000bef4(iParm1,*(undefined4 *)(iParm1 + 0xc));FUN_00014510(iParm1,0x193,"The Content-length is extreme large!");return;}}uVar1 = FUN_0000deb0(__dest);*(undefined4 *)(iParm1 + 0x76a8) = uVar1;// evaluate_access()if (((*(code **)(PTR_PTR_DAT_00054fac + 0x14) == (code *)0x0) ||(iVar3 = (**(code **)(PTR_PTR_DAT_00054fac + 0x14))(iParm1), iVar3 != 2)) &&((*(int *)(iParm1 + 0x76a8) != 0 || (iVar3 = FUN_0001d578(__dest,0,iParm1), iVar3 == 0)))) {*(undefined4 *)(iParm1 + 0x798c) = 0;__src = *(char **)(iParm1 + 0x7b18);iVar3 = strcmp(__src,"HEAD");if (iVar3 == 0) {*(undefined4 *)(iParm1 + 0x798c) = 1;if (*(int *)(iParm1 + 0x7988) == 0) {FUN_0000eb98(iParm1);}else {*(undefined4 *)(iParm1 + 0x798c) = 0;FUN_00014510(iParm1,400,"Invalid HTTP/0.9 method.");}}else {iVar3 = strcmp(__src,"GET");if (iVar3 == 0) {FUN_0000eb98(iParm1);}else {iVar3 = strcmp(__src,"POST");if (iVar3 == 0) {FUN_00014c30(iParm1);}else {FUN_00014510(iParm1,400,"Invalid or unsupported method.");}}}}return;
}

&& : 逻辑与,前后条件同时满足表达式为真;

|| : 逻辑与,前后条件只要有一个满足表达式为真。

如下面的代码,因为逻辑运算符&& 的优先级大于 || ,因此会先计算 && 的值。所以要先判断 iParm1 + 0x76a8 的值。如果值不为0 ,则接着执行 逻辑运算符的|| 的表达式。

((((code )(PTR_PTR_DAT_00054fac + 0x14) == (code )0x0) ||
(iVar3 = ((code )(PTR_PTR_DAT_00054fac + 0x14))(iParm1), iVar3 != 2)) &&
(((int )(iParm1 + 0x76a8) != 0 || (iVar3 = FUN_0001d578(__dest,0,iParm1), iVar3 == 0))))

根据 FUN_00015058() 函数的代码,可以看到 iParm1 + 0x76a8 的值是从 FUN_0000deb0(__dest) 获取到的,而 “_dest” 的值在前面可以看出来是用户请求的 URL。

如果 iParm1 + 0x76a8 不为0 ,那么就能跳过身份验证的函数evaluate_access(),来直接执行处理POST请求的FUN_00014c30函数。

接下来进入 FUN_0000deb0() 函数,来查看是怎么处理 URL

undefined4 FUN_0000deb0(char *pcParm1){size_t __n;int iVar1;char *__s;undefined **ppuVar2;ppuVar2 = &PTR_s_/images/_00054f70;__s = PTR_s_/images/_00054f70;if (PTR_s_/images/_00054f70 == (undefined *)0x0) {return 0;}do {__n = strlen(__s);iVar1 = strncasecmp(pcParm1,__s,__n);if (iVar1 == 0) {return 1;}ppuVar2 = ppuVar2 + 1;__s = *ppuVar2;} while (*ppuVar2 != (char *)0x0);return 0;
}

函数会将 url 和 &PTRs/images/00054f70 字符串进行比较,直到符合为止,而 &PTR_s/images/_00054f70 的值是 “/images/” ,所以只需要请求的URL中带有 “/images/” 字符串,就可以绕过身份认证函数访问其他页面。

前面已经分析出来了身份验证绕过的漏洞点,但是并不能绕过验证访问任意界面,因为在访问的时候,需要正确的httoken值。接下来我们来分析设备的httoken 是怎么获取和生成的,在这个设备里,httoken 是设备的token值,并且访问设备的页面需要带有给定的httoken 值。根据漏洞披露来看,httoken 是在服务端进行生成,然后前端js 中进行解密,最终向服务器请求的时候,将httoken加入到请求数据中,但是漏洞披露并没有说明httoken 是那一段字符串生成的。。

我在httpd 的逆向工程中找到了生成httoken 的函数,

undefined4 FUN_00022520(int iParm1){int iVar1;undefined4 uVar2;undefined *puVar3;size_t sVar4;char cStack120;undefined auStack119 [107];memset(&cStack120,0,0x65);iVar1 = FUN_00017df0();if (iVar1 == -1) {uVar2 = 0;}else {puVar3 = (undefined *)(iParm1 + 0x7994);if (puVar3 == (undefined *)0x0) {puVar3 = &DAT_0003d274;}uVar2 = FUN_000393e0(puVar3);sprintf(&cStack120,"%lu",uVar2);sVar4 = strlen(&cStack120);FUN_00017e78(&cStack120,sVar4,auStack119 + sVar4,100 - sVar4);uVar2 = so_printf(iParm1,"<img title=spacersrc=\"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7%s\" border=0>",auStack119 + sVar4);}return uVar2;

接下来我们来分析FUN_00022520函数。在函数中我们可以看到最终生成了一个img 标签,并且src 的值是一段“data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7 + auStack119 + sVar4 ”字符串,而其中 auStack119 + sVar4 的值是从FUN_00017e78 函数中进行base64 以及其他的方式进行处理后的字符串,并且这段字符串就是httoken的值。

生成的img 标签会在设备的login.html 中html 代码中出现,如下图所示,

根据生成httoken函数拼接这段字符串的方式,使用脚本对把token 解密出来,可以确定如下图的“372646849” 为设备的 token。

ArcBase.decode(“image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7MTU2OTQzNDE0OA==”)
根据解密出来的信息,“;” 后面的字符串 “ 372646849” 就是设备解密后的httoken 值。

0x04 ping 命令注入+配置选项

这一部分,漏洞披露的相对来说比较详细,很多的网络设备中在ping网络诊断 这个功能中,出现过大量的历史漏洞,比如NetGear,D-Link等都出现过此类漏洞,因此关于ping 这一步部分命令拼接就不展开来讲述,但是本漏洞的不同点在于使用设备内部的配置选项ARC_TELNETD_ENABLE 来开启设备的telentd,这一点可以在以后的漏洞挖掘中遇到无法执行命令的时候,提供了不同的执行命令的方式。
我们来重点的关注一下ARC_TELNETD_ENABLE 这个配置。在文件 /sbin/arc_telnetd 文件中可以看到文件内容。文件可以获取ARC_TELNETD_ENABLE的值,当ARC_TELNETD_ENABLE的值为1的时候,设备会开启telnetd。

漏洞复现

0x05 总结

这个身份验证绕过漏洞产生的根本原因在于对请求的URL 验证不严格,本来”/image”是用来用户请求前端静态资源时,默认不需要通过验证,最终导致通过“/image/” 绕过登录。

另外在前一阵子的披露的NetGear DGN2200v1 设备中同样存在通过前端静态资源的路径,来绕过身份验证。并且我在其他的一款网络设备的固件中发现类似的问题。

【2021最新整理网络安全\渗透测试/安全学习(全套视频、大厂面经、精品手册。必备工具包)戳我拿】

身份验证绕过漏洞分析相关推荐

  1. 【CVE-2020-1957】shiro搭配spring时身份验证绕过漏洞分析

    0x00 漏洞简介 https://www.openwall.com/lists/oss-security/2020/03/23/2 0x01 漏洞分析 翻查官方commit,在commit http ...

  2. struts2漏洞监测_Apache Shiro身份验证绕过漏洞风险提示

    漏洞公告 2020年8月17日,安恒应急响应中心监测发现Apache Shiro官方更新发布了1.6.0之前版本存在身份验证绕过的漏洞公告,对应CVE编号:CVE-2020-13933,相关链接: h ...

  3. 【高危】Apache Linkis Gateway模块存在身份验证绕过漏洞(CVE-2023-27987)

    漏洞描述 Apache Linkis 是一个用于将上层应用与底层数据引擎解耦,提供标准化接口的中间件.Gateway 是 Linkis 接受客户端和外部请求的主要入口点, 在 Apache Linki ...

  4. 98.网络安全渗透测试—[常规漏洞挖掘与利用篇14]—[SESSION身份验证绕过漏洞与测试]

    我认为,无论是学习安全还是从事安全的人,多多少少都有些许的情怀和使命感!!! 文章目录 一.session身份验证绕过漏洞与测试 1.session机制 2.session的生命周期 3.出现漏洞的情 ...

  5. 黑客利用数百万路由器的新身份验证绕过漏洞

    身份不明的黑客正在积极利用关键的身份验证绕过漏洞劫持家庭路由器,将它们纳入用于执行 DDoS 攻击的 Mirai 变体僵尸网络,仅在其公开披露两天后. 该漏洞被跟踪为CVE-2021-20090(CV ...

  6. Zyxel-NBG2105(CVE-2021-3297)身份验证绕过漏洞复现

    简介 Zyxel-NBG2105 存在身份验证绕过,可以通过更改 login参数可用实现以管理员身份进行后台登陆. zoomeye 漏洞验证 通过右键源代码查看一下源码,这里不知道为什么不能右键,就在 ...

  7. CVE-2022-40684 Fortinet(飞塔)身份验证绕过漏洞

    GitHub地址: https://github.com/hughink/CVE-2022-40684 漏洞简介 Fortinet(飞塔)是一家全球知名的网络安全产品和安全解决方案提供商,其产品包括防 ...

  8. 【认证绕过】NACOS身份认证绕过漏洞分析

    前言 工作中遇到一个nacos服务认证绕过的问题,在此总结一下漏洞原因. 一.nacos简介 官方文档描述: Nacos 致力于帮助您发现.配置和管理微服务.Nacos 提供了一组简单易用的特性集,帮 ...

  9. Apache Shiro 身份认证绕过漏洞(CVE-2022-32532)漏洞复现

    Apache Shiro 身份认证绕过漏洞(CVE-2022-32532)漏洞复现 0x01 漏洞简介 Apache Shiro 是一个强大且易用的 Java 安全框架,通过它可以执行身份验证.授权. ...

最新文章

  1. 【树莓派】【转载】基于树莓派,制作家庭媒体中心+下载机
  2. 八种 WebSocket 框架的性能比较
  3. 【springboot】模板路径、静态资源路径、WebRoot的本地路径
  4. TCP/IP详解--TIME_WAIT状态存在的原因
  5. date js 半年_moment.js 搜索栏获取最近一周,一个月,三个月,半年,一年时间
  6. 2怎么开机_MacBook如何取消开盖自动开机
  7. Linux puppet的安装配置部署
  8. arduino的矩阵示例程序_用树莓派 Arduino 制造 LED 矩阵彩灯
  9. 高德地图打包后不能使用,高德导航View不显示,高德地图导航组件黑屏的问题;
  10. [HDU - 3709] Balanced Number (数位dp)
  11. 假设检验、显著性水平α、P值、置信区间
  12. INVALID_PARAMETER 订单信息无法识别,建议联系卖家。 支付宝
  13. java微信分享朋友圈_Java实现微信公众平台朋友圈分享功能详细代码
  14. 爬取去哪儿酒店信息及评论
  15. 订阅号如何获取用户openid
  16. 公众号图文消息加html,微信公众号图文排版,如何给文章或者段落添加背景图?...
  17. 爬取2017年底最新中国全国五级行政区划代码省市区县乡镇村MySQL数据库
  18. could not load library cudnn_ops_infer64_8.dll. Error code 126
  19. Qt开发:Qt Widgets模块——简介
  20. 华为2020手机鸿蒙计划,华为鸿蒙 OS 2020 计划曝光!手机仍然优先用安卓

热门文章

  1. iptables指南删减版
  2. JAVA项目:后台管理页面——显示数据库中所有信息+删除和编辑(MySQL)
  3. Slax本地化:U盘上的Linux中文套件
  4. java将中文转为拼音
  5. 狂神SpringMvc笔记
  6. 健康大讲堂—凡膳皆药 寓医于食
  7. Linux GDB分析死锁
  8. UI自动化偷懒必备:AirTest封装好ADB命令
  9. 绘图计算机配置,专业设计制图需要什么样的电脑?制图电脑配置要求 (全文)
  10. Windows系统中 Xmanager 6 企业版下载安装激活教程