2011년9월27일_pcap_패킷 캡쳐 라이브러리를 사용하여 FTP서버에 로그인시 송신되는 패킷을 캡쳐해보자.



어제는 pcap_lookupdev( )로 네트워크장치 이름을 얻었었다. URL : http://sumanaki.tistory.com/218
오늘은 얻은 장치이름으로 장치를 열고 간단히 FTP서버에 로그인시 전송되는 패스워드를 캡쳐해보자.


● main.c 전체소스코드 미리보기

   1: #include <stdio.h>
   2: #include <pcap/pcap.h>
   3:  
   4: #define    ROW_LINE    16
   5:  
   6: void MSDFunction(const void *vAddr, unsigned int print_line);    //샘꺼
   7: void HexaView(const void *vp, unsigned int uiSize);    //내꺼
   8: void HexaView2(void *vp, unsigned int uiSize, char cCol);
   9:  
  10: int main()
  11: {
  12:     char errbuf[PCAP_ERRBUF_SIZE];        //에러가 나면 여기에 기록됨.
  13:     char *cpNIC_Name;    //NIC는 장치 (Network Interface Card)
  14:     pcap_t *stpNIC;        // 구조체포인터
  15:     struct pcap_pkthdr stInfo;        // 정보를 담을 구조체
  16:     const u_char *ucpData;    // 데이터
  17:     
  18:     
  19:     // 1. 네트웍 장치명 읽어오기
  20:     cpNIC_Name = pcap_lookupdev(errbuf);    // 장치이름을 알아오고,
  21:     if(NULL == cpNIC_Name)    // 에러난 경우 에러버퍼에 에러가 난 이유를 저장.
  22:     {
  23:         printf(errbuf);        
  24:         putchar('\n');
  25:         exit(-1);        //exit()가 나은가?
  26:         //return -1;        //리턴이 나은가?
  27:     }
  28:     
  29:     printf(cpNIC_Name);
  30:     putchar('\n');
  31:     
  32:  
  33:     // 2. 네트웍 장치 열기
  34:     //                         장치명, 나중에 설명, 에러버퍼   
  35:     stpNIC = pcap_open_live(cpNIC_Name, 1500, 1, 0, errbuf);
  36:     if(NULL == stpNIC)    //에러가 난 경우
  37:     {
  38:         printf(errbuf);
  39:         putchar('\n');
  40:         exit(-2);
  41:         //return -2;
  42:     }
  43:  
  44:     printf("패킷캡쳐 오픈 successful(성공)\n");
  45:     
  46:     // 3. 패킷분석을 위해 패킷캡쳐 
  47:     ucpData = pcap_next(stpNIC, &stInfo);
  48:  
  49:     // 4. 패킷내용을 출력
  50:     HexaView(ucpData, 160);
  51:     //MSDFunction(ucpData, 100);
  52:  
  53:     // last. 열린 네트웍장치를 닫는다.
  54:     pcap_close(stpNIC);        
  55:     
  56:     return 0;
  57: }
  58:  
  59:  
  60: void MSDFunction(const void *vAddr, unsigned int print_line)
  61: // Memory Status Display Function
  62: /*******************************************************************************
  63: 기능   : 인수로 넘겨받은 주소로부터 ROW_LINE개 단위를 1줄로 print_line의 숫자 만큼
  64: 화면에 출력
  65: 인수   : 출력할 대상이 있는 곳의 주소값, 메모리 출력시 출력 라인 수
  66: 반환값   : void
  67: *******************************************************************************/
  68: {
  69:   unsigned char        *addr = (unsigned char *)vAddr;
  70:   unsigned int        loop_temp   = 0;     // 반복문을 위한 임시 변수 선언
  71:   unsigned char        memory_dump[ROW_LINE];     // 반환된 메모리값을 임시로 저장
  72:  
  73:   if (0 == *addr)
  74:   {
  75:       return;
  76:   }
  77:   else
  78:   {
  79:     printf(" Address   ");         // 화면 상단 자리 표시를 위한 출력
  80:   }
  81:   
  82:   while (loop_temp < ROW_LINE)       // Hex 부분 출력
  83:   {
  84:     printf("%02X ", loop_temp++);
  85:   }
  86:  
  87:   putchar(' ');
  88:   loop_temp = 0;
  89:  
  90:   while (loop_temp < ROW_LINE)       // ASCII 부분 출력
  91:   {
  92:     printf("%X", loop_temp++);
  93:   }
  94:  
  95:   putchar('\n');
  96:  
  97:   while (0 < print_line)           // Data 부분 출력 루프 시작
  98:   {
  99:     loop_temp = 0;
 100:     printf("0x%08X ", addr);     // 메모리 주소 출력
 101:  
 102:     while (1)                 // 메모리 읽어 오기 및 hex 출력 시작
 103:     {
 104:       // 메모리 주소에 위치한 값을 배열에 저장
 105:       *(memory_dump + loop_temp) = *addr;
 106:  
 107:       // 배열에 저장된 값 출력
 108:       printf("%02X ", *(memory_dump + loop_temp));
 109:  
 110:       ++loop_temp;
 111:       ++addr;
 112:  
 113:       if (0 == (loop_temp % ROW_LINE))  // ROW_LINE개를 출력하였으면 loop 종료
 114:       {
 115:         break;
 116:       }
 117:       else
 118:       {
 119:       }
 120:     }                   // 메모리 읽어 오기 및 hex 출력 끝
 121:  
 122:     putchar(' ');
 123:     loop_temp = 0;
 124:  
 125:     while (1)               // ASCII 부분 출력 루프 시작
 126:     {
 127:       if (0 == *(memory_dump + loop_temp))
 128:       {
 129:         putchar('.');         // 널 문자 대치
 130:       }
 131:       else if (32 > *(memory_dump + loop_temp))
 132:       {
 133:         putchar('*');         // 제어 문자 대치
 134:       }
 135:       else if (127 <= *(memory_dump + loop_temp))
 136:       {
 137:         putchar('*');         // 그래픽 문자 대치
 138:       }
 139:       else
 140:       {
 141:         putchar(*(memory_dump + loop_temp));
 142:       }
 143:  
 144:       ++loop_temp;
 145:  
 146:       if (0 == (loop_temp % ROW_LINE))  // ROW_LINE개를 출력하였으면 loop 종료
 147:       {
 148:         break;
 149:       }
 150:       else
 151:       {
 152:       }
 153:     }                   // ASCII 부분 출력 루프 끝
 154:  
 155:     putchar('\n');
 156:     --print_line;
 157:   }                     // Data 출력 루프 끝
 158:  
 159:   putchar('\n');
 160: }
 161:  
 162: void HexaView(const void *vp, unsigned int uiSize)
 163: {
 164:     unsigned char *p = (unsigned char *)vp;
 165:     unsigned char ucTemp;
 166:     unsigned int iLoop1;
 167:     unsigned int iLoop2;
 168:  
 169:     //Title
 170:     //printf("\n\t\t\t\tHexaView\n");
 171:     
 172:     //고정된 것.
 173:     printf("┌─────┬────────────────────────┬────────┐\n");
 174:     printf("│   BASE   │                   Hexa Code                    │   ASCII Code   │\n");
 175:     printf("│  Address │");
 176:     //00~0F까지 출력
 177:     for(iLoop1 = 0 ; 16 > iLoop1 ; ++iLoop1)
 178:     {
 179:         printf("%02X ", iLoop1);
 180:     }
 181:  
 182:     printf("│");
 183:     
 184:     for(iLoop1 = 0 ; 16 > iLoop1 ; ++iLoop1)
 185:     {
 186:         printf("%1X", iLoop1);
 187:     }
 188:     
 189:     printf("│\n");
 190:     printf("├─────┼────────────────────────┼────────┤\n");
 191:  
 192:     /*-----------------------------------------
 193:      * 가변
 194:      * --------------------------------------*/
 195:     for(iLoop1 = 0 ; (((uiSize - 1) / 16) + 1) > iLoop1 ; ++iLoop1)
 196:     {
 197:         printf("│");
 198:         //주소 출력
 199:         printf("0x%08X", iLoop1 * 16);
 200:         printf("│");
 201:         
 202:         //각 주소에 들어 있는 데이터 출력
 203:         for(iLoop2 = 0 ; 16 > iLoop2 ; ++iLoop2)
 204:         {
 205:             printf("%02X ", *((p + iLoop1 * 16) + iLoop2));
 206:         }
 207:         
 208:         printf("│");
 209:         //그 데이터의 ASCII
 210:         for(iLoop2 = 0 ; 16 > iLoop2 ; ++iLoop2)
 211:         {
 212:             ucTemp = *((p + iLoop1 * 16) + iLoop2);
 213:             
 214:             if(32 <= ucTemp && 126 >= ucTemp)
 215:             {
 216:                 printf("%c", ucTemp);
 217:             }
 218:             else
 219:             {
 220:                 printf(".");
 221:             }
 222:         }
 223:  
 224:         printf("│\n");
 225:     }
 226:     
 227:     printf("└─────┴────────────────────────┴────────┘\n");
 228:         
 229:  
 230:     return ;
 231: }
 232:  
 233: void HexaView2(void *vp, unsigned int uiSize, char cCol)
 234: {
 235:     unsigned char *p = vp;
 236:     unsigned char ucTemp;
 237:     unsigned int iLoop1;
 238:     unsigned int iLoop2;
 239:  
 240:     //Title
 241:     printf("\n\t\t\t\tHexaView\n");
 242:     
 243:     //고정된 것.
 244:     //printf("┌─────┬────────────────────────┬────────┐\n");
 245:     printf("┌─────┬");
 246:  
 247:     //가로선
 248:     for(iLoop1 = 0 ; cCol > iLoop1 ; ++iLoop1)
 249:     {
 250:         printf("─");        //여기 편집 중
 251:     }
 252:     
 253:     printf("│   BASE   │                   Hexa Code                    │   ASCII Code   │\n");
 254:     printf("│  Address │");
 255:     //00~0F까지 출력
 256:     for(iLoop1 = 0 ; 16 > iLoop1 ; ++iLoop1)
 257:     {
 258:         printf("%02X ", iLoop1);
 259:     }
 260:  
 261:     printf("│");
 262:     
 263:     for(iLoop1 = 0 ; 16 > iLoop1 ; ++iLoop1)
 264:     {
 265:         printf("%1X", iLoop1);
 266:     }
 267:     
 268:     printf("│\n");
 269:     printf("├─────┼────────────────────────┼────────┤\n");
 270:  
 271:     /*-----------------------------------------
 272:      * 가변
 273:      * --------------------------------------*/
 274:     for(iLoop1 = 0 ; (((uiSize - 1) / 16) + 1) > iLoop1 ; ++iLoop1)
 275:     {
 276:         printf("│");
 277:         //주소 출력
 278:         printf("0x%08X", p + iLoop1 * 16);
 279:         printf("│");
 280:         
 281:         //각 주소에 들어 있는 데이터 출력
 282:         for(iLoop2 = 0 ; 16 > iLoop2 ; ++iLoop2)
 283:         {
 284:             printf("%02X ", *((p + iLoop1 * 16) + iLoop2));
 285:         }
 286:         
 287:         printf("│");
 288:         //그 데이터의 ASCII
 289:         for(iLoop2 = 0 ; 16 > iLoop2 ; ++iLoop2)
 290:         {
 291:             ucTemp = *((p + iLoop1 * 16) + iLoop2);
 292:             
 293:             if(32 <= ucTemp && 126 >= ucTemp)
 294:             {
 295:                 printf("%c", ucTemp);
 296:             }
 297:             else
 298:             {
 299:                 printf(".");
 300:             }
 301:         }
 302:  
 303:         printf("│\n");
 304:     }
 305:     
 306:     printf("└─────┴────────────────────────┴────────┘\n");
 307:         
 308:  
 309:     return ;
 310: }



