Add support for extracting PUT files.

remotes/origin/master-1.2.x
Victor Julien 14 years ago
parent 59cda9a358
commit 403b2788d6

@ -1017,6 +1017,239 @@ static void HtpRequestBodyReassemble(SCHtpTxUserData *htud,
*chunks_buffer_len = buf_len;
}
int HtpRequestBodyHandleMultipart(HtpState *hstate, SCHtpTxUserData *htud,
uint8_t *chunks_buffer, uint32_t chunks_buffer_len)
{
#ifdef PRINT
printf("CHUNK START: \n");
PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len);
printf("CHUNK END: \n");
#endif
uint8_t *expected_boundary = NULL;
uint8_t *expected_boundary_end = NULL;
uint8_t expected_boundary_len = 0;
uint8_t expected_boundary_end_len = 0;
if (HtpRequestBodySetupBoundary(htud, &expected_boundary, &expected_boundary_len,
&expected_boundary_end, &expected_boundary_end_len) < 0) {
goto end;
}
/* search for the header start, header end and form end */
uint8_t *header_start = Bs2bmSearch(chunks_buffer, chunks_buffer_len,
expected_boundary, expected_boundary_len);
uint8_t *header_end = NULL;
if (header_start != NULL) {
header_end = Bs2bmSearch(header_start, chunks_buffer_len - (header_start - chunks_buffer),
(uint8_t *)"\r\n\r\n", 4);
}
uint8_t *form_end = Bs2bmSearch(chunks_buffer, chunks_buffer_len,
expected_boundary_end, expected_boundary_end_len);
/* if we're in the file storage process, deal with that now */
if (htud->flags & HTP_FILENAME_SET) {
if (header_start != NULL || form_end != NULL || htud->flags & HTP_BODY_COMPLETE) {
SCLogDebug("reached the end of the file");
uint8_t *filedata = chunks_buffer;
uint32_t filedata_len = 0;
uint8_t flags = 0;
if (header_start < form_end || (header_start != NULL && form_end == NULL)) {
filedata_len = header_start - filedata - 2; /* 0d 0a */
} else if (form_end != NULL && form_end < header_start) {
filedata_len = form_end - filedata;
} else if (form_end != NULL && form_end == header_start) {
filedata_len = form_end - filedata - 2; /* 0d 0a */
} else if (htud->flags & HTP_BODY_COMPLETE) {
filedata_len = chunks_buffer_len;
flags = FLOW_FILE_TRUNCATED;
}
BUG_ON(filedata_len > chunks_buffer_len);
#ifdef PRINT
printf("FILEDATA (final chunk) START: \n");
PrintRawDataFp(stdout, filedata, filedata_len);
printf("FILEDATA (final chunk) END: \n");
#endif
if (HTPFileClose(hstate->f, filedata, filedata_len, flags) == -1)
{
goto end;
}
htud->flags &=~ HTP_FILENAME_SET;
/* fall through */
} else {
SCLogDebug("not yet at the end of the file");
if (chunks_buffer_len > expected_boundary_end_len) {
uint8_t *filedata = chunks_buffer;
uint32_t filedata_len = chunks_buffer_len - expected_boundary_len;
#ifdef PRINT
printf("FILEDATA (part) START: \n");
PrintRawDataFp(stdout, filedata, filedata_len);
printf("FILEDATA (part) END: \n");
#endif
if (HTPFileStoreChunk(hstate->f, filedata, filedata_len) == -1) {
goto end;
}
htud->body_parsed += filedata_len;
} else {
SCLogDebug("chunk too small to already process in part");
}
goto end;
}
}
while (header_start != NULL && header_end != NULL &&
header_end != form_end &&
header_start < (chunks_buffer + chunks_buffer_len) &&
header_end < (chunks_buffer + chunks_buffer_len) &&
header_start < header_end)
{
uint8_t *filename = NULL;
uint16_t filename_len = 0;
uint8_t *filetype = NULL;
uint16_t filetype_len = 0;
uint32_t header_len = header_end - header_start;
SCLogDebug("header_len %u", header_len);
uint8_t *header = header_start + (expected_boundary_len + 2); // + for 0d 0a
header_len -= (expected_boundary_len + 2);
HtpRequestBodyMultipartParseHeader(header, header_len, &filename,
&filename_len, &filetype, &filetype_len);
if (filename != NULL) {
uint8_t *filedata = NULL;
uint32_t filedata_len = 0;
SCLogDebug("we have a filename");
htud->flags |= HTP_FILENAME_SET;
SCLogDebug("header_end %p", header_end);
SCLogDebug("form_end %p", form_end);
/* everything until the final boundary is the file */
if (form_end != NULL) {
filedata = header_end + 4;
filedata_len = form_end - (header_end + 4 + 2);
/* or is it? */
uint8_t *header_next = Bs2bmSearch(filedata, filedata_len,
expected_boundary, expected_boundary_len);
if (header_next != NULL) {
filedata_len -= (form_end - header_next);
}
SCLogDebug("filedata_len %"PRIuMAX, (uintmax_t)filedata_len);
#ifdef PRINT
printf("FILEDATA START: \n");
PrintRawDataFp(stdout, filedata, filedata_len);
printf("FILEDATA END: \n");
#endif
if (HTPFileOpen(hstate->f, filename, filename_len,
filedata, filedata_len) == -1) {
goto end;
}
if (HTPFileClose(hstate->f, NULL, 0, 0) == -1) {
goto end;
}
} else {
SCLogDebug("more file data to come");
uint32_t offset = (header_end + 4) - chunks_buffer;
SCLogDebug("offset %u", offset);
htud->body_parsed = offset;
if (HTPFileOpen(hstate->f, filename, filename_len,
filedata, filedata_len) == -1) {
goto end;
}
}
}
SCLogDebug("header_start %p, header_end %p, form_end %p",
header_start, header_end, form_end);
/* Search next boundary entry after the start of body */
uint32_t cursizeread = header_end - chunks_buffer;
header_start = Bs2bmSearch(header_end + 4,
chunks_buffer_len - (cursizeread + 4),
expected_boundary, expected_boundary_len);
if (header_start != NULL) {
header_end = Bs2bmSearch(header_end + 4,
chunks_buffer_len - (cursizeread + 4),
(uint8_t *) "\r\n\r\n", 4);
}
}
end:
if (expected_boundary != NULL) {
SCFree(expected_boundary);
}
if (expected_boundary_end != NULL) {
SCFree(expected_boundary_end);
}
return 0;
}
/** \brief setup things for put request
* \todo really needed? */
int HtpRequestBodySetupPUT(htp_tx_data_t *d, SCHtpTxUserData *htud) {
// if (d->tx->parsed_uri == NULL || d->tx->parsed_uri->path == NULL) {
// return -1;
// }
/* filename is d->tx->parsed_uri->path */
return 0;
}
int HtpRequestBodyHandlePUT(HtpState *hstate, SCHtpTxUserData *htud,
htp_tx_t *tx, uint8_t *data, uint32_t data_len)
{
/* see if we need to open the file */
if (!(htud->flags & HTP_FILENAME_SET))
{
uint8_t *filename = NULL;
uint32_t filename_len = 0;
/* get the name */
if (tx->parsed_uri != NULL && tx->parsed_uri->path != NULL) {
filename = (uint8_t *)bstr_ptr(tx->parsed_uri->path);
filename_len = bstr_len(tx->parsed_uri->path);
}
if (HTPFileOpen(hstate->f, filename, filename_len,
data, data_len) == -1) {
goto end;
}
htud->flags |= HTP_FILENAME_SET;
}
else
{
/* otherwise, just store the data */
if (HTPFileStoreChunk(hstate->f, data, data_len) == -1) {
goto end;
}
}
return 0;
end:
return -1;
}
/**
* \brief Function callback to append chunks for Requests
* \param d pointer to the htp_tx_data_t structure (a chunk from htp lib)
@ -1026,11 +1259,6 @@ int HTPCallbackRequestBodyData(htp_tx_data_t *d)
{
SCEnter();
uint8_t *expected_boundary = NULL;
uint8_t *expected_boundary_end = NULL;
uint8_t *chunks_buffer = NULL;
uint32_t chunks_buffer_len = 0;
HtpState *hstate = (HtpState *)d->tx->connp->user_data;
if (hstate == NULL) {
SCReturnInt(HOOK_ERROR);
@ -1048,14 +1276,20 @@ int HTPCallbackRequestBodyData(htp_tx_data_t *d)
memset(htud, 0, sizeof(SCHtpTxUserData));
htud->body.operation = HTP_BODY_NONE;
HtpRequestBodySetupMultipart(d, htud);
if (d->tx->request_method_number == M_POST) {
if (HtpRequestBodySetupMultipart(d, htud) == 0) {
htud->body.operation = HTP_BODY_REQUEST_MULTIPART;
}
} else if (d->tx->request_method_number == M_PUT) {
if (HtpRequestBodySetupPUT(d, htud) == 0) {
htud->body.operation = HTP_BODY_REQUEST_PUT;
}
}
/* Set the user data for handling body chunks on this transaction */
htp_tx_set_user_data(d->tx, htud);
}
htud->body.operation = HTP_BODY_REQUEST;
SCLogDebug("htud->content_len_so_far %"PRIu64, htud->content_len_so_far);
SCLogDebug("hstate->request_body_limit %u", hstate->request_body_limit);
@ -1083,187 +1317,27 @@ int HTPCallbackRequestBodyData(htp_tx_data_t *d)
htud->flags |= HTP_BODY_COMPLETE;
}
/* multi-part body handling starts here */
if (!(htud->flags & HTP_BOUNDARY_SET)) {
goto end;
}
HtpRequestBodyReassemble(htud, &chunks_buffer, &chunks_buffer_len);
if (chunks_buffer == NULL) {
goto end;
}
#ifdef PRINT
printf("CHUNK START: \n");
PrintRawDataFp(stdout, chunks_buffer, chunks_buffer_len);
printf("CHUNK END: \n");
#endif
uint8_t *expected_boundary = NULL;
uint8_t *expected_boundary_end = NULL;
uint8_t expected_boundary_len = 0;
uint8_t expected_boundary_end_len = 0;
if (HtpRequestBodySetupBoundary(htud, &expected_boundary, &expected_boundary_len,
&expected_boundary_end, &expected_boundary_end_len) < 0) {
goto end;
}
/* search for the header start, header end and form end */
uint8_t *header_start = Bs2bmSearch(chunks_buffer, chunks_buffer_len,
expected_boundary, expected_boundary_len);
uint8_t *header_end = NULL;
if (header_start != NULL) {
header_end = Bs2bmSearch(header_start, chunks_buffer_len - (header_start - chunks_buffer),
(uint8_t *)"\r\n\r\n", 4);
}
uint8_t *form_end = Bs2bmSearch(chunks_buffer, chunks_buffer_len,
expected_boundary_end, expected_boundary_end_len);
/* if we're in the file storage process, deal with that now */
if (htud->flags & HTP_FILENAME_SET) {
if (header_start != NULL || form_end != NULL || htud->flags & HTP_BODY_COMPLETE) {
SCLogDebug("reached the end of the file");
uint8_t *filedata = chunks_buffer;
uint32_t filedata_len = 0;
uint8_t flags = 0;
if (header_start < form_end || (header_start != NULL && form_end == NULL)) {
filedata_len = header_start - filedata - 2; /* 0d 0a */
} else if (form_end != NULL && form_end < header_start) {
filedata_len = form_end - filedata;
} else if (form_end != NULL && form_end == header_start) {
filedata_len = form_end - filedata - 2; /* 0d 0a */
} else if (htud->flags & HTP_BODY_COMPLETE) {
filedata_len = chunks_buffer_len;
flags = FLOW_FILE_TRUNCATED;
}
BUG_ON(filedata_len > chunks_buffer_len);
#ifdef PRINT
printf("FILEDATA (final chunk) START: \n");
PrintRawDataFp(stdout, filedata, filedata_len);
printf("FILEDATA (final chunk) END: \n");
#endif
if (HTPFileClose(hstate->f, filedata, filedata_len, flags) == -1)
{
goto end;
}
htud->flags &=~ HTP_FILENAME_SET;
/* fall through */
} else {
SCLogDebug("not yet at the end of the file");
if (chunks_buffer_len > expected_boundary_end_len) {
uint8_t *filedata = chunks_buffer;
uint32_t filedata_len = chunks_buffer_len - expected_boundary_len;
#ifdef PRINT
printf("FILEDATA (part) START: \n");
PrintRawDataFp(stdout, filedata, filedata_len);
printf("FILEDATA (part) END: \n");
#endif
if (HTPFileStoreChunk(hstate->f, filedata, filedata_len) == -1) {
goto end;
}
htud->body_parsed += filedata_len;
} else {
SCLogDebug("chunk too small to already process in part");
}
uint8_t *chunks_buffer = NULL;
uint32_t chunks_buffer_len = 0;
if (htud->body.operation == HTP_BODY_REQUEST_MULTIPART) {
/* multi-part body handling starts here */
if (!(htud->flags & HTP_BOUNDARY_SET)) {
goto end;
}
}
while (header_start != NULL && header_end != NULL &&
header_end != form_end &&
header_start < (chunks_buffer + chunks_buffer_len) &&
header_end < (chunks_buffer + chunks_buffer_len) &&
header_start < header_end)
{
uint8_t *filename = NULL;
uint16_t filename_len = 0;
uint8_t *filetype = NULL;
uint16_t filetype_len = 0;
uint32_t header_len = header_end - header_start;
SCLogDebug("header_len %u", header_len);
uint8_t *header = header_start + (expected_boundary_len + 2); // + for 0d 0a
header_len -= (expected_boundary_len + 2);
HtpRequestBodyMultipartParseHeader(header, header_len, &filename,
&filename_len, &filetype, &filetype_len);
if (filename != NULL) {
uint8_t *filedata = NULL;
uint32_t filedata_len = 0;
SCLogDebug("we have a filename");
htud->flags |= HTP_FILENAME_SET;
SCLogDebug("header_end %p", header_end);
SCLogDebug("form_end %p", form_end);
/* everything until the final boundary is the file */
if (form_end != NULL) {
filedata = header_end + 4;
filedata_len = form_end - (header_end + 4 + 2);
/* or is it? */
uint8_t *header_next = Bs2bmSearch(filedata, filedata_len,
expected_boundary, expected_boundary_len);
if (header_next != NULL) {
filedata_len -= (form_end - header_next);
}
SCLogDebug("filedata_len %"PRIuMAX, (uintmax_t)filedata_len);
#ifdef PRINT
printf("FILEDATA START: \n");
PrintRawDataFp(stdout, filedata, filedata_len);
printf("FILEDATA END: \n");
#endif
if (HTPFileOpen(hstate->f, filename, filename_len,
filedata, filedata_len) == -1) {
goto end;
}
if (HTPFileClose(hstate->f, NULL, 0, 0) == -1) {
goto end;
}
} else {
SCLogDebug("more file data to come");
uint32_t offset = (header_end + 4) - chunks_buffer;
SCLogDebug("offset %u", offset);
htud->body_parsed = offset;
if (HTPFileOpen(hstate->f, filename, filename_len,
filedata, filedata_len) == -1) {
goto end;
}
}
HtpRequestBodyReassemble(htud, &chunks_buffer, &chunks_buffer_len);
if (chunks_buffer == NULL) {
goto end;
}
SCLogDebug("header_start %p, header_end %p, form_end %p",
header_start, header_end, form_end);
HtpRequestBodyHandleMultipart(hstate, htud, chunks_buffer, chunks_buffer_len);
/* Search next boundary entry after the start of body */
uint32_t cursizeread = header_end - chunks_buffer;
header_start = Bs2bmSearch(header_end + 4,
chunks_buffer_len - (cursizeread + 4),
expected_boundary, expected_boundary_len);
if (header_start != NULL) {
header_end = Bs2bmSearch(header_end + 4,
chunks_buffer_len - (cursizeread + 4),
(uint8_t *) "\r\n\r\n", 4);
if (chunks_buffer != NULL) {
SCFree(chunks_buffer);
}
} else if (htud->body.operation == HTP_BODY_REQUEST_PUT) {
HtpRequestBodyHandlePUT(hstate, htud, d->tx, (uint8_t *)d->data, (uint32_t)d->len);
}
}
@ -1272,16 +1346,6 @@ end:
/* see if we can get rid of htp body chunks */
HtpBodyPrune(htud);
if (expected_boundary != NULL) {
SCFree(expected_boundary);
}
if (expected_boundary_end != NULL) {
SCFree(expected_boundary_end);
}
if (chunks_buffer != NULL) {
SCFree(chunks_buffer);
}
/* set the new chunk flag */
hstate->flags |= HTP_FLAG_NEW_BODY_SET;
@ -1341,6 +1405,17 @@ static int HTPCallbackRequest(htp_connp_t *connp) {
SCLogDebug("HTTP request completed");
if (connp->in_tx != NULL) {
SCHtpTxUserData *htud = (SCHtpTxUserData *) htp_tx_get_user_data(connp->in_tx);
if (htud != NULL) {
if (htud->flags & HTP_FILENAME_SET) {
SCLogDebug("closing file that was being stored");
(void)HTPFileClose(hstate->f, NULL, 0, 0);
htud->flags &= ~HTP_FILENAME_SET;
}
}
}
SCReturnInt(HOOK_OK);
}

@ -60,6 +60,8 @@ enum {
operation */
HTP_BODY_REQUEST, /**< Flag to indicate that the
current operation is a request */
HTP_BODY_REQUEST_MULTIPART,
HTP_BODY_REQUEST_PUT,
HTP_BODY_RESPONSE /**< Flag to indicate that the current
* operation is a response */
};

Loading…
Cancel
Save