@@ -6,7 +6,7 @@ import getpass
66import argparse
77
88import requests
9- from packettotal_sdk import packettotal_api
9+ from packettotal_sdk import search_tools
1010
1111
1212def _output_text_response (response : requests .Response , output_file = None ) -> None :
@@ -36,7 +36,7 @@ def _output_binary_response(response: requests.Response, pcap_id: str) -> None:
3636 :param response: A request.Response instance containing a populated .content variable
3737 :param pcap_id: An md5 hash corresponding to the pcap file submission on PacketTotal.com
3838 """
39- if response .status_code not in [200 , 301 ]:
39+ if response .status_code not in [200 , 303 ]:
4040 print ('An error occurred. [{}]' .format (response .status_code ), file = sys .stderr )
4141 print (response .text , file = sys .stderr )
4242 elif response .status_code == 202 :
@@ -50,8 +50,8 @@ def _output_binary_response(response: requests.Response, pcap_id: str) -> None:
5050def _parse_cmdline () -> argparse .Namespace :
5151 """
5252 positional arguments:
53- mode The mode to invoke [ analyze|search|deep_search
54- |deep_search_results|info|analysis|download|similar ]
53+ mode The mode to invoke [ analyze|search|search_by_pcap|ioc_search |deep_search
54+ |deep_search_results|info|analysis|download|similar| ]
5555
5656 optional arguments:
5757 -h, --help show this help message and exit
@@ -72,8 +72,8 @@ def _parse_cmdline() -> argparse.Namespace:
7272 )
7373 parser .add_argument ('mode' , metavar = 'mode' , type = str ,
7474 help = 'The mode to invoke '
75- '[ analyze|search|deep_search|deep_search_results|info|analysis|'
76- 'download|similar ]' )
75+ '[ analyze|search|search_by_pcap|ioc_search| deep_search|deep_search_results|info|analysis|'
76+ 'download|similar| ]' )
7777 parser .add_argument (
7878 '--query' , dest = 'query' , help = 'A search query' ,
7979 required = 'search' in sys .argv or 'deep_search' in sys .argv )
@@ -85,7 +85,11 @@ def _parse_cmdline() -> argparse.Namespace:
8585 required = 'deep_search_results' in sys .argv )
8686 parser .add_argument (
8787 '--path' , dest = 'pcap_path' , help = 'The path to the pcap file you wish to analyze.' ,
88- required = 'analyze' in sys .argv )
88+ required = 'analyze' in sys .argv or 'search_by_pcap' in sys .argv )
89+ parser .add_argument ('--ioc-path' , dest = 'ioc_path' , help = 'The path to a newline delimited text file containing '
90+ 'search terms.' , required = 'ioc_search' in sys .argv )
91+ parser .add_argument ('--skip-warnings' , dest = 'skip_warnings' , help = 'Skip pcap analyze warning prompt' ,
92+ action = 'store_true' )
8993 parser .add_argument ('--name' , dest = 'pcap_name' , help = 'The optional name associated with the pcap analysis.' ,
9094 default = None )
9195 parser .add_argument ('--sources' , dest = 'pcap_sources' , help = 'URLs referencing the original analysis.' ,
@@ -96,44 +100,68 @@ def _parse_cmdline() -> argparse.Namespace:
96100 return args
97101
98102
99- def get_api () -> packettotal_api . PacketTotalApi :
103+ def get_api () -> search_tools . SearchTools :
100104 """
101105 Gets an authenticated API instance either by prompting the user or retrieving credential from disk
102106 :return: Returns a validated packettotal_api.PacketTotalApi instance
103107 """
104108 try :
105109 with open ('.pt_api_key' , 'r' ) as f :
106- api = packettotal_api . PacketTotalApi (f .read ())
110+ api = search_tools . SearchTools (f .read ())
107111 if not validate_api_key (api ):
108112 api = prompt_api_token ()
109113 except FileNotFoundError :
110114 api = prompt_api_token ()
111115 return api
112116
113117
114- def prompt_api_token () -> packettotal_api .PacketTotalApi :
118+ def prompt_analysis_disclaimer ():
119+ print ("""
120+ WARNING: Analysis will result in the network traffic becoming public at https://packettotal.com.
121+
122+ ADVERTENCIA: El análisis hará que el tráfico de la red se haga público en https://packettotal.com.
123+
124+ WARNUNG: Die Analyse führt dazu, dass der Netzwerkverkehr unter https://packettotal.com öffentlich wird.
125+
126+ ПРЕДУПРЕЖДЕНИЕ. Анализ приведет к тому, что сетевой трафик станет общедоступным на https://packettotal.com.
127+
128+ चेतावनी: विश्लेषण का परिणाम नेटवर्क ट्रैफिक https://packettotal.com पर सार्वजनिक हो जाएगा
129+
130+ 警告:分析将导致网络流量在https://packettotal.com上公开
131+
132+ 警告:分析により、ネットワークトラフィックはhttps://packettotal.comで公開されます。
133+
134+ tahdhir: sayuadiy altahlil 'iilaa 'an tusbih harakat murur alshabakat eamat ealaa https://packettotal.com
135+ """ )
136+
137+ answer = input ('Continue? [Y/n]: ' )
138+ if answer .lower () == 'n' :
139+ exit (0 )
140+
141+
142+ def prompt_api_token () -> search_tools .SearchTools :
115143 """
116144 Prompts the user to enter their API key, tests the validity of the key, and if valid caches it to disk
117145
118- :return: Returns a validated packettotal_api.PacketTotalApi instance
146+ :return: Returns a validated search_tools.SearchTools instance
119147 """
120148 valid = False
121149 api = None
122150 while not valid :
123151 api_key = getpass .getpass ('Enter your API key: ' , stream = None )
124- api = packettotal_api . PacketTotalApi (api_key )
152+ api = search_tools . SearchTools (api_key )
125153 if validate_api_key (api ):
126154 with open ('.pt_api_key' , 'w' ) as f :
127155 f .write (api_key )
128156 valid = True
129157 return api
130158
131159
132- def validate_api_key (api : packettotal_api . PacketTotalApi ) -> bool :
160+ def validate_api_key (api : search_tools . SearchTools ) -> bool :
133161 """
134162 Determines whether an API key is valid
135163
136- :param api: An unvalidated packettotal_api.PacketTotalApi instance
164+ :param api: An unvalidated search_tools.SearchTools instance
137165 :return: True if api key is valid
138166 """
139167 valid = False
@@ -151,6 +179,8 @@ def main():
151179 return
152180 api = get_api ()
153181 if args .mode == 'analyze' :
182+ if not args .skip_warnings :
183+ prompt_analysis_disclaimer ()
154184 if args .pcap_sources :
155185 pcap_sources = args .pcap_sources
156186 else :
@@ -161,6 +191,8 @@ def main():
161191 _output_text_response (api .search (args .query ), args .output )
162192 elif args .mode == 'deep_search' :
163193 _output_text_response (api .deep_search_create (args .query ), args .output )
194+ elif args .mode == 'ioc_search' :
195+ _output_text_response (api .search_by_iocs (open (args .ioc_path , 'r' )), args .output )
164196 elif args .mode == 'deep_search_results' :
165197 _output_text_response (api .deep_search_get (args .search_id ), args .output )
166198 elif args .mode == 'info' :
@@ -183,6 +215,10 @@ def main():
183215 _output_text_response (api .pcap_similar (args .pcap_id ), args .output )
184216 elif args .mode == 'usage' :
185217 _output_text_response (api .usage (), args .output )
218+ elif args .mode == 'search_by_pcap' :
219+ if not args .skip_warnings :
220+ prompt_analysis_disclaimer ()
221+ _output_text_response (api .search_by_pcap (open (args .pcap_path , 'rb' )), args .output )
186222 else :
187223 print ('Invalid mode. Valid modes are: [{}]' .format ('analyze|search|deep_search|deep_search_results|'
188224 'info|analysis|download|similar' ),
0 commit comments