Bài 59.428 phút đọc
Checklist bảo mật và fuzzing
Sau bài này bạn sẽ làm được
- Chạy qua checklist mười hai mục cho một dự án
- Viết một bộ fuzz bằng libFuzzer hoặc AFL
- Xóa dữ liệu nhạy cảm đúng cách
- Biết MISRA C và CERT C dùng cho việc gì
Bài cuối của phần này, và của cả khoá, là một danh sách. Mười hai mục bạn chạy qua trước khi coi một chương trình C là sẵn sàng, cộng với cách để máy tự tìm những lỗ hổng mà bạn không nghĩ ra.
#Checklist mười hai mục
| # | Mục | Bắt bằng gì | Bài |
|---|---|---|---|
| 1 | Mọi hàm chuỗi có giới hạn: không strcpy, strcat, sprintf, gets | grep, -Wformat | 59.1 |
| 2 | Mọi phép tính kích thước kiểm tra tràn trước khi cấp phát | UBSan, xem lại tay | 59.2 |
| 3 | Mọi độ dài dùng size_t, kiểm tra cả hai cận | -Wconversion | 59.2 |
| 4 | Đối số định dạng của printf luôn là hằng chuỗi | -Wformat-security | 59.2 |
| 5 | Không system hay popen với dữ liệu ngoài | grep | 59.3 |
| 6 | Đường dẫn được chuẩn hoá và kiểm tra tiền tố | xem lại tay | 59.3 |
| 7 | Thao tác tệp nguyên tử: O_EXCL, O_NOFOLLOW, hàm theo fd | grep access | 59.3 |
| 8 | Mọi giá trị trả về có thể lỗi đều được kiểm tra | clang-tidy, cert-err33 | 56.4 |
| 9 | Mọi nhánh lỗi dọn dẹp đúng, không rò rỉ | ASan, Valgrind | 58.3 |
| 10 | Chạy sạch dưới ASan và UBSan | sanitizer | 58.3 |
| 11 | Dữ liệu nhạy cảm được xoá đúng cách | xem lại tay | mục dưới |
| 12 | Đã fuzz các bộ phân tích và điểm vào dữ liệu ngoài | libFuzzer, AFL | mục dưới |
#Fuzzing
Fuzzing
Kỹ thuật đưa hàng triệu đầu vào tự sinh, phần lớn là rác có cấu trúc, vào chương trình để tìm đầu vào làm nó sập, treo, hoặc kích hoạt sanitizer. Fuzzer hiện đại dùng độ phủ để dẫn hướng, nên nó tự học cách đi sâu vào mã.
phan_tich.c, một bộ phân tích có lỗi
#include <stdint.h>
#include <stddef.h>
#include <string.h>
/* Khung: [1 byte loai][1 byte do dai][du lieu]. Tra ve 0 hoac -1. */
int phan_tich(const uint8_t *du_lieu, size_t co) {
if (co < 2) return -1;
uint8_t loai = du_lieu[0];
uint8_t do_dai = du_lieu[1];
(void)loai;
char bo_dem[16];
/* LOI: khong kiem tra do_dai so voi 16 hay so voi co */
memcpy(bo_dem, du_lieu + 2, do_dai);
return bo_dem[0];
}terminal
# Mo phong bang cach dua tay mot dau vao doc hai
./fuzz.exe
dau vao thuong (do_dai=3): tra ve 97 dau vao doc hai (do_dai=200): sap goi... Segmentation fault
echo $?
139
#Viết một harness
fuzz_phan_tich.c, harness cho libFuzzer
#include <stdint.h>
#include <stddef.h>
int phan_tich(const uint8_t *du_lieu, size_t co);
/* libFuzzer goi ham nay HANG TRIEU lan voi du_lieu tu sinh. */
int LLVMFuzzerTestOneInput(const uint8_t *du_lieu, size_t co) {
phan_tich(du_lieu, co);
return 0; /* luon tra ve 0 */
}terminal
# Dich voi libFuzzer VA sanitizer, chi Clang co san libFuzzer
clang -g -O1 -fsanitize=fuzzer,address,undefined phan_tich.c fuzz_phan_tich.c -o fuzz
# Chay: no tu sinh dau vao va dung khi tim thay loi
./fuzz
INFO: Running with entropic power schedule (0xFF, 100).
INFO: seed corpus: 0 files
#2 INITED
#131072 pulse cov: 6 ...
==12345==ERROR: AddressSanitizer: stack-buffer-overflow
WRITE of size 200 at 0x7ffc... thread T0
#0 memcpy
#1 phan_tich phan_tich.c:14
SUMMARY: AddressSanitizer: stack-buffer-overflow phan_tich.c:14
artifact_prefix='./'; ... Test unit written to ./crash-a1b2c3# Chay lai DUNG dau vao gay sap de go loi
./fuzz ./crash-a1b2c3
AFL++, cách khác không cần đổi mã
# AFL doc dau vao tu STDIN hoac tu mot tep, nen chuong trinh cua
# ban giu nguyen main() binh thuong. Chi can dich lai bang trinh
# bao boc cua AFL de no chen do do phu:
afl-clang-fast -g -fsanitize=address phan_tich.c chinh.c -o ct
# Tao thu muc hat giong va thu muc ket qua:
mkdir hat_giong ket_qua
printf '\x01\x03abc' > hat_giong/hop_le
# Chay:
afl-fuzz -i hat_giong -o ket_qua -- ./ct @@
# @@ duoc thay bang ten tep dau vao ma AFL sinh ra
# Man hinh AFL cho thay: so lan chay/giay, so duong da kham pha,
# so lan sap tim duoc. Cac dau vao gay sap nam trong
# ket_qua/crashes/, chay lai duoc de go loi.
# So sanh:
# libFuzzer trong tien trinh, nhanh nhat, can viet harness
# AFL++ ngoai tien trinh, khong can doi ma, ben hon
# voi chuong trinh phuc tap#Xoá dữ liệu nhạy cảm
xoa2.c, memset bị tối ưu xoá mất
/* Ham cong khai, nhan mat khau, dung roi xoa. */
void xu_ly(char *mat_khau_ra) {
char tam[32];
strncpy(tam, mat_khau_ra, sizeof tam - 1);
tam[sizeof tam - 1] = 0;
for (size_t i = 0; i < sizeof tam; ++i)
mat_khau_ra[i] = tam[i] ^ 0x5A; /* gia su bam */
memset(tam, 0, sizeof tam); /* xoa dau vet */
}terminal
# -O2: dem so lenh memset trong ham xu_ly
gcc -std=c11 -O2 -S xoa2.c -o - | sed -n '/^xu_ly:/,/ret/p' | grep -c memset
0
xoa3.c, xoá an toàn bằng con trỏ volatile
/* Xoa an toan: khong bi toi uu, vi con tro volatile. */
void xoa_an_toan(void *p, size_t n) {
volatile unsigned char *v = (volatile unsigned char *)p;
while (n--) *v++ = 0;
}
void xu_ly(char *mk) {
char tam[32];
strncpy(tam, mk, sizeof tam - 1);
tam[sizeof tam - 1] = 0;
for (size_t i = 0; i < sizeof tam; ++i) mk[i] = tam[i] ^ 0x5A;
xoa_an_toan(tam, sizeof tam); /* KHONG bi toi uu */
}terminal
gcc -std=c11 -O2 -S xoa3.c -o - | sed -n '/^xoa_an_toan:/,/ret/p' | grep -c 'movb.*0\|mov.*(%'
1
#MISRA C và CERT C
| MISRA C | CERT C | |
|---|---|---|
| Của ai | MIRA, ngành ô tô Anh | Đại học Carnegie Mellon, SEI |
| Mục đích | An toàn tính mạng: xe, máy bay, thiết bị y tế | An ninh: chống lỗ hổng khai thác được |
| Cách tiếp cận | Cấm các cấu trúc rủi ro, kể cả khi dùng đúng | Quy tắc để tránh lỗ hổng cụ thể |
| Ví dụ quy tắc | Cấm cấp phát động, cấm goto, cấm đệ quy | Kiểm tra tràn, không dùng dữ liệu ngoài làm định dạng |
| Số quy tắc | Khoảng 150 hướng dẫn và quy tắc | Khoảng 100 quy tắc, có ví dụ tuân thủ và vi phạm |
| Kiểm được tự động | Một phần, cần công cụ thương mại | Phần lớn, clang-tidy có nhóm cert-* |
| Bắt buộc khi nào | Hợp đồng ô tô, hàng không, y tế | Tự nguyện, hoặc yêu cầu của khách hàng |
Tự làm thử
- Chạy qua checklist mười hai mục cho một dự án của bạn và ghi lại mục nào chưa đạt.
- Viết một harness libFuzzer cho một bộ phân tích của bạn và chạy nó trên Linux mười phút.
- Chứng minh trên máy bạn rằng
memsetđể xoá mật khẩu bị tối ưu xoá ở-O2. - Cài macro
XOA_AN_TOANđa nền tảng và xác nhận nó sống sót qua-O2. - Chạy
clang-tidy --checks='cert-*'trên dự án và đọc từng cảnh báo. - Chọn ba quy tắc MISRA và quyết định dự án của bạn có nên theo chúng không, kèm lý do.
Trình chấm điểm tự động sẽ được bổ sung ở giai đoạn sau. Hiện tại bạn tự chạy thử trên máy.
Tóm tắt
- Mười trong mười hai mục checklist đã được tự động hoá bằng quy trình năm tầng; chỉ xoá dữ liệu nhạy cảm và fuzzing là làm riêng.
- Fuzzing thử hàng triệu đầu vào dẫn hướng bằng độ phủ, và mạnh nhất cho bộ phân tích dữ liệu ngoài.
- Harness phải nhanh, không trạng thái, và luôn dịch kèm sanitizer.
memsetđể xoá bí mật bị trình biên dịch tối ưu xoá; dùng con trỏvolatilehoặc hàm xoá an toàn có sẵn.- CERT C là cách gọi tên có hệ thống cho kỷ luật bạn đã học; MISRA C khắt khe hơn, cho hệ thống an toàn tính mạng.