Beispiel #1
0
    def test_methods(self):
        """
    Making sure following methods work as intended:
    - add_file_to_repository(data)
    - modify_file_at_repository(filepath, data)
    - delete_file_at_repository(filepath)
    - read_file_content(filepath)
    - tuf_refresh_repo()
    - tuf_refresh_and_download()

    Note: here file at the 'filepath' and the 'target' file at tuf-targets
    directory are identical files.
    Ex: filepath = '{root_repo}/reg_repo/file.txt'
        target = '{root_repo}/tuf_repo/targets/file.txt'
    """

        reg_repo = os.path.join(self.root_repo, 'reg_repo')
        tuf_repo = os.path.join(self.root_repo, 'tuf_repo')
        downloads = os.path.join(self.root_repo, 'downloads')

        # Test 'add_file_to_repository(directory, data)' and
        # read_file_content(filepath) methods.
        filepath = util_test_tools.add_file_to_repository(reg_repo, 'Test')
        self.assertTrue(os.path.isfile(filepath))
        self.assertEquals(os.path.dirname(filepath), reg_repo)
        filepath_content = util_test_tools.read_file_content(filepath)
        self.assertEquals('Test', filepath_content)

        # Test 'modify_file_at_repository(filepath, data)' method.
        filepath = util_test_tools.modify_file_at_repository(
            filepath, 'Modify')
        self.assertTrue(os.path.exists(filepath))
        filepath_content = util_test_tools.read_file_content(filepath)
        self.assertEquals('Modify', filepath_content)

        # Test 'tuf_refresh_repo' method.
        util_test_tools.tuf_refresh_repo(self.root_repo, self.keyids)
        file_basename = os.path.basename(filepath)
        target = os.path.join(tuf_repo, 'targets', file_basename)
        self.assertTrue(os.path.isfile(target))

        # Test 'delete_file_at_repository(filepath)' method.
        util_test_tools.delete_file_at_repository(filepath)
        self.assertFalse(os.path.exists(filepath))

        # Test 'tuf_refresh_repo' method once more.
        util_test_tools.tuf_refresh_repo(self.root_repo, self.keyids)
        file_basename = os.path.basename(filepath)
        target = os.path.join(tuf_repo, 'targets', file_basename)
        self.assertFalse(os.path.isfile(target))
def _download(url, filename, directory, using_tuf=False):
  destination = os.path.join(directory, filename)
  if using_tuf:
    tuf.interposition.urllib_tuf.urlretrieve(url, destination)
  else:
    urllib.urlretrieve(url, destination)

  file_contents = util_test_tools.read_file_content(destination)

  # Parse the list of required files (if it exists) and download them.
  if file_contents.find('requires:') != -1:
    required_files = file_contents[file_contents.find('requires:') + 9:].split(',')
    for required_filename in required_files:
      required_file_url = os.path.dirname(url)+os.sep+required_filename
      _download(required_file_url, required_filename, directory, using_tuf)
Beispiel #3
0
    def test_direct_download(self):
        # Setup.
        reg_repo = os.path.join(self.root_repo, 'reg_repo')
        downloads = os.path.join(self.root_repo, 'downloads')
        filepath = util_test_tools.add_file_to_repository(reg_repo, 'Test')
        file_basename = os.path.basename(filepath)
        url_to_reg_repo = self.url + 'reg_repo/' + file_basename
        downloaded_file = os.path.join(downloads, file_basename)

        # Test direct download using 'urllib.urlretrieve'.
        urllib.urlretrieve(url_to_reg_repo, downloaded_file)
        self.assertTrue(os.path.isfile(downloaded_file))

        # Verify the content of the downloaded file.
        downloaded_content = util_test_tools.read_file_content(downloaded_file)
        self.assertEquals('Test', downloaded_content)
