C 로알아보는 소켓프로그래밍 이현환 (NOON) haonun@gmail.com http://noon.tistory.com Hacking Study Grup E.Y.E --------------------------------------------------------------------
목차 -------------------------------------------------------------------- 서론 1. 이번에는왜하는걸까..? 본론 2. 네트워크란 3. TCP/IP 4. 소켓프로그래밍 - C로알아보는소켓프로그래밍 5. 응용 - C로알아보는응용 결론 6. 결론 --------------------------------------------------------------------
서론 현재의많은프로그램, 프로젝트들은네트워크를기반으로한프로그램들이많습니다. 또한최근에활발한발전을이룩한모바일, 웹기반의어플리케이션들도대부분네트워크를전재로움직입니다. 이만큼네트워크는삶에깊이침투한분야입니다. 우리그룹도취약점을찾고, 또한침투테스트를하기위해선네트워크프로그래밍의중요성을인식해야할것같습니다. 네트워크프로그래밍의기본인소켓프로그래밍을배움으로서우리가사용해야할툴이나프로그램들을직접개발할수있는환경이되길바랩니다. 본론 네트워크란 TCP/IP TCP/IP는인터넷의기본적인통신프로토콜로서, 인트라넷이나엑스트라넷과같은사설망에서도사용된다. 사용자가인터넷에접속하기위해자신의컴퓨터를설정할때 TCP/IP 프로그램이설치되며, 이를통하여역시같은 TCP/IP 프로토콜을쓰고있는다른컴퓨터사용자와메시지를주고받거나, 또는정보를얻을수있게된다. TCP/IP는 2개의계층으로이루어진프로그램이다. 상위계층인 TCP는메시지나파일들을좀더작은패킷으로나누어인터넷을통해전송하는일과, 수신된패킷들을원래의메시지로재조립하는일을담당한다. 하위계층, 즉 IP는각패킷의주소부분을처리함으로써, 패킷들이목적지에정확하게도달할수있게한다. 네트웍상의각게이트웨이는메시지를어느곳으로전달해야할지를알기위해, 메시지의주소를확인한다. 한메시지가여러개의패킷으로나뉘어진경우각패킷들은서로다른경로를통해전달될수있으며, 그것들은최종목적지에서재조립된다. TCP/IP는통신하는데있어클라이언트 / 서버모델을사용하는데, 컴퓨터사용자 ( 클라이언트 ) 의요구에대응하여, 네트웍상의다른컴퓨터 ( 서버 ) 가웹페이지를보내는식의서비스를제공한다. TCP/IP는본래점대점 ( 点對点 ) 통신을하는데, 이는각통신이네트웍상의한점 ( 또는호스트컴퓨터 ) 으로부터시작되어, 다른점또는호스트컴퓨터로전달된다는것을의미한다.
TCP/IP와 TCP/IP를이용하는상위계층의응용프로그램들은모두 " 커넥션리스 (connectionless)" 라고불리는데, 이는각클라이언트의요구가이전에했던어떠한요구와도무관한새로운요구로간주된다는것을의미한다 ( 일상적인전화통화가통화시간내내지속적으로연결되어있어야하는것과는다르다 ). 커넥션리스는네트웍을독점하지않으므로, 모든사람들이그경로를끊임없이공동으로사용할수있게한다 ( 사실 TCP 계층그자체는어떤한메시지가관계되어있는한커넥션리스가아니라는데유의해야한다. TCP 접속은어떤한메시지에속하는모든패킷들이수신될때까지계속유지된다 ). 많은인터넷사용자들이 TCP/IP를이용하는상위계층응용프로토콜에대해서는잘알고있다. 이러한상위계층프로토콜에는웹서비스에사용되는 HTTP를비롯하여, 멀리떨어져있는원격지의컴퓨터에로그온할수있게해주는 Telnet, 그리고파일전송에사용되는 FTP 와메일전송에사용되는 SMTP 등이있다. 이러한프로토콜들은종종 TCP/IP와함께패키지로일괄판매된다. PC 사용자들은보통인터넷에접속하기위해 SLIP이나 PPP 프로토콜을사용한다. 이러한프로토콜들은다이얼업전화접속을통해접속서비스사업자의모뎀으로보내질수있도록 IP 패킷들을캡슐화한다. TCP/IP와관련이있는프로토콜로 UDP가있는데, 이것은특별한목적을위해 TCP 대신에사용되는것이다. 라우팅정보를교환하기위해네트웍호스트컴퓨터에의해사용되는프로토콜에는 ICMP, IGP, EGP, 그리고 BGP 등이있다. 소켓프로그래밍 함수설명 socket : 소켓생성 bind : 주소부여 listen : 대기 accept : 연결확인및수신 connect : 접속 read : 읽기 write : 쓰기
서버 1. 소켓생성 (socket 함수 ) 2. 생성된소켓에인터넷주소부여 (bind 함수 ) 3. 데이터수신대기 (listen 함수 ) 4. 데이터수신 (accept 함수 ) 5. 데이터읽기 (read 함수 ) 6. 데이터쓰기 (write 함수 ) 7. 3번으로돌아간다 (listen 함수 ) 클라이언트 1. 소켓생성 (socket 함수 ) 2. 서버에연결 (connect 함수 ) 3. 데이터쓰기 (write 함수 ) 4. 데이터읽기 (read 함수 ) 5. 연결종료 (close 함수 )
C 로알아보기 서버 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> void error_handling(char *message); int main(int argc, char **argv) int sock; struct sockaddr_in serv_addr; char message[30]; int str_len; int ending = 0; if(argc!=3) printf("usage : %s <IP> <port> n", argv[0]); exit(1); while(!ending) sock = socket(pf_inet, SOCK_STREAM, 0); // 서버접속을위한소켓생성 if(sock == -1) error_handling("socket() error"); memset(&serv_addr, 0, sizeof(serv_addr)); // 메모리초기화 serv_addr.sin_family = AF_INET; // 인터넷주소체계저장 serv_addr.sin_addr.s_addr = inet_addr(argv[1]); // serv_addr.sin_port = htons(atoi(argv[2])); 요청 if(connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1) // 서버로연결 error_handling("connect() error"); str_len = read(sock, message, sizeof(message) -1); // 데이터수신 if(str_len == -1) error_handling("read() error!"); message[str_len] = 0;
printf("message from server : %s n", message); if(message[0] == 0x1b) ending = 1; return 0; close(sock); // 연결종료 void error_handling(char *message) fputs(message, stderr); fputc(' n', stderr); exit(1); 클라이언트 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> void error_handling(char *message); int main(int argc, char **argv) int i; int serv_sock; int clnt_sock; struct sockaddr_in serv_addr; struct sockaddr_in clnt_addr; int clnt_addr_size; char message[256]; int ending = 0; if(argc!= 2) printf("usage : %s <port> n", argv[0]); exit(1); serv_sock = socket(pf_inet, SOCK_STREAM, 0); // 서버소켓생성 if(serv_sock == -1) error_handling("socket() error"); memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; //Internet protocol
serv_addr.sin_addr.s_addr = htonl(inaddr_any); //Ip address serv_addr.sin_port = htons(atoi(argv[1])); //Port if(bind(serv_sock, (struct socketaddr*) &serv_addr, sizeof(serv_addr)) == -1) // 소켓에주소할당 error_handling("bind() error"); if(listen(serv_sock, 5) == -1) //listen stat 돌입 error_handling("listen() error"); clnt_addr_size = sizeof(clnt_addr); while(!ending) clnt_sock=accept(serv_sock, (struct sockaddr*) &clnt_addr, &clnt_addr_size); // 연결요청이들어오면수락 if(clnt_sock == -1) error_handling("accept() error"); scanf("%s", message); write(clnt_sock, message, sizeof(message)); // 전송할데이터쓰기 if(message[0] == 0x1b) ending = 1; close(clnt_sock); return 0; void error_handling(char *message) fputs(message, stderr); fputc(' n', stderr); exit(1);
응용 위에서배운소켓프로그래밍기술로간단한포트스캐너를구현하였습니다. 포트스캐너는어떠한네트워크에대해많은정보를취득할수있는도구입니다. 대표적인포트스캐너로는 nmap 이있습니다. ( 관련 http://noon.tistory.com/689) 현재는간단한예제로사용하기위해오픈되어있는포트와서비스의종류를탐지할수있도록설계해보았습니다. 현재 Hidden Eye라는포트및취약점스캐너를만들어보면서간단하게도이렇게구성할수있다는걸배웟기에이내용을공유합니다. 첨부로소스코드올려습니다. 밑의포트스캐너는리눅스에서사용하실수있습니다. #include <stdio.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <netinet/in.h> #include <errno.h> int searcheye(char *hostaddr, int cport, int socktype); char service[20]; // 서비스확인 int main(int argc, char *argv[])// 프로그램싱행인자값 int cport; // count Port if (argc < 2) printf("port 'hostname' [not Option] n"); return 0; system("clear");
printf("e.y.e SCanner nby NOON n"); printf(" n nscan... %s n",argv[1]); printf(" n------------------------------------------------- n"); printf(" Port Stat Service n"); for (cport = 1;cport < 1001;cport++) // 확인포트 if (searcheye(argv[1], cport, SOCK_STREAM) == 0) // 연결값출력 printf(" %5d Open %7s n", cport,service); memset(service,0x00, sizeof(service)); // 문자열초기화 printf(" n------------------------------------------------- n"); return 0; int searcheye(char *hostaddr, int cport, int socktype) int sockfd; // 소켓 struct hostent *he; struct sockaddr_in destaddr;//socket addr 를좀더편하게넣기위한 int pok; // 반환값 if ((he = gethostbyname(hostaddr)) == NULL) herror("gethostbyname"); // 겟바이호스트 return 0; sockfd = socket(af_inet, socktype, 0); //sockfd 소켓으로사용함 destaddr.sin_family = AF_INET; // AF_INET TCPIP destaddr.sin_addr = *((struct in_addr *)he->h_addr); // IP destaddr.sin_port = htons(cport); // 포트 bzero(&(destaddr.sin_zero), 8); // 연결 pok = connect(sockfd, (struct sockaddr *)&destaddr, sizeof(struct sockaddr)); // 실패시 -1반환 close(sockfd); // 연결종료 if (pok == -1) // 반환값으로판단 return -1; // 닫혀있으면 -1 switch(cport) // 아니면서비스탐지 case 21: strcpy(service,"ftp"); break; case 22: strcpy(service,"ssh"); break; case 23: strcpy(service,"telnet"); break; case 25: strcpy(service,"smtp"); break; case 79: strcpy(service,"finger"); break; case 80: strcpy(service,"http"); break; case 119:strcpy(service,"NNTP"); break; case 137:strcpy(service,"NetBios"); break; case 138:strcpy(service,"NetBios"); break; case 139:strcpy(service,"NetBios"); break; return 0; // 0 반환
결론 짧은시간에급히써서발표하게된글이라허술하고내용이많이부실합니다. 그러나이문서를통하여소켓이라는것에흥미라도느껴주셧으면고맙겠습니다. 침투테스트, 서버점검등여러가지일들을수행하기위해선그에맞는툴과프로그램들이필요한데그걸직접개발할수있도록기초를쌓는시간이되셨으면좋겠습니다. 감사합니다. 다른자료들은따로첨부하겠습니다.