python-tuf/tuf/ATTACKS.md
chentanjun 560d45dca2 fix-up the document spelling mistake
Signed-off-by: chentanjun <2799194073@qq.com>
2019-08-27 14:41:24 +08:00

13 KiB

Demonstrate protection against malicious updates

Table of Contents

Blocking Malicious Updates

TUF protects against a number of attacks, some of which include rollback, arbitrary package, and mix and match attacks. We begin this document on blocking malicious updates by demonstrating how the client rejects a target file downloaded from the software repository that doesn't match what is listed in TUF metadata.

The following demonstration requires and operates on the repository created in the repository management tutorial.

Arbitrary Package Attack

In an arbitrary package attack, an attacker installs anything they want on the client system. That is, an attacker can provide arbitrary files in response to download requests and the files will not be detected as illegitimate. We simulate an arbitrary package attack by creating a "malicious" target file that our client attempts to fetch.

$ mv 'repository/targets/file2.txt' 'repository/targets/file2.txt.backup'
$ echo 'bad_target' > 'repository/targets/file2.txt'

We next reset our local timestamp (so that a new update is prompted), and the target files previously downloaded by the client.

$ rm -rf "client/targets/" "client/metadata/current/timestamp.json"

The client now performs an update and should detect the invalid target file... Note: The following command should be executed in the "client/" directory.

$ python basic_client.py --repo http://localhost:8001
Error: No working mirror was found:
  localhost:8001: BadHashError()

The log file (tuf.log) saved to the current working directory contains more information on the update procedure and the cause of the BadHashError.

...

BadHashError: Observed
hash ('f569179171c86aa9ed5e8b1d6c94dfd516123189568d239ed57d818946aaabe7') !=
expected hash (u'67ee5478eaadb034ba59944eb977797b49ca6aa8d3574587f36ebcbeeb65f70e')
[2016-10-20 19:45:16,079 UTC] [tuf.client.updater] [ERROR] [_get_file:1415@updater.py]
Failed to update /file2.txt from all mirrors: {u'http://localhost:8001/targets/file2.txt': BadHashError()}

Note: The "malicious" target file should be removed and the original file2.txt restored, otherwise the following examples will fail with BadHashError exceptions:

$ mv 'repository/targets/file2.txt.backup' 'repository/targets/file2.txt'

Indefinite Freeze Attack

In an indefinite freeze attack, an attacker continues to present a software update system with the same files the client has already seen. The result is that the client does not know that new files are available. Although the client would be unable to prevent an attacker or compromised repository from feeding it stale metadata, it can at least detect when an attacker is doing so indefinitely. The signed metadata used by TUF contains an "expires" field that indicates when metadata should no longer be trusted.

In the following simulation, the client first tries to perform an update.

$ python basic_client.py --repo http://localhost:8001

According to the logger (tuf.log file in the current working directory), everything appears to be up-to-date. The remote server should also show that the client retrieved only the timestamp.json file. Let's suppose now that an attacker continues to feed our client the same stale metadata. If we were to move the time to a future date that would cause metadata to expire, the TUF framework should raise an exception or error to indicate that the metadata should no longer be trusted.

$ sudo date -s '2080-12-25 12:34:56'
Wed Dec 25 12:34:56 EST 2080

$ python basic_client.py --repo http://localhost:8001
Error: No working mirror was found:
  u'localhost:8001': ExpiredMetadataError(u"Metadata u'root' expired on Tue Jan  1 00:00:00 2030 (UTC).",)

Note: Reset the date to continue with the rest of the attacks.

Rollback Attack

In a rollback attack, an attacker presents a software update system with older files than those the client has already seen, causing the client to use files older than those the client knows about. We begin this example by saving the current version of the Timestamp file available on the repository. This saved file will later be served to the client to see if it is rejected. The client should not accept versions of metadata that is older than previously trusted.

Navigate to the directory containing the server's files and save the current timestamp.json to a temporary location:

$ cp repository/metadata/timestamp.json /tmp

We should next generate a new Timestamp file on the repository side.

$ python
>>> from tuf.repository_tool import *
>>> repository = load_repository('repository')
>>> repository.timestamp.version
1
>>> repository.timestamp.version = 2
>>> repository.dirty_roles()
Dirty roles: [u'timestamp']
>>> private_timestamp_key = import_rsa_privatekey_from_file("keystore/timestamp_key")
Enter a password for the encrypted RSA file (/path/to/keystore/timestamp_key):
>>> repository.timestamp.load_signing_key(private_timestamp_key)
>>> repository.write('timestamp')

