본문 바로가기

Code

SSH Bot_Net 환경 구축하기 [Python]

 

import argparse
from pexpect import pxssh

class Client:
    def __init__(self, host, user, password):
        self.host = host
        self.user = user
        self.password = password
        self.session = self.connect()

    def connect(self):
        try:
            s = pxssh.pxssh()
            s.login(self.host, self.user, self.password)

            return s

        except Exception, e:
            print e
            print '[-] Error Connectiong'

    def send_command(self, cmd):
        self.session.sendline(cmd)
        self.session.prompt()

        return self.session.before

def botnetCommand(command):
    for client in botNet:
        output = client.send_commend(commend)

        print '[*] Output from ' + client.host
        print '[+] ' + output + '\n'

def addClient(host, user, password):
    client = Client(host, user, password)

    botNet.append(client)

botNet = []

addClient('10.10.10.110', 'root', 'toor')
addClient('10.10.10.120', 'root', 'toor')
addClient('10.10.10.130', 'root', 'toor')

botnetCommand('uname -v')
botnetCommand('cat /etc/issue')

- SSH 봇넷 환경 구축입니다. SSH를 이용해 호스트를 제어할 수 있는데 이때 여러 호스트를 한번에 제어를 원할 때 사용합니다. 봇넷은 '공격자에 의해 감염된 호스트들의 모임'인데요. 그 뜻에 맞게 공격자가 감염 시켰던 호스트들을 동시에 여러대를 제어할 수 있게 하는 것 입니다.

 

 

< 코드 설명 >

 

사용 모듈 : argparse, pexpect import pxssh

 

 

* 모듈 설명

 

- argparse : 명령줄에서 즉, 해당 파일을 실행 할 때 해당 실행 명령과 동시에 인자를 넣어줄 수 있게 해주는 모듈 입니다. 'sys'모듈과는 다른점이 있습니다. 일단 리눅스에서 터미널 내에서 사용하는 툴들 처럼 특정 옵션을 받고 원하는 변수에 값을 집어 넣고 해당 프로그램을 어떻게 사용하는지 'help'기능 까지 한번에 사용이 가능합니다.

 

- pexpect import pxssh : pxssh 는 시스템의 SSH 명령을 둘러싼 화면 스크래핑 래퍼(화면에 보이는 데이터 중 필요한 데이터만 추출해 주는 작업입니다.) 입니다. 이번에 여러 SSH를 접속하여 처리를 해야하기 때문에 해당 작업을 좀더 편하게 도와주는 모듈입니다.

 

 

class Client:

 

 - 이번 코드는 'class'로 시작합니다. 객체 지향 프로그램에서는 근복적인 요소입니다. 이번 코딩에서는 각각의 객체를 관련된 메소드로 실체화 하는게 필요합니다. 물론 무조건 사용해야 하는건 아닙니다. 여러 툴이나 잘만들어진 코딩을 보면 오히려 안쓴게 더 많아 보입니다. 하지만 'class'를 사용하는 걸 익숙해지고 어떻게 써야할지 잘 알게될 때 큰 효율을 얻게 됩니다.

 예를 들어 저희는 '과자'를 만들려고 합니다. 혼자 먹으려고 한다면 손으로 이쁘게 뭉쳐서 먹을 만큼만 만들면 됩니다. 그런데 만약 손님이 오거나 팔아야 하기 때문에 대량으로 만들어야 한다면 직접 손으로 만드는건 매우 비효율적일 것입니다. 그러기에 우리는 과자의 모양을 쉽게 만들어주는 '틀'을 만들어 사용합니다. 일정한 크기, 모양을 빠르게 몇개든 계속 찍어낼 수 있는 상태가 됩니다. 여기서 과자를 만들기 위해 사용한 '틀'이 '클래스' 입니다. 그리고 그 '틀'에 의해 만들어진 '과자'들이 '객체'가 됩니다.

 그렇다면 지금 이코드를 다시보면 왜 'class'를 사용하려는지 눈에 보이게 됩니다. 저희는 여러게의 SSH를 제어해야 합니다. 그렇기 때문에 각각에 대한 코드를 계속 작성하는 것은 비효율 적이기 때문에 'class'를 이용하여 한번의 작성으로 여러 SSH를 제어할 수 있게 만들려고 하는것 입니다.

 

 

    def __init__(self, host, user, password):

        self.host = host

        self.user = user

        self.password = password

        self.session = self.connect()


