mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			28 lines
		
	
	
		
			1.2 KiB
		
	
	
	
		
			Solidity
		
	
	
	
	
	
			
		
		
	
	
			28 lines
		
	
	
		
			1.2 KiB
		
	
	
	
		
			Solidity
		
	
	
	
	
	
| pragma abicoder v2;
 | |
| contract Test {
 | |
| 	struct MemoryUint {
 | |
| 		uint field;
 | |
| 	}
 | |
| 	function test() public pure returns (uint) {
 | |
| 		uint[] memory before = new uint[](1); // at offset 0x80
 | |
| 		// Two problems here: The first offset is zero, the second offset is missing.
 | |
| 		bytes memory corrupt = abi.encode(uint(32), // offset to "tuple"
 | |
| 										  uint(0)); // bogus first element
 | |
| 		/*
 | |
| 		  At this point the free pointer is 0x80 + 64 (size of before) + 32 (length field of corrupt) + 64 (two encoded words)
 | |
| 
 | |
| 		  Now let's put random junk into memory immediately after the bogus first element. Our goal is to overflow the read pointer to point to before.
 | |
| 		  The value read out at this point will be added to beginning of the encoded tuple, AKA corrupt + 64. We need then to write x where:
 | |
| 		  x + 0x80 + 64 (before) + 32 (length of corrupt) + 32 (first word of corrupt) = 0x80 (mod 2^256)
 | |
| 		  that is MAX_UINT - 128
 | |
| 		*/
 | |
| 		MemoryUint memory afterCorrupt;
 | |
| 		afterCorrupt.field = uint(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80);
 | |
| 		before[0] = 123456;
 | |
| 		uint[][2] memory decoded = abi.decode(corrupt, (uint[][2]));
 | |
| 		return decoded[1][0];
 | |
| 	}
 | |
| }
 | |
| // ----
 | |
| // test() -> FAILURE
 |