function page_xss_injector() {
for($i=0;$i<2;$i++) {
// Extract the forms url and id
$form_details =
db_fetch_array(db_query("SELECT f.id,l.path FROM {crawler_forms} f INNER JOIN {crawler_links} l ON f.page_id = l.id WHERE status = 2 LIMIT 1"));
// Visit that url
$obj = new drupal_security_scanner_test();
$session_cookie =
variable_get('security_scanner_cookie',
'');
$obj->
curl_options =
array(
CURLOPT_COOKIE => $session_cookie,
);
//$obj->drupalGet($form_details['path']);
$html = $obj->drupalGet('http://localhost/soc2008/?q=node/add/page');
$obj->parse();
// Selecting only textareas and input type = 'text' before seeding
// (already included inside handleFormModified, but repeated to build the array of the value to seed)
$all_inputs = $obj->elements->xpath("//input[@type='text']|//textarea");
//echo "<pre>".print_r($all_inputs,1)."</pre>";
foreach ($all_inputs as $input) {
$name = (string)$input->attributes()->name;
$edit[$name] = "<\script\>alert('xss');</\script\>";
}
// $obj->drupalPostModified($html, $form_details['id'], $form_state, TRUE);
$obj->drupalPostModified($html, 'edit-page-node-form', $edit, TRUE);
}
// Function drupalPostModified and handleFormModified (I have to change its name)
function drupalPostModified($html, $form_id, $edit, $submit, $tamper = FALSE) {
$submit_matches = FALSE;
if ($this->parse()) {
$edit_save = $edit;
// Let's iterate over all the forms.
$forms = $this->elements->xpath("//input[@id='".$form_id."']/parent::*");
foreach ($forms as $form) {
if ($tamper) {
// @TODO: this will be Drupal specific. One needs to add the build_id
// and the token to $edit then $post that.
}
else {
// We try to set the fields of this form as specified in $edit.
$edit = $edit_save;
$submit_matches = $this->handleFormModified($post, $edit, $upload, $submit, $form);
$action =
isset($form['action']) ?
$this->
getAbsoluteUrl($form['action']) :
$this->
getUrl();
}
// We post only if we managed to handle every field in edit and the
// submit button matches.
if (!$edit && $submit_matches) {
// This part is not pretty. There is very little I can do.
if ($upload) {
foreach ($post as &$value) {
if (strlen($value) >
0 &&
$value[0] ==
'@') {
$this->
fail(t("Can't upload and post a value starting with @"));
return FALSE;
}
}
foreach ($upload as $key => $file) {
}
}
else {
$post_array = $post;
foreach ($post_array as $key => $value) {
// Whether this needs to be urlencode or rawurlencode, is not
// quite clear, but this seems to be the better choice.
}
}
$out =
$this->
curlExec(array(CURLOPT_URL =>
$action, CURLOPT_POSTFIELDS =>
$post, CURLOPT_POST =>
TRUE));
// Ensure that any changes to variables in the other thread are picked up.
$this->refreshVariables();
return $out;
}
}
// We have not found a form which contained all fields of $edit.
foreach ($edit as $name => $value) {
$this->
fail(t('Failed to set field @name to @value',
array('@name' =>
$name,
'@value' =>
$value)));
}
}
}
protected function handleFormModified(&$post, &$edit, &$upload, $submit, $form) {
// Retrieve the form elements.
$elements = $form->xpath("//input[@type='text']|//textarea");
$submit_matches = FALSE;
foreach ($elements as $element) {
// SimpleXML objects need string casting all the time.
$name = (string)$element['name'];
// This can either be the type of <input> or the name of the tag itself
// for <select> or <textarea>.
$type =
isset($element['type']) ?
(string
)$element['type'] :
$element->
getName();
$value =
isset($element['value']) ?
(string
)$element['value'] :
'';
$done = FALSE;
if (isset($edit[$name])) {
switch ($type) {
case 'text':
case 'textarea':
case 'password':
$post[$name] = $edit[$name];
break;
case 'radio':
if ($edit[$name] == $value) {
$post[$name] = $edit[$name];
}
break;
case 'checkbox':
// To prevent checkbox from being checked.pass in a FALSE,
// otherwise the checkbox will be set to its value regardless
// of $edit.
if ($edit[$name] === FALSE) {
continue 2;
}
else {
$post[$name] = $value;
}
break;
case 'select':
$new_value = $edit[$name];
$index = 0;
$options = $this->getAllOptions($element);
foreach ($options as $option) {
$option_value= (string)$option['value'];
if (in_array($option_value,
$new_value)) {
$post[$key . '[' . $index++ . ']'] = $option_value;
$done = TRUE;
}
}
elseif ($new_value == $option['value']) {
$post[$name] = $new_value;
$done = TRUE;
}
}
break;
case 'file':
$upload[$name] = $edit[$name];
break;
}
}
if (!
isset($post[$name]) && !
$done) {
switch ($type) {
case 'textarea':
$post[$name] = (string)$element;
break;
case 'select':
$single =
empty($element['multiple']);
$first = TRUE;
$index = 0;
$options = $this->getAllOptions($element);
foreach ($options as $option) {
// For single select, we load the first option, if there is a
// selected option that will overwrite it later.
if ($option['selected'] || ($first && $single)) {
$first = FALSE;
if ($single) {
$post[$name] = (string)$option['value'];
}
else {
$post[$key . '[' . $index++ . ']'] = (string)$option['value'];
}
}
}
break;
case 'file':
break;
case 'submit':
case 'image':
if ($submit == $value) {
$post[$name] = $value;
$submit_matches = TRUE;
}
break;
case 'radio':
case 'checkbox':
if (!
isset($element['checked'])) {
break;
}
// Deliberate no break.
default:
$post[$name] = $value;
}
}
}
return $submit_matches;
}