content = $content; } public function getBody() { return $this->content; } public function getLines(): array { return explode("\n", $this->content); } } interface HttpClient { public function request(string $method, string $url, array $headers = [], array $data = []): Response; } class ScriptClient implements HttpClient { private $proxy; private $credentials; public function __construct(string $settings) { $this->readSettings($settings); } private function getAuthorityComponent(string $authority = null, string $tag = null) { if(is_null($authority)){ return null; } if(!is_null($tag)){ $authority .= ":$tag"; } return $authority; } private function readSettings(string $file) { if(!is_file($file) || !is_readable($file)){ return; } $stmts = file($file); $settings = array_reduce($stmts, function($c, $stmt){ list($key, $val) = \array_pad(array_map('trim', explode(':', $stmt)), 2, null); $c[$key] = $val; return $c; }, []); $this->proxy = $this->getAuthorityComponent($settings['proxy_host'], $settings['proxy_port']); $this->credentials = $this->getAuthorityComponent($settings['proxy_user'], $settings['proxy_pass']); } public function request(string $method, string $uri, array $headers = [], array $data = []): Response { $options = [ 'http' => [ 'method' => strtoupper($method), 'header' => $headers + [$this->credentials ? 'Proxy-Authorization: Basic ' . base64_encode($this->credentials) : null], 'proxy' => $this->proxy, 'content' => http_build_query($data), ], ]; $context = stream_context_create($options); $body = file_get_contents($uri, false, $context); if($body === false){ trigger_error( "Unable to contact the Server. Are outbound connections disabled? " . "(If a proxy is required for outbound traffic, you may configure " . "the honey pot to use a proxy. For instructions, visit " . "http://www.projecthoneypot.org/settings_help.php)", E_USER_ERROR ); } return new TextResponse($body); } } trait AliasingTrait { private $aliases = []; public function searchAliases($search, array $aliases, array $collector = [], $parent = null): array { foreach($aliases as $alias => $value){ if(is_array($value)){ return $this->searchAliases($search, $value, $collector, $alias); } if($search === $value){ $collector[] = $parent ?? $alias; } } return $collector; } public function getAliases($search): array { $aliases = $this->searchAliases($search, $this->aliases); return !empty($aliases) ? $aliases : [$search]; } public function aliasMatch($alias, $key) { return $key === $alias; } public function setAlias($key, $alias) { $this->aliases[$alias] = $key; } public function setAliases(array $array) { array_walk($array, function($v, $k){ $this->aliases[$k] = $v; }); } } abstract class Data { protected $key; protected $value; public function __construct($key, $value) { $this->key = $key; $this->value = $value; } public function key() { return $this->key; } public function value() { return $this->value; } } class DataCollection { use AliasingTrait; private $data; public function __construct(Data ...$data) { $this->data = $data; } public function set(Data ...$data) { array_map(function(Data $data){ $index = $this->getIndexByKey($data->key()); if(is_null($index)){ $this->data[] = $data; } else { $this->data[$index] = $data; } }, $data); } public function getByKey($key) { $key = $this->getIndexByKey($key); return !is_null($key) ? $this->data[$key] : null; } public function getValueByKey($key) { $data = $this->getByKey($key); return !is_null($data) ? $data->value() : null; } private function getIndexByKey($key) { $result = []; array_walk($this->data, function(Data $data, $index) use ($key, &$result){ if($data->key() == $key){ $result[] = $index; } }); return !empty($result) ? reset($result) : null; } } interface Transcriber { public function transcribe(array $data): DataCollection; public function canTranscribe($value): bool; } class StringData extends Data { public function __construct($key, string $value) { parent::__construct($key, $value); } } class CompressedData extends Data { public function __construct($key, string $value) { parent::__construct($key, $value); } public function value() { $url_decoded = base64_decode(str_replace(['-','_'],['+','/'],$this->value)); if(substr(bin2hex($url_decoded), 0, 6) === '1f8b08'){ return gzdecode($url_decoded); } else { return $this->value; } } } class FlagData extends Data { private $data; public function setData($data) { $this->data = $data; } public function value() { return $this->value ? ($this->data ?? null) : null; } } class CallbackData extends Data { private $arguments = []; public function __construct($key, callable $value) { parent::__construct($key, $value); } public function setArgument($pos, $param) { $this->arguments[$pos] = $param; } public function value() { ksort($this->arguments); return \call_user_func_array($this->value, $this->arguments); } } class DataFactory { private $data; private $callbacks; private function setData(array $data, string $class, DataCollection $dc = null) { $dc = $dc ?? new DataCollection; array_walk($data, function($value, $key) use($dc, $class){ $dc->set(new $class($key, $value)); }); return $dc; } public function setStaticData(array $data) { $this->data = $this->setData($data, StringData::class, $this->data); } public function setCompressedData(array $data) { $this->data = $this->setData($data, CompressedData::class, $this->data); } public function setCallbackData(array $data) { $this->callbacks = $this->setData($data, CallbackData::class, $this->callbacks); } public function fromSourceKey($sourceKey, $key, $value) { $keys = $this->data->getAliases($key); $key = reset($keys); $data = $this->data->getValueByKey($key); switch($sourceKey){ case 'directives': $flag = new FlagData($key, $value); if(!is_null($data)){ $flag->setData($data); } return $flag; case 'email': case 'emailmethod': $callback = $this->callbacks->getByKey($key); if(!is_null($callback)){ $pos = array_search($sourceKey, ['email', 'emailmethod']); $callback->setArgument($pos, $value); $this->callbacks->set($callback); return $callback; } default: return new StringData($key, $value); } } } class DataTranscriber implements Transcriber { private $template; private $data; private $factory; private $transcribingMode = false; public function __construct(DataCollection $data, DataFactory $factory) { $this->data = $data; $this->factory = $factory; } public function canTranscribe($value): bool { if($value == ''){ $this->transcribingMode = true; return false; } if($value == ''){ $this->transcribingMode = false; } return $this->transcribingMode; } public function transcribe(array $body): DataCollection { $data = $this->collectData($this->data, $body); return $data; } public function collectData(DataCollection $collector, array $array, $parents = []): DataCollection { foreach($array as $key => $value){ if($this->canTranscribe($value)){ $value = $this->parse($key, $value, $parents); $parents[] = $key; if(is_array($value)){ $this->collectData($collector, $value, $parents); } else { $data = $this->factory->fromSourceKey($parents[1], $key, $value); if(!is_null($data->value())){ $collector->set($data); } } array_pop($parents); } } return $collector; } public function parse($key, $value, $parents = []) { if(is_string($value)){ if(key($parents) !== NULL){ $keys = $this->data->getAliases($key); if(count($keys) > 1 || $keys[0] !== $key){ return \array_fill_keys($keys, $value); } } end($parents); if(key($parents) === NULL && false !== strpos($value, '=')){ list($key, $value) = explode('=', $value, 2); return [$key => urldecode($value)]; } if($key === 'directives'){ return explode(',', $value); } } return $value; } } interface Template { public function render(DataCollection $data): string; } class ArrayTemplate implements Template { public $template; public function __construct(array $template = []) { $this->template = $template; } public function render(DataCollection $data): string { $output = array_reduce($this->template, function($output, $key) use($data){ $output[] = $data->getValueByKey($key) ?? null; return $output; }, []); ksort($output); return implode("\n", array_filter($output)); } } class Script { private $client; private $transcriber; private $template; private $templateData; private $factory; public function __construct(HttpClient $client, Transcriber $transcriber, Template $template, DataCollection $templateData, DataFactory $factory) { $this->client = $client; $this->transcriber = $transcriber; $this->template = $template; $this->templateData = $templateData; $this->factory = $factory; } public static function run(string $host, int $port, string $script, string $settings = '') { $client = new ScriptClient($settings); $templateData = new DataCollection; $templateData->setAliases([ 'doctype' => 0, 'head1' => 1, 'robots' => 8, 'nocollect' => 9, 'head2' => 1, 'top' => 2, 'legal' => 3, 'style' => 5, 'vanity' => 6, 'bottom' => 7, 'emailCallback' => ['email','emailmethod'], ]); $factory = new DataFactory; $factory->setStaticData([ 'doctype' => '', 'head1' => '', 'head2' => '', 'top' => '
', 'bottom' => '
', ]); $factory->setCompressedData([ 'robots' => 'H4sIAAAAAAAAA7PJTS1JVMhLzE21VSrKT8ovKVZSSM7PK0nNK7FVysvPzEtJrdBJy8_JyS9XsrPBrzixKDkjsyxVyQ4AO3aE7FUAAAA', 'nocollect' => 'H4sIAAAAAAAAA7PJTS1JVMhLzE21VcrL103NTczM0U3Oz8lJTS7JzM9TUkjOzytJzSuxVdJXsgMAKsBXli0AAAA', 'legal' => 'H4sIAAAAAAAAA51a23LbOBJ9369AOVuZpMrxLXZsFz2pUmzF1lQieyU5qTxSJCRyQxFcAJRG-_XbF4AXi3ScfZiJBAEE0H369Ommr2w4z6SIZJYVYRyn-fLPvaM9MVc6lpo-4k-mCCP308d_XFmN_4s_Xi1UbsUijOSfe5EqdSr13sfX-dwUgej6x325mruVkcqU_nOTpFZ-NFeHOPbx6hB-nWv3GPw0S6R4_er4-DKQc5Pipw80zp-U2KpSmHKOQ8omUgsr9YonXJzTGivFFmcf0zoNH4-OgzAWFj-dBnIlcDxcSpx0FFgjFP5yEtB4Netg99TSnXrm5tCCXOXvrA5zs8Bv3_kEB_i5vthzpigapui0Zts-00JGaZgJLfnS5xcBXzZ_d1euwpymmwItd3QUSG1evzo9DQQZrNB00_eBDldG8AyyRWnVKmQLw8LLyyD05x_iLPieZrsnT93JAUga546sSA0cLKqtDw87DzKVywPxA_c-PqfhJMTt4SexDrOSTmzp59MgXLLD9kXo3X4RwCS5u3_i9uftnA-te5oGAAubsKsdCORK5vYZD7zYZ8nv-WwYRowYUYTabulM7IgwZRAa6-GJP77Z-6uM2RE4eBawGZvwBDMvU8OXZbvS9ERkNHdjGOR5LAq-u14ocpJaiIX04KifG-Zb9khkeUuVE9qkXqcReo82h9gM52rNwG_escNGP3ds1Dktftm0dNfiL_RM2xU_GCxlf3BHKjeOGnDBiqyy7T94WBQyJNOG8xJXnn4AGLy6OA0SCtFvKRCC0kZUMfVtNB3N7idTMcBvD69ffTgLJrTih7ifiCkZ_vHTFH64DP71OBzPaKW_GFDxr_j4OQtVBt_5ZdGH6gaoXUwCoHbXW7d-odVKwJCf-yHgFZEVnsU5MI1YApg0GzslwJUijCJZWI7jKNRyUWbZ9qBOAYDBNI_TNT0eJ-PwWWD6z8PEki5xgdSQAPk4YsNIt_5eNVJ-YbkWBqcPw2ug4feBz2VMQJrj16YApyYMOtJKk3-UNft4P_k3ndakS7YOHxmSmMJxbxGeYySROXMgzGXbMcHk6X8lrEoYfDtbhx7E0c9ccdrNZEyPFbmyIoOnU5KLD3kHLWJHOwkfia0PvBAzqbCxCfmQDL6Ddy4vAkyJjo_6Q1b-XWhpnjjiuX_aU4HlJR_JOHhJSuwEGb277dJty7jjZwwi9Nfe2_7ZjCEw6SBe8UqAqAAOyFK64Qp-giSTuvTMJwMWNja0Lm6q8blW5TLpSEiVVwgRHVyVNLkqt42EoqXkjA3DBzWwO1wfvYx45a9T3S9EjT8FxLQSCdHpuml0w8hayQ34qWG2UYyGXLBdlw5XBMv-ZFPF8u1kOBSzu8GMUDIc34xIKt2KwfhHvcWnyXBwfQfBc34ZfP5dku1TuzPQTBcnLTpw6b_fkahqgcsIXf2uWiiirotAbdI6Qy2JMk0HAaqmVRLpQ5WDAmSzaSAf8v8YlCyY4sTrbRfN5yC_3pi3wOj0GNDLS5C7VvpZp4EqwbeOD4Rs0imYY_ClhbAvo-vhGAz0PqD01rQSz1G5CMU6NUzOOA7ngqx6FtT6FmTtvkAxC9yibCPSyBCseBkwzcMkKfPkWYB01ItZQqgDbCLNM_6QKw9NvHgnufkcBOxUHxPoOO-P-sep-CdVLum8RDoSyic_yHKyK4H484zyBsf8YYRckb4EwPQjjzjGZB0CRzXS50mgVcIemXcydA3_wcPDl1HTraEVqC5NmdargLhyCWRbVwomCbNMkEelWHL6sCxQbbrucIJsMDKDtVIXmAoIhtlWbFKbpIyaflWJkQ243tAJl2GaG5IqAO101XCbEjKDU-uXCoZdQQXTJsPr-8lN00BLLGq1GOUNJCuXyl0CA-QWHgWAbfhaOtX0n9KPd0ky72UQpvWj_L53g8m34XRG4mV8W-_9dTidDmD0OBi-mTYKIlSod8Pp8JnCeDh5OYuCLWCT82DaMs-AePqmNXZ9P27aCxVPVc6nHBhsx8iZLU4hcGq7YBwLrMybOdlhBpAYk9uJXEilUdbt9yassFpl9DAUZGjYk2MgQUGuIBUDWNLpLkzI_dPZZHQ9a4WIA67-gy8jMqi5WrUDPasiNtCVOtxkkoAoUXnheKRWRWtPECYoENKYtVeaCazUWWJBInUGhPCUrtQ-ex8cYaFeigVdZVGxukGBR0IQGYnLRuELVBfB9GwgqH540OlgIG4qE0gD58Hg05cqHdSpYvC9XcYRKe9DuvPEwXGdU5AL1SHykqa0hlIjB-DMqQC_hmF4kHhD7l7VYpY6QsxDdkM7AnhA7TH78Y5EKTRe-xZGmNVorzyNhOHS5iKoU1nj3m3Y3wPsjzoC2DMU1YytIIC7IEldeMnNeTBcSrgSnGyPJmVb4Ro4lvsDTVkKDnPe7fCZt9zCb7gvbgezu-GE6QJH3orZPWisDj7woTLCaV-nXmD1przpcPLtt4jjhk5BjDS6Hz8x5eddUVGr45XM66Zibg7EDHO8cMg8EJ-2gktLqtzIluRQCEKLdatkW4SlTXCMnhJjGxJsTnW6tTIXhWSnsPHTJ65_euLP95PW9_F98wa5122wv9OIeZSVsYcstfe4ibbf32lNQgdGyeVbBtWRFq4LxfVSzRuxKLQqmMGwugwdUGCYmcJ1pmBn1BgZ9zY09WMrUxMnaF-ew1MMHTLDFAq23edOZd0vXOYY1ScnTwNlMG5ng78eJyMSkK0kCpeBM0dSNtqaGugzX4pFS3pJ3yJjXZV0SAtfTewNYufADrn2s0EtElzOBWGvisJp06oIBJb1jSi0EqwU8KMT5h59RGvPC59IVs3rQvMTo6dgm_Sr0kdI5q3kO27bFNawPyGlskOrokxX6Y_ES51sNfcRQfFpWbW8bhmm09n9xBViOHozHLP6-DwaTugRUBwcvJwIqnM_TneyRzP63-xV1QmogDrhus7oymXd0NWYDEyQEIAdOPeR4-9Gybo3k9UqtajHXfe_32fGQZVNhfGyqdpkeBIDjxPTWsQbU2W63S53w8njd3ePXwfjljO_jZ6Ipn7-tfTSBd-fEPZqS2APiLNNF7f4W8GFwpyn9XfNUDY1ubc6mA31VqR5A_xqDZolFq5jHdck4jUszZLY1uIBz8vcbOIxKFFTKCkoxkO9BtoDf9a2jkUIvCaYE58SNOozylnjXUghKrhzQ0ddMfPLutxc0Ag2fHzMy723cJnqGwSGaddC2MRhn5L86ndU5LqJc4itCBIXcxjqTeexZajj5mXq0P702KXcn76I88GBxkazVwpPs4qEm6QLsYH7UbiCS1GH9CuAB0KxyivFty9mk8F4-pkrBVD209kISODiLJhxDPvDv1AKuH5r6ogVz_dMJ4Qd-EwzP8bSoda0vljYCn4PAPquHuaXI35fBlrWV2_7WJmjKOe8KlbhT3BhVcCdBmtuGoPYZrYFHKlNDklVPRWP9AJhF5zzqr_BLFwUFABZukLZ7brHW8FvTvkc_ADq2SNumxtlrlMe2TLMXAHqSkHM_dwcwrJpnTZKK0eCImpCHEqTLLQpbx-nPq0ys5qEkbEM8VzcG1Q43VfBatG-v28ozrGtECU--xxdBhUpi6kLyTVzBYxg2FFw6HZByC_DcpD90rW1WOj1ouTfJUsjitq-0rvBrY4V2GrSuFQ0k55OGgVN1z3jAzHISWjht9IUHJfPvMksuBjQCt-qwtQ6jbe4AduUo_EtyviBsyHIqv7oGYwFvay6pppt-PD_xSrINOJ3_Jxz_YyRxVU0HRuS7nHV-qiT4YF4yGRoyGxU1uqG2DOygZKFTwhP_9u6ENjnlz_H3M1aFaVlQYOYYEza1npQw1JbfumS-mq97jw459nqdS6BKN-v043xJ1ruY6PwUNX5wgtTFwtdx65eG_Mcbg7IPPJ39keGnEanhVD3CZW5Jq7fRtVbrmVe4su0mn9WpiUzaKkoob7ZbaZWHPHs3wW4rMQvkSRlZEK0pigA6x00nzW7G01uHA5Pg8H4eihQkXai7JD-LOWQ_p4FPsDv_wNoJtvA3CIAAA', 'style' => 'H4sIAAAAAAAAAyXMPQrDMAwG0KsEuuavq20y-h6qrYDB0VckDS6ld8_Qd4CXzD-dD1ovFG2G8S3o0PDIOccT4uGFXqfn_h4TaaM-G4ktxtrO6Dx8qVyg5A0SBMLxl7b_eQPWgl1mWwAAAA', 'vanity' => 'H4sIAAAAAAAAA22S207DMAyGX8XKbmEdp0nL2goxDSEk2MThgsu0ydpAFkeOWbe3Jy3jBlBkyVbi7_-dJGdVOQO1cS4GVVvfFGIi-jIorY9lhaQN9VnkgzOFqFT90RB-ei1Hs9ls3lnNrTy_mIT9XJQ5UwoNO-Vs4wvBGH4aj1AJZ2EP5ymuUlymrm-JU7JNyzKis3o4MlosFj0xefNwZGzQs6zQaej1QJFV7iQqH0-jIbuZ1-iQ5Gg6nc6Tsuw9BYyWLXpJxim2O5OY13nWU8s8Y_3HLhxzZzYs4Jf5i6Q6Sevye1oFLZlNIVrmILOs67pxIHw3NbfozSEgj5GaTEDtVIyF2GJNNuJelA_Lh5vlE6xuYf20ul8uXuBu9bh8g_XqJc9UmVf0L_3TJ-PbcY1b8Qf5nHbgTtHORDYEa0JORtLo8Gi4Q_roocnezmqjoTrA6wAb5IaLyPrHy4ZfUX4BFH-HUR0CAAA', ]); $factory->setCallbackData([ 'emailCallback' => function($email, $style = null){ $value = $email; $display = 'style="display:' . ['none',' none'][random_int(0,1)] . '"'; $style = $style ?? random_int(0,5); $props[] = "href=\"mailto:$email\""; $wrap = function($value, $style) use($display){ switch($style){ case 2: return ""; case 4: return "$value"; case 5: $id = 'ch8dr9uib1sl'; return "
$value
\n"; default: return $value; } }; switch($style){ case 0: $value = ''; break; case 3: $value = $wrap($email, 2); break; case 1: $props[] = $display; break; } $props = implode(' ', $props); $link = "$value"; return $wrap($link, $style); } ]); $transcriber = new DataTranscriber($templateData, $factory); $template = new ArrayTemplate([ 'doctype', 'injDocType', 'head1', 'injHead1HTMLMsg', 'robots', 'injRobotHTMLMsg', 'nocollect', 'injNoCollectHTMLMsg', 'head2', 'injHead2HTMLMsg', 'top', 'injTopHTMLMsg', 'actMsg', 'errMsg', 'customMsg', 'legal', 'injLegalHTMLMsg', 'altLegalMsg', 'emailCallback', 'injEmailHTMLMsg', 'style', 'injStyleHTMLMsg', 'vanity', 'injVanityHTMLMsg', 'altVanityMsg', 'bottom', 'injBottomHTMLMsg', ]); $hp = new Script($client, $transcriber, $template, $templateData, $factory); $hp->handle($host, $port, $script); } public function handle($host, $port, $script) { $data = [ 'tag1' => 'ad5b2d1d1e072f8ffc04b5e149a84b8a', 'tag2' => '5bb126ef6196fd4bfaf3bdbfd6214111', 'tag3' => '3649d4e9bcfd3422fb4f9d22ae0a2a91', 'tag4' => md5_file(__FILE__), 'version' => "php-".phpversion(), 'ip' => $_SERVER['REMOTE_ADDR'], 'svrn' => $_SERVER['SERVER_NAME'], 'svp' => $_SERVER['SERVER_PORT'], 'sn' => $_SERVER['SCRIPT_NAME'] ?? '', 'svip' => $_SERVER['SERVER_ADDR'] ?? '', 'rquri' => $_SERVER['REQUEST_URI'] ?? '', 'phpself' => $_SERVER['PHP_SELF'] ?? '', 'ref' => $_SERVER['HTTP_REFERER'] ?? '', 'uagnt' => $_SERVER['HTTP_USER_AGENT'] ?? '', ]; $headers = [ "User-Agent: PHPot {$data['tag2']}", "Content-Type: application/x-www-form-urlencoded", "Cache-Control: no-store, no-cache", "Accept: */*", "Pragma: no-cache", ]; $subResponse = $this->client->request("POST", "http://$host:$port/$script", $headers, $data); $data = $this->transcriber->transcribe($subResponse->getLines()); $response = new TextResponse($this->template->render($data)); $this->serve($response); } public function serve(Response $response) { header("Cache-Control: no-store, no-cache"); header("Pragma: no-cache"); print $response->getBody(); } } Script::run(__REQUEST_HOST, __REQUEST_PORT, __REQUEST_SCRIPT, __DIR__ . '/phpot_settings.php');