TGViewer
Из Solidity в AI и дальше Из Solidity в AI и дальше @solidityset · 2.47K subscribers
Post #477 170
Capture The Ether. Fifty Years

Да уж, заставила эта задача посидеть несколько часов, чтобы понять ее логику.

Сам я не решил ее, поэтому пошел гуглить ответы, которые были в нескольких вариациях. И вот уже над  ними просидел столько времени.

Я сам сразу понял, что вся уязвимость кроется в upsert() else логике, вот только исполнить ее не мог. Вот сам контракт и вот эта функция:

function upsert(uint256 index, uint256 timestamp) public payable {
   require(msg.sender == owner);
   if (index >= head && index < queue.length) {
      Contribution storage contribution = queue[index];
      contribution.amount += msg.value;
   } else {
       require(timestamp >= queue[queue.length - 1].unlockTimestamp + 1 days);
        contribution.amount = msg.value;
        contribution.unlockTimestamp = timestamp;
        queue.push(contribution);
   }
}

Как мы видим из контракта, msg.value переписывает первый слот памяти, где лежит длина массива, а timestamp - второй слот (head), который защищает от цикла повторного вывода денег с массива.

Что нужно тут понимать?

Во-первых, принципы работы overflow.

Нам нужно каким-то образом записать в timestamp значение 0. Но просто так этого мы сделать не можем, будет выдавать ошибку. Поэтому нам нужно для начала создать переполнение чисел uint256 (2256 - 1), а в нашем случае минус один день, т.е. (2256-86400 секунд). И уже только после этого действия (транзакции), мы сможем записать "0" в timestamp второй транзакцией, что также обновить head до 0 (каким он и должен быть!).

Во-вторых, msg.value обновляет длину массива, поэтому нам нужно отправлять не по одному Эфиру (10**18), а по 1 Wei, тогда каждый wei будет равен размерности длины массива.

В-третьих, когда выполняется действие queue.push(contribution) в данном примере, в массив записывается значение msg.value, которое мы отправляем в Wei и еще "+1". Другими словами, после того как мы в первый раз отправим транзакцию и передадим 1 Wei, то на балансе контракта будет 1 Эфир и 1 Wei, а в массиве 1 Эфир и 2 Wei.

При этой, учитывая, что длина массива на момент получения транзакций уже будет равна "1", и мы, как бы отправляя 1 Wei, пытаемся перезаписать это значение, то благодаря push, который увеличивает длину массива на 1, ошибки не будет. И длина массива всегда будет плюсоваться.

Представляю, что из моего текста это тоже звучит мало понятно, поэтому вот вам две ссылки на английском языке, которые помогут разобраться с этой задачей. Первая и вторая. Но придется тоже посидеть.

Для решение этой задача нам нужно будет отправить несколько транзакций, постепенно увеличивая количество отправляемых Wei на +1, и переписывая overflow timestamp  с "2**256-86400" до "0" до "86400", и так по кругу.

Потом мы сможем вызвать withdraw() и забрать некоторое количество Wei и Эфир.

Теперь понимаю, почему эта задача является самой дорогостоящей среди заданий CTE.

#capture #cte
  • 👍 1
More from @solidityset
  1. Oct 8, 2026Промо видео для SaaS и других ваших проектов Хочу поделить с вами одним из своих открытий…
  2. Oct 8, 2026video post
  3. Oct 2, 2026Вторая сложность — как доказать, что установилось именно опубликованное. В первом варианте…
  4. Oct 2, 2026Задача с полуоткрытым кодом На днях, в процессе создания одного приложения, столкнулся с и…
  5. Sep 22, 2026Какой язык программирования учить сейчас? На днях в Твиттере увидел небольшой пост о разви…
  6. Sep 18, 2026Интересная модель Jev Буквально пару дней назад в Твиттере многие начали обсуждение новой…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →