Angstromctf-2023 Ctf Writeup - filestore
Overview
Challenge cho source code: https://drive.google.com/file/d/1udkCu6axKKX6KhXgP4X3W_ejeIew0HNF/view?usp=sharing
index.php
:
<?php
if($_SERVER['REQUEST_METHOD'] == "POST"){
if ($_FILES["f"]["size"] > 1000) {
echo "file too large";
return;
}
$i = uniqid();
if (empty($_FILES["f"])){
return;
}
if (move_uploaded_file($_FILES["f"]["tmp_name"], "./uploads/" . $i . "_" . hash('sha256', $_FILES["f"]["name"]) . "_" . $_FILES["f"]["name"])){
echo "upload success";
} else {
echo "upload error";
}
} else {
if (isset($_GET["f"])) {
include "./uploads/" . $_GET["f"];
}
highlight_file("index.php");
// this doesn't work, so I'm commenting it out 😛
// system("/list_uploads");
}
?>
Dockerfile
:
FROM php:8.1.18-apache-bullseye
RUN groupadd -r admin && useradd -r -g admin admin
RUN groupadd -r ctf && useradd -r -g ctf ctf
RUN sed -i "s/Listen 80/Listen 8080/" /etc/apache2/ports.conf
RUN chmod -R 755 /etc/apache2 &&\
chmod -R 755 /var/www/
COPY flag.txt /flag.txt
RUN chown admin:admin /flag.txt &&\
chmod 440 /flag.txt
COPY make_abyss_entry /make_abyss_entry
RUN chown root:root /make_abyss_entry &&\
chmod 111 /make_abyss_entry &&\
chmod g+s /make_abyss_entry
COPY list_uploads /list_uploads
RUN chown admin:admin /list_uploads &&\
chmod 111 /list_uploads &&\
chmod g+s /list_uploads
COPY src /var/www/html
RUN mkdir /abyss &&\
chown -R root:root /abyss &&\
chmod -R 331 /abyss
RUN chown -R root:root /var/www/html &&\
chmod -R 555 /var/www/html
RUN rm -rf /var/www/html/uploads
RUn mkdir /var/www/html/uploads &&\
chmod -R 333 /var/www/html/uploads
RUN rm -f /bin/chmod /usr/bin/chmod /bin/chown /usr/bin/chown
USER ctf
EXPOSE 8080
Nói sơ sơ qua thì index.php
cho upload file nhưng tên file random không truy cập được + có bug LFI.
Dockerfile setup 2 file binary đáng nghi là make_abyss_entry
(set guid root) và list_uploads
(set guid admin), user chạy web php là ctf còn để đọc được flag thì cần quyền admin
Exploitation
Ngồi loay hoay tính năng upload file chẳng ra gì do tên file thì không đoán được, path traversal thì không thể do khi espace đoạn random string được prefix phía trước sẽ tạo ra 1 thư mục không tồn tại => không thể upload!!
Ngồi chơi 1 lúc mới nhớ đến với bug LFI có thể dùng pearcmd.php
, 1 lib trong php để tạo webshell. Kĩ thuật này cũng không có gì mới, mọi người có thể tham khảo tại đây (update reference)
Include file pearcmd.php
viết webshell vào webroot:
Shell nè:
RCE rồi nhưng chưa có flag ngay do còn cần phải leo thang đặc quyền mới đọc được flag, mình có tự chạy docker và có 1 vài ý tưởng rồi, mà trước tiên phải lấy được reverse shell đã:
Nội dung pastebin nè:
Khi lấy reverse shell đôi khi do một số ký tự đặc biệt như <
, $
, hay &
mà mắc lỗi encoding, server không chạy được command nên mình thường đi kiểu đường vòng như này - curl webshell rồi load vào bash, đỡ phải nghĩ nhiều hihi.
Privilege Escalation
Binary file /make_abyss_entry
tạo ra 1 thư mục random riêng cho user ctf ở thư mục /abyss
còn /list_uploads
thì chạy command ls ở thư mục /var/www/html/uploads
. Cái này mình chạy command thì biết thôi chứ không biết reverse gì đâu :))
Ai biết qua các kĩ thuật leo thang đặc quyền trên linux thì cũng chắc đoán được đây là leo thang qua PATH enviroment variable.
Do file /list_uploads
gọi command ls
- relative path nên khi thực thi, linux sẽ lookup binary file của command này thông qua PATH env. Bằng cách tạo 1 file ls
giả chứa command cat /flag.txt
, chỉnh sửa PATH env để ưu tiên file binary giả này sau đó thực thi list_uploads
(được set guid là admin), ta có thể đọc được flag. Mà thế nên nó mới cho /make_abyss_entry
để tạo thư mục riêng tạo file ls
, không thì tranh nhau tạo ở /tmp
thì lộ hết bài :))
Mình cũng quền nhắc là ở file Docker có dòng này:
RUN rm -f /bin/chmod /usr/bin/chmod /bin/chown /usr/bin/chown
Thành ra không cấp quyền thực thi cho file ls
“giả” được, google thì mình tìm được có thể dùng perl để thay thế lệnh chmod
sau
Nói đủ rồi, end game thôi. Tạo thư mục riêng bằng /make_abyss_entry
:
Tạo file ls
trong thư mục vừa rồi, cấp quyền exec bằng perl, sửa biến PATH env sau đó chạy /list_uploads
là được flag:
flag: actf{w4tch_y0ur_p4th_724248b559281824}