/** * Get the Pingback URL for a given URL * * @param string $url URL to get the Pingback URL for * @return string Pingback URL or empty string */ function PNB_getPingbackUrl($url) { $retval = ''; $http = new http_class(); $http->timeout = 0; $http->data_timeout = 0; $http->debug = 0; $http->html_debug = 0; $http->user_agent = 'glFusion/' . GVERSION; $error = $http->GetRequestArguments($url, $arguments); $error = $http->Open($arguments); $error = $http->SendRequest($arguments); if ($error == "") { $http->ReadReplyHeaders($headers); if (isset($headers['x-pingback'])) { $retval = $headers['x-pingback']; } else { COM_errorLog("Pingback (HEAD): unable to locate x-pingback header"); } } else { COM_errorLog('Pingback (HEAD): ' . $error); return false; } if (empty($retval)) { // search for <link rel="pingback"> $http = new http_class(); $http->timeout = 0; $http->data_timeout = 0; $http->debug = 0; $http->html_debug = 0; $http->user_agent = 'glFusion/' . GVERSION; $error = $http->GetRequestArguments($url, $arguments); $error = $http->Open($arguments); $error = $http->SendRequest($arguments); if ($error == "") { $http->ReadReplyHeaders($headers); if ($http->response_status == 200) { $error = $http->ReadWholeReplyBody($body); if ($error != "" && strlen($body) === 0) { COM_errorLog("Pingback (GET): unable to retrieve response body"); return false; } } else { COM_errorLog("Pingback (GET): Got HTTP response code " . $http->response_status . " when requesting " . $url); return false; } } else { COM_errorLog("Pingback (GET): " . $error . " when requesting " . $url); return false; } // only search for the first match - it doesn't make sense to have // more than one pingback URL $found = preg_match("/<link rel=\"pingback\"[^>]*href=[\"']([^\"']*)[\"'][^>]*>/i", $body, $matches); if ($found === 1 && !empty($matches[1])) { $url = str_replace('&', '&', $matches[1]); $retval = urldecode($url); } } return $retval; }
function SendAPIRequest($url, $method, $parameters, $oauth, $options, &$response) { $this->response_status = 0; $http = new http_class(); $http->debug = $this->debug && $this->debug_http; $http->log_debug = true; $http->sasl_authenticate = 0; $http->user_agent = $this->oauth_user_agent; if ($this->debug) { $this->OutputDebug('Accessing the ' . $options['Resource'] . ' at ' . $url); } $arguments = array(); $method = strtoupper($method); $authorization = ''; $type = isset($options['RequestContentType']) ? strtolower(trim(strtok($options['RequestContentType'], ';'))) : 'application/x-www-form-urlencoded'; if (isset($oauth)) { $values = array('oauth_consumer_key' => $this->client_id, 'oauth_nonce' => md5(uniqid(rand(), true)), 'oauth_signature_method' => 'HMAC-SHA1', 'oauth_timestamp' => time(), 'oauth_version' => '1.0'); if ($this->url_parameters && $type === 'application/x-www-form-urlencoded' && count($parameters)) { $first = strpos($url, '?') === false; foreach ($parameters as $parameter => $value) { $url .= ($first ? '?' : '&') . UrlEncode($parameter) . '=' . UrlEncode($value); } $parameters = array(); } $value_parameters = $type !== 'application/x-www-form-urlencoded' ? array() : $parameters; $values = array_merge($values, $oauth, $value_parameters); $uri = strtok($url, '?'); $sign = $method . '&' . $this->Encode($uri) . '&'; $first = true; $sign_values = $values; $u = parse_url($url); if (isset($u['query'])) { parse_str($u['query'], $q); foreach ($q as $parameter => $value) { $sign_values[$parameter] = $value; } } KSort($sign_values); foreach ($sign_values as $parameter => $value) { $sign .= $this->Encode(($first ? '' : '&') . $parameter . '=' . $this->Encode($value)); $first = false; } $key = $this->Encode($this->client_secret) . '&' . $this->Encode($this->access_token_secret); $values['oauth_signature'] = base64_encode($this->HMAC('sha1', $sign, $key)); if ($this->authorization_header) { $authorization = 'OAuth'; $first = true; foreach ($values as $parameter => $value) { $authorization .= ($first ? ' ' : ',') . $parameter . '="' . $this->Encode($value) . '"'; $first = false; } } else { if ($method === 'GET') { $first = strcspn($url, '?') == strlen($url); foreach ($values as $parameter => $value) { $url .= ($first ? '?' : '&') . $parameter . '=' . $this->Encode($value); $first = false; } $post_values = array(); } else { $post_values = $values; } } } if (strlen($error = $http->GetRequestArguments($url, $arguments))) { return $this->SetError('it was not possible to open the ' . $options['Resource'] . ' URL: ' . $error); } if (strlen($error = $http->Open($arguments))) { return $this->SetError('it was not possible to open the ' . $options['Resource'] . ' URL: ' . $error); } $arguments['RequestMethod'] = $method; switch ($type) { case 'application/x-www-form-urlencoded': if (isset($options['RequestBody'])) { return $this->SetError('the request body is defined automatically from the parameters'); } $arguments['PostValues'] = $parameters; break; case 'application/json': $arguments['Headers']['Content-Type'] = $options['RequestContentType']; if (!isset($options['RequestBody'])) { $arguments['Body'] = json_encode($parameters); break; } default: if (!isset($options['RequestBody'])) { return $this->SetError('it was not specified the body value of the of the API call request'); } $arguments['Headers']['Content-Type'] = $options['RequestContentType']; $arguments['Body'] = $options['RequestBody']; break; } $arguments['Headers']['Accept'] = isset($options['Accept']) ? $options['Accept'] : '*/*'; if (strlen($authorization)) { $arguments['Headers']['Authorization'] = $authorization; } if (strlen($error = $http->SendRequest($arguments)) || strlen($error = $http->ReadReplyHeaders($headers))) { $http->Close(); return $this->SetError('it was not possible to retrieve the ' . $options['Resource'] . ': ' . $error); } $error = $http->ReadWholeReplyBody($data); $http->Close(); if (strlen($error)) { return $this->SetError('it was not possible to access the ' . $options['Resource'] . ': ' . $error); } $this->response_status = intval($http->response_status); $content_type = isset($headers['content-type']) ? strtolower(trim(strtok($headers['content-type'], ';'))) : 'unspecified'; switch ($content_type) { case 'text/javascript': case 'application/json': if (!function_exists('json_decode')) { return $this->SetError('the JSON extension is not available in this PHP setup'); } $object = json_decode($data); switch (GetType($object)) { case 'object': if (!isset($options['ConvertObjects']) || !$options['ConvertObjects']) { $response = $object; } else { $response = array(); foreach ($object as $property => $value) { $response[$property] = $value; } } break; case 'array': $response = $object; break; default: if (!isset($object)) { return $this->SetError('it was not returned a valid JSON definition of the ' . $options['Resource'] . ' values'); } $response = $object; break; } break; case 'application/x-www-form-urlencoded': case 'text/plain': case 'text/html': parse_str($data, $response); break; default: $response = $data; break; } if ($this->response_status >= 200 && $this->response_status < 300) { $this->access_token_error = ''; } else { $this->access_token_error = 'it was not possible to access the ' . $options['Resource'] . ': it was returned an unexpected response status ' . $http->response_status . ' Response: ' . $data; if ($this->debug) { $this->OutputDebug('Could not retrieve the OAuth access. Error: ' . $this->access_token_error); } if (isset($options['FailOnAccessError']) && $options['FailOnAccessError']) { $this->error = $this->access_token_error; return false; } } return true; }
/** * Handle a pingback for an entry. * Also takes care of the speedlimit and spam. Assumes that the caller of this * function has already checked permissions! * * @param string $id ID of entry that got pinged * @param string $type type of that entry ('article' for stories, etc.) * @param string $url URL of the page that pinged us * @param string $oururl URL that got pinged on our site * @return object XML-RPC response */ function PNB_handlePingback($id, $type, $url, $oururl) { global $_CONF, $_TABLES, $PNB_ERROR; require_once 'HTTP/Request.php'; if (!isset($_CONF['check_trackback_link'])) { $_CONF['check_trackback_link'] = 2; } // handle pingbacks to articles on our own site $skip_speedlimit = false; if ($_SERVER['REMOTE_ADDR'] == $_SERVER['SERVER_ADDR']) { if (!isset($_CONF['pingback_self'])) { $_CONF['pingback_self'] = 0; // default: skip self-pingbacks } if ($_CONF['pingback_self'] == 0) { return new XML_RPC_Response(new XML_RPC_Value($PNB_ERROR['skipped'])); } elseif ($_CONF['pingback_self'] == 2) { $skip_speedlimit = true; } } COM_clearSpeedlimit($_CONF['commentspeedlimit'], 'pingback'); if (!$skip_speedlimit) { $last = COM_checkSpeedlimit('pingback'); if ($last > 0) { return new XML_RPC_Response(0, 49, sprintf($PNB_ERROR['speedlimit'], $last, $_CONF['commentspeedlimit'])); } } // update speed limit in any case COM_updateSpeedlimit('pingback'); if ($_SERVER['REMOTE_ADDR'] != $_SERVER['SERVER_ADDR']) { if ($_CONF['check_trackback_link'] & 4) { $parts = parse_url($url); if (empty($parts['host'])) { TRB_logRejected('Pingback: No valid URL', $url); return new XML_RPC_Response(0, 33, $PNB_ERROR['uri_invalid']); } else { $ip = gethostbyname($parts['host']); if ($ip != $_SERVER['REMOTE_ADDR']) { TRB_logRejected('Pingback: IP address mismatch', $url); return new XML_RPC_Response(0, 49, $PNB_ERROR['spam']); } } } } // See if we can read the page linking to us and extract at least // the page's title out of it ... $title = ''; $excerpt = ''; $http = new http_class(); $http->timeout = 0; $http->data_timeout = 0; $http->debug = 0; $http->html_debug = 0; $http->user_agent = 'glFusion/' . GVERSION; $error = $http->GetRequestArguments($url, $arguments); $error = $http->Open($arguments); $error = $http->SendRequest($arguments); if ($error == "") { $http->ReadReplyHeaders($headers); if ($http->response_status == 200) { $error = $http->ReadWholeReplyBody($body); if ($error == "" || strlen($body) > 0) { if ($_CONF['check_trackback_link'] & 3) { if (!TRB_containsBacklink($body, $oururl)) { TRB_logRejected('Pingback: No link to us', $url); $comment = TRB_formatComment($url); PLG_spamAction($comment, $_CONF['spamx']); return new XML_RPC_Response(0, 49, $PNB_ERROR['spam']); } } preg_match(':<title>(.*)</title>:i', $body, $content); if (empty($content[1])) { $title = ''; // no title found } else { $title = trim(COM_undoSpecialChars($content[1])); } if ($_CONF['pingback_excerpt']) { // Check which character set the site that sent the Pingback // is using $charset = 'ISO-8859-1'; // default, see RFC 2616, 3.7.1 $ctype = $headers['content-type']; $c = explode(';', $ctype); foreach ($c as $ct) { $ch = explode('=', trim($ct)); if (count($ch) === 2) { if (trim($ch[0]) === 'charset') { $charset = trim($ch[1]); break; } } } if (!empty($charset) && strcasecmp($charset, COM_getCharset()) !== 0) { if (function_exists('mb_convert_encoding')) { $body = @mb_convert_encoding($body, COM_getCharset(), $charset); } elseif (function_exists('iconv')) { $body = @iconv($charset, COM_getCharset(), $body); } } $excerpt = PNB_makeExcerpt($body, $oururl); } // we could also run the rest of the other site's page // through the spam filter here ... } else { COM_errorLog("Pingback verification: unable to retrieve response body"); return new XML_RPC_Response(0, 33, $PNB_ERROR['uri_invalid']); } } else { COM_errorLog("Pingback verification: Got HTTP response code " . $http->response_status . " when requesting {$url}"); return new XML_RPC_Response(0, 33, $PNB_ERROR['uri_invalid']); } } else { COM_errorLog("Pingback verification: " . $error . " when requesting " . $url); return new XML_RPC_Response(0, 33, $PNB_ERROR['uri_invalid']); } // check for spam first $saved = TRB_checkForSpam($url, $title, '', $excerpt); if ($saved == TRB_SAVE_SPAM) { return new XML_RPC_Response(0, 49, $PNB_ERROR['spam']); } // save as a trackback comment $saved = TRB_saveTrackbackComment($id, $type, $url, $title, '', $excerpt); if ($saved == TRB_SAVE_REJECT) { return new XML_RPC_Response(0, 49, $PNB_ERROR['multiple']); } if (isset($_CONF['notification']) && in_array('pingback', $_CONF['notification'])) { TRB_sendNotificationEmail($saved, 'pingback'); } return new XML_RPC_Response(new XML_RPC_Value($PNB_ERROR['success'])); }
function testAuthenticationSQLi($urlToCheck, $urlOfSite, $testId) { connectToDb($db); updateStatus($db, "Testing {$urlToCheck} for Broken Authentication using SQL Injection...", $testId); $log = new Logger(); $log->lfile('logs/eventlogs'); $log->lwrite("Starting Broken Authentication SQLi test function on {$urlToCheck}"); $postUrl = $urlToCheck; $postUrlPath = parse_url($postUrl, PHP_URL_PATH); //Check URL is not responding with 5xx codes $log->lwrite("Checking what response code is received from {$urlToCheck}"); $http = new http_class(); $http->timeout = 0; $http->data_timeout = 0; //$http->debug=1; $http->user_agent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"; $http->follow_redirect = 1; $http->redirection_limit = 5; $http->setTestId($testId); $error = $http->GetRequestArguments($urlToCheck, $arguments); $error = $http->Open($arguments); $log->lwrite("URL to be requested is: {$urlToCheck}"); if ($error == "") { $log->lwrite("Sending HTTP request to {$urlToCheck}"); $error = $http->SendRequest($arguments); if ($error == "") { $headers = array(); $error = $http->ReadReplyHeaders($headers); if ($error == "") { $responseCode = $http->response_status; //This is a string $log->lwrite("Received response code: {$responseCode}"); if (intval($responseCode) >= 500 && intval($responseCode) < 600) { $log->lwrite("Response code: {$responseCode} received from: {$urlToCheck}"); return; } } } $http->Close(); } if (strlen($error)) { echo "<H2 align=\"center\">Error: ", $error, "</H2>\n"; $log->lwrite("Error: {$error}"); } $html = file_get_html($postUrl, $testId); if (empty($html)) { //This can happen due to file_get_contents returning a 500 code. Then the parser won't parse it updateStatus($db, "Problem getting contents from {$urlToCheck}...", $testId); $log->lwrite("Problem getting contents from {$urlToCheck}"); return; } //Array containing all form objects found $arrayOfForms = array(); //Array containing all input fields $arrayOfInputFields = array(); $log->lwrite("Searching {$postUrl} for forms"); $formNum = 1; //Must use an integer to identify form as forms could have same names and ids foreach ($html->find('form') as $form) { isset($form->attr['id']) ? $formId = htmlspecialchars($form->attr['id']) : ($formId = ''); isset($form->attr['name']) ? $formName = htmlspecialchars($form->attr['name']) : ($formName = ''); isset($form->attr['method']) ? $formMethod = htmlspecialchars($form->attr['method']) : ($formMethod = 'get'); isset($form->attr['action']) ? $formAction = htmlspecialchars($form->attr['action']) : ($formAction = ''); $formMethod = strtolower($formMethod); //If the action of the form is empty, set the action equal to everything //after the URL that the user entered if (empty($formAction)) { $strLengthUrl = strlen($urlToCheck); $strLengthSite = strlen($urlOfSite); $firstIndexOfSlash = strpos($urlToCheck, '/', $strLengthSite - 1); $formAction = substr($urlToCheck, $firstIndexOfSlash + 1, $strLengthUrl); } $log->lwrite("Found form on {$postUrl}: {$formId} {$formName} {$formMethod} {$formAction} {$formNum}"); $newForm = new Form($formId, $formName, $formMethod, $formAction, $formNum); array_push($arrayOfForms, $newForm); foreach ($form->find('input') as $input) { isset($input->attr['id']) ? $inputId = htmlspecialchars($input->attr['id']) : ($inputId = ''); isset($input->attr['name']) ? $inputName = htmlspecialchars($input->attr['name']) : ($inputName = ''); isset($input->attr['value']) ? $inputValue = htmlspecialchars($input->attr['value']) : ($inputValue = ''); isset($input->attr['type']) ? $inputType = htmlspecialchars($input->attr['type']) : ($inputType = ''); $log->lwrite("Found input field on {$postUrl}: {$inputId} {$inputName} {$formId} {$formName} {$inputValue} {$inputType} {$formNum}"); $inputField = new InputField($inputId, $inputName, $formId, $formName, $inputValue, $inputType, $formNum); array_push($arrayOfInputFields, $inputField); } $formNum++; } //At this stage, we should have captured all forms and their input fields into the appropriate arrays //Begin testing each of the forms //Defintion of all payloads used and warnings to examine for //Payloads can be added to this $arrayOfPayloads = array("1'or'1'='1", "1'or'1'='1';#"); //Check if the URL passed into this function displays the same webpage at different intervals //If it does then attempt to login and if this URL displays a different page, the vulnerability is present //e.g. a login page would always look different when you are and are not logged in $log->lwrite("Checking if {$urlToCheck} displays the same page at different intervals"); $responseBodies = array(); $http = new http_class(); $http->timeout = 0; $http->data_timeout = 0; //$http->debug=1; $http->user_agent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"; $http->follow_redirect = 1; $http->redirection_limit = 5; $http->setTestId($testId); for ($a = 0; $a < 3; $a++) { $error = $http->GetRequestArguments($urlToCheck, $arguments); $error = $http->Open($arguments); if ($error == "") { $number = $a + 1; $log->lwrite("Sending HTTP request number {$number} to {$urlToCheck}"); $error = $http->SendRequest($arguments); if ($error == "") { $headers = array(); $error = $http->ReadReplyHeaders($headers); if ($error == "") { $error = $http->ReadWholeReplyBody($body); if (strlen($error) == 0) { array_push($responseBodies, $body); } } } $http->Close(); } if (strlen($error)) { echo "<H2 align=\"center\">Error: a= {$a} ", $error, "</H2>\n"; } } $pageChanges = true; $bodyOfUrl = ""; if ($responseBodies[0] == $responseBodies[1] && $responseBodies[1] == $responseBodies[2]) { $bodyOfUrl = $responseBodies[0]; $pageChanges = false; } $log->lwrite('Beginning testing of forms'); for ($i = 0; $i < sizeof($arrayOfForms); $i++) { $currentForm = $arrayOfForms[$i]; $currentFormId = $currentForm->getId(); $currentFormName = $currentForm->getName(); $currentFormMethod = $currentForm->getMethod(); $currentFormAction = $currentForm->getAction(); $currentFormNum = $currentForm->getFormNum(); $arrayOfCurrentFormsInputs = array(); $log->lwrite("Beginning testing of form on {$postUrl}: {$currentFormId} {$currentFormName} {$currentFormMethod} {$currentFormAction}"); for ($j = 0; $j < sizeof($arrayOfInputFields); $j++) { $currentInput = $arrayOfInputFields[$j]; $currentInputIdOfForm = $currentInput->getIdOfForm(); $currentInputNameOfForm = $currentInput->getNameOfForm(); $currentInputFormNum = $currentInput->getFormNum(); if ($currentFormNum == $currentInputFormNum) { array_push($arrayOfCurrentFormsInputs, $currentInput); } } $log->lwrite("Beginning testing input fields of form on {$postUrl}: {$currentFormId} {$currentFormName} {$currentFormMethod} {$currentFormAction}"); foreach ($arrayOfPayloads as $currentPayload) { echo '<br>Size of current form inputs = ' . sizeof($arrayOfCurrentFormsInputs) . '<br>'; $arrayOfValues = array(); //Array of PostOrGetObject objects for ($k = 0; $k < sizeof($arrayOfCurrentFormsInputs); $k++) { $currentFormInput = $arrayOfCurrentFormsInputs[$k]; $currentFormInputName = $currentFormInput->getName(); $currentFormInputType = $currentFormInput->getType(); $currentFormInputValue = $currentFormInput->getValue(); if ($currentFormInputType != 'reset') { $log->lwrite("Using payload: {$currentPayload}, to all input fields of form w/ action: {$currentFormAction}"); //Add current input and other inputs to array of post values and set their values if ($currentFormInputType == 'text' || $currentFormInputType == 'password') { $postObject = new PostOrGetObject($currentFormInputName, $currentPayload); array_push($arrayOfValues, $postObject); } else { if ($currentFormInputType == 'checkbox' || $currentFormInputType == 'submit') { $postObject = new PostOrGetObject($currentFormInputName, $currentFormInputValue); array_push($arrayOfValues, $postObject); } else { if ($currentFormInputType == 'radio') { $postObject = new PostOrGetObject($currentFormInputName, $currentFormInputValue); //Check if a radio button in the radio group has already been added $found = false; for ($n = 0; $n < sizeof($arrayOfValues); $n++) { if ($arrayOfValues[$n]->getName() == $postObject->getName()) { $found = true; break; } } if (!$found) { array_push($arrayOfValues, $postObject); } } } } } } if ($currentFormMethod == 'get') { //Build query string and submit it at end of URL if ($urlOfSite[strlen($urlOfSite) - 1] == '/') { $actionUrl = $urlOfSite . $currentFormAction; } else { $actionUrl = $urlOfSite . '/' . $currentFormAction; } $totalTestStr = ''; //Make a string to show the user how the vulnerability was tested for i.e. the data submitted to exploit the vulnerability for ($p = 0; $p < sizeof($arrayOfValues); $p++) { $currentPostValue = $arrayOfValues[$p]; $currentPostValueName = $currentPostValue->getName(); $currentPostValueValue = $currentPostValue->getValue(); $totalTestStr .= $currentPostValueName; $totalTestStr .= '='; $totalTestStr .= $currentPostValueValue; if ($p != sizeof($arrayOfValues) - 1) { $totalTestStr .= '&'; } } $actionUrl .= '?'; $actionUrl .= $totalTestStr; $error = $http->GetRequestArguments($actionUrl, $arguments); $error = $http->Open($arguments); $log->lwrite("URL to be requested is: {$actionUrl}"); if ($error == "") { $log->lwrite("Sending HTTP request to {$actionUrl}"); $error = $http->SendRequest($arguments); if ($error == "") { $headers = array(); $error = $http->ReadReplyHeaders($headers); if ($error == "") { $error = $http->ReadWholeReplyBody($body); if (strlen($error) == 0) { $http->Close(); $vulnerabilityFound = checkIfVulnerabilityFound($urlToCheck, $pageChanges, $bodyOfUrl, $log, $currentPayload, $http); if ($vulnerabilityFound) { $totalTestStr = ''; //Make a test string to show the user how the vulnerability was tested for for ($p = 0; $p < sizeof($arrayOfValues); $p++) { $currentPostValue = $arrayOfValues[$p]; $currentPostValueName = $currentPostValue->getName(); $currentPostValueValue = $currentPostValue->getValue(); $totalTestStr .= $currentPostValueName; $totalTestStr .= '='; $totalTestStr .= $currentPostValueValue; if ($p != sizeof($arrayOfValues) - 1) { $totalTestStr .= '&'; } } //The echo's below are for testing the function on its own i.e. requesting this script with your browser echo 'Broken Authentication Present!<br>Query: ' . HtmlSpecialChars($totalTestStr) . '<br>'; echo 'Method: ' . $currentFormMethod . '<br>'; echo 'Url: ' . HtmlSpecialChars($actionUrl) . '<br>'; echo 'Error: Successfully Logged In with SQL injection'; $tableName = 'test' . $testId; //Check if this vulnerability has already been found and added to DB. If it hasn't, add it to DB. $query = "SELECT * FROM test_results WHERE test_id = {$testId} AND type = 'basqli' AND method = '{$currentFormMethod}' AND url = '" . addslashes($actionUrl) . "' AND attack_str = '" . addslashes($totalTestStr) . "'"; $result = $db->query($query); if (!$result) { $log->lwrite("Could not execute query {$query}"); } else { $log->lwrite("Successfully executed query {$query}"); $numRows = $result->num_rows; if ($numRows == 0) { $log->lwrite("Number of rows is {$numRows} for query: {$query}"); insertTestResult($db, $testId, 'basqli', $currentFormMethod, addslashes($actionUrl), addslashes($totalTestStr)); } } break; } } } } } if (strlen($error)) { echo "<H2 align=\"center\">Error: ", $error, "</H2>\n"; echo 'Method: ' . $currentFormMethod . '<br>'; echo 'Url: ' . HtmlSpecialChars($actionUrl) . '<br>'; } } else { if ($currentFormMethod == 'post') { //Build query string and submit it at end of URL if ($urlOfSite[strlen($urlOfSite) - 1] == '/') { $actionUrl = $urlOfSite . $currentFormAction; } else { $actionUrl = $urlOfSite . '/' . $currentFormAction; } $error = $http->GetRequestArguments($actionUrl, $arguments); $arguments["RequestMethod"] = "POST"; $arguments["PostValues"] = array(); for ($p = 0; $p < sizeof($arrayOfValues); $p++) { $currentPostValue = $arrayOfValues[$p]; $currentPostValueName = $currentPostValue->getName(); $currentPostValueValue = $currentPostValue->getValue(); $tempArray = array($currentPostValueName => $currentPostValueValue); $arguments["PostValues"] = array_merge($arguments["PostValues"], $tempArray); } $error = $http->Open($arguments); $log->lwrite("URL to be requested is: {$actionUrl}"); if ($error == "") { $log->lwrite("Sending HTTP request to {$actionUrl}"); $error = $http->SendRequest($arguments); if ($error == "") { $headers = array(); $error = $http->ReadReplyHeaders($headers); if ($error == "") { $error = $http->ReadWholeReplyBody($body); if (strlen($error) == 0) { $http->Close(); $vulnerabilityFound = checkIfVulnerabilityFound($urlToCheck, $pageChanges, $bodyOfUrl, $log, $currentPayload, $http); if ($vulnerabilityFound) { $totalTestStr = ''; //Compile a test string to show the user how the vulnerability was tested for for ($p = 0; $p < sizeof($arrayOfValues); $p++) { $currentPostValue = $arrayOfValues[$p]; $currentPostValueName = $currentPostValue->getName(); $currentPostValueValue = $currentPostValue->getValue(); $totalTestStr .= $currentPostValueName; $totalTestStr .= '='; $totalTestStr .= $currentPostValueValue; if ($p != sizeof($arrayOfValues) - 1) { $totalTestStr .= '&'; } } //The echo's below are for testing the function on its own i.e. requesting this script with your browser echo 'Broken Authentication Present!<br>Query: ' . HtmlSpecialChars($totalTestStr) . '<br>'; echo 'Method: ' . $currentFormMethod . '<br>'; echo 'Url: ' . HtmlSpecialChars($actionUrl) . '<br>'; echo 'Error: Successfully Logged In with SQL injection'; $tableName = 'test' . $testId; //Check if this vulnerability has already been found and added to DB. If it hasn't, add it to DB. $query = "SELECT * FROM test_results WHERE test_id = {$testId} AND type = 'basqli' AND method = '{$currentFormMethod}' AND url = '" . addslashes($actionUrl) . "' AND attack_str = '" . addslashes($totalTestStr) . "'"; $result = $db->query($query); if (!$result) { $log->lwrite("Could not execute query {$query}"); } else { $log->lwrite("Successfully executed query {$query}"); $numRows = $result->num_rows; if ($numRows == 0) { $log->lwrite("Number of rows is {$numRows} for query: {$query}"); insertTestResult($db, $testId, 'basqli', $currentFormMethod, addslashes($actionUrl), addslashes($totalTestStr)); } } break; } } } } } if (strlen($error)) { echo "<H2 align=\"center\">Error: ", $error, "</H2>\n"; echo 'Method: ' . $currentFormMethod . '<br>'; echo 'Url: ' . HtmlSpecialChars($actionUrl) . '<br>'; } } } } } }
function SendAPIRequest($url, $method, $parameters, $oauth, $options, &$response) { $this->response_status = 0; $http = new http_class(); $http->debug = $this->debug && $this->debug_http; $http->log_debug = true; $http->sasl_authenticate = 0; $http->user_agent = $this->oauth_user_agent; $http->redirection_limit = isset($options['FollowRedirection']) ? intval($options['FollowRedirection']) : 0; $http->follow_redirect = $http->redirection_limit != 0; if ($this->debug) { $this->OutputDebug('Accessing the ' . $options['Resource'] . ' at ' . $url); } $post_files = array(); $method = strtoupper($method); $authorization = ''; $request_content_type = isset($options['RequestContentType']) ? strtolower(trim(strtok($options['RequestContentType'], ';'))) : ($method === 'POST' || isset($oauth) ? 'application/x-www-form-urlencoded' : ''); $files = isset($options['Files']) ? $options['Files'] : array(); if (count($files)) { foreach ($files as $name => $value) { if (!isset($parameters[$name])) { return $this->SetError('it was specified an file parameters named ' . $name); } $file = array(); switch (isset($value['Type']) ? $value['Type'] : 'FileName') { case 'FileName': $file['FileName'] = $parameters[$name]; break; case 'Data': $file['Data'] = $parameters[$name]; break; default: return $this->SetError($value['Type'] . ' is not a valid type for file ' . $name); } $file['Content-Type'] = isset($value['ContentType']) ? $value['ContentType'] : 'automatic/name'; $post_files[$name] = $file; } unset($parameters[$name]); if ($method !== 'POST') { $this->OutputDebug('For uploading files the method should be POST not ' . $method); $method = 'POST'; } if ($request_content_type !== 'multipart/form-data') { if (isset($options['RequestContentType'])) { return $this->SetError('the request content type for uploading files should be multipart/form-data'); } $request_content_type = 'multipart/form-data'; } } if (isset($oauth)) { if (!$this->Sign($url, $method, $parameters, $oauth, $request_content_type, count($files) !== 0, isset($options['PostValuesInURI']) && $options['PostValuesInURI'], $authorization, $post_values)) { return false; } } else { $post_values = $parameters; if (count($parameters)) { switch ($request_content_type) { case 'application/x-www-form-urlencoded': case 'multipart/form-data': case 'application/json': break; default: $first = strpos($url, '?') === false; foreach ($parameters as $name => $value) { if (GetType($value) === 'array') { foreach ($value as $index => $value) { $url .= ($first ? '?' : '&') . $name . '=' . UrlEncode($value); $first = false; } } else { $url .= ($first ? '?' : '&') . $name . '=' . UrlEncode($value); $first = false; } } } } } if (strlen($authorization) === 0 && !strcasecmp($this->access_token_type, 'Bearer')) { $authorization = 'Bearer ' . $this->access_token; } if (strlen($error = $http->GetRequestArguments($url, $arguments))) { return $this->SetError('it was not possible to open the ' . $options['Resource'] . ' URL: ' . $error); } if (strlen($error = $http->Open($arguments))) { return $this->SetError('it was not possible to open the ' . $options['Resource'] . ' URL: ' . $error); } if (count($post_files)) { $arguments['PostFiles'] = $post_files; } $arguments['RequestMethod'] = $method; switch ($request_content_type) { case 'application/x-www-form-urlencoded': case 'multipart/form-data': if (isset($options['RequestBody'])) { return $this->SetError('the request body is defined automatically from the parameters'); } $arguments['PostValues'] = $post_values; break; case 'application/json': $arguments['Headers']['Content-Type'] = $options['RequestContentType']; $arguments['Body'] = isset($options['RequestBody']) ? $options['RequestBody'] : json_encode($parameters); break; default: if (!isset($options['RequestBody'])) { if (isset($options['RequestContentType'])) { return $this->SetError('it was not specified the body value of the of the API call request'); } break; } $arguments['Headers']['Content-Type'] = $options['RequestContentType']; $arguments['Body'] = $options['RequestBody']; break; } $arguments['Headers']['Accept'] = isset($options['Accept']) ? $options['Accept'] : '*/*'; switch ($authentication = isset($options['AccessTokenAuthentication']) ? strtolower($options['AccessTokenAuthentication']) : '') { case 'basic': $arguments['Headers']['Authorization'] = 'Basic ' . base64_encode($this->client_id . ':' . ($this->get_token_with_api_key ? $this->api_key : $this->client_secret)); break; case '': if (strlen($authorization)) { $arguments['Headers']['Authorization'] = $authorization; } break; default: return $this->SetError($authentication . ' is not a supported authentication mechanism to retrieve an access token'); } if (isset($options['RequestHeaders'])) { $arguments['Headers'] = array_merge($arguments['Headers'], $options['RequestHeaders']); } if (strlen($error = $http->SendRequest($arguments)) || strlen($error = $http->ReadReplyHeaders($headers))) { $http->Close(); return $this->SetError('it was not possible to retrieve the ' . $options['Resource'] . ': ' . $error); } $error = $http->ReadWholeReplyBody($data); $http->Close(); if (strlen($error)) { return $this->SetError('it was not possible to access the ' . $options['Resource'] . ': ' . $error); } $this->response_status = intval($http->response_status); $content_type = isset($options['ResponseContentType']) ? $options['ResponseContentType'] : (isset($headers['content-type']) ? strtolower(trim(strtok($headers['content-type'], ';'))) : 'unspecified'); $content_type = preg_replace('/^(.+\\/).+\\+(.+)$/', '\\1\\2', $content_type); switch ($content_type) { case 'text/javascript': case 'application/json': if (!function_exists('json_decode')) { return $this->SetError('the JSON extension is not available in this PHP setup'); } $object = json_decode($data); switch (GetType($object)) { case 'object': if (!isset($options['ConvertObjects']) || !$options['ConvertObjects']) { $response = $object; } else { $response = array(); foreach ($object as $property => $value) { $response[$property] = $value; } } break; case 'array': $response = $object; break; default: if (!isset($object)) { return $this->SetError('it was not returned a valid JSON definition of the ' . $options['Resource'] . ' values'); } $response = $object; break; } break; case 'application/x-www-form-urlencoded': case 'text/plain': case 'text/html': parse_str($data, $response); break; case 'text/xml': if (isset($options['DecodeXMLResponse'])) { switch (strtolower($options['DecodeXMLResponse'])) { case 'simplexml': if ($this->debug) { $this->OutputDebug('Decoding XML response with simplexml'); } try { $response = @new SimpleXMLElement($data); } catch (Exception $exception) { return $this->SetError('Could not parse XML response: ' . $exception->getMessage()); } break 2; default: return $this->SetError($options['DecodeXML'] . ' is not a supported method to decode XML responses'); } } default: $response = $data; break; } if ($this->response_status >= 200 && $this->response_status < 300) { $this->access_token_error = ''; } else { $this->access_token_error = 'it was not possible to access the ' . $options['Resource'] . ': it was returned an unexpected response status ' . $http->response_status . ' Response: ' . $data; if ($this->debug) { $this->OutputDebug('Could not retrieve the OAuth access token. Error: ' . $this->access_token_error); } if (isset($options['FailOnAccessError']) && $options['FailOnAccessError']) { $this->error = $this->access_token_error; return false; } } return true; }
function testDirectoryListingEnabled($urlToScan, $siteBeingTested, $testId, $crawlUrlFlag) { connectToDb($db); updateStatus($db, "Testing for {$urlToScan} for Directory Listing enabled...", $testId); $log = new Logger(); $log->lfile('logs/eventlogs'); $log->lwrite("Testing for {$urlToScan} for Directory Listing enabled"); if ($crawlUrlFlag) { //Perform crawl again but allow images, etc. this time to capture every URL $crawlerNew =& new MyCrawler(); $crawlerNew->setURL($urlToScan); $crawlerNew->setTestId($testId); $crawlerNew->addReceiveContentType("/text\\/html/"); $crawlerNew->setCookieHandling(true); $crawlerNew->setFollowMode(3); $log->lwrite("Crawling {$urlToScan} again for all links including images, css, etc, in order to identify directories"); $crawlerNew->go(); $urlsFound = $crawlerNew->urlsFound; $logStr = sizeof($urlsFound) . ' URLs found for test: ' . $testId; $log->lwrite("All URLs found during crawl for directory listing check:"); foreach ($urlsFound as $currentUrl) { $log->lwrite($currentUrl); } $relativePathUrls = array(); foreach ($urlsFound as $currentUrl) { $currentUrl = str_replace($urlToScan, '', $currentUrl); array_push($relativePathUrls, $currentUrl); } $directories = array(); //Check if relative path contain a directory and if they do, add it to a list of directories foreach ($relativePathUrls as $relativePathUrl) { if (dirname($relativePathUrl) != '.') { $dir = dirname($relativePathUrl); if (!in_array($dir, $directories) && !empty($dir) && !strpos($dir, '?')) { array_push($directories, $dir); $log->lwrite("Found directory {$dir}"); } } } } else { $directories = array(1); } //Just need to make an array of size one so the for loop below iterates once $http = new http_class(); $http->timeout = 0; $http->data_timeout = 0; //$http->debug=1; $http->user_agent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"; $http->follow_redirect = 1; $http->redirection_limit = 5; $http->setTestId($testId); //Regular expressions that will indicate directory listing is enabled $regexs = array("/Parent Directory/", "/\\bDirectory Listing\\b.*(Tomcat|Apache)/", "/Parent directory/", "/\\bDirectory\\b/", "/[\\s<]+IMG\\s*=/"); //General foreach ($directories as $directory) { if ($crawlUrlFlag) { $testUrl = $urlToScan . $directory . '/'; } else { $testUrl = $siteBeingTested; } $error = $http->GetRequestArguments($testUrl, $arguments); $error = $http->Open($arguments); $log->lwrite("URL to be requested is: {$testUrl}"); if ($error == "") { $log->lwrite("Sending HTTP request to {$testUrl}"); $error = $http->SendRequest($arguments); if ($error == "") { $headers = array(); $error = $http->ReadReplyHeaders($headers); if ($error == "") { $responseCode = $http->response_status; //This is a string $log->lwrite("Received response code: {$responseCode}"); if (intval($responseCode) >= 200 && intval($responseCode) < 300) { $vulnerabilityFound = false; $error = $http->ReadWholeReplyBody($body); if (strlen($error) == 0) { $indicatorStr = ''; if (preg_match($regexs[0], $body)) { $vulnerabilityFound = true; $indicatorStr = $regexs[0]; } else { if (preg_match($regexs[1], $body)) { $vulnerabilityFound = true; $indicatorStr = $regexs[1]; } else { if (preg_match($regexs[2], $body)) { $vulnerabilityFound = true; $indicatorStr = $regexs[2]; } else { if (preg_match($regexs[3], $body)) { if (preg_match($regexs[4], $body)) { $vulnerabilityFound = true; $indicatorStr = $regexs[3] . ' and ' . $regexs[4]; } } } } } if ($vulnerabilityFound) { //The echo's are for testing function on its own echo '<br>Directory Listing Enabled!<br>Url: ' . $testUrl . '<br>'; echo 'Method: GET <br>'; echo 'Url Requested: ' . $testUrl . '<br>'; echo "Error: Received response code: {$responseCode} after requesting a directory and regular expression: {$indicatorStr}<br>"; $tableName = 'test' . $testId; //Check if this vulnerability has already been found and added to DB. If it hasn't, add it to DB. $query = "SELECT * FROM test_results WHERE test_id = {$testId} AND type = 'dirlist' AND method = 'get' AND url = '{$testUrl}' AND attack_str = '{$testUrl}'"; $result = $db->query($query); if (!$result) { $log->lwrite("Could not execute query {$query}"); } else { $log->lwrite("Successfully executed query {$query}"); $numRows = $result->num_rows; if ($numRows == 0) { $log->lwrite("Number of rows is {$numRows} for query: {$query}"); insertTestResult($db, $testId, 'dirlist', 'get', $testUrl, $testUrl); } } } } } } } $http->Close(); } if (strlen($error)) { echo "<H2 align=\"center\">Error: ", $error, "</H2>\n"; $log->lwrite("Error: {$error}"); } } }
function testForReflectedXSS($urlToCheck, $urlOfSite, $testId) { connectToDb($db); updateStatus($db, "Testing {$urlToCheck} for Reflected Cross-Site Scripting...", $testId); $log = new Logger(); $log->lfile('logs/eventlogs'); $log->lwrite("Starting Reflected XXS test function on {$urlToCheck}"); $postUrl = $urlToCheck; $postUrlPath = parse_url($postUrl, PHP_URL_PATH); //Check URL is not responding with 5xx codes $log->lwrite("Checking what response code is received from {$urlToCheck}"); $http = new http_class(); $http->timeout = 0; $http->data_timeout = 0; //$http->debug=1; $http->user_agent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"; $http->follow_redirect = 1; $http->redirection_limit = 5; $http->setTestId($testId); $error = $http->GetRequestArguments($urlToCheck, $arguments); $error = $http->Open($arguments); $log->lwrite("URL to be requested is: {$urlToCheck}"); if ($error == "") { $log->lwrite("Sending HTTP request to {$urlToCheck}"); $error = $http->SendRequest($arguments); if ($error == "") { $headers = array(); $error = $http->ReadReplyHeaders($headers); if ($error == "") { $responseCode = $http->response_status; //This is a string $log->lwrite("Received response code: {$responseCode}"); if (intval($responseCode) >= 500 && intval($responseCode) < 600) { $log->lwrite("Response code: {$responseCode} received from: {$urlToCheck}"); return; } } } $http->Close(); } if (strlen($error)) { echo "<H2 align=\"center\">Error: ", $error, "</H2>\n"; $log->lwrite("Error: {$error}"); } $html = file_get_html($postUrl, $testId); if (empty($html)) { //This can happen due to file_get_contents returning a 500 code. Then the parser won't parse it $log->lwrite("Problem getting contents from {$urlToCheck}"); return; } //Submit these //If adding string to this array, add a corresponding string (to look for in response), with he same index, in the array below //The response to look for can be the same as the payload or different. $payloads = array('<webvulscan>', 'javascript:alert(webvulscan)'); //Look for these in response after submitting corresponding payload $harmfulResponses = array('<webvulscan>', 'src="javascript:alert(webvulscan)"'); //First check does the URL passed into this function contain parameters and submit payloads as those parameters if it does $parsedUrl = parse_url($urlToCheck); $log->lwrite("Check if {$urlToCheck} contains parameters"); if ($parsedUrl) { if (isset($parsedUrl['query'])) { $log->lwrite("{$urlToCheck} does contain parameters"); $scheme = $parsedUrl['scheme']; $host = $parsedUrl['host']; $path = $parsedUrl['path']; $query = $parsedUrl['query']; parse_str($query, $parameters); $originalQuery = $query; $payloadIndex = 0; foreach ($payloads as $currentPayload) { $http = new http_class(); $http->timeout = 0; $http->data_timeout = 0; //$http->debug=1; $http->user_agent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"; $http->follow_redirect = 1; $http->redirection_limit = 5; $http->setTestId($testId); foreach ($parameters as $para) { $query = $originalQuery; $newQuery = str_replace($para, $currentPayload, $query); $query = $newQuery; $testUrl = $scheme . '://' . $host . $path . '?' . $query; $log->lwrite("URL to be requested is: {$testUrl}"); $error = $http->GetRequestArguments($testUrl, $arguments); $error = $http->Open($arguments); echo "<br>Sending HTTP request to " . htmlspecialchars($testUrl) . "<br>"; if ($error == "") { $log->lwrite("Sending HTTP request to {$testUrl}"); $error = $http->SendRequest($arguments); if ($error == "") { $headers = array(); $error = $http->ReadReplyHeaders($headers); if ($error == "") { $error = $http->ReadWholeReplyBody($body); if (strlen($error) == 0) { $indicatorStr = $harmfulResponses[$payloadIndex]; if (stripos($body, $indicatorStr)) { echo '<br>Reflected XSS Present!<br>Query: ' . HtmlSpecialChars($urlToCheck) . '<br>'; echo 'Method: GET <br>'; echo 'Url: ' . HtmlSpecialChars($testUrl) . '<br>'; echo 'Error: ' . htmlspecialchars($indicatorStr) . '<br>'; $tableName = 'test' . $testId; //Check if this vulnerability has already been found and added to DB. If it hasn't, add it to DB. $sql = "SELECT * FROM test_results WHERE test_id = {$testId} AND type = 'rxss' AND method = 'get' AND url = '{$testUrl}' AND attack_str = '" . addslashes($query) . "'"; $result = $db->query($sql); if (!$result) { $log->lwrite("Could not execute query {$sql}"); } else { $log->lwrite("Successfully executed query {$sql}"); $numRows = $result->num_rows; if ($numRows == 0) { $log->lwrite("Number of rows is {$numRows} for query: {$sql}"); insertTestResult($db, $testId, 'rxss', 'get', $testUrl, addslashes($query)); } } $http->Close(); break 2; } } } } $http->Close(); } if (strlen($error)) { echo "<H2 align=\"center\">Error: ", $error, "</H2>\n"; } } $payloadIndex++; } } } else { $log->lwrite("Could not parse malformed URL: {$urlToCheck}"); } //Array containing all form objects found $arrayOfForms = array(); //Array containing all input fields $arrayOfInputFields = array(); $log->lwrite("Searching {$postUrl} for forms"); $formNum = 1; //Must use an integer to identify form as forms could have same names and ids foreach ($html->find('form') as $form) { isset($form->attr['id']) ? $formId = htmlspecialchars($form->attr['id']) : ($formId = ''); isset($form->attr['name']) ? $formName = htmlspecialchars($form->attr['name']) : ($formName = ''); isset($form->attr['method']) ? $formMethod = htmlspecialchars($form->attr['method']) : ($formMethod = 'get'); isset($form->attr['action']) ? $formAction = htmlspecialchars($form->attr['action']) : ($formAction = ''); $formMethod = strtolower($formMethod); //If the action of the form is empty, set the action equal to everything //after the URL that the user entered if (empty($formAction)) { $strLengthUrl = strlen($urlToCheck); $strLengthSite = strlen($urlOfSite); $firstIndexOfSlash = strpos($urlToCheck, '/', $strLengthSite - 1); $formAction = substr($urlToCheck, $firstIndexOfSlash + 1, $strLengthUrl); } $log->lwrite("Found form on {$postUrl}: {$formId} {$formName} {$formMethod} {$formAction} {$formNum}"); $newForm = new Form($formId, $formName, $formMethod, $formAction, $formNum); array_push($arrayOfForms, $newForm); foreach ($form->find('input') as $input) { isset($input->attr['id']) ? $inputId = htmlspecialchars($input->attr['id']) : ($inputId = ''); isset($input->attr['name']) ? $inputName = htmlspecialchars($input->attr['name']) : ($inputName = ''); isset($input->attr['value']) ? $inputValue = htmlspecialchars($input->attr['value']) : ($inputValue = ''); isset($input->attr['type']) ? $inputType = htmlspecialchars($input->attr['type']) : ($inputType = ''); $log->lwrite("Found input field on {$postUrl}: {$inputId} {$inputName} {$formId} {$formName} {$inputValue} {$inputType} {$formNum}"); $inputField = new InputField($inputId, $inputName, $formId, $formName, $inputValue, $inputType, $formNum); array_push($arrayOfInputFields, $inputField); } $formNum++; } //At this stage, we should have captured all forms and their inputs into the corresponding arrays $log->lwrite('Beginning testing of forms'); for ($i = 0; $i < sizeof($arrayOfForms); $i++) { $currentForm = $arrayOfForms[$i]; $currentFormId = $currentForm->getId(); $currentFormName = $currentForm->getName(); $currentFormMethod = $currentForm->getMethod(); $currentFormAction = $currentForm->getAction(); $currentFormNum = $currentForm->getFormNum(); $arrayOfCurrentFormsInputs = array(); $log->lwrite("Beginning testing of form on {$postUrl}: {$currentFormId} {$currentFormName} {$currentFormMethod} {$currentFormAction}"); for ($j = 0; $j < sizeof($arrayOfInputFields); $j++) { $currentInput = $arrayOfInputFields[$j]; $currentInputIdOfForm = $currentInput->getIdOfForm(); $currentInputNameOfForm = $currentInput->getNameOfForm(); $currentInputFormNum = $currentInput->getFormNum(); //Check if the current input field belongs to the current form and add to array if it does if ($currentFormNum == $currentInputFormNum) { array_push($arrayOfCurrentFormsInputs, $currentInput); } } $log->lwrite("Beginning testing input fields of form on {$postUrl}: {$currentFormId} {$currentFormName} {$currentFormMethod} {$currentFormAction}"); for ($k = 0; $k < sizeof($arrayOfCurrentFormsInputs); $k++) { for ($plIndex = 0; $plIndex < sizeof($payloads); $plIndex++) { $testStr = $payloads[$plIndex]; $log->lwrite("Submitting payload: {$testStr}"); $defaultStr = 'Abc123'; $indicatorStr = $harmfulResponses[$plIndex]; $currentFormInput = $arrayOfCurrentFormsInputs[$k]; $currentFormInputName = $currentFormInput->getName(); $currentFormInputType = $currentFormInput->getType(); $currentFormInputValue = $currentFormInput->getValue(); if ($currentFormInputType != 'reset') { $http = new http_class(); $http->timeout = 0; $http->data_timeout = 0; //$http->debug=1; $http->user_agent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"; $http->follow_redirect = 1; $http->redirection_limit = 5; $http->setTestId($testId); $arrayOfValues = array(); //Array of PostOrGetObject objects //Get the other input values and set them equal to the default string $otherInputs = array(); for ($l = 0; $l < sizeof($arrayOfCurrentFormsInputs); $l++) { if ($currentFormInput->getName() != $arrayOfCurrentFormsInputs[$l]->getName()) { array_push($otherInputs, $arrayOfCurrentFormsInputs[$l]); } } $postObject = new PostOrGetObject($currentFormInputName, $testStr); //Add current input and other to array of post values and set their values array_push($arrayOfValues, $postObject); for ($m = 0; $m < sizeof($otherInputs); $m++) { $currentOther = $otherInputs[$m]; $currentOtherType = $currentOther->getType(); $currentOtherName = $currentOther->getName(); $currentOtherValue = $currentOther->getValue(); if ($currentOtherType == 'text' || $currentOtherType == 'password') { $postObject = new PostOrGetObject($currentOtherName, $defaultStr); array_push($arrayOfValues, $postObject); } else { if ($currentOtherType == 'checkbox' || $currentOtherType == 'submit') { $postObject = new PostOrGetObject($currentOtherName, $currentOtherValue); array_push($arrayOfValues, $postObject); } else { if ($currentOtherType == 'radio') { $postObject = new PostOrGetObject($currentOtherName, $currentOtherValue); //Check if a radio button in the radio group has already been added $found = false; for ($n = 0; $n < sizeof($arrayOfValues); $n++) { if ($arrayOfValues[$n]->getName() == $postObject->getName()) { $found = true; break; } } if (!$found) { array_push($arrayOfValues, $postObject); } } } } } echo '<br><br>'; if ($currentFormMethod == 'get') { //Build query string and submit it at end of URL if ($urlOfSite[strlen($urlOfSite) - 1] == '/') { $actionUrl = $urlOfSite . $currentFormAction; } else { $actionUrl = $urlOfSite . '/' . $currentFormAction; } $totalTestStr = ''; //Compile a test string to show the user how the vulnerability was tested for for ($p = 0; $p < sizeof($arrayOfValues); $p++) { $currentPostValue = $arrayOfValues[$p]; $currentPostValueName = $currentPostValue->getName(); $currentPostValueValue = $currentPostValue->getValue(); $totalTestStr .= $currentPostValueName; $totalTestStr .= '='; $totalTestStr .= $currentPostValueValue; if ($p != sizeof($arrayOfValues) - 1) { $totalTestStr .= '&'; } } if (strpos($actionUrl, '?') !== false) { //url may something like domain.com?id=111 so don't want to add another question mark if it is $actionUrl .= '&'; } else { $actionUrl .= '?'; } $actionUrl .= $totalTestStr; $error = $http->GetRequestArguments($actionUrl, $arguments); $error = $http->Open($arguments); if ($error == "") { $error = $http->SendRequest($arguments); if ($error == "") { $headers = array(); $error = $http->ReadReplyHeaders($headers); if ($error == "") { $error = $http->ReadWholeReplyBody($body); if (strlen($error) == 0) { if (stripos($body, $indicatorStr)) { //If the body that was returned from the request contains the payload, the //Reflected XSS vulnerabiltiy is present $totalTestStr = ''; //Compile a test string to show the user how the vulnerability was tested for for ($p = 0; $p < sizeof($arrayOfValues); $p++) { $currentPostValue = $arrayOfValues[$p]; $currentPostValueName = $currentPostValue->getName(); $currentPostValueValue = $currentPostValue->getValue(); $totalTestStr .= $currentPostValueName; $totalTestStr .= '='; $totalTestStr .= $currentPostValueValue; if ($p != sizeof($arrayOfValues) - 1) { $totalTestStr .= '&'; } } //The echo's are for testing/debugging the function on its own echo 'Reflected XSS Present!<br>Query: ' . HtmlSpecialChars($totalTestStr) . '<br>'; echo 'Method: ' . $currentFormMethod . '<br>'; echo 'Url: ' . HtmlSpecialChars($actionUrl) . ''; $tableName = 'test' . $testId; //Check if this vulnerability has already been found and added to DB. If it hasn't, add it to DB. $query = "SELECT * FROM test_results WHERE test_id = {$testId} AND type = 'rxss' AND method = '{$currentFormMethod}' AND url = '{$actionUrl}' AND attack_str = '{$totalTestStr}'"; $result = $db->query($query); if (!$result) { $log->lwrite("Could not execute query {$query}"); } else { $log->lwrite("Successfully executed query {$query}"); $numRows = $result->num_rows; if ($numRows == 0) { $log->lwrite("Number of rows is {$numRows} for query: {$query}"); insertTestResult($db, $testId, 'rxss', $currentFormMethod, $actionUrl, $totalTestStr); } } $http->Close(); break; } } } } $http->Close(); } if (strlen($error)) { echo "<H2 align=\"center\">Error: ", $error, "</H2>\n"; } } else { if ($currentFormMethod == 'post') { //Start sending requests with the values in the post values array //Build query string and submit it at end of URL if ($urlOfSite[strlen($urlOfSite) - 1] == '/') { $actionUrl = $urlOfSite . $currentFormAction; } else { $actionUrl = $urlOfSite . '/' . $currentFormAction; } $error = $http->GetRequestArguments($actionUrl, $arguments); $arguments["RequestMethod"] = "POST"; $arguments["PostValues"] = array(); for ($p = 0; $p < sizeof($arrayOfValues); $p++) { $currentPostValue = $arrayOfValues[$p]; $currentPostValueName = $currentPostValue->getName(); $currentPostValueValue = $currentPostValue->getValue(); $tempArray = array($currentPostValueName => $currentPostValueValue); $arguments["PostValues"] = array_merge($arguments["PostValues"], $tempArray); } $error = $http->Open($arguments); if ($error == "") { $error = $http->SendRequest($arguments); if ($error == "") { $headers = array(); $error = $http->ReadReplyHeaders($headers); if ($error == "") { $error = $http->ReadWholeReplyBody($body); if (strlen($error) == 0) { //echo $body; if (stripos($body, $indicatorStr)) { //If the body that was returned from the request contains the test string, the //Reflected XSS vulnerabiltiy is present $totalTestStr = ''; //Compile a test string to show the user how the vulnerability was tested for for ($p = 0; $p < sizeof($arrayOfValues); $p++) { $currentPostValue = $arrayOfValues[$p]; $currentPostValueName = $currentPostValue->getName(); $currentPostValueValue = $currentPostValue->getValue(); $totalTestStr .= $currentPostValueName; $totalTestStr .= '='; $totalTestStr .= $currentPostValueValue; if ($p != sizeof($arrayOfValues) - 1) { $totalTestStr .= '&'; } } //The echo's are for testing/debugging the function on its own echo 'Reflected XSS Present!<br>Query: ' . HtmlSpecialChars($totalTestStr) . '<br>'; echo 'Method: ' . $currentFormMethod . '<br>'; echo 'Url: ' . HtmlSpecialChars($actionUrl) . ''; $tableName = 'test' . $testId; //Check if this vulnerability has already been found and added to DB. If it hasn't, add it to DB. $query = "SELECT * FROM test_results WHERE test_id = {$testId} AND type = 'rxss' AND method = '{$currentFormMethod}' AND url = '{$actionUrl}' AND attack_str = '{$totalTestStr}'"; $result = $db->query($query); if (!$result) { $log->lwrite("Could not execute query {$query}"); } else { $log->lwrite("Successfully executed query {$query}"); $numRows = $result->num_rows; if ($numRows == 0) { $log->lwrite("Number of rows is {$numRows} for query: {$query}"); insertTestResult($db, $testId, 'rxss', $currentFormMethod, $actionUrl, $totalTestStr); } } $http->Close(); break; } } } } $http->Close(); } if (strlen($error)) { echo "<H2 align=\"center\">Error: ", $error, "</H2>\n"; } } } } } } } }
/** * Attempt to auto-detect the Trackback URL of a post. * * @param string $url URL of post with embedded RDF for the Trackback URL * @return mixed Trackback URL, or false on error * Note: The RDF, if found, is only parsed using a regular expression. Using * the XML parser may be more successful on some occassions ... */ function TRB_detectTrackbackUrl($url) { $retval = false; $http = new http_class(); $http->timeout = 0; $http->data_timeout = 0; $http->debug = 0; $http->html_debug = 0; $http->user_agent = 'glFusion/' . GVERSION; $error = $http->GetRequestArguments($url, $arguments); $error = $http->Open($arguments); $error = $http->SendRequest($arguments); if ($error == "") { $http->ReadReplyHeaders($headers); if ($http->response_status == 200) { $error = $http->ReadWholeReplyBody($page); if ($error != "" && strlen($body) === 0) { COM_errorLog("Trackback Detect TRB URL: unable to retrieve response body"); return false; } } else { COM_errorLog("Trackback Detect TRB URL: Got HTTP response code " . $http->response_status . " when requesting " . $url); return false; } } else { COM_errorLog("Trackback Detect TRB URL: " . $error . " when requesting " . $url); return false; } // search for the RDF first $startPos = strpos($page, '<rdf:RDF '); if ($startPos !== false) { $endPos = strpos($page, '</rdf:RDF>', $startPos); $endPos += strlen('</rdf:RDF>'); $rdf = substr($page, $startPos, $endPos - $startPos); // Okay, we COULD fire up the XML parser now. But then again ... if (preg_match('/trackback:ping="(.*)"/', $rdf, $matches) == 1) { if (!empty($matches[1])) { $retval = $matches[1]; } } } // no luck with the RDF? try searching for a rel="trackback" link if ($retval === false) { // remove all linefeeds first to help the regexp below $page = str_replace(array("\r", "\n"), '', $page); preg_match_all("/<a[^>]*href=[\"']([^\"']*)[\"'][^>]*>(.*?)<\\/a>/i", $page, $matches); for ($i = 0; $i < count($matches[0]); $i++) { $link = $matches[0][$i]; if (strpos($link, 'rel="trackback"') !== false) { $retval = $matches[1][$i]; break; } } } return $retval; }
function SendAPIRequest($url, $method, $parameters, $oauth, $options, &$response) { $this->response_status = 0; $http = new http_class(); $http->debug = $this->debug && $this->debug_http; $http->log_debug = true; $http->sasl_authenticate = 0; $http->user_agent = $this->oauth_user_agent; $http->redirection_limit = isset($options['FollowRedirection']) ? intval($options['FollowRedirection']) : 0; $http->follow_redirect = $http->redirection_limit != 0; if ($this->debug) { $this->OutputDebug('Accessing the ' . $options['Resource'] . ' at ' . $url); } $post_files = array(); $method = strtoupper($method); $authorization = ''; $type = isset($options['RequestContentType']) ? strtolower(trim(strtok($options['RequestContentType'], ';'))) : ($method === 'POST' ? 'application/x-www-form-urlencoded' : ''); if (isset($oauth)) { $values = array('oauth_consumer_key' => $this->client_id, 'oauth_nonce' => md5(uniqid(rand(), true)), 'oauth_signature_method' => $this->signature_method, 'oauth_timestamp' => time(), 'oauth_version' => '1.0'); $files = isset($options['Files']) ? $options['Files'] : array(); if (count($files)) { foreach ($files as $name => $value) { if (!isset($parameters[$name])) { return $this->SetError('it was specified an file parameters named ' . $name); } $file = array(); switch (isset($value['Type']) ? $value['Type'] : 'FileName') { case 'FileName': $file['FileName'] = $parameters[$name]; break; case 'Data': $file['Data'] = $parameters[$name]; break; default: return $this->SetError($value['Type'] . ' is not a valid type for file ' . $name); } $file['ContentType'] = isset($value['Content-Type']) ? $value['Content-Type'] : 'automatic/name'; $post_files[$name] = $file; } unset($parameters[$name]); if ($method !== 'POST') { $this->OutputDebug('For uploading files the method should be POST not ' . $method); $method = 'POST'; } if ($type !== 'multipart/form-data') { if (isset($options['RequestContentType'])) { return $this->SetError('the request content type for uploading files should be multipart/form-data'); } $type = 'multipart/form-data'; } $value_parameters = array(); } else { if ($this->url_parameters && $type === 'application/x-www-form-urlencoded' && count($parameters)) { $first = strpos($url, '?') === false; foreach ($parameters as $parameter => $value) { $url .= ($first ? '?' : '&') . UrlEncode($parameter) . '=' . UrlEncode($value); $first = false; } $parameters = array(); } $value_parameters = $type !== 'application/x-www-form-urlencoded' ? array() : $parameters; } $values = array_merge($values, $oauth, $value_parameters); $key = $this->Encode($this->client_secret) . '&' . $this->Encode($this->access_token_secret); switch ($this->signature_method) { case 'PLAINTEXT': $values['oauth_signature'] = $key; break; case 'HMAC-SHA1': $uri = strtok($url, '?'); $sign = $method . '&' . $this->Encode($uri) . '&'; $first = true; $sign_values = $values; $u = parse_url($url); if (isset($u['query'])) { parse_str($u['query'], $q); foreach ($q as $parameter => $value) { $sign_values[$parameter] = $value; } } KSort($sign_values); foreach ($sign_values as $parameter => $value) { $sign .= $this->Encode(($first ? '' : '&') . $parameter . '=' . $this->Encode($value)); $first = false; } $values['oauth_signature'] = base64_encode($this->HMAC('sha1', $sign, $key)); break; default: return $this->SetError($this->signature_method . ' signature method is not yet supported'); } if ($this->authorization_header) { $authorization = 'OAuth'; $first = true; foreach ($values as $parameter => $value) { $authorization .= ($first ? ' ' : ',') . $parameter . '="' . $this->Encode($value) . '"'; $first = false; } $post_values = $parameters; } else { if ($method === 'GET' || isset($options['PostValuesInURI']) && $options['PostValuesInURI']) { $first = strcspn($url, '?') == strlen($url); foreach ($values as $parameter => $value) { $url .= ($first ? '?' : '&') . $parameter . '=' . $this->Encode($value); $first = false; } $post_values = array(); } else { $post_values = $values; } } } else { $post_values = $parameters; if (count($parameters)) { switch ($type) { case 'application/x-www-form-urlencoded': case 'multipart/form-data': case 'application/json': break; default: $first = strpos($url, '?') === false; foreach ($parameters as $name => $value) { $url .= ($first ? '?' : '&') . $name . '=' . UrlEncode($value); $first = false; } } } } if (strlen($authorization) === 0 && !strcasecmp($this->access_token_type, 'Bearer')) { $authorization = 'Bearer ' . $this->access_token; } if (strlen($error = $http->GetRequestArguments($url, $arguments))) { return $this->SetError('it was not possible to open the ' . $options['Resource'] . ' URL: ' . $error); } if (strlen($error = $http->Open($arguments))) { return $this->SetError('it was not possible to open the ' . $options['Resource'] . ' URL: ' . $error); } if (count($post_files)) { $arguments['PostFiles'] = $post_files; } $arguments['RequestMethod'] = $method; switch ($type) { case 'application/x-www-form-urlencoded': case 'multipart/form-data': if (isset($options['RequestBody'])) { return $this->SetError('the request body is defined automatically from the parameters'); } $arguments['PostValues'] = $post_values; break; case 'application/json': $arguments['Headers']['Content-Type'] = $options['RequestContentType']; if (!isset($options['RequestBody'])) { $arguments['Body'] = json_encode($parameters); break; } if (!isset($options['RequestBody'])) { return $this->SetError('it was not specified the body value of the of the API call request'); } $arguments['Headers']['Content-Type'] = $options['RequestContentType']; $arguments['Body'] = $options['RequestBody']; break; } $arguments['Headers']['Accept'] = isset($options['Accept']) ? $options['Accept'] : '*/*'; switch (isset($options['AccessTokenAuthentication']) ? strtolower($options['AccessTokenAuthentication']) : '') { case 'basic': $arguments['Headers']['Authorization'] = 'Basic ' . base64_encode($this->client_id . ':' . ($this->get_token_with_api_key ? $this->api_key : $this->client_secret)); break; case '': if (strlen($authorization)) { $arguments['Headers']['Authorization'] = $authorization; } break; default: return $this->SetError($this->access_token_authentication . ' is not a supported authentication mechanism to retrieve an access token'); } if (strlen($error = $http->SendRequest($arguments)) || strlen($error = $http->ReadReplyHeaders($headers))) { $http->Close(); return $this->SetError('it was not possible to retrieve the ' . $options['Resource'] . ': ' . $error); } $error = $http->ReadWholeReplyBody($data); $http->Close(); if (strlen($error)) { return $this->SetError('it was not possible to access the ' . $options['Resource'] . ': ' . $error); } $this->response_status = intval($http->response_status); $content_type = isset($options['ResponseContentType']) ? $options['ResponseContentType'] : (isset($headers['content-type']) ? strtolower(trim(strtok($headers['content-type'], ';'))) : 'unspecified'); switch ($content_type) { case 'text/javascript': case 'application/json': if (!function_exists('json_decode')) { return $this->SetError('the JSON extension is not available in this PHP setup'); } $object = json_decode($data); switch (GetType($object)) { case 'object': if (!isset($options['ConvertObjects']) || !$options['ConvertObjects']) { $response = $object; } else { $response = array(); foreach ($object as $property => $value) { $response[$property] = $value; } } break; case 'array': $response = $object; break; default: if (!isset($object)) { return $this->SetError('it was not returned a valid JSON definition of the ' . $options['Resource'] . ' values'); } $response = $object; break; } break; case 'application/x-www-form-urlencoded': case 'text/plain': case 'text/html': parse_str($data, $response); break; default: $response = $data; break; } if ($this->response_status >= 200 && $this->response_status < 300) { $this->access_token_error = ''; } else { $this->access_token_error = 'it was not possible to access the ' . $options['Resource'] . ': it was returned an unexpected response status ' . $http->response_status . ' Response: ' . $data; if ($this->debug) { $this->OutputDebug('Could not retrieve the OAuth access token. Error: ' . $this->access_token_error); } if (isset($options['FailOnAccessError']) && $options['FailOnAccessError']) { $this->error = $this->access_token_error; return false; } } return true; }
function testUnvalidatedRedirects($arrayOfUrls, $testId) { connectToDb($db); updateStatus($db, "Testing all URLs for Unvalidated Redirects...", $testId); $log = new Logger(); $log->lfile('logs/eventlogs'); $log->lwrite("Starting Unvalidated Redirects test function on all URLs"); $http = new http_class(); $http->timeout = 0; $http->data_timeout = 0; //$http->debug=1; $http->user_agent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"; $http->follow_redirect = 0; $http->setTestId($testId); //Identify which URLs, if any, cause redirects $log->lwrite("Identifying which URLs, if any, cause redirects"); updateStatus($db, "Identifying which URLs, if any, cause redirects...", $testId); $potentiallyVulnUrls = array(); foreach ($arrayOfUrls as $currentUrl) { $error = $http->GetRequestArguments($currentUrl, $arguments); $error = $http->Open($arguments); $log->lwrite("URL to be requested is: {$currentUrl}"); if ($error == "") { $log->lwrite("Sending HTTP request to {$currentUrl}"); $error = $http->SendRequest($arguments); if ($error == "") { $headers = array(); $error = $http->ReadReplyHeaders($headers); if ($error == "") { $responseCode = $http->response_status; //This is a string $log->lwrite("Received response code: {$responseCode}"); if (intval($responseCode) >= 300 && intval($responseCode) < 400) { array_push($potentiallyVulnUrls, $currentUrl); } } } $http->Close(); } if (strlen($error)) { echo "<H2 align=\"center\">Error: ", $error, "</H2>\n"; $log->lwrite("Error: {$error}"); } } $log->lwrite("Potentially Vulnerable URLs:"); foreach ($potentiallyVulnUrls as $currentUrl) { $log->lwrite("{$currentUrl}"); } updateStatus($db, "Beginning testing each potentially vulnerable URL for unvalidated redirects ...", $testId); $redirectDomain = 'www.whatismyip.com'; foreach ($potentiallyVulnUrls as $currentUrl) { updateStatus($db, "Testing {$currentUrl} for Unvalidated Redirects...", $testId); $log->lwrite("Testing {$currentUrl} for unvalidated redirects"); echo "<br>Testing: {$currentUrl} <br>"; $parsedUrl = parse_url($currentUrl); $query = $parsedUrl['query']; $parameters = array(); parse_str($query, $parameters); $newQuery = ''; $query = urldecode($query); $originalQuery = $query; if ($parsedUrl) { foreach ($parameters as $para) { $query = $originalQuery; if (stripos($para, 'http') || stripos($para, 'www')) { if (stripos($para, 'http') === 0) { $newRedirectDomain = 'http://' . $redirectDomain; $newQuery = str_replace($para, $newRedirectDomain, $query); $query = $newQuery; $newRedirectDomain = ''; } else { if (stripos($para, 'www') === 0 && !strpos($para, 'http') === 0) { $newQuery = str_replace($para, $redirectDomain, $query); $query = $newQuery; } } } else { $newRedirectDomain = 'http://' . $redirectDomain; $newQuery = str_replace($para, $newRedirectDomain, $query); $query = $newQuery; $newRedirectDomain = ''; } $scheme = $parsedUrl['scheme']; $host = $parsedUrl['host']; $path = $parsedUrl['path']; $testUrl = $scheme . '://' . $host . $path . '?' . $newQuery; $log->lwrite("URL to be requested is: {$testUrl}"); $error = $http->GetRequestArguments($testUrl, $arguments); $error = $http->Open($arguments); if ($error == "") { $log->lwrite("Sending HTTP request to {$testUrl}"); $error = $http->SendRequest($arguments); if ($error == "") { $headers = array(); $error = $http->ReadReplyHeaders($headers); if ($error == "") { $error = $http->ReadWholeReplyBody($body); if (strlen($error) == 0) { //Check if the location in the HTTP response is the URL added as a parameter //If it is this would cause the browser to redirect to the parameter, therefore the vulnerability is present echo 'Location header is ' . $headers['location'] . '<br>'; $redirectTarget = $headers['location']; if (strpos($redirectTarget, $redirectDomain) || $redirectTarget == $redirectDomain) { //The echo's here are for testing/debugging the function on its own echo '<br>Unvalidated Redirects Present!<br>Url: ' . $currentUrl . '<br>'; echo 'Method: GET <br>'; echo 'Url Requested: ' . $testUrl . '<br>'; echo 'Error: Successfully Redirected to www.whatsmyip.com<br>'; $tableName = 'test' . $testId; //Check if this vulnerability has already been found and added to DB. If it hasn't, add it to DB. $query = "SELECT * FROM test_results WHERE test_id = {$testId} AND type = 'unredir' AND method = 'get' AND url = '{$currentUrl}' AND attack_str = '{$testUrl}'"; $result = $db->query($query); if (!$result) { $log->lwrite("Could not execute query {$query}"); } else { $log->lwrite("Successfully executed query {$query}"); $numRows = $result->num_rows; if ($numRows == 0) { $log->lwrite("Number of rows is {$numRows} for query: {$query}"); insertTestResult($db, $testId, 'unredir', 'get', $currentUrl, $testUrl); } } $http->Close(); break; } } } } $http->Close(); } if (strlen($error)) { echo "<H2 align=\"center\">Error: ", $error, "</H2>\n"; } } } else { $log->lwrite("Could not parse malformed URL: {$currentUrl}"); } } }
function testForSQLi($urlToCheck, $urlOfSite, $testId) { connectToDb($db); updateStatus($db, "Testing {$urlToCheck} for SQL Injection...", $testId); $log = new Logger(); $log->lfile('logs/eventlogs'); $log->lwrite("Starting SQL Injection test function on {$urlToCheck}"); $postUrl = $urlToCheck; $postUrlPath = parse_url($postUrl, PHP_URL_PATH); //Check URL is not responding with 5xx codes $log->lwrite("Checking what response code is received from {$urlToCheck}"); $http = new http_class(); $http->timeout = 0; $http->data_timeout = 0; //$http->debug=1; $http->user_agent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"; $http->follow_redirect = 1; $http->redirection_limit = 5; $http->setTestId($testId); $error = $http->GetRequestArguments($urlToCheck, $arguments); $error = $http->Open($arguments); $log->lwrite("URL to be requested is: {$urlToCheck}"); if ($error == "") { $log->lwrite("Sending HTTP request to {$urlToCheck}"); $error = $http->SendRequest($arguments); if ($error == "") { $headers = array(); $error = $http->ReadReplyHeaders($headers); if ($error == "") { $responseCode = $http->response_status; //This is a string $log->lwrite("Received response code: {$responseCode}"); if (intval($responseCode) >= 500 && intval($responseCode) < 600) { $log->lwrite("Response code: {$responseCode} received from: {$urlToCheck}"); return; } } } $http->Close(); } if (strlen($error)) { echo "<H2 align=\"center\">Error: ", $error, "</H2>\n"; $log->lwrite("Error: {$error}"); } $html = file_get_html($postUrl, $testId); if (empty($html)) { //This can happen due to file_get_contents returning a 500 code. Then the parser won't parse it updateStatus($db, "Problem getting contents from {$urlToCheck}...", $testId); $log->lwrite("Problem getting contents from {$urlToCheck}"); return; } $log->lwrite("Successfully got contents from {$urlToCheck}"); //Defintion of all payloads used and warnings to examine for $arrayOfPayloads = array("'", '"', ';', ')', '(', '.', '--'); //specified in webfuzz library (lib.webfuzz.js) from WebSecurify //From lib.webfuzz, some added by myself //The function checks for these errors after a payload is submitted $arrayOfSQLWarnings = array("supplied argument is not a valid MySQL", "mysql_fetch_array\\(\\)", "on MySQL result index", "You have an error in your SQL syntax;", "You have an error in your SQL syntax near", "MySQL server version for the right syntax to use", "\\[MySQL\\]\\[ODBC", "Column count doesn't match", "the used select statements have different number of columns", "Table '[^']+' doesn't exist", "DB Error: unknown error", ":[\\s]*mysql", "mysql_fetch", "System\\.Data\\.OleDb\\.OleDbException", "\\[SQL Server\\]", "\\[Microsoft\\]\\[ODBC SQL Server Driver\\]", "\\[SQLServer JDBC Driver\\]", "\\[SqlException", "System.Data.SqlClient.SqlException", "Unclosed quotation mark after the character string", "'80040e14'", "mssql_query\\(\\)", "odbc_exec\\(\\)", "Microsoft OLE DB Provider for ODBC Drivers", "Microsoft OLE DB Provider for SQL Server", "Incorrect syntax near", "Syntax error in string in query expression", "ADODB\\.Field \\(0x800A0BCD\\)<br>", "Procedure '[^']+' requires parameter '[^']+'", "ADODB\\.Recordset'", "Microsoft SQL Native Client error", "Unclosed quotation mark after the character string", "SQLCODE", "DB2 SQL error:", "SQLSTATE", "Sybase message:", "Syntax error in query expression", "Data type mismatch in criteria expression.", "Microsoft JET Database Engine", "\\[Microsoft\\]\\[ODBC Microsoft Access Driver\\]", "(PLS|ORA)-[0-9][0-9][0-9][0-9]", "PostgreSQL query failed:", "supplied argument is not a valid PostgreSQL result", "pg_query\\(\\) \\[:", "pg_exec\\(\\) \\[:", "com\\.informix\\.jdbc", "Dynamic Page Generation Error:", "Dynamic SQL Error", "\\[DM_QUERY_E_SYNTAX\\]", "has occurred in the vicinity of:", "A Parser Error \\(syntax error\\)", "java\\.sql\\.SQLException", "\\[Macromedia\\]\\[SQLServer JDBC Driver\\]"); //First check does the URL passed into this function contain parameters and submit payloads as those parameters if it does $parsedUrl = parse_url($urlToCheck); $log->lwrite("Check if {$urlToCheck} contains parameters"); if ($parsedUrl) { if (isset($parsedUrl['query'])) { $log->lwrite("{$urlToCheck} does contain parameters"); $scheme = $parsedUrl['scheme']; $host = $parsedUrl['host']; $path = $parsedUrl['path']; $query = $parsedUrl['query']; parse_str($query, $parameters); $originalQuery = $query; foreach ($arrayOfPayloads as $currentPayload) { $http = new http_class(); $http->timeout = 0; $http->data_timeout = 0; //$http->debug=1; $http->user_agent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"; $http->follow_redirect = 1; $http->redirection_limit = 5; $http->setTestId($testId); foreach ($parameters as $para) { $query = $originalQuery; $newQuery = str_replace($para, $currentPayload, $query); $query = $newQuery; $testUrl = $scheme . '://' . $host . $path . '?' . $query; $log->lwrite("URL to be requested is: {$testUrl}"); $error = $http->GetRequestArguments($testUrl, $arguments); $error = $http->Open($arguments); if ($error == "") { $log->lwrite("Sending HTTP request to {$testUrl}"); $error = $http->SendRequest($arguments); if ($error == "") { $headers = array(); $error = $http->ReadReplyHeaders($headers); if ($error == "") { $error = $http->ReadWholeReplyBody($body); if (strlen($error) == 0) { $vulnerabilityFound = false; for ($warningIndex = 0; $warningIndex < sizeof($arrayOfSQLWarnings); $warningIndex++) { $regularExpression = "/{$arrayOfSQLWarnings[$warningIndex]}/"; if (preg_match($regularExpression, $body)) { $log->lwrite("Found regular expression: {$regularExpression}, in body of HTTP response"); $vulnerabilityFound = true; break; } } if ($vulnerabilityFound) { echo '<br>SQL Injection Present!<br>Query: ' . HtmlSpecialChars($urlToCheck) . '<br>'; echo 'Method: GET <br>'; echo 'Url: ' . HtmlSpecialChars($testUrl) . '<br>'; echo 'Error: ' . $regularExpression . '<br>'; $tableName = 'test' . $testId; //Check if this vulnerability has already been found and added to DB. If it hasn't, add it to DB. $sql = "SELECT * FROM test_results WHERE test_id = {$testId} AND type = 'sqli' AND method = 'get' AND url = '" . addslashes($testUrl) . "' AND attack_str = '" . addslashes($query) . "'"; $result = $db->query($sql); if (!$result) { $log->lwrite("Could not execute query {$sql}"); } else { $log->lwrite("Successfully executed query {$sql}"); $numRows = $result->num_rows; if ($numRows == 0) { $log->lwrite("Number of rows is {$numRows} for query: {$sql}"); insertTestResult($db, $testId, 'sqli', 'get', addslashes($testUrl), addslashes($query)); } $result->free(); } $http->Close(); break 2; } } } } $http->Close(); } if (strlen($error)) { echo "<H2 align=\"center\">Error: ", $error, "</H2>\n"; } } } } } else { $log->lwrite("Could not parse malformed URL: {$urlToCheck}"); } //Array containing all form objects found $arrayOfForms = array(); //Array containing all input fields $arrayOfInputFields = array(); $log->lwrite("Searching {$postUrl} for forms"); $formNum = 1; //Must use an integer to identify form as forms could have same names and ids foreach ($html->find('form') as $form) { isset($form->attr['id']) ? $formId = htmlspecialchars($form->attr['id']) : ($formId = ''); isset($form->attr['name']) ? $formName = htmlspecialchars($form->attr['name']) : ($formName = ''); isset($form->attr['method']) ? $formMethod = htmlspecialchars($form->attr['method']) : ($formMethod = 'get'); isset($form->attr['action']) ? $formAction = htmlspecialchars($form->attr['action']) : ($formAction = ''); $formMethod = strtolower($formMethod); //If the action of the form is empty, set the action equal to everything //after the URL that the user entered if (empty($formAction)) { $strLengthUrl = strlen($urlToCheck); $strLengthSite = strlen($urlOfSite); $firstIndexOfSlash = strpos($urlToCheck, '/', $strLengthSite - 1); $formAction = substr($urlToCheck, $firstIndexOfSlash + 1, $strLengthUrl); } $log->lwrite("Found form on {$postUrl}: {$formId} {$formName} {$formMethod} {$formAction} {$formNum}"); $newForm = new Form($formId, $formName, $formMethod, $formAction, $formNum); array_push($arrayOfForms, $newForm); foreach ($form->find('input') as $input) { isset($input->attr['id']) ? $inputId = htmlspecialchars($input->attr['id']) : ($inputId = ''); isset($input->attr['name']) ? $inputName = htmlspecialchars($input->attr['name']) : ($inputName = ''); isset($input->attr['value']) ? $inputValue = htmlspecialchars($input->attr['value']) : ($inputValue = ''); isset($input->attr['type']) ? $inputType = htmlspecialchars($input->attr['type']) : ($inputType = ''); $log->lwrite("Found input field on {$postUrl}: {$inputId} {$inputName} {$formId} {$formName} {$inputValue} {$inputType} {$formNum}"); $inputField = new InputField($inputId, $inputName, $formId, $formName, $inputValue, $inputType, $formNum); array_push($arrayOfInputFields, $inputField); } $formNum++; } //Begin testing each of the forms $log->lwrite('Beginning testing of forms'); for ($i = 0; $i < sizeof($arrayOfForms); $i++) { $currentForm = $arrayOfForms[$i]; $currentFormId = $currentForm->getId(); $currentFormName = $currentForm->getName(); $currentFormMethod = $currentForm->getMethod(); $currentFormAction = $currentForm->getAction(); $currentFormNum = $currentForm->getFormNum(); $arrayOfCurrentFormsInputs = array(); $log->lwrite("Beginning testing of form on {$postUrl}: {$currentFormId} {$currentFormName} {$currentFormMethod} {$currentFormAction}"); echo sizeof($arrayOfInputFields) . "<br>"; for ($j = 0; $j < sizeof($arrayOfInputFields); $j++) { $currentInput = $arrayOfInputFields[$j]; $currentInputIdOfForm = $currentInput->getIdOfForm(); $currentInputNameOfForm = $currentInput->getNameOfForm(); $currentInputFormNum = $currentInput->getFormNum(); //Check if the current input field belongs to the current form and add to array if it does if ($currentFormNum == $currentInputFormNum) { array_push($arrayOfCurrentFormsInputs, $currentInput); } } $log->lwrite("Beginning testing input fields of form on {$postUrl}: {$currentFormId} {$currentFormName} {$currentFormMethod} {$currentFormAction}"); for ($k = 0; $k < sizeof($arrayOfCurrentFormsInputs); $k++) { echo sizeof($arrayOfCurrentFormsInputs) . '<br>'; for ($plIndex = 0; $plIndex < sizeof($arrayOfPayloads); $plIndex++) { $currentFormInput = $arrayOfCurrentFormsInputs[$k]; $currentFormInputName = $currentFormInput->getName(); $currentFormInputType = $currentFormInput->getType(); $currentFormInputValue = $currentFormInput->getValue(); if ($currentFormInputType != 'reset') { $http = new http_class(); $http->timeout = 0; $http->data_timeout = 0; //$http->debug=1; $http->user_agent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"; $http->follow_redirect = 1; $http->redirection_limit = 5; $http->setTestId($testId); $defaultStr = 'Abc123'; $arrayOfValues = array(); //Array of PostOrGetObject objects //Get the other input values and set them equal to the default string $otherInputs = array(); for ($l = 0; $l < sizeof($arrayOfCurrentFormsInputs); $l++) { if ($currentFormInput->getName() != $arrayOfCurrentFormsInputs[$l]->getName()) { array_push($otherInputs, $arrayOfCurrentFormsInputs[$l]); } } $postObject = new PostOrGetObject($currentFormInputName, $arrayOfPayloads[$plIndex]); $log->lwrite("Submitting payload: {$arrayOfPayloads[$plIndex]}, to input field: {$currentFormInputName}"); //Add current input and other to array of post values and set their values array_push($arrayOfValues, $postObject); for ($m = 0; $m < sizeof($otherInputs); $m++) { $currentOther = $otherInputs[$m]; $currentOtherType = $currentOther->getType(); $currentOtherName = $currentOther->getName(); $currentOtherValue = $currentOther->getValue(); if ($currentOtherType == 'text' || $currentOtherType == 'password') { $postObject = new PostOrGetObject($currentOtherName, $defaultStr); array_push($arrayOfValues, $postObject); } else { if ($currentOtherType == 'checkbox' || $currentOtherType == 'submit') { $postObject = new PostOrGetObject($currentOtherName, $currentOtherValue); array_push($arrayOfValues, $postObject); } else { if ($currentOtherType == 'radio') { $postObject = new PostOrGetObject($currentOtherName, $currentOtherValue); //Check if a radio button in the radio group has already been added $found = false; for ($n = 0; $n < sizeof($arrayOfValues); $n++) { if ($arrayOfValues[$n]->getName() == $postObject->getName()) { $found = true; break; } } if (!$found) { array_push($arrayOfValues, $postObject); } } } } } echo '<br><br>'; if ($currentFormMethod == 'get') { //Build query string and submit it at end of URL if ($urlOfSite[strlen($urlOfSite) - 1] == '/') { $actionUrl = $urlOfSite . $currentFormAction; } else { $actionUrl = $urlOfSite . '/' . $currentFormAction; } $totalTestStr = ''; //Compile a test string to show the user how the vulnerability was tested for for ($p = 0; $p < sizeof($arrayOfValues); $p++) { $currentPostValue = $arrayOfValues[$p]; $currentPostValueName = $currentPostValue->getName(); $currentPostValueValue = $currentPostValue->getValue(); $totalTestStr .= $currentPostValueName; $totalTestStr .= '='; $totalTestStr .= $currentPostValueValue; if ($p != sizeof($arrayOfValues) - 1) { $totalTestStr .= '&'; } } if (strpos($actionUrl, '?') !== false) { //url may be something like domain.com?id=111 so don't want to add another question mark if it is $actionUrl .= '&'; } else { $actionUrl .= '?'; } $actionUrl .= $totalTestStr; $error = $http->GetRequestArguments($actionUrl, $arguments); $error = $http->Open($arguments); $log->lwrite("URL to be requested is: {$actionUrl}"); if ($error == "") { $log->lwrite("Sending HTTP request to {$actionUrl}"); $error = $http->SendRequest($arguments); if ($error == "") { $headers = array(); $error = $http->ReadReplyHeaders($headers); if ($error == "") { $error = $http->ReadWholeReplyBody($body); if (strlen($error) == 0) { $vulnerabilityFound = false; for ($warningIndex = 0; $warningIndex < sizeof($arrayOfSQLWarnings); $warningIndex++) { $regularExpression = "/{$arrayOfSQLWarnings[$warningIndex]}/"; if (preg_match($regularExpression, $body)) { $log->lwrite("Found regular expression: {$regularExpression}, in body of HTTP response"); $vulnerabilityFound = true; break; } } if ($vulnerabilityFound) { //If the body returned from the request contains ones of the errors, the //SQL Injection vulnerabiltiy is present $totalTestStr = ''; //Compile a test string to show the user how the vulnerability was tested for for ($p = 0; $p < sizeof($arrayOfValues); $p++) { $currentPostValue = $arrayOfValues[$p]; $currentPostValueName = $currentPostValue->getName(); $currentPostValueValue = $currentPostValue->getValue(); $totalTestStr .= $currentPostValueName; $totalTestStr .= '='; $totalTestStr .= $currentPostValueValue; if ($p != sizeof($arrayOfValues) - 1) { $totalTestStr .= '&'; } } $currentFormMethod = strtolower($currentFormMethod); echo 'SQL Injection Present!<br>Query: ' . HtmlSpecialChars($totalTestStr) . '<br>'; echo 'Method: ' . $currentFormMethod . '<br>'; echo 'Url: ' . HtmlSpecialChars($actionUrl) . '<br>'; echo 'Error: ' . $regularExpression . ''; $tableName = 'test' . $testId; //Check if this vulnerability has already been found and added to DB. If it hasn't, add it to DB. $query = "SELECT * FROM test_results WHERE test_id = {$testId} AND type = 'sqli' AND method = '{$currentFormMethod}' AND url = '" . addslashes($actionUrl) . "' AND attack_str = '" . addslashes($totalTestStr) . "'"; $result = $db->query($query); if (!$result) { $log->lwrite("Could not execute query {$query}"); } else { $log->lwrite("Successfully executed query {$query}"); $numRows = $result->num_rows; if ($numRows == 0) { $log->lwrite("Number of rows is {$numRows} for query: {$query}"); insertTestResult($db, $testId, 'sqli', $currentFormMethod, addslashes($actionUrl), addslashes($totalTestStr)); } $result->free(); } $http->Close(); break; } } } } $http->Close(); } if (strlen($error)) { echo "<H2 align=\"center\">Error: ", $error, "</H2>\n"; } } else { if ($currentFormMethod == 'post') { //Start sending requests with the values in the post values array //Build query string and submit it at end of URL if ($urlOfSite[strlen($urlOfSite) - 1] == '/') { $actionUrl = $urlOfSite . $currentFormAction; } else { $actionUrl = $urlOfSite . '/' . $currentFormAction; } $error = $http->GetRequestArguments($actionUrl, $arguments); $arguments["RequestMethod"] = "POST"; $arguments["PostValues"] = array(); for ($p = 0; $p < sizeof($arrayOfValues); $p++) { $currentPostValue = $arrayOfValues[$p]; $currentPostValueName = $currentPostValue->getName(); $currentPostValueValue = $currentPostValue->getValue(); $tempArray = array($currentPostValueName => $currentPostValueValue); $arguments["PostValues"] = array_merge($arguments["PostValues"], $tempArray); } $error = $http->Open($arguments); $log->lwrite("URL to be requested is: {$actionUrl}"); if ($error == "") { $log->lwrite("Sending HTTP request to {$actionUrl}"); $error = $http->SendRequest($arguments); if ($error == "") { $headers = array(); $error = $http->ReadReplyHeaders($headers); if ($error == "") { $error = $http->ReadWholeReplyBody($body); if (strlen($error) == 0) { $vulnerabilityFound = false; for ($warningIndex = 0; $warningIndex < sizeof($arrayOfSQLWarnings); $warningIndex++) { $regularExpression = "/{$arrayOfSQLWarnings[$warningIndex]}/"; if (preg_match($regularExpression, $body)) { $log->lwrite("Found regular expression: {$regularExpression}, in body of HTTP response"); $vulnerabilityFound = true; break; } } if ($vulnerabilityFound) { //If the body returned from the request contains one of the errors specified, the //SQL Injection vulnerabiltiy is present $totalTestStr = ''; //Compile a test string to show the user how the vulnerability was tested for for ($p = 0; $p < sizeof($arrayOfValues); $p++) { $currentPostValue = $arrayOfValues[$p]; $currentPostValueName = $currentPostValue->getName(); $currentPostValueValue = $currentPostValue->getValue(); $totalTestStr .= $currentPostValueName; $totalTestStr .= '='; $totalTestStr .= $currentPostValueValue; if ($p != sizeof($arrayOfValues) - 1) { $totalTestStr .= '&'; } } $currentFormMethod = strtolower($currentFormMethod); echo 'SQL Injection Present!<br>Query: ' . HtmlSpecialChars($totalTestStr) . '<br>'; echo 'Method: ' . $currentFormMethod . '<br>'; echo 'Url: ' . HtmlSpecialChars($actionUrl) . '<br>'; echo 'Error: ' . $regularExpression . ''; $tableName = 'test' . $testId; //Check if this vulnerability has already been found and added to DB. If it hasn't, add it to DB. $query = "SELECT * FROM test_results WHERE test_id = {$testId} AND type = 'sqli' AND method = '{$currentFormMethod}' AND url = '{$actionUrl}' AND attack_str = '" . addslashes($totalTestStr) . "'"; $result = $db->query($query); if (!$result) { $log->lwrite("Could not execute query {$query}"); } else { $log->lwrite("Successfully executed query {$query}"); $numRows = $result->num_rows; if ($numRows == 0) { $log->lwrite("Number of rows is {$numRows} for query: {$query}"); insertTestResult($db, $testId, 'sqli', $currentFormMethod, $actionUrl, addslashes($totalTestStr)); } $result->free(); } $http->Close(); break; } } } } $http->Close(); } if (strlen($error)) { echo "<H2 align=\"center\">Error: ", $error, "</H2>\n"; } } } } } } } }