Command injection attack là gì?
Command injection là một cuộc tấn công trong đó mục tiêu là thực hiện các lệnh tùy ý trên hệ điều hành chủ thông qua một ứng dụng dễ bị tấn công. Các cuộc tấn công chèn lệnh có thể xảy ra khi một ứng dụng chuyển dữ liệu không an toàn do người dùng cung cấp (biểu mẫu, cookie, tiêu đề HTTP, v.v.) đến trình bao hệ thống. Trong cuộc tấn công này, các lệnh hệ điều hành do kẻ tấn công cung cấp thường được thực thi với các đặc quyền của ứng dụng dễ bị tấn công. Các cuộc tấn công chèn lệnh có thể xảy ra phần lớn do không đủ xác thực đầu vào.
Cuộc tấn công này khác với Code Injection, trong đó việc tiêm mã cho phép kẻ tấn công thêm mã của riêng chúng, sau đó được ứng dụng thực thi. Trong Command Injection, kẻ tấn công mở rộng chức năng mặc định của ứng dụng, thực thi các lệnh hệ thống mà không cần phải chèn mã.
Ví dụ 1
Đoạn mã sau là một trình bao bọc xung quanh lệnh cat UNIX để in nội dung của tệp ra đầu ra tiêu chuẩn. Nó cũng có thể tiêm:
#include <stdio.h> #include <unistd.h> int main(int argc, char **argv) { char cat[] = "cat "; char *command; size_t commandLength; commandLength = strlen(cat) + strlen(argv[1]) + 1; command = (char *) malloc(commandLength); strncpy(command, cat, commandLength); strncat(command, argv[1], (commandLength - strlen(cat)) ); system(command); return (0); }
Được sử dụng bình thường, đầu ra chỉ đơn giản là nội dung của tệp được yêu cầu:
$ ./catWrapper Story.txt
Tuy nhiên, nếu chúng ta thêm dấu chấm phẩy và một lệnh khác vào cuối dòng này, lệnh sẽ được thực thi bởi catWrapper mà không có gì phải phàn nàn:
$ ./catWrapper "Story.txt; ls"
$ ./catWrapper "Story.txt; ls" When last we left our heroes... Story.txt doubFree.c nullpointer.c unstosig.c www* a.out* format.c strlen.c useFree* catWrapper* misnull.c strlength.c useFree.c commandinjection.c nodefault.c trunc.c writeWhatWhere.c
Nếu catWrapper đã được đặt để có mức đặc quyền cao hơn người dùng tiêu chuẩn, các lệnh tùy ý có thể được thực hiện với đặc quyền cao hơn đó.
Ví dụ 2
Chương trình đơn giản sau đây chấp nhận tên tệp làm đối số dòng lệnh và hiển thị nội dung của tệp trở lại người dùng. Chương trình được cài đặt setuid root vì nó được thiết kế để sử dụng như một công cụ học tập cho phép quản trị viên hệ thống đang được đào tạo kiểm tra các tệp hệ thống đặc quyền mà không cho họ khả năng sửa đổi hoặc làm hỏng hệ thống.
int main(char* argc, char** argv) { char cmd[CMD_MAX] = "/usr/bin/cat "; strcat(cmd, argv[1]); system(cmd); }
Bởi vì chương trình chạy với đặc quyền root, cuộc gọi đến system () cũng thực thi với đặc quyền root. Nếu người dùng chỉ định một tên tệp tiêu chuẩn, thì lệnh gọi sẽ hoạt động như mong đợi. Tuy nhiên, nếu kẻ tấn công chuyển một chuỗi có dạng “; rm -rf /”, thì lệnh gọi đến system () không thể thực thi cat do thiếu đối số và sau đó tiếp tục xóa đệ quy nội dung của phân vùng gốc.
Ví dụ 3
Đoạn mã sau từ một chương trình đặc quyền sử dụng biến môi trường $ APPHOME để xác định thư mục cài đặt của ứng dụng, sau đó thực thi một tập lệnh khởi tạo trong thư mục đó.
... char* home=getenv("APPHOME"); char* cmd=(char*)malloc(strlen(home)+strlen(INITCMD)); if (cmd) { strcpy(cmd,home); strcat(cmd,INITCMD); execl(cmd, NULL); } ...
Như trong Ví dụ 2, mã trong ví dụ này cho phép kẻ tấn công thực hiện các lệnh tùy ý với đặc quyền nâng cao của ứng dụng. Trong ví dụ này, kẻ tấn công có thể sửa đổi biến môi trường $ APPHOME để chỉ định một đường dẫn khác chứa phiên bản độc hại của INITCMD. Bởi vì chương trình không xác nhận giá trị đọc từ môi trường, bằng cách kiểm soát biến môi trường, kẻ tấn công có thể đánh lừa ứng dụng chạy mã độc.
Kẻ tấn công đang sử dụng biến môi trường để điều khiển lệnh mà chương trình gọi ra, vì vậy ảnh hưởng của môi trường là rõ ràng trong ví dụ này. Bây giờ chúng ta sẽ chuyển sự chú ý của mình đến những gì có thể xảy ra khi kẻ tấn công thay đổi cách diễn giải lệnh.
Ví dụ 4
Đoạn mã dưới đây là từ một tiện ích CGI dựa trên web cho phép người dùng thay đổi mật khẩu của họ. Quá trình cập nhật mật khẩu theo NIS bao gồm chạy lệnh thực hiện trong thư mục / var / yp. Lưu ý rằng kể từ khi chương trình cập nhật các bản ghi mật khẩu, nó đã được cài đặt gốc setuid.
Chương trình gọi make như sau:
system("cd /var/yp && make &> /dev/null");
Không giống như các ví dụ trước, lệnh trong ví dụ này được mã hóa cứng, vì vậy kẻ tấn công không thể kiểm soát đối số được truyền đến system (). Tuy nhiên, vì chương trình không chỉ định một đường dẫn tuyệt đối cho make và không xóa bất kỳ biến môi trường nào trước khi gọi lệnh, kẻ tấn công có thể sửa đổi biến $ PATH của chúng để trỏ đến một tệp nhị phân độc hại có tên là make và thực thi tập lệnh CGI từ một dấu nhắc shell. Và vì chương trình đã được cài đặt gốc setuid, phiên bản make của kẻ tấn công hiện chạy với đặc quyền root.
Môi trường đóng một vai trò quan trọng trong việc thực hiện các lệnh hệ thống trong các chương trình. Các hàm như system () và execute () sử dụng môi trường của chương trình gọi chúng, và do đó những kẻ tấn công có cơ hội tiềm ẩn để ảnh hưởng đến hành vi của các lệnh gọi này.
Có nhiều trang web sẽ cho bạn biết rằng Java’s Runtime.exec hoàn toàn giống với chức năng hệ thống của C. Đây không phải là sự thật. Cả hai đều cho phép bạn gọi một chương trình / quy trình mới. Tuy nhiên, hàm hệ thống của C chuyển các đối số của nó tới shell (/ bin / sh) để được phân tích cú pháp, trong khi Runtime.exec cố gắng chia chuỗi thành một mảng các từ, sau đó thực thi từ đầu tiên trong mảng với các từ còn lại. dưới dạng các tham số. Runtime.exec KHÔNG cố gắng gọi trình bao tại bất kỳ thời điểm nào. Sự khác biệt chính là
phần lớn chức năng được cung cấp bởi shell có thể được sử dụng cho những trò nghịch ngợm (chuỗi các lệnh sử dụng “&”, “&&”, “|”, “||”, v.v., chuyển hướng đầu vào và đầu ra) sẽ chỉ đơn giản là một tham số được chuyển đến lệnh đầu tiên và có thể gây ra lỗi cú pháp hoặc bị loại bỏ dưới dạng tham số không hợp lệ.
Ví dụ 5
Các đoạn mã nhỏ sau đây dễ bị chèn lệnh OS trên nền tảng Unix / Linux:
#include <stdlib.h> #include <stdio.h> #include <string.h> int main(int argc, char **argv) { char command[256]; if(argc != 2) { printf("Error: Please enter a program to time!\n"); return -1; } memset(&command, 0, sizeof(command)); strcat(command, "time ./"); strcat(command, argv[1]); system(command); return 0; }
Nếu đây là một nhị phân suid, hãy xem xét trường hợp khi kẻ tấn công nhập vào như sau: ls; con mèo / etc / shadow. Trong môi trường Unix, các lệnh shell được phân tách bằng dấu chấm phẩy. Bây giờ chúng ta có thể thực hiện các lệnh hệ thống theo ý muốn!
Java:
Có nhiều trang web sẽ cho bạn biết rằng Java’s Runtime.exec hoàn toàn giống với chức năng hệ thống của C. Đây không phải là sự thật. Cả hai đều cho phép bạn gọi một chương trình / quy trình mới. Tuy nhiên, hàm hệ thống của C chuyển các đối số của nó tới shell (/ bin / sh) để được phân tích cú pháp, trong khi Runtime.exec cố gắng chia chuỗi thành một mảng các từ, sau đó thực thi từ đầu tiên trong mảng với các từ còn lại. dưới dạng các tham số. Runtime.exec KHÔNG cố gắng gọi trình bao tại bất kỳ thời điểm nào. Sự khác biệt chính là phần lớn các chức năng được cung cấp bởi shell có thể được sử dụng cho mục đích nghịch ngợm (chuỗi các lệnh sử dụng &, &&, |, ||, v.v., chuyển hướng đầu vào và đầu ra) sẽ chỉ đơn giản là một tham số được chuyển đến lệnh đầu tiên và có thể gây ra lỗi cú pháp hoặc bị loại bỏ dưới dạng tham số không hợp lệ.
Ví dụ 6
Đoạn mã PHP sau dễ bị tấn công chèn lệnh:
<?php print("Please specify the name of the file to delete"); print("<p>"); $file=$_GET['filename']; system("rm $file"); ?>
Yêu cầu và phản hồi sau đây là một ví dụ về một cuộc tấn công thành công:
Yêu cầu http://127.0.0.1/delete.php?filename=bob.txt;id
Please specify the name of the file to delete uid=33(www-data) gid=33(www-data) groups=33(www-data)
Cách kiểm tra lỗ hổng Command Injection
Bài viết này mô tả cách kiểm tra ứng dụng để đưa lệnh vào hệ điều hành. Người kiểm tra sẽ cố gắng đưa một lệnh hệ điều hành thông qua một yêu cầu HTTP vào ứng dụng.
Các bài viết liên quan:
Chèn lệnh hệ điều hành là một kỹ thuật được sử dụng thông qua giao diện web để thực hiện các lệnh hệ điều hành trên máy chủ web. Người dùng cung cấp các lệnh của hệ điều hành thông qua giao diện web để thực hiện các lệnh của hệ điều hành. Bất kỳ giao diện web nào không được làm sạch đúng cách đều có thể bị khai thác này. Với khả năng thực thi các lệnh hệ điều hành, người dùng có thể tải lên các chương trình độc hại hoặc thậm chí lấy mật khẩu. Việc đưa lệnh vào hệ điều hành có thể ngăn ngừa được khi tính bảo mật được nhấn mạnh trong quá trình thiết kế và phát triển các ứng dụng.
Mục tiêu kiểm tra
Xác định và đánh giá các điểm tiêm lệnh.
Làm thế nào để kiểm tra
Khi xem một tệp trong ứng dụng web, tên tệp thường được hiển thị trong URL. Perl cho phép chuyển dữ liệu từ một quy trình vào một câu lệnh mở. Người dùng có thể chỉ cần thêm ký hiệu Pipe | vào cuối tên tệp.
URL mẫu trước khi thay đổi:
http: //sensitive/cgi-bin/userData.pl? doc = user1.txt
URL mẫu đã được sửa đổi:
http: //sensitive/cgi-bin/userData.pl? doc = / bin / ls |
Thao tác này sẽ thực hiện lệnh / bin / ls.
Thêm dấu chấm phẩy vào cuối URL cho trang .PHP, theo sau là lệnh của hệ điều hành, sẽ thực thi lệnh. % 3B là URL được mã hóa và giải mã thành dấu chấm phẩy
Ví dụ:
http: //sensitive/something.php? dir =% 3Bcat% 20 / etc / passwd
Ví dụ
Hãy xem xét trường hợp của một ứng dụng có chứa một bộ tài liệu mà bạn có thể duyệt từ Internet. Nếu bạn kích hoạt proxy cá nhân (chẳng hạn như ZAP hoặc Burp Suite), bạn có thể nhận được POST HTTP như sau (http://www.example.com/public/doc):
POST /public/doc HTTP/1.1 Host: www.example.com [...] Referer: http://127.0.0.1/WebGoat/attack?Screen=20 Cookie: JSESSIONID=295500AD2AAEEBEDC9DB86E34F24A0A5 Authorization: Basic T2Vbc1Q9Z3V2Tc3e= Content-Type: application/x-www-form-urlencoded Content-length: 33 Doc=Doc1.pdf
Trong yêu cầu đăng bài này, chúng tôi nhận thấy cách ứng dụng truy xuất tài liệu công khai. Bây giờ chúng ta có thể kiểm tra xem có thể thêm lệnh hệ điều hành để đưa vào HTTP POST hay không. Hãy thử những cách sau (http://www.example.com/public/doc):
POST /public/doc HTTP/1.1 Host: www.example.com [...] Referer: http://127.0.0.1/WebGoat/attack?Screen=20 Cookie: JSESSIONID=295500AD2AAEEBEDC9DB86E34F24A0A5 Authorization: Basic T2Vbc1Q9Z3V2Tc3e= Content-Type: application/x-www-form-urlencoded Content-length: 33 Doc=Doc1.pdf+|+Dir c:\
Nếu ứng dụng không xác thực yêu cầu, chúng tôi có thể nhận được kết quả sau:
Exec Results for 'cmd.exe /c type "C:\httpd\public\doc\"Doc=Doc1.pdf+|+Dir c:\' Output... Il volume nell'unità C non ha etichetta. Numero di serie Del volume: 8E3F-4B61 Directory of c:\ 18/10/2006 00:27 2,675 Dir_Prog.txt 18/10/2006 00:28 3,887 Dir_ProgFile.txt 16/11/2006 10:43 Doc 11/11/2006 17:25 Documents and Settings 25/10/2006 03:11 I386 14/11/2006 18:51 h4ck3r 30/09/2005 21:40 25,934 OWASP1.JPG 03/11/2006 18:29 Prog 18/11/2006 11:20 Program Files 16/11/2006 21:12 Software 24/10/2006 18:25 Setup 24/10/2006 23:37 Technologies 18/11/2006 11:14 3 File 32,496 byte 13 Directory 6,921,269,248 byte disponibili Return code: 0
Trong trường hợp này, chúng tôi đã thực hiện thành công một cuộc tấn công đưa vào hệ điều hành.
Các ký tự đặc biệt cho Command Injection
- Ký tự đặc biệt sau có thể được sử dụng để chèn lệnh, chẳng hạn như | ; & $> <‘!
- cmd1 | cmd2: Công dụng của | sẽ làm cho lệnh 2 được thực hiện mặc dù lệnh 1 thực hiện có thành công hay không.
- cmd1; cmd2: Công dụng của; sẽ làm cho lệnh 2 được thực hiện mặc dù lệnh 1 thực hiện có thành công hay không.
- cmd1 || cmd2: Lệnh 2 sẽ chỉ được thực hiện nếu lệnh 1 không thực hiện được.
- cmd1 && cmd2: Lệnh 2 sẽ chỉ được thực thi nếu lệnh 1 thực hiện thành công.
- Ví dụ:
$(cmd)
: For example,echo $(whoami)
or$(touch test.sh; echo 'ls' > test.sh)
- Ví dụ:
- cmd: Nó được sử dụng để thực thi một lệnh cụ thể. Ví dụ, whoami
- >(cmd):> (ls)
- <(cmd): <(ls)
Đánh giá mã API nguy hiểm
Hãy lưu ý việc sử dụng API sau vì nó có thể dẫn đến rủi ro tiêm lệnh.
Java
Runtime.exec()
C/C++
system
exec
ShellExecute
Python
exec
eval
os.system
os.popen
subprocess.popen
subprocess.call
PHP
system
shell_exec
exec
proc_open
eval
Biện pháp khắc phục hậu quả
Vệ sinh
URL và dữ liệu biểu mẫu cần được làm sạch để tìm các ký tự không hợp lệ. Một danh sách từ chối các ký tự là một tùy chọn nhưng có thể khó nghĩ ra tất cả các ký tự để xác nhận chống lại. Ngoài ra, có thể có một số vẫn chưa được phát hiện. Danh sách cho phép chỉ chứa các ký tự hoặc danh sách lệnh phải được tạo để xác thực đầu vào của người dùng. Các nhân vật bị bỏ sót, cũng như các mối đe dọa chưa được phát hiện, nên bị loại bỏ bởi danh sách này.
Danh sách từ chối chung được đưa vào để tiêm lệnh có thể là | ; & $> <‘\! >> #
Thoát hoặc lọc các ký tự đặc biệt cho cửa sổ, () <> & * ‘| =? ; [] ^ ~! . “% @ / \: +,` Thoát hoặc lọc các ký tự đặc biệt cho Linux, {} ()> <& * ‘| =?; [] $ – # ~!.”% / \: +, `
Quyền
Ứng dụng web và các thành phần của nó phải chạy dưới các quyền nghiêm ngặt không cho phép thực thi lệnh của hệ điều hành. Cố gắng xác minh tất cả thông tin này để kiểm tra theo quan điểm kiểm tra hộp xám.