$ cp repository/metadata.staged/* repository/metadata

Now start the HTTP server from the directory containing the 'repository' subdirectory.

$ python -m SimpleHTTPServer 8001

And perform an update so that the client retrieves the updated timestamp.json.

$ python basic_client.py --repo http://localhost:8001

Finally, move the previous timestamp.json file to the current live repository and have the client try to download the outdated version. The client should reject it!

$ cp /tmp/timestamp.json repository/metadata/
$ cd repository; python -m SimpleHTTPServer 8001

On the client side, perform an update...

$ python basic_client.py --repo http://localhost:8001
Error: No working mirror was found:
  u'localhost:8001': ReplayedMetadataError()

The tuf.log file contains more information about the ReplayedMetadataError exception and update process. Please reset timestamp.json to the latest version, which can be found in the 'repository/metadata.staged' subdirectory.

$ cp repository/metadata.staged/timestamp.json repository/metadata

Endless Data Attack

In an endless data attack, an attacker responds to a file download request with an endless stream of data, causing harm to clients (e.g., a disk partition filling up or memory exhaustion). In this simulated attack, we append extra data to one of the target files available on the software repository. The client should only download the exact number of bytes it expects for a requested target file (according to what is listed in trusted TUF metadata).

$ cp repository/targets/file1.txt /tmp
$ python -c "print 'a' * 1000" >> repository/targets/file1.txt

Now delete the local metadata and target files on the client side so that remote metadata and target files are downloaded again.

$ rm -rf client/targets/
$ rm client/metadata/current/snapshot.json* client/metadata/current/timestamp.json*

Lastly, perform an update to verify that the file1.txt is downloaded up to the expected size, and no more. The target file available on the software repository does contain more data than expected, though.

$ python basic_client.py --repo http://localhost:8001

At this point, part of the "file1.txt" file should have been fetched. That is, up to 31 bytes of it should have been downloaded, and the rest of the maliciously appended data ignored. If we inspect the logger, we'd discover the following:

[2016-10-06 21:37:39,092 UTC] [tuf.download] [INFO] [_download_file:235@download.py]
Downloading: u'http://localhost:8001/targets/file1.txt'

[2016-10-06 21:37:39,145 UTC] [tuf.download] [INFO] [_check_downloaded_length:610@download.py]
Downloaded 31 bytes out of the expected 31 bytes.

[2016-10-06 21:37:39,145 UTC] [tuf.client.updater] [INFO] [_get_file:1372@updater.py]
Not decompressing http://localhost:8001/targets/file1.txt

[2016-10-06 21:37:39,145 UTC] [tuf.client.updater] [INFO] [_check_hashes:778@updater.py]
The file's sha256 hash is correct: 65b8c67f51c993d898250f40aa57a317d854900b3a04895464313e48785440da

Indeed, the sha256 sum of the first 31 bytes of the "file1.txt" available on the repository should match to what is trusted. The client did not downloaded the appended data.

Note: Restore file1.txt

$ cp /tmp/file1.txt repository/targets/

Compromised Key Attack

An attacker who compromise less than a given threshold of keys is limited in scope. This includes relying on a single online key (such as only being protected by SSL) or a single offline key (such as most software update systems use to sign files). In this example, we attempt to sign a role file with less-than-a-threshold number of keys. A single key (suppose this is a compromised key) is used to demonstrate that roles must be signed with the total number of keys required for the role. In order to compromise a role, an attacker would have to compromise a threshold of keys. This approach of requiring a threshold number of signatures provides compromise resilience.

Let's attempt to sign a new snapshot file with a less-than-threshold number of keys. The client should reject the partially signed snapshot file served by the repository (or imagine that it is a compromised software repository).

$ python
>>> from tuf.repository_tool import *
>>> repository = load_repository('repository')
>>> version = repository.root.version
>>> repository.root.version = version + 1
>>> private_root_key = import_rsa_privatekey_from_file("keystore/root_key", password="password")
>>> repository.root.load_signing_key(private_root_key)
>>> private_root_key2 = import_rsa_privatekey_from_file("keystore/root_key2", password="password")
>>> repository.root.load_signing_key(private_root_key2)

>>> repository.snapshot.version = 8
>>> repository.snapshot.threshold = 2
>>> private_snapshot_key = import_rsa_privatekey_from_file("keystore/snapshot_key", password="password")
>>> repository.snapshot.load_signing_key(private_snapshot_key)

>>> repository.timestamp.version = 8
>>> private_timestamp_key = import_rsa_privatekey_from_file("keystore/timestamp_key", password="password")
>>> repository.timestamp.load_signing_key(private_timestamp_key)

>>> repository.write('root')
>>> repository.write('snapshot')
>>> repository.write('timestamp')

$ cp repository/metadata.staged/* repository/metadata

The client now attempts to refresh the top-level metadata and the partially written snapshot.json, which should be rejected.

$ python basic_client.py --repo http://localhost:8001
Error: No working mirror was found:
  u'localhost:8001': BadSignatureError()

Slow Retrieval Attack

In a slow retrieval attack, an attacker responds to clients with a very slow stream of data that essentially results in the client never continuing the update process. In this example, we simulate a slow retrieval attack by spawning a server that serves data at a slow rate to our update client data. TUF should not be vulnerable to this attack, and the framework should raise an exception or error when it detects that a malicious server is serving it data at a slow enough rate.

We first spawn the server that slowly streams data to the client. The 'slow_retrieval_server.py' module (can be found in the tests/ directory of the source code) should be copied over to the server's 'repository/' directory from which to launch it.

# Before launching the slow retrieval server, copy 'slow_retrieval_server.py'
# to the 'repository/' directory and run it from that directory as follows:
$ python slow_retrieval_server.py 8002 mode_2

The client may now make a request to the slow retrieval server on port 8002. However, before doing so, we'll reduce (for the purposes of this demo) the minimum average download rate allowed and download chunk size. Open the 'settings.py' module and set MIN_AVERAGE_DOWNLOAD_SPEED = 5 and CHUNK_SIZE = 1. This should make it so that the client detects the slow retrieval server's delayed streaming.

$ python basic_client.py --verbose 1 --repo http://localhost:8002
Error: No working mirror was found:
  u'localhost:8002': SlowRetrievalError()

The framework should detect the slow retrieval attack and raise a SlowRetrievalError exception to the client application.

Conclusion

These are just some of the attacks that TUF provides protection against. For more attacks and updater weaknesses, please see the Security page.