From jose@THEGEEKEMPIRE.NET Thu Jul 13 13:57:09 2000 From: jose nazario To: BUGTRAQ@SECURITYFOCUS.COM Date: Wed, 21 Jun 2000 12:05:51 -0400 Subject: Predictability Problems in IRIX Cron and Compilers Crimelabs, Inc. www.crimelabs.com Security Note Crimelabs Security Note CLABS200004 Title: Poor Tempfile Use in IRIX: Compilers and Cron Date: 21 June, 2000 Application: MIPSPro Compilers (7.1, 7.2.1 tested), cron Platforms: IRIX 6.3, 6.5 Severity: Moderate, higher in some instances Author: Jose Nazario (jose@thegeekempire.net) Vendor Status: Contacted (late May, 2000), bug ID's filed 792237 (cron) and 792239 (compilers) Web: (real soon now, we promise) Solution: None yet, but ensure umasks are at least 022, 077 preferred Description: Tempfiles really aren't new, but everyone's usually rather lazy about their use. I figured I would get this notice out about SGI's poor use of them in their base system (cron) and the MIPSPro compilers (version 7.1 and 7.2.1 tested). Not earth shattering, but it's something that should be fixed while we're at it. The MIPSPro compilers (version 7.2.1 is for IRIX 6.5) are a commercial package from SGI that is not part of the base IRIX 6.5 installation. They support C, C++, F77 and F90 languages and offer excellent optimization and parallelization. Cron, however, is part of the base distribution of IRIX. Note: This is kinda lengthy, but it's mainly temp-watch output surrounded by a lot of fluff. The tool used to monitor the tempfile creations was the L0pht's temp-watch (http://www.l0pht.com/advisories/watch.txt, thanks Mudge). The systems tested were an SGI O2 running IRIX 6.5: IRIX workstation 6.5 05190004 IP32 and an O2 running IRIX 6.3: IRIX workstation2 6.3 12161207 IP32 Both systems are affected by the bugs described here. ------------------[ Cron: As cron does it's housekeeping duties specified in the various crontabs, it creates temporary files. They couldn't be more predictable, stepping up one letter each time, no matter who is running the instance of cron (in this case root or sys): + -rw------- 1 sys sys 83 Jun 6 14:00 /tmp/croutHBCa0005g - -rw------- 1 sys sys 83 Jun 6 14:00 /tmp/croutHBCa0005g + -rw------- 1 root sys 97 Jun 6 14:03 /tmp/croutKBCa0005g - -rw------- 1 root sys 97 Jun 6 14:03 /tmp/croutKBCa0005g + -rw------- 1 root sys 94 Jun 6 14:08 /tmp/croutLBCa0005g - -rw------- 1 root sys 94 Jun 6 14:08 /tmp/croutLBCa0005g + -rw------- 1 root sys 131 Jun 6 14:15 /tmp/croutMBCa0005g - -rw------- 1 root sys 131 Jun 6 14:15 /tmp/croutMBCa0005g + -rw------- 1 root sys 115 Jun 6 14:17 /tmp/croutNBCa0005g - -rw------- 1 root sys 115 Jun 6 14:17 /tmp/croutNBCa0005g + -rw------- 1 sys sys 83 Jun 6 14:20 /tmp/croutOBCa0005g - -rw------- 1 sys sys 83 Jun 6 14:20 /tmp/croutOBCa0005g The good news is that cron doesn't seem to follow symlinks, it will just alter the name (ie to croutOBCb0005g). Still, it should be considerably more random to prevent being abused in a larger scheme. (in following temp-watch examples, the ^- lines, corresponding to the deletion of a file, have been removed for brevity's sake). Invoking crontab -e to edit my crontab as a regular user demonstrates the predictability again: + -rw-r----- 1 jose user 0 Jun 8 18:28 /tmp/crontaba0020m + -rw-r----- 1 jose user 0 Jun 8 18:28 /tmp/crontaba00218 + -rw-r----- 1 jose user 0 Jun 8 18:28 /tmp/crontaba00217 + -rw-r----- 1 jose user 0 Jun 8 18:28 /tmp/crontaba00219 + -rw-r----- 1 jose user 0 Jun 8 18:28 /tmp/crontaba00213 + -rw-r----- 1 jose user 0 Jun 8 18:29 /tmp/crontaba0021C + -rw-r----- 1 jose user 0 Jun 8 18:29 /tmp/crontaba00212 + -rw-r----- 1 jose user 0 Jun 8 18:29 /tmp/crontaba0020f + -rw-r----- 1 jose user 0 Jun 8 18:29 /tmp/crontaba0021T + -rw-r----- 1 jose user 0 Jun 8 18:29 /tmp/crontaba0021N + -rw-r----- 1 jose user 0 Jun 8 18:29 /tmp/crontaba0021I Again, temporary files are simple changes of the last three positions, which we can easily predict as they're often increments (but not always) of the last positions. It looks like cron is using mktemp(), when it should be using mkstemp() and a good PRNG for increased entropy. ----------[ Compilers and their tempfiles: The compilers in the MIPSPro set are also affected by the creation of predictable tempfiles. While this has been tested on both IRIX 6.3 with the 7.1 versions of the compilers and found also, we report it only for the currently shipping product, 7.2.1. MIPSPro C compiler: I c_fe 02/26/99 C Front-end, 7.2.1 The command % cc -c usage.c yields the following tempfiles: + -rw-r----- 1 jose user 88 Jun 5 18:32 /tmp/ctmL.AAAa001JC + -rw-r----- 1 jose user 0 Jun 5 18:32 /tmp/ctmB.BAAa001JC MIPSPro C++ compiler: I c++_fe 02/26/99 C++ Front-end, 7.2.1 The command % CC -c solvate.cc produces the following tempfiles: + -rw-r----- 1 jose user 86 Jun 5 18:30 /tmp/ctmL.AAAa001Ij + -rw-r----- 1 jose user 0 Jun 5 18:30 /tmp/ctmB.BAAa001Ij MIPSPro F77 compiler: I ftn77_fe 02/26/99 Fortran 77 Front-end, 7.2.1 % f77 -c readt.f which produces the following tempfiles: + -rw-r----- 1 jose user 0 Jun 5 18:27 /tmp/ctmL.AAAa001Hs + -rw-r----- 1 jose user 0 Jun 5 18:27 /tmp/ctmB.BAAa001Hs MIPSPro F90 compiler: I ftn90_fe 02/26/99 Fortran 90 Front-end, 7.2.1 % f90 -c real64.f similarily yields the following tempfiles as it works: + -rw-r----- 1 jose user 86 Jun 5 18:34 /tmp/ctmL.AAAa001JM + -rw-r----- 1 jose user 0 Jun 5 18:34 /tmp/ctmB.BAAa001JM And finally, if we invoke the compiler to compile a final binary, we see the same behavior: % cc -o temp-watch *.c + -rw-r----- 1 jose user 0 Jun 5 18:37 /tmp/ctmL.AAAa001Jy + -rw-r----- 1 jose user 0 Jun 5 18:37 /tmp/ctmB.BAAa001Jy + -rw-r----- 1 jose user 0 Jun 5 18:37 /tmp/ctmL.CAAa001Jy + -rw-r----- 1 jose user 0 Jun 5 18:37 /tmp/ctmB.DAAa001Jy + -rw-r----- 1 jose user 93 Jun 5 18:37 /tmp/ctmL.EAAa001Jy + -rw-r----- 1 jose user 0 Jun 5 18:37 /tmp/ctmB.FAAa001Jy + -rw-r----- 1 jose user 88 Jun 5 18:37 /tmp/ctmL.GAAa001Jy + -rw-r----- 1 jose user 0 Jun 5 18:37 /tmp/ctmB.HAAa001Jy The lack of good randomness is readily observed if we do a series of compiles generating object code (cc -c). Only the last two positions change, the rest of it is predictable as a sunrise: + -rw-r----- 1 jose user 0 Jun 5 18:42 /tmp/ctmL.AAAa001K9 + -rw-r----- 1 jose user 0 Jun 5 18:42 /tmp/ctmB.BAAa001K9 + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmL.AAAa001KT + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmB.BAAa001KT + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmL.AAAa001KX + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmB.BAAa001KX + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmL.AAAa001Kd + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmB.BAAa001Kd + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmL.AAAa001K- + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmB.BAAa001K- + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmL.AAAa001Ke + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmB.BAAa001Ke + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmL.AAAa001Kg + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmB.BAAa001Kg + -rw-r----- 1 jose user 89 Jun 5 18:43 /tmp/ctmL.AAAa001Kk + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmB.BAAa001Kk + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmL.AAAa001Kn + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmB.BAAa001Kn + -rw-r----- 1 jose user 89 Jun 5 18:43 /tmp/ctmL.AAAa001Kt + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmB.BAAa001Kt + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmL.AAAa001Kx + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmB.BAAa001Kx + -rw-r----- 1 jose user 89 Jun 5 18:43 /tmp/ctmL.AAAa001Ku + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmB.BAAa001Ku + -rw-r----- 1 jose user 89 Jun 5 18:43 /tmp/ctmL.AAAa001L9 + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmB.BAAa001L9 + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmL.AAAa001L3 + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmB.BAAa001L3 + -rw-r----- 1 jose user 89 Jun 5 18:43 /tmp/ctmL.AAAa001LB + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmB.BAAa001LB + -rw-r----- 1 jose user 89 Jun 5 18:43 /tmp/ctmL.AAAa001L2 + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmB.BAAa001L2 + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmL.AAAa001LF + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmB.BAAa001LF + -rw-r----- 1 jose user 89 Jun 5 18:43 /tmp/ctmL.AAAa001LJ + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmB.BAAa001LJ + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmL.AAAa001LO + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmB.BAAa001LO + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmL.AAAa001Bv + -rw-r----- 1 jose user 0 Jun 5 18:43 /tmp/ctmB.BAAa001Bv + -rw-r----- 1 jose user 0 Jun 5 18:44 /tmp/ctmL.AAAa001LT + -rw-r----- 1 jose user 0 Jun 5 18:44 /tmp/ctmB.BAAa001LT + -rw-r----- 1 jose user 0 Jun 5 18:44 /tmp/ctmL.AAAa001LP + -rw-r----- 1 jose user 0 Jun 5 18:44 /tmp/ctmB.BAAa001LP + -rw-r----- 1 jose user 0 Jun 5 18:44 /tmp/ctmL.AAAa001LU + -rw-r----- 1 jose user 0 Jun 5 18:44 /tmp/ctmB.BAAa001LU So, all of the major compilers, C, C++, F77 and F90, shipped in the MIPSPro 7.2.1 distribution are affected by the issue. What's the big deal? The issue in predictability is that we can abuse it. The temporary files inherit the umask of the user who invokes the commands, either cron or the compilers. Should this be set to being group or, God help you, world writable, all sorts of nastiness can ensue. In the case of compilers, we can append our code to the temporary files if we were an attacker. Since we know what to expect, once we see a situation ripe for the picking, we can slow the machine down and abuse the code that is being compiled to our heart's content. The randomness, or entropy, in the naming of the tempfiles is rather low, and as such is prone to abuse by an attacker. While not a "Hey neat, I got root!" exploit, this is easily part of a larger attack. This can be abused to yield uid changes in some scenarios, either from one unprivilidged uid to another or from an unprivilidged uid to privilidged ones, including uid=0 (root). I have to admit that this isn't rocket science or even very novel thinking, but it bears pointing out. -----------[ Acknowledgements: Thanks to rabbit for some helpful discussions on this topic.