Dria

Swan
NFTHardhat
21,000 USDC
View results
Submission Details
Severity: high
Invalid

Timing Attack Vulnerability : The Swan.relist function uses the block.timestamp for comparisons, which can lead to timing attacks. Specifically, the createdAt field of the AssetListing struct is set to block.timestamp when creating a new listing.

Summary : What is a timing attack?

A timing attack is a type of attack where an attacker exploits the timing of a system's responses to gain information about the system's internal state. In the case of the Swan.relist function, the attacker can exploit the timing of the block.timestamp to gain information about the system's internal state.

How does the vulnerability work?

The vulnerability works as follows:

  1. An attacker calls the Swan.relist function with a specific block.timestamp value.

  2. The Swan.relist function uses the block.timestamp value to set the createdAt field of the AssetListing struct.

  3. The attacker can then use the createdAt field to determine the timing of the system's responses.

  4. By repeatedly calling the Swan.relist function with different block.timestamp values, the attacker can gain information about the system's internal state.

Vulnerability Details : The Swan.relist function uses the block.timestamp for comparisons, which can lead to timing attacks. Specifically, the createdAt field of the AssetListing struct is set to block.timestamp when creating a new listing.

What is the issue with using block.timestamp?

The issue with using block.timestamp is that it can be manipulated by an attacker. Since block.timestamp is a global variable that is set by the miner of the block, an attacker can manipulate the timestamp by creating a new block with a different timestamp.

How can an attacker manipulate block.timestamp?

An attacker can manipulate block.timestamp by creating a new block with a different timestamp. This can be done by:

  1. Creating a new block with a different timestamp.

  2. Broadcasting the new block to the network.

  3. Getting the new block accepted by the network.

Impact : The impact of manipulating block.timestamp is that it can affect the behavior of the Swan.relist function. Specifically, if an attacker manipulates block.timestamp to be earlier or later than the actual timestamp, it can affect the createdAt field of the AssetListing struct.

In the Swan.relist function, the createdAt field of the AssetListing struct is set to block.timestamp when creating a new listing. If an attacker manipulates block.timestamp, they can create a new listing with a different createdAt field.

For example, if an attacker manipulates block.timestamp to be earlier than the actual timestamp, they can create a new listing with a createdAt field that is earlier than the actual time. This can be used to manipulate the behavior of the Swan contract and potentially gain an advantage.

Similarly, if an attacker manipulates block.timestamp to be later than the actual timestamp, they can create a new listing with a createdAt field that is later than the actual time. This can also be used to manipulate the behavior of the Swan contract.

Therefore, it is important to ensure that block.timestamp is not manipulated by an attacker, as it can lead to unexpected behavior and potential security vulnerabilities.

Proof of Concept Code: Here is a proof of concept code that demonstrates the vulnerability:

pragma solidity ^0.8.0;
contract Swan {
struct AssetListing {
uint256 createdAt;
// ...
}
mapping (address => AssetListing) public listings;
function relist(address _asset, address _buyer, uint256 _price) external {
// ...
// set createdAt to block.timestamp
listings[_asset].createdAt = block.timestamp;
// ...
}
}
contract Attacker {
Swan public swan;
function attack() public {
// manipulate block.timestamp to be earlier than the actual timestamp
uint256 manipulatedTimestamp = block.timestamp - 1 hours;
// create a new block with the manipulated timestamp
// ...
// call the Swan.relist function with the manipulated timestamp
swan.relist(address(this), address(this), 0);
// the createdAt field of the AssetListing struct will be set to the manipulated timestamp
assert(swan.listings[address(this)].createdAt == manipulatedTimestamp);
}
}

In this example, the Attacker contract manipulates block.timestamp to be earlier than the actual timestamp and creates a new listing with the manipulated createdAt field. The assert statement checks that the createdAt field is indeed set to the manipulated timestamp.

Tools Used : Slither

Recommendations : To fix the vulnerability, it is recommended to use a more secure method for generating unique identifiers, such as using a random number generator or a cryptographic function. Here are some ways to do this:

Using a Random Number Generator

One way to generate unique identifiers is to use a random number generator. This can be done using a library such as random in Solidity. Here is an example of how to use a random number generator to generate a unique identifier:

pragma solidity ^0.8.0;
contract Swan {
struct AssetListing {
uint256 id;
// ...
}
mapping (uint256 => AssetListing) public listings;
function relist(address _asset, address _buyer, uint256 _price) external {
// generate a random id using a random number generator
uint256 id = uint256(keccak256(abi.encodePacked(block.difficulty, block.timestamp, _asset, _buyer, _price))) % (2**256);
// create a new listing with the generated id
listings[id] = AssetListing({
id: id,
// ...
});
}
}

Using a Cryptographic Function

Another way to generate unique identifiers is to use a cryptographic function such as a hash function. Here is an example of how to use a hash function to generate a unique identifier:

pragma solidity ^0.8.0;
contract Swan {
struct AssetListing {
uint256 id;
// ...
}
mapping (uint256 => AssetListing) public listings;
function relist(address _asset, address _buyer, uint256 _price) external {
// generate a unique id using a hash function
uint256 id = uint256(keccak256(abi.encodePacked(_asset, _buyer, _price)));
// create a new listing with the generated id
listings[id] = AssetListing({
id: id,
// ...
});
}
}

Ensuring maxAssetCount is Up-to-Date and Validated

In addition to using a secure method for generating unique identifiers, it is also important to ensure that the maxAssetCount value is always up-to-date and properly validated to prevent any unexpected behavior or security vulnerabilities.

Here is an example of how to ensure that maxAssetCount is up-to-date and validated:

pragma solidity ^0.8.0;
contract Swan {
uint256 public maxAssetCount;
function relist(address _asset, address _buyer, uint256 _price) external {
// check if maxAssetCount is up-to-date and validated
require(maxAssetCount > 0, "maxAssetCount must be greater than 0");
require(maxAssetCount <= 100, "maxAssetCount must be less than or equal to 100");
// ...
}
function updateMaxAssetCount(uint256 _newMaxAssetCount) external {
// validate the new maxAssetCount value
require(_newMaxAssetCount > 0, "maxAssetCount must be greater than 0");
require(_newMaxAssetCount <= 100, "maxAssetCount must be less than or equal to 100");
// update maxAssetCount
maxAssetCount = _newMaxAssetCount;
}
}

By using a secure method for generating unique identifiers and ensuring that maxAssetCount is up-to-date and validated, you can prevent unexpected behavior and security vulnerabilities in your contract.

Updates

Lead Judging Commences

inallhonesty Lead Judge 9 months ago
Submission Judgement Published
Invalidated
Reason: Too generic

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.