diff options
| author | Sebastien Blot | 2017-09-20 10:11:01 +0200 |
|---|---|---|
| committer | Sebastien Blot | 2017-09-20 10:11:01 +0200 |
| commit | 868f96c759b6650d88ff9f4fbc5c048302134248 (patch) | |
| tree | c0de0af318bf77a8959164ef11aeeeb2b7bab294 /doc | |
Initial import
Diffstat (limited to 'doc')
| -rw-r--r-- | doc/Makefile | 20 | ||||
| -rw-r--r-- | doc/source/_static/custom.css | 4 | ||||
| -rw-r--r-- | doc/source/_static/sp.jpg | bin | 0 -> 36559 bytes | |||
| -rw-r--r-- | doc/source/conf.py | 178 | ||||
| -rw-r--r-- | doc/source/config.rst | 283 | ||||
| -rw-r--r-- | doc/source/download.rst | 16 | ||||
| -rw-r--r-- | doc/source/faq.rst | 196 | ||||
| -rw-r--r-- | doc/source/features.rst | 352 | ||||
| -rw-r--r-- | doc/source/index.rst | 30 | ||||
| -rw-r--r-- | doc/source/installation.rst | 33 | ||||
| -rw-r--r-- | doc/source/papers.rst | 16 |
11 files changed, 1128 insertions, 0 deletions
diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000..7355011 --- /dev/null +++ b/doc/Makefile | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | # Minimal makefile for Sphinx documentation | ||
| 2 | # | ||
| 3 | |||
| 4 | # You can set these variables from the command line. | ||
| 5 | SPHINXOPTS = | ||
| 6 | SPHINXBUILD = sphinx-build | ||
| 7 | SPHINXPROJ = Snuffleupagus | ||
| 8 | SOURCEDIR = source | ||
| 9 | BUILDDIR = build | ||
| 10 | |||
| 11 | # Put it first so that "make" without argument is like "make help". | ||
| 12 | help: | ||
| 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) | ||
| 14 | |||
| 15 | .PHONY: help Makefile | ||
| 16 | |||
| 17 | # Catch-all target: route all unknown targets to Sphinx using the new | ||
| 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). | ||
| 19 | %: Makefile | ||
| 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file | ||
diff --git a/doc/source/_static/custom.css b/doc/source/_static/custom.css new file mode 100644 index 0000000..1c47d04 --- /dev/null +++ b/doc/source/_static/custom.css | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | blockquote { | ||
| 2 | border-left: 2px solid #999; | ||
| 3 | padding-left: 20px; | ||
| 4 | } \ No newline at end of file | ||
diff --git a/doc/source/_static/sp.jpg b/doc/source/_static/sp.jpg new file mode 100644 index 0000000..0575ca7 --- /dev/null +++ b/doc/source/_static/sp.jpg | |||
| Binary files differ | |||
diff --git a/doc/source/conf.py b/doc/source/conf.py new file mode 100644 index 0000000..b2af5f2 --- /dev/null +++ b/doc/source/conf.py | |||
| @@ -0,0 +1,178 @@ | |||
| 1 | # -*- coding: utf-8 -*- | ||
| 2 | # | ||
| 3 | # Snuffleupagus documentation build configuration file, created by | ||
| 4 | # sphinx-quickstart on Tue Jun 27 14:15:46 2017. | ||
| 5 | # | ||
| 6 | # This file is execfile()d with the current directory set to its | ||
| 7 | # containing dir. | ||
| 8 | # | ||
| 9 | # Note that not all possible configuration values are present in this | ||
| 10 | # autogenerated file. | ||
| 11 | # | ||
| 12 | # All configuration values have a default; values that are commented out | ||
| 13 | # serve to show the default. | ||
| 14 | |||
| 15 | # If extensions (or modules to document with autodoc) are in another directory, | ||
| 16 | # add these directories to sys.path here. If the directory is relative to the | ||
| 17 | # documentation root, use os.path.abspath to make it absolute, like shown here. | ||
| 18 | # | ||
| 19 | # import os | ||
| 20 | # import sys | ||
| 21 | # sys.path.insert(0, os.path.abspath('.')) | ||
| 22 | from datetime import datetime | ||
| 23 | |||
| 24 | |||
| 25 | # -- General configuration ------------------------------------------------ | ||
| 26 | |||
| 27 | # If your documentation needs a minimal Sphinx version, state it here. | ||
| 28 | # | ||
| 29 | # needs_sphinx = '1.0' | ||
| 30 | |||
| 31 | # Add any Sphinx extension module names here, as strings. They can be | ||
| 32 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom | ||
| 33 | # ones. | ||
| 34 | #extensions = ['sphinx.ext.githubpages'] | ||
| 35 | |||
| 36 | # Add any paths that contain templates here, relative to this directory. | ||
| 37 | templates_path = ['_templates'] | ||
| 38 | |||
| 39 | # The suffix(es) of source filenames. | ||
| 40 | # You can specify multiple suffix as a list of string: | ||
| 41 | # | ||
| 42 | # source_suffix = ['.rst', '.md'] | ||
| 43 | source_suffix = '.rst' | ||
| 44 | |||
| 45 | # The master toctree document. | ||
| 46 | master_doc = 'index' | ||
| 47 | |||
| 48 | # General information about the project. | ||
| 49 | project = u'Snuffleupagus' | ||
| 50 | copyright = u'%d, NBS System' % datetime.now().year | ||
| 51 | author = u'Sebastien Blot & Julien Voisin' | ||
| 52 | |||
| 53 | # The version info for the project you're documenting, acts as replacement for | ||
| 54 | # |version| and |release|, also used in various other places throughout the | ||
| 55 | # built documents. | ||
| 56 | # | ||
| 57 | # The short X.Y version. | ||
| 58 | version = u'0.1' | ||
| 59 | # The full version, including alpha/beta/rc tags. | ||
| 60 | release = u'Public Alpha' | ||
| 61 | |||
| 62 | # The language for content autogenerated by Sphinx. Refer to documentation | ||
| 63 | # for a list of supported languages. | ||
| 64 | # | ||
| 65 | # This is also used if you do content translation via gettext catalogs. | ||
| 66 | # Usually you set "language" from the command line for these cases. | ||
| 67 | language = None | ||
| 68 | |||
| 69 | # List of patterns, relative to source directory, that match files and | ||
| 70 | # directories to ignore when looking for source files. | ||
| 71 | # This patterns also effect to html_static_path and html_extra_path | ||
| 72 | exclude_patterns = [] | ||
| 73 | |||
| 74 | # The name of the Pygments (syntax highlighting) style to use. | ||
| 75 | pygments_style = 'manni' | ||
| 76 | |||
| 77 | # If true, `todo` and `todoList` produce output, else they produce nothing. | ||
| 78 | todo_include_todos = False | ||
| 79 | |||
| 80 | |||
| 81 | # -- Options for HTML output ---------------------------------------------- | ||
| 82 | |||
| 83 | # The theme to use for HTML and HTML Help pages. See the documentation for | ||
| 84 | # a list of builtin themes. | ||
| 85 | # | ||
| 86 | html_theme = 'alabaster' | ||
| 87 | |||
| 88 | # Theme options are theme-specific and customize the look and feel of a theme | ||
| 89 | # further. For a list of options available for each theme, see the | ||
| 90 | # documentation. | ||
| 91 | # | ||
| 92 | |||
| 93 | html_sidebars = { | ||
| 94 | '**': [ | ||
| 95 | 'about.html', | ||
| 96 | 'navigation.html', | ||
| 97 | 'relations.html', | ||
| 98 | 'searchbox.html', | ||
| 99 | #'donate.html', | ||
| 100 | ] | ||
| 101 | } | ||
| 102 | html_theme_options = { | ||
| 103 | 'logo': './sp.jpg', | ||
| 104 | #'description': '<br>Killing bug-classes in PHP 7, virtual-patching the rest.', | ||
| 105 | #'fixed_sidebar': True, | ||
| 106 | 'page_width': '60%', | ||
| 107 | 'show_powered_by': False, | ||
| 108 | } | ||
| 109 | |||
| 110 | sidebar_collapse = True | ||
| 111 | |||
| 112 | # Add any paths that contain custom static files (such as style sheets) here, | ||
| 113 | # relative to this directory. They are copied after the builtin static files, | ||
| 114 | # so a file named "default.css" will overwrite the builtin "default.css". | ||
| 115 | html_static_path = ['_static'] | ||
| 116 | |||
| 117 | #html_logo = './sp.png' | ||
| 118 | |||
| 119 | html_show_sphinx = False | ||
| 120 | |||
| 121 | # -- Options for HTMLHelp output ------------------------------------------ | ||
| 122 | |||
| 123 | # Output file base name for HTML help builder. | ||
| 124 | htmlhelp_basename = 'Snuffleupagusdoc' | ||
| 125 | |||
| 126 | |||
| 127 | # -- Options for LaTeX output --------------------------------------------- | ||
| 128 | |||
| 129 | latex_elements = { | ||
| 130 | # The paper size ('letterpaper' or 'a4paper'). | ||
| 131 | # | ||
| 132 | # 'papersize': 'letterpaper', | ||
| 133 | |||
| 134 | # The font size ('10pt', '11pt' or '12pt'). | ||
| 135 | # | ||
| 136 | # 'pointsize': '10pt', | ||
| 137 | |||
| 138 | # Additional stuff for the LaTeX preamble. | ||
| 139 | # | ||
| 140 | # 'preamble': '', | ||
| 141 | |||
| 142 | # Latex figure (float) alignment | ||
| 143 | # | ||
| 144 | # 'figure_align': 'htbp', | ||
| 145 | } | ||
| 146 | |||
| 147 | # Grouping the document tree into LaTeX files. List of tuples | ||
| 148 | # (source start file, target name, title, | ||
| 149 | # author, documentclass [howto, manual, or own class]). | ||
| 150 | latex_documents = [ | ||
| 151 | (master_doc, 'Snuffleupagus.tex', u'Snuffleupagus Documentation', | ||
| 152 | u'Sebastien Blot \\& Julien Voisin', 'manual'), | ||
| 153 | ] | ||
| 154 | |||
| 155 | |||
| 156 | # -- Options for manual page output --------------------------------------- | ||
| 157 | |||
| 158 | # One entry per manual page. List of tuples | ||
| 159 | # (source start file, name, description, authors, manual section). | ||
| 160 | man_pages = [ | ||
| 161 | (master_doc, 'snuffleupagus', u'Snuffleupagus Documentation', | ||
| 162 | [author], 1) | ||
| 163 | ] | ||
| 164 | |||
| 165 | |||
| 166 | # -- Options for Texinfo output ------------------------------------------- | ||
| 167 | |||
| 168 | # Grouping the document tree into Texinfo files. List of tuples | ||
| 169 | # (source start file, target name, title, author, | ||
| 170 | # dir menu entry, description, category) | ||
| 171 | texinfo_documents = [ | ||
| 172 | (master_doc, 'Snuffleupagus', u'Snuffleupagus Documentation', | ||
| 173 | author, 'Snuffleupagus', 'One line description of project.', | ||
| 174 | 'Miscellaneous'), | ||
| 175 | ] | ||
| 176 | |||
| 177 | |||
| 178 | |||
diff --git a/doc/source/config.rst b/doc/source/config.rst new file mode 100644 index 0000000..8318e7d --- /dev/null +++ b/doc/source/config.rst | |||
| @@ -0,0 +1,283 @@ | |||
| 1 | Configuration | ||
| 2 | ============= | ||
| 3 | |||
| 4 | Since PHP *ini-like* configuration model isn't flexible enough, | ||
| 5 | Snuffleupagus is using its own format. | ||
| 6 | |||
| 7 | Options are chainable by using dots (``.``), and string parameters | ||
| 8 | **must** be quoted, while booleans and integers aren't. | ||
| 9 | |||
| 10 | Comments are prefixed either with ``#``, or ``;``. | ||
| 11 | |||
| 12 | Some rules applies in a specific ``function`` (context), on a specific ``variable`` | ||
| 13 | (data), like ``disable_functions``, others can only be enabled/disabled, like | ||
| 14 | ``harden_random``. | ||
| 15 | |||
| 16 | .. warning:: | ||
| 17 | |||
| 18 | Careful, a wrongly configured Snuffleupagus might break your website. | ||
| 19 | It's up to you to understand its :doc:`features <features>`, | ||
| 20 | read the present documentation about how to configure them, | ||
| 21 | evaluate your threat model, and write your configuration file accordingly. | ||
| 22 | |||
| 23 | The rules are evaluated in the order that they are written, and the **first** one | ||
| 24 | to match will terminate the evaluation (except for rules in simulation mode). | ||
| 25 | |||
| 26 | Bugclass-killer features | ||
| 27 | ------------------------ | ||
| 28 | |||
| 29 | global_strict | ||
| 30 | ^^^^^^^^^^^^^ | ||
| 31 | `default: disabled` | ||
| 32 | |||
| 33 | ``global_strict`` will enable the `strict <https://secure.php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration.strict>`_ mode globally, | ||
| 34 | forcing PHP to throw a `TypeError <https://secure.php.net/manual/en/class.typeerror.php>`_ | ||
| 35 | exception if an argument type being passed to a function does not match its corresponding declared parameter type. | ||
| 36 | |||
| 37 | It can either be ``enabled`` or ``disabled`` | ||
| 38 | |||
| 39 | :: | ||
| 40 | |||
| 41 | sp.global_strict.disable(); | ||
| 42 | sp.global_strict.enable(); | ||
| 43 | |||
| 44 | harden_random | ||
| 45 | ^^^^^^^^^^^^^ | ||
| 46 | * `default: enabled` | ||
| 47 | * `more <features.html#weak-prng-via-rand-mt-rand>`__ | ||
| 48 | |||
| 49 | ``harden_random`` will silently replace the insecure `rand <https://secure.php.net/manual/en/function.rand.php>`_ | ||
| 50 | and `mt_rand <https://secure.php.net/manual/en/function.mt-rand.php>`_ functions with | ||
| 51 | the secure PRNG `random_int <https://secure.php.net/manual/en/function.random-int.php>`_. | ||
| 52 | |||
| 53 | It can either be ``enabled`` or ``disabled``. | ||
| 54 | |||
| 55 | :: | ||
| 56 | |||
| 57 | sp.harden_random.enable(); | ||
| 58 | sp.harden_random.disable(); | ||
| 59 | |||
| 60 | .. _config_global: | ||
| 61 | |||
| 62 | global | ||
| 63 | ^^^^^^ | ||
| 64 | |||
| 65 | This configuration variable contain parameters that are used by other ones: | ||
| 66 | |||
| 67 | - ``secret_key``: A secret key used by various cryptographic features, | ||
| 68 | like `cookies protection <features.html#session-cookie-stealing-via-xss>`__ or `unserialize protection <features.html#unserialize-related-magic>`__, | ||
| 69 | so do make sure that it's random and long enough. | ||
| 70 | You can generate it with something like this: ``head -c 256 /dev/urandom | tr -dc 'a-zA-Z0-9'``. | ||
| 71 | |||
| 72 | :: | ||
| 73 | |||
| 74 | sp.global.secret_key("44239bd400aa82e125337c9d4eb8315767411ccd"); | ||
| 75 | |||
| 76 | unserialize_hmac | ||
| 77 | ^^^^^^^^^^^^^^^^ | ||
| 78 | * `default: disabled` | ||
| 79 | * `more <features.html#unserialize-related-magic>`__ | ||
| 80 | |||
| 81 | ``unserialize_hmac`` will add integrity check to ``unserialize`` calls, preventing | ||
| 82 | abritrary code execution in their context. | ||
| 83 | |||
| 84 | :: | ||
| 85 | |||
| 86 | sp.unserialize_hmac.enable(); | ||
| 87 | sp.unserialize_hmac.disable(); | ||
| 88 | |||
| 89 | |||
| 90 | auto_cookie_secure | ||
| 91 | ^^^^^^^^^^^^^^^^^^ | ||
| 92 | * `default: disabled` | ||
| 93 | * `more <features.html#session-cookie-stealing-via-xss>`__ | ||
| 94 | |||
| 95 | ``auto_cookie_secure`` will automatically mark cookies as `secure <https://en.wikipedia.org/wiki/HTTP_cookie#Secure_cookie>`_ | ||
| 96 | when the web page is requested over HTTPS. | ||
| 97 | |||
| 98 | It can either be ``enabled`` or ``disabled``. | ||
| 99 | |||
| 100 | :: | ||
| 101 | |||
| 102 | sp.auto_cookie_secure.enable(); | ||
| 103 | sp.auto_cookie_secure.disable(); | ||
| 104 | |||
| 105 | cookie_encryption | ||
| 106 | ^^^^^^^^^^^^^^^^^ | ||
| 107 | * `default: disabled` | ||
| 108 | * `more <features.html#session-cookie-stealing-via-xss>`__ | ||
| 109 | |||
| 110 | .. warning:: | ||
| 111 | |||
| 112 | To use this feature, you **must** set the :ref:`global.secret_key <config_global>` variable. | ||
| 113 | This design decision prevents attacker from | ||
| 114 | `trivially bruteforcing <https://www.idontplaydarts.com/2011/11/decrypting-suhosin-sessions-and-cookies/>`_ | ||
| 115 | session cookies. | ||
| 116 | |||
| 117 | ``cookie_secure`` will activate transparent encryption of specific cookies. | ||
| 118 | |||
| 119 | It can either be ``enabled`` or ``disabled``. | ||
| 120 | |||
| 121 | :: | ||
| 122 | |||
| 123 | sp.cookie_encryption.cookie("my_cookie_name"); | ||
| 124 | sp.cookie_encryption.cookie("another_cookie_name"); | ||
| 125 | |||
| 126 | |||
| 127 | readonly_exec | ||
| 128 | ^^^^^^^^^^^^^ | ||
| 129 | * `default: disabled` | ||
| 130 | |||
| 131 | ``readonly_exec`` will prevent the execution of writable PHP files. | ||
| 132 | |||
| 133 | It can either be ``enabled`` or ``disabled``. | ||
| 134 | |||
| 135 | :: | ||
| 136 | |||
| 137 | sp.readonly_exec.enable(); | ||
| 138 | |||
| 139 | upload_validation | ||
| 140 | ^^^^^^^^^^^^^^^^^ | ||
| 141 | * `default: disabled` | ||
| 142 | * `more <features.html#remote-code-execution-via-file-upload>`__ | ||
| 143 | |||
| 144 | ``upload_validation`` will call a given script upon a file upload, with the path | ||
| 145 | to the file being uploaded as argument, and various information about it in the environment: | ||
| 146 | |||
| 147 | * ``SP_FILENAME``: the name of the uploaded file | ||
| 148 | * ``SP_FILESIZE``: the size of the file being uploaded | ||
| 149 | * ``SP_REMOTE_ADDR``: the ip address of the uploader | ||
| 150 | * ``SP_CURRENT_FILE``: the current file being executed | ||
| 151 | |||
| 152 | This feature can be used, for example, to check if an uploaded file contains php | ||
| 153 | code, with something like `vld <https://derickrethans.nl/projects.html#vld>`_ | ||
| 154 | (``php -d vld.execute=0 -d vld.active=1 -d extension=vld.so yourfile.php``). | ||
| 155 | |||
| 156 | The upload will be **allowed** if the script return the value ``0``. Every other | ||
| 157 | value will prevent the file from being uploaded. | ||
| 158 | |||
| 159 | :: | ||
| 160 | |||
| 161 | sp.upload_validation.script("/var/www/is_valid_php.py").enable(); | ||
| 162 | |||
| 163 | |||
| 164 | disable_xxe | ||
| 165 | ^^^^^^^^^^^ | ||
| 166 | * `default: enabled` | ||
| 167 | * `more <features.html#xxe>`__ | ||
| 168 | |||
| 169 | ``disable_xxe`` will prevent XXE attacks by disabling the loading of external entities (``libxml_disable_entity_loader``) in the XML parser. | ||
| 170 | |||
| 171 | :: | ||
| 172 | |||
| 173 | sp.disable_xxe.enable(); | ||
| 174 | |||
| 175 | |||
| 176 | Virtual-patching | ||
| 177 | ---------------- | ||
| 178 | |||
| 179 | Snuffleupagus provides virtual-patching, via the ``disable_functions`` directive, allowing you to stop or control dangerous behaviours. | ||
| 180 | Admitting you have a call to ``system()`` that lacks proper user-input validation, thus leading to an **RCE**, this might be the right tool. | ||
| 181 | |||
| 182 | :: | ||
| 183 | |||
| 184 | # Allow `id.php` to restrict system() calls to `id` | ||
| 185 | sp.disable_functions.function("system").filename("id.php").param("cmd").value("id").allow(); | ||
| 186 | sp.disable_functions.function("system").filename("id.php").drop() | ||
| 187 | |||
| 188 | Of course, this is a trivial example, and a lot can be achieved with this feature, as you will see below. | ||
| 189 | |||
| 190 | |||
| 191 | Filters | ||
| 192 | ^^^^^^^ | ||
| 193 | |||
| 194 | - ``alias(:str)``: human-readable description of the rule | ||
| 195 | - ``cidr(ip/mask:str)``: match on the client's `cidr <https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing>`_ | ||
| 196 | - ``filename(name:str)``: match in the file ``name`` | ||
| 197 | - ``filename_r(regexp:str)``: the file name matching the ``regexp`` | ||
| 198 | - ``function(name:str)``: match on function ``name`` | ||
| 199 | - ``function_r(regexp:str)``: the function matching the ``regexp`` | ||
| 200 | - ``hash(:str)``: match on the file's `sha256 <https://en.wikipedia.org/wiki/SHA-2>`_ sum | ||
| 201 | - ``param(name:str)``: match on the function's parameter ``name`` | ||
| 202 | - ``param_r(regexp:str)``: match on the function's parameter ``regexp`` | ||
| 203 | - ``param_type(type:str)``: match on the function's parameter ``type`` | ||
| 204 | - ``ret(value:str)``: match on the function's return ``value`` | ||
| 205 | - ``ret_r(regexp:str)``: match with a ``regexp`` on the function's return | ||
| 206 | - ``ret_type(type_name:str)``: match on the ``type_name`` of the function's return value | ||
| 207 | - ``value(:str)``: match on a litteral value | ||
| 208 | - ``value_r(:regexp)``: match on a value matching the ``regexp`` | ||
| 209 | - ``var(name:str)``: match on a **local variable** ``name`` | ||
| 210 | |||
| 211 | The ``type`` must be one of the following values: | ||
| 212 | |||
| 213 | - ``FALSE``: for boolean false | ||
| 214 | - ``TRUE``: for boolean true | ||
| 215 | - ``NULL``: for the **null** value | ||
| 216 | - ``LONG``: for a long (also know as ``integer``) value | ||
| 217 | - ``DOUBLE``: for a **double** (also known as ``float``) value | ||
| 218 | - ``STRING``: for a string | ||
| 219 | - ``OBJECT``: for a object | ||
| 220 | - ``ARRAY``: for an array | ||
| 221 | - ``RESOURCE``: for a resource | ||
| 222 | |||
| 223 | Actions | ||
| 224 | ^^^^^^^ | ||
| 225 | |||
| 226 | - ``allow()``: **allow** the request if the rule matches | ||
| 227 | - ``drop()``: **drop** the request if the rule matches | ||
| 228 | - ``dump(directory:str)``: dump the request in the ``directory`` if it matches the rule | ||
| 229 | - ``simulation()``: enabled the simulation mode | ||
| 230 | |||
| 231 | Details | ||
| 232 | ^^^^^^^ | ||
| 233 | |||
| 234 | The ``function`` filter is able to do various dereferencing: | ||
| 235 | |||
| 236 | - ``function("AwesomeClass::my_method")`` will match in the method ``my_method`` in the class ``AwesomeClass`` | ||
| 237 | |||
| 238 | The ``param`` filter is also able to do some dereferencing: | ||
| 239 | |||
| 240 | - ``param(foo[bar])`` will get match on the value corresponding to the ``bar`` key in the hashtable ``foo``. | ||
| 241 | Remember that in PHP, almost every data structure is a hashtable. You can of course nest this like | ||
| 242 | ``param(foo[bar][baz][batman])``. | ||
| 243 | - The ``var`` filter will walk the calltrace until it finds the variable's name, or the end of it, | ||
| 244 | allowing to match on global variables: ``.var("_GET[param]")`` will match on the GET parameter ``param``. | ||
| 245 | |||
| 246 | For clarity's sake, the presence of the ``allow`` or ``drop`` action is **mandatory**. | ||
| 247 | |||
| 248 | .. warning:: | ||
| 249 | |||
| 250 | When you're writing rules, please do keep in mind that the **order matters**. | ||
| 251 | For example, if you're denying a call to ``system()`` and then allowing it in a | ||
| 252 | more narrowed way later, the call will be denied, | ||
| 253 | because it'll match the deny first. | ||
| 254 | |||
| 255 | If you're paranoid, we're providing a php script to automatically generate | ||
| 256 | hash of files containing dangerous functions, | ||
| 257 | and blacklisting them everywhere else. | ||
| 258 | |||
| 259 | Examples | ||
| 260 | ^^^^^^^^ | ||
| 261 | |||
| 262 | Evaluation order of rules | ||
| 263 | """"""""""""""""""""""""" | ||
| 264 | |||
| 265 | The following rules will: | ||
| 266 | |||
| 267 | 1. Allow calls to ``system("id")`` | ||
| 268 | 2. Issue a trace in the logs on calls to ``system`` with its parameters starting with ``ping``, | ||
| 269 | and pursuing evaluation of the remaining rules. | ||
| 270 | 3. Drop calls to ``system``. | ||
| 271 | |||
| 272 | |||
| 273 | :: | ||
| 274 | |||
| 275 | sp.disable_functions.function("system").param("cmd").value("id").allow(); | ||
| 276 | sp.disable_functions.function("system").param("cmd").value_r("^ping").drop().simulation(); | ||
| 277 | sp.disable_functions.function("system").param("cmd").drop(); | ||
| 278 | |||
| 279 | Miscellaneous examples | ||
| 280 | """""""""""""""""""""" | ||
| 281 | |||
| 282 | .. literalinclude:: ../../config/examples.ini | ||
| 283 | :language: python \ No newline at end of file | ||
diff --git a/doc/source/download.rst b/doc/source/download.rst new file mode 100644 index 0000000..161937f --- /dev/null +++ b/doc/source/download.rst | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | Download | ||
| 2 | ======== | ||
| 3 | |||
| 4 | Debian | ||
| 5 | ------ | ||
| 6 | |||
| 7 | |||
| 8 | Ubuntu | ||
| 9 | ------ | ||
| 10 | |||
| 11 | |||
| 12 | Source code | ||
| 13 | ----------- | ||
| 14 | |||
| 15 | :: | ||
| 16 | git clone https://github.com/nbs-system.com/snuffleupagus | ||
diff --git a/doc/source/faq.rst b/doc/source/faq.rst new file mode 100644 index 0000000..07aba33 --- /dev/null +++ b/doc/source/faq.rst | |||
| @@ -0,0 +1,196 @@ | |||
| 1 | FAQ | ||
| 2 | === | ||
| 3 | |||
| 4 | General | ||
| 5 | ------- | ||
| 6 | |||
| 7 | What is Snuffleupagus? | ||
| 8 | """""""""""""""""""""" | ||
| 9 | |||
| 10 | Snuffleupagus is a `PHP7+ <http://php.net/manual/en/migration70.php>`_ | ||
| 11 | module designed to drastically raising the cost of attacks against website, | ||
| 12 | by killing entire bug classes, and also providing a powerful virtual-patching system, | ||
| 13 | allowing administrator to fix specific vulnerabilities without having to touch the PHP code. | ||
| 14 | |||
| 15 | |||
| 16 | Where does the name *Snuffeupagus* comes from? | ||
| 17 | """""""""""""""""""""""""""""""""""""""""""""" | ||
| 18 | |||
| 19 | Aloysius Snuffleupagus, more commonly known as Mr. Snuffleupagus, Snuffleupagus | ||
| 20 | or Snuffy for short, is one of the characters on Sesame Street, | ||
| 21 | the educational television program for young children. | ||
| 22 | |||
| 23 | He was created as a woolly mammoth, without tusks or (visible) ears, | ||
| 24 | and has a long thick pointed tail, similar in shape to that of a dinosaur | ||
| 25 | or other reptile. He has long thick brown hair and a trunk, or "snuffle", | ||
| 26 | that drags along the ground. He is Big Bird's best friend and | ||
| 27 | has a baby sister named Alice. He also attends "Snufflegarten". | ||
| 28 | |||
| 29 | --- `Wikipedia <https://en.wikipedia.org/wiki/Mr._Snuffleupagus>`_ | ||
| 30 | |||
| 31 | |||
| 32 | Why is Snuffleupagus called Snuffleupagus? | ||
| 33 | """""""""""""""""""""""""""""""""""""""""" | ||
| 34 | |||
| 35 | Like PHP's `ElePHPant <https://secure.php.net/elephpant.php>`_, | ||
| 36 | we thought that using an elephant as a mascot would be a great idea. | ||
| 37 | |||
| 38 | |||
| 39 | Why did you write Snuffleupagus? | ||
| 40 | """""""""""""""""""""""""""""""" | ||
| 41 | |||
| 42 | We're working for `NBS System <https://nbs-system.com/en/>`__, | ||
| 43 | a web hosting company (meaning that we're dealing with PHP code all day long), | ||
| 44 | with a strong focus on security. We do have hardening | ||
| 45 | (kernel, `WAF <https://naxsi.org>`_, `IDS <https://en.wikipedia.org/wiki/Intrusion_detection_system>`_, …) | ||
| 46 | below the web stack, but most of the time, when a website is compromised, | ||
| 47 | it's either to send ads, spam, deface it, steal data, … | ||
| 48 | This is why we need to harden the website itself too, but we can't touch its | ||
| 49 | source code. | ||
| 50 | |||
| 51 | Why not Suhosin? | ||
| 52 | """""""""""""""" | ||
| 53 | |||
| 54 | We're huge fans of `Suhosin <https://suhosin.org>`_, unfortunately: | ||
| 55 | |||
| 56 | - it doesn't work very well on PHP 7 | ||
| 57 | - it has some oudated features and misses new ones | ||
| 58 | - it doesn't cope very well with our various industrialization needs | ||
| 59 | - it has some shortcomings by design | ||
| 60 | |||
| 61 | We're using the `disable_function <https://secure.php.net/manual/en/ini.core.php#ini.disable-functions>`_ | ||
| 62 | directive, but unfortunately, it doesn't provide enough usable granularity (guess how many CMS are using | ||
| 63 | ``system`` to do various mandatory maintenance tasks…). | ||
| 64 | |||
| 65 | This is why we decided to write our own hardening module, in the spirit of Suhosin, | ||
| 66 | via virtual-patching support, and other cool new features. | ||
| 67 | |||
| 68 | What license is Snuffleupagus under and why? | ||
| 69 | """""""""""""""""""""""""""""""""""""""""""" | ||
| 70 | |||
| 71 | Snuffleupagus is licensed under the `LGPL <https://www.gnu.org/copyleft/lesser.html>`_, | ||
| 72 | and is developed by the fine people from `NBS System <https://nbs-system.com/>`__. | ||
| 73 | |||
| 74 | We chose the LGPL because we don't care that much how you're using Snuffleupagus, | ||
| 75 | but we'd like to force people to make their improvements/contributions | ||
| 76 | available to everyone. | ||
| 77 | |||
| 78 | Should I use Snuffleupagus? | ||
| 79 | """"""""""""""""""""""""""" | ||
| 80 | |||
| 81 | Yes. | ||
| 82 | |||
| 83 | Even if you're not using the virtual-patching capabilities, Snuffleupagus comes | ||
| 84 | with various passive features that won't break your website while killing numerous vulnerabilities. | ||
| 85 | |||
| 86 | Please keep in mind that you are not only protecting yourself and your users/customers, | ||
| 87 | but also other people on the internet that might be attacked by your server if | ||
| 88 | it becomes compromised. | ||
| 89 | |||
| 90 | How mature is this project? | ||
| 91 | """"""""""""""""""""""""""" | ||
| 92 | |||
| 93 | This project was floating around since early 2016, and we did the first commit | ||
| 94 | the 28ᵗʰ of December of the same year. We're currently in a private alpha phase, | ||
| 95 | finding and fixing as much bugs as possible with the help of friends. | ||
| 96 | |||
| 97 | Are you saying that PHP isn't secure? | ||
| 98 | """"""""""""""""""""""""""""""""""""" | ||
| 99 | |||
| 100 | We don't like PHP's approach of security; namely (sometimes) adding warnings | ||
| 101 | in the documentation and trusting the developer to not do any mistake, | ||
| 102 | instead of focusing on the root cause, and killing the | ||
| 103 | bug class one for all. | ||
| 104 | |||
| 105 | Moreover, it seems that the current attitude toward security in the PHP world | ||
| 106 | is to `blame the user <https://externals.io/message/100147>`_ instead of acknowledging | ||
| 107 | issues, as stated in their `documentation <https://wiki.php.net/security#not_a_security_issue>`_. | ||
| 108 | We do think that an security issue that "requires the use of code or settings known to be insecure" | ||
| 109 | is still a security issue, and should be treated as such. | ||
| 110 | |||
| 111 | Installation and configuration | ||
| 112 | ------------------------------ | ||
| 113 | |||
| 114 | Can snuffleupagus break my application? | ||
| 115 | """"""""""""""""""""""""""""""""""""""" | ||
| 116 | Yes. | ||
| 117 | |||
| 118 | Some options won't break anything, like ``harden_rand``, but some like ``global_strict`` | ||
| 119 | or overly-restrictives virtual-patching rules might pretty well break your website. | ||
| 120 | It's up to you to configure Snuffleupaggus accordingly to your needs. | ||
| 121 | |||
| 122 | You can also enable the ``simulation`` mode on features that you're not sure about, | ||
| 123 | to see what would snuffleupagus do to your application, before activating them for good. | ||
| 124 | |||
| 125 | How can I find out the problem when my application breaks? | ||
| 126 | """""""""""""""""""""""""""""""""""""""""""""""""""""""""" | ||
| 127 | |||
| 128 | By checking the logs; Snuffleupagus systematically prefix them with ``[snuffleupagus]``. | ||
| 129 | |||
| 130 | |||
| 131 | Does Snuffleupagus run on Windows? | ||
| 132 | """""""""""""""""""""""""""""""""" | ||
| 133 | No idea. | ||
| 134 | |||
| 135 | |||
| 136 | Will Snuffleupagus run on my old PHP 5? | ||
| 137 | """"""""""""""""""""""""""""""""""""""" | ||
| 138 | No. | ||
| 139 | |||
| 140 | Since PHP5 `will be deprecated at the end of 2018 <http://php.net/supported-versions.php>`_, | ||
| 141 | you should think about moving to PHP7 anyway. You can (and should) use | ||
| 142 | `Suhosin <https://suhosin.org>`_ in the meantime. | ||
| 143 | |||
| 144 | Help and support | ||
| 145 | ---------------- | ||
| 146 | |||
| 147 | I found a security issue | ||
| 148 | """""""""""""""""""""""" | ||
| 149 | If you believe you have found a security issue affecting Snuffleupagus, | ||
| 150 | then we would be more than happy to hear from you! | ||
| 151 | |||
| 152 | We promise to treat any reported issue seriously and, | ||
| 153 | if the investigation confirms it affects Snuffleupagus, | ||
| 154 | to patch it within a reasonable time, | ||
| 155 | release a public announcement that describes the issue, | ||
| 156 | discuss potential impact of the vulnerability, | ||
| 157 | reference applicable patches or workarounds, | ||
| 158 | and credit the discoverer. | ||
| 159 | |||
| 160 | Please send it us a mail to the ``snuffleupagus`` user, | ||
| 161 | on ``nbs-system.com``. | ||
| 162 | |||
| 163 | I found a bug. How can I report it? | ||
| 164 | """"""""""""""""""""""""""""""""""" | ||
| 165 | We do have an issue tracker on `Github <https://github.com/nbs-system/snuffleupagus/issues>`_. | ||
| 166 | Please make sure to include as much information as possible when reporting your issue, | ||
| 167 | such as your operating system, your version of PHP 7, your version of snuffleupagus, | ||
| 168 | your logs, the problematic php code, the request, a brief description, … long story short, | ||
| 169 | give us everything that you can. | ||
| 170 | |||
| 171 | Where can I find even more help? | ||
| 172 | """""""""""""""""""""""""""""""" | ||
| 173 | The :doc:`configuration page <config>` might be what you're looking for. | ||
| 174 | If you're adventurous, you can also check the `issue tracker <https://github.com/nbs-system/snuffleupagus/issues/?q=is%3Aissue>`_ | ||
| 175 | (make sure to check the closed issues too). | ||
| 176 | |||
| 177 | I need professional support for my company. | ||
| 178 | """"""""""""""""""""""""""""""""""""""""""" | ||
| 179 | Contact `NBS System <https://nbs-system.com>`_. | ||
| 180 | |||
| 181 | Unimplemented mitigations and abandoned ideas | ||
| 182 | --------------------------------------------- | ||
| 183 | |||
| 184 | Contant time comparisons | ||
| 185 | """""""""""""""""""""""" | ||
| 186 | We didn't manage to perform time-based side-channel attacks on strings | ||
| 187 | against real world PHP application, and the results that we gathered on | ||
| 188 | tailored test cases weren't concluding: for simplicity's sake, we chose | ||
| 189 | to not implement a mitigation against this class of attacks. | ||
| 190 | |||
| 191 | We would be happy to be proven wrong, and reconsider implementing this feature, | ||
| 192 | if someone can manage to get better results than us. | ||
| 193 | |||
| 194 | The possibility of having this natively in PHP has | ||
| 195 | `been discussed <https://marc.info/?l=php-internals&m=141692988212413&w=2>`_, | ||
| 196 | but as 2017, nothing has been merged yet. | ||
diff --git a/doc/source/features.rst b/doc/source/features.rst new file mode 100644 index 0000000..89cd756 --- /dev/null +++ b/doc/source/features.rst | |||
| @@ -0,0 +1,352 @@ | |||
| 1 | Features | ||
| 2 | ======== | ||
| 3 | |||
| 4 | Snuffleupagus has a lot of features that can be divided in two main categories: bug-classes | ||
| 5 | killers and virtual-patching. The first category provides primitives to kill various | ||
| 6 | bug families (like arbitrary code execution via ``unserialize`` for example) or rise the | ||
| 7 | cost of exploitation, the second one is a highly configurable system to patch functions in php itself. | ||
| 8 | |||
| 9 | Bug classes killed | ||
| 10 | ------------------ | ||
| 11 | |||
| 12 | ``system`` injections | ||
| 13 | ^^^^^^^^^^^^^^^^^^^^^ | ||
| 14 | |||
| 15 | The ``system`` function execute an external program and displays the output. | ||
| 16 | It's used to interract with various external tools, like file-format converters for example. | ||
| 17 | Unfortunately, passing user-controlled parameters to it often leads to an arbitrary command execution. | ||
| 18 | |||
| 19 | When allowing user-supplied data to be passed to this function, | ||
| 20 | use `escapeshellarg()` or `escapeshellcmd()` to ensure that users cannot trick | ||
| 21 | the system into executing arbitrary commands. | ||
| 22 | |||
| 23 | --- `The PHP documentation about system <https://secure.php.net/manual/en/function.system.php>`_ | ||
| 24 | |||
| 25 | We're kind of killing it by filtering the ``$``, ``|``, ``;``, ````` and ``&`` chars in our | ||
| 26 | default configuration, making it a lot harder for an attacker to inject arbitrary commands. | ||
| 27 | |||
| 28 | This family of vulnerabilities lead to various CVE, like: | ||
| 29 | |||
| 30 | - `CVE-2017-7981 <https://tuleap.net/plugins/tracker/?aid=10159>`_: Authenticated remote code execution on Tuleap | ||
| 31 | - `CVE-2014-4688 <https://www.pfsense.org/security/advisories/pfSense-SA-14_10.webgui.asc>`_: Authenticated remote code execution on pfSense | ||
| 32 | - `CVE-2014-1610 <https://www.rapid7.com/db/modules/exploit/multi/http/mediawiki_thumb>`_: Unauthenticated remote code execution on DokuWiki | ||
| 33 | - `CVE-2013-3630 <https://www.rapid7.com/db/modules/exploit/multi/http/moodle_cmd_exec>`_: Authenticated remote code execution on Moodle | ||
| 34 | - Every single shitty `modem/router/switch/IoT <https://twitter.com/internetofshit>`_. | ||
| 35 | |||
| 36 | |||
| 37 | ``mail``-related injections | ||
| 38 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 39 | |||
| 40 | This vulnerability is known `since 2011 <http://esec-pentest.sogeti.com/posts/2011/11/03/using-mail-for-remote-code-execution.html>`_, | ||
| 41 | and was popularized by `RIPS <https://www.ripstech.com/blog/2016/roundcube-command-execution-via-email/>`_ in 2016. | ||
| 42 | The last flag of the `mail` function can be used to pass various parameters to | ||
| 43 | the underlying binary used to send emails: this can lead to an arbitrary file write, | ||
| 44 | often meaning an arbitrary code execution. | ||
| 45 | |||
| 46 | The ``additional_parameters`` parameter can be used to pass additional flags | ||
| 47 | as command line options to the program configured to be used when sending mail | ||
| 48 | |||
| 49 | --- `The PHP documentation about mail <https://secure.php.net/manual/en/function.mail.php>`_ | ||
| 50 | |||
| 51 | We're killing it by preventing any extra options in additional_parameters. | ||
| 52 | |||
| 53 | This family of vulnerabilities lead to various CVE, like: | ||
| 54 | |||
| 55 | - `CVE-2017-7692 <https://legalhackers.com/advisories/SquirrelMail-Exploit-Remote-Code-Exec-CVE-2017-7692-Vuln.html>`_: Authenticated remote code execution in SquirrelMail | ||
| 56 | - `CVE-2016-10074 <https://legalhackers.com/advisories/SwiftMailer-Exploit-Remote-Code-Exec-CVE-2016-10074-Vuln.html>`_: remote code execution in SwiftMailer | ||
| 57 | - `CVE-2016-10033 <https://legalhackers.com/advisories/PHPMailer-Exploit-Remote-Code-Exec-CVE-2016-10033-Vuln.html>`_: remote code execution in PHPMailer | ||
| 58 | - `CVE-2016-9920 <https://www.ripstech.com/blog/2016/roundcube-command-execution-via-email/>`_: Unauthenticated remote code execution in Roundcube | ||
| 59 | |||
| 60 | Session-cookie stealing via XSS | ||
| 61 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 62 | |||
| 63 | The goto payload for XSS is often to steal cookies. | ||
| 64 | Like *Suhosin*, we are encrypting the cookies with a secret key, the IP of the user | ||
| 65 | and its user-agent. This means that an attacker with an XSS won't be able to use | ||
| 66 | the stolen cookie, since he (often) can't spoof the IP address of the user. | ||
| 67 | |||
| 68 | This feature is roughly the same than the `Suhosin one <https://suhosin.org/stories/configuration.html#transparent-encryption-options>`_. | ||
| 69 | |||
| 70 | Users behind the same IP address but with different browsers won't be able to use each other stolen cookies, | ||
| 71 | except if they can manage to guess the user agent. This isn't especially difficult, | ||
| 72 | but an invalid decryption will leave a trace in the logs. | ||
| 73 | |||
| 74 | Finally, having a secret server-side key will prevent anyone (even the user himself) | ||
| 75 | from reading the content of the cookie, reducing the impact of an application storing sensitive data client-side. | ||
| 76 | |||
| 77 | The encryption is done via the [tweetnacl library](https://tweetnacl.cr.yp.to/), | ||
| 78 | thus using curve25519, xsalsa20 and poly1305 for the encryption. We chose this | ||
| 79 | library because of its portability, simplicity and reduced size (a single `.h` and | ||
| 80 | `.c` file.). | ||
| 81 | |||
| 82 | Remote code execution via file-upload | ||
| 83 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 84 | |||
| 85 | Some PHP applications allows users to upload contents, like avatars for a forum. | ||
| 86 | Unfortunately, sometimes, content validation isn't implemented properly (if at all), | ||
| 87 | meaning arbitrary file upload, often leading, contrary to what the documentation is saying, | ||
| 88 | to an arbitrary code execution. | ||
| 89 | |||
| 90 | Not validating which file you operate on may mean that users can *access sensitive information* in other directories. | ||
| 91 | |||
| 92 | --- `The PHP documentation about file uploads <https://secure.php.net/manual/en/features.file-upload.common-pitfalls.php>`_ | ||
| 93 | |||
| 94 | We're killing it, like Suhosin, by automatically calling a script upon file upload, | ||
| 95 | if it returns something else than ``0``, the file will be removed (or stored in a quarantine, | ||
| 96 | for further analysis). | ||
| 97 | |||
| 98 | We're recommending to use the `vld <https://derickrethans.nl/projects.html#vld>`_ project | ||
| 99 | inside the script to ensure the file doesn't contain any valid PHP code, with something like this: | ||
| 100 | |||
| 101 | :: | ||
| 102 | |||
| 103 | $ php -d vld.execute=0 -d vld.active=1 -d extension=vld.so $file | ||
| 104 | |||
| 105 | Unserialize-related magic | ||
| 106 | ^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 107 | |||
| 108 | PHP is able to *serialize* arbitrary objects, to easily store them. | ||
| 109 | Unfortunately, it's often possible to gain arbitrary code execution upon deserialization | ||
| 110 | of user-supplied serialized objects. | ||
| 111 | |||
| 112 | Do not pass untrusted user input to ``unserialize()`` regardless of the options value of allowed_classes. | ||
| 113 | Unserialization can result in code being loaded and executed due to object instantiation and autoloading, | ||
| 114 | and a malicious user may be able to exploit this. | ||
| 115 | |||
| 116 | --- `The PHP documentation about serialize <https://secure.php.net/manual/en/function.serialize.php>`_ | ||
| 117 | |||
| 118 | We're killing it by exploiting the fact that PHP will discard any garbage found at the end of a serialized object, | ||
| 119 | allowing us to simply append a `HMAC <https://en.wikipedia.org/wiki/Hash-based_message_authentication_code>`_ | ||
| 120 | at the end of strings generated by the ``serialize``, | ||
| 121 | hence guaranteeing that any object deserialized came from the application, | ||
| 122 | and wasn't tampered with, | ||
| 123 | |||
| 124 | We're not encrypting it, like we do with the cookies, | ||
| 125 | allowing this feature to be disabled (or switch into leaning mode) | ||
| 126 | without the need to invalidate any data. | ||
| 127 | |||
| 128 | .. warning:: | ||
| 129 | |||
| 130 | This feature can't be deployed on websites that already stored serialized | ||
| 131 | objects (ie. in database), since they are missing the HMAC, and thus will be detected as | ||
| 132 | an attack. If you're in this situation, you should use this feature with the | ||
| 133 | ``simulation`` mode, and switch it off once you don't have any messages in your | ||
| 134 | logs. | ||
| 135 | |||
| 136 | A nice side-effect of this feature is that it'll defeat various memory corruption | ||
| 137 | issues related to the complexity of ``unserialize``'s implementation, | ||
| 138 | and the amount of control if provides to an attacker, like `CVE-2016-9137, CVE-2016-9138 <https://bugs.php.net/bug.php?id=73147>`_, | ||
| 139 | `2016-7124 <https://bugs.php.net/bug.php?id=72663>`_, `CVE-2016-5771 and CVE-2016-5773 <https://www.evonide.com/how-we-broke-php-hacked-pornhub-and-earned-20000-dollar/>`_, … | ||
| 140 | |||
| 141 | This family of vulnerabilities lead to various CVE, like: | ||
| 142 | |||
| 143 | - `CVE-2016-???? <https://www.computest.nl/advisories/CT-2016-1110_Observium.txt>`_: Unauthenticated remote code execution in Observium (leading to remote root) | ||
| 144 | - `CVE-2016-5726 <http://seclists.org/oss-sec/2016/q2/521>`_: Unauthenticated remote code execution in Simple Machines Forums | ||
| 145 | - `CVE-2016-4010 <http://netanelrub.in/2016/05/17/magento-unauthenticated-remote-code-execution/>`_: Unauthenticated remote code execution in Magento | ||
| 146 | - `CVE-2017-2641 <http://netanelrub.in/2017/03/20/moodle-remote-code-execution/>`_: Unauthenticated remote code execution in Moodle | ||
| 147 | - `CVE-2015-8562 <https://www.rapid7.com/db/modules/exploit/multi/http/joomla_http_header_rce>`_: Unauthenticated remote code execution in Joomla | ||
| 148 | - `CVE-2015-7808 <https://www.rapid7.com/db/modules/exploit/multi/http/vbulletin_unserialize>`_: Unauthenticated remote code execution in vBulletin | ||
| 149 | - `CVE-2014-1691 <http://seclists.org/oss-sec/2014/q1/153>`_: Unauthenticated remote code execution in Horde | ||
| 150 | - `CVE-2012-5692 <https://www.rapid7.com/db/modules/exploit/unix/webapp/invision_pboard_unserialize_exec>`_: Unauthenticated remote code execution in IP.Board | ||
| 151 | |||
| 152 | |||
| 153 | |||
| 154 | Weak-PRNG via rand/mt_rand | ||
| 155 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 156 | |||
| 157 | The functions ``rand`` and ``mt_rand`` are often used to generate random numbers used | ||
| 158 | in sensitive context, like password generation, token creation, … | ||
| 159 | Unfortunately, as said in the documentation, the quality of their entropy is low, | ||
| 160 | leading to the generation of guessable values. | ||
| 161 | |||
| 162 | This function does not generate cryptographically secure values, and should not be used for cryptographic purposes. | ||
| 163 | |||
| 164 | --- `The PHP documentation about rand <https://secure.php.net/manual/en/function.rand.php>`_ | ||
| 165 | |||
| 166 | We're addressing this issue by replacing every call to ``rand`` and ``mt_rand`` with | ||
| 167 | a call to the ``random_int``, a `CSPRNG <https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator>`_. | ||
| 168 | |||
| 169 | It's worth noting that the PHP documentation contains the following warning: | ||
| 170 | |||
| 171 | ``min`` ``max`` range must be within the range ``getrandmax()``. i.e. ``(max - min) <= getrandmax()``. | ||
| 172 | Otherwise, ``rand()`` may return poor-quality random numbers. | ||
| 173 | |||
| 174 | --- `The PHP documentation about rand <https://secure.php.net/manual/en/function.rand.php>`_ | ||
| 175 | |||
| 176 | This is of course addressed as well by the ``harden_rand`` feature. | ||
| 177 | |||
| 178 | .. warning:: | ||
| 179 | |||
| 180 | Activating this feature will raise an `Error <https://secure.php.net/manual/en/class.error.php>`_ | ||
| 181 | exception if ``min`` is superior to ``max``, while the default dehaviour is simply to swap them. | ||
| 182 | |||
| 183 | This family of vulnerabilities lead to various CVE, like: | ||
| 184 | |||
| 185 | - `CVE-2015-5267 <https://moodle.org/mod/forum/discuss.php?d=320291>`_: Unauthenticated accounts takeover in in Moodle | ||
| 186 | - `CVE-2014-9624 <https://www.mantisbt.org/bugs/view.php?id=17984>`_: Captcha bypass in MantisBT | ||
| 187 | - `CVE-2014-6412 <https://core.trac.wordpress.org/ticket/28633>`_: Unauthenticated account takeover in Wordpress | ||
| 188 | - `CVE-2015-???? <https://hackerone.com/reports/31171>`_: Unauthenticated accounts takeover in Concrete5 | ||
| 189 | - `CVE-2013-6386 <https://www.drupal.org/SA-CORE-2013-003>`_: Unauthenticated accounts takeover in Drupal | ||
| 190 | - `CVE-2010-???? <http://www.sektioneins.com/advisories/advisory-022010-mybb-password-reset-weak-random-numbers-vulnerability.html>`_: Unauthenticated accounts takeover in MyBB | ||
| 191 | - `CVE-2008-4102 <https://sektioneins.de/en/advisories/advisory-042008-joomla-weak-random-password-reset-token-vulnerability.html>`_: Unauthenticated accounts takeover in Joomla | ||
| 192 | - `CVE-2006-0632 <https://www.cvedetails.com/cve/CVE-2006-0632/>`_: Unauthenticated account takeover in phpBB | ||
| 193 | |||
| 194 | XXE | ||
| 195 | ^^^ | ||
| 196 | |||
| 197 | Despite the documentation saying nothing about this class of vulnerabilities, | ||
| 198 | `XML eXternal Entitiy <https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing>`_ (XXE) are often leading to arbitrary file reading, SSRF, and sometimes even arbitrary | ||
| 199 | code execution. | ||
| 200 | |||
| 201 | XML documents can contain a `Document Type Definition <https://www.w3.org/TR/REC-xml/#sec-prolog-dtd>`_ (DTD), | ||
| 202 | enabling definition of XML entities. It's possible to define an (external) entity by an | ||
| 203 | URI, that the parser will access, and embed its content back into the document | ||
| 204 | for further processing. | ||
| 205 | |||
| 206 | For example, providing an url like ``file:///etc/passwd`` will read | ||
| 207 | this file's content, and since it's not valid XML, the application | ||
| 208 | will spit it out in an error message, thus leaking its content. | ||
| 209 | |||
| 210 | We're killing this class of vulnerabilities by calling | ||
| 211 | the `libxml_disable_entity_loader <https://secure.php.net/manual/en/function.libxml-disable-entity-loader.php>`_ | ||
| 212 | function with its parameter set to ``true`` at startup, | ||
| 213 | and then *nop'ing* it, so it won't do anything if ever called again. | ||
| 214 | |||
| 215 | This family of vulnerabilities lead to various CVE, like: | ||
| 216 | |||
| 217 | - `CVE-2015-5161 <https://legalhackers.com/advisories/eBay-Magento-XXE-Injection-Vulnerability.html>`_: Unauthenticated arbitrary file disclosure on Magento | ||
| 218 | - `CVE-2014-8790 <https://github.com/GetSimpleCMS/GetSimpleCMS/issues/944>`_: Unauthenticated remote code execution in GetSimple CMS | ||
| 219 | - `CVE-2011-4107 <https://www.phpmyadmin.net/security/PMASA-2011-17/>`_: Authenticated local file disclosure in PHPMyAdmin | ||
| 220 | |||
| 221 | |||
| 222 | Cookie stealing via HTTP MITM | ||
| 223 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 224 | |||
| 225 | While it's possible to set the ``secure`` flag on cookies to prevent them from being | ||
| 226 | transmitted over HTTP, and only allow its transmission over HTTPS. | ||
| 227 | Snuffleupagus can automatically set this flag if the client is accessing the | ||
| 228 | website over a secure connection. | ||
| 229 | |||
| 230 | This behaviour is suggested in the documentation: | ||
| 231 | |||
| 232 | On the server-side, it's on the programmer to send this kind of cookie only | ||
| 233 | on secure connection (e.g. with respect to ``$_SERVER["HTTPS"]``). | ||
| 234 | |||
| 235 | --- `The PHP documentation about setcookie <https://secure.php.net/manual/en/function.setcookie.php>`_ | ||
| 236 | |||
| 237 | |||
| 238 | Exploitation, post-exploitation and general hardening | ||
| 239 | ----------------------------------------------------- | ||
| 240 | |||
| 241 | Virtual-patching | ||
| 242 | ^^^^^^^^^^^^^^^^ | ||
| 243 | |||
| 244 | PHP itself exposes a number of functions that might be considered **dangerous** and that have limited legitimate use cases. | ||
| 245 | ``system()``, ``exec()``, ``dlopen()`` - for example - fall into this category. By default, PHP only allows to globally disable some functions. | ||
| 246 | |||
| 247 | |||
| 248 | However, (ie. ``system()``) they might have legitimate use cases in processes such as self upgrade etc., making it impossible to effectively | ||
| 249 | disable them - at the risk of breaking critical features. | ||
| 250 | |||
| 251 | SnuffleuPagus allows the user to restrict usage of specific functions per files, or per | ||
| 252 | files with a matching (sha256) hash, thus allowing the use of such functions **only** in the intended places. | ||
| 253 | |||
| 254 | Furthermore, running the `following script <FIXME>`_ will generate an hash and line-based whitelist | ||
| 255 | of dangerous functions, droping them everywhere else: | ||
| 256 | |||
| 257 | |||
| 258 | .. literalinclude:: ../../scripts/generate_rules.php | ||
| 259 | :language: php | ||
| 260 | |||
| 261 | |||
| 262 | The intent is to make post-exploitation process (such as backdooring of legitimate code, or RAT usage) a lot harder for the attacker. | ||
| 263 | |||
| 264 | |||
| 265 | Global strict mode | ||
| 266 | ^^^^^^^^^^^^^^^^^^ | ||
| 267 | |||
| 268 | By default, PHP will coerce values of the wrong type into the expected one | ||
| 269 | if possible. For example, if a function expecting an integer is given a string, | ||
| 270 | it will be coerced in an integer. | ||
| 271 | |||
| 272 | PHP7 introduced a **strict mode**, in which variables won't be coerced anymore, | ||
| 273 | and a `TypeError <https://php.net/manual/en/class.typeerror.php>`_ exception will | ||
| 274 | be raised if the types aren't matching. | ||
| 275 | `Scalar type declarations <https://secure.php.net/manual/en/migration70.new-features.php#migration70.new-features.scalar-type-declarations>`_ | ||
| 276 | are optional, but you don't have to used them in your code to benefit from them, | ||
| 277 | since every internal function from php has them. | ||
| 278 | |||
| 279 | This option provide a switch to globally activate this strict mode, | ||
| 280 | helping to uncover vulnerabilities like the classical | ||
| 281 | `strcmp bypass <https://danuxx.blogspot.fr/2013/03/unauthorized-access-bypassing-php-strcmp.html>`_, | ||
| 282 | and various other types mismatch. | ||
| 283 | |||
| 284 | This feature is largely inspired from the | ||
| 285 | `autostrict <https://github.com/krakjoe/autostrict>`_ module from `krakjoe <krakjoe.ninja>`_. | ||
| 286 | |||
| 287 | |||
| 288 | Preventing execution of writable PHP files | ||
| 289 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 290 | |||
| 291 | If an attacker manages to upload an arbitrary file or to modify an existing one, | ||
| 292 | odds are that (thanks to the default `umask <https://en.wikipedia.org/wiki/Umask>`_) | ||
| 293 | this file is writable by the PHP process. | ||
| 294 | |||
| 295 | Snuffleupagus can prevent the execution of this kind of files. A good practise | ||
| 296 | would be to use a different user to run PHP than for administrating the website, | ||
| 297 | and using this feature to lock this up. | ||
| 298 | |||
| 299 | |||
| 300 | |||
| 301 | Dumping capabilities | ||
| 302 | ^^^^^^^^^^^^^^^^^^^^ | ||
| 303 | It's possible to apply the ``dump(:str)`` filter to any virtual-patching rule, | ||
| 304 | to dump the complete web request, along with the filename and the corresponding | ||
| 305 | line number. By using the *right* set of restrictive rules (or by using the | ||
| 306 | *overly* restrictives ones in ``simulation`` mode), you might be able | ||
| 307 | to gather interesting vulnerabilities used against your website. | ||
| 308 | |||
| 309 | |||
| 310 | Misc low-hanging fruits in the default configuration file | ||
| 311 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 312 | |||
| 313 | Snuffleupagus is shipping with a default configuration file, containing | ||
| 314 | various examples and ideas of things that you might want to enable (or not). | ||
| 315 | |||
| 316 | Available functions recon | ||
| 317 | """"""""""""""""""""""""" | ||
| 318 | |||
| 319 | After compromising a website, most of the time, the attacker does some recon | ||
| 320 | within its webshell, to check which functions are available to execute arbitrary code, | ||
| 321 | since it's not uncommon for some web-hoster to disable things like ``system`` or ``passthru``, | ||
| 322 | or to check if mitigations are enabled, like ``open_basedir``. | ||
| 323 | This behaviour can be detected by preventing the execution of functions like ``ini_get`` | ||
| 324 | or ``is_callable`` with *suspicious* parameters. | ||
| 325 | |||
| 326 | ``chmod`` hardening | ||
| 327 | """"""""""""""""""" | ||
| 328 | |||
| 329 | Some PHP applications are using broad rights when using the ``chmod`` function, | ||
| 330 | like the infamous ``chmod(777)`` command, effectively making the file writable by everyone. | ||
| 331 | Snuffleupagus is preventing this kind of behaviour by restricting the parameters | ||
| 332 | than can be passer to ``chmod``. | ||
| 333 | |||
| 334 | Arbitrary file inclusion hardening | ||
| 335 | """""""""""""""""""""""""""""""""" | ||
| 336 | |||
| 337 | Arbitrary file inclusion is a common vulnerability, that might be detected | ||
| 338 | by preventing the use of anything else than a whitelist of extensions in calls | ||
| 339 | to ``include`` or ``require``. | ||
| 340 | |||
| 341 | *Cheap* SQL injections detection | ||
| 342 | """""""""""""""""""""""""""""""" | ||
| 343 | |||
| 344 | In some SQL injections, attackers might need to use comments, a feature that is | ||
| 345 | often not used in production system, so it might be a good idea to filter | ||
| 346 | queries that contains some. The same filtering idea can be used against | ||
| 347 | SQL functions that are frequently used in SQL injections, like ``sleep``, ``benchmark`` | ||
| 348 | or strings like ``version_info``. | ||
| 349 | |||
| 350 | Still about SQL injections, if a function performing a query returns ``FALSE`` | ||
| 351 | (indicating an error), it might be useful to dump the request for further analysis. | ||
| 352 | |||
diff --git a/doc/source/index.rst b/doc/source/index.rst new file mode 100644 index 0000000..8a9c340 --- /dev/null +++ b/doc/source/index.rst | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | Snuffleupagus | ||
| 2 | ============= | ||
| 3 | |||
| 4 | Snuffleupagus is a `PHP 7+ <https://secure.php.net/>`_ module designed to drastically raising the cost of | ||
| 5 | attacks against website, by killing entire bug classes, and also providing a | ||
| 6 | powerful virtual-patching system, allowing administrator to fix specific | ||
| 7 | vulnerabilities and audit suspicious behaviours without having to touch the PHP code. | ||
| 8 | |||
| 9 | Documentation | ||
| 10 | ------------- | ||
| 11 | |||
| 12 | .. toctree:: | ||
| 13 | :maxdepth: 2 | ||
| 14 | |||
| 15 | features | ||
| 16 | installation | ||
| 17 | config | ||
| 18 | download | ||
| 19 | faq | ||
| 20 | papers | ||
| 21 | |||
| 22 | Greetings | ||
| 23 | --------- | ||
| 24 | We would like to thank the following people: | ||
| 25 | |||
| 26 | - `Suhosin <http://suhosin.org>`_, for paving the way. | ||
| 27 | - The people behind the `RIPS <https://www.ripstech.com/>`_ scanner for their ground breaking work | ||
| 28 | - `NBS System <https://nbs-system.com>`_, for creating and open-sourcing this piece of software | ||
| 29 | - `Websec.fr <https://websec.fr>`_, for keeping our interesting vulnerabilities alive | ||
| 30 | - Web developers around the world, for being so imaginative | ||
diff --git a/doc/source/installation.rst b/doc/source/installation.rst new file mode 100644 index 0000000..779008d --- /dev/null +++ b/doc/source/installation.rst | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | Installation | ||
| 2 | ============ | ||
| 3 | |||
| 4 | Snuffleupagus is tested against various PHP 7+ versions: XXX | ||
| 5 | |||
| 6 | Manual installation | ||
| 7 | ------------------- | ||
| 8 | |||
| 9 | Depending on the system, we might already offer binary packages. | ||
| 10 | You can check our :doc:`download`. In that case you only need to activate | ||
| 11 | the extension inside your ``php.ini`` and to configure it. | ||
| 12 | |||
| 13 | |||
| 14 | Quickstart | ||
| 15 | ^^^^^^^^^^ | ||
| 16 | |||
| 17 | :: | ||
| 18 | |||
| 19 | git clone https://github.com/nbs-system/snuffleupagus | ||
| 20 | cd snuffleupagus | ||
| 21 | phpize | ||
| 22 | ./configure | ||
| 23 | make | ||
| 24 | make install | ||
| 25 | |||
| 26 | This should install ``snuffleupagus.so`` file in your extension directory. The final step is adding a load directive to ``php.ini``:: | ||
| 27 | |||
| 28 | extension=snuffleupagus.so | ||
| 29 | |||
| 30 | Upgrading | ||
| 31 | --------- | ||
| 32 | |||
| 33 | Upgrading the Snuffleupagus is as simple as recompiling it (or using a binary), replacing the file and restarting your webserver. | ||
diff --git a/doc/source/papers.rst b/doc/source/papers.rst new file mode 100644 index 0000000..d028b14 --- /dev/null +++ b/doc/source/papers.rst | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | Propaganda | ||
| 2 | ========== | ||
| 3 | |||
| 4 | This pages lists various mentions, articles and presentations about Snuffleupagus. | ||
| 5 | |||
| 6 | Talks | ||
| 7 | ----- | ||
| 8 | |||
| 9 | - `BerlinSide0x08 <https://berlinsides.org/?page_id=2168>`_ - `Php7 Nightmares <slides.pdf>`_ - 2017-05-28 | ||
| 10 | - `Hack.lu <https://2017.hack.lu/talks/>`_ - soon™ - 2017-10-18 | ||
| 11 | - `BlackAlps <https://blackalps.ch/2017program.php>`_ - soon™ - 2017-11-16 | ||
| 12 | |||
| 13 | Articles | ||
| 14 | -------- | ||
| 15 | |||
| 16 | - `Killing php bug classes at berlinsides <https://dustri.org/b/killing-php-bug-classes-at-berlinsides.html>`_ - 2017-06-05 \ No newline at end of file | ||
