-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathintegrity-checked.php
More file actions
131 lines (99 loc) · 4.68 KB
/
integrity-checked.php
File metadata and controls
131 lines (99 loc) · 4.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
<?php
/**
Repo integrity checker example by UtilMind.
@see https://github.com/utilmind/git-deployment/ The GitHub project
@author Oleksii Kuznietsov (utilmind) <utilmind@gmail.com>
USAGE:
* This script can be used to check code integrity (comparing it with original Git repository)
and inform Administrator about any code modifications, injections, hacks.
* This script supposed to run on crontab, several times per hour. (The more often is better.)
* Script accepts paths as command-line arguments. Run it as follows:
php integity-checker.php [path to .git directory] [your project code directory] [site name (optional)]
* Don't mix this integrity checker with your primary project code. Better rename it and hide somewhere.
CONTRIBUTORS to original branch:
* Please keep legacy PHP5 syntax;
* Don't require any other libraries. Use only standard PHP5 functions.
**/
// gettings arguments
if (!is_array($argv) || count($argv) < 3) {
echo <<<END
Usage: $argv[0] [git directory] [project code directory] [sitename (optional)]
END;
exit;
}
function add_trailing_slash($d) {
return $d.((substr($d, -1) === '/') ? '' : '/');
} // * remove trailing slash with: rtrim($str, '/');
$git_dir = add_trailing_slash($argv[1]).'.git'; // add '/.git' to provided path
$target_dir = add_trailing_slash($argv[2]);
$sitename = empty($argv[3]) ? basename($target_dir) : $argv[3];
// ideas: https://stackoverflow.com/questions/5237605/how-to-run-git-status-and-just-get-the-filenames
// documentation: https://git-scm.com/docs/git-ls-files
//
// See also: git ls-files -md
// or: git fsck --full (check integrity of git folder itself: https://stackoverflow.com/questions/42479034/how-to-verify-integrity-of-a-git-folder)
//
if (exec('git --git-dir='.escapeshellarg($git_dir).' --work-tree='.escapeshellarg($target_dir).' status --porcelain', $output, $ret)) {
if (0 !== $ret) {
exit("Return code: $ret\n");
}
// If everything is clean
if (empty($output)) {
exit;
}
// collect information
$out = '';
foreach ($output as $row) {
// row example: " D www/css/a.src.css" or "?? tmp/x.php" or "R old -> new"
$row = rtrim($row, "\r\n");
if (strlen($row) < 4) {
continue;
}
$xy = substr($row, 0, 2); // status. (May contain 2 characters combined?)
$path = trim(substr($row, 3)); // everything after status
// Handle rename/copy format: "old -> new" (we care about the new path)
if (false !== strpos($path, ' -> ')) {
$parts = explode(' -> ', $path, 2);
$path = trim($parts[1]);
}
$fn = $target_dir . $path;
// Determine "primary" status char:
// - For "??" use '?'
// - Otherwise take first non-space char from XY (index or worktree)
$primary = '??' === $xy ? '?' : (trim($xy)[0] ?? '');
$label = $label_map[$primary] ?? $xy; // fallback to raw XY if unknown
// Timestamp only if file exists
$extra = '';
$extra = is_file($fn)
? date('Y-m-d H:i:s', filemtime($fn))
// For deleted files it's expected not to exist
: 'missing';
$line = "$label $path - $extra\n";
echo $line;
$out .= '<li><b>' . htmlspecialchars($label, ENT_QUOTES, 'UTF-8') . '</b> '
. htmlspecialchars($path, ENT_QUOTES, 'UTF-8')
. ' <span style="color:#666">(' . htmlspecialchars($extra, ENT_QUOTES, 'UTF-8') . ')</span></li>';
}
if ($out) {
$this_script_name = ltrim(substr(basename($argv[0]), 0, strrpos(basename($argv[0]), '.')));
$last_check_fn = __DIR__.'/status/'.$this_script_name.'-'.$sitename.'-last.log';
if (@file_get_contents($last_check_fn) !== $out) {
file_put_contents($last_check_fn, $out);
// ------------------------------------------------------
// Send notifications to Admin emails, messengers, slack!
// ------------------------------------------------------
// Email (example)
$msg = <<<END
Integrity violation on SITE_NAME!
<p>Broken integrity for the following files:</p>
<ol>$out</ol>
<p>Act immediately! If this is intrusion -- immediately close the possibility to provide payment details, then rotate ALL keys!</p>
<p>If this is just manual edit -- pull the fresh data from Git ASAP.</p>
END;
require __SDK__.'/vendor/autoload.php';
require __INC__.'/aws-ses.php';
$AwsSES = new AwsSES();
$AwsSES->sendAwsEmail($admin_email, 'Integrity violation on SITE_NAME', $msg, $from_email);
}
}
}