You are here

protected function FileFieldWidgetTest::doTestTemporaryFileRemovalExploit in Drupal 10

Same name and namespace in other branches
  1. 8 core/modules/file/tests/src/Functional/FileFieldWidgetTest.php \Drupal\Tests\file\Functional\FileFieldWidgetTest::doTestTemporaryFileRemovalExploit()
  2. 9 core/modules/file/tests/src/Functional/FileFieldWidgetTest.php \Drupal\Tests\file\Functional\FileFieldWidgetTest::doTestTemporaryFileRemovalExploit()

Helper for testing exploiting the temporary file removal using fid.

Parameters

\Drupal\user\UserInterface $victim_user: The victim user.

\Drupal\user\UserInterface $attacker_user: The attacker user.

File

core/modules/file/tests/src/Functional/FileFieldWidgetTest.php, line 565

Class

FileFieldWidgetTest
Tests the file field widget with public and private files.

Namespace

Drupal\Tests\file\Functional

Code

protected function doTestTemporaryFileRemovalExploit(UserInterface $victim_user, UserInterface $attacker_user) {
  $type_name = 'article';
  $field_name = 'test_file_field';
  $this
    ->createFileField($field_name, 'node', $type_name);
  $test_file = $this
    ->getTestFile('text');
  $type = 'no-js';

  // Create a temporary file owned by the victim user. This will be as if
  // they had uploaded the file, but not saved the node they were editing
  // or creating.
  $victim_tmp_file = $this
    ->createTemporaryFile('some text', $victim_user);
  $victim_tmp_file = File::load($victim_tmp_file
    ->id());
  $this
    ->assertTrue($victim_tmp_file
    ->isTemporary(), 'New file saved to disk is temporary.');
  $this
    ->assertNotEmpty($victim_tmp_file
    ->id(), 'New file has an fid.');
  $this
    ->assertEquals($victim_user
    ->id(), $victim_tmp_file
    ->getOwnerId(), 'New file belongs to the victim.');

  // Have attacker create a new node with a different uploaded file and
  // ensure it got uploaded successfully.
  $edit = [
    'title[0][value]' => $type . '-title',
  ];

  // Attach a file to a node.
  $edit['files[' . $field_name . '_0]'] = $this->container
    ->get('file_system')
    ->realpath($test_file
    ->getFileUri());
  $this
    ->drupalGet(Url::fromRoute('node.add', [
    'node_type' => $type_name,
  ]));
  $this
    ->submitForm($edit, 'Save');
  $node = $this
    ->drupalGetNodeByTitle($edit['title[0][value]']);

  /** @var \Drupal\file\FileInterface $node_file */
  $node_file = File::load($node->{$field_name}->target_id);
  $this
    ->assertFileExists($node_file
    ->getFileUri());
  $this
    ->assertEquals($attacker_user
    ->id(), $node_file
    ->getOwnerId(), 'New file belongs to the attacker.');

  // Ensure the file can be downloaded.
  $this
    ->drupalGet($node_file
    ->createFileUrl());
  $this
    ->assertSession()
    ->statusCodeEquals(200);

  // "Click" the remove button (emulating either a nojs or js submission).
  // In this POST request, the attacker "guesses" the fid of the victim's
  // temporary file and uses that to remove this file.
  $this
    ->drupalGet($node
    ->toUrl('edit-form'));
  $file_id_field = $this
    ->assertSession()
    ->hiddenFieldExists($field_name . '[0][fids]');
  $file_id_field
    ->setValue((string) $victim_tmp_file
    ->id());
  $this
    ->submitForm([], 'Remove');

  // The victim's temporary file should not be removed by the attacker's
  // POST request.
  $this
    ->assertFileExists($victim_tmp_file
    ->getFileUri());
}