Sunday, 12 August 2012

Specific Flaws to Check For: Security Holes?


1) Look for routines that don't do boundary checking, or verify input.
   ie: the gets() family of routines, where it is possible to overwrite
   buffer boundaries. ( sprintf()?, gets(), etc. )
   also: strcpy() which is why most src has:
     #define SCYPYN((a)(b)) strcpy(a, b, sizeof(a))

2) SUID/SGID routines written in one of the shells, instead of C or
   PERL.

3) SUID/SGID routines written in PERL that don't use the "taintperl"
   program.)

4) SUID/SGID routines that use the system(), popen(), execlp(), or
   execvp() calls to run something else.

5) Any program that uses relative path names inside the program.

6) The use of relative path names to specify dynamically linked libraries.
   (look in Makefile).

7) Routines that don't check error return codes from system calls. (ie:
   fork(2), suid(2), etc), setuid() rather, as in the famous rcp bug

8) Holes can often be found in code that:
  A) is ported to a new environment.
  B) receives unexpected input.
  C) interacts with other local software.
  D) accesses system files like passwd, L.sys, etc.
  E) reads input from a publicly writable file/directory.
  F) diagnostic programs which are typically not user-proofed.

9) Test code for unexpected input. Coverage, data flow, and mutation
   testing tools are available.

10) Look in man pages, and users guides for warnings against doing X, and
   try variations of X. Ditto for "bugs" section.

11) Look for seldom used, or unusual functions or commands - read backwards.
   In particular looking for undocumented flags/arguments may prove useful.
   Check flags that were in prior releases, or in other OS versions. Check
   for options that other programs might use. For instance telnet uses -h
   option to login ...
     right, as most login.c's I've seen have:
          if((getuid()) && hflag){
                 syslog()
                 exit()
                 }

12) Look for race conditions.

13) Failure of software to authenticate that it is really communicating
   with the desired software or hardware module it wants to be accessing.

14) Lack or error detection to reset protection mechanisms following an
   error.

15) Poor implementation resulting in, for example, condition codes being
   improperly tested.

16) Implicit trust: Routine B assumes routine A's parameters are correct
   because routine A is a system process.

17) System stores it's data or references user parameters in the users
   address space.

18) Inter process communication: return conditions (passwd OK, illegal
   parameter, segment error, etc) can provide a significant wedge, esp.
   when combined with (17).

19) User parameters may not be adequately checked.

20) Addresses that overlap or refer to system areas.

21) Condition code checks may be omitted.

22) Failure to anticipate unusual or extraordinary parameters.

23) Look for system levels where the modules involved were written by
   different programmers, or groups of programmers - holes are likely
   to be found.

24) Registers that point to the location of a parameters value instead
   of passing the value itself.

25) Any program running with system privileges. (too many progs are given
   uid 0, to facilitate access to certain tables, etc.)

26) Group or world readable temporary files, buffers, etc.

27) Lack of threshold values, and lack of logging/notification once these
   have been triggered.

28) Changing parameters of critical system areas prior to their execution
   by a concurrent process. (race conditions)

29) Inadequate boundary checking at compile time, for example, a user
   may be able to execute machine code disguised as data in a data area.
   (if text and data areas are shared)

30) Improperly handling user generated asynchronous interrupts. Users
   interrupting a process, performing an operation, and either returning
   to continue the process or begin another will frequently leave the
   system in an unprotected state. Partially written files are left open,
   improper writing of protection infraction messages, improper setting
   of protection bits, etc often occur.

31) Code that uses fopen(3) without setting the umask. ( eg: at(1), etc. )
  In general, code that does not reset the real and effective uid before
  forking.

32) Trace is your friend (or truss in SVR4) for helping figure out what
  system calls a program is using.

33) Scan /usr/local fs's closely. Many admins will install software from
  the net. Often you'll find tcpdump, top, nfswatch, ... suid'd root for
  their ease of use.

34) Check suid programs to see if they are the ones originally put on the
  system. Admins will sometimes put in a passwd replacement which is less
  secure than the distributed version.

35) Look for programs that were there to install software or loadable
  kernel modules.

36) Dynamically linked programs in general. Remember LD_PRELOAD, I think
  that was the variable.

37) I/O channel programming is a prime target. Look for logical errors,
  inconsistencies, and omissions.

38) See if it's possible for a I/O channel program to modify itself, loop
  back, and then execute the newly modified code. (instruction pre-load
  may screw this up)

39) If I/O channels act as independent processors they may have unlimited
  access to memory, thus system code may be modified in memory prior to
  execution.

40) Look for bugs requiring flaws in multiple pieces of software, i.e. say
  program a can be used to change config file /etc/a now program b assumes
  the information in a to be correct and this leads to unexpected results
  (just look at how many programs trust /etc/utmp)

41) Any program, especially those suid/sgid, that allow shell escapes.

No comments:

Post a Comment