Arduino+Avr libc制作Badusb原理及示例講解


一、 前言

2014年美國黑帽大會上研究人員JakobLell和Karsten Nohl展示了badusb的攻擊方法后,國內與badusb相關的文章雖然有了一些,但是大部分人把相關文章都閱讀后還是會有種“不明覺厲”的感覺,badusb仍有一層朦朧的面紗。經過一段時間的學習和研究后,筆者希望通過自己的一些心得體會可以幫助其他人更清晰地認識badusb,也希望這篇文章能夠起到一定的啟發。這篇文章主要分為五個部分——知識掃盲部分、badusb固件編寫部分、badusb配置界面部分、技術展望部分和總結部分。

二、硬件准備

本文使用的硬件是Arduino Leonardo開發板,但是不難將Leonardo開發板替換為其它Arduino開發板。

三、知識掃盲

1. 雖然USB協議有一定的漏洞,但是不是任何USB設備都能制作badusb的。制作badusb有兩個核心,一個是能夠為USB設備編寫相應的固件,另一個是能夠將編寫的固件燒錄到USB設備中。要編寫相應的固件就需要掌握USB設備中微控制器(或者說芯片)的指令規范文檔(如果Intel不提供開發文檔,那么除了Intel自己沒有人能為Intel處理器編寫程序);而要將固件燒錄到USB設備中,要么使用相應的硬件編程器,要么就需要USB設備本身已經存在的bootloader來輔助進行燒錄工作(bootloader是USB設備廠商在生產時就放在USB設備中的,網上某些優盤的優盤量產工具也是從廠商流出的,而不是第三方編寫的)。要同時滿足兩個核心條件還是比較難的,即便是JakobLell和Karsten Nohl公布的badusb利用代碼也是針對滿足一定條件的優盤,因為流出的優盤量產工具有限(既然有優盤量產工具,可以推測相應的優盤中肯定有bootloader或者類似bootloader的固件存在,那么通過逆向優盤量產工具就可以掌握PC端軟件和特定優盤的通信方式,進而實現自己的燒錄工具)。

2. Arduino 和 teensy這類開發板之所以容易制作badusb,是因為它們采用的微控制器官方有詳細的說明文檔。最常用的是atmel公司的微控制器,atmel官網提供了各種開發文檔和開發相關的庫等。

3. Atmel廠商的微控制器整合了SRAM, FLASH和EEPROM。SRAM就好比電腦的內存,不用關心;FLASH高地址存放的是bootloader,低地址則存放用戶燒錄的固件,芯片加電時直接執行用戶的固件,但是芯片復位時會先執行bootloader(這一點是燒錄的關鍵),再執行用戶的固件;EEPROM則主要用來存放數據,用戶可以隨意修改EEPROM中的數據,固件也可以從EEPROM里讀取數據(本文的固件示例和PC端程序都利用了這一特性)。

4. Avr libc是一個開源項目,針對atmel廠商的各種微控制器開發C語言庫、編譯器、燒錄工具等一系列輔助工具,還有針對Windows平台的WinAvr項目。Arduino ide的核心其實也是avr libc。

5. Arduino的開發板有相應的bootloader(在FLASH高地址)可以和avr libc項目中的avrdude.exe軟件通信,實現固件的燒寫和讀取動作。在Arduino開發板復位時,會加載bootloader,這時候就可以利用avrdude.exe和bootloader通信。復位操作可以通過開發板上的復位按鈕,或者編程實現軟復位操作(如果開發板支持的話)。

6. Intel hex 是一種用於編程器的特殊的文件格式,正是因為這種格式,使得我們可以自由控制數據的存儲地址。Intel hex的文件格式解析可以自行網上搜索。

四、知識獲取途徑

1. USB知識獲取

如果只是為了簡單了解USB設備為什么可以模擬鍵盤、鼠標等其它設備,網上有許多博客是關於USB規范詳解的,也可以簡單地看《USB開發大全》和《USB應用開發實例詳解》前面關於USB通用協議部分,如果不是對硬件感興趣沒必要深究。

2. Arduino、Avr libc知識獲取

