init code and manual

attribution:

- cayo did code and explanations
- pedro formatted and edited to inclusion as a repository
This commit is contained in:
pedro 2024-09-18 11:13:40 -03:00
parent 8163ab3c3f
commit 44959acdf5
5 changed files with 383 additions and 0 deletions

3
README-en.md Normal file
View file

@ -0,0 +1,3 @@
TODO I suggest that when we have a mature and good README-es we do a translation
The reason to first work on README-es is that our collaborators are Spanish, and we want to facilitate the software for them

56
README-es.md Normal file
View file

@ -0,0 +1,56 @@
## Resumen
1. workbench solo hace dos funcionalidades:
1. recopila datos del PC y los guarda como fichero snapshot o los sube a devicehub
2. opcionalmente borra discos
### Hoja de ruta (2024)
A través de un proyecto de ISOC se van a trabajar las dos funcionalidades siguientes:
- F1: Borrado de discos SSD
- F2: Firma criptográfica de snapshots, conversión de los snapshots en credenciales verificables o evidencias
## Detalle funcionalidad
1. Genera snapshot
2. Guarda snapshot en el path que indicas
3. Envía a una URL si le pasas URL y token
4. Borra
1. borrado basico como hay ahora
2. borrado baseline como hay ahora
3. borrado enhanced como hay ahora
4. borrado ata para quien lo soporte
5. borrado nvme para quien lo soporte
Comentarios sobre el borrado:
1. Comentario de borrado por encriptación: no borra por encriptacion porque lo unico que hace es quitar las claves de encriptacion. Depende de que tu disco esté cifrado. Si tu disco no está cifrado por hardware, entonces no funcionará este tipo de borrado (pendiente revisar).
2. El borrado 4.4 y 4.5 no siguen especificamente un estándar, pero creo que son mejores.
## Uso del script
Detalles del uso del script para los técnicos
```
workbench.py [-h] -p PATH [-u URL] [-t TOKEN] [-d DEVICE] [-e {basic,baseline,enhanced}]
OPCIONES
El -p es el unico que es obligatorio el resto son opcionales. Si no pones -e no borra.
-p path
deja el snapshot en el dir path (tal como /mnt)
-e tipo-borrado
tipo de borrado de disco: basic, baseline, enhanced. Nota: bueno si pones -e tampoco borra porque hay que cambiar el script pero es descomentar unas lineas y ya.
-d device
le dices que device quieres borrar y depende de -e que defines el tipo de borrado. Nota: si no le dices -d y solo usas -e borrara todo lo que pille, menos el de boot como dijimos (no probado)
-u tiene que ir con -t y se usa para enviar a una direccion con su token (no probado)
```
## Enfoque
workbench-script trata de ser simple y minimalista, una función principal y funciones de soporte la lectura de las diferentes funcionalidades.

View file

@ -1,2 +1,5 @@
# workbench-script
- [Español](./README-es.md)
- [English](./README-en.md)

2
requirements.txt Normal file
View file

@ -0,0 +1,2 @@
ntplib
requests

319
workbench-script.py Normal file
View file