Beispiel #4
0
def test_endless_data_attack(using_tuf=False, TIMESTAMP=False):
    """
  <Purpose>
    Illustrate endless data attack vulnerability.

  <Arguments>
    using_tuf:
      If set to 'False' all directories that start with 'tuf_' are ignored, 
      indicating that tuf is not implemented.

  """

    ERROR_MSG = 'Endless Data Attack was Successful!\n'

    try:
        # Setup.
        root_repo, url, server_proc, keyids = util_test_tools.init_repo(
            using_tuf)
        reg_repo = os.path.join(root_repo, 'reg_repo')
        tuf_repo = os.path.join(root_repo, 'tuf_repo')
        downloads = os.path.join(root_repo, 'downloads')
        tuf_targets = os.path.join(tuf_repo, 'targets')

        # Original data.
        INTENDED_DATA = 'Test A'

        # Add a file to 'repo' directory: {root_repo}
        filepath = util_test_tools.add_file_to_repository(
            reg_repo, INTENDED_DATA)
        file_basename = os.path.basename(filepath)
        url_to_repo = url + 'reg_repo/' + file_basename
        downloaded_file = os.path.join(downloads, file_basename)
        # We do not deliver truly endless data, but we will extend the original
        # file by many bytes.
        noisy_data = 'X' * 100000

        if using_tuf:
            # Update TUF metadata before attacker modifies anything.
            util_test_tools.tuf_refresh_repo(root_repo, keyids)
            # Modify the url.  Remember that the interposition will intercept
            # urls that have 'localhost:9999' hostname, which was specified in
            # the json interposition configuration file.  Look for 'hostname'
            # in 'util_test_tools.py'. Further, the 'file_basename' is the target
            # path relative to 'targets_dir'.
            url_to_repo = 'http://localhost:9999/' + file_basename

            # Attacker modifies the file at the targets repository.
            target = os.path.join(tuf_targets, file_basename)
            original_data = util_test_tools.read_file_content(target)
            larger_original_data = original_data + noisy_data
            util_test_tools.modify_file_at_repository(target,
                                                      larger_original_data)

            # Attacker modifies the timestamp.txt metadata.
            if TIMESTAMP:
                metadata = os.path.join(tuf_repo, 'metadata')
                timestamp = os.path.join(metadata, 'timestamp.txt')
                original_data = util_test_tools.read_file_content(timestamp)
                larger_original_data = original_data + noisy_data
                util_test_tools.modify_file_at_repository(
                    timestamp, larger_original_data)

        # Attacker modifies the file at the regular repository.
        original_data = util_test_tools.read_file_content(filepath)
        larger_original_data = original_data + noisy_data
        util_test_tools.modify_file_at_repository(filepath,
                                                  larger_original_data)

        # End Setup.

        # Client downloads (tries to download) the file.
        try:
            _download(url_to_repo, downloaded_file, using_tuf)
        except Exception, exception:
            # Because we are extending the true timestamp TUF metadata with invalid
            # JSON, we except to catch an error about invalid metadata JSON.
            if using_tuf and TIMESTAMP:
                endless_data_attack = False

                for mirror_url, mirror_error in exception.mirror_errors.iteritems(
                ):
                    if isinstance(mirror_error, tuf.InvalidMetadataJSONError):
                        endless_data_attack = True
                        break

                # In case we did not detect what was likely an endless data attack, we
                # reraise the exception to indicate that endless data attack detection
                # failed.
                if not endless_data_attack: raise
            else: raise

        # When we test downloading "endless" timestamp with TUF, we want to skip
        # the following test because downloading the timestamp should have failed.
        if not (using_tuf and TIMESTAMP):
            # Check whether the attack succeeded by inspecting the content of the
            # update.  The update should contain 'Test A'.  Technically it suffices
            # to check whether the file was downloaded or not.
            downloaded_content = util_test_tools.read_file_content(
                downloaded_file)
            if downloaded_content != INTENDED_DATA:
                raise EndlessDataAttack(ERROR_MSG)
Beispiel #5
0
      # Client downloads (tries to download) the file.
      _download(url_to_repo, downloaded_file, using_tuf)

    except tuf.NoWorkingMirrorError, error:
      # We only set up one mirror, so if it fails, we expect a
      # NoWorkingMirrorError. If TUF has worked as intended, the mirror error
      # contained within should be a BadHashError.
      mirror_error = error.mirror_errors[url+'tuf_repo/targets/'+file_basename]

      assert isinstance(mirror_error, tuf.BadHashError)

    else:
      # Check whether the attack succeeded by inspecting the content of the
      # update.  The update should contain 'Test A'.  Technically it suffices
      # to check whether the file was downloaded or not.
      downloaded_content = util_test_tools.read_file_content(downloaded_file)
      if 'Test A' != downloaded_content:
        raise ArbitraryPackageAlert(ERROR_MSG)


  finally:
    util_test_tools.cleanup(root_repo, server_proc)




print('Attempting arbitrary package attack without TUF:')
try:
  test_arbitrary_package_attack(using_tuf=False)

except ArbitraryPackageAlert, error:
Beispiel #6
0
def test_replay_attack(using_tuf=False):
    """
  <Arguments>
    using_tuf:
      If set to 'False' all directories that start with 'tuf_' are ignored, 
      indicating that tuf is not implemented.

  <Purpose>
    Illustrate replay attack vulnerability.

  """

    ERROR_MSG = '\tReplay Attack was Successful!\n\n'
    FIRST_CONTENT = 'Test A'
    SECOND_CONTENT = 'Test B'

    try:
        # Setup.
        root_repo, url, server_proc, keyids = \
          util_test_tools.init_repo(using_tuf=using_tuf)
        reg_repo = os.path.join(root_repo, 'reg_repo')
        tuf_repo = os.path.join(root_repo, 'tuf_repo')
        tuf_repo_copy = os.path.join(root_repo, 'tuf_repo_copy')
        downloads = os.path.join(root_repo, 'downloads')
        tuf_targets = os.path.join(tuf_repo, 'targets')

        # Add file to 'repo' directory: {root_repo}
        filepath = util_test_tools.add_file_to_repository(
            reg_repo, FIRST_CONTENT)
        file_basename = os.path.basename(filepath)
        url_to_repo = url + 'reg_repo/' + file_basename
        downloaded_file = os.path.join(downloads, file_basename)

        # Attacker saves the original file into 'evil_dir'.
        evil_dir = tempfile.mkdtemp(dir=root_repo)
        original_file = os.path.join(evil_dir, file_basename)
        shutil.copy(filepath, evil_dir)

        if using_tuf:
            # Update TUF metadata before attacker modifies anything.
            util_test_tools.tuf_refresh_repo(root_repo, keyids)
            # Copy the first version of the repository for replay later.
            shutil.copytree(tuf_repo, tuf_repo_copy)

            # Modify the url.  Remember that the interposition will intercept
            # urls that have 'localhost:9999' hostname, which was specified in
            # the json interposition configuration file.  Look for 'hostname'
            # in 'util_test_tools.py'. Further, the 'file_basename' is the target
            # path relative to 'targets_dir'.
            url_to_repo = 'http://localhost:9999/' + file_basename
        # End of Setup.

        # Client performs initial update.
        _download(url=url_to_repo,
                  filename=downloaded_file,
                  using_tuf=using_tuf)

        # Downloads are stored in the same directory '{root_repo}/downloads/'
        # for regular and tuf clients.
        downloaded_content = util_test_tools.read_file_content(downloaded_file)
        if FIRST_CONTENT != downloaded_content:
            raise TestSetupError(
                '[Initial Update] Failed to download the file.')

        # Developer patches the file and updates the repository.
        util_test_tools.modify_file_at_repository(filepath, SECOND_CONTENT)

        # Updating tuf repository.  This will copy files from regular repository
        # into tuf repository and refresh the metadata
        if using_tuf:
            util_test_tools.tuf_refresh_repo(root_repo, keyids)

        # Client downloads the patched file.
        _download(url=url_to_repo,
                  filename=downloaded_file,
                  using_tuf=using_tuf)

        # Content of the downloaded file.
        downloaded_content = util_test_tools.read_file_content(downloaded_file)
        if SECOND_CONTENT != downloaded_content:
            raise TestSetupError('[Update] Failed to update the file.')

        # Attacker tries to be clever, he manages to modifies regular and tuf
        # targets directory by replacing a patched file with an old one.
        if using_tuf:
            # Delete the current TUF repository...
            shutil.rmtree(tuf_repo)
            # ...and replace it with a previous copy.
            shutil.move(tuf_repo_copy, tuf_repo)
        else:
            # Delete the current file...
            util_test_tools.delete_file_at_repository(filepath)
            # ...and replace it with a previous copy.
            shutil.copy(original_file, reg_repo)

        try:
            # Client downloads the file once more.
            _download(url=url_to_repo,
                      filename=downloaded_file,
                      using_tuf=using_tuf)
        except tuf.NoWorkingMirrorError, exception:
            replayed_metadata_attack = False

            for mirror_url, mirror_error in exception.mirror_errors.iteritems(
            ):
                if isinstance(mirror_error, tuf.ReplayedMetadataError):
                    replayed_metadata_attack = True
                    break

            # In case we did not detect what was likely a replayed metadata attack,
            # we reraise the exception to indicate that replayed metadata attack
            # detection failed.
            if not replayed_metadata_attack: raise
        else:
