Coverage for /root/GitHubProjects/impacket/impacket/examples/os_ident.py: 1%

# Coverage for /root/GitHubProjects/impacket/impacket/examples/os_ident.py : 1%

## 1238 statements

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

10 import math

11 import array

12 from six.moves import xrange, reduce

13

14 from pcapy import lookupdev, open_live

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

16 from impacket.ImpactDecoder import EthDecoder

17 from impacket import LOG

18

19 g_nmap1_signature_filename="nmap-os-fingerprints"

20 g_nmap2_signature_filename="nmap-os-db"

21

22

23 def 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

35 class os_id_exception:

36 def __init__(self, value):

37 self.value = value

38 def __str__(self):

39 return repr(self.value)

40

41 class 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

79 class 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

125 class 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

146 class 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

165 class 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

209 class 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

259 class 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

271 class 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

365 class 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

404 class 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

474 class 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

656 class 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

685 class 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

704 class 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

719 class 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

800 class 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

976 class 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

1052 class 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

1077 class 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

1084 class 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

1098 class 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

1109 class 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

1126 class 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

1134 class 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

1149 class 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

1182 class 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

1203 class 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

1222 class 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

1241 class 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

1262 class 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

1279 class 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

1298 class 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

1313 class 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

1509 class 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

1686 class 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

1714 class 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

1742 class 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

1777 class 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

1863 class 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

1886 class 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

1901 class 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

1911 class 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

1926 class 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

1938 class 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

1955 class 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

1971 class 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

2062 class 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