● 핵심코드만

   1: // 1. 네트웍 장치명 읽어오기
   2: cpNIC_Name = pcap_lookupdev(errbuf);    // 장치이름을 알아오고,
   3: if(NULL == cpNIC_Name)    // 에러난 경우 에러버퍼에 에러가 난 이유를 저장.
   4: {
   5:     printf(errbuf);        
   6:     putchar('\n');
   7:     exit(-1);        //exit()가 나은가?
   8:     //return -1;        //리턴이 나은가?
   9: }
  10:  
  11: printf(cpNIC_Name);
  12: putchar('\n');
  13:  
  14:  
  15: // 2. 네트웍 장치 열기
  16: //                         장치명, 나중에 설명, 에러버퍼   
  17: stpNIC = pcap_open_live(cpNIC_Name, 1500, 1, 0, errbuf);
  18: if(NULL == stpNIC)    //에러가 난 경우
  19: {
  20:     printf(errbuf);
  21:     putchar('\n');
  22:     exit(-2);
  23:     //return -2;
  24: }
  25:  
  26: printf("패킷캡쳐 오픈 successful(성공)\n");
  27:  
  28: // 3. 패킷분석을 위해 패킷캡쳐 
  29: ucpData = pcap_next(stpNIC, &stInfo);
  30:  
  31: // 4. 패킷내용을 출력
  32: HexaView(ucpData, 160);
  33: //MSDFunction(ucpData, 100);
  34:  
  35: // last. 열린 네트웍장치를 닫는다.
  36: pcap_close(stpNIC);        


