해킹 공격의 예술 실습

힙 기반 오버 플로우

amoogotomollayo 2022. 3. 6. 22:16

이번 실습은 힙 오버 플로우 공격입니다.

 

취약한 소스 코드는 아래와 같습니다.

더보기
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "hacking.h"

void usage(char *prog_name, char *filename) {
   printf("Usage: %s <data to add to %s>\n", prog_name, filename);
   exit(0);
}

void fatal(char *);            // a function for fatal errors
void *ec_malloc(unsigned int); // an errorchecked malloc() wrapper

int main(int argc, char *argv[]) {
   int userid, fd; // file descriptor
   char *buffer, *datafile;

   buffer = (char *) ec_malloc(100);
   datafile = (char *) ec_malloc(20);
   strcpy(datafile, "/var/notes");

   if(argc < 2)                // If there aren't commandline arguments
      usage(argv[0], datafile); // display usage message and exit

   strcpy(buffer, argv[1]);  // copy into buffer

   printf("[DEBUG] buffer   @ %p: \'%s\'\n", buffer, buffer);
   printf("[DEBUG] datafile @ %p: \'%s\'\n", datafile, datafile);

 // Opening the file
   fd = open(datafile, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR);
   if(fd == -1)
      fatal("in main() while opening file");
   printf("[DEBUG] file descriptor is %d\n", fd);

   userid = getuid(); // get the real user ID

// Writing data
   if(write(fd, &userid, 4) == -1) // write user ID before note data
      fatal("in main() while writing userid to file");
   write(fd, "\n", 1); // terminate line

   if(write(fd, buffer, strlen(buffer)) == -1) // write note
      fatal("in main() while writing buffer to file");
   write(fd, "\n", 1); // terminate line

// Closing file
   if(close(fd) == -1)
      fatal("in main() while closing file");

   printf("Note has been saved.\n");
   free(buffer);
   free(datafile);
}

해당 소스 코드는 /var/notes 파일에 사용자의 아이디와 사용자가 입력한 데이터를 저장하는 소스 코드입니다.

 

 

취약한 부분은 strcpy 함수 부분으로 사용자가 입력한 인자에 대한 길이 검증이 없어 datafile 영역까지 침범할 수 있습니다.

 

 

buffer와 datafile의 거리는 104byte입니다. 입력을 "{데이터}//104byte"+ "/원하는 디렉터리"를 입력하게 되면 임의의 디렉터리에 데이터를 저장할 수 있습니다.

 

"A" * 104 + "/etc/passwd"를 입력하게 되면 /etc/passwd 파일에 접근하여 임의의 데이터를 삽입할 수 있게 됩니다.

 

해당 취약점을 이용해 /etc/passwd에 root 권한을 가진 사용자를 추가해보도록 하겠습니다.

rooot:AA2VB0KULascU:0:0:me:/root:/bin/sh(40byte)가 /etc/passwd에 추가될 계정입니다.

하지만 /etc/passwd라는 문자열을 datafile에 덮어 씌우기 위해서는 104byte를 채워야 합니다.

5번째 부분은 사용자 관련 정보를 나타내는 부분인데 아무 값이 넣어도 됩니다.

그래서 이 부분을 임의의 64byte를 채워넣어 104byte를 맞추어야 됩니다.

 

2번째 부분은 패스워드로 단반향 해시를 사용하여 암호화가 되어 있습니다.

perl의 crypt 함수를 이용하여 구할 수 있습니다.

 

 

 

위와 같이 입력을 하게 되면 root 권한을 가진 계정을 만들 수는 있지만 로그인 셸이 /bin/sh/etc/passwd가 돼버려 셸을 실행시키지 못합니다.

 

 

그래서 /etc/passwd에 저장되게 하면서 셸을 실행시킬 수 있도록 심볼릭 파일 링크를 사용해 문제를 해결할 수 있습니다.

 

다시 페이로드를 짜 넣어 보겠습니다. 이렇게 입력하면 /etc/passwd에 입력되면서 로그인 셸을 /bin/bash가 되도록 만듭니다.

 

결과는 아래와 같습니다.