博客 / 詳情

返回

Redis之父學生時代發現的ping漏洞的源碼分析

Redis 的作者 Salvatore Sanfilippo(網名 antirez)在意大利西西里島長大,雖然從小就接觸計算機,也有一些編程經驗,但在大學期間卻選擇了建築學院,可能當時並沒有打算走職業程序員的道路吧。

然而 antirez 應該就屬於老天爺賞飯的那類人,據説僅僅因為錯把顯卡買成了網卡,商家又不肯退貨,他就放下游戲,拿起了 C 語言的教材。不久之後,antirez 發現了一個 ping 的漏洞,非 root 用户也可以執行 flood ping。這是怎麼回事呢?

ping 命令普通的工作方式是間隔 1 秒就發送 1 個 ping 數據包,而這種週期性是藉助系統的定時器所產生的 SIGALRM 信號實現的。超時時間為 1 秒的定時器一到期,就會產生 SIGALRM 信號,進而觸發 ping 數據包的發送。

既然只要收到 SIGALRM 信號就會發送 ping 數據包,那如果繞過定時器,大量偽造這種信號呢?antirez 發現 ping 根本不校驗這個信號是否真的是因定時器到期(超時)而發出的。於是,antirez 利用一些編程技巧,不需要 root 權限就可以瘋狂產生 SIGALRM 信號,間接達到了 flood ping 的效果。

1998 年 5 月,21 歲的 antirez 將這一發現發佈到一個專注於計算機安全漏洞披露的公共郵件列表上,並很快得到了網絡安全公司 SECLAB 的垂青,一通來自米蘭的長途電話邀請他前往 SECLAB 工作。

下面簡單分析一下學生時代(21 歲)的 antirez 在 https://seclists.org/bugtraq/1998/May/139 上提交的代碼,看看他是如何利用 ping 的漏洞,繞過了“只有 root 賬户才能執行 flood ping”的限制,讓普通用户賬户也能一刻不停瘋狂地向目標主機發送 ICMP 報文。

#include <signal.h>
#define PING "/bin/ping"

main( int argc, char *argv[] )
{
  int pid_ping;

  // ...
  
  if(!(pid_ping = fork())) // ①
    execl(PING, "ping", argv[1], NULL); // ②

  if ( pid_ping <=0 ) {
    // 處理 fork() 的錯誤
  }

  sleep (1);  /* give it a second to start going  */
  while (1) // ③
    if ( kill(pid_ping, SIGALRM) ) // ④
      // 處理 kill() 的錯誤
}

首先,調用 fork() 系統調用創建一個子進程①。如果子進程創建成功,那麼在父進程中,變量 pid_ping 中存放的是子進程的進程 id(大於 0);而在子進程中,pid_ping 的值為 0。

pid_ping == 0 時,即在子進程中,if 的條件 (!pid_ping) 成立。此時通過調用 execl() 讓子進程執行 ping 命令②,向通過參數 argv[1] 指定的目標主機發送 ICMP 報文,就像直接在命令行中執行ping <hostname> 一樣。

ping 命令向目標主機發送 ICMP Echo Request 報文 是通過定時器和 SIGALRM 信號驅動的。ping 只要收到 SIGALRM 信號就會發送一個 ICMP Echo Request 報文,發送完後隨即通過 alarm(1) 設定定時器在 1 秒後重新產生 SIGALRM 信號,從而能夠繼續收到該信號,繼續發送下一個 ICMP 報文。直到用户按下 Ctrl + C 退出程序或已發送了指定數量的 ICMP 報文。

這套機制看似能夠每間隔 1 秒就發送 1 個 ICMP Echo Request 報文,但 antirez 敏鋭地發現了其中的漏洞。既然 ping 只要收到 SIGALRM 信號就會發送 ICMP 報文,那要是偽造大量這種信號呢?ping 會不會根本不校驗這個信號是否真的是因定時器到期(超時)而發出的?於是,antirez 在父進程中寫了個死循環③,瘋狂地調用 kill() 向子進程(進程 id 存放在 pid_ping 中)發送 SIGALRM 信號④。最終達到了不需要 root 權限就可以瘋狂產生 SIGALRM 信號,間接實現 flood ping 的效果。

以上便是21 歲還在念書的 antirez 的發現。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.