Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# Impacket - Collection of Python classes for working with network protocols. 

2# 

3# SECUREAUTH LABS. Copyright (C) 2018 SecureAuth Corporation. All rights reserved. 

4# 

5# This software is provided under a slightly modified version 

6# of the Apache Software License. See the accompanying LICENSE file 

7# for more information. 

8# 

9 

10import math 

11import array 

12from six.moves import xrange, reduce 

13 

14from pcapy import lookupdev, open_live 

15from impacket.ImpactPacket import UDP, TCPOption, Data, TCP, IP, ICMP, Ethernet 

16from impacket.ImpactDecoder import EthDecoder 

17from impacket import LOG 

18 

19g_nmap1_signature_filename="nmap-os-fingerprints" 

20g_nmap2_signature_filename="nmap-os-db" 

21 

22 

23def my_gcd(a, b): 

24 if a < b: 

25 c = a 

26 a = b 

27 b = c 

28 

29 while 0 != b: 

30 c = a & b 

31 a = b 

32 b = c 

33 return a 

34 

35class os_id_exception: 

36 def __init__(self, value): 

37 self.value = value 

38 def __str__(self): 

39 return repr(self.value) 

40 

41class os_id_test: 

42 

43 def __init__(self, id): 

44 self.__id = id 

45 self.__my_packet = None 

46 self.__result_dict = {} 

47 

48 def test_id(self): 

49 return self.__class__.__name__ 

50 

51 def get_test_packet(self): 

52 return self.__my_packet.get_packet() 

53 

54 def set_packet(self, packet): 

55 self.__my_packet = packet 

56 

57 def get_packet(self): 

58 return self.__my_packet 

59 

60 def process(self, packet): 

61 pass 

62 

63 def add_result(self, name, value): 

64 self.__result_dict[name] = value 

65 

66 def get_id(self): 

67 return self.__id 

68 def is_mine(self, packet): 

69 pass 

70 

71 def get_result_dict(self): 

72 return self.__result_dict; 

73 

74 def get_final_result(self): 

75 "Returns a string representation of the final result of this test or None if no response was received" 

76 pass 

77 

78 

79class icmp_request(os_id_test): 

80 type_filter = { ICMP.ICMP_ECHO : ICMP.ICMP_ECHOREPLY, 

81 ICMP.ICMP_IREQ : ICMP.ICMP_IREQREPLY, 

82 ICMP.ICMP_MASKREQ : ICMP.ICMP_MASKREPLY, 

83 ICMP.ICMP_TSTAMP : ICMP.ICMP_TSTAMPREPLY } 

84 

85 def __init__(self, id, addresses, type): 

86 os_id_test.__init__(self, id) 

87 self.e = Ethernet() 

88 self.i = IP() 

89 self.icmp = ICMP() 

90 

91 self.i.set_ip_src(addresses[0]) 

92 self.i.set_ip_dst(addresses[1]) 

93 

94 self.__type = type 

95 self.icmp.set_icmp_type(type) 

96 

97 self.e.contains(self.i) 

98 self.i.contains(self.icmp) 

99 self.set_packet(self.e) 

100 

101 def is_mine(self, packet): 

102 

103 if packet.get_ether_type() != IP.ethertype: 

104 return 0 

105 ip = packet.child() 

106 if not ip or ip.get_ip_p() != ICMP.protocol: 

107 return 0 

108 icmp = ip.child() 

109 

110 # icmp_request.type_filter is a dictionary that maps request  

111 # type codes to the reply codes 

112 

113 if not icmp or \ 

114 icmp.get_icmp_type() != icmp_request.type_filter[self.__type]: 

115 return 0 

116 if icmp.get_icmp_id() != self.get_id(): 

117 return 0 

118 

119 return 1 

120 

121 def process(self, packet): 

122 pass 

123 

124 

125class nmap2_icmp_echo_probe_1(icmp_request): 

126 # The first one has the IP DF bit set, a type-of-service (TOS) byte  

127 # value of zero, a code of nine (even though it should be zero),  

128 # the sequence number 295, a random IP ID and ICMP request identifier,  

129 # and a random character repeated 120 times for the data payload. 

130 sequence_number = 295 

131 id = 0x5678 

132 

133 def __init__(self, id, addresses): 

134 icmp_request.__init__(self, id, addresses, ICMP.ICMP_ECHO) 

135 self.i.set_ip_df(True) 

136 self.i.set_ip_tos(0) 

137 self.icmp.set_icmp_code(9) 

138 self.icmp.set_icmp_seq(nmap2_icmp_echo_probe_1.sequence_number) 

139 self.i.set_ip_id(nmap2_icmp_echo_probe_1.id) 

140 self.icmp.set_icmp_id(nmap2_icmp_echo_probe_1.id) 

141 self.icmp.contains(Data("I" * 120)) 

142 

143 def process(self, packet): 

144 pass 

145 

146class nmap2_icmp_echo_probe_2(icmp_request): 

147 # The second ping query is similar, except a TOS of four  

148 # (IP_TOS_RELIABILITY) is used, the code is zero, 150 bytes of data is  

149 # sent, and the IP ID, request ID, and sequence numbers are incremented  

150 # by one from the previous query values. 

151 

152 def __init__(self, id, addresses): 

153 icmp_request.__init__(self, id, addresses, ICMP.ICMP_ECHO) 

154 self.i.set_ip_df(False) 

155 self.i.set_ip_tos(4) 

156 self.icmp.set_icmp_code(0) 

157 self.icmp.set_icmp_seq(nmap2_icmp_echo_probe_1.sequence_number + 1) 

158 self.i.set_ip_id(nmap2_icmp_echo_probe_1.id + 1) 

159 self.icmp.set_icmp_id(nmap2_icmp_echo_probe_1.id + 1) 

160 self.icmp.contains(Data("I" * 150)) 

161 

162 def process(self, packet): 

163 pass 

164 

165class udp_closed_probe(os_id_test): 

166 

167 ip_id = 0x1234 # HARDCODED 

168 

169 def __init__(self, id, addresses, udp_closed ): 

170 

171 os_id_test.__init__(self, id ) 

172 self.e = Ethernet() 

173 self.i = IP() 

174 self.u = UDP() 

175 

176 self.i.set_ip_src(addresses[0]) 

177 self.i.set_ip_dst(addresses[1]) 

178 self.i.set_ip_id(udp_closed_probe.ip_id) 

179 self.u.set_uh_sport(id) 

180 

181 self.u.set_uh_dport( udp_closed ) 

182 

183 self.e.contains(self.i) 

184 self.i.contains(self.u) 

185 self.set_packet(self.e) 

186 

187 def is_mine(self, packet): 

188 if packet.get_ether_type() != IP.ethertype: 

189 return 0 

190 ip = packet.child() 

191 if not ip or ip.get_ip_p() != ICMP.protocol: 

192 return 0 

193 icmp = ip.child() 

194 if not icmp or icmp.get_icmp_type() != ICMP.ICMP_UNREACH: 

195 return 0 

196 

197 if icmp.get_icmp_code() != ICMP.ICMP_UNREACH_PORT: 

198 return 0; 

199 

200 

201 self.err_data = icmp.child() 

202 if not self.err_data: 

203 return 0 

204 

205 

206 return 1 

207 

208 

209class tcp_probe(os_id_test): 

210 

211 def __init__(self, id, addresses, tcp_ports, open_port ): 

212 

213 self.result_string = "[]" 

214 os_id_test.__init__(self, id) 

215 self.e = Ethernet() 

216 self.i = IP() 

217 self.t = TCP() 

218 self.i.set_ip_src(addresses[0]) 

219 self.i.set_ip_dst(addresses[1]) 

220 self.i.set_ip_id(0x2323) # HARDCODED 

221 self.t.set_th_sport(id) 

222 

223 if open_port: 

224 self.target_port = tcp_ports[0] 

225 else: 

226 self.target_port = tcp_ports[1] 

227 

228 self.t.set_th_dport(self.target_port) 

229 

230 self.e.contains(self.i) 

231 self.i.contains(self.t) 

232 self.set_packet(self.e) 

233 

234 self.source_ip = addresses[0] 

235 self.target_ip = addresses[1] 

236 

237 def socket_match(self, ip, tcp): 

238 # scr ip and port 

239 if (ip.get_ip_src() != self.target_ip) or (tcp.get_th_sport() != self.target_port): 

240 return 0 

241 # dst ip and port 

242 if(ip.get_ip_dst() != self.source_ip) or (tcp.get_th_dport() != self.get_id()): 

243 return 0 

244 return 1 

245 

246 def is_mine(self, packet): 

247 if packet.get_ether_type() != IP.ethertype: 

248 return 0 

249 ip = packet.child() 

250 if not ip or ip.get_ip_p() != TCP.protocol: 

251 return 0 

252 tcp = ip.child() 

253 if self.socket_match(ip, tcp): 

254 return 1 

255 

256 return 0 

257 

258 

259class nmap_tcp_probe(tcp_probe): 

260 

261 def __init__(self, id, addresses, tcp_ports, open_port, sequence, options): 

262 tcp_probe.__init__(self, id, addresses, tcp_ports, open_port) 

263 self.t.set_th_seq(sequence) 

264 self.set_resp(False) 

265 for op in options: 

266 self.t.add_option(op) 

267 

268 def set_resp(self,resp): 

269 pass 

270 

271class nmap1_tcp_probe(nmap_tcp_probe): 

272 sequence = 0x8453 # 0xBASE, obviously 

273 mss = 265 

274 

275 # From: https://nmap.org/nmap-fingerprinting-old.html 

276 # [...] 

277 # Nmap sends these options along with almost every probe packet: 

278 # Window Scale=10; NOP; Max Segment Size = 265; Timestamp; End of Ops; 

279 # [...] 

280 # From nmap-4.22SOC8/osscan.cc:get_fingerprint(...) 

281 # [...] 

282 # "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000" 

283 # [...] 

284 tcp_options = [ 

285 TCPOption(TCPOption.TCPOPT_WINDOW, 0o12), #\003\003\012 

286 TCPOption(TCPOption.TCPOPT_NOP), #\001 

287 TCPOption(TCPOption.TCPOPT_MAXSEG, mss), #\002\004\001\011 

288 TCPOption(TCPOption.TCPOPT_TIMESTAMP, 0x3F3F3F3F), #\010\012\077\077\077\077\000\000\000\000 

289 TCPOption(TCPOption.TCPOPT_EOL), #\000 

290 TCPOption(TCPOption.TCPOPT_EOL) #\000 

291 ] 

292 

293 def __init__(self, id, addresses, tcp_ports, open_port): 

294 nmap_tcp_probe.__init__(self, id, addresses, tcp_ports, open_port, 

295 self.sequence, self.tcp_options) 

296 

297 def set_resp(self,resp): 

298 if resp: 

299 self.add_result("Resp", "Y") 

300 else: 

301 self.add_result("Resp", "N") 

302 

303 def process(self, packet): 

304 ip = packet.child() 

305 tcp = ip.child() 

306 

307 self.set_resp(True) 

308 

309 if ip.get_ip_df(): 

310 self.add_result("DF", "Y") 

311 else: 

312 self.add_result("DF", "N") 

313 

314 self.add_result("W", tcp.get_th_win()) 

315 

316 if tcp.get_th_ack() == self.sequence + 1: 

317 self.add_result("ACK", "S++") 