● 소스코드설명 (절차와 분석 + man page오류)

//임시로 맨 아래의 참조문서를 참고하세요.




● 컴파일 & 실행과정 (리눅스 사용자 계정과 루트계정? + uec계정 + -l옵션 없이 컴파일시 에러메시지분석)

image 

리눅스공유폴더에서,
# gcc –o main main.c –lpcap

-l 옵션을 줘서 pcap라이브러리를 연결시키고 컴파일한 후 생성된 main 실행파일을..
예전에 만든 사용자계정 디렉토리로 복사한다.
(사용자를 바꾼 후 루트로 이동했는지 아니면 사용자계정 디렉토리에 복사 후 루트로 이동해서 사용자를 바꾸었는지 기억이..)


image image 
어쨋든 예전에 만든 사용자계정 suman의 디렉토리에 main실행파일의 속성을 보면,
-rwx------로 처음 ‘-‘는 파일을 뜻하고 다음에 오는 rwx는 관리자 권한으로 읽기/쓰기/실행이 가능하다는 것이다.
다른 사용자와 그룹(?)은 권한이 없다. 그래서,

# su – suman

su명령으로 사용자르 바꾼 후 main을 실행할순 없다. 그래서,

# chmod 777 main

chmod명령으로 파일의 속성을 모두 1로 만들어 모든 권한이 가능하게 한다.(?)
그런 후 사용자계정으로,

$ ./main

main파일을 실행하면 파일속성이 모든 권한이 되어 실행은 되나 정작 중요한 네트워크장치를 열 수 없다.
네트워크장치는 루트권한이 있는 슈퍼유저만 사용할 수 있는 것 같다. 그래서,

$ exit

exit명령이나 Ctrl + D키로 로그아웃하여 다시 루트계정으로 돌아와,

# ./main

main파일을 실행하면 정상적으로 코드가 실행되어 장치도 열고 패킷도 캡쳐가 된다.




● FTP서버에 접속 후 ID와 Password입력하여 전송되는 패킷 캡쳐 + 헤더 분석


image image
//자세한 설명은 나중에 일단 참조문서 보삼 ㅠㅠ

image




● TCP/IP 4 Layer와 OSI 7 Layer + 패킷전송과정(흐름)

// 이것도 일단 맨 아래 참조문서를…보삼;


참조(Reference)


DSCN4469 DSCN4470 DSCN4471 DSCN4472 DSCN4473