linux-integrity.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Weak hash algorithms allowed with DIGEST_NG
@ 2021-07-07  9:54 THOBY Simon
  2021-07-07 14:37 ` Mimi Zohar
  0 siblings, 1 reply; 4+ messages in thread
From: THOBY Simon @ 2021-07-07  9:54 UTC (permalink / raw)
  To: linux-integrity

Hello,
first of all I'm sorry if this isn't the best mailing list to discuss this, but the "users" mailing list on sourceforge seems dead since around 2017. Maybe there is some other mailing I missed ?

When using evmctl and IMA-EVM in hash+HMAC mode (no digital signatures involved), I was suprised to see that IMA didn't complain if a file was hashed with an algorithm "weaker" than the one specified on the command line.
Of course I suppose EVM should stop downgrade attacks (by that I mean an offline attacker changing the hash of a legitimate file from sha256 to sha1 or md5). However, if files were already hashed as md5 - or more probably sha1 because that is still the default value for evmctl - then the attacker could potentially perform collision attacks against the weakly hashed file. The user may believe himself protected against collision attacks because of the 'ima_hash=sha256' command line parameter (with or without 'ima_template=ima-ng').

Here is an example on a CentOS 8 box with a vanilla 5.13 kernel:

[root@localhost ~]# cat /proc/cmdline
root=UUID=xxxxxxxx ro rd.luks.uuid=luks-xxxxxxxx  ima_hash=sha256 ima_template=ima-ng
[root@localhost ~]# cat /sys/kernel/security/ima/policy
dont_measure fsmagic=0x9fa0
[...]
dont_appraise fsmagic=0x6e736673
appraise func=BPRM_CHECK fowner=0
appraise func=BPRM_CHECK euid=0
appraise func=MMAP_CHECK mask=MAY_EXEC fowner=0
appraise func=MMAP_CHECK mask=MAY_EXEC euid=0
appraise func=MODULE_CHECK
appraise func=FIRMWARE_CHECK
appraise func=POLICY_CHECK
[root@localhost ~]# cat > /tmp/a.c <<EOF
int main() {
printf("helo\n");
}
EOF
[root@localhost ~]# gcc /tmp/a.c -o testfile
[root@localhost ~]# evmctl ima_hash -a md5 -d testfile
hash(md5): 0108f04837b9336d40b8ec4f78df320143
[root@localhost ~]# getfattr -e hex -m . -d testfile
# file: testfile
security.evm=0x02a0cb5aab84522b5bc9d662998786676ad27ad142
security.ima=0x0108f04837b9336d40b8ec4f78df320143
security.selinux=0x756e636f6e66696e65645f753a6f626a6563745f723a61646d696e5f686f6d655f743a733000
[root@localhost ~]# ./testfile
helo

By the size if the security.ima xattr (smaller than a sha1 hash), the value of the first byte (0x1 so this is a DIGEST, not a DIGEST_NG) and the fact that nothing was pushed to the audit log, we can confirm that md5 is truly used for validation.

In addition, I am sure that IMA is enabled and working, as can be shown in this example where I craft an invalid IMA xattr):

[root@localhost ~]# cat /sys/kernel/security/evm
1[root@localhost ~]#
[root@localhost ~]# setfattr -n security.ima -v 0x01aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa testfile
[root@localhost ~]# getfattr -e hex -m . -d testfile
# file: testfile
security.evm=0x028fa94dc0950002fdfb2674ae94a7677fc5fb4ff4
security.ima=0x01aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
security.selinux=0x756e636f6e66696e65645f753a6f626a6563745f723a61646d696e5f686f6d655f743a733000
[root@localhost ~]# ./testfile
-bash: ./testfile: Permission denied
and I get the expected audti log message:
type=INTEGRITY_DATA msg=audit(...): pid=1428 uid=0 auid=0 ses=1 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 op=appraise_data cause=invalid-hash comm="bash" name="/root/testfile" dev="dm-0" ino=2224735 res=0 errno=0UID="root" AUID="root"

So I took a quick glance at kernel source code and indeed, when looking at ima_get_hash_algo (in security/integrity/ima/ima_appraise.c), there is no validation for the algorithm used:
	case IMA_XATTR_DIGEST_NG:
		/* first byte contains algorithm id */
		ret = xattr_value->data[0];
		if (ret < HASH_ALGO__LAST)
			return ret;
		break;

That hash is then used as-is in process_measurement (in security/integrity/ima/ima_main.c):
	hash_algo = ima_get_hash_algo(xattr_value, xattr_len);

	rc = ima_collect_measurement(iint, file, buf, size, hash_algo, modsig);

ima_collect_measurement (defined in security/integrity/ima/ima_api.c) then proceeds to use the hash algorithm without further ado:
	hash.hdr.algo = algo;

	/* Initialize hash digest to 0's in case of failure */
	memset(&hash.digest, 0, sizeof(hash.digest));

	if (buf)
		result = ima_calc_buffer_hash(buf, size, &hash.hdr);
	else
		result = ima_calc_file_hash(file, &hash.hdr);

To confirm that there was no validation, I took what appeared to be the weakest hash to my non-cryptographer eyes, MD4, and I decided to hash my file wiht it.
It appears evmctl was not really conceived to use md4 (and it shouldn't be either, so all is well), and we need to apply a tiny trick here:

[root@localhost ~]# evmctl ima_hash -a md4 -d testfile
hash(md4): 013785074a0decdf72f189fce55ff3c743
# We need to drop the 01 prefix (that indicated that the IMA type is DIGEST) because the DIGEST type uses the digest size to determine the algorithme, and only supports SHA1 and MD5.
# To use MD4, we must use the newer digest type (digest_ng instead of digest) to use the oldest algorithm. I dare say this made me smile a bit.
# We will prepend 04 (DIGEST_NG) and the index of the target hash algorithm in the hash_algo_name list: 00 because HASH_ALGO_MD4 is the first in the list (see crypto/hash_info.c).
# This gives 013785074a0decdf72f189fce55ff3c743 -> 3785074a0decdf72f189fce55ff3c743 -> 04003785074a0decdf72f189fce55ff3c743
[root@localhost ~]# setfattr -n security.ima -v 0x04003785074a0decdf72f189fce55ff3c743 testfile
[root@localhost ~]# getfattr -e hex -m . -d testfile
# file: testfile
security.evm=0x02aaa230ee23a3d82169c346711eea31573c861348
security.ima=0x04003785074a0decdf72f189fce55ff3c743
security.selinux=0x756e636f6e66696e65645f753a6f626a6563745f723a61646d696e5f686f6d655f743a733000
[root@localhost ~]# ./testfile
helo

Is there any way to enforce the use of the hash specified in the 'ima_hash' cmdline parameter ?
I couldn't find any glancing at the code, but I didn't read all of it and I understood even less, so I secretly hope to have missed a small yet critical check/option.
And if there is no such way, would you be opposed to a patch adding an option (something like 'ima_enforce_hash_alg') that only allows digest hashed with the values supplied in the 'ima_hash' parameter ?


Thanks for your consideration,
Have a nice day,
Simon Thoby

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2021-07-07 16:19 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-07  9:54 Weak hash algorithms allowed with DIGEST_NG THOBY Simon
2021-07-07 14:37 ` Mimi Zohar
2021-07-07 15:10   ` THOBY Simon
2021-07-07 16:18     ` Mimi Zohar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).