318 elif tcp.get_th_ack() == self.sequence: 

319 self.add_result("ACK", "S") 

320 else: 

321 self.add_result("ACK", "O") 

322 

323 flags = [] 

324 

325 # TCP flags 

326 if tcp.get_ECE(): 

327 flags.append("B") 

328 if tcp.get_URG(): 

329 flags.append("U") 

330 if tcp.get_ACK(): 

331 flags.append("A") 

332 if tcp.get_PSH(): 

333 flags.append("P") 

334 if tcp.get_RST(): 

335 flags.append("R") 

336 if tcp.get_SYN(): 

337 flags.append("S") 

338 if tcp.get_FIN(): 

339 flags.append("F") 

340 

341 self.add_result("FLAGS", flags) 

342 

343 options = [] 

344 

345 for op in tcp.get_options(): 

346 if op.get_kind() == TCPOption.TCPOPT_EOL: 

347 options.append("L") 

348 elif op.get_kind() == TCPOption.TCPOPT_MAXSEG: 

349 options.append("M") 

350 if op.get_mss() == self.mss: 

351 options.append("E") # Echoed 

352 elif op.get_kind() == TCPOption.TCPOPT_NOP: 

353 options.append("N") 

354 elif op.get_kind() == TCPOption.TCPOPT_TIMESTAMP: 

355 options.append("T") 

356 elif op.get_kind() == TCPOption.TCPOPT_WINDOW: 

357 options.append("W") 

358 

359 self.add_result("OPTIONS", options) 

360 

361 def get_final_result(self): 

362 return {self.test_id(): self.get_result_dict()} 

363 

364 

365class nmap2_tcp_probe(nmap_tcp_probe): 

366 acknowledgment = 0x181d4f7b 

367 

368 def __init__(self, id, addresses, tcp_ports, open_port, sequence, options): 

369 nmap_tcp_probe.__init__(self, id, addresses, tcp_ports, open_port, 

370 sequence, options) 

371 self.t.set_th_ack(self.acknowledgment) 

372 

373 def set_resp(self,resp): 

374 # Responsiveness (R) 

375 # This test simply records whether the target responded to a given probe.  

376 # Possible values are Y and N. If there is no reply, remaining fields  

377 # for the test are omitted. 

378 if resp: 

379 self.add_result("R", "Y") 

380 else: 

381 self.add_result("R", "N") 

382 

383 def process(self, packet): 

384 ip = packet.child() 

385 tcp = ip.child() 

386 

387 # R, DF, T*, TG*, W, S, A, F, O, RD*, Q 

388 self.set_resp(True) 

389 

390 tests = nmap2_tcp_tests(ip, tcp, self.sequence, self.acknowledgment) 

391 

392 self.add_result("DF", tests.get_df()) 

393 self.add_result("W", tests.get_win()) 

394 self.add_result("S", tests.get_seq()) 

395 self.add_result("A", tests.get_ack()) 

396 self.add_result("F", tests.get_flags()) 

397 self.add_result("O", tests.get_options()) 

398 self.add_result("Q", tests.get_quirks()) 

399 

400 def get_final_result(self): 

401 return {self.test_id() : self.get_result_dict()} 

402 

403 

404class nmap2_ecn_probe(nmap_tcp_probe): 

405 # From nmap-4.22SOC8/osscan2.cc: 

406 # [...] 

407 # "\003\003\012\001\002\004\005\264\004\002\001\001" 

408 # [...] 

409 

410 # From: https://nmap.org/book/osdetect-methods.html 

411 # [...] 

412 # This probe tests for explicit congestion notification (ECN) support  

413 # in the target TCP stack. ECN is a method for improving Internet  

414 # performance by allowing routers to signal congestion problems before  

415 # they start having to drop packets. It is documented in RFC 3168.  

416 # Nmap tests this by sending a SYN packet which also has the ECN CWR  

417 # and ECE congestion control flags set. For an unrelated (to ECN) test,  

418 # the urgent field value of 0xF7F5 is used even though the urgent flag  

419 # is not set. The acknowledgment number is zero, sequence number is  

420 # random, window size field is three, and the reserved bit which  

421 # immediately precedes the CWR bit is set. TCP options are WScale (10),  

422 # NOP, MSS (1460), SACK permitted, NOP, NOP. The probe is sent to an  

423 # open port. 

424 # [...] 

425 tcp_options = [ 

426 TCPOption(TCPOption.TCPOPT_WINDOW, 0o12), #\003\003\012 

427 TCPOption(TCPOption.TCPOPT_NOP), #\001 

428 TCPOption(TCPOption.TCPOPT_MAXSEG, 1460), #\002\004\005\0264 

429 TCPOption(TCPOption.TCPOPT_SACK_PERMITTED), #\004\002 

430 TCPOption(TCPOption.TCPOPT_NOP), #\001 

431 TCPOption(TCPOption.TCPOPT_NOP) #\001 

432 ] 

433 

434 

435 def __init__(self, id, addresses, tcp_ports): 

436 nmap_tcp_probe.__init__(self, id, addresses, tcp_ports, 1, 

437 0x8b6a, self.tcp_options) 

438 self.t.set_SYN() 

439 self.t.set_CWR() 

440 self.t.set_ECE() 

441 self.t.set_flags(0x800) 

442 self.t.set_th_urp(0xF7F5) 

443 self.t.set_th_ack(0) 

444 self.t.set_th_win(3) 

445 #self.t.set_th_flags(self.t.get_th_flags() | 0x0100) # 0000 0001 00000000 

446 

447 def test_id(self): 

448 return "ECN" 

449 

450 def set_resp(self,resp): 

451 if resp: 

452 self.add_result("R", "Y") 

453 else: 

454 self.add_result("R", "N") 

455 

456 def process(self, packet): 

457 ip = packet.child() 

458 tcp = ip.child() 

459 

460 # R, DF, T*, TG*, W, O, CC, Q 

461 self.set_resp(True) 

462 

463 tests = nmap2_tcp_tests(ip, tcp, 0, 0) 

464 

465 self.add_result("DF", tests.get_df()) 

466 self.add_result("W", tests.get_win()) 

467 self.add_result("O", tests.get_options()) 

468 self.add_result("CC", tests.get_cc()) 

469 self.add_result("Q", tests.get_quirks()) 

470 

471 def get_final_result(self): 

472 return {self.test_id() : self.get_result_dict()} 

473 

474class nmap2_tcp_tests: 

475 def __init__(self, ip, tcp, sequence, acknowledgment): 

476 self.__ip = ip 

477 self.__tcp = tcp 

478 self.__sequence = sequence 

479 self.__acknowledgment = acknowledgment 

480 

481 def get_df(self): 

482 # IP don't fragment bit (DF) 

483 # The IP header contains a single bit which forbids routers from fragmenting  

484 # a packet. If the packet is too large for routers to handle, they will just  

485 # have to drop it (and ideally return a "destination unreachable, 

486 # fragmentation needed" response). This test records Y if the bit is set,  

487 # and N if it isn't. 

488 if self.__ip.get_ip_df(): 

489 return "Y" 

490 else: 

491 return "N" 

492 

493 def get_win(self): 

494 # TCP initial window size (W, W1-W6) 

495 # This test simply records the 16-bit TCP window size of the received packet.  

496 return "%X" % self.__tcp.get_th_win() 

497 

498 def get_ack(self): 

499 # TCP acknowledgment number (A) 

500 # This test is the same as S except that it tests how the acknowledgment  

501 # number in the response compares to the sequence number in the  

502 # respective probe. 

503 # Value Description 

504 # Z Acknowledgment number is zero. 

505 # S Acknowledgment number is the same as the sequence number in the probe. 

506 # S+ Acknowledgment number is the same as the sequence number in the probe plus one. 

507 # O Acknowledgment number is something else (other). 

508 if self.__tcp.get_th_ack() == self.__sequence + 1: 

509 return "S+" 

510 elif self.__tcp.get_th_ack() == self.__sequence: 

511 return "S" 

512 elif self.__tcp.get_th_ack() == 0: 

513 return "Z" 

514 else: 

515 return "O" 

516 

517 def get_seq(self): 

518 # TCP sequence number (S) 

519 # This test examines the 32-bit sequence number field in the TCP  

520 # header. Rather than record the field value as some other tests  

521 # do, this one examines how it compares to the TCP acknowledgment  

522 # number from the probe that elicited the response.  

523 # Value Description 

524 # Z Sequence number is zero. 

525 # A Sequence number is the same as the acknowledgment number in the probe. 

526 # A+ Sequence number is the same as the acknowledgment number in the probe plus one. 

527 # O Sequence number is something else (other). 

528 if self.__tcp.get_th_seq() == self.__acknowledgment + 1: 

529 return "A+" 

530 elif self.__tcp.get_th_seq() == self.__acknowledgment: 

531 return "A" 

532 elif self.__tcp.get_th_seq() == 0: 

533 return "Z" 

534 else: 

535 return "O" 

536 

537 def get_flags(self): 

538 # TCP flags (F) 

539 # This field records the TCP flags in the response. Each letter represents  

540 # one flag, and they occur in the same order as in a TCP packet (from  

541 # high-bit on the left, to the low ones). So the value SA represents the  

542 # SYN and ACK bits set, while the value AS is illegal (wrong order).  

543 # The possible flags are shown in Table 8.7. 

544 # Character Flag name Flag byte value 

545 # E ECN Echo (ECE) 64 

546 # U Urgent Data (URG) 32 

547 # A Acknowledgment (ACK) 16 

548 # P Push (PSH) 8 

549 # R Reset (RST) 4 

550 # S Synchronize (SYN) 2 

551 # F Final (FIN) 1 

552 

553 flags = "" 

554 

555 if self.__tcp.get_ECE(): 

556 flags += "E" 

557 if self.__tcp.get_URG(): 

558 flags += "U" 

559 if self.__tcp.get_ACK(): 

560 flags += "A" 

561 if self.__tcp.get_PSH(): 

562 flags += "P" 

563 if self.__tcp.get_RST(): 

564 flags += "R" 

565 if self.__tcp.get_SYN(): 

566 flags += "S" 

567 if self.__tcp.get_FIN(): 

568 flags += "F" 

569 

570 return flags 

571 

572 def get_options(self): 

573 # Option Name Character Argument (if any) 

574 # End of Options List (EOL) L  

575 # No operation (NOP) N  

576 # Maximum Segment Size (MSS) M The value is appended. Many systems  

577 # echo the value used in the corresponding probe. 

578 # Window Scale (WS) W The actual value is appended. 

579 # Timestamp (TS) T The T is followed by two binary characters  

580 # representing the TSval and TSecr values respectively.  

581 # The characters are 0 if the field is zero  

582 # and 1 otherwise. 

583 # Selective ACK permitted (SACK) S  

584 

585 options = "" 

586 

587 for op in self.__tcp.get_options(): 

588 if op.get_kind() == TCPOption.TCPOPT_EOL: 

589 options += "L" 

590 elif op.get_kind() == TCPOption.TCPOPT_MAXSEG: 

591 options += "M%X" % (op.get_mss()) 

592 elif op.get_kind() == TCPOption.TCPOPT_NOP: 

593 options += "N" 

594 elif op.get_kind() == TCPOption.TCPOPT_TIMESTAMP: 

595 options += "T%i%i" % (int(op.get_ts()!=0), 

596 int(op.get_ts_echo()!=0)) 

