Malware 통신 이상 행위 분석

소켓 통신 과정에서 발생한 프로토콜 예외 에러 및 원인 분석 결과 리포트

콘솔 에러 로그 (Console Error Exception)

수신 대기 상태(`NORMAL`) 중 식별되지 않은 바이트 입력으로 인한 프로토콜 에러가 검출되었습니다.

Protocol error: expecting ! for state NORMAL, got: 218 Ú

와이어샤크 수신 패킷 raw-data

Wireshark 스니핑을 통해 확인된 실제 유입 데이터 구조는 다음과 같습니다.

Wireshark 패킷 분석 화면
!100!!100.100.100.100!0!

예상 원인 분석 및 메커니즘 (Root Cause)

ERR 01
데이터 오류 송신
릴레이 서버(messageRelayServer.py)에서 전달된 IP 리스트 패킷의 Bit 수가 일치하지 않은 상태로 소켓에 전송되었습니다.
ERR 02
오인 복호화 발생
자바 서버단에서 CipherInputStream(cin2) 스트림을 생성하였으나, 잘못된 데이터를 읽은 후 복호화 루틴이 꼬이며 데이터 오염(218 Ú)이 초래되었습니다.

코드 분석 (Context)

messageRelayServer.py (문제 구간)
    
def sendIPList(self,address=""):
    state = "100"
    ips = self.toVirus.keys()
    data = ""
    for ip in ips:
        data += ip + ":" + self.toVirus[ip][2]
    length = len(data)
       
    pkt = Packet()
    pkt.state = state
    pkt.length = str(length)
    pkt.data = data
    pkt.encryptData(self.AESKey)
    print "IPList: " + data
    if address != "":
        pkt.returnIP = address[0]
        self.enqueueToClient(pkt)
    else:
        for ip in self.toClient.keys():
            self.enqueueToClient(pkt,ip)
messageRelayServer.py (수정)

def sendIPList(self,address=""):
    state = "100"
    ips = self.toVirus.keys()
    data = ""
    for ip in ips:
        data += ip + ":" + self.toVirus[ip][2]
    length = len(data)

    pkt = Packet()
    pkt.state = state
    pkt.data = data
    pkt.encryptData(self.AESKey)
	pkt.length = str(len(pkt.data))
	print ("IPList: " + data)
    if address != "":
        pkt.returnIP = address[0]
        self.enqueueToClient(pkt)
    else:
        for ip in self.toClient.keys():
            self.enqueueToClient(pkt,ip)

        

최종 해결 조치 방안 (Mitigation)

Recommendation
  • 방안 (검증 강화): messageRelayServer.py에서 (pkt.data)를 사용해 packet을 직접 읽게 만들어 오인 복호화 될 여지를 없앱니다.

테스트를 위한 IP하드코딩

Client에서 IP를 받아오지 못해 IP리스트가 초기화 됩니다.
따라서 일시적으로 IP를 하드코딩해 SelectionPanel.java에 추가해줍니다.

클라이언트 뷰 반영 참조 소스

SelectionPanel.java (updateIpSet)
public void updateIpSet(Set<InetAddress> newIps) {
  for (InetAddress ip : newIps) {
    if (!ips.contains(ip)) ips.add(ip);
  }
  Iterator<InetAddress> i = ips.iterator();
  while (i.hasNext()) {
    if (!newIps.contains(i.next())) i.remove();
  }
  try {
      ips.add(InetAddress.getByName("125.246.95.152")); 
  } catch (UnknownHostException e) {
      e.printStackTrace();
  }
}