# The twelfth change: on Nextcloud's paths, some fields skip the rules that # refused ordinary Nextcloud requests there. They are the fields where Nextcloud # sends a search, a name, a file name, a folder, a comment or a document's text. # Each exclusion runs with the request, before the rules it switches off, so # this file is loaded before the Core Rule Set's rules. Each comment names a # request a rule refused. An exclusion on a field of a JSON body applies only # when the query has no parameter of that name, so it matters only while # SWW_WAF_BODY_LIMIT is set. Nextcloud's pages are matched at the site root and # under /index.php/, where a Nextcloud without pretty URLs serves them. # # Four rules read a search or a name as a command or a system file: # 930120: .htaccess # 932120: powershell # 932250: ls -la # 932260: python3 # Each exclusion below removes these four from its fields. Two more rules # misfire on a comment or a document's text that runs a command after a ";", # such as "Run python3 or powershell; ls -la shows .htaccess": # 932125: ; ls # 932230: ; ls -la # Those fields skip them too. Rule 932235 stays, so that # "; wget http://example.com/x.sh" is still refused there. It refuses # "Run powershell; python3 next" too. # The sync client and the Files app use these WebDAV methods besides those # the first change allows, on /remote.php/dav/ and /public.php/dav/ and on the # older /remote.php/webdav/ and /public.php/webdav/. 911100 refused each: # PROPFIND, PROPPATCH: listing a folder, marking a file a favourite # MKCOL: making a folder, and starting a chunked upload # COPY, MOVE: copying, moving and renaming, and ending a chunked upload # REPORT: listing favourites and comments # SEARCH: the Files app's search SecRule REQUEST_FILENAME "@rx ^/(?:remote|public)\.php/(?:dav|webdav)(?:/|$)" \ "id:900100,phase:1,pass,nolog,\ setvar:'tx.allowed_methods=%{tx.allowed_methods} PROPFIND PROPPATCH MKCOL COPY MOVE REPORT SEARCH'" # Nextcloud keeps the name of the account signed in in the cookie nc_username, # which every request sends, on every path. Each request of the account # python3 was refused. SecAction "id:900101,phase:1,pass,nolog,\ ctl:ruleRemoveTargetById=930120;REQUEST_COOKIES:nc_username,\ ctl:ruleRemoveTargetById=932120;REQUEST_COOKIES:nc_username,\ ctl:ruleRemoveTargetById=932250;REQUEST_COOKIES:nc_username,\ ctl:ruleRemoveTargetById=932260;REQUEST_COOKIES:nc_username" # Signing in, in the query or the body: # user, password: user=python3&password=Example-pass-python3 # redirect_url: /login?redirect_url=/apps/files/%3Fdir%3D/Python3%20notes SecRule REQUEST_FILENAME "@rx ^/(?:index\.php/)?login$" \ "id:900102,phase:1,pass,nolog,\ ctl:ruleRemoveTargetById=930120;ARGS:/^(?:user|password|redirect_url)$/,\ ctl:ruleRemoveTargetById=932120;ARGS:/^(?:user|password|redirect_url)$/,\ ctl:ruleRemoveTargetById=932250;ARGS:/^(?:user|password|redirect_url)$/,\ ctl:ruleRemoveTargetById=932260;ARGS:/^(?:user|password|redirect_url)$/" # The folder the Files app shows: /apps/files/?dir=/Powershell%20modules. SecRule REQUEST_FILENAME "@rx ^/(?:index\.php/)?apps/files/" \ "id:900103,phase:1,pass,nolog,\ ctl:ruleRemoveTargetById=930120;ARGS:dir,\ ctl:ruleRemoveTargetById=932120;ARGS:dir,\ ctl:ruleRemoveTargetById=932250;ARGS:dir,\ ctl:ruleRemoveTargetById=932260;ARGS:dir" # The file names on a public share's page: # file: /apps/files_sharing/publicpreview/?file=/powershell+profile.ps1 # path, files: /s//download?path=/&files=powershell%20profile.ps1 SecRule REQUEST_FILENAME "@rx ^/(?:index\.php/)?(?:apps/files_sharing/publicpreview/|s/[^/]+/download$)" \ "id:900104,phase:1,pass,nolog,\ ctl:ruleRemoveTargetById=930120;ARGS:/^(?:file|path|files)$/,\ ctl:ruleRemoveTargetById=932120;ARGS:/^(?:file|path|files)$/,\ ctl:ruleRemoveTargetById=932250;ARGS:/^(?:file|path|files)$/,\ ctl:ruleRemoveTargetById=932260;ARGS:/^(?:file|path|files)$/" # The OCS API's searches and names, in the query, a form data body or a JSON # body: # search: /ocs/v2.php/cloud/users/details?search=python3, and the same on # cloud/users, cloud/groups, cloud/groups/details and the sharees # term, from: /ocs/v2.php/search/providers/files/search?term=python3 # groupid, userid, displayName: adding the group "Python3 admins" and the # account python3, displayName=Ls+-la+Example # groups[], or groups in JSON: the groups of a new account, # groups[]=Python3+admins # value: changing an account's name, address or headline, value=Powershell+Lane # path, label, note, shareWith: sharing the folder "/ls -la output" with the # label "python3 link" and the note "Read the .htaccess notes" # message: the status "Writing python3 and powershell" SecRule REQUEST_FILENAME "@rx ^/ocs/v[12]\.php/" \ "id:900105,phase:1,pass,nolog,\ ctl:ruleRemoveTargetById=930120;ARGS:/^(?:search|term|from|groupid|userid|displayname|value|path|label|note|sharewith|message|groups\[\])$/,\ ctl:ruleRemoveTargetById=932120;ARGS:/^(?:search|term|from|groupid|userid|displayname|value|path|label|note|sharewith|message|groups\[\])$/,\ ctl:ruleRemoveTargetById=932250;ARGS:/^(?:search|term|from|groupid|userid|displayname|value|path|label|note|sharewith|message|groups\[\])$/,\ ctl:ruleRemoveTargetById=932260;ARGS:/^(?:search|term|from|groupid|userid|displayname|value|path|label|note|sharewith|message|groups\[\])$/" SecRule REQUEST_FILENAME "@rx ^/ocs/v[12]\.php/" \ "id:900106,phase:1,pass,nolog,chain" SecRule &ARGS_GET:/^json\.(?:search|term|from|groupid|userid|displayname|value|path|label|note|sharewith|message|groups\.[0-9]+)$/ "@eq 0" \ "ctl:ruleRemoveTargetById=930120;ARGS:/^json\.(?:search|term|from|groupid|userid|displayname|value|path|label|note|sharewith|message|groups\.[0-9]+)$/,\ ctl:ruleRemoveTargetById=932120;ARGS:/^json\.(?:search|term|from|groupid|userid|displayname|value|path|label|note|sharewith|message|groups\.[0-9]+)$/,\ ctl:ruleRemoveTargetById=932250;ARGS:/^json\.(?:search|term|from|groupid|userid|displayname|value|path|label|note|sharewith|message|groups\.[0-9]+)$/,\ ctl:ruleRemoveTargetById=932260;ARGS:/^json\.(?:search|term|from|groupid|userid|displayname|value|path|label|note|sharewith|message|groups\.[0-9]+)$/" # The name and slogan in the theming admin settings, in the JSON field value: # {"setting":"slogan","value":"ls -la and .htaccess"}. SecRule REQUEST_FILENAME "@rx ^/(?:index\.php/)?apps/theming/ajax/updateStylesheet$" \ "id:900107,phase:1,pass,nolog,chain" SecRule &ARGS_GET:json.value "@eq 0" \ "ctl:ruleRemoveTargetById=930120;ARGS:json.value,\ ctl:ruleRemoveTargetById=932120;ARGS:json.value,\ ctl:ruleRemoveTargetById=932250;ARGS:json.value,\ ctl:ruleRemoveTargetById=932260;ARGS:json.value" # The Text editor saves a document, such as a folder's Readme.md, with its # path in the JSON field filePath and its text in autosaveContent. The text # skips the two rules for a command after a ";" too. SecRule REQUEST_FILENAME "@rx ^/(?:index\.php/)?apps/text/session/[0-9]+/save$" \ "id:900108,phase:1,pass,nolog,chain" SecRule &ARGS_GET:/^json\.(?:filepath|autosavecontent)$/ "@eq 0" \ "ctl:ruleRemoveTargetById=930120;ARGS:/^json\.(?:filepath|autosavecontent)$/,\ ctl:ruleRemoveTargetById=932120;ARGS:/^json\.(?:filepath|autosavecontent)$/,\ ctl:ruleRemoveTargetById=932250;ARGS:/^json\.(?:filepath|autosavecontent)$/,\ ctl:ruleRemoveTargetById=932260;ARGS:/^json\.(?:filepath|autosavecontent)$/,\ ctl:ruleRemoveTargetById=932125;ARGS:json.autosavecontent,\ ctl:ruleRemoveTargetById=932230;ARGS:json.autosavecontent" # A comment on a file, in the JSON field message of a new comment, and in the # XML body of an edited one. It skips the two rules for a command after a ";" # too. An edited comment's XML holds nothing else a person writes. SecRule REQUEST_FILENAME "@rx ^/remote\.php/dav/comments/files/[0-9]+$" \ "id:900109,phase:1,pass,nolog,chain" SecRule &ARGS_GET:json.message "@eq 0" \ "ctl:ruleRemoveTargetById=930120;ARGS:json.message,\ ctl:ruleRemoveTargetById=932120;ARGS:json.message,\ ctl:ruleRemoveTargetById=932125;ARGS:json.message,\ ctl:ruleRemoveTargetById=932230;ARGS:json.message,\ ctl:ruleRemoveTargetById=932250;ARGS:json.message,\ ctl:ruleRemoveTargetById=932260;ARGS:json.message" SecRule REQUEST_FILENAME "@rx ^/remote\.php/dav/comments/files/[0-9]+/[0-9]+$" \ "id:900110,phase:1,pass,nolog,chain" SecRule REQUEST_METHOD "@streq PROPPATCH" \ "ctl:ruleRemoveTargetById=930120;XML:/*,\ ctl:ruleRemoveTargetById=932120;XML:/*,\ ctl:ruleRemoveTargetById=932125;XML:/*,\ ctl:ruleRemoveTargetById=932230;XML:/*,\ ctl:ruleRemoveTargetById=932250;XML:/*,\ ctl:ruleRemoveTargetById=932260;XML:/*" # The Files app's search sends its words in the XML body of a SEARCH request, # %python3%, which holds nothing else a person writes. SecRule REQUEST_FILENAME "@rx ^/remote\.php/dav/?$" \ "id:900111,phase:1,pass,nolog,chain" SecRule REQUEST_METHOD "@streq SEARCH" \ "ctl:ruleRemoveTargetById=930120;XML:/*,\ ctl:ruleRemoveTargetById=932120;XML:/*,\ ctl:ruleRemoveTargetById=932250;XML:/*,\ ctl:ruleRemoveTargetById=932260;XML:/*" # The name of a new tag, in the JSON field name: {"name": "python3"}. SecRule REQUEST_FILENAME "@rx ^/remote\.php/dav/systemtags/?$" \ "id:900112,phase:1,pass,nolog,chain" SecRule &ARGS_GET:json.name "@eq 0" \ "ctl:ruleRemoveTargetById=930120;ARGS:json.name,\ ctl:ruleRemoveTargetById=932120;ARGS:json.name,\ ctl:ruleRemoveTargetById=932250;ARGS:json.name,\ ctl:ruleRemoveTargetById=932260;ARGS:json.name"