597 elif op.get_kind() == TCPOption.TCPOPT_WINDOW: 

598 options += "W%X" % (op.get_shift_cnt()) 

599 elif op.get_kind() == TCPOption.TCPOPT_SACK_PERMITTED: 

600 options += "S" 

601 

602 return options 

603 

604 def get_cc(self): 

605 # Explicit congestion notification (CC) 

606 # This test is only used for the ECN probe. That probe is a SYN packet  

607 # which includes the CWR and ECE congestion control flags. When the  

608 # response SYN/ACK is received, those flags are examined to set the  

609 # CC (congestion control) test value as described in Table 8.3. 

610 

611 # Table 8.3. CC test values 

612 # Value Description 

613 # Y Only the ECE bit is set (not CWR). This host supports ECN. 

614 # N Neither of these two bits is set. The target does not support  

615 # ECN. 

616 # S Both bits are set. The target does not support ECN, but it  

617 # echoes back what it thinks is a reserved bit. 

618 # O The one remaining combination of these two bits (other). 

619 ece, cwr = self.__tcp.get_ECE(), self.__tcp.get_CWR() 

620 if ece and not cwr: 

621 return "Y" 

622 elif not ece and not cwr: 

623 return "N" 

624 elif ece and cwr: 

625 return "S" 

626 else: 

627 return "O" 

628 

629 def get_quirks(self): 

630 # TCP miscellaneous quirks (Q) 

631 # This tests for two quirks that a few implementations have in their  

632 # TCP stack. The first is that the reserved field in the TCP header  

633 # (right after the header length) is nonzero. This is particularly  

634 # likely to happen in response to the ECN test as that one sets a  

635 # reserved bit in the probe. If this is seen in a packet, an "R" 

636 # is recorded in the Q string. 

637 

638 # The other quirk Nmap tests for is a nonzero urgent pointer field  

639 # value when the URG flag is not set. This is also particularly  

640 # likely to be seen in response to the ECN probe, which sets a  

641 # non-zero urgent field. A "U" is appended to the Q string when  

642 # this is seen. 

643 

644 # The Q string must always be generated in alphabetical order.  

645 # If no quirks are present, the Q test is empty but still shown. 

646 

647 quirks = "" 

648 

649 if ((self.__tcp.get_th_flags() >> 8) & 0x0f) != 0: 

650 quirks += "R" 

651 if self.__tcp.get_URG() == 0 and self.__tcp.get_th_urp() != 0: 

652 quirks += "U" 

653 

654 return quirks 

655 

656class nmap2_tcp_probe_2_6(nmap2_tcp_probe): 

657 sequence = 0x8453 # 0xBASE, obviously 

658 mss = 265 

659 

660 # From nmap-4.22SOC8/osscan2.cc: 

661 # [...] 

662 # "\003\003\012\001\002\004\001\011\010\012\377\377\377\377\000\000\000\000\004\002" 

663 # [...] 

664 

665 # From: https://nmap.org/book/osdetect-methods.html 

666 # [...] 

667 # The six T2 through T7 tests each send one TCP probe packet.  

668 # With one exception, the TCP options data in each case is (in hex)  

669 # 03030A0102040109080AFFFFFFFF000000000402.  

670 # Those 20 bytes correspond to window scale (10), NOP, MSS (265),  

671 # Timestamp (TSval: 0xFFFFFFFF; TSecr: 0), then SACK permitted.  

672 # (... 

673 tcp_options = [ 

674 TCPOption(TCPOption.TCPOPT_WINDOW, 0o12), #\003\003\012 

675 TCPOption(TCPOption.TCPOPT_NOP), #\001 

676 TCPOption(TCPOption.TCPOPT_MAXSEG, mss), #\002\004\001\011 

677 TCPOption(TCPOption.TCPOPT_TIMESTAMP, 0xFFFFFFFF), #\010\012\377\377\377\377\000\000\000\000 

678 TCPOption(TCPOption.TCPOPT_SACK_PERMITTED) #\004\002 

679 ] 

680 

681 def __init__(self, id, addresses, tcp_ports, open_port): 

682 nmap2_tcp_probe.__init__(self, id, addresses, tcp_ports, open_port, 

683 self.sequence, self.tcp_options) 

684 

685class nmap2_tcp_probe_7(nmap2_tcp_probe): 

686 sequence = 0x8453 # 0xBASE, obviously 

687 mss = 265 

688 

689 # ...) 

690 # The exception is that T7 uses a Window scale value of 15 rather than 10 

691 # [...] 

692 tcp_options = [ 

693 TCPOption(TCPOption.TCPOPT_WINDOW, 0o17), #\003\003\017 

694 TCPOption(TCPOption.TCPOPT_NOP), #\001 

695 TCPOption(TCPOption.TCPOPT_MAXSEG, mss), #\002\004\001\011 

696 TCPOption(TCPOption.TCPOPT_TIMESTAMP, 0xFFFFFFFF), #\010\012\377\377\377\377\000\000\000\000 

697 TCPOption(TCPOption.TCPOPT_SACK_PERMITTED) #\004\002 

698 ] 

699 

700 def __init__(self, id, addresses, tcp_ports, open_port): 

701 nmap2_tcp_probe.__init__(self, id, addresses, tcp_ports, open_port, 

702 self.sequence, self.tcp_options) 

703 

704class nmap_port_unreachable(udp_closed_probe): 

705 

706 def __init__(self, id, addresses, ports): 

707 udp_closed_probe.__init__(self, id, addresses, ports[2]) 

708 self.set_resp(False) 

709 

710 def test_id(self): 

711 pass 

712 

713 def set_resp(self, resp): 

714 pass 

715 

716 def process(self, packet): 

717 pass 

718 

719class nmap1_port_unreachable(nmap_port_unreachable): 

720 

721 def __init__(self, id, addresses, ports): 

722 nmap_port_unreachable.__init__(self, id, addresses, ports) 

723 self.u.contains(Data("A" * 300)) 

724 

725 def test_id(self): 

726 return "PU" 

727 

728 def set_resp(self,resp): 

729 if resp: 

730 self.add_result("Resp", "Y") 

731 else: 

732 self.add_result("Resp", "N") 

733 

734 def process(self, packet): 

735 ip_orig = self.err_data 

736 if ip_orig.get_ip_p() != UDP.protocol: 

737 return 

738 

739 udp = ip_orig.child() 

740 

741 if not udp: 

742 return 

743 

744 ip = packet.child() 

745 

746 self.set_resp(True) 

747 

748 if ip.get_ip_df(): 

749 self.add_result("DF", "Y") 

750 else: 

751 self.add_result("DF", "N") 

752 

753 self.add_result("TOS", ip.get_ip_tos()) 

754 

755 self.add_result("IPLEN", ip.get_ip_len()) 

756 

757 self.add_result("RIPTL", ip_orig.get_ip_len()) # Some systems return a different IPLEN 

758 

759 recv_ip_id = ip_orig.get_ip_id() 

760 if 0 == recv_ip_id: 

761 self.add_result("RID", "0") 

762 elif udp_closed_probe.ip_id == recv_ip_id: 

763 self.add_result("RID", "E") 

764 else: 

765 self.add_result("RID", "F") 

766 

767 ip_sum = ip_orig.get_ip_sum() 

768 ip_orig.set_ip_sum(0) 

769 checksum = ip_orig.compute_checksum(ip_orig.get_bytes()) 

770 

771 if 0 == checksum: 

772 self.add_result("RIPCK", "0") 

773 elif checksum == ip_sum: 

774 self.add_result("RIPCK", "E") 

775 else: 

776 self.add_result("RIPCK", "F") 

777 

778 udp_sum = udp.get_uh_sum() 

779 udp.set_uh_sum(0) 

780 udp.auto_checksum = 1 

781 udp.calculate_checksum() 

782 

783 if 0 == udp_sum: 

784 self.add_result("UCK", "0") 

785 elif self.u.get_uh_sum() == udp_sum: 

786 self.add_result("UCK", "E") 

787 else: 

788 self.add_result("UCK", "F") 

789 

790 self.add_result("ULEN", udp.get_uh_ulen()) 

791 

792 if ip.child().child().child().child() == udp.child(): # Some systems meddle with the data 

793 self.add_result("DAT", "E") 

794 else: 

795 self.add_result("DAT", "F") 

796 

797 def get_final_result(self): 

798 return {self.test_id(): self.get_result_dict()} 

799 

800class nmap2_port_unreachable(nmap_port_unreachable): 

801 # UDP (U1) 

802 # This probe is a UDP packet sent to a closed port. The character 'C' 

803 # (0x43) is repeated 300 times for the data field. The IP ID value is  

804 # set to 0x1042 for operating systems which allow us to set this. If  

805 # the port is truly closed and there is no firewall in place, Nmap  

806 # expects to receive an ICMP port unreachable message in return.  

807 # That response is then subjected to the R, DF, T, TG, TOS, IPL, UN,  

808 # RIPL, RID, RIPCK, RUCK, RUL, and RUD tests.  

809 def __init__(self, id, addresses, ports): 

810 nmap_port_unreachable.__init__(self, id, addresses, ports) 

811 self.u.contains(Data("C" * 300)) 

812 self.i.set_ip_id(0x1042) 

813 

814 def test_id(self): 

815 return "U1" 

816 

817 def set_resp(self,resp): 

818 if resp: 

819 self.add_result("R", "Y") 

820 else: 

821 self.add_result("R", "N") 

822 

823 def process(self, packet): 

824 ip_orig = self.err_data 

825 if ip_orig.get_ip_p() != UDP.protocol: 

826 return 

827 

828 udp = ip_orig.child() 

829 

830 if not udp: 

831 return 

832 

833 ip = packet.child() 

834 

835 icmp = ip.child() 

836 

837 if ip.get_ip_df(): 

838 self.add_result("DF", "Y") 

839 else: 

840 self.add_result("DF", "N") 

841 

842 # XXX T 

843 # IP initial time-to-live (T) 

844 # IP packets contain a field named time-to-live (TTL) which is  

845 # decremented every time they traverse a router. If the field  

846 # reaches zero, the packet must be discarded. This prevents  

847 # packets from looping endlessly. Because operating systems differ  

848 # on which TTL they start with, it can be used for OS detection.  

849 # Nmap determines how many hops away it is from the target by  

850 # examining the ICMP port unreachable response to the U1 probe.  

851 # That response includes the original IP packet, including the  

852 # already-decremented TTL field, received by the target. By  

853 # subtracting that value from our as-sent TTL, we learn how many  

854 # hops away the machine is. Nmap then adds that hop distance to  

855 # the probe response TTL to determine what the initial TTL was  

856 # when that ICMP probe response packet was sent. That initial TTL  

857 # value is stored in the fingerprint as the T result. 

858 # Even though an eight-bit field like TTL can never hold values  

859 # greater than 0xFF, this test occasionally results in values of  

860 # 0x100 or higher. This occurs when a system (could be the source,  

861 # a target, or a system in between) corrupts or otherwise fails to 

862 # correctly decrement the TTL. It can also occur due to asymmetric  

863 # routes. 

864 

865 # XXX TG 

866 # IP initial time-to-live guess (TG) 

867 # It is not uncommon for Nmap to receive no response to the U1 probe,  

868 # which prevents Nmap from learning how many hops away a target is.  

869 # Firewalls and NAT devices love to block unsolicited UDP packets.  

