1- VERSION = '0.6.2 '
1+ VERSION = '0.7.0 '
22
33from pprint import pprint
44import time
2222
2323# Flask
2424try :
25- from flask import request
25+ from flask import request , redirect , url_for
2626 from flask import Response as FlaskResponse
2727 from flask .wrappers import Response as FlaskResponseType
2828 from werkzeug .utils import import_string
@@ -308,6 +308,17 @@ class PyRASP():
308308 'errors' : 0 ,
309309 'attacks' : 0
310310 }
311+
312+ # API DATA
313+ API_CONFIG = {}
314+ API_BLACKLIST = []
315+ API_STATUS = {
316+ 'version' : '' ,
317+ 'blacklist' : 0 ,
318+ 'xss_loaded' : False ,
319+ 'sqli_loaded' : False ,
320+ 'config' : 'Default'
321+ }
311322
312323 ####################################################
313324 # CONSTRUCTOR & DESTRUCTOR
@@ -362,6 +373,8 @@ def __init__(self, app = None, app_name = None, hosts = [], conf = None, key = N
362373
363374 if not self .load_cloud_config ():
364375 self .print_screen ('[!] Could not load configuration from cloud server. Running default configuration.' , init = True , new_line_up = True )
376+ else :
377+ self .API_STATUS ['config' ] = 'Cloud'
365378
366379 # Load configuration file
367380 if not conf is None :
@@ -370,7 +383,8 @@ def __init__(self, app = None, app_name = None, hosts = [], conf = None, key = N
370383 self .CONF_FILE = os .environ .get ('PYRASP_CONF' )
371384
372385 if not self .CONF_FILE is None :
373- self .load_file_config (self .CONF_FILE )
386+ if self .load_file_config (self .CONF_FILE ):
387+ self .API_STATUS ['config' ] = 'Local'
374388
375389 # Default config customization from
376390 if all ([
@@ -462,6 +476,10 @@ def __init__(self, app = None, app_name = None, hosts = [], conf = None, key = N
462476 else :
463477 self .print_screen ('[+] SQLI model loaded' , init = True , new_line_up = False )
464478
479+ # Agent status
480+ self .API_STATUS ['version' ] = VERSION
481+ self .API_STATUS ['xss_loaded' ] = xss_model_loaded
482+ self .API_STATUS ['sqli_loaded' ] = sqli_model_loaded
465483
466484 # AWS, GCP & Azure
467485 if self .PLATFORM in CLOUD_FUNCTIONS :
@@ -607,8 +625,7 @@ def send_beacon(self):
607625 remove_blacklist_entries = blacklist_update .get ('remove' ) or []
608626 for remove_entry in remove_blacklist_entries :
609627 if remove_entry in self .BLACKLIST :
610- del self .BLACKLIST [remove_entry ]
611-
628+ del self .BLACKLIST [remove_entry ]
612629
613630 # Set configuration
614631 if not error and server_data .get ('config' ):
@@ -750,20 +767,26 @@ def load_cloud_config(self):
750767
751768 def load_file_config (self , conf_file ):
752769
770+ result = True
771+
753772 self .print_screen (f'[+] Loading configuration from { conf_file } ' , init = True , new_line_up = False )
754773
755774 try :
756775 with open (conf_file ) as f :
757776 config = json .load (f )
758777 except Exception as e :
759778 self .print_screen (f'[!] Error reading { conf_file } : { str (e )} ' , init = True , new_line_up = False )
779+ result = False
760780 else :
761781 self .load_config (config )
782+
783+ return result
762784
763785 def load_config (self , config ):
764786
765787 # Load parameters
766788 config_params = config .get ('config' ) or config
789+ self .API_CONFIG = config_params
767790
768791 for key in config_params :
769792 setattr (self , key , config_params [key ])
@@ -780,6 +803,7 @@ def load_config(self, config):
780803 config_blacklist = config .get ('blacklist' )
781804
782805 if config_blacklist :
806+
783807 self .BLACKLIST = config_blacklist
784808
785809 return True
@@ -793,28 +817,41 @@ def handle_attack(self, attack, host, request_path, source_ip, timestamp):
793817 attack_id = attack ['type' ]
794818 attack_check = ATTACKS_CHECKS [attack_id ]
795819 attack_details = attack .get ('details' ) or {}
820+ attack_payload = None
821+ if attack_details and attack_details .get ('payload' ):
822+ attack_payload = attack_details ['payload' ]
823+ try :
824+ attack_payload_b64 = base64 .b64encode (attack_details ['payload' ].encode ()).decode ()
825+ attack_details ['payload' ] = attack_payload_b64
826+ except :
827+ pass
828+
796829 action = None
797830
798- # Generic case
831+ # Action
832+ ## Generic case
799833 if not attack_id == 0 :
800834 action = self .SECURITY_CHECKS [attack_check ]
801- # Blacklist
835+ ## Blacklist
802836 else :
803837 action = 2
804838
805839 attack_details ['action' ] = action
840+
841+ # Attack type
806842 if ATTACKS_CODES .get (attack_id ):
807843 attack_details ['codes' ] = ATTACKS_CODES [attack_id ]
808844
809845 if not self .BLACKLIST_OVERRIDE and action == 2 :
810846 self .blacklist_ip (source_ip , timestamp , attack_check )
811847
812-
848+ # Print screen
813849 try :
814- self .print_screen (f'[!] { ATTACKS [attack_id ]} : { attack ["details" ]["location" ]} -> { attack [ "details" ][ "payload" ] } ' )
850+ self .print_screen (f'[!] { ATTACKS [attack_id ]} : { attack ["details" ]["location" ]} -> { attack_payload } ' )
815851 except :
816852 self .print_screen (f'[!] Attack - No details' )
817853
854+ # Log
818855 if self .LOG_ENABLED :
819856 self .log_security_event (attack_check , source_ip , None , attack_details )
820857
@@ -1735,6 +1772,26 @@ def check_pattern(self, text, pattern, match_type):
17351772
17361773 return match
17371774
1775+ ####################################################
1776+ # API
1777+ ####################################################
1778+
1779+ def get_config (self ):
1780+
1781+ return self .API_CONFIG
1782+
1783+ def get_blacklist (self ):
1784+
1785+ self .API_BLACKLIST = [ i for i in self .BLACKLIST ]
1786+
1787+ return self .API_BLACKLIST
1788+
1789+ def get_status (self ):
1790+
1791+ self .API_STATUS ['blacklist' ] = len (self .BLACKLIST )
1792+
1793+ return self .API_STATUS
1794+
17381795class FlaskRASP (PyRASP ):
17391796
17401797 CURRENT_ATTACKS = {}
@@ -1768,8 +1825,9 @@ def before_request_callback():
17681825 # Send attack status in status code for handling by @after_request
17691826 if not attack == None :
17701827 attack_id = '::' .join ([host , request_method , request_path , source_ip ])
1771- self .CURRENT_ATTACKS [attack_id ] = attack
1772-
1828+ self .CURRENT_ATTACKS [attack_id ] = attack
1829+ return FlaskResponse ()
1830+
17731831 # Outgoing responses
17741832 def set_after_security_checks (self , app ):
17751833 @app .after_request
0 commit comments