@ -0,0 +1,319 @@
# -*- coding: utf-8 -*-
import os
import json
import uuid
import hashlib
import argparse
import ntplib
import requests
from datetime import datetime
## Utility Functions ##
def logs(f):
def wrapper(*args, **kwargs):
try:
return f(*args, **kwargs)
except Exception as err:
print(err)
return ''
return wrapper
@logs
def exec_cmd(cmd):
return os.popen(cmd).read()
@logs
def exec_cmd_erase(cmd):
print(cmd)
return ''
# return os.popen(cmd).read()
def gen_code():
uid = str(uuid.uuid4()).encode('utf-8')
return hashlib.shake_256(uid).hexdigest(3)
## End Utility functions ##
SNAPSHOT_BASE = {
'timestamp': str(datetime.now()),
'type': 'Snapshot',
'uuid': str(uuid.uuid4()),
'code': gen_code(),
'software': "EreuseWorkbench",
'version': "0.0.1",
'data': {},
'erase': []
}
## Command Functions ##
## Erase Functions ##
## Xavier Functions ##
def erase_basic(disk):
"""
Basic Erasure
https://tsapps.nist.gov/publication/get_pdf.cfm?pub_id=917935
Settings for basic data erasure using shred Linux command.
A software-based fast non-100%-secured way of erasing data storage.
Performs 1 pass overwriting one round using all zeros.
Compliant with NIST SP-800-8y8.
In settings appear:
WB_ERASE = EraseBasic
WB_ERASE_STEPS = 1
WB_ERASE_LEADING_ZEROS = False
"""
cmd = f'shred -vn 1 /dev/{disk}'
return [exec_cmd_erase(cmd)]
def erase_baseline(disk):
"""
Baseline Secure Erasure
Settings for advanced data erasure using badblocks Linux software.
A secured-way of erasing data storages, erase hidden areas,
checking the erase sector by sector.
Performs 1 pass overwriting each sector with zeros and a final verification.
Compliant with HMG Infosec Standard 5 Baseline.
In settings appear:
WB_ERASE = EraseSectors
WB_ERASE_STEPS = 1
WB_ERASE_LEADING_ZEROS = True
WB_ERASE_1_METHOD = EraseBasic
WB_ERASE_1_STEP_TYPE = 0
WB_ERASE_2_METHOD = EraseSectors
WB_ERASE_2_STEP_TYPE = 1
"""
result = []
cmd = f'shred -zvn 0 /dev/{disk}'
result.append(exec_cmd_erase(cmd))
cmd = f'badblocks -st random -w /dev/{disk}'
result.append(exec_cmd_erase(cmd))
return result
def erase_enhanced(disk):
"""
Enhanced Secure Erasure
Settings for advanced data erasure using badblocks Linux software.
A secured-way of erasing data storages, erase hidden areas,
checking the erase sector by sector.
Performs 3 passes overwriting every sector with zeros and ones,
and final verification. Compliant with HMG Infosec Standard 5 Enhanced.
In settings appear:
WB_ERASE = EraseSectors
WB_ERASE_LEADING_ZEROS = True
WB_ERASE_1_METHOD = EraseBasic
WB_ERASE_1_STEP_TYPE = 1
WB_ERASE_2_METHOD = EraseBasic
WB_ERASE_2_STEP_TYPE = 0
WB_ERASE_3_METHOD = EraseSectors
WB_ERASE_3_STEP_TYPE = 1
"""
result = []
cmd = f'shred -vn 1 /dev/{disk}'
result.append(exec_cmd_erase(cmd))
cmd = f'shred -zvn 0 /dev/{disk}'
result.append(exec_cmd_erase(cmd))
## creo que realmente seria asi (3 pases y una extra poniendo a ceros):
# shred -zvn 3 /def/{disk}
# tampoco estoy seguro que el badblocks haga un proceso de verificacion.
cmd = f'badblocks -st random -w /dev/{disk}'
result.append(exec_cmd_erase(cmd))
return result
## End Xavier Functions ##
def ata_secure_erase_null(disk):
cmd_baseline = f'hdparm --user-master u --security-erase NULL /dev/{disk}'
return [exec_cmd_erase(cmd_baseline)]
def ata_secure_erase_enhanced(disk):
cmd_enhanced = f'hdparm --user-master u --security-erase-enhanced /dev/{disk}'
return [exec_cmd_erase(cmd_enhanced)]
def nvme_secure_erase(disk):
cmd_encrypted = f'nvme format /dev/{disk} --ses=1'
return [exec_cmd_erase(cmd_encrypted)]
## End Erase Functions ##
@logs
def get_disks():
disks = json.loads(
exec_cmd('lsblk -Jdo NAME,TYPE,MOUNTPOINTS,ROTA,TRAN')
)
return disks.get('blockdevices', [])
@logs
def gen_erase(all_disks, type_erase, user_disk=None):
erase = []
for disk in all_disks:
if user_disk and disk['name'] not in user_disk:
continue
if disk['type'] != 'disk':
continue
if 'boot' in disk['mountpoints']:
continue
if not disk['rota']:
# if soport nvme erase
erase.append(nvme_secure_erase(disk['name']))
elif disk['tran'] in ['ata', 'sata']:
# if soport ata erase
if type_erase == 'basic':
erase.append(ata_secure_erase_null(disk['name']))
elif type_erase == 'baseline':
erase.append(ata_secure_erase_null(disk['name']))
elif type_erase == 'enhanced':
erase.append(ata_secure_erase_enhanced(disk['name']))
else:
# For old disks
if type_erase == 'basic':
erase.append(erase_basic(disk['name']))
elif type_erase == 'baseline':
erase.append(erase_baseline(disk['name']))
elif type_erase == 'enhanced':
erase.append(erase_enhanced(disk['name']))
return erase
@logs
def exec_smart(disk):
cmd = f'smartctl -x --json=cosviu /dev/{disk}'
return json.loads(exec_cmd(cmd))
@logs
def smartctl(all_disks, disk=None):
if disk:
return exec_smart(disk)
data_list = []
for disk in all_disks:
if disk['type'] == 'disk':
data = exec_smart(disk['name'])
data_list.append(data)
return data_list
## End Command Functions ##
def get_data(all_disks):
lshw = 'lshw -json'
hwinfo = 'hwinfo --reallyall'
dmidecode = 'dmidecode'
data = {
'lshw': exec_cmd(lshw),
'disks': smartctl(all_disks),
'hwinfo': exec_cmd(hwinfo),
'dmidecode': exec_cmd(dmidecode)
}
return data
def gen_snapshot(all_disks):
snapshot = SNAPSHOT_BASE.copy()
snapshot['data'] = get_data(all_disks)
return snapshot
def save_snapshot_in_disk(snapshot, path):
filename = "{}/{}_{}.json".format(
path,
datetime.now().strftime("%Y%m%d-%H_%M_%S"),
snapshot['uuid']
)
with open(filename, "w") as f:
f.write(json.dumps(snapshot))
def send_snapshot_to_devicehub(snapshot, token, url):
headers = {
f"Authorization": "Basic {token}",
"Content-Type": "application/json"
}
return requests.post(url, data=snapshot, header=headers)
@logs
def sync_time():
# is neccessary?
ntplib.NTPClient()
response = client.request('pool.ntp.org')
def main():
print("START")
parser=argparse.ArgumentParser()
parser.add_argument("-p", "--path", required=True)
parser.add_argument("-u", "--url", required=False)
parser.add_argument("-t", "--token", required=False)
parser.add_argument("-d", "--device", required=False)
parser.add_argument(
"-e",
"--erase",
choices=["basic", "baseline", "enhanced"],
required=False
)
args=parser.parse_args()
if args.device and not args.erase:
print("error: argument --erase: expected one argument")
return
if args.token and not args.url:
print("error: argument --url: expected one argument")
return
if args.url and not args.token:
print("error: argument --token: expected one argument")
return
all_disks = get_disks()
snapshot = gen_snapshot(all_disks)
if args.erase and args.device:
snapshot['erase'] = gen_erase(all_disks, args.erase, user_disk=args.device)
elif args.erase:
snapshot['erase'] = gen_erase(all_disks, args.erase)
save_snapshot_in_disk(snapshot, args.path)
if args.url:
send_snapshot_to_devicehub(snapshot, args.token, args.url)
print("END")
if __name__ == '__main__':
main()