870 # But since common TTL values are spread well apart and targets are  

871 # rarely more than 20 hops away, Nmap can make a pretty good guess  

872 # anyway. Most systems send packets with an initial TTL of 32, 60, 64,  

873 # 128, or 255. So the TTL value received in the response is rounded  

874 # up to the next value out of 32, 64, 128, or 255. 60 is not in that  

875 # list because it cannot be reliably distinguished from 64. It is  

876 # rarely seen anyway.  

877 # The resulting guess is stored in the TG field. This TTL guess field  

878 # is not printed in a subject fingerprint if the actual TTL (T) value  

879 # was discovered. 

880 

881 # IP type of service (TOS) 

882 # This test simply records the type of service byte from the  

883 # IP header of ICMP port unreachable packets.  

884 # This byte is described in RFC 791 

885 self.add_result("TOS", "%X" % ip.get_ip_tos()) 

886 

887 # IP total length (IPL) 

888 # This test records the total length (in octets) of an IP packet.  

889 # It is only used for the port unreachable response elicited by the  

890 # U1 test. 

891 self.add_result("IPL", "%X" % ip.get_ip_len()) 

892 

893 # Unused port unreachable field nonzero (UN) 

894 # An ICMP port unreachable message header is eight bytes long, but  

895 # only the first four are used. RFC 792 states that the last four  

896 # bytes must be zero. A few implementations (mostly ethernet switches  

897 # and some specialized embedded devices) set it anyway. The value of  

898 # those last four bytes is recorded in this field. 

899 self.add_result("UN", "%X" % icmp.get_icmp_void()) 

900 

901 # Returned probe IP total length value (RIPL) 

902 # ICMP port unreachable messages (as are sent in response to the U1  

903 # probe) are required to include the IP header which generated them.  

904 # This header should be returned just as they received it, but some  

905 # implementations send back a corrupted version due to changes they  

906 # made during IP processing. This test simply records the returned  

907 # IP total length value. If the correct value of 0x148 (328) is  

908 # returned, the value G (for good) is stored instead of the actual value. 

909 if ip_orig.get_ip_len() == 0x148: 

910 self.add_result("RIPL","G") 

911 else: 

912 self.add_result("RIPL", "%X" % ip_orig.get_ip_len()) 

913 

914 # Returned probe IP ID value (RID) 

915 # The U1 probe has a static IP ID value of 0x1042. If that value is  

916 # returned in the port unreachable message, the value G is stored for  

917 # this test. Otherwise the exact value returned is stored. Some systems,  

918 # such as Solaris, manipulate IP ID values for raw IP packets that  

919 # Nmap sends. In such cases, this test is skipped. We have found  

920 # that some systems, particularly HP and Xerox printers, flip the bytes  

921 # and return 0x4210 instead.  

922 if 0x1042 == ip_orig.get_ip_id(): 

923 self.add_result("RID", "G") 

924 else: 

925 self.add_result("RID", "%X" % ip_orig.get_ip_id()) 

926 

927 # Integrity of returned probe IP checksum value (RIPCK) 

928 # The IP checksum is one value that we don't expect to remain the same  

929 # when returned in a port unreachable message. After all, each network  

930 # hop during transit changes the checksum as the TTL is decremented.  

931 # However, the checksum we receive should match the enclosing IP packet.  

932 # If it does, the value G (good) is stored for this test. If the returned  

933 # value is zero, then Z is stored. Otherwise the result is I (invalid). 

934 ip_sum = ip_orig.get_ip_sum() 

935 ip_orig.set_ip_sum(0) 

936 checksum = ip_orig.compute_checksum(ip_orig.get_bytes()) 

937 

938 if 0 == checksum: 

939 self.add_result("RIPCK", "Z") 

940 elif checksum == ip_sum: 

941 self.add_result("RIPCK", "G") 

942 else: 

943 self.add_result("RIPCK", "I") 

944 

945 # Integrity of returned probe UDP length and checksum (RUL and RUCK) 

946 # The UDP header length and checksum values should be returned exactly  

947 # as they were sent. If so, G is recorded for these tests. Otherwise  

948 # the value actually returned is recorded. The proper length is 0x134 (308). 

949 udp_sum = udp.get_uh_sum() 

950 udp.set_uh_sum(0) 

951 udp.auto_checksum = 1 

952 udp.calculate_checksum() 

953 

954 if self.u.get_uh_sum() == udp_sum: 

955 self.add_result("RUCK", "G") 

956 else: 

957 self.add_result("RUCK", "%X" % udp_sum) 

958 

959 if udp.get_uh_ulen() == 0x134: 

960 self.add_result("RUL","G") 

961 else: 

962 self.add_result("RUL", "%X" % udp.get_uh_ulen()) 

963 

964 # Integrity of returned UDP data (RUD) 

965 # If the UDP payload returned consists of 300 'C' (0x43)  

966 # characters as expected, a G is recorded for this test.  

967 # Otherwise I (invalid) is recorded. 

968 if ip.child().child().child().child() == udp.child(): 

969 self.add_result("RUD", "G") 

970 else: 

971 self.add_result("RUD", "I") 

972 

973 def get_final_result(self): 

974 return {self.test_id(): self.get_result_dict()} 

975 

976class OS_ID: 

977 

978 def __init__(self, target, ports): 

979 pcap_dev = lookupdev() 

980 self.p = open_live(pcap_dev, 600, 0, 3000) 

981 

982 self.__source = self.p.getlocalip() 

983 self.__target = target 

984 

985 self.p.setfilter("src host %s and dst host %s" % (target, self.__source), 1, 0xFFFFFF00) 

986 self.p.setmintocopy(10) 

987 self.decoder = EthDecoder() 

988 

989 self.tests_sent = [] 

990 self.outstanding_count = 0 

991 self.results = {} 

992 self.current_id = 12345 

993 

994 self.__ports = ports 

995 

996 def releasePcap(self): 

997 if not (self.p is None): 

998 self.p.close() 

999 

1000 def get_new_id(self): 

1001 id = self.current_id 

1002 self.current_id += 1 

1003 self.current_id &= 0xFFFF 

1004 return id 

1005 

1006 def send_tests(self, tests): 

1007 self.outstanding_count = 0 

1008 

1009 for t_class in tests: 

1010 

1011 # Ok, I need to know if the constructor accepts the parameter port 

1012 # We could ask also by co_varnames, but the port parameters is not a standarized... asking by args count :( 

1013 if t_class.__init__.im_func.func_code.co_argcount == 4: 

1014 test = t_class(self.get_new_id(), [self.__source, self.__target], self.__ports ) 

1015 else: 

1016 test = t_class(self.get_new_id(), [self.__source, self.__target] ) 

1017 

1018 self.p.sendpacket(test.get_test_packet()) 

1019 self.outstanding_count += 1 

1020 self.tests_sent.append(test) 

1021 while self.p.readready(): 

1022 self.p.dispatch(1, self.packet_handler) 

1023 

1024 while self.outstanding_count > 0: 

1025 data = self.p.next()[0] 

1026 if data: 

1027 self.packet_handler(0, data) 

1028 else: 

1029 break 

1030 

1031 def run(self): 

1032 pass 

1033 

1034 def get_source(self): 

1035 return self.__source 

1036 

1037 def get_target(self): 

1038 return self.__target 

1039 

1040 def get_ports(self): 

1041 return self.__ports 

1042 

1043 def packet_handler(self, len, data): 

1044 packet = self.decoder.decode(data) 

1045 

1046 for t in self.tests_sent: 

1047 if t.is_mine(packet): 

1048 t.process(packet) 

1049 self.outstanding_count -= 1 

1050 

1051 

1052class nmap1_tcp_open_1(nmap1_tcp_probe): 

1053 def __init__(self, id, addresses, tcp_ports): 

1054 nmap1_tcp_probe.__init__(self, id, addresses, tcp_ports, 1) 

1055 self.t.set_ECE() 

1056 self.t.set_SYN() 

1057 

1058 def test_id(self): 

1059 return "T1" 

1060 

1061 def is_mine(self, packet): 

1062 if tcp_probe.is_mine(self, packet): 

1063 ip = packet.child() 

1064 if not ip: 

1065 return 0 

1066 tcp = ip.child() 

1067 if not tcp: 

1068 return 0 

1069 if tcp.get_SYN() and tcp.get_ACK(): 

1070 return 1 

1071 else: 

1072 return 0 

1073 else: 

1074 return 0 

1075 

1076 

1077class nmap1_tcp_open_2(nmap1_tcp_probe): 

1078 def __init__(self, id, addresses, tcp_ports): 

1079 nmap1_tcp_probe.__init__(self, id, addresses, tcp_ports, 1) 

1080 

1081 def test_id(self): 

1082 return "T2" 

1083 

1084class nmap2_tcp_open_2(nmap2_tcp_probe_2_6): 

1085 # From: https://nmap.org/book/osdetect-methods.html 

1086 # [...] 

1087 # T2 sends a TCP null (no flags set) packet with the IP DF bit set and a  

1088 # window field of 128 to an open port. 

1089 # ... 

1090 def __init__(self, id, addresses, tcp_ports): 

1091 nmap2_tcp_probe_2_6.__init__(self, id, addresses, tcp_ports, 1) 

1092 self.i.set_ip_df(1) 

1093 self.t.set_th_win(128) 

1094 

1095 def test_id(self): 

1096 return "T2" 

1097 

1098class nmap1_tcp_open_3(nmap1_tcp_probe): 

1099 def __init__(self, id, addresses, tcp_ports ): 

1100 nmap1_tcp_probe.__init__(self, id, addresses, tcp_ports, 1) 

1101 self.t.set_SYN() 

1102 self.t.set_FIN() 

1103 self.t.set_URG() 

1104 self.t.set_PSH() 

1105 

1106 def test_id(self): 

1107 return "T3" 

1108 

1109class nmap2_tcp_open_3(nmap2_tcp_probe_2_6): 

1110 # ... 

1111 # T3 sends a TCP packet with the SYN, FIN, URG, and PSH flags set and a  

1112 # window field of 256 to an open port. The IP DF bit is not set. 

1113 # ... 

1114 def __init__(self, id, addresses, tcp_ports ): 

1115 nmap2_tcp_probe_2_6.__init__(self, id, addresses, tcp_ports, 1) 

1116 self.t.set_SYN() 

1117 self.t.set_FIN() 

1118 self.t.set_URG() 

1119 self.t.set_PSH() 

1120 self.t.set_th_win(256) 

1121 self.i.set_ip_df(0) 

1122 

1123 def test_id(self): 

1124 return "T3" 

1125 

1126class nmap1_tcp_open_4(nmap1_tcp_probe): 

1127 def __init__(self, id, addresses, tcp_ports): 

1128 nmap1_tcp_probe.__init__(self, id, addresses, tcp_ports, 1) 

1129 self.t.set_ACK() 

1130 

1131 def test_id(self): 

1132 return "T4" 

1133 

1134class nmap2_tcp_open_4(nmap2_tcp_probe_2_6): 

1135 # ... 

1136 # T4 sends a TCP ACK packet with IP DF and a window field of 1024 to  

1137 # an open port. 

1138 # ... 

1139 def __init__(self, id, addresses, tcp_ports ): 

1140 nmap2_tcp_probe_2_6.__init__(self, id, addresses, tcp_ports, 1) 

