14a7d8405SKristof Provost#!/usr/bin/env python3 265d553b0SKristof Provost# 3*4d846d26SWarner Losh# SPDX-License-Identifier: BSD-2-Clause 465d553b0SKristof Provost# 565d553b0SKristof Provost# Copyright (c) 2019 Kristof Provost <kp@FreeBSD.org> 665d553b0SKristof Provost# 765d553b0SKristof Provost# Redistribution and use in source and binary forms, with or without 865d553b0SKristof Provost# modification, are permitted provided that the following conditions 965d553b0SKristof Provost# are met: 1065d553b0SKristof Provost# 1. Redistributions of source code must retain the above copyright 1165d553b0SKristof Provost# notice, this list of conditions and the following disclaimer. 1265d553b0SKristof Provost# 2. Redistributions in binary form must reproduce the above copyright 1365d553b0SKristof Provost# notice, this list of conditions and the following disclaimer in the 1465d553b0SKristof Provost# documentation and/or other materials provided with the distribution. 1565d553b0SKristof Provost# 1665d553b0SKristof Provost# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1765d553b0SKristof Provost# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1865d553b0SKristof Provost# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1965d553b0SKristof Provost# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2065d553b0SKristof Provost# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2165d553b0SKristof Provost# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2265d553b0SKristof Provost# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2365d553b0SKristof Provost# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2465d553b0SKristof Provost# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2565d553b0SKristof Provost# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2665d553b0SKristof Provost# SUCH DAMAGE. 277de4bd92SKristof Provost 287de4bd92SKristof Provostimport argparse 29a26e895fSKristof Provostimport logging 30a26e895fSKristof Provostlogging.getLogger("scapy").setLevel(logging.CRITICAL) 317de4bd92SKristof Provostimport scapy.all as sp 327de4bd92SKristof Provostimport sys 337de4bd92SKristof Provostfrom sniffer import Sniffer 347de4bd92SKristof Provost 357de4bd92SKristof Provostdef check_icmp_error(args, packet): 367de4bd92SKristof Provost ip = packet.getlayer(sp.IP) 377de4bd92SKristof Provost if not ip: 387de4bd92SKristof Provost return False 397de4bd92SKristof Provost if ip.dst != args.to[0]: 407de4bd92SKristof Provost return False 417de4bd92SKristof Provost 427de4bd92SKristof Provost icmp = packet.getlayer(sp.ICMP) 437de4bd92SKristof Provost if not icmp: 447de4bd92SKristof Provost return False 457de4bd92SKristof Provost if icmp.type != 3 or icmp.code != 3: 467de4bd92SKristof Provost return False 477de4bd92SKristof Provost 487de4bd92SKristof Provost return True 497de4bd92SKristof Provost 507de4bd92SKristof Provostdef main(): 517de4bd92SKristof Provost parser = argparse.ArgumentParser("CVE-2019-icmp.py", 527de4bd92SKristof Provost description="CVE-2019-icmp test tool") 537de4bd92SKristof Provost parser.add_argument('--sendif', nargs=1, 547de4bd92SKristof Provost required=True, 557de4bd92SKristof Provost help='The interface through which the packet will be sent') 567de4bd92SKristof Provost parser.add_argument('--recvif', nargs=1, 577de4bd92SKristof Provost required=True, 587de4bd92SKristof Provost help='The interface on which to check for the packet') 597de4bd92SKristof Provost parser.add_argument('--src', nargs=1, 607de4bd92SKristof Provost required=True, 617de4bd92SKristof Provost help='The source IP address') 627de4bd92SKristof Provost parser.add_argument('--to', nargs=1, 637de4bd92SKristof Provost required=True, 647de4bd92SKristof Provost help='The destination IP address') 657de4bd92SKristof Provost 667de4bd92SKristof Provost args = parser.parse_args() 677de4bd92SKristof Provost 687de4bd92SKristof Provost # Send the allowed packet to establish state 697de4bd92SKristof Provost udp = sp.Ether() / \ 707de4bd92SKristof Provost sp.IP(src=args.src[0], dst=args.to[0]) / \ 717de4bd92SKristof Provost sp.UDP(dport=53, sport=1234) 727de4bd92SKristof Provost sp.sendp(udp, iface=args.sendif[0], verbose=False) 737de4bd92SKristof Provost 747de4bd92SKristof Provost # Start sniffing on recvif 75a39dedebSKajetan Staszkiewicz sniffer = Sniffer(args, check_icmp_error, args.recvif[0]) 767de4bd92SKristof Provost 777de4bd92SKristof Provost # Send the bad error packet 787de4bd92SKristof Provost icmp_reachable = sp.Ether() / \ 797de4bd92SKristof Provost sp.IP(src=args.src[0], dst=args.to[0]) / \ 807de4bd92SKristof Provost sp.ICMP(type=3, code=3) / \ 817de4bd92SKristof Provost sp.IP(src="4.3.2.1", dst="1.2.3.4") / \ 827de4bd92SKristof Provost sp.UDP(dport=53, sport=1234) 837de4bd92SKristof Provost sp.sendp(icmp_reachable, iface=args.sendif[0], verbose=False) 847de4bd92SKristof Provost 857de4bd92SKristof Provost sniffer.join() 86a39dedebSKajetan Staszkiewicz if sniffer.correctPackets: 877de4bd92SKristof Provost sys.exit(1) 887de4bd92SKristof Provost 897de4bd92SKristof Provost sys.exit(0) 907de4bd92SKristof Provost 917de4bd92SKristof Provostif __name__ == '__main__': 927de4bd92SKristof Provost main() 93