{"id":446,"date":"2023-01-30T11:43:36","date_gmt":"2023-01-30T09:43:36","guid":{"rendered":"https:\/\/ackeeblockchain.com\/blog\/?p=446"},"modified":"2023-01-31T14:49:58","modified_gmt":"2023-01-31T12:49:58","slug":"2022-solana-hacks-explained-cashio","status":"publish","type":"post","link":"https:\/\/ackee.xyz\/blog\/2022-solana-hacks-explained-cashio\/","title":{"rendered":"2022 Solana Hacks Explained: Cashio"},"content":{"rendered":"<p><span style=\"font-weight: 400;\"><strong><a href=\"https:\/\/github.com\/cashioapp\/cashio\">Cashio<\/a><\/strong> was <strong>a decentralised stablecoin<\/strong> fully <strong>backed<\/strong> by interest-bearing<strong> Saber USD liquidity provider tokens<\/strong>.<\/span><\/p>\n<p><strong>What happened <\/strong><\/p>\n<p><span style=\"font-weight: 400;\">Like with the <a href=\"https:\/\/ackeeblockchain.com\/blog\/2022-solana-hacks-explained-wormhole\/\"><strong>Wormhole hack<\/strong><\/a>, the attacker used <strong>fake accounts<\/strong> to <strong>mint<\/strong> Cashio&#8217;s <strong>CASH<\/strong> tokens and <strong>stole<\/strong> over <strong>$52M<\/strong>. It is worth mentioning that Cashio <strong>was never audited<\/strong> <strong>by a third party.<\/strong><\/span><\/p>\n<p><span style=\"font-weight: 400;\">Due to a <strong>collateral token validation flaw<\/strong>, the attacker minted <strong>2 billion CASH<\/strong> tokens using a <strong>faked<\/strong> worthless <strong>token<\/strong> as collateral. He then <strong>burnt<\/strong> part of the tokens for the Saber USDT-USDC LP tokens that he <strong>swapped<\/strong> for <strong>$16.4<\/strong> USDC and<strong> $10.8<\/strong> USDT, respectively. The remaining CASH tokens were <strong>swapped out<\/strong> for <strong>$8.6M<\/strong> <strong>UST<\/strong> and <strong>$17M USDC<\/strong> through Saber. What&#8217;s curious is that the hacker embedded a <a href=\"https:\/\/etherscan.io\/tx\/0xa8394d2e55042f84d096c72dd1075fa2648faf88e248c7992273b4d50a6a647b\"><strong>hidden message<\/strong><\/a> in the transaction that, after viewing the input data as UTF-8 says:<\/span><\/p>\n<p style=\"text-align: center;\"><span style=\"font-weight: 400;\"> <em>&#8220;Accounts with less than 100k have been returned. All other money will be donated to charity&#8221;.<\/em><\/span><\/p>\n<p><b>Exploit Details<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Cashio has two programs: <strong>Bankman<\/strong> and <strong>Brrr<\/strong>. The Bank manager, or <strong>Bankman<\/strong> for short, <strong>keeps track of the collateral<\/strong> that is allowed to be <strong>used as a backing for the $CASH token<\/strong>. The <strong>Brrr<\/strong> program <strong>handles<\/strong> <strong>the printing and burning<\/strong> of <strong>$CASH<\/strong>, using Saber LP Arrows as collateral.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">In order to <strong>print $CASH<\/strong>, the <strong>brrr<\/strong> program performs <strong>checks that the exploiter could circumvent.<\/strong> First of all, the <strong>supplied bank account<\/strong> must <strong>correspond to the bank of the collateral used<\/strong>.<\/span><\/p>\n<pre><span style=\"font-weight: 400;\">impl&lt;'info&gt; Validate&lt;'info&gt; for BrrrCommon&lt;'info&gt; {<\/span>\r\n\r\n<span style=\"font-weight: 400;\"> \u00a0\u00a0\u00a0fn validate(&amp;self) -&gt; Result&lt;()&gt; {<\/span><span style=\"font-weight: 400;\">\r\n\r\n<strong>\/\/these checks passed due to fake bank account supplied\r\n<\/strong><\/span><\/pre>\n<pre><span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0assert_keys_eq!(self.bank, self.collateral.bank);<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0assert_keys_eq!(self.bank.crate_mint, self.crate_mint);<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0assert_keys_eq!(self.crate_token, self.crate_collateral_tokens.owner);<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0assert_keys_eq!(self.crate_mint, self.crate_token.mint);<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0assert_keys_eq!(self.crate_collateral_tokens.mint, self.collateral.mint);<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ saber swap<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0self.saber_swap.validate()?;<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0assert_keys_eq!(self.collateral.mint, self.saber_swap.arrow.mint);<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Ok(())<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0}<\/span>\r\n\r\n<span style=\"font-weight: 400;\">}<\/span><\/pre>\n<p><span style=\"font-weight: 400;\">To pass the <strong>bank verification<\/strong>, the attacker simply <strong>created a new bank<\/strong> with the <strong>same mint<\/strong> as his <strong>worthless token mint.<\/strong><\/span><\/p>\n<p><span style=\"font-weight: 400;\">Next, the Saber swap accounts are verified; however, the verification <strong>missed the critical check<\/strong> if the <\/span><\/p>\n<pre><span style=\"font-weight: 400;\">saber_swap.mint <\/span><\/pre>\n<p><span style=\"font-weight: 400;\">actually <strong>matches<\/strong> the expected mint.<\/span><\/p>\n<pre><span style=\"font-weight: 400;\">impl&lt;'info&gt; Validate&lt;'info&gt; for SaberSwapAccounts&lt;'info&gt; {<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0fn validate(&amp;self) -&gt; Result&lt;()&gt; {<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ missing verification that the saber_swap.mint is correct<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0assert_keys_eq!(self.arrow.vendor_miner.mint, self.pool_mint);<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0assert_keys_eq!(self.saber_swap.pool_mint, self.pool_mint);<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0assert_keys_eq!(self.saber_swap.token_a.reserves, self.reserve_a);<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0assert_keys_eq!(self.saber_swap.token_b.reserves, self.reserve_b);<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Ok(())<\/span>\r\n\r\n<span style=\"font-weight: 400;\">\u00a0\u00a0\u00a0\u00a0}<\/span>\r\n\r\n<span style=\"font-weight: 400;\">}<\/span><\/pre>\n<p><span style=\"font-weight: 400;\">Therefore, the exploiter <strong>supplied<\/strong> his <strong>fake<\/strong> worthless <strong>token<\/strong> <strong>as collateral<\/strong> and <strong>passed the checks<\/strong> proving that the collateral token corresponds to the expected token from the bank. There was <strong>no check<\/strong> to ensure that the token was indeed a <strong>Saber Arrow<\/strong> token leading to a successful transaction.<\/span><\/p>\n<p><b>In simple words,<\/b><span style=\"font-weight: 400;\"> the exploiter had to perform multiple steps and supply the <strong>worthless tokens<\/strong> he created earlier as <strong>collateral<\/strong> to mint 2 billion CASH tokens. The reason why he managed to do this boils down to the <strong>flawed verification of input accounts.<\/strong><\/span><\/p>\n<p><a href=\"https:\/\/twitter.com\/0xavarek\/status\/1506812700516503554\"><strong>Reference<\/strong><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Cashio was a decentralised stablecoin fully backed by interest-bearing Saber USD liquidity provider tokens. What happened Like with the Wormhole hack, the attacker used fake accounts to mint Cashio&#8217;s CASH tokens and stole over $52M. It is worth mentioning that Cashio was never audited by a third party. Due to a collateral token validation flaw, the attacker minted 2 billion CASH tokens&hellip;<\/p>\n","protected":false},"author":15,"featured_media":447,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[84,5],"tags":[86,6,19],"class_list":["post-446","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-hacks","category-solana","tag-hack","tag-solana","tag-solana-security"],"aioseo_notices":[],"featured_image_src":"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/01\/Cashio-600x400.png","featured_image_src_square":"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/01\/Cashio-600x600.png","author_info":{"display_name":"Aleksandra Yudina","author_link":"https:\/\/ackee.xyz\/blog\/author\/aleksandra-yudina\/"},"_links":{"self":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts\/446","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\/15"}],"replies":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/comments?post=446"}],"version-history":[{"count":0,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts\/446\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/media\/447"}],"wp:attachment":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/media?parent=446"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/categories?post=446"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/tags?post=446"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}