Skip to content

Instantly share code, notes, and snippets.

@si458
Created May 26, 2025 08:57
Show Gist options
  • Save si458/43222e3db06932e56a3d3664841108db to your computer and use it in GitHub Desktop.
Save si458/43222e3db06932e56a3d3664841108db to your computer and use it in GitHub Desktop.
Get Plesk Passwords From Database
<?php
// Configuration
$config = [
'server' => 'localhost',
'username' => 'admin',
'password' => trim(file_get_contents("/etc/psa/.psa.shadow")),
'key' => file_get_contents("/etc/psa/private/secret_key"),
'database' => 'psa'
];
// Database queries and output files configuration
$queries = [
'database_passwords' => [
'sql' => "SELECT domains.name AS domain_name, data_bases.name AS database_name,
db_users.login, accounts.password FROM data_bases, db_users, domains, accounts
WHERE data_bases.dom_id = domains.id AND db_users.db_id = data_bases.id
AND db_users.account_id = accounts.id ORDER BY domain_name",
'format' => function($row) {
return "Host: {$row['domain_name']}\nDatabase name: {$row['database_name']}\n" .
"Username: {$row['login']}\nPassword: " . decryptPleskPassword($row['password'], $GLOBALS['config']['key']) . "\n\n";
},
'filter' => fn($row) => !empty($row['domain_name'])
],
'mail_passwords' => [
'sql' => "SELECT accounts.id, mail.mail_name, accounts.password, domains.name
FROM domains LEFT JOIN mail ON domains.id = mail.dom_id
LEFT JOIN accounts ON mail.account_id = accounts.id",
'format' => function($row) {
return "Email: {$row['mail_name']}@{$row['name']}\n" .
"Password: " . decryptPleskPassword($row['password'], $GLOBALS['config']['key']) . "\n\n";
},
'filter' => fn($row) => !empty($row['mail_name'])
],
'ftp_passwords' => [
'sql' => "SELECT REPLACE(sys_users.home,'/home/httpd/vhosts/','') AS domain,
sys_users.login, accounts.password FROM sys_users
LEFT JOIN accounts on sys_users.account_id=accounts.id ORDER BY sys_users.home ASC",
'format' => function($row) {
$domain = str_replace("/var/www/vhosts/", "", $row["domain"]);
$domain = explode("/", $domain);
return "Host: ftp.{$domain[0]}\nLogin: {$row['login']}\nPassword: " .
decryptPleskPassword($row['password'], $GLOBALS['config']['key']) . "\n\n";
},
'filter' => fn($row) => !empty($row['domain'])
]
];
// Decryption function
function decryptPleskPassword($encryptedString, $key) {
$parts = explode('$', $encryptedString);
if (count($parts) < 4) throw new Exception("Invalid encrypted string format");
return trim(openssl_decrypt(
base64_decode($parts[3]),
$parts[1],
$key,
OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING,
base64_decode($parts[2])
));
}
// Main execution
try {
$conn = new mysqli($config['server'], $config['username'], $config['password'], $config['database']);
if ($conn->connect_error) throw new Exception("Connection failed: " . $conn->connect_error);
foreach ($queries as $filename => $query) {
$result = $conn->query($query['sql']);
if (!$result) throw new Exception("Query failed: " . $conn->error);
if ($result->num_rows > 0) {
$output = '';
while ($row = $result->fetch_assoc()) {
if ($query['filter']($row)) {
$output .= $query['format']($row);
}
}
file_put_contents($filename, $output);
}
}
$conn->close();
} catch (Exception $e) {
die("Error: " . $e->getMessage());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment