Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
bef committed Aug 2, 2021
2 parents 6c132e6 + e62f226 commit 4cda012
Show file tree
Hide file tree
Showing 34 changed files with 441 additions and 149 deletions.
43 changes: 43 additions & 0 deletions .github/workflows/coverity.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Coverity scan
on:
schedule:
- cron: '0 18 * * 1' # Weekly at 18:00 UTC on Mondays

jobs:
latest:
runs-on: ubuntu-latest
container: debian:stable
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Install dependencies
run: |
apt update
DEBIAN_FRONTEND=noninteractive apt install -y --no-install-recommends php-dev curl ca-certificates make gcc
- name: Remove php8 tests on php7
run: rm -rf src/tests/*php8*/
- name: Download Coverity Build Tool
run: |
curl https://scan.coverity.com/download/linux64 --form token=$TOKEN --form project=jvoisin/snuffleupagus -o cov-analysis-linux64.tar.gz
mkdir cov-analysis-linux64
tar xzf cov-analysis-linux64.tar.gz --strip-components=1 -C cov-analysis-linux64
env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
- name: Configure
run: cd src; phpize; ./configure --enable-snuffleupagus; cd -
- name: Build with cov-build
run: ./cov-analysis-linux64/bin/cov-build --dir cov-int make compile_debug
- name: Submit the result to Coverity Scan
run: |
tar czf snuffleupagus.tgz cov-int
curl \
--form project=jvoisin/snuffleupagus \
--form token=$TOKEN \
--form [email protected] \
--form version=master \
--form [email protected] \
--form description=master \
https://scan.coverity.com/builds?project=jvoisin/snuffleupagus
env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}

32 changes: 32 additions & 0 deletions .github/workflows/distributions_php8.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: CI for linux distributions, on php8
on: ['pull_request', 'push']

jobs:
alpine:
runs-on: ubuntu-latest
container: alpine:edge
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Remove php7 tests for php8
run: rm -rf src/tests/*php7*/
- name: Remove tests failing on alpine for wathever reason
run: rm -rf src/tests/*session*/ src/tests/broken_configuration/ src/tests/*cookie* src/tests/upload_validation/
- name: Install dependencies
run: apk add php8-dev php8-cgi php8-simplexml php8-xml pcre-dev build-base php8-pear php8-openssl
- name: Install pecl
continue-on-error: true
run: pecl install vld-beta
- name: Link phpize
run: ln -s /usr/bin/phpize8 /usr/bin/phpize
- name: Link php-config
run: ln -s /usr/bin/php-config8 /usr/bin/php-config
- name: Build and run the testsuite
continue-on-error: true
run: make tests
- name: Show logs in case of failure
if: ${{ failure() }}
continue-on-error: true
run: |
grep -r . ./src/tests/*/*.out
grep -r . ./src/tests/*/*.diff
34 changes: 4 additions & 30 deletions config/default.rules
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ sp.disable_xxe.enable();
# https://snuffleupagus.readthedocs.io/features.html#protection-against-cross-site-request-forgery
sp.cookie.name("PHPSESSID").samesite("lax");

# Harden the `chmod` function
sp.disable_function.function("chmod").param("mode").value_r("^[0-9]{2}[67]$").drop();
# Harden the `chmod` function (0777 (oct = 511, 0666 = 438)
sp.disable_function.function("chmod").param("mode").value("438").drop();
sp.disable_function.function("chmod").param("mode").value("511").drop();

# Prevent various `mail`-related vulnerabilities
sp.disable_function.function("mail").param("additional_parameters").value_r("\\-").drop();
Expand Down Expand Up @@ -96,34 +97,7 @@ sp.disable_function.function("is_callable").param("var").value("shell_exec").dro
sp.disable_function.function("is_callable").param("var").value("proc_open").drop();
sp.disable_function.function("is_callable").param("var").value("passthru").drop();

# Commenting sqli related stuff to improve performance.
# TODO figure out why these functions can't be hooked at startup
# Ghetto sqli hardening
# sp.disable_function.function("mysql_query").param("query").value_r("/\\*").drop();
# sp.disable_function.function("mysql_query").param("query").value_r("--").drop();
# sp.disable_function.function("mysql_query").param("query").value_r("#").drop();
# sp.disable_function.function("mysql_query").param("query").value_r(";.*;").drop();
# sp.disable_function.function("mysql_query").param("query").value_r("benchmark").drop();
# sp.disable_function.function("mysql_query").param("query").value_r("sleep").drop();
# sp.disable_function.function("mysql_query").param("query").value_r("information_schema").drop();

# sp.disable_function.function("mysqli_query").param("query").value_r("/\\*").drop();
# sp.disable_function.function("mysqli_query").param("query").value_r("--").drop();
# sp.disable_function.function("mysqli_query").param("query").value_r("#").drop();
# sp.disable_function.function("mysqli_query").param("query").value_r(";.*;").drop();
# sp.disable_function.function("mysqli_query").param("query").value_r("benchmark").drop();
# sp.disable_function.function("mysqli_query").param("query").value_r("sleep").drop();
# sp.disable_function.function("mysqli_query").param("query").value_r("information_schema").drop();

# sp.disable_function.function("PDO::query").param("query").value_r("/\\*").drop();
# sp.disable_function.function("PDO::query").param("query").value_r("--").drop();
# sp.disable_function.function("PDO::query").param("query").value_r("#").drop();
# sp.disable_function.function("PDO::query").param("query").value_r(";.*;").drop();
# sp.disable_function.function("PDO::query").param("query").value_r("benchmark\\s*\\(").drop();
# sp.disable_function.function("PDO::query").param("query").value_r("sleep\\s*\\(").drop();
# sp.disable_function.function("PDO::query").param("query").value_r("information_schema").drop();

# Ghetto sqli detection
# 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();
Expand Down
120 changes: 120 additions & 0 deletions config/default_php8.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# This is the default configuration file for Snuffleupagus (https://snuffleupagus.rtfd.io),
# for php8.
# 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();

# Disabled XXE
sp.disable_xxe.enable();

# Global configuration variables
# sp.global.secret_key("YOU _DO_ NEED TO CHANGE THIS WITH SOME RANDOM CHARACTERS.");

# Globally activate strict mode
# https://secure.php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration.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)
sp.disable_function.function("chmod").param("permissions").value("438").drop();
sp.disable_function.function("chmod").param("permissions").value("511").drop();

# Prevent various `mail`-related vulnerabilities
sp.disable_function.function("mail").param("additional_parameters").value_r("\\-").drop();

# Since it's now burned, me might as well mitigate it publicly
sp.disable_function.function("putenv").param("assignment").value_r("LD_").drop()

# This one was burned in Nov 2019 - https://gist.github.com/LoadLow/90b60bd5535d6c3927bb24d5f9955b80
sp.disable_function.function("putenv").param("assignment").value_r("GCONV_").drop()

# Since people are stupid enough to use `extract` on things like $_GET or $_POST, we might as well mitigate this vector
sp.disable_function.function("extract").param("array").value_r("^_").drop()
sp.disable_function.function("extract").param("flags").value("0").drop()

# 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 ;)
sp.disable_function.function("ini_set").param("option").value_r("open_basedir").drop()

##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();
sp.disable_function.function("shell_exec").param("command").value_r("[$|;&`\\n\\(\\)\\\\]").drop();
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
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();

# Detect some backdoors via environment recon
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();

# 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.");

# File upload
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();

# Logging lockdown
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()
2 changes: 1 addition & 1 deletion debian/control
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Source: snuffleupagus
Priority: optional
Maintainer: Julien (jvoisin) Voisin <[email protected]>
Build-Depends: debhelper (>= 9), php-curl, php-xml, php7.0-dev | php7.1-dev | php7.2-dev | php7.3-dev | php7.4-dev
Build-Depends: debhelper (>= 9), php-curl, php-xml, php7.0-dev | php7.1-dev | php7.2-dev | php7.3-dev | php7.4-dev | php8.0-dev
Standards-Version: 4.1.3
Homepage: https://github.com/jvoisin/snuffleupagus
Section: php
Expand Down
6 changes: 6 additions & 0 deletions doc/source/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,12 @@ It can either be ``enabled`` or ``disabled`` and can be used in ``simulation`` m
sp.unserialize_hmac.enable();
sp.unserialize_hmac.disable();


.. warning::

This feature breaks web applications doing checks on the serialized
representation of data on their own, like `WordPress <https://wordpress.com/>`__.

.. _config_cookie-encryption:

Cookies-related mitigations
Expand Down
12 changes: 3 additions & 9 deletions doc/source/features.rst
Original file line number Diff line number Diff line change
Expand Up @@ -480,15 +480,9 @@ to see that people are disabling it on production too.
We're detecting/preventing this by not allowing the ``CURLOPT_SSL_VERIFYPEER`` and
``CURLOPT_SSL_VERIFYHOST`` options from being set to ``0``.

*Cheap* SQL injections detection
""""""""""""""""""""""""""""""""
*Cheap* error-based SQL injections detection
""""""""""""""""""""""""""""""""""""""""""""

In some SQL injections, attackers might need to use comments, a feature that is
often not used in production system, so it might be a good idea to filter
queries that contains some. The same filtering idea can be used against
SQL functions that are frequently used in SQL injections, like ``sleep``, ``benchmark``
or strings like ``version_info``.

On the topic of SQL injections, if a function performing a query returns ``FALSE``
If a function performing a SQL query returns ``FALSE``
(indicating an error), it might be useful to dump the request for further analysis.

1 change: 1 addition & 0 deletions doc/source/papers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ Articles
""""

- `Sortie de Snuffleupagus 0.7.0 - Los Elefantes <https://linuxfr.org/news/sortie-de-snuffleupagus-0-7-0-los-elefantes>`__ (fr) - linuxfr
- `Virtual patching CVE-2021-29447 with Snuffleupagus <https://dustri.org/b/virtual-patching-cve-2021-29447-with-snuffleupagus.html>`__ - dustri.org


Papers
Expand Down
2 changes: 1 addition & 1 deletion src/php_snuffleupagus.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ typedef void (*zif_handler)(INTERNAL_FUNCTION_PARAMETERS);
#define TSRMLS_FETCH()
#define TSRMLS_C
#else
#if ( !HAVE_PCRE && !HAVE_BUNDLED_PCRE )
#if (!HAVE_PCRE && !HAVE_BUNDLED_PCRE)
#error Snuffleupagus requires PHP7+ with PCRE support
#endif
#endif
Expand Down
Loading

0 comments on commit 4cda012

Please sign in to comment.