Hack the TON
0. INTRODUCTION¶
-
可以在控制台中使用
help()
查看可以使用的程序功能(index) description fromNano(nano) "convert nano units to ton" toNano(ton) "convert ton units to nano" contract "current level contract instance (if created)" player "current player (if wallet connected)" Address.parse(addressString) "parse Address from string" tonConnectUI.sendTransaction(tx, options) "send custom transaction to arbitrary address" beginCell() "start building a cell" -
在连接钱包后,点击
GET NEW INSTANCE
获取一个题目实例 -
与 Ethernaut 类似,可以在控制台使用
contract
获取信息或与合约交互 -
完成后点击
CHECK SOLUTION
验证
References¶
1. DEPOSIT¶
You will beat this level if:
Claim ownership of the contract
Reduce its balance to 0
DepositLevel
-
只有所有者才能取出合约持有的 TON,首先向合约发送 TON 以成为所有者
-
使用
withdraw
取出合约中所有的资金
2. SCANNER¶
Claim ownership of the contract below to complete this level.
ScannerLevel
- 要成为合约的所有者需要知道
Child
合约的地址,可以通过 Tonviewer 查看ScannerLevel
部署的交易来获知 -
发送
Child
合约地址
3. BOUNCE¶
Claim ownership of the contract below to complete this level.
BounceLevel
- 合约
BounceLevel
收到弹回的消息后就会将玩家设为合约所有者 -
只需要在发送完
start
的三分钟后向BounceLevel
发送finish
,让合约Timer
抛出错误弹回消息即可- 或直接向
Timer
发送start
设置自定义开始时间
- 或直接向
References¶
4. INTRUDER¶
Claim ownership of the contract below to complete this level.
IntruderLevel
- 只有
manager
能设置合约的所有者,而初始manager
为Manager
合约 -
合约
Manager
不检查ChangeClientOwner
消息的发送者 -
可以向
Manager
合约发送ChangeClientOwner
消息来设置IntruderLevel
合约的所有者
5. PARTIAL¶
The goal of this level is to hack the vault contract below.
You are given 100 tokens to start with and you will beat the level if you manage to acquire 1000 or more.
PartialLevel
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 110 111 112 113 114 115 |
|
-
通过
WithdrawFromVault
可以增加合约的余额,但若WithdrawInternal
执行失败,将回弹消息并回滚余额 -
在 TON 中, 如果支付的费用不足以完成执行,则不会创建回弹消息。因此只需要支付仅供
WithdrawFromVault
执行的费用,使余额增加即可
References¶
6. PEEK¶
Unlock the contract below to complete this level.
PeekLevel
- 提供正确的密码即可解锁,需要解析初始化消息
- 部署 Tact 编写的合约,函数
init()
的参数包含在 init data 中,并将在部署附带的第一次合约调用中根据 init data 更新存储 -
使用
pytoniq-core
解析初始数据- 尽管可以使用较小的
Int
表示形式来减少存储开销,但 TVM 仅对 257 位整型进行操作。因此,init data 中的整型参数均为 257 位有符号整数
- 尽管可以使用较小的
-
发送解锁消息
References¶
7. SWAP¶
You will beat the level if you manage to acquire tokens amount equivalent to 1000 TON or more.
SwapLevel
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 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
|
-
操作
swap ton to tokens
每次能使Token
的balance
增加myBalance() - context().value
,即合约SwapLevel
持有的 TON 越多,每次的增加量越大。向合约SwapLevel
发送 TON 增加其余额以减少操作的次数 -
合约
Token
执行操作SwapTonToTokens
时,会向合约SwapLevel
发送send ton
消息,使其将所持有的全部 TON 发送给合约Token
。需要控制swap ton to tokens
消息附带的 TON,使合约SwapLevel
无法将余额发送给合约Token
。经测试,可以使用 0.008 TON -
使用 TON Web IDE 部署辅助合约,批量发送消息
- 全局设置中可以修改消息附带的 TON 数量
-
检查结束后取回合约中的 TON
8. COIN¶
To complete the level, guess 10 times in a row which side the coin will land on.
CoinLevel
-
需要连续猜对 10 次,借助辅助合约预测结果并发送消息
- 题目合约使用的 Tact 编译器版本为 1.4.4。不同编译器版本可能产生不同的编译结果,最好使用相同版本的编译器,保证
initOf
在辅助合约中的计算结果与实例合约相同
- 题目合约使用的 Tact 编译器版本为 1.4.4。不同编译器版本可能产生不同的编译结果,最好使用相同版本的编译器,保证
9. GATEKEEPER¶
Unlock the contract below to complete this level.
GatekeeperLevel
- 解锁需要
sender().asSlice().asCell().hash() ^ ((msg.a << 2) + msg.b)
的值与myAddress().asSlice().asCell().hash()
相等 -
获取实例地址的哈希值
-
由于
a
和b
没有限制范围,可以直接将a
设置为 0,b
为发送者地址哈希值与实例地址哈希值异或的结果
10. BRUTE-FORCE¶
Unlock the contract below to complete this level.
BruteforceLevel
- 解锁需要提供满足特定条件的四个整数
(self.x + self.y) == 2
即msg.a + msg.b + msg.c + msg.d == 2
,说明正负整数的绝对值之差为 2,且msg.a + msg.c
和msg.b + msg.d
的结果在 8 位无符号整型的范围内(((pow(msg.a, 25) + pow(msg.b, 25)) + pow(msg.c, 25)) + pow(msg.d, 25))
的结果是一个正整数1968172103452999492963878188028555943794336458502883276710491621054698698752
-
由此推测出两种可能的情况
self.x
为 2,self.y
为 0(反之亦同)self.x
和self.y
同为 1
-
发送结果到实例合约
11. TOLK¶
Unlock the contract below to complete this level.
Tolk
发送 OP_UNLOCK
对应的操作码即可解锁。
12. UPGRADE¶
Unlock the contract below to complete this level.
Upgrade
-
向合约发送
OP_UPGRADE
消息可以更新合约的代码 -
可以在新代码中增加更新存储的逻辑
-
更新代码并解锁
13. ACCESS¶
Unlock the contract below to complete this level.
Access
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 110 111 112 113 114 115 116 117 118 119 |
|
-
解锁需要
ctx_owner
是ctx_player
-
操作
op::change_owner
调用函数check_owner()
检查调用者是否为ctx_owner
,但由于未使用impure
标识符且没有检查函数调用的结果,该函数调用会在编译时被移除 -
因此,先修改
ctx_nonce
再更新ctx_owner
,即可解锁
14. DONATE¶
You will beat this level if you manage to reduce its balance to 0.
Donate
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 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
|
- 操作
op::withdraw
可以将合约所持有的所有 TON 都发送给调用者destination
- 修改
destination
的操作op::change_destination
只有owner
可以调用 -
由于全局变量不能被重定义,当合约余额大于
donation_goal
时,操作op::donate
实际上更新的是全局变量destination
,而不是其定义的本地变量 -
捐款并设置
destination
,随后发送op::withdraw
消息
References¶
15. LOGICAL¶
Unlock the contract below to complete this level.
Logical
-
当当前交易的逻辑时间和上一交易的逻辑时间之差为
ctxLogicalTimeDiff
时,可以解锁 -
获取
ctxLogicalTimeDiff
的值 -
由于要求逻辑时间差仅为 1,可以从同一个合约中发出两条消息
16. SEED¶
Unlock the contract below to complete this level.
Seed
-
当
ctxSeed
不为 0 时,将直接设置 seed 并获取随机数作为下一个 seed -
发送一条消息初始化 seed
-
在已知 seed 的情况下,可以通过辅助合约获取随机的结果