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 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
|
# This is the default configuration file for Snuffleupagus (https://snuffleupagus.rtfd.io).
# It contains "reasonable" defaults that won't break your websites,
# and a lot of commented directives that you can enable if you want to
# have a better protection.
# Harden the PRNG
sp.harden_random.enable();
# Enable XXE protection
@condition extension_loaded("xml");
sp.xxe_protection.enable();
@end_condition;
# Global configuration variables
# sp.global.secret_key("YOU _DO_ NEED TO CHANGE THIS WITH SOME RANDOM CHARACTERS.");
# Globally activate strict mode
# https://www.php.net/manual/en/language.types.declarations.php#language.types.declarations.strict
# sp.global_strict.enable();
# Prevent unserialize-related exploits
# sp.unserialize_hmac.enable();
# Only allow execution of read-only files. This is a low-hanging fruit that you should enable.
# sp.readonly_exec.enable();
# PHP has a lot of wrappers, most of them aren't usually useful, you should
# only enable the ones you're using.
# sp.wrappers_whitelist.list("file,php,phar");
# Prevent sloppy comparisons.
# sp.sloppy_comparison.enable();
# Use SameSite on session cookie
# https://snuffleupagus.readthedocs.io/features.html#protection-against-cross-site-request-forgery
sp.cookie.name("PHPSESSID").samesite("lax");
# Harden the `chmod` function (0777 (oct = 511, 0666 = 438)
@condition PHP_VERSION_ID < 80000;
sp.disable_function.function("chmod").param("mode").value("438").drop();
sp.disable_function.function("chmod").param("mode").value("511").drop();
@condition PHP_VERSION_ID >= 80000;
sp.disable_function.function("chmod").param("permissions").value("438").drop();
sp.disable_function.function("chmod").param("permissions").value("511").drop();
@end_condition;
# Prevent various `mail`-related vulnerabilities
@condition PHP_VERSION_ID < 80300;
sp.disable_function.function("mail").param("additional_parameters").value_r("\\-").drop();
@condition PHP_VERSION_ID >= 80300;
sp.disable_function.function("mail").param("additional_params").value_r("\\-").drop();
@end_condition;
# Since it's now burned, me might as well mitigate it publicly
@condition PHP_VERSION_ID < 80000;
sp.disable_function.function("putenv").param("setting").value_r("LD_").drop();
sp.disable_function.function("putenv").param("setting").value("PATH").drop();
@condition PHP_VERSION_ID >= 80000;
sp.disable_function.function("putenv").param("assignment").value_r("LD_").drop();
sp.disable_function.function("putenv").param("assignment").value("PATH").drop();
@end_condition;
# This one was burned in Nov 2019 - https://gist.github.com/LoadLow/90b60bd5535d6c3927bb24d5f9955b80
@condition PHP_VERSION_ID < 80000;
sp.disable_function.function("putenv").param("setting").value_r("GCONV_").drop()
@condition PHP_VERSION_ID >= 80000;
sp.disable_function.function("putenv").param("assignment").value_r("GCONV_").drop()
@end_condition;
# Since people are stupid enough to use `extract` on things like $_GET or $_POST, we might as well mitigate this vector
@condition PHP_VERSION_ID < 80000;
sp.disable_function.function("extract").pos("0").value_r("^_").drop()
sp.disable_function.function("extract").pos("1").value("0").drop()
@condition PHP_VERSION_ID >= 80000;
sp.disable_function.function("extract").param("array").value_r("^_").drop()
sp.disable_function.function("extract").param("flags").value("0").drop()
@end_condition;
# This is also burned:
# ini_set('open_basedir','..');chdir('..');…;chdir('..');ini_set('open_basedir','/');echo(file_get_contents('/etc/passwd'));
# Since we have no way of matching on two parameters at the same time, we're
# blocking calls to open_basedir altogether: nobody is using it via ini_set anyway.
# Moreover, there are non-public bypasses that are also using this vector ;)
@condition PHP_VERSION_ID < 80000;
sp.disable_function.function("ini_set").param("varname").value_r("open_basedir").drop()
@condition PHP_VERSION_ID >= 80000;
sp.disable_function.function("ini_set").param("option").value_r("open_basedir").drop()
@end_condition;
# Prevent various `include`-related vulnerabilities
sp.disable_function.function("require_once").value_r("\.(inc|phtml|php)$").allow();
sp.disable_function.function("include_once").value_r("\.(inc|phtml|php)$").allow();
sp.disable_function.function("require").value_r("\.(inc|phtml|php)$").allow();
sp.disable_function.function("include").value_r("\.(inc|phtml|php)$").allow();
sp.disable_function.function("require_once").drop();
sp.disable_function.function("include_once").drop();
sp.disable_function.function("require").drop();
sp.disable_function.function("include").drop();
# Prevent `system`-related injections
sp.disable_function.function("system").param("command").value_r("[$|;&`\\n\\(\\)\\\\]").drop();
@condition PHP_VERSION_ID < 80000;
sp.disable_function.function("shell_exec").pos("0").value_r("[$|;&`\\n\\(\\)\\\\]").drop();
@condition PHP_VERSION_ID >= 80000;
sp.disable_function.function("shell_exec").param("command").value_r("[$|;&`\\n\\(\\)\\\\]").drop();
@end_condition;
sp.disable_function.function("exec").param("command").value_r("[$|;&`\\n\\(\\)\\\\]").drop();
sp.disable_function.function("proc_open").param("command").value_r("[$|;&`\\n\\(\\)\\\\]").drop();
# Prevent runtime modification of interesting things
@condition PHP_VERSION_ID < 80000;
sp.disable_function.function("ini_set").param("varname").value("assert.active").drop();
sp.disable_function.function("ini_set").param("varname").value("zend.assertions").drop();
sp.disable_function.function("ini_set").param("varname").value("memory_limit").drop();
sp.disable_function.function("ini_set").param("varname").value("include_path").drop();
sp.disable_function.function("ini_set").param("varname").value("open_basedir").drop();
@condition PHP_VERSION_ID >= 80000;
sp.disable_function.function("ini_set").param("option").value("assert.active").drop();
sp.disable_function.function("ini_set").param("option").value("zend.assertions").drop();
sp.disable_function.function("ini_set").param("option").value("memory_limit").drop();
sp.disable_function.function("ini_set").param("option").value("include_path").drop();
sp.disable_function.function("ini_set").param("option").value("open_basedir").drop();
@end_condition;
# Detect some backdoors via environment recon
@condition PHP_VERSION_ID < 80000;
sp.disable_function.function("ini_get").param("varname").value("allow_url_fopen").drop();
sp.disable_function.function("ini_get").param("varname").value("open_basedir").drop();
sp.disable_function.function("ini_get").param("varname").value_r("suhosin").drop();
sp.disable_function.function("function_exists").param("function_name").value("eval").drop();
sp.disable_function.function("function_exists").param("function_name").value("exec").drop();
sp.disable_function.function("function_exists").param("function_name").value("system").drop();
sp.disable_function.function("function_exists").param("function_name").value("shell_exec").drop();
sp.disable_function.function("function_exists").param("function_name").value("proc_open").drop();
sp.disable_function.function("function_exists").param("function_name").value("passthru").drop();
sp.disable_function.function("is_callable").param("var").value("eval").drop();
sp.disable_function.function("is_callable").param("var").value("exec").drop();
sp.disable_function.function("is_callable").param("var").value("system").drop();
sp.disable_function.function("is_callable").param("var").value("shell_exec").drop();
sp.disable_function.function("is_callable").param("var").value("proc_open").drop();
sp.disable_function.function("is_callable").param("var").value("passthru").drop();
@condition PHP_VERSION_ID >= 80000;
sp.disable_function.function("ini_get").param("option").value("allow_url_fopen").drop();
sp.disable_function.function("ini_get").param("option").value("open_basedir").drop();
sp.disable_function.function("ini_get").param("option").value_r("suhosin").drop();
sp.disable_function.function("function_exists").param("function").value("eval").drop();
sp.disable_function.function("function_exists").param("function").value("exec").drop();
sp.disable_function.function("function_exists").param("function").value("system").drop();
sp.disable_function.function("function_exists").param("function").value("shell_exec").drop();
sp.disable_function.function("function_exists").param("function").value("proc_open").drop();
sp.disable_function.function("function_exists").param("function").value("passthru").drop();
sp.disable_function.function("is_callable").param("value").value("eval").drop();
sp.disable_function.function("is_callable").param("value").value("exec").drop();
sp.disable_function.function("is_callable").param("value").value("system").drop();
sp.disable_function.function("is_callable").param("value").value("shell_exec").drop();
sp.disable_function.function("is_callable").param("value").value("proc_open").drop();
sp.disable_function.function("is_callable").param("value").value("passthru").drop();
@end_condition;
# Ghetto error-based sqli detection
# sp.disable_function.function("mysql_query").ret("FALSE").drop();
# sp.disable_function.function("mysqli_query").ret("FALSE").drop();
# sp.disable_function.function("PDO::query").ret("FALSE").drop();
# Ensure that certificates are properly verified
sp.disable_function.function("curl_setopt").param("value").value("1").allow();
sp.disable_function.function("curl_setopt").param("value").value("2").allow();
# `81` is SSL_VERIFYHOST and `64` SSL_VERIFYPEER
sp.disable_function.function("curl_setopt").param("option").value("64").drop().alias("Please don't turn CURLOPT_SSL_VERIFYCLIENT off.");
sp.disable_function.function("curl_setopt").param("option").value("81").drop().alias("Please don't turn CURLOPT_SSL_VERIFYHOST off.");
# Ensure that file:// protocol is not allowed in CURL
sp.disable_function.function("curl_setopt").param("value").value_r("file://").drop().alias("file:// protocol is disabled");
sp.disable_function.function("curl_init").param("url").value_r("file://").drop().alias("file:// protocol is disabled");
# File upload
@condition PHP_VERSION_ID >= 80000;
sp.disable_function.function("move_uploaded_file").param("to").value_r("\\.ph").drop();
sp.disable_function.function("move_uploaded_file").param("to").value_r("\\.ht").drop();
@condition PHP_VERSION_ID >= 70400;
sp.disable_function.function("move_uploaded_file").param("new_path").value_r("\\.ph").drop();
sp.disable_function.function("move_uploaded_file").param("new_path").value_r("\\.ht").drop();
@condition PHP_VERSION_ID >= 70000;
sp.disable_function.function("move_uploaded_file").param("destination").value_r("\\.ph").drop();
sp.disable_function.function("move_uploaded_file").param("destination").value_r("\\.ht").drop();
@end_condition;
# Logging lockdown
@condition PHP_VERSION_ID >= 70000;
sp.disable_function.function("ini_set").param("varname").value_r("error_log").drop();
sp.disable_function.function("ini_set").param("varname").value_r("error_reporting").drop();
sp.disable_function.function("ini_set").param("varname").value_r("display_errors").drop();
@condition PHP_VERSION_ID >= 80000;
sp.disable_function.function("ini_set").param("option").value_r("error_log").drop();
sp.disable_function.function("ini_set").param("option").value_r("error_reporting").drop();
sp.disable_function.function("ini_set").param("option").value_r("display_errors").drop();
@end_condition;
# Classic webshells patterns
sp.disable_function.function("system>base64_decode").drop();
sp.disable_function.function("shell_exec>base64_decode").drop();
sp.disable_function.function("exec>base64_decode").drop();
sp.disable_function.function("passthru>base64_decode").drop();
sp.disable_function.function("proc_open>base64_decode").drop();
sp.eval_blacklist.list("system,exec,shell_exec,passthru,proc_open");
|