| 1 |
<?php |
| 2 |
/* |
| 3 |
+=====================================================================+ |
| 4 |
| __ ______ _____ | |
| 5 |
| \ \ / / _ \_ _|__ _ __ _ __ ___ | |
| 6 |
| \ \ /\ / /| |_) || |/ _ \ '__| '_ ` _ \ | |
| 7 |
| \ V V / | __/ | | __/ | | | | | | | | |
| 8 |
| \_/\_/ |_| |_|\___|_| |_| |_| |_| | |
| 9 |
| | |
| 10 |
| (c) Jerome Bruandet ~ https://nintechnet.com/ | |
| 11 |
+=====================================================================+ |
| 12 |
*/ |
| 13 |
if (! defined('ABSPATH') ) { |
| 14 |
die('Forbidden'); |
| 15 |
} |
| 16 |
|
| 17 |
|
| 18 |
class WPTerm_ajax { |
| 19 |
|
| 20 |
|
| 21 |
/** |
| 22 |
* Terminal AJAX action. |
| 23 |
*/ |
| 24 |
public static function init() { |
| 25 |
|
| 26 |
add_action('wp_ajax_wptermajax', [ __CLASS__, 'wptermajax_callback' ] ); |
| 27 |
|
| 28 |
} |
| 29 |
|
| 30 |
|
| 31 |
public static function wptermajax_callback() { |
| 32 |
|
| 33 |
// The terminal AJAX callback function: |
| 34 |
|
| 35 |
if (! current_user_can('install_plugins' ) || ! is_main_site() ) { |
| 36 |
wp_die(0); |
| 37 |
} |
| 38 |
|
| 39 |
// Check AJAX security nonce: |
| 40 |
if ( check_ajax_referer( 'wpterm_menu_terminal', 'wpterm_ajax_nonce', false ) ) { |
| 41 |
|
| 42 |
// Path to return in case of fatal error: |
| 43 |
$if_error = htmlspecialchars( rtrim( ABSPATH, '/' ) ) . '::'; |
| 44 |
|
| 45 |
// If the password protection is enabled, check the password: |
| 46 |
if (! wpterm_is_allowed( 'ajax' ) ) { |
| 47 |
echo $if_error . __( 'WPTerm: error, your password has expired. Reload this page to renew it.', 'wpterm'); |
| 48 |
wp_die(); |
| 49 |
} |
| 50 |
|
| 51 |
if ( empty( $_POST['cmd'] ) || empty( $_POST['cwd'] ) || |
| 52 |
empty( $_POST['exec'] ) || empty( $_POST['abs'] ) ) { |
| 53 |
|
| 54 |
echo $if_error . __( 'WPTerm error: missing command, path, function or abspath', 'wpterm' ); |
| 55 |
wp_die(); |
| 56 |
} |
| 57 |
// Make sure the max number of lines to returned to WPTerm |
| 58 |
// is a digit, otherwise set it to 512, its default value: |
| 59 |
if ( empty( $_POST['scrollback'] ) || ! ctype_digit( $_POST['scrollback'] ) ) { |
| 60 |
$scrollback = 512; |
| 61 |
} else { |
| 62 |
$scrollback = (int)$_POST['scrollback']; |
| 63 |
if ( $scrollback > 3000 ) { |
| 64 |
$scrollback = 3000; |
| 65 |
} |
| 66 |
} |
| 67 |
|
| 68 |
// We don't want WordPress to escape strings with slashes. |
| 69 |
$cmd = wp_unslash( base64_decode( trim( $_POST['cmd'] ) ) ); |
| 70 |
$cwd = wp_unslash( trim( $_POST['cwd'] ) ); |
| 71 |
$abs = wp_unslash( trim( $_POST['abs'] ) ); |
| 72 |
$cwd_real = realpath( $cwd ); |
| 73 |
$abs_real = realpath( $abs ); |
| 74 |
if ( false === $cwd_real || false === $abs_real ) { |
| 75 |
wp_die( $if_error . __('Invalid path.', 'wpterm') ); |
| 76 |
} |
| 77 |
|
| 78 |
// Set the ABSPATH variable, go to the current working directory, |
| 79 |
// run the command, redirect STDERR to STDOUT and return the current |
| 80 |
// working directory (it may have been changed e.g., `cd /foo/bar`): |
| 81 |
$command = sprintf( |
| 82 |
'ABSPATH=%s; cd %s; %s 2>&1; echo [-{-`pwd`-}-]', |
| 83 |
escapeshellarg( $abs_real ), |
| 84 |
escapeshellarg( $cwd_real ), |
| 85 |
$cmd // arbitrary by design, we're a terminal. |
| 86 |
); |
| 87 |
|
| 88 |
// Run the command: |
| 89 |
list( $res, $ret_var ) = @run_command( $command, trim( $_POST['exec'] ) ); |
| 90 |
|
| 91 |
// Split the PWD and the data returned by the command: |
| 92 |
if ( preg_match('`^(.+)?\[-{-(/.*?)-}-\]`s', $res, $match ) ) { |
| 93 |
// Turn the string into an array... |
| 94 |
$res_array = explode( "\n", $match[1] ); |
| 95 |
// ...keep only the last $scrollback lines and re-create the string... |
| 96 |
$res_str = implode( "\n", array_slice( $res_array, -$scrollback ) ); |
| 97 |
// ...and return it to WPTerm terminal: |
| 98 |
echo rtrim( $match[2] . '::' . $res_str ); |
| 99 |
} else { |
| 100 |
if (! empty( $ret_var ) ) { |
| 101 |
echo $if_error . sprintf( esc_html__('WPTerm: error %s', 'wpterm'), (int) $ret_var ); |
| 102 |
} else { |
| 103 |
echo $if_error . esc_html__('WPTerm: unknown error. Are you allowed to run PHP program execution functions?', 'wpterm'); |
| 104 |
} |
| 105 |
} |
| 106 |
} else { |
| 107 |
echo '/::' . esc_html__('WPTerm: error, security nonces do not match. Try to reload this page to renew them.', 'wpterm'); |
| 108 |
} |
| 109 |
wp_die(); |
| 110 |
|
| 111 |
} |
| 112 |
|
| 113 |
} |
| 114 |
|
| 115 |
WPTerm_ajax::init(); |
| 116 |
|
| 117 |
/* ================================================================== */ |
| 118 |
// EOF |
| 119 |
|