1141 self.t.set_ACK() 

1142 self.i.set_ip_df(1) 

1143 self.t.set_th_win(1024) 

1144 

1145 def test_id(self): 

1146 return "T4" 

1147 

1148 

1149class nmap1_seq(nmap1_tcp_probe): 

1150 SEQ_UNKNOWN = 0 

1151 SEQ_64K = 1 

1152 SEQ_TD = 2 

1153 SEQ_RI = 4 

1154 SEQ_TR = 8 

1155 SEQ_i800 = 16 

1156 SEQ_CONSTANT = 32 

1157 

1158 TS_SEQ_UNKNOWN = 0 

1159 TS_SEQ_ZERO = 1 # At least one of the timestamps we received back was 0 

1160 TS_SEQ_2HZ = 2 

1161 TS_SEQ_100HZ = 3 

1162 TS_SEQ_1000HZ = 4 

1163 TS_SEQ_UNSUPPORTED = 5 # System didn't send back a timestamp 

1164 

1165 IPID_SEQ_UNKNOWN = 0 

1166 IPID_SEQ_INCR = 1 # simple increment by one each time 

1167 IPID_SEQ_BROKEN_INCR = 2 # Stupid MS -- forgot htons() so it counts by 256 on little-endian platforms 

1168 IPID_SEQ_RPI = 3 # Goes up each time but by a "random" positive increment 

1169 IPID_SEQ_RD = 4 # Appears to select IPID using a "random" distributions (meaning it can go up or down) 

1170 IPID_SEQ_CONSTANT = 5 # Contains 1 or more sequential duplicates 

1171 IPID_SEQ_ZERO = 6 # Every packet that comes back has an IP.ID of 0 (eg Linux 2.4 does this) 

1172 

1173 def __init__(self, id, addresses, tcp_ports): 

1174 nmap1_tcp_probe.__init__(self, id, addresses, tcp_ports, 1) 

1175 self.t.set_SYN() 

1176 self.t.set_th_seq(id) # Used to match results with sent packets. 

1177 

1178 def process(self, p): 

1179 raise Exception("Method process is meaningless for class %s." % self.__class__.__name__) 

1180 

1181 

1182class nmap2_seq(nmap2_tcp_probe): 

1183 TS_SEQ_UNKNOWN = 0 

1184 TS_SEQ_ZERO = 1 # At least one of the timestamps we received back was 0 

1185 TS_SEQ_UNSUPPORTED = 5 # System didn't send back a timestamp 

1186 

1187 IPID_SEQ_UNKNOWN = 0 

1188 IPID_SEQ_INCR = 1 # simple increment by one each time 

1189 IPID_SEQ_BROKEN_INCR = 2 # Stupid MS -- forgot htons() so it counts by 256 on little-endian platforms 

1190 IPID_SEQ_RPI = 3 # Goes up each time but by a "random" positive increment 

1191 IPID_SEQ_RD = 4 # Appears to select IPID using a "random" distributions (meaning it can go up or down) 

1192 IPID_SEQ_CONSTANT = 5 # Contains 1 or more sequential duplicates 

1193 IPID_SEQ_ZERO = 6 # Every packet that comes back has an IP.ID of 0 (eg Linux 2.4 does this) 

1194 

1195 def __init__(self, id, addresses, tcp_ports, options): 

1196 nmap2_tcp_probe.__init__(self, id, addresses, tcp_ports, 1, 

1197 id, options) 

1198 self.t.set_SYN() 

1199 

1200 def process(self, p): 

1201 raise Exception("Method process is meaningless for class %s." % self.__class__.__name__) 

1202 

1203class nmap2_seq_1(nmap2_seq): 

1204 # Packet #1: window scale (10),  

1205 # NOP,  

1206 # MSS (1460),  

1207 # timestamp (TSval: 0xFFFFFFFF; TSecr: 0),  

1208 # SACK permitted.  

1209 # The window field is 1. 

1210 tcp_options = [ 

1211 TCPOption(TCPOption.TCPOPT_WINDOW, 10), 

1212 TCPOption(TCPOption.TCPOPT_NOP), 

1213 TCPOption(TCPOption.TCPOPT_MAXSEG, 1460), 

1214 TCPOption(TCPOption.TCPOPT_TIMESTAMP, 0xFFFFFFFF), 

1215 TCPOption(TCPOption.TCPOPT_SACK_PERMITTED) 

1216 ] 

1217 

1218 def __init__(self, id, addresses, tcp_ports): 

1219 nmap2_seq.__init__(self, id, addresses, tcp_ports, self.tcp_options) 

1220 self.t.set_th_win(1) 

1221 

1222class nmap2_seq_2(nmap2_seq): 

1223 # Packet #2: MSS (1400),  

1224 # window scale (0),  

1225 # SACK permitted,  

1226 # timestamp (TSval: 0xFFFFFFFF; TSecr: 0),  

1227 # EOL.  

1228 # The window field is 63. 

1229 tcp_options = [ 

1230 TCPOption(TCPOption.TCPOPT_MAXSEG, 1400), 

1231 TCPOption(TCPOption.TCPOPT_WINDOW, 0), 

1232 TCPOption(TCPOption.TCPOPT_SACK_PERMITTED), 

1233 TCPOption(TCPOption.TCPOPT_TIMESTAMP, 0xFFFFFFFF), 

1234 TCPOption(TCPOption.TCPOPT_EOL) 

1235 ] 

1236 

1237 def __init__(self, id, addresses, tcp_ports): 

1238 nmap2_seq.__init__(self, id, addresses, tcp_ports, self.tcp_options) 

1239 self.t.set_th_win(63) 

1240 

1241class nmap2_seq_3(nmap2_seq): 

1242 # Packet #3: Timestamp (TSval: 0xFFFFFFFF; TSecr: 0),  

1243 # NOP,  

1244 # NOP,  

1245 # window scale (5),  

1246 # NOP,  

1247 # MSS (640).  

1248 # The window field is 4. 

1249 tcp_options = [ 

1250 TCPOption(TCPOption.TCPOPT_TIMESTAMP, 0xFFFFFFFF), 

1251 TCPOption(TCPOption.TCPOPT_NOP), 

1252 TCPOption(TCPOption.TCPOPT_NOP), 

1253 TCPOption(TCPOption.TCPOPT_WINDOW, 5), 

1254 TCPOption(TCPOption.TCPOPT_NOP), 

1255 TCPOption(TCPOption.TCPOPT_MAXSEG, 640) 

1256 ] 

1257 

1258 def __init__(self, id, addresses, tcp_ports): 

1259 nmap2_seq.__init__(self, id, addresses, tcp_ports, self.tcp_options) 

1260 self.t.set_th_win(4) 

1261 

1262class nmap2_seq_4(nmap2_seq): 

1263 # Packet #4: SACK permitted,  

1264 # Timestamp (TSval: 0xFFFFFFFF; TSecr: 0),  

1265 # window scale (10),  

1266 # EOL.  

1267 # The window field is 4. 

1268 tcp_options = [ 

1269 TCPOption(TCPOption.TCPOPT_SACK_PERMITTED), 

1270 TCPOption(TCPOption.TCPOPT_TIMESTAMP, 0xFFFFFFFF), 

1271 TCPOption(TCPOption.TCPOPT_WINDOW, 10), 

1272 TCPOption(TCPOption.TCPOPT_EOL) 

1273 ] 

1274 

1275 def __init__(self, id, addresses, tcp_ports): 

1276 nmap2_seq.__init__(self, id, addresses, tcp_ports, self.tcp_options) 

1277 self.t.set_th_win(4) 

1278 

1279class nmap2_seq_5(nmap2_seq): 

1280 # Packet #5: MSS (536),  

1281 # SACK permitted, 

1282 # Timestamp (TSval: 0xFFFFFFFF; TSecr: 0),  

1283 # window scale (10),  

1284 # EOL.  

1285 # The window field is 16. 

1286 tcp_options = [ 

1287 TCPOption(TCPOption.TCPOPT_MAXSEG, 536), 

1288 TCPOption(TCPOption.TCPOPT_SACK_PERMITTED), 

1289 TCPOption(TCPOption.TCPOPT_TIMESTAMP, 0xFFFFFFFF), 

1290 TCPOption(TCPOption.TCPOPT_WINDOW, 10), 

1291 TCPOption(TCPOption.TCPOPT_EOL) 

1292 ] 

1293 

1294 def __init__(self, id, addresses, tcp_ports): 

1295 nmap2_seq.__init__(self, id, addresses, tcp_ports, self.tcp_options) 

1296 self.t.set_th_win(16) 

1297 

1298class nmap2_seq_6(nmap2_seq): 

1299 # Packet #6: MSS (265),  

1300 # SACK permitted,  

1301 # Timestamp (TSval: 0xFFFFFFFF; TSecr: 0).  

1302 # The window field is 512. 

1303 tcp_options = [ 

1304 TCPOption(TCPOption.TCPOPT_MAXSEG, 265), 

1305 TCPOption(TCPOption.TCPOPT_SACK_PERMITTED), 

1306 TCPOption(TCPOption.TCPOPT_TIMESTAMP, 0xFFFFFFFF) 

1307 ] 

1308 

1309 def __init__(self, id, addresses, tcp_ports): 

1310 nmap2_seq.__init__(self, id, addresses, tcp_ports, self.tcp_options) 

1311 self.t.set_th_win(512) 

1312 

1313class nmap1_seq_container(os_id_test): 

1314 def __init__(self, num_seq_samples, responses, seq_diffs, ts_diffs, time_diffs): 

1315 os_id_test.__init__(self, 0) 

1316 

1317 self.num_seq_samples = num_seq_samples 

1318 self.seq_responses = responses 

1319 self.seq_num_responses = len(responses) 

1320 self.seq_diffs = seq_diffs 

1321 self.ts_diffs = ts_diffs 

1322 self.time_diffs = time_diffs 

1323 self.pre_ts_seqclass = nmap1_seq.TS_SEQ_UNKNOWN 

1324 

1325 def test_id(self): 

1326 return "TSEQ" 

1327 

1328 def set_ts_seqclass(self, ts_seqclass): 

1329 self.pre_ts_seqclass = ts_seqclass 

1330 

1331 def process(self): 

1332 ipid_seqclass = self.ipid_sequence() 

1333 if nmap1_seq.TS_SEQ_UNKNOWN != self.pre_ts_seqclass: 

1334 ts_seqclass = self.pre_ts_seqclass 

1335 else: 

1336 ts_seqclass = self.ts_sequence() 

1337 

1338 if self.seq_num_responses >= 4: 

1339 seq_seqclass = self.seq_sequence() 

1340 if nmap1_seq.SEQ_UNKNOWN != seq_seqclass: 

1341 self.add_seqclass(seq_seqclass) 

1342 if nmap1_seq.IPID_SEQ_UNKNOWN != ipid_seqclass: 

1343 self.add_ipidclass(ipid_seqclass) 

1344 if nmap1_seq.TS_SEQ_UNKNOWN != ts_seqclass: 

1345 self.add_tsclass(ts_seqclass) 

1346 else: 

1347 LOG.error("Insufficient responses for TCP sequencing (%d out of %d), OS detection may be less accurate." 

1348 % (self.seq_num_responses, self.num_seq_samples)) 

1349 

1350 def get_final_result(self): 

1351 "Returns a string representation of the final result of this test or None if no response was received" 

1352 return {self.test_id(): self.get_result_dict()} 

1353 

1354 def ipid_sequence(self): 

1355 if self.seq_num_responses < 2: 

1356 return nmap1_seq.IPID_SEQ_UNKNOWN 

1357 

1358 ipid_diffs = array.array('H', [0] * (self.seq_num_responses - 1)) 

1359 

1360 null_ipids = 1 

1361 for i in xrange(1, self.seq_num_responses): 

1362 prev_ipid = self.seq_responses[i-1].get_ipid() 

1363 cur_ipid = self.seq_responses[i].get_ipid() 

1364 

1365 if cur_ipid < prev_ipid and (cur_ipid > 500 or prev_ipid < 65000): 

1366 return nmap1_seq.IPID_SEQ_RD 

1367 

1368 if prev_ipid != 0 or cur_ipid != 0: 

1369 null_ipids = 0 

1370 ipid_diffs[i-1] = abs(cur_ipid - prev_ipid) 

1371 

1372 if null_ipids: 

1373 return nmap1_seq.IPID_SEQ_ZERO 

1374 

1375 # Battle plan: 

1376 # If any diff is > 1000, set to random, if 0, set to constant. 

1377 # If any of the diffs are 1, or all are less than 9, set to incremental. 

1378 

1379 for i in xrange(0, self.seq_num_responses - 1): 

1380 if ipid_diffs[i] > 1000: 

1381 return nmap1_seq.IPID_SEQ_RPI 

1382 if ipid_diffs[i] == 0: 

1383 return nmap1_seq.IPID_SEQ_CONSTANT 

1384 

1385 is_incremental = 1 # All diferences are less than 9 

1386 is_ms = 1 # All diferences are multiples of 256 

1387 for i in xrange(0, self.seq_num_responses - 1): 

1388 if ipid_diffs[i] == 1: 

1389 return nmap1_seq.IPID_SEQ_INCR 

1390 if is_ms and ipid_diffs[i] < 2560 and (ipid_diffs[i] % 256) != 0: 

1391 is_ms = 0 

1392 if ipid_diffs[i] > 9: 

1393 is_incremental = 0 

1394 

1395 if is_ms: 

1396 return nmap1_seq.IPID_SEQ_BROKEN_INCR 

1397 if is_incremental: 

1398 return nmap1_seq.IPID_SEQ_INCR 

1399 

1400 return nmap1_seq.IPID_SEQ_UNKNOWN 

1401 

1402 def ts_sequence(self): 

1403 if self.seq_num_responses < 2: 

1404 return nmap1_seq.TS_SEQ_UNKNOWN 

1405 

1406 # Battle plan: 

1407 # 1) Compute average increments per second, and variance in incr. per second. 

1408 # 2) If any are 0, set to constant. 

1409 # 3) If variance is high, set to random incr. [ skip for now ] 

1410 # 4) if ~10/second, set to appropriate thing. 

1411 # 5) Same with ~100/s. 

1412 

1413 avg_freq = 0.0 

1414 for i in xrange(0, self.seq_num_responses - 1): 

1415 dhz = self.ts_diffs[i] / self.time_diffs[i] 

1416 avg_freq += dhz / (self.seq_num_responses - 1) 

1417 

1418 LOG.info("The avg TCP TS HZ is: %f" % avg_freq) 

1419 

1420 if 0 < avg_freq < 3.9: 

1421 return nmap1_seq.TS_SEQ_2HZ 

1422 if 85 < avg_freq < 115: 

1423 return nmap1_seq.TS_SEQ_100HZ 

1424 if 900 < avg_freq < 1100: 

1425 return nmap1_seq.TS_SEQ_1000HZ 

1426 

1427 return nmap1_seq.TS_SEQ_UNKNOWN 

1428 

1429 def seq_sequence(self): 

1430 self.seq_gcd = reduce(my_gcd, self.seq_diffs) 

1431 avg_incr = 0 

1432 seqclass = nmap1_seq.SEQ_UNKNOWN 

1433 

1434 if 0 != self.seq_gcd: 

1435 map(lambda x, gcd = self.seq_gcd: x / gcd, self.seq_diffs) 

1436 for i in xrange(0, self.seq_num_responses - 1): 

1437 if abs(self.seq_responses[i+1].get_seq() - self.seq_responses[i].get_seq()) > 50000000: 

1438 seqclass = nmap1_seq.SEQ_TR; 

1439 self.index = 9999999 

1440 break 

1441 avg_incr += self.seq_diffs[i] 

1442 

1443 if 0 == self.seq_gcd: 

1444 seqclass = nmap1_seq.SEQ_CONSTANT 

1445 self.index = 0 

1446 elif 0 == self.seq_gcd % 64000: 

1447 seqclass = nmap1_seq.SEQ_64K 

1448 self.index = 1 

1449 elif 0 == self.seq_gcd % 800: 

1450 seqclass = nmap1_seq.SEQ_i800 

1451 self.index = 10 

1452 elif nmap1_seq.SEQ_UNKNOWN == seqclass: 

1453 avg_incr = int(.5 + avg_incr / (self.seq_num_responses - 1)) 

1454 sum_incr = 0.0 

1455 for i in range(0, self.seq_num_responses - 1): 

1456 d = abs(self.seq_diffs[i] - avg_incr) 

1457 sum_incr += float(d * d) 

1458 sum_incr /= self.seq_num_responses - 1 

1459 self.index = int(.5 + math.sqrt(sum_incr)) 

1460 if self.index < 75: 

1461 seqclass = nmap1_seq.SEQ_TD 

1462 else: 

1463 seqclass = nmap1_seq.SEQ_RI 

1464 

1465 return seqclass 

1466 

1467 seqclasses = { 

1468 nmap1_seq.SEQ_64K: '64K', 

1469 nmap1_seq.SEQ_TD: 'TD', 

1470 nmap1_seq.SEQ_RI: 'RI', 

1471 nmap1_seq.SEQ_TR: 'TR', 

1472 nmap1_seq.SEQ_i800: 'i800', 

1473 nmap1_seq.SEQ_CONSTANT: 'C', 

1474 } 

1475 

1476 def add_seqclass(self, id): 

1477 self.add_result('CLASS', nmap1_seq_container.seqclasses[id]) 

1478 

1479 if nmap1_seq.SEQ_CONSTANT == id: 

1480 self.add_result('VAL', '%i' % self.seq_responses[0].get_seq()) 

1481 elif id in (nmap1_seq.SEQ_TD, nmap1_seq.SEQ_RI): 

1482 self.add_result('GCD', '%i' % self.seq_gcd) 

1483 self.add_result('SI', '%i' % self.index) 

1484 

1485 tsclasses = { 

1486 nmap1_seq.TS_SEQ_ZERO: '0', 

1487 nmap1_seq.TS_SEQ_2HZ: '2HZ', 

1488 nmap1_seq.TS_SEQ_100HZ: '100HZ', 

1489 nmap1_seq.TS_SEQ_1000HZ: '1000HZ', 

1490 nmap1_seq.TS_SEQ_UNSUPPORTED: 'U', 

1491 } 

1492 

1493 def add_tsclass(self, id): 

1494 self.add_result('TS', nmap1_seq_container.tsclasses[id]) 

1495 

1496 ipidclasses = { 

1497 nmap1_seq.IPID_SEQ_INCR: 'I', 

1498 nmap1_seq.IPID_SEQ_BROKEN_INCR: 'BI', 

1499 nmap1_seq.IPID_SEQ_RPI: 'RPI', 

1500 nmap1_seq.IPID_SEQ_RD: 'RD', 

1501 nmap1_seq.IPID_SEQ_CONSTANT: 'C', 

1502 nmap1_seq.IPID_SEQ_ZERO: 'Z', 

1503 } 

1504 

1505 def add_ipidclass(self, id): 

1506 self.add_result('IPID', nmap1_seq_container.ipidclasses[id]) 

1507 

1508 

1509class nmap2_seq_container(os_id_test): 

1510 def __init__(self, num_seq_samples, responses, seq_diffs, ts_diffs, time_diffs): 

1511 os_id_test.__init__(self, 0) 

1512 

1513 self.num_seq_samples = num_seq_samples 

1514 self.seq_responses = responses 

1515 self.seq_num_responses = len(responses) 

1516 self.seq_diffs = seq_diffs 

1517 self.ts_diffs = ts_diffs 

1518 self.time_diffs = time_diffs 

1519 self.pre_ts_seqclass = nmap2_seq.TS_SEQ_UNKNOWN 

1520 

1521 def test_id(self): 

1522 return "SEQ" 

1523 

1524 def set_ts_seqclass(self, ts_seqclass): 

1525 self.pre_ts_seqclass = ts_seqclass 

1526 

1527 def process(self): 

1528 if self.seq_num_responses >= 4: 

1529 self.calc_ti() 

1530 self.calc_ts() 

1531 self.calc_sp() 

1532 else: 

1533 self.add_result('R', 'N') 

1534 LOG.error("Insufficient responses for TCP sequencing (%d out of %d), OS detection may be less accurate." 

1535 % (self.seq_num_responses, self.num_seq_samples)) 

1536 

1537 def get_final_result(self): 

1538 return {self.test_id(): self.get_result_dict()} 

1539 

1540 def calc_ti(self): 

1541 if self.seq_num_responses < 2: 

1542 return 

1543 

1544 ipidclasses = { 

1545 nmap2_seq.IPID_SEQ_INCR: 'I', 

1546 nmap2_seq.IPID_SEQ_BROKEN_INCR: 'BI', 

1547 nmap2_seq.IPID_SEQ_RPI: 'RI', 

1548 nmap2_seq.IPID_SEQ_RD: 'RD', 

1549 nmap2_seq.IPID_SEQ_CONSTANT: 'C', 

1550 nmap2_seq.IPID_SEQ_ZERO: 'Z', 

1551 } 

1552 

1553 ipid_diffs = array.array('H', [0] * (self.seq_num_responses - 1)) 

1554 

1555 # Random and zero 

1556 null_ipids = 1 

1557 for i in xrange(1, self.seq_num_responses): 

1558 prev_ipid = self.seq_responses[i-1].get_ipid() 

1559 cur_ipid = self.seq_responses[i].get_ipid() 

1560 

1561 if prev_ipid != 0 or cur_ipid != 0: 

1562 null_ipids = 0 

1563 

1564 if prev_ipid <= cur_ipid: 

1565 ipid_diffs[i-1] = cur_ipid - prev_ipid 

1566 else: 

1567 ipid_diffs[i-1] = (cur_ipid - prev_ipid + 65536) & 0xffff 

1568 

1569 if self.seq_num_responses > 2 and ipid_diffs[i-1] > 20000: 

1570 self.add_result('TI', ipidclasses[nmap2_seq.IPID_SEQ_RD]) 

1571 return 

1572 

1573 if null_ipids: 

1574 self.add_result('TI', ipidclasses[nmap2_seq.IPID_SEQ_ZERO]) 

1575 return 

1576 

1577 # Constant 

1578 all_zero = 1 

1579 for i in xrange(0, self.seq_num_responses - 1): 

1580 if ipid_diffs[i] != 0: 

1581 all_zero = 0 

1582 break 

1583 

1584 if all_zero: 

1585 self.add_result('TI', ipidclasses[nmap2_seq.IPID_SEQ_CONSTANT]) 

1586 return 

1587 

