2014-04-08 41 views
0

我试图通过套接字发送一个二进制文件。我抓住了Curl头文件来尝试对其进行逆向工程。我的应用程序和curl请求看起来与我相同,但PHP脚本无法接收文件。通过C++套接字POST二进制文件到PHP

这里是我的代码:

#include <iostream> 
#include <string> 
#include <fstream> 
#include <winsock.h> 
#pragma comment(lib, "wsock32.lib") 

/***************** PROTOTYPE *******************/ 
int SockRecv(SOCKET sock); 
int SockSend(SOCKET sock, std::string request); 
std::streamoff FileSize(std::string filename); 
int HTTP_POST(SOCKET sock, std::string host, std::string filename); 
int SendFile(SOCKET sock, std::string filename); 
/***************** PROTOTYPE *******************/ 

int main(){ 

     /* Standard networking stuff */ 
     u_short Port = 8080; 
     const char* IP = "192.168.1.140"; 
     std::string host(IP); 
     host += ":" + std::to_string(Port); 

     WSAData wsa; 
     WSAStartup(MAKEWORD(1, 1), &wsa); 
     SOCKET sock; 
     sockaddr_in RemoteSin; 
     RemoteSin.sin_family = AF_INET; 
     RemoteSin.sin_port = htons(Port); 

     if ((RemoteSin.sin_addr.S_un.S_addr = inet_addr(IP)) == INADDR_NONE){ 
       std::cout << "Error setting IP: " << GetLastError() << std::endl; 
       return 1; 
     } 
     if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR){ 
       std::cout << "Error creating socket" << std::endl; 
       return 1; 
     } 

     if (connect(sock, (sockaddr *)&RemoteSin, sizeof(sockaddr_in)) == SOCKET_ERROR){ 
       std::cout << "Error connecting to remote host: " << GetLastError() << std::endl; 
       return 1; 
     } 

     /* Sending the binary file */ 
     HTTP_POST(sock, host, "test.exe"); 

     /* Closing and cleaning connection */ 
     closesocket(sock); 
     WSACleanup(); 

     getchar(); 
} 

std::streamoff FileSize(std::string filename){ 

     std::ifstream file(filename, std::ios::binary | std::ios::ate); 
     return file.tellg(); 
} 

int HTTP_POST(SOCKET sock, std::string host, std::string filename){ 

     std::string header; 
     std::streamoff lenght = FileSize(filename); 

     /* Pre-building body to get the size */ 
     std::string strSize = "------------------------448eacc7eda1d5ef45\r\n"; 
     strSize += "Content-Disposition: form-data; name=\"uploadedfile\"; "; 
     strSize += "filename=\"" + filename + "\"\r\n"; 
     strSize += "Content-Type: application/octet-stream\r\n\r\n"; 
     strSize += "\r\n------------------------448eacc7eda1d5ef45--\r\n"; 

     /* Calculating Content-Lenght */ 
     lenght = lenght + strSize.size(); 

     /* Building header */ 
     header = "POST /upload.php HTTP/1.1\r\n"; 
     header += "User-Agent: Bot\r\n"; 
     header += "Host: " + host + "\r\n"; 
     header += "Accept: */*\r\n"; 
     header += "Content-Length: " + std::to_string(lenght) + "\r\n"; 
     //  header += "Expect: 100-continue\r\n"; // Curl send this but I think this is not required and might only complicate things  
     header += "Content-Type: multipart/form-data-stream; "; 
     header += "boundary=------------------------448eacc7eda1d5ef45\r\n\r\n"; 

     /* Appending first part of body to header */ 
     header += "------------------------448eacc7eda1d5ef45\r\n"; 
     header += "Content-Disposition: form-data; name=\"uploadedfile\"; "; 
     header += "filename=\"" + filename + "\"\r\n"; 
     header += "Content-Type: application/octet-stream\r\n\r\n"; 

     /* Sending header with first part of body */ 
     if (!SockSend(sock, header)) { 

       /* Sending binary file */ 
       if (!SendFile(sock, filename)){ 

         /* Closing body by sending end of boundary string */ 
         std::string header_end = "\r\n------------------------448eacc7eda1d5ef45--\r\n"; 
         if (!SockSend(sock, header_end)){ 

           /* Printing server response to stdout */ 
           if (!SockRecv(sock)){ 
             return 0; 
           } 

           return 1; 
         } 
       } 
     } 
     return 1; 
} 

int SockSend(SOCKET sock, std::string request){ 

     if (send(sock, request.c_str(), strlen(request.c_str()), 0) == SOCKET_ERROR){ 
       return 1; 
     } 
     return 0; 
} 

