Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c0071a7e8c |
No files matched your search
@@ -602,7 +602,7 @@ 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
|
||||
WebDAV methods, searches, file names, account names, comments and
|
||||
documents do too.
|
||||
- A password made of any printable characters gets through these forms:
|
||||
- A random password, as a password manager makes one, 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.
|
||||
|
||||
@@ -920,13 +920,19 @@ The changes hold in front of every app, and no setting undoes them:
|
||||
- `newcontent` of a plugin's or a theme's file saved from its editor,
|
||||
which is PHP.
|
||||
- `pwd`, the password 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). An SQL injection or a path
|
||||
traversal sent as the password reaches WordPress. A script injection
|
||||
is still refused.
|
||||
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.
|
||||
|
||||
`' OR '1'='1`, `../../etc/passwd`, `; cat /etc/passwd` and
|
||||
`<img src=x onerror=x()>` sent as the password reach WordPress;
|
||||
`<script>alert(1)</script>` and `javascript:alert(1)` are still
|
||||
refused.
|
||||
|
||||
- `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
|
||||
(930120, 932120, 932250, 932260).
|
||||
@@ -995,12 +1001,17 @@ The changes hold in front of every app, and no setting undoes them:
|
||||
JSON:API, which hold HTML and any code it shows.
|
||||
- `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.
|
||||
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.
|
||||
|
||||
`' OR '1'='1`, `../../etc/passwd`, `; cat /etc/passwd` and
|
||||
`<img src=x onerror=x()>` sent as the password reach Drupal;
|
||||
`<script>alert(1)</script>` and `javascript:alert(1)` are still refused.
|
||||
|
||||
- `name` when resetting a password through Drupal's JSON format on
|
||||
`/user/password`, for the same four rules.
|
||||
- `mail` in that same reset, for 932120 and 932260 only.
|
||||
@@ -1080,16 +1091,20 @@ The changes hold in front of every app, and no setting undoes them:
|
||||
- `wpTextbox1` on MediaWiki's pages;
|
||||
- `text`, `appendtext` and `prependtext` on `/api.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):
|
||||
- The passwords when signing in:
|
||||
- `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.
|
||||
They 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.
|
||||
|
||||
`' OR '1'='1`, `../../etc/passwd`, `; cat /etc/passwd` and
|
||||
`<img src=x onerror=x()>` sent as a password reach MediaWiki;
|
||||
`<script>alert(1)</script>` and `javascript:alert(1)` are still refused.
|
||||
|
||||
These body exclusions matter only while `SWW_WAF_BODY_LIMIT` is set. None
|
||||
applies when the query has a parameter of the same name.
|
||||
@@ -1216,11 +1231,7 @@ 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
|
||||
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):
|
||||
The passwords in a body:
|
||||
- on `/auth`, `/settings/migration` and `/settings/delete`, and the paths
|
||||
under them:
|
||||
- `user[password]`, `user[password_confirmation]` and
|
||||
@@ -1230,8 +1241,16 @@ The changes hold in front of every app, and no setting undoes them:
|
||||
- `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.
|
||||
They 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.
|
||||
|
||||
`' OR '1'='1`, `../../etc/passwd`, `; cat /etc/passwd` and
|
||||
`<img src=x onerror=x()>` sent as a password reach Mastodon;
|
||||
`<script>alert(1)</script>` and `javascript:alert(1)` are still refused.
|
||||
|
||||
These body exclusions matter only while `SWW_WAF_BODY_LIMIT` is set. None
|
||||
applies when the query has a parameter of the same name.
|
||||
@@ -1366,13 +1385,17 @@ The changes hold in front of every app, and no setting undoes them:
|
||||
- `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.
|
||||
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. `' OR '1'='1`,
|
||||
`../../etc/passwd`, `; cat /etc/passwd` and `<img src=x onerror=x()>` sent
|
||||
as the password reach Nextcloud; `<script>alert(1)</script>` and
|
||||
`javascript:alert(1)` are still refused.
|
||||
|
||||
Some fields hold sentences a person writes:
|
||||
- `note`, a share's note, on `apps/files_sharing/api/v1/shares` of the OCS
|
||||
|
||||
@@ -846,16 +846,35 @@ func wantRandomPasswordsPass(t *testing.T, r request, name string) {
|
||||
}
|
||||
}
|
||||
|
||||
// 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,
|
||||
) {
|
||||
// wantPasswordAttacksPass checks that an SQL injection, a path traversal, a
|
||||
// shell command and a script in an event handler, each sent as the whole
|
||||
// password in the field name of r's body, pass while bodies are read.
|
||||
func wantPasswordAttacksPass(t *testing.T, r request, name string) {
|
||||
t.Helper()
|
||||
|
||||
const threshold = 5 // SWW_WAF_ANOMALY_THRESHOLD's default
|
||||
|
||||
for _, attack := range attacks {
|
||||
for _, attack := range []string{
|
||||
"' OR '1'='1", pathTraversal, "; cat /etc/passwd",
|
||||
"<img src=x onerror=x()>",
|
||||
} {
|
||||
body := passwordBody(t, r, name, attack)
|
||||
if got, _ := inspectBody(t, readingBodies(t), r, body); got.Score >= threshold {
|
||||
t.Errorf("%s %s %s %q refused: %+v", r.method, r.target, name,
|
||||
attack, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// wantPasswordAttacksRefused checks that a script tag and a javascript: link,
|
||||
// each sent as the whole password in the field name of r's body, are refused
|
||||
// while bodies are read.
|
||||
func wantPasswordAttacksRefused(t *testing.T, r request, name string) {
|
||||
t.Helper()
|
||||
|
||||
const threshold = 5 // SWW_WAF_ANOMALY_THRESHOLD's default
|
||||
|
||||
for _, attack := range []string{scriptTag, "javascript:alert(1)"} {
|
||||
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,
|
||||
@@ -1594,9 +1613,8 @@ func TestWordPressPasswordsPass(t *testing.T) {
|
||||
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)
|
||||
wantPasswordAttacksPass(t, signIn, "pwd")
|
||||
wantPasswordAttacksRefused(t, signIn, "pwd")
|
||||
}
|
||||
|
||||
func TestWordPressExclusionsAreNarrow(t *testing.T) {
|
||||
@@ -1656,6 +1674,9 @@ const injection = "1' OR '1'='1"
|
||||
// scriptTag is a script injection, not escaped.
|
||||
const scriptTag = "<script>alert(1)</script>"
|
||||
|
||||
// pathTraversal is a path traversal, not escaped.
|
||||
const pathTraversal = "../../etc/passwd"
|
||||
|
||||
// readingBodies returns the Core Rule Set as sww runs it by
|
||||
// default, but reading bodies up to bodyLimit.
|
||||
func readingBodies(t *testing.T) *coreruleset.CoreRuleSet {
|
||||
|
||||
@@ -182,10 +182,8 @@ func TestDrupalPasswordPasses(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)
|
||||
wantPasswordAttacksPass(t, r, "pass")
|
||||
wantPasswordAttacksRefused(t, r, "pass")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,6 +152,7 @@ var mastodonFormFields = []mastodonBodyField{
|
||||
//nolint:gochecknoglobals // a constant cannot be a list
|
||||
var mastodonPasswordForms = []mastodonBodyField{
|
||||
{http.MethodPost, mastodonSignIn, mastodonPassword},
|
||||
{http.MethodPost, mastodonAccount, mastodonPassword},
|
||||
{http.MethodPost, mastodonAccount, "user[password_confirmation]="},
|
||||
{http.MethodPost, mastodonAccount, "user[current_password]="},
|
||||
{http.MethodPost, "/settings/migration", "account_migration[current_password]="},
|
||||
@@ -313,10 +314,8 @@ func TestMastodonPasswordsPass(t *testing.T) {
|
||||
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)
|
||||
wantPasswordAttacksPass(t, r, name)
|
||||
wantPasswordAttacksRefused(t, r, name)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -327,7 +326,8 @@ func TestMastodonPasswordsPass(t *testing.T) {
|
||||
[]string{jsonBody}}
|
||||
|
||||
wantRandomPasswordsPass(t, r, "password")
|
||||
wantPasswordAttacksRefused(t, r, "password", scriptTag)
|
||||
wantPasswordAttacksPass(t, r, "password")
|
||||
wantPasswordAttacksRefused(t, r, "password")
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -174,6 +174,7 @@ var mediawikiBodyFields = []mediawikiBodyField{
|
||||
//nolint:gochecknoglobals // a constant cannot be a list
|
||||
var mediawikiPasswordFields = []mediawikiBodyField{
|
||||
{mediawikiSignIn, "wpPassword="},
|
||||
{"/w" + mediawikiSignInPage, "wpPassword="},
|
||||
{mediawikiAPI, "lgpassword="},
|
||||
{mediawikiAPI, passwordField},
|
||||
}
|
||||
@@ -252,10 +253,8 @@ func TestMediaWikiPasswordsPass(t *testing.T) {
|
||||
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)
|
||||
wantPasswordAttacksPass(t, r, name)
|
||||
wantPasswordAttacksRefused(t, r, name)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,10 +288,8 @@ func TestNextcloudPasswordPasses(t *testing.T) {
|
||||
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)
|
||||
wantPasswordAttacksPass(t, r, "password")
|
||||
wantPasswordAttacksRefused(t, r, "password")
|
||||
}
|
||||
|
||||
func TestNextcloudSentencesPassInTheTexts(t *testing.T) {
|
||||
|
||||
Reference in new issue
Block a user