<?php if (!isset($test_ua)) $test_ua = "curl"; /* * Clean all cookies */ function clean_cookies() { global $_testns; $path = __DIR__ . '/jars'; if (!file_exists($path)) return; rg_log('Cleaning cookies...'); $cookie_jar = $path . '/' . $_testns; @unlink($cookie_jar); } /* * This is called at the begining of all tests */ function prepare_http() { clean_cookies(); } /* * Data is an array */ function do_req($url, &$data, &$headers) { global $test_ua, $test_referer; global $cookie_jar; static $http_handles = array(); global $http_client; global $_testns; global $rg_log_sid; if (!isset($http_client)) $http_client = $_testns; $path = __DIR__ . '/jars'; if (!file_exists($path)) mkdir($path); $cookie_jar = $path . '/' . $http_client; if (is_null($data)) $data = array(); if (!is_array($headers)) { rg_log("Headers is not an array, reset it."); $headers = array(); } // to easy identify requests in the logs if (!strstr($url, '?')) $url .= '?tid=' . rg_id(10); else $url .= '&tid=' . rg_id(10); $url .= '&_testns=' . $_testns; $url .= '&rg_log_sid=' . $rg_log_sid; rg_log_ml('do_req url: ' . $url . "\n" . 'data=' . print_r($data, TRUE) . "\n" . 'headers=' . print_r($headers, TRUE)); $c = FALSE; if (isset($http_handles[$http_client])) $c = $http_handles[$http_client]; if ($c === FALSE) { $c = curl_init(); $http_handles[$http_client] = $c; } curl_setopt($c, CURLOPT_URL, $url); if (!empty($data)) { curl_setopt($c, CURLOPT_POST, 1); curl_setopt($c, CURLOPT_POSTFIELDS, $data); } else { curl_setopt($c, CURLOPT_POST, 0); } curl_setopt($c, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($c, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($c, CURLOPT_HEADER, 1); curl_setopt($c, CURLOPT_HTTPHEADER, $headers); curl_setopt($c, CURLOPT_USERAGENT, $test_ua); curl_setopt($c, CURLOPT_REFERER, $test_referer); curl_setopt($c, CURLOPT_CERTINFO, TRUE); curl_setopt($c, CURLOPT_VERBOSE, TRUE); curl_setopt($c, CURLOPT_ENCODING , 'gzip'); curl_setopt($c, CURLOPT_COOKIEJAR, $cookie_jar); curl_setopt($c, CURLOPT_COOKIEFILE, $cookie_jar); // HTTP/2 if (curl_version()['features'] & CURL_VERSION_HTTP2) curl_setopt($c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); $err = @fopen('php://temp', 'w'); if ($err !== FALSE) { curl_setopt($c, CURLOPT_STDERR, $err); } else { rg_log('Cannot open stderr redirection!'); } $r = curl_exec($c); if ($err !== FALSE) { rewind($err); $xerr = @fread($err, 16 * 4096); fclose($err); rg_log_ml($xerr); } if ($r === FALSE) { rg_log_ml("Cannot load (url=$url), data: " . print_r($data, TRUE)); rg_log("curl error: " . curl_error($c)); exit(1); } $ret = array(); $ret['ci'] = @curl_getinfo($c); if ($ret['ci'] === FALSE) { rg_log('Cannot call curl_getinfo!'); exit(1); } //rg_log_ml('DEBUG: ci: ' . print_r($ret['ci'], TRUE)); if ($ret['ci']['http_code'] == 500) return $ret; $header_size = $ret['ci']['header_size']; //rg_log('DEBUG: r (len=' . strlen($r) . '): ' . $r); //rg_log('DEBUG: header_size: ' . $header_size); $ret['header'] = substr($r, 0, $header_size); $ret['body'] = substr($r, $header_size); if ($ret['ci']['http_code'] != 200) return $ret; if (stristr($ret['header'], 'Content-Type: text/html')) { // Check for XSS if (stristr($ret['body'], '<xss>')) { file_put_contents('http_xss.out', $ret['body']); rg_log("Found <xss> token! Check http_xss.out. Not good!"); exit(1); } } // TODO: should we compress the file downloads? if (stristr($ret['header'], 'Content-Disposition: attachment')) return $ret; if (!stristr($ret['header'], 'Content-Encoding: gzip')) { rg_log_ml('headers: ' . print_r($ret['header'], TRUE)); rg_log('Content is not compressed!'); exit(1); } if (!stristr($ret['header'], "\n" . 'ETag: ')) { rg_log_ml('headers: ' . print_r($ret['header'], TRUE)); rg_log('ETag is not present!'); exit(1); } // Check with tidy if (!stristr($ret['header'], 'Content-Type: ')) { // do nothing } else if (stristr($ret['header'], 'Content-Type: application/octet-stream')) { // do nothing } else if (stristr($ret['header'], 'Content-Type: text/html')) { // some fixes $ret['body'] = str_replace('autocomplete="off"', '', $ret['body']); $ret['body'] = str_replace('<xss>', '|xss|', $ret['body']); file_put_contents("http.tidy.in", $ret['body']); $cmd = "tidy -errors -utf8 -file http.tidy.out http.tidy.in"; $r = rg_exec($cmd, '', FALSE, FALSE, FALSE); if ($r['ok'] != 1) { rg_log_ml('body: ' . $ret['body']); rg_log_ml('tidy error: ' . $r['stderr']); rg_log_ml(file_get_contents('http.tidy.out')); exit(1); } } else if (stristr($ret['header'], 'Content-Type: application/json')) { $ret['json'] = @json_decode($ret['body'], TRUE); if ($ret['json'] === NULL) { rg_log('body: ' . $ret['body']); rg_log('Cannot decode JSON: ' . json_last_error_msg() . '!'); exit(1); } rg_log_ml('Decoded JSON: ' . print_r($ret['json'], TRUE)); } else { rg_log('I do not know how to deal with this content-type!'); exit(1); } // Check if a '@@' is present if (strstr($ret['body'], '@@')) { $t = explode('@@', $ret['body']); $t = explode('@@', $t[1]); if (!strstr($t[0], ' ')) { rg_log_ml('body: ' . $ret['body']); rg_log("We have unresolved variables: [" . $t[0] . "]!"); exit(1); } } // Find cookies $ret['cookies'] = array(); $x = preg_match_all('/Set-Cookie: (.*?)=(.*?)[;]/', $ret['header'], $matches, PREG_SET_ORDER); if ($x !== FALSE) { foreach ($matches as $junk => $info) { $k = $info[1]; $v = $info[2]; $ret['cookies'][$k] = $v; } } //rg_log_ml('ret[cookies]: ' . print_r($ret['cookies'], TRUE)); $ret['sid'] = ''; if (isset($ret['cookies']['sidu'])) $ret['sid'] = $ret['cookies']['sidu']; if (isset($ret['cookies']['sids'])) $ret['sid'] = $ret['cookies']['sids']; $ret['tokens'] = array(); $x = preg_match_all('/ name="token" value="([a-zA-Z0-9_:]*)"/', $ret['body'], $matches); //rg_log_ml('DEBUG: tokens matches: ' . print_r($matches, TRUE)); if (($x === FALSE) || (!isset($matches[1]))) { //rg_log("CHECK: no token found"); } else { foreach ($matches[1] as $m) { $t = explode(':', $m); if (!isset($t[1])) { rg_log_ml('body: ' . print_r($ret['body'], TRUE)); rg_log_ml('matches: ' . print_r($matches[1], TRUE)); rg_log('Invalid debug token (no prefix): ' . $m); exit(1); } $ret['tokens'][$t[1]] = $t[0]; } } rg_log('DEBUG ret[tokens]: ' . rg_array2string($ret['tokens']) . '.'); // Collect '<input>' tags $ret['inputs'] = array(); $x = preg_match_all('/<input .* name="(.*?)" .*value="(.*?)"/uD', $ret['body'], $matches); //rg_log_ml('DEBUG: inputs matches: ' . print_r($matches, TRUE)); if (($x === FALSE) || (!isset($matches[1]))) { //rg_log("CHECK: no token found"); } else { foreach ($matches[1] as $i => $d) $ret['inputs'][$d] = $matches[2][$i]; } //rg_log_ml('DEBUG ret[inputs]: ' .print_r($ret['inputs'], TRUE)); // find logout token $x = preg_match('/logout\?token=([a-zA-Z0-9:]*)"/', $ret['body'], $matches); //rg_log_ml('DEBUG: matches[logout]: ' . print_r($matches, TRUE)); if (($x === FALSE) || (!isset($matches[1]))) { $ret['tokens']['logout'] = ''; } else { $t = explode(':', $matches[1]); $ret['tokens']['logout'] = $t[0]; } $x = preg_match_all('/ class="secret_token">([A-Z0-9]*)</', $ret['body'], $matches); if (($x !== FALSE) && (isset($matches[1])) && isset($matches[1][0])) { $ret['totp_secret'] = $matches[1][0]; rg_log('DEBUG ret[totp_secret]=' . $ret['totp_secret']); } @rename('http-last.out', 'http-prev.out'); file_put_contents('http-last.out', $ret['body']); return $ret; } /* * Helper function that will do the login */ function test_login($url, $rg_ui) { global $test_ua; // First we need to load the form so we can get the token $data = array(); $r = do_req($url . "/op/login", $data, $headers); if ($r === FALSE) { rg_log('Cannot load login form!'); return FALSE; } if (!isset($r['tokens']['login'])) { rg_log_ml('r: ' . print_r($r, TRUE)); rg_log('Login token not returned!'); return FALSE; } $good_token = $r['tokens']['login']; // Now, post login form rg_log("Do the real login post request"); $data = array( "doit" => 1, "token" => $good_token, "user" => $rg_ui['username'], "pass" => $rg_ui['pass'], "lock_ip" => 1 ); if (isset($rg_ui['t'])) $data['t'] = $rg_ui['t']; $headers = array(); $r = do_req($url . "/op/login", $data, $headers); if ($r === FALSE) { rg_log_ml("Cannot login: " . print_r($r, TRUE)); return FALSE; } if (strstr($r['body'], "invalid user")) { rg_log_ml(print_r($r, TRUE)); rg_log("Login invalid. Check above!"); return FALSE; } return $r; } /* * Restore password aaaa for user catab */ function test_restore($db) { $salt = 'd0a41957b835fbf7bfe63b750db15108cc048259'; $pass = 'aaaa'; $pass = rg_user_pass($salt, $pass); $sql = "UPDATE users SET salt = '$salt'" . ", pass = '$pass'" . ", session_time = 3600" . " WHERE username = 'catab'"; $res = rg_sql_query($db, $sql); if ($res == FALSE) { rg_log("Cannot update (" . rg_sql_error() . ")!"); exit(1); } rg_sql_free_result($res); rg_cache_unset('user::4::info', RG_SOCKET_NO_WAIT); } /* * Set user agent */ function test_set_ua($s) { global $test_ua; $test_ua = $s; } /* * Set referer */ function test_set_referer($s) { global $test_referer; $test_referer = $s; } ?>