script (⏱,💰)

script (⏱,💰)

NG#7 - calldata

The content of this task is about the calldata of the StarkNet contract. Calldata refers to the data passed to a function during a function call. In StarkNet, the data passed can be of various types, but it will ultimately be converted into a snapshot consisting of multiple felt252s. For more details, see the call_contract_syscall in the StarkNet contract.

There are two contracts, the cast function in the PortalSpell contract accepts an Array<PortalData>, and the cast function in the DrunkenMage contract accepts two Array<felt252>. You need to pass calldata consisting of two arrays, and the first two PortalData in the Array<PortalData> should be the same (as verified in the contract code).

The above cast will be called across contracts through the dispatcher, so there is no need to verify if the parameters are the same.

Approach#

First, you need to understand how the StarkNet contract parses calldata, which is explained clearly in the task walkthrough.

The goal is to encode an Array<PortalData> value, which is [ 0: { location: 'TAVERN', details: [ 'OPEN', 'PORTAL' ] }, 1: { location: 'HOME', details: [ 'CLOSE', 'PORTAL' ] } ].

Since Serde is implemented, the struct can be serialized. In the test, when printed, a single struct is encoded as follows:

When two PortalData are combined and a 2 is added at the beginning, it becomes the final encoding.

The drunk_spell.cast(origin, destination) is passed separately, and we must find the values for origin and destination so that when it is interpreted as Array<PortalData>, it reflects the desired calldata.

The only thing that needs to be verified is the first two Portals, which are ['TAVERN', 2, 'OPEN', 'PORTAL', 'HOME', 2, 'CLOSE', 'PORTAL'].

If an additional PortalData {location: 'VOID', details: ['ANY']} is added, the encoding will become [3, 'TAVERN', 2, 'OPEN', 'PORTAL', 'HOME', 2, 'CLOSE', 'PORTAL','VOID', 1 , 'ANY'], which can also be verified.

However, if it is split into two separate arrays to be passed, it will be [3, 'TAVERN', 2, 'OPEN', 'PORTAL'] and ['PORTAL', 'HOME', 2, 'CLOSE', 'PORTAL','VOID', 1 , 'ANY'], and converting 'PORTAL' to a felt decimal number will be very large. To satisfy the length requirement of details or add more portals, it will consume a lot of gas and will result in an error when running the test.

If the number of Portals is increased until the length of the second parameter array is a very small number, it will not consume much gas. Now you should know how to write it.

After passing the test, I am ready to deploy the contract to crack it. First, using starkli invoke, I found that arrays cannot be passed. snforge invoke --calldata can pass calldata, but I don't know how to pass additional parameters such as the account. Finally, I found that sending the two calldata directly through the Voyager browser is the simplest method.

Conclusion#

The composition rule of StarkNet's calldata is very simple. The challenging part of this question is adding more Portals to form a specific calldata. It is an interesting CTF question.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.