Skip to content

Commit eaab344

Browse files
committed
Admin panels login - brute force logging in module (#249)
1 parent 580502a commit eaab344

File tree

1 file changed

+135
-0
lines changed

1 file changed

+135
-0
lines changed
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import logging
2+
from re import search
3+
from typing import Optional
4+
5+
# disable in config
6+
from selenium import webdriver # type: ignore
7+
from selenium.common.exceptions import NoSuchElementException # type: ignore
8+
from selenium.webdriver.chrome.service import Service # type: ignore
9+
from selenium.webdriver.chrome.webdriver import WebDriver # type: ignore
10+
from selenium.webdriver.common.by import By # type: ignore
11+
from selenium.webdriver.common.keys import Keys # type: ignore
12+
from selenium.webdriver.remote.webelement import WebElement # type: ignore
13+
from selenium.webdriver.support import expected_conditions as ec # type: ignore
14+
from selenium.webdriver.support.ui import WebDriverWait # type: ignore
15+
16+
logger = logging.getLogger(__name__)
17+
logger.setLevel(logging.INFO)
18+
handler = logging.StreamHandler()
19+
handler.setLevel(logging.INFO)
20+
logger.addHandler(handler)
21+
22+
23+
class LoginBruter:
24+
BRUTE_CREDENTIALS = [
25+
("admin", "admin"),
26+
("admin", "password"),
27+
("user", "password"),
28+
("djangouser", "password"),
29+
("b", "b"),
30+
]
31+
32+
LOGIN_FAILED_MSGS = [
33+
"Please enter the correct username and password for a staff account. "
34+
"Note that both fields may be case-sensitive.",
35+
"Unrecognized username or password. Forgot your password?",
36+
"Username and password do not match or you do not have an account yet.",
37+
# common keywords
38+
"credentials",
39+
"Invalid credentials",
40+
"username or password",
41+
"Username or password",
42+
"username and/or password",
43+
"username and password",
44+
"użytkownik lub hasło",
45+
"Użytkownik lub hasło",
46+
"użytkownik i hasło",
47+
"Użytkownik i hasło",
48+
"dane logowania",
49+
"Login i / lub hasło" "niepoprawne",
50+
]
51+
52+
def brute(self, url: str) -> None:
53+
for username, password in self.BRUTE_CREDENTIALS:
54+
driver = LoginBruter._get_webdriver()
55+
driver.get(url)
56+
WebDriverWait(driver, 10).until(ec.url_matches(url))
57+
try:
58+
user_input, password_input = LoginBruter._find_form_inputs(url, driver)
59+
except TypeError:
60+
driver.close()
61+
driver.quit()
62+
break
63+
driver.implicitly_wait(10)
64+
LoginBruter._send_credentials(
65+
user_input=user_input,
66+
password_input=password_input,
67+
username=username,
68+
password=password,
69+
)
70+
driver.implicitly_wait(10)
71+
result = LoginBruter._get_logging_in_result(driver, self.LOGIN_FAILED_MSGS)
72+
driver.implicitly_wait(10)
73+
if result is None:
74+
logger.error("The result of the login attempt could not be confirmed.")
75+
elif not result:
76+
logger.info(f"Logging in successful with credentials: {username}, {password}")
77+
# break
78+
else:
79+
continue
80+
driver.close()
81+
driver.quit()
82+
83+
@staticmethod
84+
def _get_webdriver() -> WebDriver:
85+
service = Service(executable_path="./chromedriver-linux64/chromedriver")
86+
return webdriver.Chrome(service=service)
87+
88+
@staticmethod
89+
def _find_form_inputs(url: str, driver: WebDriver) -> Optional[tuple[WebElement, WebElement]]:
90+
user_input, password_input = None, None
91+
inputs = driver.find_elements(By.TAG_NAME, "input")
92+
if not inputs:
93+
logging.error(f"Login form has not been found on {url}")
94+
return None
95+
else:
96+
for field in inputs:
97+
if field.get_attribute("type") == "text":
98+
tag_values = driver.execute_script(
99+
"var items = []; for (index = 0; index < arguments[0].attributes.length; ++index)"
100+
"items.push(arguments[0].attributes[index].value); return items;",
101+
field,
102+
)
103+
for value in tag_values:
104+
if search(r"[Uu]ser", value) or search(r"[Ll]ogin", value) or search(r"[Nn]ame", value):
105+
user_input = field
106+
break
107+
elif field.get_attribute("type") == "password":
108+
password_input = field
109+
if not password_input or not user_input:
110+
logging.error(f"Login form has not been found on {url}")
111+
return None
112+
return user_input, password_input
113+
114+
@staticmethod
115+
def _send_credentials(user_input: WebElement, password_input: WebElement, username: str, password: str) -> None:
116+
if user_input:
117+
user_input.send_keys(username)
118+
if password_input:
119+
password_input.send_keys(password)
120+
password_input.send_keys(Keys.ENTER)
121+
122+
@staticmethod
123+
def _get_logging_in_result(driver: WebDriver, login_failure_msgs: list[str]) -> Optional[list[str]]:
124+
try:
125+
web_content = driver.find_element(By.XPATH, "html/body").text
126+
driver.implicitly_wait(10)
127+
result = [msg for msg in login_failure_msgs if (msg in web_content)]
128+
return result
129+
except NoSuchElementException:
130+
return None
131+
132+
133+
if __name__ == "__main__":
134+
bruter = LoginBruter()
135+
bruter.brute("example-url")

0 commit comments

Comments
 (0)