int SockRecv(SOCKET sock){ 

     char reply[1024]; 
     ZeroMemory(reply, 1024); 
     if (recv(sock, reply, 1024, 0) == SOCKET_ERROR){ 
       return 1; 
     } 
     std::cout << reply << std::endl; 

     return 0; 
} 

int SendFile(SOCKET sock, std::string filename){ 

     char buf[1040]; 
     std::ifstream infile; 
     infile.open(filename.c_str(), std::ios::in | std::ios::binary); 

     if (infile.fail() == 1) 
     { 
       infile.close(); 
       return 1; 
     } 

     while (!infile.eof()) 
     { 
       infile.read(buf, sizeof(buf)); 
       if (send(sock, buf, infile.gcount(), 0) == SOCKET_ERROR){ 
         return 1; 
       } 
     } 

     infile.close(); 
     return 0; 
} 

这里是接收PHP脚本:

<?php 

// Where the file is going to be placed 
$target_path = "upload/"; 

/* Add the original filename to our target path. 
Result is "uploads/filename.extension" */ 
$target_path = $target_path . basename($_FILES['uploadedfile']['name']); 

if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) { 
    echo "The file ". basename($_FILES['uploadedfile']['name']). 
    " has been uploaded"; 
} else{ 
    echo "There was an error uploading the file, please try again!"; 
} 

?> 

使用这种卷曲要求:

curl --form "[email protected]" http://192.168.1.140:8080/upload.php 

这是一个成功上传的样子:

Request: 
POST /upload.php HTTP/1.1 
User-Agent: curl/7.35.0 
Host: 192.168.1.140:8080 
Accept: */* 
Content-Length: 69328 
Expect: 100-continue 
Content-Type: multipart/form-data; boundary=------------------------bfaa9a39adfbb3c1 

--------------------------bfaa9a39adfbb3c1 
Content-Disposition: form-data; name="uploadedfile"; filename="test.exe" 
Content-Type: application/octet-stream 

/* Binary data */ 
--------------------------bfaa9a39adfbb3c1-- 

Response: 
HTTP/1.1 100 Continue 

HTTP/1.1 200 OK 
Server: nginx/1.2.6 (Ubuntu) 
Date: Tue, 08 Apr 2014 19:45:38 GMT 
Content-Type: text/html 
Connection: keep-alive 
X-Powered-By: PHP/5.4.9-4ubuntu2.4 
Content-Length: 35 

The file test.exe has been uploaded 

然后用我的C++应用程序,这是一个失败的上传是什么样子:

Request: 
POST /upload.php HTTP/1.1 
User-Agent: Bot 
Host: 192.168.1.140:8080 
Accept: */* 
Content-Length: 69328 
Content-Type: multipart/form-data-stream; boundary=------------------------448eacc7eda1d5ef45 

------------------------448eacc7eda1d5ef45 
Content-Disposition: form-data; name="uploadedfile"; filename="test.exe" 
Content-Type: application/octet-stream 

/* Binary data */ 
------------------------448eacc7eda1d5ef45-- 

Response: 
HTTP/1.1 200 OK 
Server: nginx/1.2.6 (Ubuntu) 
Date: Tue, 08 Apr 2014 19:45:49 GMT 
Content-Type: text/html 
Connection: keep-alive 
X-Powered-By: PHP/5.4.9-4ubuntu2.4 
Content-Length: 56 

There was an error uploading the file, please try again! 

我省略了“期望:100继续”,因为我觉得这是可选的。否则,这两个请求看起来完全一样。三重检查了我所能做的一切,但现在我被困在那里。

感谢您的任何意见!

回答

0

您使用了错误的标题:

header += "Content-Type: multipart/form-data-stream; "; 
               ^^^^^^^---- wrong type 

这应该只是multipart/form-data

至于你的PHP代码,你就不能检查一个成功/有效的上传,并简单地假设一切都工作:

if ($_FILES['uploadedfile']['error'] !== UPLOAD_ERR_OK) { 
    die("Upload failed with error code" . $_FILES['uploadedfile']['error']); 
} 

,如果你有连这个最小的错误处理,你必须被告知没有上传开始,而不是在稍后尝试移动不存在的文件时才发现。

+0

使用multipart/form-data是我尝试的第一件事情之一。我将我的代码编辑为multipart/form-data,并将错误检查添加到PHP脚本中。现在我从PHP脚本中得到错误0,所以我将继续调查,因为它似乎没有上传文件。 – 01BTC10

相关问题