- 'class'내부의 첫 메소드(함수) 입니다. 파이썬에서 클래스 내부에서 메소드를 생성할 때 인자의 첫 부분은 'self'를 사용하게 됩니다. 'self'인자 부분에는 해당 클래스의 인스턴스(객체 지향 프로그래밍에서 컴퓨터 메모리에 할당된 실체입니다.)가 자동으로 입력됩니다. 저희가 직접 입력하는 인자의 부분이 아닌 컴퓨터가 사용하는 공간입니다. 해당 부분을 통해 클래스의 구조가 메모리에 저장되고 저장된 메모리 주소부분을 호출하여 해당 클래스를 사용하는 것입니다. 클래스를 사용하는 이유였죠 같은 객체를 여러개 사용하는 것.

 그렇다면 'self'를 안쓰면 어떻게 될까요 컴퓨터 메모리에 해당 클래스의 주소가 등록이 안된상태로 실행이 될 것입니다. 저희가 여러개를 동시에 사용하고 싶어서 만들었지만 저장이 안되는 상태가 됩니다. 그래서 'self'를 이용하여 각각의 호스트에 대한 클래스의 주소를 부여하여 동시에 관리를 하는 것입니다.

 '__init__'을 보겠습니다. 파이썬에서 특별하게 약속된 메소드 중 하나입니다. 간단하게 생각하면 '__init__'내부의 값으로 클래스 내부 값을 초기화 한다고 생각해도 됩니다.

 하나의 호스트에 연결시키고 인스턴스값을 저장하고 다음을 실행시키고 다른 인스턴스 값을 저장하는 작업을 반복하여 여러개의 호스트를 연결합니다.



    def connect(self):

        try:

            s = pxssh.pxssh()

            s.login(self.host, self.user, self.password)


            return s


        except Exception, e:

            print e

            print '[-] Error Connectiong'


 - 'try, except'를 이용한 예외처리가 들어가 있습니다. 's = pxssh.pxssh()'는 해당 모듈을 실행하기위한 작업입니다. 그리고 's.login(self.host, self.user, self.password)'로 접속을 시도합니다. 접속한 값 's'를 'return'을 통해 반환받습니다. 'except'에서는 오류에 대한 예외를 오류 알림 문구 출력으로 넘깁니다.



    def send_command(self, cmd):

        self.session.sendline(cmd)

        self.session.prompt()


        return self.session.before


 - 커멘드를 입력하기 위한 메소드입니다. 'session.sendline(cmd)'는 메시지를 전송하는 함수입니다. 'session.prompt()'은 대화형으로 전송할 수 있게 만들어 주는 함수입니다. 마지막으로 이전 세션의 값을 반환합니다.



def botnetCommand(command):


    for client in botNet:

        output = client.send_commend(commend)


        print '[*] Output from ' + client.host

        print '[+] ' + output + '\n'


 - 봇넷에 연결된 호스트들을 출력합니다. 반복문을 사용하여 'botNet'배열 내부에 있는 연결된 호스트의 정보를 공격자가 볼 수 있게 출력합니다. 그리고 'command'인자를 이용하여 명령을 전달할 수 있습니다.



def addClient(host, user, password):

    client = Client(host, user, password)

    botNet.append(client)


 - 'Client' 클래스를 이용한 연결을 하는 함수 입니다. 연결이 확인된 사용자는 'botNet' 배열에 추가되어 'botnetCommand' 함수에서 출력을 위해 사용됩니다.



botNet = []


addClient('10.10.10.110', 'root', 'toor')

addClient('10.10.10.120', 'root', 'toor')

addClient('10.10.10.130', 'root', 'toor')

botnetCommand('uname -v')

botnetCommand('cat /etc/issue')


 - 'botNet' 변수는 로그인 완료된 호스트에 대한 정보를 저장하기 위한 배열 입니다. 'addClient()'함수를 호출하여 원하는 호스트들과 동시에 연결을 시도합니다. 연결이 완료 된 호스트는 'botnetCommand()'함수를 이용하여 확인을 하고 원하는 명령을 전달 합니다. 해당 코드에서는 'uname -v'과 'cat /etc/issue'를 사용하였습니다.

 

 

반응형