這兩樣其實都是開源的,所以只要有足夠的精力和實力,看源代碼深入了解相關知識是沒問題的。但是如果只是想體驗一下制作badusb,可以只看一下Arduino的官方文檔和avrdude.exe的相關文檔,看這些文檔時也沒必要深究每個細節,能一定程度上“照葫蘆畫瓢”就可以了。

五、Badusb固件編寫

這里給的固件示例在執行時會從EEPROM中指定的地址讀取數據,根據讀取的數據和制定的規則發送相應的按鍵響應給PC主機。

#include"Keyboard.h"

#include"EEPROM.h"

 

intmodifier_key = -1;      //modifier_key不為-1說明Win鍵、Ctrl鍵或者Shift鍵按下,這個示例特指Win鍵

intkeycode;                //存放要發送的按鍵代碼

unsignedint delay_time = 0;    //固件執行下條指令時延遲的時間

unsignedint address  = 0;  //從EEPROM讀取數據的地址,這里要和EEPROM存放數據的地址一致

charnum_char[10] = {0};        //某個數字的字符串形式,這個數字用於delay()的參數,也就是作為睡眠的時間

int num= 0;

intindex = 0;

 

//change this to match your platform:

voidsetup() {

  // make pin 2 an input and turn on the

  // pullup resistor so it goes high unless

  // connected to ground:

  pinMode(2, INPUT_PULLUP);

  Keyboard.begin();

  delay(1000);                  //等待一段時間,讓USB設備和PC主機通信完成初始化工作

  while((keycode = EEPROM.read(address++))!= 0){//循環從EEPROM中讀取數據直到讀到數值0(不是數字0),這個值是在向EEPROM中寫入數據時在末尾添加的。

    if (keycode == '$') {            //如果從EEPROM中讀到的數值等於'$'的ASCII碼

      modifier_key = 131;            //將modifier_key的值設為Win鍵的鍵值,這個值會和后續的按鍵組合后發送給PC主機

      continue;

    }

/* 將兩個'&'字符之間的數字作為后續一個按鍵發送后睡眠的時間,這里之所以要有這個控制值是因為種種因素都會影響按鍵按下到某個窗口彈出的時間,如果在窗口未彈出就發送了某個按鍵,這個按鍵就失效了,后續的按鍵組合起來也不完整了。比如在按下Win+R鍵后,還沒等運行對話框彈出,固件就發送了"cmd"按鍵,那么這次啟動cmd肯定就失敗了。 */

    if (keycode == '&') {           

      while ((keycode = EEPROM.read(address++))!= '&') {

        num_char[index++] = keycode;

      }

      sscanf(num_char, "%d",&num);

      delay_time = num;          //將EEPROM中讀取的數據轉換為數值后保存到delay_time,控制下次發送按鍵后睡眠時間

      memset(num_char, 0, sizeof(num_char));//清空num_char為下次轉換做准備

      continue;

    }

    if (keycode == ';') {    //如果從EEPROM中讀取的數值等於';'的ASCII碼,將發送一個回車鍵的按鍵碼

      keycode = 176;     //176等於回車鍵的按鍵碼

    }

     Write(keycode);     //實際發送按鍵的動作

  };

}

//

voidloop() {

  // do nothing:

  while (true);

}

 

voidWrite(int code)

{

  if (modifier_key != -1) {     //在這個例子中,modifier_key不等於-1就等於Win鍵的按鍵碼

    Keyboard.press(modifier_key);    //按下Win鍵,不放

    Keyboard.press(code);            //按下另一個按鍵,不放

    Keyboard.releaseAll();       //同時放開Win鍵和另一個按鍵,發送Win+某個按鍵給PC主機

    modifier_key = -1;

    delay(delay_time);           //這個時間要么等於0,要么等於兩個'&'字符之間指定的值

  } else {

    Keyboard.write(code);            //否則直接按下某個按鍵並放開

    delay(delay_time);           //這個時間要么等於0,要么等於兩個'&'字符之間指定的值

  }

  delay_time = 0;

}

這里針對這個固件給幾個例子幫助理解:

1. 從EEPROM中依次讀取到’$'、’r'($r)表示badusb會按下Win+R鍵。

