- Issue created by @mcdruid
- 🇬🇧United Kingdom mcdruid 🇬🇧🇪🇺
Unusually, because the fix has already been committed, the test only patch here has to remove that fix... so it's sort of a reverse test only patch.
Without the protection in place, executing the exploit via the ajax system generates a handful of PHP notices / warnings because the payload that's been written to cache_form doesn't represent a valid ajax form structure.
We could try to suppress these in the error handler, but as they only happen when the protection is not in place.. perhaps we don't need to.
I've not yet added testing of the opt-out for this protection. We could do a basic test for that which just checks if we can get a key/value written out to cache form by the DrupalCacheArray destructor; no need to try and execute an actual payload.
- Status changed to Needs review
over 1 year ago 2:46pm 16 August 2023 - last update
over 1 year ago run-tests.sh exception - last update
over 1 year ago 2,160 pass - last update
over 1 year ago 2,159 pass, 3 fail - 🇬🇧United Kingdom mcdruid 🇬🇧🇪🇺
Oops I didn't mean to leave the error_reporting change in.. that was me trying to see if we could suppress the warnings/notices that the final exploit generates.
I'll remove that.
The last submitted patch, 2: 3381481-2_reverse_test_only.patch, failed testing. View results →
- last update
over 1 year ago 2,155 pass, 4 fail - last update
over 1 year ago 2,159 pass, 3 fail - 🇬🇧United Kingdom mcdruid 🇬🇧🇪🇺
Removed the error_reporting change on setUp.
Also added some final checks to test the opt-out variable, but stopping short of trying to execute the 2nd stage payload.
- last update
over 1 year ago 2,160 pass - 🇬🇧United Kingdom mcdruid 🇬🇧🇪🇺
Oops again - that last patch is actually another "reverse test only" as it also removes the fix.
Here's one that does not do that (the interdiff looks a bit confusing as it's really removing a change that's already been committed), so this one should pass.
The last submitted patch, 6: 3381481-6.patch, failed testing. View results →
- 🇬🇧United Kingdom mcdruid 🇬🇧🇪🇺
Noting that the "test only" patch seems to only fully work under PHP 7.4 (see #2) where the payload actually executes and outputs the string the test is looking for. That's fine.
So where are we?
- #7 passes
- the test-only patches show that we'd get failures if the protection was removed
- #7 verifies that the opt-out variable works
- last update
over 1 year ago 2,120 pass, 4 fail - last update
over 1 year ago 2,156 pass - last update
over 1 year ago 2,120 pass, 1 fail - 🇸🇰Slovakia poker10
Thanks for working on this @mcdruid!
I have reviewed the patch and it seems like it is not working correctly on PostgreSQL, see #7 (PostgreSQL test) and #2 (PostgreSQL test).
The PostgreSQL LIKE query on a bytea field might be a bit buggy and we are probably hitting this bug: #2914599: Pgsql prepareQuery() doesn't properly cast bytea to text → , because the record from
cache_form
is not being loaded correctly in both cases (when the opt-out is enabled and disabled).Tested this directly on PostgreSQL DB and this does not work:
SELECT cid FROM cache_form WHERE data::text ILIKE '%phpinfo%';
SELECT cid FROM cache_form WHERE data::text LIKE '%phpinfo%';
This work:
SELECT cid FROM cache_form WHERE data LIKE '%phpinfo%';
If we would not like to complicate things, I think we should either only check if there is a record with
form_DrupalRCE
CID
, or better, compare the whole value of thedata
field, like this:$payload2 = db_query_range('SELECT cid FROM {cache_form} WHERE data = :data', 0, 1, array(':data' => urldecode('a:3:{s:8:"#form_id"%3Bs:9:"DrupalRCE"%3Bs:8:"#process"%3Ba:1:{i:0%3Bs:23:"drupal_process_attached"%3B}s:9:"#attached"%3Ba:1:{s:7:"phpinfo"%3Ba:1:{i:0%3Ba:1:{i:0%3Bs:1:"2"%3B}}}}')))->fetchField();
- Status changed to Needs work
over 1 year ago 5:14pm 18 August 2023 - Status changed to Needs review
over 1 year ago 9:16am 21 August 2023 - last update
over 1 year ago 2,159 pass, 3 fail - last update
over 1 year ago 2,160 pass - 🇬🇧United Kingdom mcdruid 🇬🇧🇪🇺
How about we select the data from the row and use PHP to check if it contains the function name... does that make all the dbs happy?
The last submitted patch, 12: 3381481-12_reverse_test_only.patch, failed testing. View results →
- last update
over 1 year ago 2,159 pass, 3 fail - last update
over 1 year ago 2,160 pass - last update
over 1 year ago 2,160 pass - last update
over 1 year ago 2,159 pass, 3 fail - 🇬🇧United Kingdom mcdruid 🇬🇧🇪🇺
Oops and I'd left an extra empty string param in one of the assertions...
The last submitted patch, 14: 3381481-14_reverse_test_only.patch, failed testing. View results →
The last submitted patch, 15: 3381481-15_reverse_test_only.patch, failed testing. View results →
- last update
over 1 year ago 2,155 pass, 4 fail - last update
over 1 year ago run-tests.sh exception - last update
over 1 year ago 2,121 pass - last update
over 1 year ago run-tests.sh exception - last update
over 1 year ago 2,120 pass, 4 fail - last update
over 1 year ago run-tests.sh exception - last update
over 1 year ago 2,121 pass - last update
over 1 year ago 2,159 pass, 4 fail - last update
over 1 year ago 2,160 pass - last update
over 1 year ago 2,160 pass - last update
over 1 year ago 2,160 pass - last update
over 1 year ago 2,121 pass - last update
over 1 year ago 2,156 pass - last update
over 1 year ago 2,160 pass - last update
over 1 year ago 2,160 pass - last update
over 1 year ago 2,160 pass - Status changed to RTBC
over 1 year ago 3:14pm 21 August 2023 - 🇸🇰Slovakia poker10
I think the patch in #15 looks good! The reversed test-only patch is failing the on PostgreSQL/MySQL/SQLite (PHP 7.4) as expected and the patch with the test itself is passing all tests. Moving to RTBC, thanks!
- Status changed to Fixed
over 1 year ago 6:19pm 21 August 2023 Automatically closed - issue fixed for 2 weeks with no activity.