1588 # Random positive increments 

1589 for i in xrange(0, self.seq_num_responses - 1): 

1590 if ipid_diffs[i] > 1000 and \ 

1591 ((ipid_diffs[i] % 256 != 0) or \ 

1592 ((ipid_diffs[i] % 256 == 0) and (ipid_diffs[i] >= 25600))): 

1593 self.add_result('TI', ipidclasses[nmap2_seq.IPID_SEQ_RPI]) 

1594 return 

1595 

1596 # Broken Increment and Incremental 

1597 is_incremental = 1 # All diferences are less than 10 

1598 is_ms = 1 # All diferences are multiples of 256 and no greater than 5120 

1599 for i in xrange(0, self.seq_num_responses - 1): 

1600 if is_ms and ((ipid_diffs[i] > 5120) or (ipid_diffs[i] % 256) != 0): 

1601 is_ms = 0 

1602 if is_incremental and ipid_diffs[i] > 9: 

1603 is_incremental = 0 

1604 

1605 if is_ms: 

1606 self.add_result('TI', ipidclasses[nmap2_seq.IPID_SEQ_BROKEN_INCR]) 

1607 elif is_incremental: 

1608 self.add_result('TI', ipidclasses[nmap2_seq.IPID_SEQ_INCR]) 

1609 

1610 def calc_ts(self): 

1611 # 1. If any of the responses have no timestamp option, TS  

1612 # is set to U (unsupported). 

1613 # 2. If any of the timestamp values are zero, TS is set to 0. 

1614 # 3. If the average increments per second falls within the  

1615 # ranges 0-5.66, 70-150, or 150-350, TS is set to 1, 7, or 8,  

1616 # respectively. These three ranges get special treatment  

1617 # because they correspond to the 2 Hz, 100 Hz, and 200 Hz  

1618 # frequencies used by many hosts. 

1619 # 4. In all other cases, Nmap records the binary logarithm of  

1620 # the average increments per second, rounded to the nearest  

1621 # integer. Since most hosts use 1,000 Hz frequencies, A is  

1622 # a common result. 

1623 

1624 if self.pre_ts_seqclass == nmap2_seq.TS_SEQ_ZERO: 

1625 self.add_result('TS', '0') 

1626 elif self.pre_ts_seqclass == nmap2_seq.TS_SEQ_UNSUPPORTED: 

1627 self.add_result('TS', 'U') 

1628 elif self.seq_num_responses < 2: 

1629 return 

1630 

1631 avg_freq = 0.0 

1632 for i in xrange(0, self.seq_num_responses - 1): 

1633 dhz = self.ts_diffs[i] / self.time_diffs[i] 

1634 avg_freq += dhz / (self.seq_num_responses - 1) 

1635 

1636 LOG.info("The avg TCP TS HZ is: %f" % avg_freq) 

1637 

1638 if avg_freq <= 5.66: 

1639 self.add_result('TS', "1") 

1640 elif 70 < avg_freq <= 150: 

1641 self.add_result('TS', "7") 

1642 elif 150 < avg_freq <= 350: 

1643 self.add_result('TS', "8") 

1644 else: 

1645 ts = int(round(.5 + math.log(avg_freq)/math.log(2))) 

1646 self.add_result('TS', "%X" % ts) 

1647 

1648 def calc_sp(self): 

1649 seq_gcd = reduce(my_gcd, self.seq_diffs) 

1650 

1651 seq_avg_rate = 0.0 

1652 for i in xrange(0, self.seq_num_responses - 1): 

1653 seq_avg_rate += self.seq_diffs[i] / self.time_diffs[i] 

1654 seq_avg_rate /= (self.seq_num_responses - 1) 

1655 

1656 seq_rate = seq_avg_rate 

1657 si_index = 0 

1658 seq_stddev = 0 

1659 

1660 if 0 == seq_gcd: 

1661 seq_rate = 0 

1662 else: 

1663 seq_rate = int(round(.5 + (math.log(seq_rate) / math.log(2)) * 8)) 

1664 

1665 div_gcd = 1 

1666 if seq_gcd > 9: 

1667 div_gcd = seq_gcd 

1668 

1669 for i in xrange(0, self.seq_num_responses - 1): 

1670 rtmp = (self.seq_diffs[i] / self.time_diffs[i]) / div_gcd - \ 

1671 seq_avg_rate / div_gcd 

1672 seq_stddev += rtmp * rtmp 

1673 

1674 seq_stddev /= self.seq_num_responses - 2 

1675 seq_stddev = math.sqrt(seq_stddev) 

1676 

1677 if seq_stddev <= 1: 

1678 si_index = 0 

1679 else: 

1680 si_index = int(round(.5 + (math.log(seq_stddev) / math.log(2)) * 8.0)) 

1681 

1682 self.add_result('SP', "%X" % si_index) 

1683 self.add_result('GCD', "%X" % seq_gcd) 

1684 self.add_result('ISR', "%X" % seq_rate) 

1685 

1686class nmap2_ops_container(os_id_test): 

1687 def __init__(self, responses): 

1688 os_id_test.__init__(self, 0) 

1689 

1690 self.seq_responses = responses 

1691 self.seq_num_responses = len(responses) 

1692 

1693 def test_id(self): 

1694 return "OPS" 

1695 

1696 def process(self): 

1697 if self.seq_num_responses != 6: 

1698 self.add_result('R', 'N') 

1699 return 

1700 

1701 for i in xrange(0, self.seq_num_responses): 

1702 tests = nmap2_tcp_tests(self.seq_responses[i].get_ip(), 

1703 self.seq_responses[i].get_tcp(), 

1704 0, 

1705 0) 

1706 self.add_result("O%i" % (i+1), tests.get_options()) 

1707 

1708 def get_final_result(self): 

1709 if not self.get_result_dict(): 

1710 return None 

1711 else: 

1712 return {self.test_id(): self.get_result_dict()} 

1713 

1714class nmap2_win_container(os_id_test): 

1715 def __init__(self, responses): 

1716 os_id_test.__init__(self, 0) 

1717 

1718 self.seq_responses = responses 

1719 self.seq_num_responses = len(responses) 

1720 

1721 def test_id(self): 

1722 return "WIN" 

1723 

1724 def process(self): 

1725 if self.seq_num_responses != 6: 

1726 self.add_result('R', 'N') 

1727 return 

1728 

1729 for i in xrange(0, self.seq_num_responses): 

1730 tests = nmap2_tcp_tests(self.seq_responses[i].get_ip(), 

1731 self.seq_responses[i].get_tcp(), 

1732 0, 

1733 0) 

1734 self.add_result("W%i" % (i+1), tests.get_win()) 

1735 

1736 def get_final_result(self): 

1737 if not self.get_result_dict(): 

1738 return None 

1739 else: 

1740 return {self.test_id(): self.get_result_dict()} 

1741 

1742class nmap2_t1_container(os_id_test): 

1743 def __init__(self, responses, seq_base): 

1744 os_id_test.__init__(self, 0) 

1745 

1746 self.seq_responses = responses 

1747 self.seq_num_responses = len(responses) 

1748 self.seq_base = seq_base 

1749 

1750 def test_id(self): 

1751 return "T1" 

1752 

1753 def process(self): 

1754 # R, DF, T*, TG*, W-, S, A, F, O-, RD*, Q 

1755 if self.seq_num_responses < 1: 

1756 self.add_result("R","N") 

1757 return 

1758 

1759 response = self.seq_responses[0] 

1760 tests = nmap2_tcp_tests(response.get_ip(), 

1761 response.get_tcp(), 

1762 self.seq_base, 

1763 nmap2_tcp_probe.acknowledgment) 

1764 self.add_result("R", "Y") 

1765 self.add_result("DF", tests.get_df()) 

1766 self.add_result("S", tests.get_seq()) 

1767 self.add_result("A", tests.get_ack()) 

1768 self.add_result("F", tests.get_flags()) 

1769 self.add_result("Q", tests.get_quirks()) 

1770 

1771 def get_final_result(self): 

1772 if not self.get_result_dict(): 

1773 return None 

1774 else: 

1775 return {self.test_id(): self.get_result_dict()} 

1776 

1777class nmap2_icmp_container(os_id_test): 

1778 def __init__(self, responses): 

1779 os_id_test.__init__(self, 0) 

1780 

1781 self.icmp_responses = responses 

1782 self.icmp_num_responses = len(responses) 

1783 

1784 def test_id(self): 

1785 return "IE" 

1786 

1787 def process(self): 

1788 # R, DFI, T*, TG*, TOSI, CD, SI, DLI* 

1789 if self.icmp_num_responses != 2: 

1790 self.add_result("R","N") 

1791 return 

1792 

1793 ip1 = self.icmp_responses[0].child() 

1794 ip2 = self.icmp_responses[1].child() 

1795 icmp1 = ip1.child() 

1796 icmp2 = ip2.child() 

1797 

1798 self.add_result("R", "Y") 

1799 

1800 # Value Description 

1801 # N Neither of the ping responses have the DF bit set. 

1802 # S Both responses echo the DF value of the probe. 

1803 # Y Both of the response DF bits are set. 

1804 # O The one remaining other combination-both responses have the DF bit toggled. 

1805 if not ip1.get_ip_df() and not ip2.get_ip_df(): 

1806 self.add_result("DFI","N") 

1807 elif ip1.get_ip_df() and not ip2.get_ip_df(): 

1808 self.add_result("DFI","S") 

1809 elif ip1.get_ip_df() and ip2.get_ip_df(): 

1810 self.add_result("DFI","Y") 

1811 else: 

1812 self.add_result("DFI","O") 

1813 

1814 # Value Description 

1815 # Z Both TOS values are zero. 

1816 # S Both TOS values are each the same as in the corresponding probe. 

1817 # <NN> When they both use the same non-zero number, it is recorded here. 

1818 # O Any other combination. 

1819 if ip1.get_ip_tos() == 0 and ip2.get_ip_tos() == 0: 

1820 self.add_result("TOSI","Z") 

1821 elif ip1.get_ip_tos() == 0 and ip2.get_ip_tos() == 4: 

1822 self.add_result("TOSI","S") 

1823 elif ip1.get_ip_tos() == ip2.get_ip_tos(): 

1824 self.add_result("TOSI","%X" % ip1.get_ip_tos()) 

1825 else: 

1826 self.add_result("TOSI","O") 

1827 

1828 # Value Description 

1829 # Z Both code values are zero. 

1830 # S Both code values are the same as in the corresponding probe. 

1831 # <NN> When they both use the same non-zero number, it is shown here. 

1832 # O Any other combination. 

1833 if icmp1.get_icmp_code() == 0 and icmp2.get_icmp_code() == 0: 

1834 self.add_result("CD","Z") 

1835 elif icmp1.get_icmp_code() == 9 and icmp2.get_icmp_code() == 0: 

1836 self.add_result("CD","S") 

1837 elif icmp1.get_icmp_code() == icmp2.get_icmp_code(): 

1838 self.add_result("CD","%X" % icmp1.get_icmp_code()) 

1839 else: 

1840 self.add_result("CD","O") 

1841 

1842 # Value Description 

1843 # Z Both sequence numbers are set to 0. 

1844 # S Both sequence numbers echo the ones from the probes. 

1845 # <NNNN> When they both use the same non-zero number, it is recorded here. 

1846 # O Any other combination. 