2. 從EEPROM中依次讀取到’$'、’r'、’;'($r;)表示badusb會按下Win+R,然后按回車鍵。

3. 從EEPROM中依次讀取到’&’、’5′、’0′、’0′、’&’、’$'、’r'、’;'(&500&$r;)表示badusb會按下Win+R鍵,然后等待500毫秒(保證運行對話框彈出),再按下回車鍵。

4. 從EEPROM中依次讀取到(&500&$rpowershell&400&;Get-Date;)表示badusb先按下Win+R鍵,等待500毫秒后輸入powershell,按回車鍵后等待400毫秒,再輸入Get-Date,最后按下回車鍵。

六、Badusb配置界面

所謂的Badusb配置界面,就是avrdude.exe的UI界面精簡版,再額外提供了控制Badusb執行的動作的功能(本質就是修改了EEPROM特定地址的數據,因為固件是根據EEPROM中的數據執行動作的)。

圖1 PC程序界面

這個程序主要就是avrdude.exe的UI界面,只有executable處和address處是為了自定義Badusb動作設計的。partno的選項和programmer的選項是解析選定的avrdude.conf得到的,所以不選擇avrdude.conf的話partno和programmer的下拉框將為空;端口號是通過注冊表獲取到的。

當點擊upload按鈕或者dump按鈕時,先利用編程方式實現復位操作(后面會解釋怎么實現的),在短暫的暫停后使用CreateProcess執行avrdude.exe程序;而如果用戶在executable處輸入了字符串,PC程序會根據用戶輸入的字符串和Address處給定的地址生成intel hex格式的文件(還記得前面知識掃盲部分提到的intel hex格式?熟悉了intel hex的格式后,完全可以自己寫出生成hex文件的代碼,所以這里就不貼出代碼了),再調用avrdude.exe把生成的intel hex文件燒錄到eeprom。下面給個具體的演示。

圖2 燒錄固件並指定Badusb執行動作

Executable處輸入的字符串指示badusb執行的動作,這里badusb先按下Win+R鍵,等待500毫秒后輸入powershell,按下回車鍵,等待600毫秒后輸入Get-Date然后按下回車鍵,再輸入echoabcdefghijklmnopqrstuvwxyz按下回車鍵,最后再次輸入Get-Date和回車鍵。至於界面中其它一些零碎的參數筆者怎么知道的后面會說,實在不行完全可以一個一個嘗試。

效果演示:

視頻沒有演示badusb的危害多大(比如從服務器下載木馬執行、竊取個人信息等),畢竟這些更多的屬於powershell腳本知識、cmd命令之類的,不是這篇文章的目的。

演示視頻中主要經歷了以下幾個階段:

1. 選擇了avrdude.conf文件后partno和programmer下拉框會展示avrdude.exe支持的芯片型號和編程器(編程器本質上是和bootloader通信的協議)。

2. 插上開發板(有提示音)后,port下拉框會展示開發板的串口號。

3. 在executable編輯框中輸入badusb需要執行的按鍵序列”&500&$rcmd”,再選擇要燒錄到FLASH的固件(只需要燒錄一次固件,以后都不需要了),點擊upload后兩次彈出命令窗口進行燒錄(第一次燒錄固件,第二次向EEPROM中寫入數據),發現開發板重啟后彈出了運行對話框並輸入了”cmd”。

4. 修改executable編輯框的內容為”&500&$rcmd;”(多了一個分號,也就是多按了一個回車鍵),再次點擊upload(因為沒有選擇固件,所以不會進行固件的燒錄,只會修改EEPROM的數據),發現開發板重啟后彈出運行對話框緊接着迅速彈出了命令窗口。

5. 之后又修改了兩次executable編輯框的內容並燒錄以修改EEPROM的數據,發現一次是只彈出了powershell窗口,一次是彈出了powershell窗口后又執行了三條powershell指令。

七、技術展望

