{"id":555,"date":"2023-08-31T10:00:39","date_gmt":"2023-08-31T08:00:39","guid":{"rendered":"https:\/\/ackeeblockchain.com\/blog\/?p=555"},"modified":"2024-07-04T13:37:44","modified_gmt":"2024-07-04T11:37:44","slug":"zunami-hack-post-mortem","status":"publish","type":"post","link":"https:\/\/ackee.xyz\/blog\/zunami-hack-post-mortem\/","title":{"rendered":"Zunami hack post-mortem: what happened?"},"content":{"rendered":"<p><em>Note: Ackee audited an earlier version of the protocol before the attacked MimCurveStakeDAO strategy was added.<\/em><\/p>\n<h2><span style=\"font-weight: 400;\">Exploit cause<\/span><\/h2>\n<p><span style=\"font-weight: 400;\">The exploit consisted of two hacks, both of which involved <\/span><a href=\"https:\/\/github.com\/ZunamiProtocol\/ZunamiStable\/blob\/7d6a1b0238f37aec016134abf3e0939130641dc7\/contracts\/ElasticERC20.sol#L105-L108\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">price caching vulnerability<\/span><\/a><span style=\"font-weight: 400;\"> The first target was Zunami ETH (zETH) and the second was Zunami Stable (UZD). The first attack drained <\/span><i><span style=\"font-weight: 400;\">only<\/span><\/i><span style=\"font-weight: 400;\"> 26 WETH, unlike the second one with whopping 1178 WETH.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">The root cause was the price manipulation using the <\/span><a href=\"https:\/\/github.com\/ZunamiProtocol\/ZunamiProtocol\/commit\/6df0ae533a718a34df70984d745cc2d70fb7172d\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">MIMCurveStakeDao<\/span><\/a><span style=\"font-weight: 400;\"> strategy then caching the inflated price for the whole block (suitable for flash loans) for UZD and then performing previous operations in reverse order to take profit of the inflated price.<\/span><\/p>\n<h3><span style=\"font-weight: 400;\">Price caching<\/span><\/h3>\n<p><span style=\"font-weight: 400;\">The caching of the liquidity pool (LP) price in UZD was partially implemented in the 1.0 version that was <\/span><a href=\"https:\/\/ackeeblockchain.com\/blog\/zunami-uzd-audit-summary\/\"><span style=\"font-weight: 400;\">audited<\/span><\/a><span style=\"font-weight: 400;\"> by Ackee Blockchain. However, it wasn\u2019t used globally and functions like <code class=\"codehl\">balanceOf<\/code> were doing multiple costly calls (LP price calculation from strategies) instead of caching.<\/span><\/p>\n<p><script src=\"https:\/\/gist.github.com\/encryptedbae\/8a3f659b06bc53754146cbe42b888894.js\"><\/script><\/p>\n<p><span style=\"font-weight: 400;\">The caching was extended to functions such as <code class=\"codehl\">totalSupply<\/code>, <code class=\"codehl\">balanceOf<\/code> and <code class=\"codehl\">allowance<\/code> later in the <\/span><a href=\"https:\/\/github.com\/ZunamiProtocol\/ZunamiStable\/commit\/27f37bb115fc6f7216e9168a842146b71e0c0a0a#diff-db89ee74237c5171ece42feeef0292e13586db74806447878e7902020fe1da39R105-R108\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">UZD version 1.1<\/span><\/a><span style=\"font-weight: 400;\">. The caching was adjusted in the following way:<\/span><\/p>\n<p style=\"text-align: center;\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-565 aligncenter\" src=\"https:\/\/abchprod.wpengine.com\/wp-content\/uploads\/2023\/08\/image-17.png\" alt=\"\" width=\"1791\" height=\"439\" srcset=\"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/image-17.png 1791w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/image-17-300x74.png 300w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/image-17-1024x251.png 1024w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/image-17-768x188.png 768w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/image-17-1536x376.png 1536w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/image-17-370x91.png 370w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/image-17-760x186.png 760w\" sizes=\"auto, (max-width: 1791px) 100vw, 1791px\" \/><a href=\"https:\/\/github.com\/ZunamiProtocol\/ZunamiStable\/commit\/27f37bb115fc6f7216e9168a842146b71e0c0a0a\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">Source<\/span><\/a><span style=\"font-weight: 400;\">\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This allowed calling an inflated price from other contracts with the <code class=\"codehl\">balanceOf<\/code>\u00a0function.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">The version 1.1 was launched without any audit. It was later audited by HashEx in October 29, 2023, for the v1.2 launch, but according to the<\/span> <a href=\"https:\/\/hashex.org\/audits\/zunami-protocol-uzd\/\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">audit report<\/span><\/a><span style=\"font-weight: 400;\">, the attack vector using the cashed functions was not discovered.<\/span><\/p>\n<h3><span style=\"font-weight: 400;\">MIMCurveStakeDao strategy<\/span><\/h3>\n<p><span style=\"font-weight: 400;\">The strategy was introduced in commit <\/span><a href=\"https:\/\/github.com\/ZunamiProtocol\/ZunamiProtocol\/commit\/6df0ae533a718a34df70984d745cc2d70fb7172d\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">6df0ae5<\/span><\/a><span style=\"font-weight: 400;\">. The attacker could change LP price calculation by donating SDT tokens to the strategy since the calculation was dependent on its price and balance in the strategy. This strategy was audited prior to the launch by HashEx (check out this <\/span><a href=\"https:\/\/github.com\/ZunamiProtocol\/ZunamiProtocol\/blob\/main\/audit\/HashEx%20-%20Zunami%20Protocol.pdf\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">audit report<\/span><\/a><span style=\"font-weight: 400;\">) but the exploit possibility was not discovered.<\/span><\/p>\n<h3><span style=\"font-weight: 400;\">The Attack<\/span><\/h3>\n<p><span style=\"font-weight: 400;\">The attack happened on August 13 and can be viewed here: <\/span><a href=\"https:\/\/explorer.phalcon.xyz\/tx\/eth\/0x0788ba222970c7c68a738b0e08fb197e669e61f9b226ceec4cab9b85abe8cceb\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">https:\/\/explorer.phalcon.xyz\/tx\/eth\/0x0788ba222970c7c68a738b0e08fb197e669e61f9b226ceec4cab9b85abe8cceb<\/span><\/a><\/p>\n<p><span style=\"font-weight: 400;\">Or you can check the <\/span><a href=\"https:\/\/github.com\/SunWeb3Sec\/DeFiHackLabs\/blob\/main\/src\/test\/Zunami_exp.sol\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">PoC<\/span><\/a><span style=\"font-weight: 400;\"> of the attack (good work DeFiHackLabs!).\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">We hope this post-mortem analysis was helpful and may contribute to making web3 a safer space without hacks and exploits.\u00a0<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Note: Ackee audited an earlier version of the protocol before the attacked MimCurveStakeDAO strategy was added. Exploit cause The exploit consisted of two hacks, both of which involved price caching vulnerability The first target was Zunami ETH (zETH) and the second was Zunami Stable (UZD). The first attack drained only 26 WETH, unlike the second one with whopping 1178 WETH. The root&hellip;<\/p>\n","protected":false},"author":6,"featured_media":566,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[61,10,85,84],"tags":[14,86],"class_list":["post-555","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-education","category-ethereum","category-exploits","category-hacks","tag-exploit","tag-hack"],"aioseo_notices":[],"featured_image_src":"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/Zunami-600x400.png","featured_image_src_square":"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/Zunami-600x600.png","author_info":{"display_name":"Jan Kalivoda","author_link":"https:\/\/ackee.xyz\/blog\/author\/jan-kalivoda\/"},"_links":{"self":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts\/555","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/comments?post=555"}],"version-history":[{"count":0,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts\/555\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/media\/566"}],"wp:attachment":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/media?parent=555"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/categories?post=555"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/tags?post=555"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}