{"id":36,"date":"2021-11-06T19:25:42","date_gmt":"2021-11-06T18:25:42","guid":{"rendered":"https:\/\/abch-330809.firebaseapp.com\/blog\/?p=36"},"modified":"2022-01-26T22:21:05","modified_gmt":"2022-01-26T21:21:05","slug":"possible-vulnerability-in-gsn-implementation","status":"publish","type":"post","link":"https:\/\/ackee.xyz\/blog\/possible-vulnerability-in-gsn-implementation\/","title":{"rendered":"Possible vulnerability in GSN implementation"},"content":{"rendered":"<p class=\"part\" title=\"\" data-startline=\"6\" data-endline=\"6\" data-position=\"83\" data-size=\"0\" data-original-title=\"\" aria-describedby=\"popover958132\"><span data-position=\"84\" data-size=\"25\">The Gas Station Network (<\/span><a href=\"https:\/\/github.com\/opengsn\/gsn\" target=\"_blank\" rel=\"noopener\"><span data-position=\"109\" data-size=\"3\">GSN<\/span><\/a><span data-position=\"145\" data-size=\"128\">) helps to execute gas-free transactions, but an incorrect implementation of its functionalities could make any project extremely exploitable. We describe an issue we addressed at <a href=\"https:\/\/ackee.xyz\">Ackee Blockchain<\/a> during a security assessment of one of our clients.<\/span><\/p>\n<p title=\"\" data-startline=\"6\" data-endline=\"6\" data-position=\"83\" data-size=\"0\" data-original-title=\"\" aria-describedby=\"popover958132\"><!--more--><\/p>\n<p class=\"part\" data-startline=\"8\" data-endline=\"8\" data-position=\"276\" data-size=\"0\"><span data-position=\"276\" data-size=\"129\">If we look at GSN documentation a GSN compatible project needs to replace all occurrences of <\/span><code class=\"codehl\" data-position=\"406\" data-size=\"10\">msg.sender<\/code><span data-position=\"417\" data-size=\"6\">\u00a0with\u00a0<\/span><code class=\"codehl\" data-position=\"424\" data-size=\"10\">_msgSender<\/code><span data-position=\"435\" data-size=\"10\">\u00a0function.<\/span><\/p>\n<p class=\"part\" data-startline=\"10\" data-endline=\"10\" data-position=\"448\" data-size=\"0\"><a href=\"https:\/\/docs.opengsn.org\/contracts\/#receiving-a-relayed-call\" target=\"_blank\" rel=\"noopener\"><span data-position=\"448\" data-size=\"60\">https:\/\/docs.opengsn.org\/contracts\/#receiving-a-relayed-call<\/span><\/a><\/p>\n<p class=\"part\" data-startline=\"12\" data-endline=\"12\" data-position=\"510\" data-size=\"0\"><span data-position=\"510\" data-size=\"62\">This step is generating a possible risk because with Solidity structure (<\/span><code class=\"codehl\" data-position=\"573\" data-size=\"10\">msg.sender<\/code><span data-position=\"584\" data-size=\"118\">) every developer can rely on its value. But it&#8217;s replaced by a custom function (<code class=\"codehl\" data-position=\"573\" data-size=\"10\">_msgsender()<\/code>) with an arbitrary body (depends on implementation) where we can&#8217;t say the same.<\/span><\/p>\n<pre class=\"part\" data-startline=\"15\" data-endline=\"28\" data-position=\"705\"><code class=\"codehl\">    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;\/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;_msgSender&lt;\/span&gt;() &lt;span class=&quot;hljs-title&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;internal&lt;\/span&gt;&lt;\/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;\/span&gt;&lt;\/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;virtual&lt;\/span&gt;&lt;\/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;view&lt;\/span&gt;&lt;\/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;returns&lt;\/span&gt;&lt;\/span&gt; (&lt;span class=&quot;hljs-params&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;address&lt;\/span&gt; ret&lt;\/span&gt;) &lt;\/span&gt;{\n        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;\/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;msg&lt;\/span&gt;.&lt;span class=&quot;hljs-built_in&quot;&gt;data&lt;\/span&gt;.&lt;span class=&quot;hljs-built_in&quot;&gt;length&lt;\/span&gt; &gt;= &lt;span class=&quot;hljs-number&quot;&gt;20&lt;\/span&gt; &amp;&amp; isTrustedForwarder(&lt;span class=&quot;hljs-built_in&quot;&gt;msg&lt;\/span&gt;.&lt;span class=&quot;hljs-built_in&quot;&gt;sender&lt;\/span&gt;)) {\n            &lt;span class=&quot;hljs-comment&quot;&gt;\/\/ At this point we know that the sender is a trusted forwarder,&lt;\/span&gt;\n            &lt;span class=&quot;hljs-comment&quot;&gt;\/\/ so we trust that the last bytes of msg.data are the verified sender address.&lt;\/span&gt;\n            &lt;span class=&quot;hljs-comment&quot;&gt;\/\/ extract sender address from the end of msg.data&lt;\/span&gt;\n            &lt;span class=&quot;hljs-keyword&quot;&gt;assembly&lt;\/span&gt; {\n                ret := &lt;span class=&quot;hljs-built_in&quot;&gt;shr&lt;\/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;96&lt;\/span&gt;,&lt;span class=&quot;hljs-built_in&quot;&gt;calldataload&lt;\/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;sub&lt;\/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;calldatasize&lt;\/span&gt;(),&lt;span class=&quot;hljs-number&quot;&gt;20&lt;\/span&gt;)))\n            }\n        } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;\/span&gt; {\n            ret = &lt;span class=&quot;hljs-built_in&quot;&gt;msg&lt;\/span&gt;.&lt;span class=&quot;hljs-built_in&quot;&gt;sender&lt;\/span&gt;;\n        }\n    }\n<\/code><\/pre>\n<p class=\"part\" data-startline=\"30\" data-endline=\"30\" data-position=\"1274\" data-size=\"0\"><a href=\"https:\/\/github.com\/opengsn\/gsn\/blob\/f9d5b4a3239f226a7d70d2be3f230ccb21d50763\/packages\/contracts\/src\/BaseRelayRecipient.sol\" target=\"_blank\" rel=\"noopener\"><span data-position=\"1274\" data-size=\"122\">https:\/\/github.com\/opengsn\/gsn\/blob\/f9d5b4a3239f226a7d70d2be3f230ccb21d50763\/packages\/contracts\/src\/BaseRelayRecipient.sol<\/span><\/a><\/p>\n<p class=\"part\" data-startline=\"32\" data-endline=\"32\" data-position=\"1398\" data-size=\"0\"><span data-position=\"1398\" data-size=\"35\">As can be seen on code snippet, if:<\/span><\/p>\n<ul class=\"part\" data-startline=\"33\" data-endline=\"35\">\n<li class=\"\" data-startline=\"33\" data-endline=\"33\" data-position=\"1436\" data-size=\"0\"><span data-position=\"1436\" data-size=\"12\">transaction\u00a0<\/span><code class=\"codehl\" data-position=\"1449\" data-size=\"8\">msg.data<\/code><span data-position=\"1458\" data-size=\"31\">\u00a0length is higher or equal 20,\u00a0<\/span><img decoding=\"async\" class=\"emoji\" src=\"https:\/\/assets.hackmd.io\/build\/emojify.js\/dist\/images\/basic\/heavy_check_mark.png\" alt=\":heavy_check_mark:\" data-position=\"1489\" data-size=\"18\" \/><\/li>\n<li class=\"\" data-startline=\"34\" data-endline=\"35\" data-position=\"1510\" data-size=\"0\"><span data-position=\"1510\" data-size=\"4\">and\u00a0<\/span><code class=\"codehl\" data-position=\"1515\" data-size=\"10\">msg.sender<\/code><span data-position=\"1526\" data-size=\"25\">\u00a0is a trusted forwarder,\u00a0<\/span><img decoding=\"async\" class=\"emoji\" src=\"https:\/\/assets.hackmd.io\/build\/emojify.js\/dist\/images\/basic\/question.png\" alt=\":question:\" data-position=\"1551\" data-size=\"10\" \/><\/li>\n<\/ul>\n<p class=\"part\" data-startline=\"36\" data-endline=\"36\" data-position=\"1563\" data-size=\"0\"><span data-position=\"1563\" data-size=\"36\">it will return the last 20 bytes of\u00a0<\/span><code class=\"codehl\" data-position=\"1600\" data-size=\"8\">msg.data<\/code><span data-position=\"1609\" data-size=\"1\">.<\/span><\/p>\n<p class=\"part\" data-startline=\"38\" data-endline=\"38\" data-position=\"1612\" data-size=\"0\"><span data-position=\"1612\" data-size=\"32\">But there can be literally anything!<\/span><\/p>\n<p class=\"part\" data-startline=\"40\" data-endline=\"40\" data-position=\"1646\" data-size=\"0\"><span data-position=\"1646\" data-size=\"77\">We\u2019ve discovered this during an audit where the project had <\/span><code class=\"codehl\" data-position=\"1724\" data-size=\"19\">setTrustedForwarder<\/code><span data-position=\"1744\" data-size=\"81\"> function set as a public, so anyone could have set up anyone as a trusted forwarder.<\/span><\/p>\n<p class=\"part\" data-startline=\"42\" data-endline=\"42\" data-position=\"1828\" data-size=\"0\"><span data-position=\"1828\" data-size=\"59\">We have created an exploit that was based on altering the <\/span><code class=\"codehl\" data-position=\"1888\" data-size=\"8\">msg.data<\/code><span data-position=\"1897\" data-size=\"60\">. Especially, appending the victim\u2019s address to the end, so\u00a0<\/span><code class=\"codehl\" data-position=\"1958\" data-size=\"10\">_msgSender<\/code><span data-position=\"1969\" data-size=\"60\"> would return a different address than is the original caller.<\/span><\/p>\n<pre class=\"part\" data-startline=\"44\" data-endline=\"53\" data-position=\"2031\"><code class=\"codehl\">&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;\/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;executeAttack&lt;\/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;address&lt;\/span&gt; VICTIM_ADDRESS&lt;\/span&gt;) &lt;span class=&quot;hljs-title&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;\/span&gt;&lt;\/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;returns&lt;\/span&gt;&lt;\/span&gt; (&lt;span class=&quot;hljs-params&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;bool&lt;\/span&gt; success, &lt;span class=&quot;hljs-keyword&quot;&gt;bytes&lt;\/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;memory&lt;\/span&gt; returndata&lt;\/span&gt;) &lt;\/span&gt;{\n\n    ...\n\n    &lt;span class=&quot;hljs-keyword&quot;&gt;bytes&lt;\/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;memory&lt;\/span&gt; data_extension = &lt;span class=&quot;hljs-built_in&quot;&gt;abi&lt;\/span&gt;.&lt;span class=&quot;hljs-built_in&quot;&gt;encodePacked&lt;\/span&gt;(VICTIM_ADDRESS);\n    &lt;span class=&quot;hljs-keyword&quot;&gt;bytes&lt;\/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;memory&lt;\/span&gt; data = &lt;span class=&quot;hljs-built_in&quot;&gt;abi&lt;\/span&gt;.&lt;span class=&quot;hljs-built_in&quot;&gt;encodePacked&lt;\/span&gt;(data_base, data_extension);\n    (success, returndata) = &lt;span class=&quot;hljs-keyword&quot;&gt;address&lt;\/span&gt;(mainContract).&lt;span class=&quot;hljs-built_in&quot;&gt;call&lt;\/span&gt;(data);\n}\n<\/code><\/pre>\n<p class=\"part\" data-startline=\"55\" data-endline=\"55\" data-position=\"2363\" data-size=\"0\"><span data-position=\"2363\" data-size=\"172\">This exploit allowed us to act as any user we wanted and additionally thanks to the architecture of withdrawal functions of the project also stealing funds from any user of the contract.<\/span><\/p>\n<p class=\"part\" data-startline=\"57\" data-endline=\"57\" data-position=\"2537\" data-size=\"0\"><span data-position=\"2537\" data-size=\"69\">The issue was immediately reported and hotfixed by the team by using\u00a0<\/span><code class=\"codehl\" data-position=\"2607\" data-size=\"9\">onlyOwner<\/code><span data-position=\"2617\" data-size=\"13\">\u00a0modifier on\u00a0<\/span><code class=\"codehl\" data-position=\"2631\" data-size=\"21\">setTrustedForwarder<\/code><span data-position=\"2653\" data-size=\"10\">\u00a0function.<\/span><\/p>\n<p class=\"part\" data-startline=\"59\" data-endline=\"59\" data-position=\"2665\" data-size=\"0\"><span data-position=\"2665\" data-size=\"13\">Is it enough?<\/span><\/p>\n<p class=\"part\" data-startline=\"61\" data-endline=\"61\" data-position=\"2680\" data-size=\"0\"><span data-position=\"2680\" data-size=\"252\">The vulnerability still exists. The owner of the contract could be an initiator of the attack (consciously or by mistake), so there is still some risk. Even the owner shouldn\u2019t have such a big power, otherwise it should be announced to contract users.<\/span><\/p>\n<p class=\"part\" data-startline=\"63\" data-endline=\"63\" data-position=\"2934\" data-size=\"0\"><span data-position=\"2934\" data-size=\"28\">To sum up, actual design of\u00a0<\/span><code class=\"codehl\" data-position=\"2963\" data-size=\"10\">_msgSender<\/code><span data-position=\"2974\" data-size=\"149\">\u00a0function from GSN is quite unhappy, because even when it is well implemented, it can in some cases significantly affect trust model of the contract.<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The Gas Station Network (GSN) helps to execute gas-free transactions, but an incorrect implementation of its functionalities could make any project extremely exploitable. We describe an issue we addressed at Ackee Blockchain during a security assessment of one of our clients.<\/p>\n","protected":false},"author":6,"featured_media":42,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[10],"tags":[14,12,11,13],"class_list":["post-36","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ethereum","tag-exploit","tag-gas-station-network","tag-gsn","tag-vulnerability"],"aioseo_notices":[],"featured_image_src":"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2021\/11\/ABCH-Hack-600x400.png","featured_image_src_square":"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2021\/11\/ABCH-Hack-600x518.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\/36","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=36"}],"version-history":[{"count":0,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts\/36\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/media\/42"}],"wp:attachment":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/media?parent=36"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/categories?post=36"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/tags?post=36"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}