├── README.md └── bypass.py /README.md: -------------------------------------------------------------------------------- 1 | # ipv4Bypass 2 | **Using IPv6 to Bypass Security** 3 | 4 | **Dependences (tested on Kali Linux)** 5 | - python2.7 6 | - nmap 7 | - arp-scan (apt-get install arp-scan) 8 | - python-nmap (https://pypi.org/project/python-nmap/) 9 | - termcolor (https://pypi.org/project/termcolor/) 10 | 11 | **Example on how to run the tool** 12 | ``` 13 | $ python bypass.py -i eth0 -r 10.5.192.0/24 14 | 15 | $ python bypass.py -h 16 | Usage: bypass.py [options] 17 | 18 | Options: 19 | -h, --help show this help message and exit 20 | -i INTERFACENO Network interface (e.g. eth0) 21 | -r IPRANGE Local network IP range (e.g. 192.168.0.1/24) 22 | 23 | ``` 24 | 25 | **Screenshot of tool** 26 | ![Screenshot of tool](https://milo2012.files.wordpress.com/2018/06/screen-shot-2018-06-23-at-1-47-06-am.png?w=1190&h=950) 27 | 28 | **More information** 29 | See https://milo2012.wordpress.com/2018/06/22/using-ipv6-to-bypass-security-tool/ for an explanation on the technique and how the tool works. 30 | 31 | 32 | -------------------------------------------------------------------------------- /bypass.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import nmap 4 | import sys 5 | import subprocess 6 | import socket 7 | import fcntl 8 | import struct 9 | import optparse 10 | 11 | import re 12 | from termcolor import colored, cprint 13 | 14 | arpscanToolPath="/usr/sbin/arp-scan" 15 | if not os.path.exists(arpscanToolPath): 16 | print("[-] arp-scan does not exists in "+arpscanToolPath) 17 | sys.exit() 18 | 19 | nm = nmap.PortScanner() 20 | interfaceNo="" 21 | bold=True 22 | 23 | def mac_to_ipv6_linklocal(mac): 24 | edit_mac_format = mac.replace('b','') 25 | edit_mac_format = mac.replace("'",'') 26 | edit_mac_format = mac.replace(' ','') 27 | edit_mac_format = edit_mac_format.replace('.','') 28 | edit_mac_format = edit_mac_format.replace(':','') 29 | edit_mac_format = edit_mac_format.replace('-','') 30 | 31 | mac_value = int(edit_mac_format, 16) 32 | high2 = mac_value >> 32 & 0xffff ^ 0x0200 33 | high1 = mac_value >> 24 & 0xff 34 | low1 = mac_value >> 16 & 0xff 35 | low2 = mac_value & 0xffff 36 | return 'fe80::{:04x}:{:02x}ff:fe{:02x}:{:04x}'.format(high2, high1, low1, low2) 37 | 38 | def ip2bin(ip): 39 | b = "" 40 | inQuads = ip.split(".") 41 | outQuads = 4 42 | for q in inQuads: 43 | if q != "": 44 | b += dec2bin(int(q),8) 45 | outQuads -= 1 46 | while outQuads > 0: 47 | b += "00000000" 48 | outQuads -= 1 49 | return b 50 | 51 | def dec2bin(n,d=None): 52 | s = "" 53 | while n>0: 54 | if n&1: 55 | s = "1"+s 56 | else: 57 | s = "0"+s 58 | n >>= 1 59 | if d is not None: 60 | while len(s) 255): 97 | print("Error: quad "+str(q)+" wrong size.") 98 | return False 99 | # subnet is an appropriate value (1-32) 100 | if (int(subnet) < 1) or (int(subnet) > 32): 101 | print("Error: subnet "+str(subnet)+" wrong size.") 102 | return False 103 | # passed all checks -> return True 104 | return True 105 | 106 | def diff(li1, li2): 107 | return (list(set(li1) - set(li2))) 108 | 109 | def setColor(message, bold=False, color=None, onColor=None): 110 | retVal = colored(message, color=color, on_color=onColor, attrs=("bold",)) 111 | return retVal 112 | 113 | def get_hw_address(ifname): 114 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 115 | info = fcntl.ioctl(s.fileno(), 0x8927, struct.pack('256s', bytes(ifname[:15], 'utf-8'))) 116 | return ''.join(['%02x:' % b for b in info[18:24]])[:-1] 117 | 118 | def get_ip_address(ifname): 119 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 120 | return socket.inet_ntoa(fcntl.ioctl( 121 | s.fileno(), 122 | 0x8915, # SIOCGIFADDR 123 | struct.pack('256s', bytes(ifname[:15], 'utf-8')))[20:24]) 124 | 125 | def get_ip_addressv6(ifname): 126 | cmd = "ifconfig "+ifname 127 | p1 = subprocess.Popen(["ifconfig",ifname],stdout=subprocess.PIPE) 128 | 129 | cmd = "grep -i inet6" 130 | p2 = subprocess.Popen(["grep","-i","inet6"],stdin=p1.stdout,stdout=subprocess.PIPE) 131 | 132 | cmd = "awk '{print $2}'" 133 | p3 = subprocess.Popen(["awk","{print $2}"],stdin=p2.stdout,stdout=subprocess.PIPE) 134 | stdout,stderr = p3.communicate() 135 | return (stdout).strip() 136 | 137 | def ipv62mac(ipv6): 138 | ipv6=ipv6.decode('utf8').split("%")[0] 139 | # remove subnet info if given 140 | subnetIndex = ipv6.find("/") 141 | if subnetIndex != -1: 142 | ipv6 = ipv6[:subnetIndex] 143 | 144 | ipv6Parts = ipv6.split(":") 145 | macParts = [] 146 | for ipv6Part in ipv6Parts[-4:]: 147 | while len(ipv6Part) < 4: 148 | ipv6Part = "0" + ipv6Part 149 | macParts.append(ipv6Part[:2]) 150 | macParts.append(ipv6Part[-2:]) 151 | 152 | # modify parts to match MAC value 153 | macParts[0] = "%02x" % (int(macParts[0], 16) ^ 2) 154 | del macParts[4] 155 | del macParts[3] 156 | 157 | return ":".join(macParts) 158 | 159 | def runCommand(cmd): 160 | cmdList=cmd.split(" ") 161 | out = subprocess.Popen(cmdList,stdout=subprocess.PIPE,stderr=subprocess.STDOUT) 162 | stdout,stderr = out.communicate() 163 | return stdout 164 | 165 | def getRemoteMac(ip): 166 | tmpMacAddr="" 167 | a=nm.scan(hosts=ip.decode(), arguments='-sP -6') 168 | for k,v in a['scan'].items(): 169 | x=str(v['vendor']).split("': '")[0] 170 | x=x.replace("{'","") 171 | return x 172 | def scanTarget(ipv4,ipv6): 173 | tmpIPv4pPortList=[] 174 | tmpIPv6pPortList=[] 175 | #print(ipv6) 176 | #print(ipv4) 177 | a=nm.scan(hosts=ipv6, arguments='-sT -6 -T4 --top-ports 65535') 178 | for host in nm.all_hosts(): 179 | for proto in nm[host].all_protocols(): 180 | lport = nm[host][proto].keys() 181 | for port in lport: 182 | tmpIPv6pPortList.append(port) 183 | a=nm.scan(hosts=ipv4, arguments='-sT -T4 --top-ports 65535') 184 | for host in nm.all_hosts(): 185 | for proto in nm[host].all_protocols(): 186 | lport = nm[host][proto].keys() 187 | for port in lport: 188 | tmpIPv4pPortList.append(port) 189 | return tmpIPv4pPortList,tmpIPv6pPortList 190 | 191 | parser = optparse.OptionParser() 192 | parser.add_option('-i', action="store", dest="interfaceNo", help="Network interface (e.g. eth0)") 193 | parser.add_option('-r', action="store", dest="ipRange", help="Local network IP range (e.g. 192.168.0.1/24)") 194 | options, remainder = parser.parse_args() 195 | if not options.interfaceNo or not options.ipRange: 196 | print("[*] Please provide the -i and -r options") 197 | sys.exit() 198 | 199 | convertedIPv6LinkLocalList=[] 200 | 201 | interfaceNo=options.interfaceNo 202 | myMac=get_hw_address(interfaceNo) 203 | myIP=get_ip_address(interfaceNo) 204 | myIPv6=get_ip_addressv6(interfaceNo) 205 | targetIP=(options.ipRange).strip() 206 | if not validateCIDRBlock(targetIP): 207 | sys.exit() 208 | 209 | cmd="" 210 | if myIPv6.startswith(b"2620:"): 211 | cmd='ping6 -I '+myIPv6+' -c 2 ff02::1%'+interfaceNo 212 | else: 213 | cmd='ping6 -c 2 ff02::1%'+interfaceNo 214 | 215 | cmdList=cmd.split(" ") 216 | out = subprocess.Popen(cmdList,stdout=subprocess.PIPE,stderr=subprocess.STDOUT) 217 | ipv6List=[] 218 | stdout,stderr = out.communicate() 219 | tmpResultList=stdout.split(b"\n") 220 | for x in tmpResultList: 221 | if " bytes from " in x.decode(): 222 | tmpIP=x.split(b" ")[3] 223 | if tmpIP not in ipv6List and len(tmpIP)>0: 224 | ipv6List.append(tmpIP) 225 | 226 | nm.scan(targetIP,arguments='-sP -T4') 227 | ipv4List=[] 228 | for x in nm.all_hosts(): 229 | if x not in ipv4List: 230 | ipv4List.append(x) 231 | 232 | print("\n[*] Found the below IPv4 addresses") 233 | tmpIPv4List=[] 234 | tmpIPTargetList=convertCIDR(targetIP) 235 | 236 | cmd="/usr/sbin/arp-scan -I "+interfaceNo+" "+targetIP 237 | 238 | tmpResults=runCommand(cmd) 239 | tmpList1=tmpResults.split(b"\n") 240 | for x in tmpList1: 241 | for y in tmpIPTargetList: 242 | if y+"\t" in x.decode(): 243 | tmpIP=x.split(b"\t")[0] 244 | tmpMacAddr=x.split(b"\t")[1] 245 | print(tmpIP.decode()+"\t"+tmpMacAddr.decode()) 246 | tmpIPv4List.append([tmpIP.decode(),tmpMacAddr.decode()]) 247 | print("\n[*] Converting Mac Address to Link Local IPv6 addresses") 248 | for x in tmpIPv4List: 249 | tmpLocalIPv6=mac_to_ipv6_linklocal(x[1]) 250 | print(tmpLocalIPv6+"\t"+x[1].upper()+"\t"+x[0]) 251 | convertedIPv6LinkLocalList.append([tmpLocalIPv6,x[1].upper(),x[0]]) 252 | 253 | print("\n[*] Found the below IPv6 addresses") 254 | tmpIPv6List=[] 255 | for x in ipv6List: 256 | tmpMacAddr=getRemoteMac(x) 257 | if tmpMacAddr!="{}" and tmpMacAddr!=None: 258 | tmpIPv6List.append([x.decode(),tmpMacAddr]) 259 | print(x.decode()+"\t"+tmpMacAddr) 260 | else: 261 | tmpMacAddr=ipv62mac(x) 262 | tmpIPv6List.append([x,tmpMacAddr]) 263 | if tmpMacAddr==myMac: 264 | print(x.decode()+"\t"+tmpMacAddr+" [This Computer]") 265 | else: 266 | print(x.decode()+"\t"+tmpMacAddr) 267 | print("\n[*] Matching IPv4 and IPv6 addresses") 268 | tmpCompletedMacAddrList=[] 269 | tmpResultList=[] 270 | for y in tmpIPv6List: 271 | tmpFound=False 272 | for x in tmpIPv4List: 273 | if y[1].lower()==x[1].lower(): 274 | print(y[0]+"\t"+y[1]+"\t"+x[0]) 275 | tmpResultList.append([y[0],y[1],x[0]]) 276 | tmpCompletedMacAddrList.append(y[1]) 277 | tmpFound=True 278 | if tmpFound==False: 279 | if [y[0],"",""] not in tmpResultList: 280 | tmpMac=ipv62mac(y[0]) 281 | if tmpMac==myMac: 282 | print(y[0]+"\t"+tmpMac+"\t"+myIP+" [This Computer]") 283 | tmpResultList.append([y[0],tmpMac,myIP]) 284 | #tmpResultList.append([y[0],tmpMac,"[This Computer]"]) 285 | tmpCompletedMacAddrList.append(tmpMac) 286 | else: 287 | print(y[0].decode()+"\t"+tmpMac) 288 | tmpCompletedMacAddrList.append(tmpMac) 289 | tmpResultList.append([y[0],tmpMac,""]) 290 | 291 | for x in convertedIPv6LinkLocalList: 292 | if x[1] not in tmpCompletedMacAddrList: 293 | print(x[0]+"%"+interfaceNo+":"+"\t"+x[1]+"\t"+x[2]+" [Converted]") 294 | tmpResultList.append([x[0]+"%"+interfaceNo+":",x[1],x[2]]) 295 | 296 | print("\n[*] Comparing ports on IPv4 and IPv6 interfaces on hosts") 297 | for x in tmpResultList: 298 | if x[2]!=myIP: 299 | #if x[2]!="[This Computer]": 300 | 301 | tmpIPv4pPortList,tmpIPv6pPortList=scanTarget(x[2], str(x[0])) 302 | if len(tmpIPv4pPortList)!=len(tmpIPv6pPortList): 303 | if len(tmpIPv6pPortList)>len(tmpIPv4pPortList): 304 | if len(x[2])>0: 305 | diffList=diff(tmpIPv6pPortList,tmpIPv4pPortList) 306 | tmpResultList=[] 307 | for y in diffList: 308 | if y in tmpIPv6pPortList: 309 | tmpResultList.append(str(y)) 310 | if len(tmpResultList)>0: 311 | print(x[2]+"\t["+x[0]+"] - Additional ports on IPv6: "+setColor(", ".join(tmpResultList), bold, color="red")) 312 | else: 313 | print(x[2]+"\t["+x[0]+"]") 314 | else: 315 | #print "["+x[0]+"]" 316 | diffList=diff(tmpIPv6pPortList,tmpIPv4pPortList) 317 | tmpResultList=[] 318 | for y in diffList: 319 | if y in tmpIPv6pPortList: 320 | tmpResultList.append(str(y)) 321 | if len(tmpResultList)>0: 322 | print("["+x[0]+"] - Additional ports on IPv6: "+setColor(", ".join(tmpResultList), bold, color="red")) 323 | else: 324 | print("["+x[0]+"]") 325 | else: 326 | print(x[2]+"\t["+x[0]+"] - No additional ports on IPv6") 327 | 328 | 329 | if len(tmpIPv6pPortList) < len(tmpIPv4pPortList): 330 | if len(x[0]) > 0: 331 | diffList = diff(tmpIPv4pPortList, tmpIPv6pPortList) 332 | tmpResultList = [] 333 | for y in diffList: 334 | if y in tmpIPv4pPortList: 335 | tmpResultList.append(str(y)) 336 | if len(tmpResultList) > 0: 337 | print(x[0] + "\t[" + x[2] + "] - Additional ports on IPv4: " + setColor(", ".join(tmpResultList), bold, color="red")) 338 | else: 339 | print(x[0] + "\t[" + x[2] + "]") 340 | else: 341 | # print "["+x[0]+"]" 342 | 343 | diffList = diff(tmpIPv4pPortList, tmpIPv6pPortList) 344 | tmpResultList = [] 345 | for y in diffList: 346 | if y in tmpIPv4pPortList: 347 | tmpResultList.append(str(y)) 348 | if len(tmpResultList) > 0: 349 | print("[" + x[2] + "] - Additional ports on IPv4: " + setColor(", ".join(tmpResultList), bold, color="red")) 350 | else: 351 | print("[" + x[2] + "]") 352 | else: 353 | print(x[0]+"\t["+x[2]+"] - No additional ports on IPv4") 354 | 355 | 356 | print("\n[*] Comparing ports on IPv4 and IPv6 interfaces on hosts") 357 | --------------------------------------------------------------------------------