Apache2 access.log 对于相同的数据包不同

Posted

技术标签:

【中文标题】Apache2 access.log 对于相同的数据包不同【英文标题】:Apache2 access.log different for same packets 【发布时间】:2017-11-11 20:47:18 【问题描述】:

我有一个 C++ 程序正在尝试使用在 Apache2 网络服务器上运行的 php 应用程序上传文件。我有一个非常奇怪的问题,我不知道该怎么办。因此,我使用 httpSendRequest() 函数创建了 HTTP 请求,当在 Wireshark 中查看时,它的格式似乎正确。但是,该文件没有上传,当我查看 apache 的 access.log 文件时,它没有显示用户代理或内容长度,尽管数据包捕获中明显存在两者。

作为参考,返回 200 状态的请求是使用 burp 套件而不是我的程序使用 httpSendRequest 发送的相同数据包,并且我还能够使用网络浏览器成功上传文件。

这是使用 httpSendRequest 创建请求的代码,其中大部分直接取自this codeguru post。

#include <windows.h>
#include <wininet.h>
#include <iostream>


#define ERROR_OPEN_FILE       10
#define ERROR_MEMORY          11
#define ERROR_SIZE            12
#define ERROR_INTERNET_OPEN   13
#define ERROR_INTERNET_CONN   14
#define ERROR_INTERNET_REQ    15
#define ERROR_INTERNET_SEND   16

using namespace std;

int main()

   // Local variables
   static char *filename   = "test.txt";   //Filename to be loaded
   static char *type       = "image/jpg";
   static char boundary[]  = "PaulRules";            //Header boundary
   static char nameForm[]  = "fileToUpload";     //Input form name
   static char iaddr[]     = "192.168.0.105";        //IP address
   static char url[]       = "upload.php";         //URL

   char hdrs[255];                  //Headers
   char * buffer;                   //Buffer containing file + headers
   char * content;                  //Buffer containing file
   FILE * pFile;                    //File pointer
   long lSize;                      //File size
   size_t result;


   // Open file
   pFile = fopen ( filename , "rb" );
   if (pFile==NULL) return ERROR_OPEN_FILE;

   // obtain file size:
   fseek (pFile , 0 , SEEK_END);
   lSize = ftell (pFile);
   rewind (pFile);

   // allocate memory to contain the whole file:
   content = (char*) malloc (sizeof(char)*lSize);
   if (content == NULL) return ERROR_MEMORY;

   // copy the file into the buffer:
   result = fread (content,1,lSize,pFile);
   if (result != lSize) return ERROR_SIZE;

   // terminate
   fclose (pFile);

   //allocate memory to contain the whole file + HEADER
   buffer = (char*) malloc (sizeof(char)*lSize + 2048);

   //print header
   sprintf(hdrs,"Content-Type: multipart/form-data; boundary=%s",boundary);
   sprintf(buffer,"--%s\r\nContent-Disposition: form-data; name=\"fileToUpload\"; filename=\"test.bmp\"\r\n",boundary,nameForm,filename);
   sprintf(buffer,"%sContent-Type: %s\r\n\r\n",buffer,type);

   int cb = strlen(buffer);
   char * bp = buffer + cb;
   memcpy(bp, content, lSize);
   bp += lSize;
   int cw = sprintf(bp,"\r\n--%s--\r\n",boundary);

   //Open internet connection
   HINTERNET hSession = InternetOpen("Paul was here :)",INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
   if(hSession==NULL) return ERROR_INTERNET_OPEN;

   HINTERNET hConnect = InternetConnect(hSession, iaddr,INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);
   if(hConnect==NULL) return ERROR_INTERNET_CONN;

   HINTERNET hRequest = HttpOpenRequest(hConnect, (const char*)"POST",url, NULL, NULL, (const char**)"*/*", 0, 1);
   if(hRequest==NULL) return ERROR_INTERNET_REQ;

   BOOL sent= HttpSendRequest(hRequest, hdrs, strlen(hdrs), buffer, cb + lSize + cw);
   if(!sent) return ERROR_INTERNET_SEND;

   //close any valid internet-handles
   InternetCloseHandle(hSession);
   InternetCloseHandle(hConnect);
   InternetCloseHandle(hRequest);

   return 0;

这是服务器端的 PHP 脚本

<?php
$target_dir = "recvFile/";
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
$uploadOk = 1;
$imageFileType = pathinfo($target_file,PATHINFO_EXTENSION);

// Check if file already exists
if (file_exists($target_file)) 
    echo "File already exists";
    $uploadOk = 0;


// Check file size
if ($_FILES["fileToUpload"]["size"] > 500000) 
    echo "File to large";
    $uploadOk = 0;


// Check if $uploadOk is set to 0 by an error
if ($uploadOk == 0) 
    echo "ERROR File not uploaded";


//attempt to upload the file
else 
    if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) 
        //echo "The file ". basename( $_FILES["fileToUpload"]["name"]). " has been uploaded.";
        echo "Command:1";
    
    else 
        echo $_FILES["fileToUpload"]["tmp_name"];
        echo "ERROR uploading file";
    

?>

【问题讨论】:

冒号是用户代理产品令牌中的合法字符吗? @IInspectable 我很确定它是合法的,但是我还是摆脱了它,因为它是不必要的。不管同样的问题仍然存在。 【参考方案1】:

您的源文件是"test.txt",但您正在上传到"test.bmp"。使它们具有相同的扩展名。

type = "image/jpg";

如果应该是文本,请将 type 更改为 "image/*""text/*"

看到打印"Command 1",您的操作可能是成功的。该文件可能在那里,但它不是您所期望的。如果没有,看看你可以从 PHP 端提取什么错误。

sprintf(buffer,"--%s\r\nContent-Disposition: form-data; \
name=\"fileToUpload\"; filename=\"test.bmp\"\r\n",
boundary,nameForm,filename);

您有一个格式说明符 "%s" 和 4 个参数。删除最后两个参数。

按照推荐的方式使用HttpOpenRequest

const char *accept[] =  "image/*", NULL ; // or `"text/*"`
HttpOpenRequest(hConnect, "POST",url, NULL, NULL, accept, 0, 1);


使用 C++ 的代码
#include <Windows.h>
#include <Wininet.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

#pragma comment(lib, "wininet.lib")

int main()

    HINTERNET hsession = NULL;
    HINTERNET hconnect = NULL;
    HINTERNET hrequest = NULL;

    const char* server = "localhost";
    const char* url = "upload.php";
    const char* type = "image/*";
    std::string filename = "test.bmp";

    std::ifstream infile("c:\\test\\test.bmp", std::ios::binary);
    if(!infile) 
        return 0;

    std::ostringstream oss;
    oss << infile.rdbuf();

    std::string headers = "Content-type: multipart/form-data, boundary=uniquestring";

    std::string data = "--uniquestring\r\n\
Content-Disposition: form-data; name=\"fileToUpload\"; filename=\"%1\"\r\n\
Content-Type: %2\r\n\
\r\n\
%3\r\n\
--uniquestring--";

    data.replace(data.find("%1"), 2, filename);
    data.replace(data.find("%2"), 2, type);
    data.replace(data.find("%3"), 2, oss.str());

    hsession = InternetOpen("appname", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
    if(!hsession) 
        goto cleanup;

    hconnect = InternetConnect(hsession, server, INTERNET_DEFAULT_HTTP_PORT,
        NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);
    if(!hconnect)
        goto cleanup;

    const char *accept[] =  type, NULL ;
    hrequest = HttpOpenRequest(hconnect, "POST", url, NULL, NULL, accept, 0, 1);
    if(!hrequest)
        goto cleanup;

    BOOL sent = HttpSendRequest(hrequest, headers.data(), headers.size(), 
        &data[0], data.size());
    if(sent)
    
        DWORD bufsize = 4096;
        std::string read(bufsize, 0);
        InternetReadFile(hrequest, &read[0], bufsize, &bufsize);
        read.resize(bufsize);
        std::cout << read << "\n";
    
    else
    
        goto cleanup;
    

cleanup:
    if(hrequest) InternetCloseHandle(hrequest);
    if(hconnect) InternetCloseHandle(hconnect);
    if(hsession) InternetCloseHandle(hsession);
    return 0;

【讨论】:

当我尝试将 .txt 文件上传为 .jpg 时,您确实是正确的服务器正在中断。感谢所有的帮助,我真的很感激! 好的好的。顺便说一句,您的代码是 C,我添加了 C++ 11 代码以使事情变得更简单。【参考方案2】:

为了完整起见,这里是完全可操作的代码

#include <windows.h>
#include <wininet.h>
#include <iostream>

using namespace std;
int main()

   // Local variables
   static char *filename   = "Desert.jpg";   //Filename to be loaded
   static char *type       = "multipart/form-data";
   static char boundary[]  = "PaulRules";            //Header boundary
   static char nameForm[]  = "fileToUpload";     //Input form name
   static char iaddr[]     = "192.168.0.105";        //IP address
   static char url[]       = "upload.php";         //URL

   char hdrs[255];                  //Headers
   char * buffer;                   //Buffer containing file + headers
   char * content;                  //Buffer containing file
   FILE * pFile;                    //File pointer
   long lSize;                      //File size
   size_t result;


   // Open file
   pFile = fopen ( filename , "rb" );

   // obtain file size:
   fseek (pFile , 0 , SEEK_END);
   lSize = ftell (pFile);
   rewind (pFile);

   // allocate memory to contain the whole file:
   content = (char*) malloc (sizeof(char)*lSize);

   // copy the file into the buffer:
   result = fread (content,1,lSize,pFile);

   // terminate
   fclose (pFile);

   //allocate memory to contain the whole file + HEADER
   buffer = (char*) malloc (sizeof(char)*lSize + 2048);

   //print header
   sprintf(hdrs,"Content-Type: multipart/form-data; boundary=%s",boundary);
   sprintf(buffer,"--%s\r\nContent-Disposition: form-data; name=\"fileToUpload\"; filename=\"%s\"\r\n",boundary, filename);
   sprintf(buffer,"%sContent-Type: %s\r\n\r\n",buffer,type);

   int cb = strlen(buffer);
   char * bp = buffer + cb;
   memcpy(bp, content, lSize);
   bp += lSize;
   int cw = sprintf(bp,"\r\n--%s--\r\n",boundary);

   //Open internet connection
   HINTERNET hSession = InternetOpen("Winsock",INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);

   HINTERNET hConnect = InternetConnect(hSession, iaddr,INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);

   const char* accept[] = "*/*", NULL;
   HINTERNET hRequest = HttpOpenRequest(hConnect, (const char*)"POST",url, NULL, NULL, accept, 0, 1);

   BOOL sent= HttpSendRequest(hRequest, hdrs, strlen(hdrs), buffer, cb + lSize + cw);

   DWORD dwSize, dwRead;
   CHAR szBuffer[1024];
   if(!InternetQueryDataAvailable(hRequest, &dwSize, 0, 0))
      std::cout << "QUERYDATA ERROR: " << GetLastError() << std::endl;
   
   else
      while(InternetReadFile(hRequest, szBuffer, sizeof(szBuffer)-1, &dwRead) && dwRead) 
        szBuffer[dwRead] = 0;
        dwRead=0;
      
      cout << szBuffer;
   

   //close any valid internet-handles
   InternetCloseHandle(hSession);
   InternetCloseHandle(hConnect);
   InternetCloseHandle(hRequest);

   return 0;

【讨论】:

以上是关于Apache2 access.log 对于相同的数据包不同的主要内容,如果未能解决你的问题,请参考以下文章

apache2 日志文件太大的解决方案

网络安全面试题——文件目录穿越实现特权文件读取

nginx设置电脑手机访问相同网址页面不同

纯手工玩转 Nginx 日志

明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了N个1到1000之间的随机整数(N≤1000),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不同的

Nginx演练配置日志访问