#BOT from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.chrome.service import Service from selenium.webdriver.chrome.options import Options import time import random import json from pathlib import Path class Bot(): def __init__(self): """ Initializes the MyBrowser instance. Sets up Chrome WebDriver with headless mode and necessary arguments for a minimal and secure browsing session. Also defines login and labs URLs. """ self.LOGIN_URL = 'https://portswigger.net/users' self.LABS_URL = 'https://portswigger.net/web-security/all-labs#' self.prefixes_filename = 'topics_prefixes.json' self.options = Options() for arg in ['--headless','--disable-gpu', '--no-sandbox']: self.options.add_argument(arg) self.driver = webdriver.Chrome(options=self.options) def __wait_random_time(self,min_seconds=3, max_seconds=5): """ Waits for a random amount of time between min_seconds and max_seconds. Args: min_seconds (int, optional): Minimum number of seconds to wait. Defaults to 3. max_seconds (int, optional): Maximum number of seconds to wait. Defaults to 5. """ duration = random.uniform(min_seconds, max_seconds) time.sleep(duration) def login(self,username,password): """ Logs in to the PortSwigger user portal using the given credentials. Args: username (str): The email address or username for login. password (str): The corresponding password for the user account. Opens the login page, waits a random time, then fills and submits the login form. """ #Open the login page self.driver.get(self.LOGIN_URL) #Wait for the page to load self.__wait_random_time() #Find and fill in the email field email_input = self.driver.find_element(By.ID, "EmailAddress") email_input.send_keys(username) #Find and fill in the password field password_input = self.driver.find_element(By.ID, "Password") password_input.send_keys(password) #Submit the login form password_input.send_keys(Keys.RETURN) #Wait for the page to load self.__wait_random_time() def choose_topic(self,topic_name='sql-injection',level=None): """ Extract urls of each of the labs in the selected section. Args: topic_name (str): the name of the topic. Read topic prefixes files, extract links of labs based by topic section (topic_name) and returns a list of lab urls. """ #Read topic prefixes json file and get prefix for topic_name current_folder = Path(__file__).parent available_topics = json.loads(open(f'{current_folder}/{self.prefixes_filename}').read()) #If topic_name does not exists then returns empty list try: topic_prefix = available_topics[topic_name] except KeyError: print(f"Topic '{topic_name}' not found") return [] #Go to sections urls self.driver.get(f'{self.LABS_URL}{topic_name}') #Find all elements that have the topic prefix in the href links = self.driver.find_elements(By.CLASS_NAME, 'flex-columns') #Extract the href attributes if level: extracted_links = [link.find_element(By.TAG_NAME, 'a').get_attribute('href') for link in links if link.find_element(By.TAG_NAME, 'span').text == level] else: extracted_links = [link.find_element(By.TAG_NAME, 'a').get_attribute('href') for link in links] #Filter links that contain the topic prefix return [link for link in extracted_links if topic_name == link.split('/')[4]] def obtain_lab_information(self,lab_url): """ Extract the information associated to a lab url. Args: lab_url (str): the url of the lab. Extract the information associated to the lab such as Title, Description, Solution and Environment url. """ #Go to lab url self.driver.get(lab_url) #Extract type of lab from url labtype = lab_url.split('/')[4] #Extract title of the lab title = self.driver.find_element(By.CLASS_NAME, 'heading-2').text #Extract description of the lab description_section = self.driver.find_element(By.CLASS_NAME, "section.theme-white") paragraphs = description_section.find_elements(By.XPATH, ".//p[following-sibling::div[@class='container-buttons-left']]") #Extract solution of the lab solution_sections = self.driver.find_elements(By.CLASS_NAME, "component-solution") if len(solution_sections) <=2: #when there are no Hint section solution_sections[0].find_element(By.TAG_NAME, 'details').click() solution = solution_sections[0].find_element(By.CLASS_NAME, 'content').text else: #when there are Hint section solution_sections[1].find_element(By.TAG_NAME, 'details').click() solution = solution_sections[1].find_element(By.CLASS_NAME, 'content').text #Extract url to access the lab environment ##Find the "Start lab" button and click it start_button = self.driver.find_element(By.CLASS_NAME, 'button-orange') start_button.click() ##Get the current tab and switch to the new tab main_tab = self.driver.current_window_handle lab_tab = [handle for handle in self.driver.window_handles if handle != main_tab][0] self.driver.switch_to.window(lab_tab) ##Get the URL of the lab environment environment_url = self.driver.current_url ##Close the new tab self.driver.close() ##Switch back to the main tab self.driver.switch_to.window(main_tab) lab_info = { 'type': labtype, 'url': lab_url, 'title': title, 'description': "\n".join([p.text for p in paragraphs]), 'solution': solution, 'environment_url': environment_url } return lab_info def check_solved_lab(self,lab_url): """ Check if lab was solved. Args: lab_url (str): the url of the lab. Go to the lab url and check if status "Solved or Not Solved". """ #Go to lab url self.driver.get(lab_url) #get text of status container lab_status = self.driver.find_element(By.CLASS_NAME, 'lab-status-icon').text return lab_status