forked from unixrox/prebellico
-
Notifications
You must be signed in to change notification settings - Fork 0
/
prebellico.py
1851 lines (1620 loc) · 123 KB
/
prebellico.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/python
"""
Prebellico v1.8 - 100% Passive Pre-Engagement and Post Compromise Network Reconnaissance Tool
Written by William Suthers
Shout out to the Impacket and pcapy teams - you make this easy.
Shout out to all those before me, those who invested in me, those who stand with me, and those who have yet to join our cause.
"""
import pcapy
import socket
import netifaces
import sys
import os
import re
import time
import base64
import struct
import sqlite3
import argparse
import logging
import threading
from datetime import datetime
from impacket import ImpactDecoder
from pcapy import findalldevs, open_live, PcapError
from operator import itemgetter
from itertools import groupby
from collections import defaultdict
import string
from pdb import set_trace as bp
####
#### Prebellico Functions Here
####
# Function to process MAC addresses and see if we can map them to a VM instance or a physical instance.
def macPlatformDetection(macAddy):
with lockMacPlatformDetection:
vendMac = macAddy[0:8].replace(":","").lower()
if vendMac == "005056" or vendMac == "000c29" or vendMac == "000569" or vendMac == "001c14":
hostType = "VMWare VM"
return hostType
elif vendMac == "0003ff" or vendMac == "00155d":
hostType = "Microsoft Hyper-V VM"
return hostType
elif vendMac == "001c42":
hostType = "Parallels Desktop VM"
return hostType
elif vendMac == "000f4b":
hostType = "Oracle VM"
return hostType
elif vendMac == "00163e":
hostType = "XenSource VM"
return hostType
elif vendMac == "080027":
hostType = "VirtualBox VM"
return hostType
elif vendMac == "525400":
hostType = "KMV/QEMU VM"
return hostType
else:
hostType = "physical system, bridged VM or unknown VM OUI"
return hostType
# Function to establish the name of the SQLite DB name, either as specified by the user, or using the default, and validating that it is a prebellico database which we can access.
def checkPrebellicoDb():
sqliteDbFile=args['db']
if sqliteDbFile is None:
sqliteDbFile='prebellico.db'
print("\nChecking for a '%s' database file.") % ( sqliteDbFile )
if not os.path.exists(sqliteDbFile):
print("\nThe '%s' database file does not exist. Creating a prebellico database now.") % ( sqliteDbFile )
try:
dbConnect=sqlite3.connect(sqliteDbFile)
db=dbConnect.cursor()
db.execute('create table prebellico(prebellicodb text)')
db.execute('insert into prebellico values("prebellico_recon")')
db.execute('create table HostIntelligence(number integer primary key, firstObserved text, lastObserved text, ipAddress text, macAddy text, hostname text, fqdn text, domain text, hostDescription text, dualHomed text, os text, hostType text, trustRelationships text, openTcpPorts text, openUdpPorts text, zombieIpid text, validatedSnmp text, validatedUsernames text, validatedPasswords text, credentials text, exploits text, permittedEgress text, discoveryInterface text, interfaceIp text)')
db.execute('create table NetworkIntelligence(id integer primary key, recordType text, data text, dateObserved text, associatedHost text, methodObtained text, sourceInterface text)')
db.execute('create table TcpPushSessionTracking(number integer primary key, sourceIp text, sourcePort text, destIp text, destPort text)')
db.execute('create table UdpServerTracking(number integer primary key, sourceIp text, udpSourcePort text, destIp text, udpDestPort text)')
db.execute('create table PrebellicoMeshNodes(id integer primary key, observerId text, role text, ipAddress text, connectionMethod text, networkEgress text, egressMethod text, c2Endpoint text, encryptionKey text)')
db.execute('create table PrebellicoHostConfiguration(id integer primary key, executionDate text, flags text, interface text, ipAddress text, role text, c2Method text)')
dbConnect.commit()
print("\nThe '%s' prebellico database file has been created.") % ( sqliteDbFile )
dbConnect.close()
except sqlite3.OperationalError, msg:
print msg
else:
print("\nThe '%s' database file exists Working to confirm it's a Prebellico database file and we have access to the database file.") % ( sqliteDbFile )
try:
dbConnect=sqlite3.connect(sqliteDbFile)
db=dbConnect.cursor()
db.execute('select * from prebellico')
confirmPrebellicoDb=db.fetchone()[0]
if confirmPrebellicoDb == "prebellico_recon":
print("\nThe '%s' file is a prebellico database file.") % ( sqliteDbFile )
dbConnect.close()
else:
print("\nThe '%s' file is not a prebellico database file:") % ( sqliteDbFile )
print("\nPlease correct this issue and try again.")
exit(1)
except sqlite3.OperationalError, msg:
print("\nThe '%s' file is not a prebellico database file:") % ( sqliteDbFile )
print msg
print("\nPlease correct this issue and try again.")
exit(1)
# Function to open and close the DB, as well as return data as required.
def prebellicoDb(queryType, statement, data, **keywordDbSearchParameters):
with lockPrebellicoDb:
sqliteDbFile=args['db']
if sqliteDbFile is None:
sqliteDbFile='prebellico.db'
dbConnect=sqlite3.connect(sqliteDbFile)
db=dbConnect.cursor()
# Test to see if the data is a single string/int or a list/tuple and execute a db function based upon determination to set the correct number of tokens.
if isinstance(data, basestring) or isinstance(data, (int, long)):
db.execute(statement, [data])
else:
dataListLength = len(data)
db.execute(statement, data)
# If the request is to read data from the DB, read the data from the DB.
if queryType is 'readFromDb':
if ('readMany' in keywordDbSearchParameters):
returnData=db.fetchall()
else:
returnData=db.fetchone()
# If the request is to write data to the DB, post the data.
elif queryType is 'writeToDb':
dbConnect.commit()
# If something else goes wrong, alter the user through STDIO.
else:
print("Something went wrong while trying to interact with the %s database via the %s function! The query type was '%s' and the data was '%s'.") % ( sqliteDbFile, queryType, data )
exit(1)
# Close the database connection and return data if a select statement was called.
dbConnect.close()
if queryType is 'readFromDb':
return(returnData)
else:
return
# Function to produce the time for database record keeping purposes. This is a function with intent to allow the user to specify how to create timestamps.
def timeStamp():
#Obtain the current date/time in a standard format and return it.
now = datetime.now()
return(str(now.strftime('%d%b%y %H:%M:%S')))
# Function to write data to the screen and prebellico log.
def prebellicoLog(data):
with lockPrebellicoLog:
#Obtain the current date/time and write the message out to the log.
logging.info(("\n%s %s") % (timeStamp(), data))
return
# Because everyone needs a cool banner - shown by default unless someone asks for it to be disabled.
def prebellicoBanner():
banner = """
___ __ _____
/ _ \_______ / / ___ / / (_)______
/ ___/ __/ -_) _ \/ -_) / / / __/ _ \\
/_/ /_/ \__/___/ \__/_/_/_/\__/\___/
"""
print(banner)
time.sleep(1)
print("\nThere is no patch for passive recon. ;)\n")
time.sleep(2)
# Function to validate if an IP address is associated with an RFC1918 address or a known non-RFC1918 address space that a target site uses internally.
def checkInternalAddress(networkIp):
with lockCheckInternalAddress:
rfc1918addressregex = re.compile('^(127\.)|(192\.168\.)|(10\.)|(172\.1[6-9]\.)|(172\.2[0-9]\.)|(172\.3[0-1]\.)')# Add this when IPv6 is ready: |(::1$)|([fF][cCdD])')
networkMatch = rfc1918addressregex.match(networkIp)
return(networkMatch)
# Function to create source and destination networks for known network tracking to assist future targeting.
def checkKnownNetwork(networkIp, internalMatch):
with lockCheckKnownNetwork:
networkIpOctets = networkIp.split('.')
knownNetworkCidr = networkIpOctets[0] + '.' + networkIpOctets[1] + '.' + networkIpOctets [2] + '.1/24'
knownSourceNetwork = prebellicoDb('readFromDb', 'select * from NetworkIntelligence where recordType = "knownNet" and data=(?)', knownNetworkCidr)
if knownSourceNetwork is None and internalMatch:
prebellicoDb('writeToDb', 'insert into NetworkIntelligence (recordType, data, dateObserved, associatedHost, methodObtained, sourceInterface) values ("knownNet", ?, ?, ?, "passiveNetwork", ?)', [knownNetworkCidr, timeStamp(), networkIp, dev] )
prebellicoLog(("-=-Network Recon-=-\nA new network has been identified: %s.") % (knownNetworkCidr))
newKnownNet = 1
else:
newKnownNet = 0
return(newKnownNet)
# Function to detect the protocol used within the packet to steer accordingly.
def inspectProto(header, data):
# Prepare for inspectproto threadding
prebellicoInspectProtoTheads = []
# If the user has set a timer to shift to a more aggressive recon phase, check the timer around every fifteen minutes to see if a more aggressive form of recon is required.
global initialReconUpdateTimeCheck
global previousTrackUpdateTime
if trackUpdateTime is not None:
currentTrackUpdateTime = time.time()
if initialReconUpdateTimeCheck == 0:
previousTrackUpdateTime = time.time()
initialReconUpdateTimeCheck = 1
if int(round(currentTrackUpdateTime - previousTrackUpdateTime)/60) == 15:
previousTrackUpdateTime = time.time()
prebellicoReconPhaseShiftStatus = checkPrebellicoWaitTimer()
if prebellicoReconPhaseShiftStatus == 1:
Print("\n\n\n\nSpitting Hot Fire!!!\n\n\n")
# Start to decode the packet, determine the protocol number and call the appropriate method.
ethernetPacket = decoder.decode(data)
# If we were able to identify a protocol, extract the protocol number, otherwise, further inspect the ethernet packet.
if hasattr(ethernetPacket.child().child(), 'protocol'):
protocolNumber = ethernetPacket.child().child().protocol
# If this is a VTP/DTP packet, call a function to manage this frame. This is not precise.
elif hasattr(ethernetPacket.child().child(), 'get_protoID') and hasattr(ethernetPacket.child().child(), 'get_OUI'):
ethernetProtoId = ethernetPacket.child().child().get_protoID()
ethernetOUI = ethernetPacket.child().child().get_OUI()
if ethernetProtoId == 8196 and ethernetOUI == 12:
ciscoVtpDtpDetection(header, data)
return
# If we have no idea what this is, simply return.
else:
return
# If we were able to determine the protocol number, call the correct function to handle the protocol.
if protocolNumber == 1:
#print("\nThis is an ICMP packet.")
t = threading.Thread(name='IcmpDiscoveryThread', target=icmpDiscovery, args=(header,data))
prebellicoInspectProtoTheads.append(t)
t.start()
return
elif protocolNumber == 4:
#print("\nThis is an IP packet.")
return
elif protocolNumber == 6:
#print("\nThis is a TCP packet.")
# Pull TCP flags to determine TCP session state so that we can determine what TCP method to call for intel.
tcpSyn = ethernetPacket.child().child().get_SYN()
tcpAck = ethernetPacket.child().child().get_ACK()
tcpEce = ethernetPacket.child().child().get_ECE()
tcpCwr = ethernetPacket.child().child().get_CWR()
tcpFin = ethernetPacket.child().child().get_FIN()
tcpPsh = ethernetPacket.child().child().get_PSH()
tcpRst = ethernetPacket.child().child().get_RST()
tcpUrg = ethernetPacket.child().child().get_URG()
if ( tcpSyn == 1 and tcpAck == 1 ):
t = threading.Thread(name='SynAckDiscoveryThread', target=synAckDiscovery, args=(header,data))
prebellicoInspectProtoTheads.append(t)
t.start()
if ( tcpPsh == 1 and tcpAck == 1 or tcpAck == 1):
t = threading.Thread(name='TcpPushDiscoveryThread', target=tcpPushDiscovery, args=(header,data))
prebellicoInspectProtoTheads.append(t)
t.start()
t = threading.Thread(name='TcpDiscoveryThread', target=tcpDiscovery, args=(header,data))
prebellicoInspectProtoTheads.append(t)
t.start()
# Define regex for snarfing credentials disclosed via TCP
clearTextUsernameRegex = re.findall('(?<=USER )[^\r]*', data, re.IGNORECASE)
clearTextPasswordRegex = re.findall('(?<=PASS )[^\r]*', data, re.IGNORECASE)
basicAuthRegex = re.findall('(?<=Authorization: Basic )[^\n]*', data)
httpNtlm2Regex = re.findall('(?<=WWW-Authenticate: NTLM )[^\r]*', data)
httpNtlm3Regex = re.findall('(?<=Authorization: NTLM )[^\r]*', data)
ntlm1Regex = re.findall('NTLMSSP\x00\x01\x00\x00\x00.*[^EOF]*', data)
ntlm2Regex = re.findall('NTLMSSP\x00\x02\x00\x00\x00.*[^EOF]*', data)
ntlm3Regex = re.findall('NTLMSSP\x00\x03\x00\x00\x00.*[^EOF]*', data, re.DOTALL)
smbUserRegex = re.findall('((?<=Administrator )|(?<=user )|(?<=email )|(?<=username )).*(?=\\r)', data, re.IGNORECASE)
smbPassRegex = re.findall('((?<=cpassword )|(?<=password )|(?<=pass )|(?<=_password )|(?<=passwd )|(?<=pwd )).*(?=\\r)', data, re.IGNORECASE)
# If we get some sort of match indicating we might have some form of NTLM authentication, start a new thread and process this sucker
if ( httpNtlm2Regex or httpNtlm3Regex or ntlm1Regex or ntlm2Regex or ntlm3Regex ):
t = threading.Thread(name='NtlmAuthSnarfThread', target=ntlmAuthDiscovery, args=(header,data))
prebellicoInspectProtoTheads.append(t)
t.start()
# If we get some form of SMB traffic, try to extract authentication information out of it if at all possible.
if ( smbUserRegex or smbPassRegex):
t = threading.Thread(name='SmbCredSnarf', target=smbAuthDiscovery, args=(header,data))
t.start()
# If we get some form of potential clear-text or encoded authentication, start a new thread and process this information.
if ( clearTextPasswordRegex or clearTextUsernameRegex ):
t = threading.Thread(name='ClearTextCredsTread', target=processClearTextCreds, args=(header,data))
prebellicoInspectProtoTheads.append(t)
t.start()
if ( basicAuthRegex ):
t = threading.Thread(name='BasicAuthCredsThread', target=processBasicAuthCreds, args=(header, data))
prebellicoInspectProtoTheads.append(t)
t.start()
return
elif protocolNumber == 17:
#print("\nThis is a UDP packet.")
t = threading.Thread(name='UdpDiscoveryThread', target=udpDiscovery, args=(header,data))
prebellicoInspectProtoTheads.append(t)
t.start()
return
elif protocolNumber == 41:
#print("\nThis is an IPv6 encapsulated packet.")
return
elif protocolNumber == 43:
#print("\nThis is an IPv6 routing header packet.")
return
elif protocolNumber == 44:
#print("\nThis is an IPv6 fragment header packet.")
return
elif protocolNumber == 58:
#print("\nThis is an IPv6 ICMP packet.")
return
elif protocolNumber == 59:
#print("\nThis is an IPv6 no next header packet.")
return
elif protocolNumber == 60:
#print("\nThis is an IPv6 destination options packet.")
return
# This is not an accurate catchall and will more than likely fail at some point.
elif protocolNumber == None:
#print("\nThis is not a supported IP packet.")
return
else:
#print("\nThe protocol number in this packet is %s. This is not TCP.") % ( protocolNumber )
#print("\nEnd of the inspectProto method.\n")
return
# Function designed to alert the user to potential VTP/DTP packets, indicating potential DTP support.
def ciscoVtpDtpDetection(header, data):
# Work to extract data and validate that we are supposed to be here.
ethernetPacket = decoder.decode(data)
ethernetProtoId = ethernetPacket.child().child().get_protoID()
ethernetOUI = ethernetPacket.child().child().get_OUI()
if ethernetProtoId != 8196 and ethernetOUI != 12:
return
ciscoVtpDtpDetection = prebellicoDb('readFromDb', 'select * from NetworkIntelligence where recordType = "ciscoVtpDtpDetection" and data=(?)', "1")
if ciscoVtpDtpDetection is None:
prebellicoLog('-=-Layer2/3 Recon-=-\nCisco VTP/DTP is spoken here. It might be possible to trunk this port! If so, no VLAN is safe!')
prebellicoDb('writeToDb', 'insert into NetworkIntelligence (recordType, data, methodObtained, dateObserved, sourceInterface) values ("ciscoVtpDtpDetection","1","passiveNetwork",?,?)', [ timeStamp(), dev ] )
ciscoVtpDtpTempData = ethernetPacket.child().child().child().get_buffer_as_string()
ciscoVtpDtpDomainFilterRegex = re.compile('[a-zA-Z0-9.*].*')# Regex to yank vlan domain data within buffer string.
ciscoVtpDtpTempData = ciscoVtpDtpDomainFilterRegex.findall(ciscoVtpDtpTempData)
potentialVtpDtpDomainName = re.split('[\x00-\x1f,\x7f-\xff]',ciscoVtpDtpTempData[0])
for justTheDomainName in potentialVtpDtpDomainName:
if len(justTheDomainName) >=3:
ciscoVtpDtpDomainName = justTheDomainName
knownCiscoVtpDtpDomainName = prebellicoDb('readFromDb', 'select * from NetworkIntelligence where recordType = "ciscoVtpDtpDomainName" and data=(?)', ciscoVtpDtpDomainName)
if knownCiscoVtpDtpDomainName is None:
prebellicoLog(('-=-Layer2/3 Recon-=-\nIdentified a VTP/DTP domain name: %s.') % ( ciscoVtpDtpDomainName ))
prebellicoDb('writeToDb', 'insert into NetworkIntelligence (recordType, data, methodObtained, dateObserved, sourceInterface) values ("ciscoVtpDtpDomainName",?,"passiveNetwork",?,?)', [ ciscoVtpDtpDomainName, timeStamp(), dev ] )
# Function designed to sniff out intel tied to ICMP traffic.
def icmpDiscovery(header,data):
ethernetPacket = decoder.decode(data)
protocolNumber = ethernetPacket.child().child().protocol
if protocolNumber != 1:
return
ipHdr = ethernetPacket.child()
macHdr = ethernetPacket
sourceMac = macHdr.as_eth_addr(macHdr.get_ether_shost())
destMac = macHdr.as_eth_addr(macHdr.get_ether_dhost())
sourceIp = ipHdr.get_ip_src()
destIp = ipHdr.get_ip_dst()
icmpHdr = ethernetPacket.child().child()
icmpType = icmpHdr.get_type_name(icmpHdr.get_icmp_type())
# Work to determine if this is an ICMP echo or echo reply. This is important, as it will allow us to determine if ICMP is permitted egress for C2 uses.
if icmpType == "ECHO" or icmpType == "ECHOREPLY":
# Work to determine if these are known internal IP addresses based upon RFC1918 or user supplied data.
(sourceMatch, destMatch) = ( checkInternalAddress(sourceIp), checkInternalAddress(destIp) )
# If a host does not match an RFC1918 address or a user specified internal address that an internal address is talking to, note the external host and the internal host permitted to talk to it and notify the user about the permitted connection.
if not sourceMatch and destMatch:
global icmpNetworkEgressPermitted
if icmpNetworkEgressPermitted == 0:
prebellicoDb('writeToDb', 'insert into NetworkIntelligence (recordType, data, associatedHost, methodObtained, dateObserved, sourceInterface) values ("egressMethod", "icmp", ?, "passiveNetwork", ?, ?)', [destIp, timeStamp(), dev] )
prebellicoLog("-=-Egress Recon-=-\nNetwork egress detected! Internal hosts are permitted to ping the internet.")
icmpNetworkEgressPermitted = 1
# If the source host does match an RFC1918 address or a user specified internal address that an internal address is talking to, check to see if it belongs to any known nets.
if sourceMatch:
checkKnownNetwork(sourceIp, sourceMatch)
# See if the source host is stored in the DB in some way. If not, make a database record and alert the user.
host = prebellicoDb('readFromDb', 'select * from HostIntelligence where ipAddress=(?)', sourceIp)
if host is None:
prebellicoLog(("-=-ICMP Recon-=-\nIdentified a host through ICMP(%s): %s.") % ( icmpType, sourceIp ))
hostType = macPlatformDetection(sourceMac)
prebellicoLog(("-=-Layer 2/3 Recon-=-\n%s appears to be a %s based host.") % ( sourceIp, hostType ))
prebellicoDb('writeToDb', 'insert into HostIntelligence (firstObserved, lastObserved, ipAddress, macAddy, hostType, discoveryInterface, interfaceIp) values (?,?,?,?,?,?,?)', [ timeStamp(), timeStamp(), sourceIp, sourceMac, hostType, dev, devIp ] )
return
# Function designed to sniff out intel tied to generic UDP intelligence such as SMB and SNMP traffic.
def udpDiscovery(header,data):
# Start to decode the packet and determine the protocol number. If not UDP, return as it does not apply here.
ethernetPacket = decoder.decode(data)
protocolNumber = ethernetPacket.child().child().protocol
if protocolNumber != 17:
return
# Extract relevant data from the ethernet packet.
macHdr = ethernetPacket
sourceMac = macHdr.as_eth_addr(macHdr.get_ether_shost())
destMac = macHdr.as_eth_addr(macHdr.get_ether_dhost())
ipHdr = ethernetPacket.child()
udpHdr = ipHdr.child()
sourceIp = ipHdr.get_ip_src()
destIp = ipHdr.get_ip_dst()
udpSourcePort = udpHdr.get_uh_sport()
udpDestPort = udpHdr.get_uh_dport()
tempData = udpHdr.get_data_as_string()
# Work to determine if these are known internal IP addresses based upon RFC1918 or user supplied data.
(sourceMatch, destMatch) = ( checkInternalAddress(sourceIp), checkInternalAddress(destIp) )
# Look to see if the IP address appears to belong to a set of known nets. If not, log the new network and alert the user.
if sourceMatch:
checkKnownNetwork(sourceIp, sourceMatch)
if destMatch:
checkKnownNetwork(destIp, destMatch)
# If a host does not match an RFC1918 address or a user specified internal address that an internal address is talking to, note the external host and the internal host permitted to talk to it and notify the user about the permitted connection.
if not sourceMatch and destMatch:
global udpNetworkEgressPermitted
if udpNetworkEgressPermitted == 0:
prebellicoLog("-=-Egress Recon-=-\nNetwork egress detected! Internal hosts are permitted to connect to the internet via UDP.")
udpNetworkEgressPermitted = 1
knownExternalHost = prebellicoDb('readFromDb', 'select * from NetworkIntelligence where recordType = "externalHost" and data=(?)', sourceIp)
if knownExternalHost is None:
prebellicoDb('writeToDb', 'insert into NetworkIntelligence (recordType, data, associatedHost, methodObtained, dateObserved, sourceInterface) values ("externalHost", ?, ?, "passiveNetwork", ?, ? )', [ sourceIp, destIp, timeStamp(), dev] )
prebellicoLog(("-=-Egress Recon Update-=-\n%s is permitted to connect to %s on UDP port %s.") % (destIp, sourceIp, udpSourcePort))
# If the UDP source port is less than or equal to 1024 and this is a host that does not exist in the HostIntelligence table, log the data and alert the user.
hostExists = prebellicoDb('readFromDb', 'select * from HostIntelligence where ipAddress=(?)', sourceIp)
if (hostExists is None and sourceMatch and destMatch) and (udpSourcePort <= 1024 or udpSourcePort == 3389 or udpSourcePort == 1985):
prebellicoLog(("-=-Host Recon-=-\nA new host was identified with an open UDP port: %s:%s.") % (sourceIp, udpSourcePort))
hostType = macPlatformDetection(sourceMac)
prebellicoLog(("-=-Layer 2/3 Recon-=-\n%s appears to be a %s based host.") % ( sourceIp, hostType ))
prebellicoDb('writeToDb', 'insert into HostIntelligence (firstObserved, lastObserved, ipAddress, macAddy, hostType, openUdpPorts, trustRelationships, discoveryInterface, interfaceIp) values (?,?,?,?,?,?,?,?,?)', [ timeStamp(), timeStamp(), sourceIp, sourceMac, hostType, udpSourcePort, destIp, dev, devIp ] )
# If this is a previous host and the port is less than 1024 (which is just an arbitrary number - have to start somewhere), update the ports for the host.
if (hostExists is not None and destMatch and sourceMatch) and (udpSourcePort <=1024 or udpSourcePort == 3389 or udpSourcePort == 1985):
# Using the source IP address, lookup open UDP ports to see if they match the source port captured within the packet. If this is a new port for this host, update the database and alert the user.
countGetKnownUdpPorts = prebellicoDb('readFromDb', 'select count (openUdpPorts) from HostIntelligence where ipAddress=(?)', sourceIp )
if countGetKnownUdpPorts[0] != 0:
getKnownUdpPorts = prebellicoDb('readFromDb', 'select openUdpPorts from HostIntelligence where ipAddress=(?)', sourceIp )
newUdpPorts = checkUnique(getKnownUdpPorts, udpSourcePort, 'int')
if newUdpPorts != 0:
prebellicoDb('writeToDb', 'update HostIntelligence set openUdpPorts=(?), lastObserved=(?) where ipAddress = (?)', [ newUdpPorts, timeStamp(), sourceIp] )
prebellicoLog(("-=-UDP Service Discovery-=-\nA new open UDP port was discovered for %s. This host has the following open UDP ports: %s.") % (sourceIp, newUdpPorts))
else:
prebellicoDb('writeToDb', 'update HostIntelligence set openUdpPorts=(?), lastObserved=(?) where ipAddress = (?)', [ udpSourcePort, timeStamp(), sourceIp] )
prebellicoLog(("-=-UDP Service Discovery-=-\nA new open UDP port was discovered for %s. This host has the following open UDP ports: %s.") % (sourceIp, udpSourcePort))
# If we have a situation where we are not sure where the server is, because both ports are above 1024, work to pool intel to determine where the UDP server is.
if (udpSourcePort > 1024 and udpDestPort > 1024 and sourceMatch and destMatch) and ((udpSourcePort != 3389 and udpDestPort != 3389) or (udpSourcePort != 1985 and udpDestPort != 1985)):
# If the host does not exist in the HostIntelligence table, log the data and alert the user.
hostExists = prebellicoDb('readFromDb', 'select * from HostIntelligence where ipAddress=(?)', sourceIp)
knownExternalHost = prebellicoDb('readFromDb', 'select * from NetworkIntelligence where recordType = "externalHost" and data=(?)', sourceIp)
if hostExists is None and sourceMatch and destMatch and knownExternalHost is None:
# Work to confirm if the destination IP is a broadcast IP address.
destIpIsBroadcast = 0
destIpHostOctets = destIp.split('.')
destIpHostOctets = [ int(x) for x in destIpHostOctets ]
if ((destIpHostOctets[0] == 255) or (destIpHostOctets[1] == 255 and destIpHostOctets[3] == 255) or (destIpHostOctets[2] == 255 and destIpHostOctets[3] == 255) or (destIpHostOctets[2] < 255 and destIpHostOctets[3] == 255)):
destIpIsBroadcast = 1
if destIpIsBroadcast == 0:
prebellicoLog(("-=-UDP Service Discovery-=-\nA new host was discovered %s, which is talking to %s:%s.") % ( sourceIp, destIp, udpDestPort ))
if destIpIsBroadcast == 1:
prebellicoLog(("-=-UDP Service Discovery-=-\nA new host was discovered %s, which is broadcasting traffic form UDP port %s to %s:%s.") % ( sourceIp, udpSourcePort, destIp, udpDestPort ))
hostType = macPlatformDetection(sourceMac)
prebellicoLog(("-=-Layer 2/3 Recon-=-\n%s appears to be a %s based host.") % ( sourceIp, hostType ))
prebellicoDb('writeToDb', 'insert into HostIntelligence (firstObserved, lastObserved, ipAddress, macAddy, hostType, trustRelationships, discoveryInterface, interfaceIp) values (?,?,?,?,?,?,?,?)', [ timeStamp(), timeStamp(), sourceIp, sourceMac, hostType, destIp, dev, devIp ] )
# Using the source IP address, lookup open UDP ports to see if they match the source port captured within the packet.
getKnownUdpPortsSourceHost = prebellicoDb('readFromDb', 'select openUdpPorts from HostIntelligence where ipAddress=(?)', sourceIp)
# Since we do not know which system has the server service, assume that the destination host is hosting the service and consult the HostIntelligence db for host/port information.
getKnownUdpPortsDestHost = prebellicoDb('readFromDb', 'select openUdpPorts from HostIntelligence where ipAddress=(?)', destIp)
# Check each open port to see if the ports from the client or the server are a match, if they are, disregard the packet.
skipIntelPoolingMessageUpdate = 0
if str(getKnownUdpPortsSourceHost) != 'None':
if str(getKnownUdpPortsSourceHost[0]) != 'None':
getKnownUdpPortsSourceHostList = str(getKnownUdpPortsSourceHost[0]).split(" ")
for index in range(len(getKnownUdpPortsSourceHostList)):
if str(getKnownUdpPortsSourceHostList[index]) == str(udpSourcePort):
skipIntelPoolingMessageUpdate = 1
if str(getKnownUdpPortsDestHost) != 'None':
if str(getKnownUdpPortsSourceHost[0]) != 'None':
getKnownUdpPortsDestHostList = str(getKnownUdpPortsDestHost[0]).split(" ")
for index in range(len(getKnownUdpPortsDestHostList)):
if str(getKnownUdpPortsDestHostList[index]) == str(udpDestPort):
skipIntelPoolingMessageUpdate = 1
checkForKnownUdpEnterpriseService = 0
enterpriseUdpService = str(sourceIp) + ":" + str(udpSourcePort)
checkForKnownUdpEnterpriseService = int(list(prebellicoDb('readFromDb', 'select count( data ) from NetworkIntelligence where recordType = (?) and data = (?)', [ "enterpriseUdpService", enterpriseUdpService ] ))[0])
# Work to confirm if the destination IP is a broadcast IP address.
destIpIsBroadcast = 0
destIpHostOctets = destIp.split('.')
destIpHostOctets = [ int(x) for x in destIpHostOctets ]
if ((destIpHostOctets[0] == 255) or (destIpHostOctets[1] == 255 and destIpHostOctets[3] == 255) or (destIpHostOctets[2] == 255 and destIpHostOctets[3] == 255) or (destIpHostOctets[2] < 255 and destIpHostOctets[3] == 255)):
destIpIsBroadcast = 1
# If this is a new port for the source host and the dest port and IP do not match anything within the HostIntelligence DB, assuming this is a new server we don't know anything about, work to gather as much information about the hosts and ports, update the database and alert the user.
if skipIntelPoolingMessageUpdate != 1 and destIpIsBroadcast != 1:
prebellicoLog(("-=-UDP Service Discovery-=-\nThere appears to be a UDP based conversation between %s:%s and %s:%s. Consulting intelligence to see if we can identify which host has a listening UDP service.") % ( sourceIp, udpSourcePort, destIp, udpDestPort ))
elif skipIntelPoolingMessageUpdate != 1 and destIpIsBroadcast == 1:
prebellicoLog(("-=-UDP Service Discovery-=-\n%s appears to be broadcasting traffic on UDP port %s to %s:%s. Consulting intelligence to determine if there is some sort of service on this port.") %( sourceIp, udpSourcePort, destIp, udpDestPort ))
# Utilize the UdpServerTracking DB to pool intelligence about UDP connections to find a common source port on a reoccurring host.
prebellicoDb('writeToDb', 'insert into UdpServerTracking (sourceIp, udpSourcePort, destIp, udpDestPort) values ((?),(?),(?),(?))', [ sourceIp, udpSourcePort, destIp, udpDestPort] )
# Count the number of instances where the sourceIP and udpSourcePort targeting the same destination broadcast host are referenced in the database. If this number is greater than 10, notify the user and store the data.
if skipIntelPoolingMessageUpdate != 1 and destIpIsBroadcast == 1:
udpSourcePortBroadcastCount = int(list(prebellicoDb('readFromDb', 'select count(sourceIp) from UdpServerTracking where sourceIp = (?) and udpSourcePort = (?) and destIp = (?) and udpDestPort = (?)', [ sourceIp, udpSourcePort, destIp, udpDestPort ] ))[0])
if udpSourcePortBroadcastCount > 10:
prebellicoLog(("-=-UDP Service Discovery-=-\nIntelligence confirms that %s has open UDP port %s.") % ( sourceIp, udpSourcePort ))
if str(getKnownUdpPortsSourceHost[0]) != 'None':
newUdpPorts = checkUnique(getKnownUdpPortsSourceHost, udpSourcePort, 'int')
if str(newUdpPorts) != '0':
prebellicoDb('writeToDb', 'update HostIntelligence set openUdpPorts=(?), lastObserved=(?) where ipAddress = (?)', [ newUdpPorts, timeStamp(), sourceIp ] )
elif str(getKnownUdpPortsSourceHost[0]) == 'None':
prebellicoDb('writeToDb', 'update HostIntelligence set openUdpPorts=(?), lastObserved=(?) where ipAddress = (?)', [ udpSourcePort, timeStamp(), sourceIp ] )
#
# 3 2 1 service detection algorithm
#
# Count the number of instances where the sourceIP and udpSourcePort are referenced in the database.
udpSourcePortCount = int(list(prebellicoDb('readFromDb', 'select count(sourceIp) from UdpServerTracking where sourceIp = (?) and udpSourcePort = (?)', [ sourceIp, udpSourcePort ] ))[0])
# Count how many times the dest IP has connected to the sourceIp and udpSourcePort using a different port than udpDestPort.
destIpCount = int(list(prebellicoDb('readFromDb', 'select count(sourceIp) from UdpServerTracking where sourceIp = (?) and udpSourcePort = (?) and destIp = (?) and udpDestPort != (?)', [ sourceIp, udpSourcePort, destIp, udpDestPort ] ))[0])
# Count how many times another host has connected to the sourceIP and udpSourcePort.
nonDestIpCount = int(list(prebellicoDb('readFromDb', 'select count(sourceIp) from UdpServerTracking where sourceIp = (?) and udpSourcePort = (?) and destIp != (?) and udpDestPort != (?)', [ sourceIp, udpSourcePort, destIp, udpDestPort ] ))[0])
#
# 2 2 2 service detection algorithm
#
destIpDistinctCount = int(list(prebellicoDb('readFromDb', 'select count(distinct destIp) from UdpServerTracking where sourceIp = (?) and udpSourcePort = (?)', [ sourceIp, udpSourcePort ] ))[0])
udpDestPortDistinctCount = int(list(prebellicoDb('readFromDb', 'select count(distinct udpDestPort) from UdpServerTracking where sourceIp = (?) and udpSourcePort = (?)', [ sourceIp, udpSourcePort ] ))[0])
# If the udpSourcePort appears to be associated with numerous other hosts on numerous other udpDestPorts, report this to the user, store it in the HostIntelligence database, and clear the UdpServerTracking database as this data will no longer be needed.
if (( udpSourcePortCount >= 3 and destIpCount >= 2 and nonDestIpCount >= 1 ) or (( destIpDistinctCount >= 2 and udpDestPortDistinctCount >=2 ) and ( destIpDistinctCount == udpDestPortDistinctCount ))) and skipIntelPoolingMessageUpdate != 1:
prebellicoLog(("-=-UDP Service Discovery-=-\nIntelligence confirms that %s has an open UDP port: %s.") % ( sourceIp, udpSourcePort ))
if str(getKnownUdpPortsSourceHost[0]) != 'None':
newUdpPorts = checkUnique(getKnownUdpPortsSourceHost, udpSourcePort, 'int')
if str(newUdpPorts) != '0':
prebellicoDb('writeToDb', 'update HostIntelligence set openUdpPorts=(?), lastObserved=(?) where ipAddress = (?)', [ newUdpPorts, timeStamp(), sourceIp ] )
elif str(getKnownUdpPortsSourceHost[0]) == 'None':
prebellicoDb('writeToDb', 'update HostIntelligence set openUdpPorts=(?), lastObserved=(?) where ipAddress = (?)', [ udpSourcePort, timeStamp(), sourceIp ] )
# Determine if this is a widely used service, such as a network proxy. If so, alert the user and log the data to the NetworkIntel db.
numberOfUdpServiceClients = int(list(prebellicoDb('readFromDb', 'select count (distinct destIp) from UdpServerTracking where sourceIp = (?) and udpSourcePort = (?)', [ sourceIp, udpSourcePort ] ))[0])
if numberOfUdpServiceClients >= 5 and checkForKnownUdpEnterpriseService == 0 :
prebellicoLog(("-=-UDP Service Discovery-=-\nIntelligence confirms that %s:%s is a heavily used network service. While pooling data, %s clients were found to be interacting with this service.") % ( sourceIp, udpSourcePort, numberOfUdpServiceClients ))
enterpriseUdpService = str(sourceIp) + ":" + str(udpSourcePort)
prebellicoDb('writeToDb', 'insert into NetworkIntelligence ( recordType, data, associatedHost, methodObtained, dateObserved, sourceInterface ) values ( "enterpriseUdpService", ?, ?, "passiveNetwork", ?, ? )', [ enterpriseUdpService, sourceIp, timeStamp(), dev ] )
# Limit collections for push events to 1000, allowing users to query the DB with enough historical data without filling too much of the disk.
numberOfUdpServiceClients = int(list(prebellicoDb('readFromDb', 'select count (distinct destIp) from UdpServerTracking where sourceIp = (?) and udpSourcePort = (?)', [ sourceIp, udpSourcePort ] ))[0])
if numberOfUdpServiceClients > 1000:
prebellicoDb('writeToDb', 'delete from UdpServerTracking where sourceIP = (?) and udpSourcePort = (?)', [ sourceIp, udpSourcePort ] )
# If we see someone scanning for SNMP using community strings, alert the user to the names that are used, and the source host that it is coming from. Typically, this is an IT/Security event, so this is attributed to 'Skynet'.
if udpDestPort == 161:
snmpPacketFilterRegex = re.compile('[a-zA-Z0-9*].*')# Regex to yank data within SNMP string data.
snmpTempData=snmpPacketFilterRegex.findall(tempData)
if len(snmpTempData) == 0:
return
else:
potentialSnmpStrings = re.split('[\x00-\x1f,\x7f-\xff]',snmpTempData[0])
for justTheString in potentialSnmpStrings:
if len(justTheString) >= 4:
communityString = justTheString
knownSnmpString = prebellicoDb('readFromDb', 'select * from NetworkIntelligence where recordType = "observedSnmp" and data=(?)', communityString)
knownSkynetSystem = prebellicoDb('readFromDb', 'select * from NetworkIntelligence where recordType = "skynet" and data=(?)', sourceIp)
if knownSkynetSystem is None:
prebellicoLog(("-=-Skynet Recon-=-\nA new security system has been identified: %s.") % ( sourceIp ))
prebellicoDb('writeToDb', 'insert into NetworkIntelligence (recordType, data, associatedHost, methodObtained, dateObserved, sourceInterface) values ("skynet", ?, ?, "passiveNetwork", ?, ?)', [ sourceIp, sourceIp, timeStamp(), dev ] )
if knownSnmpString is None:
prebellicoLog(("-=-Skynet Recon-=-\n%s is scanning for systems with an SNMPv1 community string: %s.") % ( sourceIp, communityString ))
prebellicoDb('writeToDb', 'insert into NetworkIntelligence (recordType, data, associatedHost, methodObtained, dateObserved, sourceInterface) values ("observedSnmp",?,?,"passiveNetwork",?,?)', [ communityString, sourceIp, timeStamp(), dev ] )
# If we have a response from a host on port 161, notify the user and extract the SNMP string - note this is buggy as there is not SNMP packet verification.
if udpSourcePort == 161:
snmpPacketFilterRegex = re.compile('[a-zA-Z0-9.*].*(?=:)')# Regex to yank data before colon within SNMP string data.
snmpTempData=snmpPacketFilterRegex.findall(tempData)
if len(snmpTempData) == 0:
return
else:
potentialSnmpStrings = re.split('[\x00-\x1f,\x7f-\xff]',snmpTempData[0])
for justTheString in potentialSnmpStrings:
if len(justTheString) >= 4:
communityString = justTheString
# Look in the NetworkIntel table of the DB and see if we have observed this SNMP community string with a host before.
knownValidatedSnmpString = prebellicoDb('readFromDb', 'select * from NetworkIntelligence where recordType = "validatedSnmp" and data=(?)', communityString)
# If not, notify the user that this is a new string and store the data in the NetworkIntel table and HostIntel table.
if knownValidatedSnmpString is None:
prebellicoLog(("-=-SNMP Recon-=-We have a new SNMPv1 community string from %s: %s.") % ( sourceIp, communityString ))
prebellicoDb('writeToDb', 'insert into NetworkIntelligence (recordType, data, associatedHost, methodObtained, dateObserved, sourceInterface) values ("validatedSnmp",?,?,"passiveNetwork",?,?)', [ communityString, sourceIp, timeStamp(), dev ] )
prebellicoDb('writeToDb', 'update HostIntelligence set validatedSnmp=(?), lastObserved=(?) where ipAddress = (?)', [communityString, timeStamp(), sourceIp] )
# If this is not a new SNMP community string, work to verify if this string is unique to this host. I think this is rather inefficient.
if knownValidatedSnmpString is not None:
hostsUsingValdiatedSnmpString = prebellicoDb('readFromDb', 'select associatedHost from NetworkIntelligence where recordType="validatedSnmp" and data=(?)', communityString)
# This should never return as None, but there was a bug of some sorts where it did, so this is my quick fix after it pwned me.
if hostsUsingValdiatedSnmpString is not None:
countHostsUsingValidatedSnmpString = 0
notifyUserOfNewHostUsingSnmpString = 0
while countHostsUsingValidatedSnmpString < len(hostsUsingValdiatedSnmpString):
if hostsUsingValdiatedSnmpString[countHostsUsingValidatedSnmpString] == sourceIp:
notifyUserOfNewHostUsingSnmpString = 1
countHostsUsingValidatedSnmpString += 1
# If this known SNMP community string is unique to this host, annotate it within the NetworkIntel table within the DB and notify the user.
if notifyUserOfNewHostUsingSnmpString == 0:
prebellicoLog(("-=-SNMP Recon-=-Identified another host that uses '%s' as an SNMP community string: %s") % ( communityString, sourceIp ))
prebellicoDb('writeToDb', 'update HostIntelligence set validatedSnmp=(?), lastObserved=(?) where ipAddress = (?)', [ communityString, timeStamp(), sourceIp ] )
prebellicoDb('writeToDb', 'insert into NetworkIntelligence (recordType, data, associatedHost, methodObtained, dateObserved, sourceInterface) values ("validatedSnmp",?,?,"passiveNetwork",?,?)', [ communityString, sourceIp, timeStamp(), dev ] )
# If we have an SMB packet, extract intelligence from this - this is going to be bigger than simply dumping the packets Going to require classification of types of requests.
if udpSourcePort == 138:
# Ran into a python bug that pwned me arse, so I rewrote this trying to solve the problem, which resulted in bloated code. I should work to trim this down.
knownHostnameString = prebellicoDb('readFromDb', 'select hostname from HostIntelligence where ipAddress = (?)', sourceIp)
knownHostDescriptionString = prebellicoDb('readFromDb', 'select hostDescription from HostIntelligence where ipAddress = (?)', sourceIp)
mailSlotMatch = re.search("\\MAILSLOT.*BROWSE", ethernetPacket.child().child().child().get_buffer_as_string(), re.MULTILINE)
if mailSlotMatch:
mailSlotString = re.findall("(?<=\n\x00)(?!\x03\x90\x00)[\w\-\!\@\$\%\^\&\(\)\+\=\[\]\{\}\'\;\~\`]{1,15}(?=\x00)|(?<=\x0f\x01U\xaa)(?!\x03\x90\x00)[\w\s\:\-\=\_\-\+\[\]\{\}\!\@\#\$\%\^\&\*\(\)\'\"\:\;\~\`]+(?=\x00)", ethernetPacket.child().child().child().get_buffer_as_string(), re.MULTILINE)
if len(mailSlotString) == 1:
if knownHostnameString[0] != mailSlotString[0]:
prebellicoLog(('-=-SMB Recon-=-\nThe hostname for \'%s\' is \'%s\'.') % ( sourceIp, mailSlotString[0] ))
prebellicoDb('writeToDb', 'update HostIntelligence set hostname=(?), lastObserved=(?) where ipAddress = (?)', [ mailSlotString[0], timeStamp(), sourceIp ] )
if len(mailSlotString) == 2:
if knownHostnameString[0] != mailSlotString[0] and knownHostDescriptionString != mailSlotString[1]:
prebellicoLog(('-=-SMB Recon-=-\nThe hostname for \'%s\' is \'%s\' and it describes itself as \'%s\'.') % ( sourceIp, mailSlotString[0], mailSlotString[1] ))
prebellicoDb('writeToDb', 'update HostIntelligence set hostname=(?), hostDescription=(?), lastObserved=(?) where ipAddress = (?)', [ mailSlotString[0], mailSlotString[1], timeStamp(), sourceIp] )
# Work support for HSRP protocol
global hsrpNotification
if ( udpSourcePort == 1985 and hsrpNotification != 1 ):
prebellicoLog('-=-Layer2/3 Recon-=-\nCisco HSRP is spoken here.')
hsrpNotification = 1
if ( udpSourcePort == 1985 ):
hsrpTempData = ethernetPacket.child().child().child().get_buffer_as_string()
hsrpPacketFilterRegex = re.compile('[a-zA-Z0-9*].*')# Regex to yank data within HSRP string data.
hsrpTempData=hsrpPacketFilterRegex.findall(hsrpTempData)
#Trying to work past a bug here for various types of HSRP packets. To manage this I have adopted a try/except-pass method to manage these issues. Additionally, this doesn't really work to pull the hashed value, but manages a crash Need to resolve this issue somehow.
try:
potentialHsrpPass = re.split('[\x00-\x1f,\x7f-\xff]',hsrpTempData[0])
for justTheString in potentialHsrpPass:
if len(justTheString) >= 4:
hsrpPass = justTheString
knownHsrpPassword = prebellicoDb('readFromDb', 'select * from NetworkIntelligence where recordType = "hsrp" and data=(?)', hsrpPass)
if len(hsrpPass) == 32:
md5Detect = re.match("(?:" + '[a-zA-Z0-9.*]{32}' + r")\Z", hsrpPass) # This is a re.findall hack for Python2.
if md5Detect is not None and knownHsrpPassword is None:
prebellicoLog(('-=-Layer2/3 Recon-=-\nWe have an HSRP packet with either an MD5 hashed password or a raw password: %s') % ( hsrpPass ))
prebellicoDb('writeToDb', 'insert into NetworkIntelligence (recordType, data, associatedHost, methodObtained, dateObserved, sourceInterface) values ("hsrp",?,?,"passiveNetwork",?,?)', [ hsrpPass, sourceIp, timeStamp(), dev ] )
elif knownHsrpPassword is None:
prebellicoLog(('-=-Layer2/3 Recon-=-\nWe have an HSRP packet with an unhashed password: %s') % ( hsrpPass ))
prebellicoDb('writeToDb', 'insert into NetworkIntelligence (recordType, data, associatedHost, methodObtained, dateObserved, sourceInterface) values ("hsrp",?,?,"passiveNetwork",?,?)', [ hsrpPass, sourceIp, timeStamp(), dev ] )
except:
pass
return
# Function designed to sniff out intel tied to captured TCP PSH requests.
def tcpPushDiscovery(header,data):
# Start to decode the packet and determine the protocol number. If not TCP, return as it does not apply here.
ethernetPacket = decoder.decode(data)
protocolNumber = ethernetPacket.child().child().protocol
if protocolNumber != 6:
return
# Extract relevant data from the ethernet packet.
macHdr = ethernetPacket
sourceMac = macHdr.as_eth_addr(macHdr.get_ether_shost())
destMac = macHdr.as_eth_addr(macHdr.get_ether_dhost())
ipHdr = ethernetPacket.child()
tcpHdr = ipHdr.child()
sourceIp = ipHdr.get_ip_src()
sourcePort = tcpHdr.get_th_sport()
destIp = ipHdr.get_ip_dst()
destPort = tcpHdr.get_th_dport()
# Pull TCP flags to determine TCP session state so that we can determine what TCP method to call for intel.
tcpSyn = ethernetPacket.child().child().get_SYN()
tcpAck = ethernetPacket.child().child().get_ACK()
tcpEce = ethernetPacket.child().child().get_ECE()
tcpCwr = ethernetPacket.child().child().get_CWR()
tcpFin = ethernetPacket.child().child().get_FIN()
tcpPsh = ethernetPacket.child().child().get_PSH()
tcpRst = ethernetPacket.child().child().get_RST()
tcpUrg = ethernetPacket.child().child().get_URG()
# If a TCP push packet is discovered from a previously unknown session, work to process it.
if ( tcpPsh == 1 and tcpAck == 1 ):
# Work to determine if these are known internal IP addresses based upon RFC1918 or user supplied data.
(sourceMatch, destMatch) = ( checkInternalAddress(sourceIp), checkInternalAddress(destIp) )
# Look to see if the IP address appears to belong to a set of known nets. If not, log the new network and alert the user.
if sourceMatch:
checkKnownNetwork(sourceIp, sourceMatch)
if destMatch:
checkKnownNetwork(destIp, destMatch)
# If a host does not match an RFC1918 address or a user specified internal address that an internal address is talking to, note the external host and the internal host permitted to talk to it and notify the user about the permitted connection.
if not sourceMatch and destMatch:
global tcpNetworkEgressPermitted
if tcpNetworkEgressPermitted == 0:
prebellicoLog("-=-Egress Recon-=-\nNetwork egress detected! Internal hosts are permitted to connect to the internet via TCP.")
tcpNetworkEgressPermitted = 1
knownExternalHost = prebellicoDb('readFromDb', 'select * from NetworkIntelligence where recordType = "externalHost" and data=(?)', sourceIp)
if knownExternalHost is None:
prebellicoDb('writeToDb', 'insert into NetworkIntelligence (recordType, data, associatedHost, methodObtained, dateObserved, sourceInterface) values ("externalHost", ?,?,"passiveNetwork",?,?)', [ sourceIp, destIp, timeStamp(), dev ] )
prebellicoLog(("-=-Egress Recon Update-=-\n%s is permitted to connect to %s on TCP port %s.") % (destIp, sourceIp, sourcePort))
# If completely arbitrary numbers based off of assumed sessions exist where the source port is less than 1024, extract intel and alert the user.
if ( sourcePort <= 1024 and destPort > 1024 and sourceMatch and destMatch):
# If the host does not exist in the HostIntelligence table, log the data and alert the user.
hostExists = prebellicoDb('readFromDb', 'select * from HostIntelligence where ipAddress=(?)', sourceIp)
knownExternalHost = prebellicoDb('readFromDb', 'select * from NetworkIntelligence where recordType = "externalHost" and data=(?)', sourceIp)
if hostExists is None and destMatch and sourceMatch and knownExternalHost is None:
prebellicoLog(("-=-TCP Service Discovery-=-\nA new host was discovered with what appears to be an open TCP port - %s:%s. %s is talking to this service.") % ( sourceIp, sourcePort, destIp ))
hostType = macPlatformDetection(sourceMac)
prebellicoLog(("-=-Layer 2/3 Recon-=-\n%s appears to be a %s based host.") % ( sourceIp, hostType ))
prebellicoDb('writeToDb', 'insert into HostIntelligence (firstObserved, lastObserved, ipAddress, macAddy, hostType, openTcpPorts, trustRelationships, discoveryInterface, interfaceIp) values (?,?,?,?,?,?,?,?,?)', [ timeStamp(), timeStamp(), sourceIp, sourceMac, hostType, sourcePort, destIp, dev, devIp ] )
return
# Using the source IP address, lookup open TCP ports to see if they match the source port captured within the packet. If this is a new port for this host, update the database and alert the user.
countGetKnownTcpPorts = prebellicoDb('readFromDb', 'select count (openTcpPorts) from HostIntelligence where ipAddress=(?)', sourceIP)
if countGetKnownTcpPorts[0] != 0:
getKnownTcpPorts = prebellicoDb('readFromDb', 'select openTcpPorts from HostIntelligence where ipAddress=(?)', sourceIp )
newTcpPorts = checkUnique(getKnownTcpPorts, sourcePort, 'int')
if str(newTcpPorts) != '0':
prebellicoDb('writeToDb', 'update HostIntelligence set openTcpPorts=(?), lastObserved=(?) where ipAddress = (?)', [ newTcpPorts, timeStamp(), sourceIp ] )
prebellicoLog(("-=-TCP Service Discovery-=-\nThere appears to be an open TCP port on %s:%s, which is talking to %s.") % ( sourceIp, sourcePort, destIp ))
elif countGetKnownTcpPorts[0] == 0:
prebellicoDb('writeToDb', 'update HostIntelligence set openTcpPorts=(?), lastObserved=(?) where ipAddress = (?)', [ sourcePort, timeStamp(), sourceIp ] )
prebellicoLog(("-=-TCP Service Discovery-=-\nThere appears to be an open TCP port on %s:%s, which is talking to %s.") % ( sourceIp, sourcePort, destIp ))
# Using the source IP address, look up known trusted hosts and see if this is a new trusted host. If it is, log this and alert the user.
countGetKnownTrustedHosts = prebellicoDb('readFromDb', 'select count(trustRelationships) from HostIntelligence where ipAddress = (?)', sourceIp )
if countGetKnownTrustedHosts[0] == 0:
prebellicoDb('writeToDb', 'update HostIntelligence set trustRelationships = (?), lastObserved = (?) where ipAddress = (?)', [ destIp, timeStamp(), sourceIp] )
prebellicoLog(("-=-Trust Intelligence-=-\nThe following host(s) are permitted to talk to %s: %s.") % (sourceIp, destIp))
elif countGetKnownTrustedHosts[0] != 0:
getKnownTrustedHosts = prebellicoDb('readFromDb', 'select trustRelationships from HostIntelligence where ipAddress = (?)', sourceIp)
newTrustedHosts = checkUnique(getKnownTrustedHosts, destIp, 'string')
if newTrustedHosts != 0:
prebellicoLog(("-=-Trust Intelligence-=-\nThe following host(s) are permitted to talk to %s: %s.") % (sourceIp, newTrustedHosts))
prebellicoDb('writeToDb', 'update HostIntelligence set trustRelationships = (?), lastObserved = (?) where ipAddress = (?)', [ newTrustedHosts, timeStamp(), sourceIp ] )
return
# If the inverse of a session using TCP ports less than 1024 exist, extract intel and alert the user.
if ( sourcePort > 1024 and destPort <= 1024 and sourceMatch and destMatch):
# If the host does not exist in the HostIntelligence table, log the data and alert the user.
hostExists = prebellicoDb('readFromDb', 'select * from HostIntelligence where ipAddress=(?)', destIp)
knownExternalHost = prebellicoDb('readFromDb', 'select * from NetworkIntelligence where recordType = "externalHost" and data=(?)', destIp)
if hostExists is None and destMatch and sourceMatch and knownExternalHost is None:
prebellicoLog(("-=-TCP Service Discovery-=-\n%s appears to be talking to a newly discovered host on an open TCP port - %s:%s.") % ( sourceIp, destIp, destPort ))
hostType = macPlatformDetection(destMac)
prebellicoLog(("-=-Layer 2/3 Recon-=-\n%s appears to be a %s based host.") % ( sourceIp, hostType ))
prebellicoDb('writeToDb', 'insert into HostIntelligence (firstObserved, lastObserved, ipAddress, macAddy, hostType, discoveryInterface, interfaceIp) values (?,?,?,?,?,?,?)', [ timeStamp(), timeStamp(), destIp, destMac, hostType, dev, devIp] )
return
# Using the source IP address, lookup open TCP ports to see if they match the source port captured within the packet. If this is a new port for this host, update the database and alert the user.
countGetKnownTcpPorts = prebellicoDb('readFromDb', 'select count (openTcpPorts) from HostIntelligence where ipAddress=(?)', destIp )
if countGetKnownTcpPorts[0] != 0:
getKnownTcpPorts = prebellicoDb('readFromDb', 'select openTcpPorts from HostIntelligence where ipAddress=(?)', destIp )
newTcpPorts = checkUnique(getKnownTcpPorts, destPort, 'int')
if str(newTcpPorts) != '0':
prebellicoDb('writeToDb', 'update HostIntelligence set openTcpPorts=(?), lastObserved=(?) where ipAddress = (?)', [ newTcpPorts, timeStamp(), destIp ] )
prebellicoLog(("-=-TCP Service Discovery-=-\n%s appears to be talking to an open TCP port - %s:%s.") % ( sourceIp, destIp, destPort ))
elif countGetKnownTcpPorts[0] == 0:
prebellicoDb('writeToDb', 'update HostIntelligence set openTcpPorts=(?), lastObserved=(?) where ipAddress = (?)', [ sourcePort, timeStamp(), sourceIp ] )
prebellicoLog(("-=-TCP Service Discovery-=-\nThere appears to be an open TCP port on %s:%s, which is talking to %s.") % ( sourceIp, sourcePort, destIp ))
countGetKnownTrustedHosts = prebellicoDb('readFromDb', 'select count(trustRelationships) from HostIntelligence where ipAddress = (?)', destIp )
if countGetKnownTrustedHosts[0] == 0:
prebellicoDb('writeToDb', 'update HostIntelligence set trustRelationships = (?), lastObserved = (?) where ipAddress = (?)', [ sourceIp, timeStamp(), destIp ] )
prebellicoLog(("-=-Trust Intelligence-=-\nThe following host(s) are permitted to talk to %s: %s.") % (destIp, sourceIp))
elif countGetKnownTrustedHosts[0] != 0:
getKnownTrustedHosts = prebellicoDb('readFromDb', 'select trustRelationships from HostIntelligence where ipAddress = (?)', destIp )
newTrustedHosts = checkUnique(getKnownTrustedHosts, sourceIp, 'string')
if newTrustedHosts != 0:
prebellicoLog(("-=-Trust Intelligence-=-\nThe following host(s) are permitted to talk to %s: %s.") % (destIp, newTrustedHosts))
prebellicoDb('writeToDb', 'update HostIntelligence set trustRelationships = (?), lastObserved = (?) where ipAddress = (?)', [ newTrustedHosts, timeStamp(), destIp ] )
return
# If we have a situation where we are not sure where the server is, because both ports are above 1024, work to pool intel to determine where the server is.
if sourcePort > 1024 and destPort > 1024 and sourceMatch and destMatch:
# If the host does not exist in the HostIntelligence table, log the data and alert the user.
hostExists = prebellicoDb('readFromDb', 'select * from HostIntelligence where ipAddress=(?)', sourceIp)
knownExternalHost = prebellicoDb('readFromDb', 'select * from NetworkIntelligence where recordType = "externalHost" and data=(?)', sourceIp)
if hostExists is None and sourceMatch and destMatch and knownExternalHost is None:
prebellicoLog(("-=-TCP Service Discovery-=-\nA new host was discovered %s, which is talking to %s:%s.") % ( sourceIp, destIp, destPort ))
hostType = macPlatformDetection(sourceMac)
prebellicoLog(("-=-Layer 2/3 Recon-=-\n%s appears to be a %s based host.") % ( sourceIp, hostType ))
prebellicoDb('writeToDb', 'insert into HostIntelligence (firstObserved, lastObserved, ipAddress, macAddy, hostType, trustRelationships, discoveryInterface, interfaceIp) values (?,?,?,?,?,?,?,?)', [ timeStamp(), timeStamp(), sourceIp, sourceMac, hostType, destIp, dev, devIp ] )
# Using the source IP address, lookup open TCP ports to see if they match the source port captured within the packet.
getKnownTcpPortsSourceHost = prebellicoDb('readFromDb', 'select openTcpPorts from HostIntelligence where ipAddress=(?)', sourceIp)
# Since we do not know which system has the server service, assume that the destination host is hosting the service and consult the HostIntelligence db for host/port information.
getKnownTcpPortsDestHost = prebellicoDb('readFromDb', 'select openTcpPorts from HostIntelligence where ipAddress=(?)', destIp)
# Check each open port to see if the ports from the client or the server are a match, if they are, disregard the packet.
skipIntelPoolingMessageUpdate = 0
if str(getKnownTcpPortsSourceHost) != 'None':
if str(getKnownTcpPortsSourceHost[0]) != 'None':
getKnownTcpPortsSourceHostList = str(getKnownTcpPortsSourceHost[0]).split(" ")
for index in range(len(getKnownTcpPortsSourceHostList)):
if str(getKnownTcpPortsSourceHostList[index]) == str(sourcePort):
skipIntelPoolingMessageUpdate = 1
if str(getKnownTcpPortsDestHost) != 'None':
if str(getKnownTcpPortsSourceHost[0]) != 'None':
getKnownTcpPortsDestHostList = str(getKnownTcpPortsDestHost[0]).split(" ")
for index in range(len(getKnownTcpPortsDestHostList)):
if str(getKnownTcpPortsDestHostList[index]) == str(destPort):
skipIntelPoolingMessageUpdate = 1
checkForKnownEnterpriseService = 0
enterpriseTcpService = str(sourceIp) + ":" + str(sourcePort)
checkForKnownEnterpriseService = int(list(prebellicoDb('readFromDb', 'select count( data ) from NetworkIntelligence where recordType = (?) and data = (?)', [ "enterpriseTcpService", enterpriseTcpService ] ))[0])
# If this is a new port for the source host and the dest port and IP do not match anything within the HostIntelligence DB, assuming this is a new server we don't know anything about, work to gather as much information about the hosts and ports, update the database and alert the user.
if skipIntelPoolingMessageUpdate != 1:
prebellicoLog(("-=-TCP Service Discovery-=-\nThere appears to be a TCP based conversation between %s:%s and %s:%s. Consulting intelligence to see if we can identify which host has a listening TCP service.") % ( sourceIp, sourcePort, destIp, destPort ))
# Utilize the tcpPushSessionTracking table to pool intelligence about push sessions to find a common source port on a reoccurring host.
prebellicoDb('writeToDb', 'insert into TcpPushSessionTracking (sourceIp, sourcePort, destIp, destPort) values ((?),(?),(?),(?))', [ sourceIp, sourcePort, destIp, destPort] )
#
# 3 2 1 service detection algorithm
#
# Count the number of instances where the sourceIP and sourcePort are referenced in the database.
sourcePortCount = int(list(prebellicoDb('readFromDb', 'select count(sourceIp) from TcpPushSessionTracking where sourceIp = (?) and sourcePort = (?)', [ sourceIp, sourcePort ] ))[0])
# Count how many times the dest IP has connected to the sourceIp and sourcePort using a different port than destPort.
destIpCount = int(list(prebellicoDb('readFromDb', 'select count(sourceIp) from TcpPushSessionTracking where sourceIp = (?) and sourcePort = (?) and destIp = (?) and destPort != (?)', [ sourceIp, sourcePort, destIp, destPort ] ))[0])
# Count how many times another host has connected to the sourceIP and sourcePort.
nonDestIpCount = int(list(prebellicoDb('readFromDb', 'select count(sourceIp) from TcpPushSessionTracking where sourceIp = (?) and sourcePort = (?) and destIp != (?) and destPort != (?)', [ sourceIp, sourcePort, destIp, destPort ] ))[0])
#
# 2 2 2 service detection algorithm
#
destIpDistinctCount = int(list(prebellicoDb('readFromDb', 'select count(distinct destIp) from TcpPushSessionTracking where sourceIp = (?) and sourcePort = (?)', [ sourceIp, sourcePort ] ))[0])
destPortDistinctCount = int(list(prebellicoDb('readFromDb', 'select count(distinct destPort) from TcpPushSessionTracking where sourceIp = (?) and sourcePort = (?)', [ sourceIp, sourcePort ] ))[0])
# If the sourcePort appears to be associated with numerous other hosts on numerous other destPorts, report this to the user, store it in the HostIntelligence database, and clear the TcpPushSessionTracking database as this data will no longer be needed.
if (( sourcePortCount >= 3 and destIpCount >= 2 and nonDestIpCount >= 1 ) or (( destIpDistinctCount >= 2 and destPortDistinctCount >=2 ) and ( destIpDistinctCount == destPortDistinctCount ))) and skipIntelPoolingMessageUpdate != 1:
prebellicoLog(("-=-TCP Service Discovery-=-\nIntelligence confirms that %s is the host with open TCP port %s.") % ( sourceIp, sourcePort ))
if str(getKnownTcpPortsSourceHost[0]) != 'None':
newTcpPorts = checkUnique(getKnownTcpPortsSourceHost, sourcePort, 'int')
if str(newTcpPorts) != '0':
prebellicoDb('writeToDb', 'update HostIntelligence set openTcpPorts=(?), lastObserved=(?) where ipAddress = (?)', [ newTcpPorts, timeStamp(), sourceIp ] )
elif str(getKnownTcpPortsSourceHost[0]) == 'None':
prebellicoDb('writeToDb', 'update HostIntelligence set openTcpPorts=(?), lastObserved=(?) where ipAddress = (?)', [ sourcePort, timeStamp(), sourceIp ] )
# Determine if this is a widely used service, such as a network proxy. If so, alert the user and log the data to the NetworkIntel db.
numberOfServiceClients = int(list(prebellicoDb('readFromDb', 'select count (distinct destIp) from TcpPushSessionTracking where sourceIp = (?) and sourcePort = (?)', [ sourceIp, sourcePort ] ))[0])
if numberOfServiceClients >= 5 and checkForKnownEnterpriseService == 0 :
prebellicoLog(("-=-TCP Service Discovery-=-\nIntelligence confirms that %s:%s is a heavily used network service. While pooling data, %s clients were found to be interacting with this service.") % ( sourceIp, sourcePort, numberOfServiceClients ))
enterpriseTcpService = str(sourceIp) + ":" + str(sourcePort)
prebellicoDb('writeToDb', 'insert into NetworkIntelligence ( recordType, data, associatedHost, methodObtained, dateObserved, sourceInterface ) values ( "enterpriseTcpService", ?, ?, "passiveNetwork", ?, ? )', [ enterpriseTcpService, sourceIp, timeStamp(), dev ] )
# Limit collections for push events to 1000, allowing users to query the DB with enough historical data without filling too much of the disk.
numberOfServiceClients = int(list(prebellicoDb('readFromDb', 'select count (distinct destIp) from TcpPushSessionTracking where sourceIp = (?) and sourcePort = (?)', [ sourceIp, sourcePort ] ))[0])
if numberOfServiceClients > 1000:
prebellicoDb('writeToDb', 'delete from TcpPushSessionTracking where sourceIP = (?) and sourcePort = (?)', [ sourceIp, sourcePort ] )
return
# Function designed to sniff out intel tied to generic TCP intelligence such as predictable IPID numbers.
def tcpDiscovery(header,data):
# Start to decode the packet and determine the protocol number. If not TCP, return as it does not apply here.
ethernetPacket = decoder.decode(data)
protocolNumber = ethernetPacket.child().child().protocol
if protocolNumber != 6:
return
# Extract relevant data from the ethernet packet
macHdr = ethernetPacket
ipHdr = ethernetPacket.child()
tcpHdr = ipHdr.child()
sourceIpSequenceNumber = tcpHdr.get_th_seq()
sourceIp = ipHdr.get_ip_src()
# Work to determine if we have an IPID sequence number from this host. If so, simply return for more carnage.
checkKnownIpidNumberHost = prebellicoDb('readFromDb', 'select count (zombieIpid) from HostIntelligence where ipAddress=(?)', sourceIp )
if checkKnownIpidNumberHost != 0:
return
# Get a count of ipid sequence numbers
ipidCount = len(tcpIpidNumbers[sourceIp])
# Once we have three IPID sequence numbers, look for predictability and clean the list of ipid sequence numbers to preserve memory.
if ipidCount == 12:
oldZombieHost = 0
ipidItem = 0
oldDiffIpid = 0
diffIpidMatch = 0
while ipidItem <= 10:
newDiffIpid = tcpIpidNumbers[sourceIp][ipidItem] - tcpIpidNumbers[sourceIp][ipidItem + 1]
if oldDiffIpid == newDiffIpid:
diffIpidMatch += 1
for zombieHost in zombieHosts.keys():
if zombieHost == sourceIp:
oldZombieHost = 1
oldDiffIpid = newDiffIpid
ipidItem += 1
if ( oldZombieHost == 0 and diffIpidMatch >= 10 and newDiffIpid != 0 ):
prebellicoDb('writeToDb', 'update HostIntelligence set zombieIpid=(?), lastObserved=(?) where ipAddress = (?)', [newDiffIpid, timeStamp(), sourceIp] )
prebellicoLog(("-=-Zombie Recon-=-\n%s uses predictable IPID sequence numbers! Last difference:%s. Captured IPID sequence numbers:\n%s\n") % ( sourceIp,newDiffIpid,tcpIpidNumbers[sourceIp] ))
for ipidNumber in tcpIpidNumbers[sourceIp]:
zombieHosts[sourceIp].add(ipidNumber)
# Clean the list of ipid sequence numbers to preserve memory.
ipidMaster = tcpIpidNumbers[sourceIp][11]
del tcpIpidNumbers[sourceIp]
tcpIpidNumbers[sourceIp].append(ipidMaster)
if sourceIpSequenceNumber != 0:
tcpIpidNumbers[sourceIp].append(sourceIpSequenceNumber)
return
# Function designed to sniff out the TCP SYN/ACK portion of the three way handshake to enumerate listing services for a host.
def synAckDiscovery(header, data):
# Start to decode the packet and determine the protocol number. If not TCP, return as it does not apply here.
ethernetPacket = decoder.decode(data)
protocolNumber = ethernetPacket.child().child().protocol
if protocolNumber != 6:
return
# Extract relevant data from the ethernet packet.
macHdr = ethernetPacket
sourceMac = macHdr.as_eth_addr(macHdr.get_ether_shost())
destMac = macHdr.as_eth_addr(macHdr.get_ether_dhost())
ipHdr = ethernetPacket.child()
tcpHdr = ipHdr.child()
sourceIp = ipHdr.get_ip_src()
sourcePort = tcpHdr.get_th_sport()
destIp = ipHdr.get_ip_dst()
destPort = tcpHdr.get_th_dport()
# Pull TCP flags to determine TCP session state so that we can determine what TCP method to call for intel.
tcpSyn = ethernetPacket.child().child().get_SYN()
tcpAck = ethernetPacket.child().child().get_ACK()
tcpEce = ethernetPacket.child().child().get_ECE()
tcpCwr = ethernetPacket.child().child().get_CWR()
tcpFin = ethernetPacket.child().child().get_FIN()
tcpPsh = ethernetPacket.child().child().get_PSH()
tcpRst = ethernetPacket.child().child().get_RST()
tcpUrg = ethernetPacket.child().child().get_URG()
# Work to determine if these are known internal IP addresses based upon RFC1918 or user supplied data.
(sourceMatch, destMatch) = ( checkInternalAddress(sourceIp), checkInternalAddress(destIp) )