
Problema
Alguns velhosServidor WS_FTPparou de inicializar no trabalho após uma atualização do Windows. O administrador correspondente já se foi. A única informação que tenho é:
- estrutura de arquivo
- nomes de usuário
- hash SHA256 sem sal para cada usuário
Um desses hashes é:
5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8
que corresponde a "password"
. Eu poderia verificar com: echo -n password | sha256sum
.
Eu nem sei onde estão os clientes FTP. Alguns deles são sensores remotos aos quais não consigo acessar. Eles ainda estavam enviando dados até o servidor parar. Os dados não são confidenciais, mas são importantes para nós.
Tentativas
Eu tentei correrJoão, o Estripadornos hashes. Encontrou 4 senhas de 30.
Tentei encontrar um servidor FTP Linux que usa hashes SHA256 sem sal. Eu acho que é muito inseguro, então nenhum servidor propôs isso, pelo menos não como padrão
Alguns servidores (por exemplovsftpd) delegar para htpasswd. No entanto, não consegui encontrar uma maneira de salvar um hash SHA256 sem sal.
Pergunta
É possível criar um htpasswd
hash com SHA256, sem sal e apenas uma rodada? O mínimo parece ser um salt de 8 bytes e 1000 rodadas com mkpasswd
.
Existe outro servidor FTP Linux que pode ser configurado para funcionar com esses hashes?
Não me importo muito com segurança, gostaria apenas de configurar um servidor FTP que aceite conexões de entrada dos sensores.
Responder1
@Broco sugeriu usarpyftpdlib, que funcionou perfeitamente para minhas necessidades!
Aqui estão as etapas:
- Instale um servidor Linux
- InstalarAnaconda
- Instalarpyftpdlib
- Crie um arquivo json com um ditado de nome de usuário, hash e pasta
- Crie um script pyftpdlib para um servidor FTP que compare os hashes SHA256
- Redirecionarporta 21 para porta 8021
- Execute-o como umunidade do sistemacomo um usuário não privilegiado
- Reinicie oservidor FTP automaticamentese o arquivo json for modificado.
Aqui está um modelo para o arquivo json:
{
"user1": {
"folder": "users/user1",
"sha256": "DFB0CE07EDF923F1F40BA56CC9BA9C396B53E3399E3164D60E35050BAA2BE9C9"
},
"user2": {
"folder": "users/user2",
"sha256": "5E884898DA28047151D0E56F8DC6292773603D0D6AABBDD62A11EF721D1542D8"
}
}
Aqui está o roteiro:
#!/opt/anaconda3/bin/python -u
#encoding: UTF-8
import re
import os
import hashlib
import json
from pathlib import Path
from pyftpdlib.authorizers import DummyAuthorizer, AuthenticationFailed
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.servers import FTPServer
from pyftpdlib.filesystems import AbstractedFS
FTP_FOLDER = Path("/media/ftp_data")
with open('input/ftp_users.json') as users_json:
USERS = json.loads(users_json.read())
current_folder = Path.cwd().resolve()
def login_dump(username, password, success):
if success:
subfolder = 'logins'
attr = 'w'
else:
subfolder = 'logins/failed'
attr = 'a'
logins_folder = current_folder.joinpath(subfolder)
logins_folder.mkdir(parents=True, exist_ok=True)
with open(str(logins_folder.joinpath(username)), attr) as user_file:
# NOTE: Could write better hash directly, e.g. with `mkpasswd -m sha-512`
user_file.write(password + "\n")
class SHA256Authorizer(DummyAuthorizer):
def validate_authentication(self, username, password, handler):
sha256_hash = hashlib.sha256(password.encode('ascii')).hexdigest().upper()
try:
# NOTE: Case sensitive!
if self.user_table[username]['pwd'] != sha256_hash:
login_dump(username, password, False)
raise AuthenticationFailed
except KeyError:
login_dump(username, password, False)
raise AuthenticationFailed
login_dump(username, password, True)
authorizer = SHA256Authorizer()
for user, params in USERS.items():
print("Adding user %r" % user)
folder = FTP_FOLDER.joinpath(params['folder'])
folder.mkdir(parents=True, exist_ok=True)
authorizer.add_user(user,
params['sha256'].upper(),
str(folder),
perm="elradfmw",
msg_login="Welcome, %s!" % user)
handler = FTPHandler
handler.authorizer = authorizer
handler.banner = "FTP server"
class WindowsOrUnixPathFS(AbstractedFS):
def ftpnorm(self, ftppath):
# NOTE: Some old clients still think they talk to a Windows Server
return super().ftpnorm(ftppath.replace("\\", "/"))
handler.abstracted_fs = WindowsOrUnixPathFS
handler.passive_ports = range(40000, 40500)
# NOTE: Port forwarding is needed because this script shouldn't be run as root.
# See https://serverfault.com/a/238565/442344
server = FTPServer((IP_ADDRESS, 8021), handler)
server.serve_forever()
O script registra as senhas em texto simples, o que é aceitável porque os dados não são confidenciais. Depois de alguns meses, mudarei para o vsftpd.