2014-04-08 40 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

相關問題