Beispiel #7
0
def test_mix_and_match_attack(using_tuf=False):
  """
  Attack design:
    There are 3 stages:
      Stage 1: Consists of a usual mode of operations using tuf.  Client 
      downloads a target file. (Initial download)

      Stage 2: The target file is legitimately modified and metadata correctly
      updated.  Client downloads the target file again. (Patched target download)

      Stage 3: The target file is legitimately modified  and metadata correctly
      updated again.  However, before client gets to download the newly patched
      target file the attacker replaces the release metadata, targets metadata
      and the target file with the ones from stage 1 (mix-and-match attack).
      Note that timestamp metadata is untouched.  Further note that same would
      happen if only target metadata, and target file are reverted.
  """

  ERROR_MSG = '\tMix-And-Match Attack was Successful!\n\n'


  try:
    # Setup / Stage 1
    # ---------------
    root_repo, url, server_proc, keyids = util_test_tools.init_repo(using_tuf)
    reg_repo = os.path.join(root_repo, 'reg_repo')
    downloads = os.path.join(root_repo, 'downloads')
    evil_dir = tempfile.mkdtemp(dir=root_repo)
    
    # Add file to 'repo' directory: {root_repo}
    filepath = util_test_tools.add_file_to_repository(reg_repo, 'A'*10)
    file_basename = os.path.basename(filepath)
    url_to_file = url+'reg_repo/'+file_basename
    downloaded_file = os.path.join(downloads, file_basename)

    # Attacker saves the initial file.
    shutil.copy(filepath, evil_dir)
    unpatched_file = os.path.join(evil_dir, file_basename)


    if using_tuf:
      print('TUF ...')
      tuf_repo = os.path.join(root_repo, 'tuf_repo')
      tuf_targets = os.path.join(tuf_repo, 'targets')
      metadata_dir = os.path.join(tuf_repo, 'metadata')
      release_meta_file = os.path.join(metadata_dir, 'release.txt')
      targets_meta_file = os.path.join(metadata_dir, 'targets.txt')
      target = os.path.join(tuf_targets, file_basename)
      
      # Update TUF metadata before attacker modifies anything.
      util_test_tools.tuf_refresh_repo(root_repo, keyids)

      # Attacker saves the original metadata and the target file.
      #shutil.copy(target, evil_dir)
      shutil.copy(release_meta_file, evil_dir)
      shutil.copy(targets_meta_file, evil_dir)
      #target_old = os.path.join(evil_dir, file_basename)
      release_meta_file_old = os.path.join(evil_dir, 'release.txt')
      targets_meta_file_old = os.path.join(evil_dir, 'targets.txt')

      # Modify the url.  Remember that the interposition will intercept 
      # urls that have 'localhost:9999' hostname, which was specified in
      # the json interposition configuration file.  Look for 'hostname'
      # in 'util_test_tools.py'. Further, the 'file_basename' is the target
      # path relative to 'targets_dir'. 
      url_to_file = 'http://localhost:9999/'+file_basename


    # Wait for some time to let program set up local http server
    time.sleep(1)
    # Client's initial download.
    _download(url_to_file, downloaded_file, using_tuf)

    # Stage 2
    # -------
    # Developer patches the file and updates the repository.
    util_test_tools.modify_file_at_repository(filepath, 'B'*11)

    # Updating tuf repository.  This will copy files from regular repository
    # into tuf repository and refresh the metadata
    if using_tuf:
      util_test_tools.tuf_refresh_repo(root_repo, keyids)

    # Client downloads the patched file.
    _download(url_to_file, downloaded_file, using_tuf)

    downloaded_content = util_test_tools.read_file_content(downloaded_file)

    # Stage 3
    # -------
    # Developer patches the file and updates the repository again.
    util_test_tools.modify_file_at_repository(filepath, 'C'*10)

    # Updating tuf repository.  This will copy files from regular repository
    # into tuf repository and refresh the metadata
    if using_tuf:
      util_test_tools.tuf_refresh_repo(root_repo, keyids)

      # Attacker replaces the metadata and the target file.
      shutil.copyfile(unpatched_file, target)
      shutil.copyfile(release_meta_file_old, release_meta_file)
      shutil.copyfile(targets_meta_file_old, targets_meta_file)

    # Attacker replaces the patched file with the unpatched one.
    shutil.copyfile(unpatched_file, filepath)

    # Client tries to downloads the newly patched file.
    try:
      _download(url_to_file, downloaded_file, using_tuf)
    except tuf.NoWorkingMirrorError as errors:
      for mirror_url, mirror_error in errors.mirror_errors.iteritems():
        if type(mirror_error) == tuf.BadHashError:
          print('Caught a Bad Hash Error!')

    # Check whether the attack succeeded by inspecting the content of the
    # update.  The update should contain 'Test NOT A'.
    downloaded_content = util_test_tools.read_file_content(downloaded_file)
    if ('B'*11) != downloaded_content:
      raise MixAndMatchAttackAlert(ERROR_MSG)


  finally:
    util_test_tools.cleanup(root_repo, server_proc)