1847 if icmp1.get_icmp_seq() == 0 and icmp2.get_icmp_seq() == 0: 

1848 self.add_result("SI","Z") 

1849 elif (icmp1.get_icmp_seq() == nmap2_icmp_echo_probe_1.sequence_number and 

1850 icmp2.get_icmp_seq() == nmap2_icmp_echo_probe_1.sequence_number + 1): 

1851 self.add_result("SI","S") 

1852 elif icmp1.get_icmp_seq() == icmp2.get_icmp_seq(): 

1853 self.add_result("SI","%X" % icmp1.get_icmp_code()) 

1854 else: 

1855 self.add_result("SI","O") 

1856 

1857 def get_final_result(self): 

1858 if not self.get_result_dict(): 

1859 return None 

1860 else: 

1861 return {self.test_id(): self.get_result_dict()} 

1862 

1863class nmap1_tcp_closed_1(nmap1_tcp_probe): 

1864 def __init__(self, id, addresses, tcp_ports): 

1865 nmap1_tcp_probe.__init__(self, id, addresses, tcp_ports, 0) 

1866 self.t.set_SYN() 

1867 

1868 def test_id(self): 

1869 return "T5" 

1870 

1871 def is_mine(self, packet): 

1872 if tcp_probe.is_mine(self, packet): 

1873 ip = packet.child() 

1874 if not ip: 

1875 return 0 

1876 tcp = ip.child() 

1877 if not tcp: 

1878 return 0 

1879 if tcp.get_RST(): 

1880 return 1 

1881 else: 

1882 return 0 

1883 else: 

1884 return 0 

1885 

1886class nmap2_tcp_closed_1(nmap2_tcp_probe_2_6): 

1887 # ... 

1888 # T5 sends a TCP SYN packet without IP DF and a window field of  

1889 # 31337 to a closed port 

1890 # ... 

1891 def __init__(self, id, addresses, tcp_ports): 

1892 nmap2_tcp_probe_2_6.__init__(self, id, addresses, tcp_ports, 0) 

1893 self.t.set_SYN() 

1894 self.i.set_ip_df(0) 

1895 self.t.set_th_win(31337) 

1896 

1897 def test_id(self): 

1898 return "T5" 

1899 

1900 

1901class nmap1_tcp_closed_2(nmap1_tcp_probe): 

1902 

1903 def __init__(self, id, addresses, tcp_ports): 

1904 nmap1_tcp_probe.__init__(self, id, addresses, tcp_ports, 0) 

1905 self.t.set_ACK() 

1906 

1907 def test_id(self): 

1908 return "T6" 

1909 

1910 

1911class nmap2_tcp_closed_2(nmap2_tcp_probe_2_6): 

1912 # ... 

1913 # T6 sends a TCP ACK packet with IP DF and a window field of  

1914 # 32768 to a closed port. 

1915 # ... 

1916 def __init__(self, id, addresses, tcp_ports): 

1917 nmap2_tcp_probe_2_6.__init__(self, id, addresses, tcp_ports, 0) 

1918 self.t.set_ACK() 

1919 self.i.set_ip_df(1) 

1920 self.t.set_th_win(32768) 

1921 

1922 def test_id(self): 

1923 return "T6" 

1924 

1925 

1926class nmap1_tcp_closed_3(nmap1_tcp_probe): 

1927 

1928 def __init__(self, id, addresses, tcp_ports): 

1929 nmap1_tcp_probe.__init__(self, id, addresses, tcp_ports, 0) 

1930 self.t.set_FIN() 

1931 self.t.set_URG() 

1932 self.t.set_PSH() 

1933 

1934 def test_id(self): 

1935 return "T7" 

1936 

1937 

1938class nmap2_tcp_closed_3(nmap2_tcp_probe_7): 

1939 # ... 

1940 # T7 sends a TCP packet with the FIN, PSH, and URG flags set and a  

1941 # window field of 65535 to a closed port. The IP DF bit is not set. 

1942 # ... 

1943 def __init__(self, id, addresses, tcp_ports): 

1944 nmap2_tcp_probe_7.__init__(self, id, addresses, tcp_ports, 0) 

1945 self.t.set_FIN() 

1946 self.t.set_URG() 

1947 self.t.set_PSH() 

1948 self.t.set_th_win(65535) 

1949 self.i.set_ip_df(0) 

1950 

1951 def test_id(self): 

1952 return "T7" 

1953 

1954 

1955class NMAP2_OS_Class: 

1956 def __init__(self, vendor, name, family, device_type): 

1957 self.__vendor = vendor 

1958 self.__name = name 

1959 self.__family = family 

1960 self.__device_type = device_type 

1961 

1962 def get_vendor(self): 

1963 return self.__vendor 

1964 def get_name(self): 

1965 return self.__name 

1966 def get_family(self): 

1967 return self.__family 

1968 def get_device_type(self): 

1969 return self.__device_type 

1970 

1971class NMAP2_Fingerprint: 

1972 def __init__(self, id, os_class, tests): 

1973 self.__id = id 

1974 self.__os_class = os_class 

1975 self.__tests = tests 

1976 

1977 def get_id(self): 

1978 return self.__id 

1979 def get_os_class(self): 

1980 return self.__os_class 

1981 def get_tests(self): 

1982 return self.__tests 

1983 

1984 def __str__(self): 

1985 ret = "FP: [%s]" % self.__id 

1986 ret += "\n vendor: %s" % self.__os_class.get_vendor() 

1987 ret += "\n name: %s" % self.__os_class.get_name() 

1988 ret += "\n family: %s" % self.__os_class.get_family() 

1989 ret += "\n device_type: %s" % self.__os_class.get_device_type() 

1990 

1991 for test in self.__tests: 

1992 ret += "\n test: %s" % test 

1993 for pair in self.__tests[test]: 

1994 ret += "\n %s = [%s]" % (pair, self.__tests[test][pair]) 

1995 

1996 return ret 

1997 

1998 literal_conv = { "RIPL" : { "G" : 0x148 }, 

1999 "RID" : { "G" : 0x1042 }, 

2000 "RUL" : { "G" : 0x134 } } 

2001 

2002 def parse_int(self, field, value): 

2003 try: 

2004 return int(value, 16) 

2005 except ValueError: 

2006 if field in NMAP2_Fingerprint.literal_conv: 

2007 if value in NMAP2_Fingerprint.literal_conv[field]: 

2008 return NMAP2_Fingerprint.literal_conv[field][value] 

2009 return 0 

2010 

2011 def match(self, field, ref, value): 

2012 options = ref.split("|") 

2013 

2014 for option in options: 

2015 if option.startswith(">"): 

2016 if self.parse_int(field, value) > \ 

2017 self.parse_int(field, option[1:]): 

2018 return True 

2019 elif option.startswith("<"): 

2020 if self.parse_int(field, value) < \ 

2021 self.parse_int(field, option[1:]): 

2022 return True 

2023 elif option.find("-") > -1: 

2024 range = option.split("-") 

2025 if self.parse_int (field, value) >= self.parse_int (field, range[0]) and \ 

2026 self.parse_int (field, value) <= self.parse_int (field, range[1]): 

2027 return True 

2028 else: 

2029 if str(value) == str(option): 

2030 return True 

2031 

2032 return False 

2033 

2034 def compare(self, sample, mp): 

2035 max_points = 0 

2036 total_points = 0 

2037 

2038 for test in self.__tests: 

2039 # ignore unknown response lines: 

2040 if test not in sample: 

2041 continue 

2042 

2043 for field in self.__tests[test]: 

2044 # ignore unsupported fields: 

2045 if field not in sample[test] or \ 

2046 test not in mp or \ 

2047 field not in mp[test]: 

2048 continue 

2049 

2050 ref = self.__tests[test][field] 

2051 value = sample[test][field] 

2052 

2053 points = int(mp[test][field]) 

2054 

2055 max_points += points 

2056 

2057 if self.match(field, ref, value): 

2058 total_points += points 

2059 

2060 return (total_points / float(max_points)) * 100 

2061 

2062class NMAP2_Fingerprint_Matcher: 

2063 def __init__(self, filename): 

2064 self.__filename = filename 

2065 

2066 def find_matches(self, res, threshold): 

2067 output = [] 

2068 

2069 try: 

2070 infile = open(self.__filename,"r") 

2071 

2072 mp = self.parse_mp(self.matchpoints(infile)) 

2073 

2074 for fingerprint in self.fingerprints(infile): 

2075 fp = self.parse_fp(fingerprint) 

2076 similarity = fp.compare(res, mp) 

2077 if similarity >= threshold: 

2078 print("\"%s\" matches with an accuracy of %.2f%%" \ 

2079 % (fp.get_id(), similarity)) 

2080 output.append((similarity / 100, 

2081 fp.get_id(), 

2082 (fp.get_os_class().get_vendor(), 

2083 fp.get_os_class().get_name(), 

2084 fp.get_os_class().get_family(), 

2085 fp.get_os_class().get_device_type()))) 

2086 

2087 infile.close() 

2088 except IOError as err: 

2089 print("IOError: %s", err) 

2090 

2091 return output 

2092 

2093 def sections(self, infile, token): 

2094 OUT = 0 

2095 IN = 1 

2096 

2097 state = OUT 

2098 output = [] 

2099 

2100 for line in infile: 

2101 line = line.strip() 

2102 if state == OUT: 

2103 if line.startswith(token): 

2104 state = IN 

2105 output = [line] 

2106 elif state == IN: 

2107 if line: 

2108 output.append(line) 

2109 else: 

2110 state = OUT 

2111 yield output 

2112 output = [] 

2113 

2114 if output: 

2115 yield output 

2116 

2117 def fingerprints(self, infile): 

2118 for section in self.sections(infile,"Fingerprint"): 

2119 yield section 

2120 

2121 def matchpoints(self, infile): 

2122 return self.sections(infile,"MatchPoints").next() 

2123 

2124 def parse_line(self, line): 

2125 name = line[:line.find("(")] 

2126 pairs = line[line.find("(") + 1 : line.find(")")] 

2127 

2128 test = {} 

2129 

2130 for pair in pairs.split("%"): 

2131 pair = pair.split("=") 

2132 test[pair[0]] = pair[1] 

2133 

2134 return (name, test) 

2135 

2136 def parse_fp(self, fp): 

2137 tests = {} 

2138 

2139 for line in fp: 

2140 if line.startswith("#"): 

2141 continue 

2142 elif line.startswith("Fingerprint"): 

2143 fingerprint = line[len("Fingerprint") + 1:] 

2144 elif line.startswith("Class"): 

2145 (vendor, 

2146 name, 

2147 family, 

2148 device_type) = line[len("Class") + 1:].split("|") 

2149 os_class = NMAP2_OS_Class(vendor.strip(), 

2150 name.strip(), 

2151 family.strip(), 

2152 device_type.strip()) 

2153 else: 

2154 test = self.parse_line(line) 

2155 tests[test[0]] = test[1] 

2156 

2157 return NMAP2_Fingerprint(fingerprint, os_class, tests) 

2158 

2159 def parse_mp(self, fp): 

2160 tests = {} 

2161 

2162 for line in fp: 

2163 if line.startswith("#"): 

2164 continue 

2165 elif line.startswith("MatchPoints"): 

2166 continue 

2167 else: 

2168 test = self.parse_line(line) 

2169 tests[test[0]] = test[1] 

2170 

2171 return tests