Enterprise Blockchain
Description¶
Smart Contract Solutions is proud to introduce the only Enterprise Blockchain that you'll ever need.
Solution¶
-
There are two chains and the challenge is deployed on the layer 1 chain. Initially, there are 100 FlagTokens (18 decimals) in the l1Bridge. The objective of this challenge is to pull at least 10 FlagTokens from the l1Bridge
-
Users can transfer funds between chains via the bridge. The relayer will listen to the
SendRemoteMessage
event in both chains and relay messages to the target chain -
To emit a SendRemoteMessage event, we can call
sendRemoteMessage()
function and the transaction to be executed on the other chain can be customized -
Since L2 RPC is also provided and the player has some ethers, we can send a remote message from L2 to L1 and transfer tokens from l1Bridge to users
-
However, the
sendRemoteMessage()
function is not intended to be public and it is expected to only useethOut()
/ERC20Out()
to transfer funds between chains :< The above is an unintended solution lol -
A
SimpleMultiSigGov
is deployed at 0x31337 on the L2 chain. It can be used to interact with the precompiled contractADMIN
at 1337 -
The precompiled contract
ADMIN
has a functionfn_dump_state()
, operations in which may cause undefined behavior. First,x.len()
should be greater than0x10
, otherwise the program will panic withindex out of bounds
wheni == x.len()
.states
is a raw pointer to slices&[u8]
and a slice is 16 bytes on an x86-64. The count ofstates.offset
is in units of a slice. Since the maximum ofi
is0x10
, the minimum memory that should be allocated is 0x110 (16 * (0x10 + 1)) instead of0x100
. Thus, ifx.len()
is greater than0x10
, the program will write to unallocated memorystates.offset(0x10)
-
Calling
fn_dump_state()
whenx.len() > 0x10
will kill the L2 node. Theanvil
service will soon restart and load the state from the previously dumped state -
The state dump interval is 5 seconds, but the relayer will relay the message as long as it catches the
SendRemoteMessage
event. If the L2 node goes down when new cross-chain transfer transactions have been included in a block but the latest state has not yet been dumped, the message will be relayed to L1 while the state of L2 can only be restored to the state before the transfer occurred. In this case, users can transfer funds to L1 without spending any in L2 :O -
Only the
SimpleMultiSigGov
at 0x31337 can interact with theADMIN
, but we can't obtain any valid signatures to let it execute transactions. Alternatively, we can leverage the state override set to ephemerally override the code at 0x31337 and simulate the call -
The
admin_func_run()
function is the entry point ofADMIN
. To invoke thefn_dump_state()
function, the first two bytes should be0x0204
Exploitation¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
|
Flag¶
PCTF{57473_0V3RR1d35_90_8RR}
References¶
- rust - Unexpected segfault when working with raw pointers - Stack Overflow
- Arrays and Slices - Rust By Example
- pointer - Rust
- eth_call - Ethereum