這次的示例只是展示了利用arduino leonardo開發板模擬usb鍵盤,而windows一旦鎖屏,模擬成鍵盤鼠標之類的badusb就失效了。而有人發現在鎖屏狀態下插入網卡會讓windows操作系統發送dhcp請求給新插入的網卡分配ip,那么是不是可以讓usb設備模擬成網卡兼dhcp服務器兼dns服務器,達到在鎖屏狀態下通過badusb劫持流量、竊取信息的目的?雖然有局限性,但是也說明了一個問題——badusb不只是簡單地利用usb協議的漏洞,還可以結合操作系統的一系列特性(缺陷?)在看似不可能的環境下執行,badusb的技術還有很多可以探索的地方。

八、總結

1. 理一下思路,要制作badusb,就要保證能編寫出相應的固件並能通過某種手段將固件燒錄到usb設備中。要想通過這兩點,最方便的就是使用arduino或者teensy這類開發板,否則就需要看有沒有官方的集成開發環境,比如Cypress官網就提供了詳細的開發文檔、示例、開發環境等。

2. arduino開發板主要使用的是atmel廠商的微控制器,編譯工具和燒錄工具也是來自開源項目avr libc。可以在arduino ide中“文件->首選項->設置”勾上顯示編譯和上傳的詳細輸出,然后使用ide的上傳功能上傳一個示例代碼,在輸出窗口就能看到很多有用的信息。附上一個示例:

圖3 arduino ide詳細輸出信息(a)

3. 看到圖4的輸出信息,應該可以聯想到通過軟件復位開發板其實是通過以1200bps速率和開發板進行串口通信,再進一步去看Windows串口通信時發現還需要設置幾個其他參數,這時候怎么辦呢?只能看arduinoide是怎么設置那些參數的,通過以下幾個步驟尋找到arduino ide設置相關參數的源代碼(arduino ide的源代碼github上有):

①在源代碼根目錄使用findstr /Sn /c:”Foundupload port”查找含有字符串“Found upload port”的文件,發現路徑為arduino-core\src\cc\arduino\packages\uploaders\SerialUploader.java:276:(findstr是Windows提供的在文檔中查找字符串的工具)

②查看Serial Uploader代碼,發現字符串“Found upload port”在waitForUploadPort方法中,進一步發現調用了waitForUploadPort方法的是uploadUsingPreferences方法,在uploadUsingPreferences方法中發現調用了Serial.touchForCDCReset方法,通過方法名字猜測這個函數和開發板復位有關。

③再次使用findstr /Sn /c:”touchForCDCReset”找到touchForCDCReset方法的實現是在文件arduino-core\src\processing\app\Serial.java:90:中。

④在Serial.java中發現有這么一行代碼:

serialPort.setParams(1200,8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);

到這里可以大膽猜測出利用串口通信的方式復位開發板時除了1200這個參數值外其他參數的值了。

圖4 arduino ide詳細輸出信息(b)

4. 通過圖5可以看到arduino ide在調用avrdude.exe燒錄固件到我的開發板時的一系列參數(-p就是partno,-c就是programmer,-b就是baudrate,可以發現和我前面演示時設定的參數是一樣的,因為我的那些參數就是根據這里顯示的設置的)。有興趣的可以看看“Arduino安裝路徑\hardware\arduino\avr”目錄下的boards.txt、platform.txt和programmers.txt,應該會有很多收獲。

5. 想利用arduino開發板制作有用的,或者擴展性強的badusb,需要理清以下邏輯:

①arduino開發板使用的主要是atmel廠商的微控制器,而atmel廠商的微控制器集成了SRAM,FlASH和EEPROM,其中arduino開發板中的FLASH高地址存放了某種bootloader,低地址則存放用戶上傳到開發板的固件;arduino開發板的EERPOM可以根據自己的情況使用。

②arduino開發板復位時,先啟動bootloader,一段時間(通常是幾秒)后啟動用戶的固件。而avrdude.exe燒錄過程其實就是在復位時和arduino開發板的bootloader通信,所以只有在bootloader啟動階段利用avrdude.exe才能成功燒錄。一定要把握好時間。

③固件程序可以從eeprom或flash中讀取數據,而intelhex格式文件可以控制將數據寫入特定存儲器的特定地址,利用這一點可以極大的擴展badusb的功能,而且將要執行的指令放在flash或者eeprom中也能在一定程度上起到隱藏效果。

Arduino+Avr libc制作badusb效果展示:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM