# Zip Symlink attack

Một người anh từng nói với em Khánh là: “Đừng simp cái 1 cái gì quá ngoại trừ symlink”. vậy thì symlink là gì mà lại có được ngoại lệ đấy??

# I. Symlink là gì?

Chắc anh em nào đọc blog này cũng từng có một thời cầm usb mà cứ ngỡ được cầm cả bầu trời, hí hửng copy game về nhà nhưng ai mà ngờ đc nó chỉ là 1 cái shortcut không hơn không kém. Vậy lý do là gì?

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728664603280/cf36c18a-551b-4185-80c9-36196a6731a9.png align="center")

Shortcut thực chất là một `symbolic link` , nó liên kết tới 1 tệp gốc, ở đây shortcut `war3.exe` được liên kết tới `D:\Games\Warrcraft PTR\war3.exe` . Nếu chúng ta khởi động `war3.exe` thì Windows sẽ tìm tới tệp gốc được liên kết và khởi động.

Khi copy shortcut từ quán net vào máy của mình, Windows sẽ cố gắng tìm tệp gốc và khởi động nó; tuy nhiên không hề có điều này lý giải cho việc không thể khởi động game khi chỉ copy shortcut về máy.

Note: từ giờ mình sẽ gọi luôn tên của symbolic link là symlink nhé 🤣

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728665057053/bed83f84-ae60-4bcd-92b3-76768935cc17.png align="center")

Ở ảnh phía trên mình đã tạo 1 symlink tên `symlink_to_test.txt` để trỏ tới `/home/kali/test` . Có thể nhận thấy khi đọc và sửa tệp symlink, tệp gốc sẽ bị thay đổi (Nếu có quyền nhé). Đây là 1 cơ chế khá hay để mình tận dụng vào case study này.

Tuy nhiên khi xóa 1 symlink thì không hề ảnh hưởng đến sự tồn vong của tệp gốc nhé.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728665365211/0a788676-27ff-4bb4-bc41-bfbf9be8a329.gif align="center")

# **II. Symlink Attack**

Cùng đặt ra giả thuyết nào?

Vậy điều gì khi chúng ta upload 1 symlink lên trang web ?  
Liệu có phải chúng ta upload `sym.html` link tới `/etc/passwd`, sau đó truy cập `http://server/sym.html` là sẽ đọc được `/etc/passwd` đúng chứ?

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728738365814/df6d250a-187b-4f34-b581-2b79d1037011.png align="center")

Câu trả lời là không phải, Khi upload 1 symlink, browser sẽ cố gắng đọc file gốc(nếu có quyền) và gửi nội dung của file đó lên server. Và lúc này nội dung của file `sym.html` sẽ là nội dung `/etc/passwd` của attacker. Điều này chẳng giúp ích được gì 😒

Sự thực thì khi muốn vận chuyển 1 symlink, nó phải được bọc bên trong zip file hoặc thông qua github(cái này mình mới nghe nói, chưa kiểm nghiệm).

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728665926072/a792d28e-3db0-4173-bb1c-59f72b87b876.png align="center")

Cách tấn công Symlink

Bước 1: chúng ta sẽ nén file symlink `link_to_html` link tới `/var/www/html` sau đó upload lên server. Khi server giải nén file `link_to_html` ra, nó sẽ tìm tới file `/var/www/html` trên server. =&gt; chúng ta có thể dẫn tới việc đọc file trên server

Bước 2: tạo 1 folder `link_to_html` với file `shell.php` , nén nó lại rồi upload. Khi server giải nén folder `link_to_html`, nó sẽ cố gắng tạo folder `link_to_html` và ghi file `shell.php` vào folder, thì server nhận ra `link_to_html` đã tồn tại và đang trỏ tới `/var/www/html` . Do đó thay vì tạo folder mới, nó sẽ ghi luôn file `shell.php` vào `/var/www/html` =&gt; dẫn tới RCE server.

# III. Code Vulnerability

Vào một ngày trực soc bình dị, mình nhớ đến thịt chó nhưng không có tiền, quyết định chạy lên huntr để đọc 1 con source bất kì thì mình nhận ra đoạn code này

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728666800876/08548792-2732-4993-9725-042d9cdd6719.png align="center")

Mình đặt ra câu hỏi là tại sao chỉ có tệp tar đang được phòng thủ path traversal? Điều này 1 phần làm kích thích challenge bypass trong mình.

---

Tản mạn về đoạn code xử lý tệp tar

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728667045790/4392356c-7e92-4c9e-a6a0-5db73ffd646b.png align="center")

Giả sử `dest_dir` = `/home/kali/test.extract` , bảng dưới đây mô tả cách hoạt động từng dòng code ứng với mỗi giá trị `member.name` được truyền vào.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728666998372/a0f7d2d0-6cb3-44dd-9540-cda890fe53c0.png align="center")

Có thể nhận thấy đoạn code này phòng thủ zip slip khá tốt (zip slip là kĩ thuật chèn path traversal vào file name các file trong tệp zip). Tuy nhiên với symlink thì không. Tất cả tại vì `os.path.normpath` sẽ cố gắng lấy ra name hiện tại(name của symlink) chứ không phải tên của tệp được trỏ tới.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728667366461/d17ee569-ee99-4c07-b6a0-ca32c9f8e8af.png align="center")

Điều kiện cần - `dùng symlink bypass` và đủ - `app cho phép upload tar file và giải nén ngay lập tức` =&gt; Bắt tay vào khai thác

# IV. Exploit

Để không phải upload file tar 2 lần. Mình quyết định nghĩ ra 1 cách là nén symlink vào trước, sau đó nén file cùng tên với symlink vào sau với nội dung bất kì. Khi giải nén, chúng ta sẽ ghi đè được file trên server tùy ý. (Nếu chưa hiểu cảm phiền mọi người đọc lại mục II một chút😘)

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728667548911/2472c58e-5855-4597-8493-087adb8de872.png align="center")

Ở đây mình đã tạo được 2 file cùng tên với file symlink được nén vào trước, file thường nén vào sau.

<s>Để tránh quá nhiều thông tin trong 1 bài viết 😘. Mình quyết định bỏ qua việc trace code để tìm hàm upload.</s>

---

Một chút hình ảnh minh họa

[POC](https://drive.google.com/file/d/1cAN0nIl9N6LQvZ8SbqeV6V9o9D4-EZOx/view)

╰(\*°▽°\*)╯  
Mong đây là cái CVE đầu tay 😂. Cảm ơn mọi người đã đọc
