github.com/n00py/Slackor@v0.0.0-20200610224921-d007fcea1740/impacket/examples/nmapAnswerMachine.py (about) 1 #!/usr/bin/env python 2 import uncrc32 3 4 try: 5 import pcap as pcapy 6 except ImportError: 7 import pcapy 8 9 from impacket import ImpactPacket 10 from impacket import ImpactDecoder 11 from impacket.ImpactPacket import TCPOption 12 from impacket.examples import logger 13 from impacket.examples import os_ident 14 15 #defaults 16 17 MAC = "01:02:03:04:05:06" 18 IP = "192.168.67.254" 19 IFACE = "eth0" 20 OPEN_TCP_PORTS = [80, 443] 21 OPEN_UDP_PORTS = [111] 22 UDP_CMD_PORT = 12345 23 nmapOSDB = '/usr/share/nmap/nmap-os-db' 24 25 # Fingerprint = 'Adtran NetVanta 3200 router' # CD=Z TOSI=Z <----------- NMAP detects it as Linux!!! 26 # Fingerprint = 'ADIC Scalar 1000 tape library remote management unit' # DFI=S 27 # Fingerprint = 'Siemens Gigaset SX541 or USRobotics USR9111 wireless DSL modem' # DFI=O U1(DF=N IPL=38) 28 # Fingerprint = 'Apple Mac OS X 10.5.6 (Leopard) (Darwin 9.6.0)' # DFI=Y SI=S U1(DF=Y) 29 30 Fingerprint = 'Sun Solaris 10 (SPARC)' 31 # Fingerprint = 'Sun Solaris 9 (x86)' 32 33 # Fingerprint = '3Com OfficeConnect 3CRWER100-75 wireless broadband router' # TI=Z DFI=N !SS TI=Z II=I 34 # Fingerprint = 'WatchGuard Firebox X5w firewall/WAP' # TI=RD 35 # no TI=Hex 36 # Fingerprint = 'FreeBSD 6.0-STABLE - 6.2-RELEASE' # TI=RI 37 # Fingerprint = 'Microsoft Windows 98 SE' # TI=BI ----> BROKEN! nmap shows no SEQ() output 38 # Fingerprint = 'Microsoft Windows NT 4.0 SP5 - SP6' # TI=BI TOSI=S SS=S 39 # Fingerprint = 'Microsoft Windows Vista Business' # TI=I U1(IPL=164) 40 41 # Fingerprint = 'FreeBSD 6.1-RELEASE' # no TI (TI=O) 42 43 # Fingerprint = '2Wire 1701HG wireless ADSL modem' # IE(R=N) 44 45 # Fingerprint = 'Cisco Catalyst 1912 switch' # TOSI=O SS=S 46 47 O_ETH = 0 48 O_IP = 1 49 O_ARP = 1 50 O_UDP = 2 51 O_TCP = 2 52 O_ICMP = 2 53 O_UDP_DATA = 3 54 O_ICMP_DATA = 3 55 56 def string2tuple(string): 57 if string.find(':') >= 0: 58 return [int(x) for x in string.split(':')] 59 else: 60 return [int(x) for x in string.split('.')] 61 62 class Responder: 63 templateClass = None 64 signatureName = None 65 66 def __init__(self, machine): 67 self.machine = machine 68 print("Initializing %s" % self.__class__.__name__) 69 self.initTemplate() 70 self.initFingerprint() 71 72 def initTemplate(self): 73 if not self.templateClass: 74 self.template_onion = None 75 else: 76 try: 77 probe = self.templateClass(0, ['0.0.0.0',self.getIP()],[0, 0]) 78 except: 79 probe = self.templateClass(0, ['0.0.0.0',self.getIP()]) 80 self.template_onion = [probe.get_packet()] 81 try: 82 while 1: self.template_onion.append (self.template_onion[-1].child ()) 83 except: pass 84 85 # print("Template: %s" % self.template_onion[O_ETH]) 86 # print("Options: %r" % self.template_onion[O_TCP].get_padded_options()) 87 # print("Flags: 0x%04x" % self.template_onion[O_TCP].get_th_flags()) 88 89 def initFingerprint(self): 90 if not self.signatureName: 91 self.fingerprint = None 92 else: 93 self.fingerprint = self.machine.fingerprint.get_tests()[self.signatureName].copy() 94 95 def isMine(self, in_onion): 96 return False 97 98 def buildAnswer(self, in_onion): 99 return None 100 101 def sendAnswer(self, out_onion): 102 self.machine.sendPacket(out_onion) 103 104 def process(self, in_onion): 105 if not self.isMine(in_onion): return False 106 print("Got packet for %s" % self.__class__.__name__) 107 108 out_onion = self.buildAnswer(in_onion) 109 110 if out_onion: self.sendAnswer(out_onion) 111 return True 112 113 def getIP(self): 114 return self.machine.ipAddress 115 116 # Generic Responders (does the word Responder exist?) 117 118 class ARPResponder(Responder): 119 def isMine(self, in_onion): 120 if len(in_onion) < 2: return False 121 122 if in_onion[O_ARP].ethertype != ImpactPacket.ARP.ethertype: 123 return False 124 125 return ( 126 in_onion[O_ARP].get_ar_op() == 1 and # ARP REQUEST 127 in_onion[O_ARP].get_ar_tpa() == string2tuple(self.machine.ipAddress)) 128 129 def buildAnswer(self, in_onion): 130 eth = ImpactPacket.Ethernet() 131 arp = ImpactPacket.ARP() 132 eth.contains(arp) 133 134 arp.set_ar_hrd(1) # Hardward type Ethernet 135 arp.set_ar_pro(0x800) # IP 136 arp.set_ar_op(2) # REPLY 137 arp.set_ar_hln(6) 138 arp.set_ar_pln(4) 139 arp.set_ar_sha(string2tuple(self.machine.macAddress)) 140 arp.set_ar_spa(string2tuple(self.machine.ipAddress)) 141 arp.set_ar_tha(in_onion[O_ARP].get_ar_sha()) 142 arp.set_ar_tpa(in_onion[O_ARP].get_ar_spa()) 143 144 eth.set_ether_shost(arp.get_ar_sha()) 145 eth.set_ether_dhost(arp.get_ar_tha()) 146 147 return [eth, arp] 148 149 class IPResponder(Responder): 150 def buildAnswer(self, in_onion): 151 eth = ImpactPacket.Ethernet() 152 ip = ImpactPacket.IP() 153 154 eth.contains(ip) 155 156 eth.set_ether_shost(in_onion[O_ETH].get_ether_dhost()) 157 eth.set_ether_dhost(in_onion[O_ETH].get_ether_shost()) 158 159 ip.set_ip_src(in_onion[O_IP].get_ip_dst()) 160 ip.set_ip_dst(in_onion[O_IP].get_ip_src()) 161 ip.set_ip_id(self.machine.getIPID()) 162 163 return [eth, ip] 164 165 def sameIPFlags(self, in_onion): 166 if not self.template_onion: return True 167 return (self.template_onion[O_IP].get_ip_off() & 0xe000) == (in_onion[O_IP].get_ip_off() & 0xe000) 168 169 def isMine(self, in_onion): 170 if len(in_onion) < 2: return False 171 172 return ( 173 (in_onion[O_IP].ethertype == ImpactPacket.IP.ethertype) and 174 (in_onion[O_IP].get_ip_dst() == self.machine.ipAddress) and 175 self.sameIPFlags(in_onion) 176 ) 177 178 def setTTLFromFingerprint(self, out_onion): 179 f = self.fingerprint 180 # Test T: Initial TTL = range_low-range_hi, base 16 181 # Assumption: we are using the minimum in the TTL range 182 try: 183 ttl = f['T'].split('-') 184 ttl = int(ttl[0], 16) 185 except: 186 ttl = 0x7f 187 188 # Test TG: Initial TTL Guess. It's just a number, we prefer this 189 try: ttl = int(f['TG'], 16) 190 except: pass 191 192 out_onion[O_IP].set_ip_ttl(ttl) 193 194 class ICMPResponder(IPResponder): 195 def buildAnswer(self, in_onion): 196 out_onion = IPResponder.buildAnswer(self, in_onion) 197 icmp = ImpactPacket.ICMP() 198 199 out_onion[O_IP].contains(icmp) 200 out_onion.append(icmp) 201 202 icmp.set_icmp_id(in_onion[O_ICMP].get_icmp_id()) 203 icmp.set_icmp_seq(in_onion[O_ICMP].get_icmp_seq()) 204 205 out_onion[O_IP].set_ip_id(self.machine.getIPID_ICMP()) 206 207 return out_onion 208 209 def isMine(self, in_onion): 210 if not IPResponder.isMine(self, in_onion): return False 211 if len(in_onion) < 3: return False 212 213 return (in_onion[O_ICMP].protocol == ImpactPacket.ICMP.protocol) and self.sameICMPTemplate(in_onion) 214 215 def sameICMPTemplate(self, in_onion): 216 t_ip = self.template_onion[O_IP] 217 t_icmp = self.template_onion[O_ICMP] 218 t_icmp_datalen = self.template_onion[O_ICMP_DATA].get_size() 219 220 return ( 221 (t_ip.get_ip_tos () == in_onion[O_IP].get_ip_tos ()) and ( 222 t_ip.get_ip_df () == in_onion[O_IP].get_ip_df ()) and ( 223 t_icmp.get_icmp_type () == in_onion[O_ICMP].get_icmp_type ()) and ( 224 t_icmp.get_icmp_code () == in_onion[O_ICMP].get_icmp_code ()) and ( 225 t_icmp_datalen == in_onion[O_ICMP_DATA].get_size ()) 226 ) 227 228 class UDPResponder(IPResponder): 229 def isMine(self, in_onion): 230 return ( 231 IPResponder.isMine(self, in_onion) and 232 (len(in_onion) >= 3) and 233 (in_onion[O_UDP].protocol == ImpactPacket.UDP.protocol) 234 ) 235 236 class OpenUDPResponder(UDPResponder): 237 def isMine(self, in_onion): 238 return ( 239 UDPResponder.isMine(self, in_onion) and 240 self.machine.isUDPPortOpen(in_onion[O_UDP].get_uh_dport())) 241 242 def buildAnswer(self, in_onion): 243 out_onion = IPResponder.buildAnswer(self, in_onion) 244 udp = ImpactPacket.UDP() 245 246 out_onion[O_IP].contains(udp) 247 out_onion.append(udp) 248 249 udp.set_uh_dport(in_onion[O_UDP].get_uh_sport()) 250 udp.set_uh_sport(in_onion[O_UDP].get_uh_dport()) 251 252 return out_onion 253 254 class ClosedUDPResponder(UDPResponder): 255 def isMine(self, in_onion): 256 return ( 257 UDPResponder.isMine(self, in_onion) and 258 not self.machine.isUDPPortOpen(in_onion[O_UDP].get_uh_dport())) 259 260 def buildAnswer(self, in_onion): 261 out_onion = IPResponder.buildAnswer(self, in_onion) 262 icmp = ImpactPacket.ICMP() 263 264 out_onion[O_IP].contains(icmp) 265 out_onion.append(icmp) 266 267 icmp.contains(in_onion[O_IP]) 268 out_onion += in_onion[O_IP:] 269 270 icmp.set_icmp_type(icmp.ICMP_UNREACH) 271 icmp.set_icmp_code(icmp.ICMP_UNREACH_PORT) 272 273 return out_onion 274 275 class TCPResponder(IPResponder): 276 def buildAnswer(self, in_onion): 277 out_onion = IPResponder.buildAnswer(self, in_onion) 278 tcp = ImpactPacket.TCP() 279 280 out_onion[O_IP].contains(tcp) 281 out_onion.append(tcp) 282 283 tcp.set_th_dport(in_onion[O_TCP].get_th_sport()) 284 tcp.set_th_sport(in_onion[O_TCP].get_th_dport()) 285 286 return out_onion 287 288 def sameTCPFlags(self, in_onion): 289 if not self.template_onion: return True 290 in_flags = in_onion[O_TCP].get_th_flags() & 0xfff 291 t_flags = self.template_onion[O_TCP].get_th_flags() & 0xfff 292 293 return in_flags == t_flags 294 295 def sameTCPOptions(self, in_onion): 296 if not self.template_onion: return True 297 in_options = in_onion[O_TCP].get_padded_options() 298 t_options = self.template_onion[O_TCP].get_padded_options() 299 300 return in_options == t_options 301 302 def isMine(self, in_onion): 303 if not IPResponder.isMine(self, in_onion): return False 304 if len(in_onion) < 3: return False 305 306 return (in_onion[O_TCP].protocol == ImpactPacket.TCP.protocol and self.sameTCPFlags (in_onion) and self.sameTCPOptions ( 307 in_onion)) 308 309 class OpenTCPResponder(TCPResponder): 310 def isMine(self, in_onion): 311 return (TCPResponder.isMine (self, in_onion) and in_onion[O_TCP].get_SYN () and self.machine.isTCPPortOpen ( 312 in_onion[O_TCP].get_th_dport ())) 313 314 def buildAnswer(self, in_onion): 315 out_onion = TCPResponder.buildAnswer(self, in_onion) 316 317 out_onion[O_TCP].set_SYN() 318 out_onion[O_TCP].set_ACK() 319 out_onion[O_TCP].set_th_ack(in_onion[O_TCP].get_th_seq()+1) 320 out_onion[O_TCP].set_th_seq(self.machine.getTCPSequence()) 321 322 return out_onion 323 324 class ClosedTCPResponder(TCPResponder): 325 def isMine(self, in_onion): 326 return ( 327 TCPResponder.isMine(self, in_onion) and 328 in_onion[O_TCP].get_SYN() and 329 not self.machine.isTCPPortOpen(in_onion[O_TCP].get_th_dport())) 330 331 def buildAnswer(self, in_onion): 332 out_onion = TCPResponder.buildAnswer(self, in_onion) 333 334 out_onion[O_TCP].set_RST() 335 out_onion[O_TCP].set_ACK() 336 out_onion[O_TCP].set_th_ack(in_onion[O_TCP].get_th_seq()+1) 337 out_onion[O_TCP].set_th_seq(self.machine.getTCPSequence()) 338 339 return out_onion 340 341 class UDPCommandResponder(OpenUDPResponder): 342 # default UDP_CMD_PORT is 12345 343 # use with: 344 # echo cmd:exit | nc -u $(IP) $(UDP_CMD_PORT) 345 # echo cmd:who | nc -u $(IP) $(UDP_CMD_PORT) 346 347 def set_port(self, port): 348 self.port = port 349 self.machine.openUDPPort(port) 350 return self 351 352 def isMine(self, in_onion): 353 return ( OpenUDPResponder.isMine(self, in_onion))# and 354 #in_onion[O_UDP].get_uh_dport() == self.port) 355 356 def buildAnswer(self, in_onion): 357 cmd = in_onion[O_UDP_DATA].get_bytes().tostring() 358 if cmd[:4] == 'cmd:': cmd = cmd[4:].strip() 359 print("Got command: %r" % cmd) 360 361 if cmd == 'exit': 362 from sys import exit 363 exit() 364 365 out_onion = OpenUDPResponder.buildAnswer(self, in_onion) 366 out_onion.append(ImpactPacket.Data()) 367 out_onion[O_UDP].contains(out_onion[O_UDP_DATA]) 368 if cmd == 'who': 369 out_onion[O_UDP_DATA].set_data(self.machine.fingerprint.get_id()) 370 371 return out_onion 372 373 # NMAP2 specific responders 374 class NMAP2UDPResponder(ClosedUDPResponder): 375 signatureName = 'U1' 376 377 # No real need to filter 378 # def isMine(self, in_onion): 379 # return ( 380 # ClosedUDPResponder.isMine(self, inOnion) and 381 # (in_onion[O_UDP_DATA].get_size() == 300)) 382 383 def buildAnswer(self, in_onion): 384 out_onion = ClosedUDPResponder.buildAnswer(self, in_onion) 385 f = self.fingerprint 386 387 # assume R = Y 388 try: 389 if (f['R'] == 'N'): return None 390 except: pass 391 392 # Test DF: Don't fragment IP bit set = [YN] 393 if (f['DF'] == 'Y'): out_onion[O_IP].set_ip_df(True) 394 else: out_onion[O_IP].set_ip_df(False) 395 396 self.setTTLFromFingerprint(out_onion) 397 398 # UN. Assume 0 399 try: un = int(f['UN'],16) 400 except: un = 0 401 out_onion[O_ICMP].set_icmp_void(un) 402 403 # RIPL. Assume original packet just quoted 404 try: 405 ripl = int(f['RIPL'],16) # G generates exception 406 out_onion[O_ICMP_DATA].set_ip_len(ripl) 407 except: 408 pass 409 410 # RID. Assume original packet just quoted 411 try: 412 rid = int(f['RID'],16) # G generates exception 413 out_onion[O_ICMP_DATA].set_ip_id(rid) 414 except: 415 pass 416 417 # RIPCK. Assume original packet just quoted 418 try: ripck = f['RIPCK'] 419 except: ripck = 'G' 420 if ripck == 'I': out_onion[O_ICMP_DATA].set_ip_sum(0x6765) 421 elif ripck == 'Z': out_onion[O_ICMP_DATA].set_ip_sum(0) 422 elif ripck == 'G': out_onion[O_ICMP_DATA].auto_checksum = 0 423 424 # RUCK. Assume original packet just quoted 425 try: 426 ruck = int(f['RUCK'], 16) 427 out_onion[O_ICMP_DATA+1].set_uh_sum(ruck) 428 except: 429 out_onion[O_ICMP_DATA+1].auto_checksum = 0 430 431 # RUD. Assume original packet just quoted 432 try: rud = f['RUD'] 433 except: rud = 'G' 434 435 if rud == 'I': 436 udp_data = out_onion[O_ICMP_DATA+2] 437 udp_data.set_data('G'*udp_data.get_size()) 438 439 # IPL. Assume all original packet is quoted 440 # This has to be the last thing we do 441 # as we are going to render the packet before doing it 442 try: ipl = int(f['IPL'], 16) 443 except: ipl = None 444 445 if not ipl is None: 446 data = out_onion[O_ICMP_DATA].get_packet() 447 out_onion[O_ICMP].contains(ImpactPacket.Data()) 448 ip_and_icmp_len = out_onion[O_IP].get_size() 449 450 data = data[:ipl - ip_and_icmp_len] 451 452 data += '\x00'*(ipl-len(data)-ip_and_icmp_len) 453 out_onion = out_onion[:O_ICMP_DATA] 454 out_onion.append(ImpactPacket.Data(data)) 455 out_onion[O_ICMP].contains(out_onion[O_ICMP_DATA]) 456 457 return out_onion 458 459 class NMAP2ICMPResponder(ICMPResponder): 460 def buildAnswer(self, in_onion): 461 f = self.fingerprint 462 463 # assume R = Y 464 try: 465 if (f['R'] == 'N'): return None 466 except: pass 467 468 out_onion = ICMPResponder.buildAnswer(self, in_onion) 469 470 # assume DFI = N 471 try: dfi = f['DFI'] 472 except: dfi = 'N' 473 474 if dfi == 'N': out_onion[O_IP].set_ip_df(False) 475 elif dfi == 'Y': out_onion[O_IP].set_ip_df(True) 476 elif dfi == 'S': out_onion[O_IP].set_ip_df(in_onion[O_IP].get_ip_df()) 477 elif dfi == 'O': out_onion[O_IP].set_ip_df(not in_onion[O_IP].get_ip_df()) 478 else: raise Exception('Unsupported IE(DFI=%s)' % dfi) 479 480 # assume DLI = S 481 try: dli = f['DLI'] 482 except: dli = 'S' 483 484 if dli == 'S': out_onion[O_ICMP].contains(in_onion[O_ICMP_DATA]) 485 elif dli != 'Z': raise Exception('Unsupported IE(DFI=%s)' % dli) 486 487 self.setTTLFromFingerprint(out_onion) 488 489 # assume SI = S 490 try: si = f['SI'] 491 except: si = 'S' 492 493 if si == 'S': out_onion[O_ICMP].set_icmp_seq(in_onion[O_ICMP].get_icmp_seq()) 494 elif si == 'Z': out_onion[O_ICMP].set_icmp_seq(0) # this is not currently supported by nmap, but I've done it already 495 else: 496 try: out_onion[O_ICMP].set_icmp_seq(int(si, 16)) # this is not supported either by nmap 497 except: raise Exception('Unsupported IE(SI=%s)' % si) 498 499 # assume CD = S 500 try: cd = f['CD'] 501 except: cd = 'S' 502 503 if cd == 'Z': out_onion[O_ICMP].set_icmp_code(0) 504 elif cd == 'S': out_onion[O_ICMP].set_icmp_code(in_onion[O_ICMP].get_icmp_code()) 505 elif cd == 'O': out_onion[O_ICMP].set_icmp_code(in_onion[O_ICMP].get_icmp_code()+1) # no examples in DB 506 else: 507 try: out_onion[O_ICMP].set_icmp_code(int(cd, 16)) # documented, but no examples available 508 except: raise Exception('Unsupported IE(CD=%s)' % cd) 509 510 # assume TOSI = S 511 try: tosi = f['TOSI'] 512 except: tosi = 'S' 513 514 if tosi == 'Z': out_onion[O_IP].set_ip_tos(0) 515 elif tosi == 'S': out_onion[O_IP].set_ip_tos(in_onion[O_IP].get_ip_tos()) 516 elif tosi == 'O': out_onion[O_IP].set_ip_tos(in_onion[O_IP].get_ip_tos()+1) # no examples in DB 517 else: 518 try: out_onion[O_IP].set_ip_tos(int(tosi, 16)) # documented, but no examples available 519 except: raise Exception('Unsupported IE(TOSI=%s)' % tosi) 520 521 return out_onion 522 523 class NMAP2TCPResponder(TCPResponder): 524 def buildAnswer(self, in_onion): 525 out_onion = TCPResponder.buildAnswer(self, in_onion) 526 527 f = self.fingerprint 528 529 # Test R: There is a response = [YN] 530 if (f['R'] == 'N'): return None 531 532 # Test DF: Don't fragment IP bit set = [YN] 533 if (f['DF'] == 'Y'): out_onion[O_IP].set_ip_df(True) 534 else: out_onion[O_IP].set_ip_df(False) 535 536 # Test W: Initial TCP windows size 537 try: win = int(f['W'],16) 538 except: win = 0 539 out_onion[O_TCP].set_th_win(win) 540 541 self.setTTLFromFingerprint(out_onion) 542 543 # Test CC: Explicit congestion notification 544 # Two TCP flags are used in this test: ECE and CWR 545 try: 546 cc = f['CC'] 547 if cc == 'N': ece,cwr = 0,0 548 if cc == 'Y': ece,cwr = 1,0 549 if cc == 'S': ece,cwr = 1,1 550 if cc == 'O': ece,cwr = 0,1 551 except: 552 ece,cwr = 0,0 553 554 if ece: out_onion[O_TCP].set_ECE() 555 else: out_onion[O_TCP].reset_ECE() 556 if cwr: out_onion[O_TCP].set_CWR() 557 else: out_onion[O_TCP].reset_CWR() 558 559 560 # Test O: TCP Options 561 try: options = f['O'] 562 except: options = '' 563 self.setTCPOptions(out_onion, options) 564 565 # Test S: TCP Sequence number 566 # Z: Sequence number is zero 567 # A: Sequence number is the same as the ACK in the probe 568 # A+: Sequence number is the same as the ACK in the probe + 1 569 # O: Other value 570 try: s = f['S'] 571 except: s = 'O' 572 if s == 'Z': out_onion[O_TCP].set_th_seq(0) 573 if s == 'A': out_onion[O_TCP].set_th_seq(in_onion[O_TCP].get_th_ack()) 574 if s == 'A+': out_onion[O_TCP].set_th_seq(in_onion[O_TCP].get_th_ack()+1) 575 if s == 'O': out_onion[O_TCP].set_th_seq(self.machine.getTCPSequence()) 576 577 # Test A: TCP ACK number 578 # Z: Ack is zero 579 # S: Ack is the same as the Squence number in the probe 580 # S+: Ack is the same as the Squence number in the probe + 1 581 # O: Other value 582 try: a = f['A'] 583 except: a = 'O' 584 if a == 'Z': out_onion[O_TCP].set_th_ack(0) 585 if a == 'S': out_onion[O_TCP].set_th_ack(in_onion[O_TCP].get_th_seq()) 586 if a == 'S+': out_onion[O_TCP].set_th_ack(in_onion[O_TCP].get_th_seq()+1) 587 588 # Test Q: Quirks 589 # R: Reserved bit set (right after the header length) 590 # U: Urgent pointer non-zero and URG flag clear 591 try: 592 if 'R' in f['Q']: out_onion[O_TCP].set_flags(0x800) 593 except: pass 594 try: 595 if 'U' in f['Q']: out_onion[O_TCP].set_th_urp(0xffff) 596 except: pass 597 598 # Test F: TCP Flags 599 try: flags = f['F'] 600 except: flags = '' 601 if 'E' in flags: out_onion[O_TCP].set_ECE() 602 if 'U' in flags: out_onion[O_TCP].set_URG() 603 if 'A' in flags: out_onion[O_TCP].set_ACK() 604 if 'P' in flags: out_onion[O_TCP].set_PSH() 605 if 'R' in flags: out_onion[O_TCP].set_RST() 606 if 'S' in flags: out_onion[O_TCP].set_SYN() 607 if 'F' in flags: out_onion[O_TCP].set_FIN() 608 609 # Test RD: TCP Data checksum (mostly for data in RST) 610 try: 611 crc = f['RD'] 612 if crc != '0': # when the 613 crc = int(crc, 16) 614 data = 'TCP Port is closed\x00' 615 data += uncrc32.compensate(data, crc) 616 data = ImpactPacket.Data(data) 617 out_onion.append(data) 618 out_onion[O_TCP].contains(data) 619 except: 620 pass 621 return out_onion 622 623 def setTCPOptions(self, onion, options): 624 def getValue(string, i): 625 value = 0 626 627 idx = i 628 for c in options[i:]: 629 try: 630 value = value * 0x10 + int(c,16) 631 except: 632 break 633 idx += 1 634 635 return value, idx 636 637 # Test O,O1=O6: TCP Options 638 # L: End of Options 639 # N: NOP 640 # S: Selective ACK 641 # Mx: MSS (x is a hex number) 642 # Wx: Windows Scale (x is a hex number) 643 # Tve: Timestamp (v and e are two binary digits, v for TSval and e for TSecr 644 645 i = 0 646 tcp = onion[O_TCP] 647 while i < len(options): 648 opt = options[i] 649 i += 1 650 if opt == 'L': tcp.add_option(TCPOption(TCPOption.TCPOPT_EOL)) 651 if opt == 'N': tcp.add_option(TCPOption(TCPOption.TCPOPT_NOP)) 652 if opt == 'S': tcp.add_option(TCPOption(TCPOption.TCPOPT_SACK_PERMITTED)) 653 if opt == 'T': 654 opt = TCPOption(TCPOption.TCPOPT_TIMESTAMP) # default ts = 0, ts_echo = 0 655 if options[i] == '1': opt.set_ts(self.machine.getTCPTimeStamp()) 656 if options[i+1] == '1': opt.set_ts_echo(0xffffffff) 657 tcp.add_option(opt) 658 i += 2 659 if opt == 'M': 660 maxseg, i = getValue(options, i) 661 tcp.add_option(TCPOption(TCPOption.TCPOPT_MAXSEG, maxseg)) 662 if opt == 'W': 663 window, i = getValue(options, i) 664 tcp.add_option(TCPOption(TCPOption.TCPOPT_WINDOW, window)) 665 666 class nmap2_SEQ(NMAP2TCPResponder): 667 templateClass = None 668 signatureName = None 669 seqNumber = None 670 671 def initFingerprint(self): 672 NMAP2TCPResponder.initFingerprint(self) 673 if not self.seqNumber: return 674 else: 675 OPS = self.machine.fingerprint.get_tests()['OPS'] 676 WIN = self.machine.fingerprint.get_tests()['WIN'] 677 self.fingerprint['O'] = OPS['O%d' % self.seqNumber] 678 self.fingerprint['W'] = WIN['W%d' % self.seqNumber] 679 680 class nmap2_ECN(NMAP2TCPResponder): 681 templateClass = os_ident.nmap2_ecn_probe 682 signatureName = 'ECN' 683 684 class nmap2_SEQ1(nmap2_SEQ): 685 templateClass = os_ident.nmap2_seq_1 686 signatureName = 'T1' 687 seqNumber = 1 688 689 class nmap2_SEQ2(nmap2_SEQ): 690 templateClass = os_ident.nmap2_seq_2 691 signatureName = 'T1' 692 seqNumber = 2 693 694 class nmap2_SEQ3(nmap2_SEQ): 695 templateClass = os_ident.nmap2_seq_3 696 signatureName = 'T1' 697 seqNumber = 3 698 699 class nmap2_SEQ4(nmap2_SEQ): 700 templateClass = os_ident.nmap2_seq_4 701 signatureName = 'T1' 702 seqNumber = 4 703 704 class nmap2_SEQ5(nmap2_SEQ): 705 templateClass = os_ident.nmap2_seq_5 706 signatureName = 'T1' 707 seqNumber = 5 708 709 class nmap2_SEQ6(nmap2_SEQ): 710 templateClass = os_ident.nmap2_seq_6 711 signatureName = 'T1' 712 seqNumber = 6 713 714 class nmap2_T2(NMAP2TCPResponder): 715 templateClass = os_ident.nmap2_tcp_open_2 716 signatureName = 'T2' 717 718 class nmap2_T3(NMAP2TCPResponder): 719 templateClass = os_ident.nmap2_tcp_open_3 720 signatureName = 'T3' 721 722 class nmap2_T4(NMAP2TCPResponder): 723 templateClass = os_ident.nmap2_tcp_open_4 724 signatureName = 'T4' 725 726 class nmap2_T5(NMAP2TCPResponder): 727 templateClass = os_ident.nmap2_tcp_closed_1 728 signatureName = 'T5' 729 730 class nmap2_T6(NMAP2TCPResponder): 731 templateClass = os_ident.nmap2_tcp_closed_2 732 signatureName = 'T6' 733 734 class nmap2_T7(NMAP2TCPResponder): 735 templateClass = os_ident.nmap2_tcp_closed_3 736 signatureName = 'T7' 737 738 class nmap2_ICMP_1(NMAP2ICMPResponder): 739 templateClass = os_ident.nmap2_icmp_echo_probe_1 740 signatureName = 'IE' 741 742 class nmap2_ICMP_2(NMAP2ICMPResponder): 743 templateClass = os_ident.nmap2_icmp_echo_probe_2 744 signatureName = 'IE' 745 746 class Machine: 747 AssumedTimeIntervalPerPacket = 0.11 # seconds 748 def __init__(self, emmulating, interface, ipAddress, macAddress, openTCPPorts = [], openUDPPorts = [], nmapOSDB = 'nmap-os-db'): 749 self.interface = interface 750 self.ipAddress = ipAddress 751 self.macAddress = macAddress 752 self.responders = [] 753 self.decoder = ImpactDecoder.EthDecoder() 754 755 self.initPcap() 756 self.initFingerprint(emmulating, nmapOSDB) 757 758 self.initSequenceGenerators() 759 self.openTCPPorts = openTCPPorts 760 self.openUDPPorts = openUDPPorts 761 print(self) 762 763 def openUDPPort(self, port): 764 if self.isUDPPortOpen(port): return 765 self.openUDPPorts.append(port) 766 767 def isUDPPortOpen(self, port): 768 return port in self.openUDPPorts 769 770 def isTCPPortOpen(self, port): 771 return port in self.openTCPPorts 772 773 def initPcap(self): 774 self.pcap = pcapy.open_live(self.interface, 65535, 1, 0) 775 try: self.pcap.setfilter("host %s or ether host %s" % (self.ipAddress, self.macAddress)) 776 except: self.pcap.setfilter("host %s or ether host %s" % (self.ipAddress, self.macAddress), 1, 0xFFFFFF00) 777 778 def initGenericResponders(self): 779 # generic responders 780 self.addResponder(ARPResponder(self)) 781 self.addResponder(OpenUDPResponder(self)) 782 self.addResponder(ClosedUDPResponder(self)) 783 self.addResponder(OpenTCPResponder(self)) 784 self.addResponder(ClosedTCPResponder(self)) 785 786 def initFingerprint(self, emmulating, nmapOSDB): 787 fpm = os_ident.NMAP2_Fingerprint_Matcher('') 788 f = open(nmapOSDB, 'r') 789 for text in fpm.fingerprints(f): 790 fingerprint = fpm.parse_fp(text) 791 if fingerprint.get_id() == emmulating: 792 self.fingerprint = fingerprint 793 self.simplifyFingerprint() 794 # print(fingerprint) 795 return 796 797 raise Exception("Couldn't find fingerprint data for %r" % emmulating) 798 799 def simplifyFingerprint(self): 800 tests = self.fingerprint.get_tests() 801 for probeName in tests: 802 probe = tests[probeName] 803 for test in probe: 804 probe[test] = probe[test].split('|')[0] 805 806 def initSequenceGenerators(self): 807 self.initIPIDGenerator() 808 self.initTCPISNGenerator() 809 self.initTCPTSGenerator() 810 811 def initIPIDGenerator(self): 812 seq = self.fingerprint.get_tests()['SEQ'] 813 self.ip_ID = 0 814 815 try: TI = seq['TI'] 816 except: TI = 'O' 817 818 if TI == 'Z': self.ip_ID_delta = 0 819 elif TI == 'RD': self.ip_ID_delta = 30000 820 elif TI == 'RI': self.ip_ID_delta = 1234 821 elif TI == 'BI': self.ip_ID_delta = 1024+256 822 elif TI == 'I': self.ip_ID_delta = 1 823 elif TI == 'O': self.ip_ID_delta = 123 824 else: self.ip_ID_delta = int(TI, 16) 825 826 try: ss = seq['SS'] 827 except: ss = 'O' 828 829 self.ip_ID_ICMP_delta = None 830 if ss == 'S': self.ip_ID_ICMP = None 831 else: 832 self.ip_ID_ICMP = 0 833 try: II = seq['II'] 834 except: II = 'O' 835 836 if II == 'Z': self.ip_ID_ICMP_delta = 0 837 elif II == 'RD': self.ip_ID_ICMP_delta = 30000 838 elif II == 'RI': self.ip_ID_ICMP_delta = 1234 839 elif II == 'BI': self.ip_ID_ICMP_delta = 1024+256 840 elif II == 'I': self.ip_ID_ICMP_delta = 1 841 elif II == 'O': self.ip_ID_ICMP_delta = 123 842 else: self.ip_ID_ICMP_delta = int(II, 16) 843 844 # generate a few, so we don't start with 0 when we don't have to 845 for i in range(10): 846 self.getIPID() 847 self.getIPID_ICMP() 848 849 print("IP ID Delta: %d" % self.ip_ID_delta) 850 print("IP ID ICMP Delta: %s" % self.ip_ID_ICMP_delta) 851 852 def initTCPISNGenerator(self): 853 # tcp_ISN and tcp_ISN_delta for TCP Initial sequence numbers 854 self.tcp_ISN = 0 855 try: 856 self.tcp_ISN_GCD = int(self.fingerprint.get_tests()['SEQ']['GCD'].split('-')[0], 16) 857 except: 858 self.tcp_ISN_GCD = 1 859 860 try: 861 isr = self.fingerprint.get_tests()['SEQ']['ISR'].split('-') 862 if len(isr) == 1: 863 isr = int(isr[0], 16) 864 else: 865 isr = (int(isr[0], 16) + int(isr[1], 16)) / 2 866 except: 867 isr = 0 868 869 try: 870 sp = self.fingerprint.get_tests()['SEQ']['SP'].split('-') 871 sp = int(sp[0], 16) 872 except: 873 sp = 0 874 875 self.tcp_ISN_stdDev = (2**(sp/8.0)) * 5 / 4 # n-1 on small populations... erm... 876 877 if self.tcp_ISN_GCD > 9: 878 self.tcp_ISN_stdDev *= self.tcp_ISN_GCD 879 880 self.tcp_ISN_stdDev *= self.AssumedTimeIntervalPerPacket 881 882 self.tcp_ISN_delta = 2**(isr/8.0) * self.AssumedTimeIntervalPerPacket 883 884 # generate a few, so we don't start with 0 when we don't have to 885 for i in range(10): self.getTCPSequence() 886 887 print("TCP ISN Delta: %f" % self.tcp_ISN_delta) 888 print("TCP ISN Standard Deviation: %f" % self.tcp_ISN_stdDev) 889 890 def initTCPTSGenerator(self): 891 # tcp_TS and tcp_TS_delta for TCP Time stamp generation 892 self.tcp_TS = 0 893 894 try: ts = self.fingerprint.get_tests()['SEQ']['TS'] 895 except: ts = 'U' 896 897 if ts == 'U' or ts == 'Z': self.tcp_TS_delta = 0 898 else: 899 self.tcp_TS_delta = (2**int(ts, 16)) * self.AssumedTimeIntervalPerPacket 900 901 # generate a few, so we don't start with 0 when we don't have to 902 for i in range(10): self.getTCPTimeStamp() 903 904 print("TCP TS Delta: %f" % self.tcp_TS_delta) 905 906 def getIPID(self): 907 answer = self.ip_ID 908 self.ip_ID += self.ip_ID_delta 909 self.ip_ID %= 0x10000 910 # print("IP ID: %x" % answer) 911 return answer 912 913 def getIPID_ICMP(self): 914 if self.ip_ID_ICMP is None: 915 return self.getIPID() 916 917 answer = self.ip_ID_ICMP 918 self.ip_ID_ICMP += self.ip_ID_ICMP_delta 919 self.ip_ID_ICMP %= 0x10000 920 # print("---> IP ID: %x" % answer) 921 return answer 922 923 def getTCPSequence(self): 924 answer = self.tcp_ISN + self.tcp_ISN_stdDev # *random.random() 925 self.tcp_ISN_stdDev *= -1 926 answer = int(int(answer/self.tcp_ISN_GCD) * self.tcp_ISN_GCD) 927 self.tcp_ISN += self.tcp_ISN_delta 928 self.tcp_ISN %= 0x100000000 929 # print("---> TCP Sequence: %d" % (answer % 0x100000000)) 930 return answer % 0x100000000 931 932 def getTCPTimeStamp(self): 933 answer = int(round(self.tcp_TS)) 934 self.tcp_TS += self.tcp_TS_delta 935 self.tcp_TS %= 0x100000000 936 # print("---> TCP Time Stamp: %x" % answer) 937 return answer 938 939 def sendPacket(self, onion): 940 if not onion: return 941 print("--> Packet sent:") 942 #print(onion[0]) 943 #print() 944 self.pcap.sendpacket(onion[O_ETH].get_packet()) 945 946 def addResponder(self, aResponder): 947 self.responders.append(aResponder) 948 949 def run(self): 950 while 1: 951 p = self.pcap.next() 952 try: in_onion = [self.decoder.decode(p[1])] 953 except: in_onion = [self.decoder.decode(p[0])] 954 try: 955 while 1: in_onion.append(in_onion[-1].child()) 956 except: 957 pass 958 959 #print("-------------- Received: ", in_onion[0]) 960 for r in self.responders: 961 if r.process(in_onion): break 962 963 964 def main(): 965 def initResponders(machine): 966 # cmd responder 967 # machine.addResponder(UDPCommandResponder(machine).set_port(UDP_CMD_PORT)) 968 969 # nmap2 specific responders 970 machine.addResponder(nmap2_SEQ1(machine)) 971 machine.addResponder(nmap2_SEQ2(machine)) 972 machine.addResponder(nmap2_SEQ3(machine)) 973 machine.addResponder(nmap2_SEQ4(machine)) 974 machine.addResponder(nmap2_SEQ5(machine)) 975 machine.addResponder(nmap2_SEQ6(machine)) 976 machine.addResponder(nmap2_ECN(machine)) 977 machine.addResponder(nmap2_T2(machine)) 978 machine.addResponder(nmap2_T3(machine)) 979 machine.addResponder(nmap2_T4(machine)) 980 machine.addResponder(nmap2_T5(machine)) 981 machine.addResponder(nmap2_T6(machine)) 982 machine.addResponder(nmap2_T7(machine)) 983 machine.addResponder(nmap2_ICMP_1(machine)) 984 machine.addResponder(nmap2_ICMP_2(machine)) 985 machine.addResponder(NMAP2UDPResponder(machine)) 986 987 from sys import argv, exit 988 def usage(): 989 print(""" 990 if arg == '-h': usage() 991 if arg == '--help': usage() 992 if arg == '-f': Fingerprint = value 993 if arg == '-p': IP = value 994 if arg == '-m': MAC = value 995 if arg == '-i': IFACE = value 996 if arg == '-d': nmapOsDB = value 997 998 where: 999 arg = argv[i] 1000 value = argv[i+1] 1001 """) 1002 exit() 1003 1004 global Fingerprint, IFACE, MAC, IP, nmapOSDB 1005 for i, arg in enumerate(argv): 1006 try: value = argv[i+1] 1007 except: value = None 1008 if arg == '-h': usage() 1009 if arg == '--help': usage() 1010 if arg == '-f': Fingerprint = value 1011 if arg == '-p': IP = value 1012 if arg == '-m': MAC = value 1013 if arg == '-i': IFACE = value 1014 if arg == '-d': nmapOSDB = value 1015 1016 print("Emulating: %r" % Fingerprint) 1017 print("at %s / %s / %s" % (IFACE, MAC, IP)) 1018 machine = Machine( 1019 Fingerprint, 1020 IFACE, 1021 IP, 1022 MAC, 1023 OPEN_TCP_PORTS, 1024 OPEN_UDP_PORTS, 1025 nmapOSDB=nmapOSDB) 1026 1027 initResponders(machine) 1028 machine.initGenericResponders() 1029 machine.run() 1030 1031 if __name__ == '__main__': 1032 # Init the example's logger theme 1033 logger.init() 1034 main() 1035 1036 # All Probes 1037 # [x] SEQ 1038 # [x] OPS 1039 # [x] WIN 1040 # [x] T1 1041 # [x] T2 1042 # [x] T3 1043 # [x] T4 1044 # [x] T5 1045 # [x] T6 1046 # [x] T7 1047 # [x] IE 1048 # [x] ECN 1049 # [x] U1 1050 1051 # All Tests 1052 1053 # SEQ() 1054 # [x] TCP ISN sequence predictability index (SP) 1055 # [x] TCP ISN greatest common divisor (GCD) 1056 # [x] TCP ISN counter rate (ISR) 1057 # [x] IP ID sequence generation algorithm on TCP Open ports (TI) 1058 # [x] Z - All zeros 1059 # [x] RD - Random: It increments at least once by at least 20000. 1060 # [-] Hex Value - fixed IP ID 1061 # [x] RI - Random positive increments. Any (delta_i > 1000, and delta_i % 256 != 0) or (delta_i > 256000 and delta_i % 256 == 0) 1062 # [x] BI - Broken increment. All delta_i % 256 = 0 and all delta_i <= 5120. 1063 # [x] I - Incremental. All delta_i < 10 1064 # [x] O - (Omitted, the test does not show in the fingerprint). None of the other 1065 # [-] IP ID sequence generation algorithm on TCP closed ports (CI) 1066 # [x] IP ID sequence generation algorithm on ICMP messages (II) 1067 # [x] Shared IP ID sequence Boolean (SS) 1068 # [x] TCP timestamp option algorithm (TS) 1069 # [x] U - unsupported (don't send TS) 1070 # [x] 0 - Zero 1071 # [x] 1 - 0-5.66 (2 Hz) 1072 # [x] 7 - 70-150 (100 Hz) 1073 # [x] 8 - 150-350 (200 Hz) 1074 # [x] - avg_freq = sum(TS_diff/time_diff) . round(.5 + math.log(avg_freq)/math.log(2))) 1075 # time_diff = 0.11 segs 1076 # OPS() 1077 # [x] TCP options (O, O1-O6) 1078 # WIN() 1079 # [x] TCP initial window size (W, W1-W6) 1080 # ECN, T1-T7 1081 # [x] TCP options (O, O1-O6) 1082 # [x] TCP initial window size (W, W1-W6) 1083 # [x] Responsiveness (R) 1084 # [x] IP don't fragment bit (DF) 1085 # [x] IP initial time-to-live (T) 1086 # [x] IP initial time-to-live guess (TG) 1087 # [x] Explicit congestion notification (CC) 1088 # [x] TCP miscellaneous quirks (Q) 1089 # [x] TCP sequence number (S) 1090 # [x] TCP acknowledgment number (A) 1091 # [x] TCP flags (F) 1092 # [x] TCP RST data checksum (RD) 1093 # IE() 1094 # [x] Responsiveness (R) 1095 # [x] Don't fragment (ICMP) (DFI) 1096 # [x] IP initial time-to-live (T) 1097 # [x] IP initial time-to-live guess (TG) 1098 # [x] ICMP response code (CD) 1099 #-[x] IP Type of Service (TOSI) 1100 #-[x] ICMP Sequence number (SI) 1101 #-[x] IP Data Length (DLI) 1102 # U1() 1103 # [x] Responsiveness (R) 1104 # [x] IP don't fragment bit (DF) 1105 # [x] IP initial time-to-live (T) 1106 # [x] IP initial time-to-live guess (TG) 1107 # [x] IP total length (IPL) 1108 # [x] Unused port unreachable field nonzero (UN) 1109 # [x] Returned probe IP total length value (RIPL) 1110 # [x] Returned probe IP ID value (RID) 1111 # [x] Integrity of returned probe IP checksum value (RIPCK) 1112 # [x] Integrity of returned probe UDP checksum (RUCK) 1113 # [x] Integrity of returned UDP data (RUD) 1114 # [-] ??? (TOS) Type of Service 1115 # [-] ??? (RUL) Length of return UDP packet is correct 1116 1117 # sudo nmap -O 127.0.0.2 -p 22,111,89 1118 # sudo python nmapAnswerMachine.py -i eth0 -p 192.168.66.254 -f 'Sun Solaris 9 (SPARC)'