固件安全性—防止内存损坏和注入攻击
固件安全性—防止內存損壞和注入攻擊
Firmware Security – Preventing memory corruption and injection attacks
構成物聯網(IoT)主干的連接設備存在多個漏洞,可供黑客入侵。為了減輕這些設備中底層固件的威脅,開發人員需要熟悉大量的安全技術。本文引導開發人員了解固件保護的最佳實踐,討論了在固件中防止內存損壞漏洞和注入攻擊的機制。
Firmware Security Best Practices
Covering the following recipes:
·
Preventing memory-corruption vulnerabilities
· Preventing injection attacks
· Securing firmware updates
· Securing sensitive information
· Hardening embedded frameworks
· Securing third-party code and components
介紹以下配方:
防止內存損壞漏洞
防止注入攻擊
保護固件更新
保護敏感信息
加固嵌入式框架
保護第三方代碼和組件
介紹
嵌入式軟件是物聯網的核心,盡管嵌入式應用程序的安全性通常不被認為是嵌入式開發人員和物聯網設備制造商的首要任務。這可能是由于缺乏安全編碼知識或團隊代碼庫之外的其挑戰造成的。開發人員面臨的其挑戰可能包括但不限于原始設計制造商(ODM)供應鏈、有限的內存、較小的堆棧以及將固件更新安全地推送到端點的挑戰。提供開發人員可以在嵌入式固件應用程序中使用的實用最佳實踐指南。根據OWASP的嵌入式應用程序安全項目(https://www.owasp.org/index.php/OWASP_Embedded_Application_Security),嵌入式最佳實踐包括:
· Buffer and stack overflow protection
· Injection attack prevention
· Securing firmware updates
· Securing sensitive information
· Identity management controls
· Embedded framework and C-based toolchain
hardening
· Usage of debugging code and interfaces
· Securing device communications
· Usage of data collection and storage
· Securing third-party code
· Threat modeling
緩沖區和堆棧溢出保護
預防注入攻擊
保護固件更新
保護敏感信息
身份管理控制
嵌入式框架與基于C的工具鏈強化
調試代碼和接口的使用
保護設備通信
數據收集和存儲的使用
保護第三方代碼
威脅建模
將討論前面提到的幾個主要針對POSIX環境定制的最佳實踐,但是這些原則的設計與平臺無關。
防止內存損壞漏洞
在使用諸如C之類的低級語言時,如果開發人員沒有通過編程方式正確檢查和驗證邊界,則很有可能出現內存損壞錯誤。防止使用已知的危險函數和api有助于防止固件中的內存損壞漏洞。例如,已知的、不安全的C函數的非詳盡列表包括:strcat、strcpy、sprintf、scanf和gets。
常見的內存損壞漏洞(如緩沖區溢出或堆溢出)可能由堆棧或堆溢出組成。這些特定的內存損壞漏洞被利用時的影響因操作系統平臺而異。例如,商業RTOS平臺(如QNX Neutrino)將每個進程及其堆棧與文件系統隔離開來,從而使攻擊面最小化。但是,對于常見的嵌入式Linux發行版,情況可能并非如此。嵌入式Linux中的緩沖區溢出可能導致攻擊者任意執行惡意代碼和修改操作系統。在這個表單中,將展示工具如何幫助檢測易受攻擊的C函數,并提供安全控制以及防止內存損壞漏洞的最佳實踐。
將使用以下工具:
Flawfinder: Flawfinder是一個免費的C/C++靜態代碼分析工具,報告潛在的安全漏洞。
How to do it…
通用Linux實用程序有助于通過C/C++代碼文件進行搜索。盡管如此,在防止開發人員可以使用的IDE插件的內存損壞漏洞方面,有一些商用的源代碼分析工具比普通實用工具做得更好。出于演示的目的,將在下面的步驟中演示如何使用grep和fluxfinder在代碼文件中搜索預定義的函數易受攻擊調用和規則列表。
要發現不安全的C函數,可以使用幾種方法。最簡單的形式是使用類似于以下示例的grepexpression:
$ grep -E ‘(strcpy|strcat|sprintf|strlen|memcpy|fopen|gets)’ code.c
可以調整此表達式以使其更智能,或者封裝在腳本中,該腳本可以在每個構建中執行,也可以在特定的基礎上執行。
可以使用免費工具(如fluenfinder)通過調用flawfinder和代碼段的路徑來搜索易受攻擊的函數,如下例所示:
$ flawfinder fuzzgoat.cFlawfinder version 1.31, ? 2001-2014 David A. Wheeler. Number of rules (primarily dangerous function names) in C/C++ ruleset: 169Examining fuzzgoat.c FINAL RESULTS:fuzzgoat.c:1049: [4] (buffer) strcpy:Does not check for buffer overflows when copying to destination (CWE-120).Consider using strcpy_s, strncpy, or strlcpy (warning, strncpy is easily misused). fuzzgoat.c:368: [2] (buffer) memcpy: Does not check for buffer overflows when copying to destination (CWE-120). Make sure destination can always hold the source data. fuzzgoat.c:401: [2] (buffer) sprintf: Does not check for buffer overflows (CWE-120). Use sprintf_s, snprintf, or vsnprintf. Risk is low because the source has a constant maximum length. fuzzgoat.c:1036: [2] (buffer) strcpy: Does not check for buffer overflows when copying to destination (CWE-120). Consider using strcpy_s, strncpy, or strlcpy (warning, strncpy is easily misused). Risk is low because the source is a constant string.fuzzgoat.c:1041: [2] (buffer) sprintf: Does not check for buffer overflows (CWE-120). Use sprintf_s, snprintf, or vsnprintf. Risk is low because the source has a constant maximum length.fuzzgoat.c:1051: [2] (buffer) strcpy: Does not check for buffer overflows when copying to destination (CWE-120). Consider using strcpy_s, strncpy, or strlcpy (warning, strncpy is easily misused). Risk is low because the source is a constant string.ANALYSIS SUMMARY:Hits = 24Lines analyzed = 1082 in approximately 0.02 seconds (59316 lines/second)Physical Source Lines of Code (SLOC) = 765 Hits@level = [0] 0 [1] 0 [2] 23 [3] 0 [4] 1 [5] 0Hits@level+ = [0+] 24 [1+] 24 [2+] 24 [3+] 1 [4+] 1 [5+] 0Hits/KSLOC@level+ = [0+] 31.3725 [1+] 31.3725 [2+] 31.3725 [3+]1.30719 [4+] 1.30719 [5+] 0Minimum risk level = 1Not every hit is necessarily a security vulnerability.There may be other security vulnerabilities; review your code! See ‘Secure Programming for Linux and Unix HOWTO’ (http://www.dwheeler.com/secure-programs) for more information.
在發現正在使用的易受攻擊的C函數時,必須包含安全的替代方法。例如,以下易受攻擊的代碼使用不安全的gets()函數,該函數不檢查緩沖區長度:
#include int main () { char userid[8]; int allow = 0; printf external link("Enter your userID, please: "); gets(userid); if (grantAccess(userid)) { allow = 1; } if (allow != 0) { privilegedAction(); } return 0;}
用戶標識可以使用超過8個的任意數量的字符溢出,例如帶有自定義執行函數的緩沖區溢出漏洞利用(BoF)負載。為了減少緩沖區溢出,可以使用fgets()函數作為一個安全的替代方法。以下示例代碼演示如何安全地使用fgets()并正確分配內存:
#include <stdio.h>#include <stdlib.h>#define LENGTH 8int main () { char* userid, *nlptr; int allow = 0; userid = malloc(LENGTH * sizeof(*userid)); if (!userid) return EXIT_FAILURE; printf external link("Enter your userid, please: "); fgets(userid,LENGTH, stdin); nlptr = strchr(userid, ‘\n’); if (nlptr) *nlptr = ‘\0’; if (grantAccess(userid)) { allow = 1; } if (allow != 0) { priviledgedAction(); } free(userid); return 0;}
同樣的緩解也可以用于其安全的替代函數,如snprintf()、strlcpy()和strlcat()。根據操作系統平臺的不同,一些安全的替代方案可能不可用。執行自己的研究以確定特定架構和平臺的安全替代方案非常重要。英特爾創建了一個名為safestringlib的開源跨平臺庫,以防止使用這些不安全的禁用函數;使用另一個安全替換函數。有關safestringlib的詳細信息,請訪問GitHub頁面:https://github.com/01org/safestringlib。
其內存安全控件可用于防止內存損壞漏洞,例如:
請使用安全編譯器標志,例如-fPIE, -fstack-protector-all, -Wl,-
z,noexecstack, -Wl,-z,noexecheap和其可能取決于特定編譯器版本的代碼。
首選片上系統(SoC)和微控制器(MCU)包含內存管理單元(MMU)。MMU隔離線程和進程,以在內存漏洞被利用時減少攻擊面。
首選系統芯片(SoC)和微控制器(MCU)包含內存保護單元(MPU)。MPU強制內存和獨立進程的訪問規則,以及強制特權規則。
如果沒有可用的MMU或MPU,則使用已知位監視堆棧,通過確定堆棧中有多少不再包含已知位來監視堆棧的消耗量。
使用后要注意緩沖區和空閑緩沖區的位置是什么。
利用地址空間布局隨機化(ASLR)和其堆棧控件攻擊內存漏洞確實需要攻擊者付出大量努力才能利用。不過,在某些情況下還是有可能的。確保代碼具有彈性,并對存儲在內存中的數據采用深度防御的方法,將有助于嵌入式設備的安全態勢。
另請參見
· For further secure memory management guidelines, reference Carnegie Mellon’s Secure CERT C Coding Standard (https://www.securecoding.cert.org/confluence/display/c/SEI+CERT+C+Coding+Standard).
· For further secure memory management guidelines, reference Carnegie Mellon’s Secure CERT C++ Coding Standard (https://www.securecoding.cert.org/confluence/pages/viewpage.action?pageId=637)
Preventing injection attacks
注入攻擊是任何web應用程序的主要漏洞之一,尤其是在物聯網系統中。事實上,自2010年以來,injection一直被評為OWASP前10名的前2名。有許多類型的注入攻擊,如操作系統(OS)命令注入、跨站點腳本(例如,JavaScript注入)、SQL注入、日志注入,以及其類型的注入,如表達式語言注入。在物聯網和嵌入式系統中,最常見的注入攻擊類型是操作系統命令注入;當應用程序接受不可信的用戶輸入并將該值傳遞給執行shell命令時,沒有輸入驗證或正確的轉義和跨站點腳本(XSS)。這個方法將向展示如何通過確保所有不可信的數據和用戶輸入都經過驗證、清理并使用其安全功能來減輕命令注入攻擊。
How to do it…
當物聯網設備運行時,命令注入漏洞不難測試靜態和動態。固件可以調用system()、exec()和類似的變量來執行OS命令,或者調用一個外部腳本,該腳本從解釋語言(如Lua)運行OS調用。命令注入漏洞也可能由緩沖區溢出引起。下面的步驟和示例顯示了易受命令注入攻擊的代碼,以及如何減輕命令注入的影響。之后,將列出常見的安全控制,以防止常見的注入攻擊。
下面的代碼片段調用dangerous system() C函數來刪除home中的.cfg文件。如果攻擊者能夠控制該函數,則可以連接后續的shell命令來執行未經授權的操作。此外,攻擊者還可以操縱環境變量來刪除以.cfg結尾的任何文件:
#include <stdlib.h> void func(void) { system(“rm ~/.cfg”);}
為了減輕前面的易受攻擊的代碼,將使用unlink()函數而不是system()。unlink()函數不易受到符號鏈接和命令注入攻擊的影響。函數的作用是:刪除符號鏈接,不影響由符號鏈接內容命名的文件或目錄。這降低了unlink()函數對symlink攻擊的敏感度,但是不能完全阻止symlink攻擊;如果命名目錄相同,也可以刪除。unlink()函數可以阻止命令注入攻擊,應該使用類似的上下文函數,而不是執行操作系統調用:
#include <pwd.h>#include <unistd.h>#include <string.h>#include <stdlib.h>#include <stdio.h>void func(void) {const char *file_format = “%s/.cfg”;size_t len;char *pathname;struct passwd pwd; pwd = getpwuid(getuid());if (pwd == NULL) { / Handle error */} len = strlen(pwd->pw_dir) + strlen(file_format) + 1;pathname = (char )malloc(len);if (NULL == pathname) { / Handle error /}int r = snprintf(pathname, len, file_format, pwd->pw_dir);if (r < 0 || r >= len) { / Handle error /}if (unlink(pathname) != 0) { / Handle error */} free(pathname);}
還有幾種其方法可以減輕注入攻擊。以下是預防注入攻擊的常見最佳實踐和控制措施的列表:
如果可能,避免直接調用操作系統調用。
如果需要,白名單接受命令并在執行之前驗證輸入值。
對于可能傳遞給操作系統(如{ 1:ping -c 5 })的用戶驅動字符串numbers-to-command-strings,使用數字的查找映射來命令字符串。
在代碼庫上執行靜態代碼分析,并在語言使用操作系統命令時發出警報,例如操作系統().
將所有用戶輸入視為不受信任的,并且輸出對呈現給用戶的數據進行編碼字符。(for example, Convert & to &, Convert < to <,
Convert > to >, and so on.)
對于XSS,使用HTTP響應頭,如X-XSS-Protection and Content- Security-Policy,并配置適當的指令。
確保在生產固件版本上禁用了帶有命令執行的調試接口(例如,http://example.com/command.php).
在生產環境中使用固件之前,前面提到的控件總是需要測試。通過注入攻擊,設備和用戶面臨被攻擊者和胭脂設備接管的風險。
總結
以上是生活随笔為你收集整理的固件安全性—防止内存损坏和注入攻击的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 现代传感器的接口:中断驱动的ADC驱动程
- 下一篇: 提高汽车系统的安全性