{"id":4434,"date":"2022-03-17T17:11:47","date_gmt":"2022-03-17T16:11:47","guid":{"rendered":"https:\/\/www.vaadata.com\/blog\/?p=4434"},"modified":"2022-12-12T14:59:34","modified_gmt":"2022-12-12T13:59:34","slug":"rce-vulnerability-in-a-file-name","status":"publish","type":"post","link":"https:\/\/www.vaadata.com\/blog\/rce-vulnerability-in-a-file-name\/","title":{"rendered":"RCE vulnerability in a file name"},"content":{"rendered":"<div class=\"wp-block-image\">\n<figure class=\"alignright size-medium\"><img decoding=\"async\" width=\"300\" height=\"157\" src=\"https:\/\/www.vaadata.com\/blog\/wp-content\/uploads\/2022\/03\/RCE_vulnerability-300x157.png\" alt=\"RCE vulnerability : Remote Code Execution\" class=\"wp-image-5370\" srcset=\"https:\/\/www.vaadata.com\/blog\/wp-content\/uploads\/2022\/03\/RCE_vulnerability-300x157.png 300w, https:\/\/www.vaadata.com\/blog\/wp-content\/uploads\/2022\/03\/RCE_vulnerability-1024x535.png 1024w, https:\/\/www.vaadata.com\/blog\/wp-content\/uploads\/2022\/03\/RCE_vulnerability.png 1200w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/figure>\n<\/div>\n\n\n<p>During our security audits, we are regularly confronted with vulnerabilities that allow commands to be executed on a system. These can take various forms depending on the type of application and the functionality impacted. You will find in this article an example of a <strong>RCE vulnerability<\/strong> encountered during a <a href=\"https:\/\/www.vaadata.com\/en\/pentest-web\/\" target=\"_blank\" rel=\"noreferrer noopener\">penetration test of a web application<\/a> coded in PHP.<\/p>\n\n\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">What is a RCE (Remote Code Execution)?<\/h2>\n\n\n\n<p>In computer security, <a href=\"https:\/\/en.wikipedia.org\/wiki\/Arbitrary_code_execution\" target=\"_blank\" rel=\"noreferrer noopener\">arbitrary code execution (ACE)<\/a> is the ability of an attacker to execute any command or code of his choice on a target machine or in a target process. The ability to trigger an arbitrary code execution over a network (especially via a wide area network such as the internet) is often referred to as remote code execution, or RCE.<\/p>\n\n\n\n<p>A RCE is particularly dangerous, as it often provides <strong>privileged access to a system.<\/strong> For example, a RCE vulnerability on a web application will often allow to execute commands on the server that hosts it and therefore to break into it. This will give the attacker access to all or part of the server&#8217;s files.<\/p>\n\n\n\n\n\n<h2 class=\"wp-block-heading\">Presentation of the RCE vulnerability<\/h2>\n\n\n\n<p>The purpose of the functionality tested was to allow the user to upload files to a platform so that they can be reused elsewhere. When the uploaded file is an audio or video file, the PHP application will run a command on the server to retrieve the duration of the file and thus be able to communicate it to the user.<\/p>\n\n\n\n<p>Here is the code (simplified and modified for the example) of the application:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;?php\n$message = \"\";\nfunction upload($file): string\n{\n    $base_dir = __DIR__ . \"\/..\/upload\/\";\n    $ext = strtolower(pathinfo(\"\/\" . $file&#91;\"name\"], PATHINFO_EXTENSION));\n    $filepath = $base_dir . uniqid() . '.' . $ext;\n    $filetype = mime_content_type($file&#91;\"tmp_name\"]);\n\n    move_uploaded_file($file&#91;\"tmp_name\"], $filepath);\n\n    if (str_starts_with($filetype, \"video\/\") || str_starts_with($filetype, \"audio\/\")) {\n        $command = sprintf(\"ffprobe -i \\\"%s\\\" -show_entries format=duration -v quiet -of csv=\\\"p=0\\\"\", $filepath);\n        $duration = shell_exec($command);\n        return \"Media file of duration \" . $duration . \" uploaded.\";\n    } else {\n        return \"File uploaded\";\n    }\n}\n\nif ($_SERVER&#91;\"REQUEST_METHOD\"] === \"POST\") {\n    $file = $_FILES&#91;\"formFile\"] ?? null;\n    $message = $file === null ? \"Missing file.\" : upload($file);\n}\n?&gt;\n\n&lt;!DOCTYPE html&gt;\n&lt;html lang=\"en\"&gt;\n&lt;head&gt;\n    &lt;meta charset=\"UTF-8\"&gt;\n    &lt;title&gt;Upload media file&lt;\/title&gt;\n    &lt;link href=\"https:\/\/cdn.jsdelivr.net\/npm\/bootstrap@5.0.2\/dist\/css\/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-EVSTQN3\/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC\" crossorigin=\"anonymous\"&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n\n&lt;div class=\"container\"&gt;\n    &lt;header&gt;\n        &lt;h1&gt;Upload media file&lt;\/h1&gt;\n        &lt;hr&gt;\n    &lt;\/header&gt;\n    &lt;div class=\"row justify-content-md-center\"&gt;\n        &lt;div class=\"col col-lg-6\"&gt;\n            &lt;form action=\"\" method=\"post\" enctype=\"multipart\/form-data\"&gt;\n                &lt;div class=\"mb-3\"&gt;\n                    &lt;label for=\"formFile\" class=\"form-label\"&gt;File to upload&lt;\/label&gt;\n                    &lt;input class=\"form-control\" type=\"file\" name=\"formFile\" id=\"formFile\"&gt;\n                &lt;\/div&gt;\n                &lt;div class=\"col-auto\"&gt;\n                    &lt;button type=\"submit\" class=\"btn btn-primary mb-3\"&gt;Upload&lt;\/button&gt;\n                &lt;\/div&gt;\n\n                &lt;?php if (!empty($message)) { ?&gt;\n                    &lt;div class=\"alert alert-primary\" role=\"alert\"&gt;\n                        &lt;?= htmlentities($message, ENT_QUOTES) ?&gt;\n                    &lt;\/div&gt;\n                &lt;?php } ?&gt;\n\n            &lt;\/form&gt;\n        &lt;\/div&gt;\n    &lt;\/div&gt;\n&lt;\/div&gt;\n\n&lt;\/body&gt;\n&lt;\/html&gt;\n<\/code><\/pre>\n\n\n\n<p>What we can see at first is that a command is built on line 13 thanks to the PHP function &#8220;sprintf&#8221; with the path of the previously uploaded file as parameter. This command is then executed on line 14 and its result is sent back to the user to be displayed on the page.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" width=\"560\" height=\"208\" src=\"https:\/\/www.vaadata.com\/blog\/wp-content\/uploads\/2022\/03\/File_1.png\" alt=\"File_1\" class=\"wp-image-4426\" srcset=\"https:\/\/www.vaadata.com\/blog\/wp-content\/uploads\/2022\/03\/File_1.png 560w, https:\/\/www.vaadata.com\/blog\/wp-content\/uploads\/2022\/03\/File_1-300x111.png 300w\" sizes=\"(max-width: 560px) 100vw, 560px\" \/><\/figure>\n\n\n\n<p>The file path is built on line 7 from the following elements:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>The variable $basedir: its value is hardcoded in the code, so it cannot be manipulated<\/li><li>The output of the PHP function uniqid: its value is not manipulable<\/li><li>The output of the PHP pathinfo function which is asked to return the extension of the uploaded file: this is where the vulnerability lies<\/li><\/ul>\n\n\n\n<p>Indeed, the pathinfo function, when asked for the file extension (with the PATHINFO_EXTENSION flag), will simply return everything after the last point of the path passed to it. It is therefore possible to inject malicious code in the file extension, so that it is inserted in the command built on line 13.<\/p>\n\n\n\n<p>However, given the way the PHP function &#8220;pathinfo&#8221; works, our command must not contain a dot or a slash. So, we must be cunning to exploit this vulnerability.<\/p>\n\n\n\n\n\n<h2 class=\"wp-block-heading\">Exploitation of the RCE vulnerability<\/h2>\n\n\n\n<p>To exploit this vulnerability, we will start by trying to inject a simple command into the file name. We&#8217;ll add a \\&#8221; to get out of the double quotes in which our command is located, then we&#8217;ll add a semicolon (;), then our command, and we&#8217;ll add another semicolon and a # to comment out the rest of the line so that it doesn&#8217;t interfere with us.<\/p>\n\n\n\n<p>So, our payload is as follows:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\\\";id;#<\/code><\/pre>\n\n\n\n<p>We will replay the request, injecting this payload into the file extension. The full name of the file is therefore:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>02.mp3\\\";id;#<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"1024\" height=\"624\" src=\"https:\/\/www.vaadata.com\/blog\/wp-content\/uploads\/2022\/03\/Burp_1-1024x624.png\" alt=\"\" class=\"wp-image-4428\" srcset=\"https:\/\/www.vaadata.com\/blog\/wp-content\/uploads\/2022\/03\/Burp_1-1024x624.png 1024w, https:\/\/www.vaadata.com\/blog\/wp-content\/uploads\/2022\/03\/Burp_1-300x183.png 300w, https:\/\/www.vaadata.com\/blog\/wp-content\/uploads\/2022\/03\/Burp_1.png 1266w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><figcaption><em>Clic to enlarge<\/em><\/figcaption><\/figure>\n\n\n\n<p>We see that the output of the &#8220;id&#8221; command is returned. We will then try to read the &#8220;\/etc\/passwd&#8221; file. However, as mentioned above, because of the way the function that retrieves the extension works, we will have to be tricky to insert commands containing dots and slashes. There are many ways to do this (for example by encoding the characters). As our application is in PHP, the php executable is certainly present on the server. So, we will use it to execute PHP code from the command line.<\/p>\n\n\n\n<p>We are going to create variables that contain the characters &#8221; \/ &#8221; and &#8221; . &#8221; generated from their respective charcode, then we are going to use them to build our commands. The PHP code will be as follows:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$sl=chr(47); \/\/ Character code of \/\n$dot=chr(46); \/\/ Character code of .\necho 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 .\n<\/code><\/pre>\n\n\n\n<p>The complete payload will be as follows:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>02.mp3\\\";php -r '$sl=chr(47);$dot=chr(46);echo shell_exec(\\\"cat ${sl}etc${sl}passwd\\\");';#<\/code><\/pre>\n\n\n\n<p>Here is a complete example of a command to read the file &#8220;\/etc\/passwd&#8221;:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"1024\" height=\"624\" src=\"https:\/\/www.vaadata.com\/blog\/wp-content\/uploads\/2022\/03\/Burp_2-1024x624.png\" alt=\"Burp_2\" class=\"wp-image-4430\" srcset=\"https:\/\/www.vaadata.com\/blog\/wp-content\/uploads\/2022\/03\/Burp_2-1024x624.png 1024w, https:\/\/www.vaadata.com\/blog\/wp-content\/uploads\/2022\/03\/Burp_2-300x183.png 300w, https:\/\/www.vaadata.com\/blog\/wp-content\/uploads\/2022\/03\/Burp_2.png 1266w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><figcaption><em>Clic to enlarge<\/em><\/figcaption><\/figure>\n\n\n\n<p>Here is another example to retrieve a file containing a &#8220;.&#8221; in its path.<\/p>\n\n\n\n<p>The payload is as follows:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>02.mp3\\\";php -r '$sl=chr(47);$dot=chr(46);echo shell_exec(\\\"cat ${sl}etc${sl}resolv${dot}conf\\\");';#<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"1024\" height=\"624\" src=\"https:\/\/www.vaadata.com\/blog\/wp-content\/uploads\/2022\/03\/Burp_3-1024x624.png\" alt=\"\" class=\"wp-image-4432\" srcset=\"https:\/\/www.vaadata.com\/blog\/wp-content\/uploads\/2022\/03\/Burp_3-1024x624.png 1024w, https:\/\/www.vaadata.com\/blog\/wp-content\/uploads\/2022\/03\/Burp_3-300x183.png 300w, https:\/\/www.vaadata.com\/blog\/wp-content\/uploads\/2022\/03\/Burp_3.png 1266w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><figcaption><em>Clic to enlarge<\/em><\/figcaption><\/figure>\n\n\n\n<p>From here we can run any command on the server. These will be executed with the rights of the user running the web service (e.g. www-data), and we are mostly not root, but the rights are often sufficient to compromise the system and the data it hosts.<\/p>\n\n\n\n\n\n<h2 class=\"wp-block-heading\">How to fix this RCE?<\/h2>\n\n\n\n<p>To fix this problem, the first recommendation would obviously be to never use data that can be manipulated by users in commands to the system.<\/p>\n\n\n\n<p>However, if it is necessary, it is important to make sure that the data that is used is clean and properly secured. For example, in our case, we could simply set up a whitelist of authorized extensions and not run the command if it is not in the list:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$allowedExtensions = &#91;\"mp3\", \"mpeg\"];\nif (!in_array($ext, $allowedExtensions)) {\n    return \"File not allowed\";\n}<\/code><\/pre>\n\n\n\n<p>It is also possible, for example, to use a regex in the PHP &#8220;filter_var&#8221; function to allow only letters and numbers:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>if (!filter_var($ext, FILTER_VALIDATE_REGEXP, &#91;\"options\"=&gt;array(\"regexp\"=&gt;\"\/^\\w+$\/\")])) {\n    return \"Invalid extension\";\n}\n<\/code><\/pre>\n\n\n\n<p><strong>Conclusion<\/strong><\/p>\n\n\n\n<p>When developing an application, it is important to understand where the data we are manipulating comes from and especially what the output of the functions we are using will be. Indeed, in this example, the PHP function &#8220;pathinfo&#8221; is quite basic and is not made to ensure that what it returns is really what we could expect for an extension (only letters and numbers, quite short&#8230;).<\/p>\n\n\n\n<p>It is also important to consider whether, when using data in a feature, it can pose a security problem, especially when that data is returned to the user (e.g. for XSS), or when it is used, for example, in system commands (RCE) or SQL (SQL injections). You can consult our article on s<a href=\"https:\/\/www.vaadata.com\/blog\/how-to-protect-your-website-php-security-tips-and-tricks-2\/\" target=\"_blank\" rel=\"noreferrer noopener\">ecurity best practices for PHP regarding injections and XSS<\/a>. It is therefore important to filter this data as much as possible and\/or to encode it in such a way that malicious content cannot be interpreted.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p class=\"has-text-align-right\"><em>Auteur : Romain Garcia<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>During our security audits, we are regularly confronted with vulnerabilities that allow commands to be executed on a system. These can take various forms depending on the type of application and the functionality impacted. You will find in this article an example of a RCE vulnerability encountered during a penetration test of a web application<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[],"class_list":{"0":"post-4434","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-technical"},"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.vaadata.com\/blog\/wp-json\/wp\/v2\/posts\/4434","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.vaadata.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.vaadata.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.vaadata.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.vaadata.com\/blog\/wp-json\/wp\/v2\/comments?post=4434"}],"version-history":[{"count":12,"href":"https:\/\/www.vaadata.com\/blog\/wp-json\/wp\/v2\/posts\/4434\/revisions"}],"predecessor-version":[{"id":5372,"href":"https:\/\/www.vaadata.com\/blog\/wp-json\/wp\/v2\/posts\/4434\/revisions\/5372"}],"wp:attachment":[{"href":"https:\/\/www.vaadata.com\/blog\/wp-json\/wp\/v2\/media?parent=4434"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.vaadata.com\/blog\/wp-json\/wp\/v2\/categories?post=4434"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.vaadata.com\/blog\/wp-json\/wp\/v2\/tags?post=4434"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}