Fail2ban et Iptables

Tout ça n'est pas encore au point.

À un moment faudra que tout ça soit revu de fond en comble… J'apprends petit à petit.

En attendant, n'utilisez pas ça “comme ça”, ne croyez pas à la qualité de ce qui est là !

Fail2ban logiciel me file des boutons mais je n'ai pas vraiment trouvé de remplaçant. Son principal mérite est de délayer les attaques par brute-force ; en principe notre serveur n'y est pas vulnérable, mais les principes et la sécurité… Bref, c'est aussi bien de l'avoir comme protection supplémentaire, selon le principe du tamis : si ça passe une couche, avec un peu de chance ça ne passera pas la suivante.

En principe aussi, il marche bien avec nftables, le nouveau pare-feu par défaut sur debian. Sauf que là aussi le principe se heurte à la pratique et j'ai le droit à des erreurs si je tente de l'utiliser. En plus y'a pas autant de tutos avec nftables et je trouve ce soft encore plus illisible qu'iptable, c'est dire… Comme iptable et nftables peuvent cohabiter, je vais gérer fail2ban avec iptable, et lui adjoindre ipset afin de gérer les ip qui ont un peu trop abusé.

apt install fail2ban ipset iptable netfilter-persistent ipset-persistent iptables-persistent whois python3-systemd 

Iptable

*-persistent permet de charger des règles au démarrage, en principe situées dans /etc/iptables/.

Règles de base

Actuellement mon routeur me coince en ipv4 (/etc/iptables/rules.v4) donc mes règles ne concernent que ça, il faudra adapter pour ipv6.

Son contenu actuel :

# source https://antoinelounis.com/informatique/securite/configuration-fail2ban-iptables-debian-raspberry/
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]

# Allow internal traffic on the loopback device
-A INPUT -i lo -j ACCEPT

# Continue connections that are already established or related to an established connection
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

# Drop non-conforming packets, such as malformed headers, etc.
-A INPUT -m conntrack --ctstate INVALID -j DROP

# SSH
-A INPUT -p tcp --dport 226 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# HTTP + HTTPS
-A INPUT -p tcp -m multiport --dports 80,443 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT


# Email (postfix + dovecot)
# 25 = smtp, 587 = submission and 993 = IMAPS, 143 imap, 110 pop
-A INPUT -p tcp -m multiport --dports 25,587,993,110,143 -j ACCEPT

# NTP
-A INPUT -p udp --dport 123 -j ACCEPT

# Chain for preventing ping flooding - up to 6 pings per second from a single
# source, again with log limiting. Also prevents us from ICMP REPLY flooding
# some victim when replying to ICMP ECHO from a spoofed source.
-N ICMPFLOOD
-A ICMPFLOOD -m recent --name ICMP --set --rsource
#-A ICMPFLOOD -m recent --name ICMP --update --seconds 1 --hitcount 6 --rsource --rttl -m limit --limit 1/sec --limit-burst 1 -j LOG --log-prefix "iptables[ICMP-flood]>
-A ICMPFLOOD -m recent --name ICMP --update --seconds 1 --hitcount 6 --rsource --rttl -j DROP
-A ICMPFLOOD -j ACCEPT

# Permit useful IMCP packet types.
# Note: RFC 792 states that all hosts MUST respond to ICMP ECHO requests.
# Blocking these can make diagnosing of even simple faults much more tricky.
# Real security lies in locking down and hardening all services, not by hiding.
-A INPUT -p icmp --icmp-type 0  -m conntrack --ctstate NEW -j ACCEPT
-A INPUT -p icmp --icmp-type 3  -m conntrack --ctstate NEW -j ACCEPT
-A INPUT -p icmp --icmp-type 8  -m conntrack --ctstate NEW -j ICMPFLOOD
-A INPUT -p icmp --icmp-type 11 -m conntrack --ctstate NEW -j ACCEPT

# Drop all incoming malformed NULL packets
-A INPUT -p tcp --tcp-flags ALL NONE -j DROP

# Drop syn-flood attack packets
-A INPUT -p tcp ! --syn -m conntrack --ctstate NEW -j DROP

# Drop incoming malformed XMAS packets
-A INPUT -p tcp --tcp-flags ALL ALL -j DROP
COMMIT

# Usage des tables déclarées avec ipset
#-A INPUT -m set --match-set blocklist_ip src -j DROP
# Ça, ça ne veut pas...

#rejeter tout le reste 
-A INPUT -j REJECT --reject-with icmp-port-unreachable

Commandes Iptables utiles

Lister “tout” en vrac :

iptables -S

Lister tout en format tableau verbeux, avec numéros de ligne

iptables -L -n -v --line-numbers

Juste dans un des tableaux (ici INPUT)

iptables -L INPUT --line-numbers

Sauf que ce n'est pas “tout”, genre pour lister les règles nat :

iptables -t nat -S

Enlever une règle d'après son numéro de ligne

iptables -D INPUT 14

Restaurer des règles

iptables-restore /etc/iptables/rules.v4

Quelques explications

Différence entre -I et -A

  • -I signifie “insérer la règle à la ligne n° X” ; sans préciser de numéro, la règle se retrouve au début et a donc la priorité sur tout autre.
  • -A indique d'ajouter donc ce sera à la suite du reste des règles.

Bref, quand on a un fichier qui charge les règles, elles sont forcément les unes après les autres, -A est indiqué. Si on teste une règle, alors -I peut être plus pertinent.

DROP ou REJECT --reject-with icmp-port-unreachable

  • DROP ignore complètement le paquet (comme si le serveur n'existait pas). Il ne renvoie pas de message, ce qui évite les attaques où on force le serveur à envoyer des messages icmp à un autre serveur par exemple.
  • REJECT –reject-with icmp-port-unreachable renvoie un message icmp disant que le port est fermé (comme si le service qui écoute sur ce port n'était pas lancé et que le port était inutilisé).

Ordre des règles

Les règles sont appliquées dans l'ordre.

Donc il faut que les commandes d'ipset et fail2ban soient avant celles qui acceptent une connexion :

  1. On regarde si l'un de ces logiciels dit qu'il faut bloquer l'ip
    1. Si oui, elle dégage
    2. Si non, on passe à la règle suivante
  2. La règle suivante étant “on accepte”.

Sinon, ça serait :

  1. On accepte la connexion
  2. On regarde si fail2ban… ah ben non, forcément, ça ne marche pas, puisque la connexion est acceptée.

Ipset

Créer une entrée pour toutes les ip qui vont être renvoyées dans les limbes (adapter le nom blocklist_ip):

ipset create blocklist_ip hash:ip

Faire en sorte qu'iptables utilise cette liste d'ipset (appelée chaine) :

iptables -A INPUT -m set --match-set blocklist_ip src -j DROP

Et à présent pour alimenter la liste des ip définitivement bannies, ça sera ce genre de commande (remplacer $ip par l'ip) :

ipset add blocklist_ip $ip

Commandes ipset

Pour lister les ip et “chaînes” :

ipset list

Pour juste lister les chaînes :

ipset list -n

Pour enlever une des ip sur notre chaîne “bloclist_ip” :

ipset del blocklist_ip X.X.X.X

Rendre ça persistant au démarrage

C'est netfilter qui gère ça.

S'assurer que les règles iptable et ipset sont bonnes, et que netfilter-persistent est démarré et en mode “enable”

iptables -L -n -v
ipset list
systemctl status netfilter-persistent

Pour garder les ip bannies dans ipset, il faut aussi faire cette commande (à renouveler quand on ajoute des ip) :

ipset save

Sauver le tout :

netfilter-persistent save

Fail2ban

On crée un fichier dans /etc/fail2ban/jail.d/custom.conf qui va contenir nos règles.

Il faudra aussi les tester, regarder les logs d'erreurs, etc… parce que c'est assez facile de croire que Fail2ban fonctionne, alors que non, il a bugué sur un truc obscur et en réalité ne fait rien du tout.

Sur ssh : il ne faut pas indiquer ssh et sftp dans les ports, juste les numéros. Et ça va mieux. J'ai galéré un moment pour que ça marche, à cause de ça…

Le principe est simple : on regarde dans /etc/fail2ban/jail.conf les prisons disponibles et les diverses options, puis dans /etc/fail2ban/jail.d/custom.conf on ne copie que ce qu'on veut changer par rapport au fonctionnement par défaut, et en particulier les “jails” qu'on va activer.

Ça pourrait probablement s'optimiser en créant une jail sur mesure avec toutes les regexp utiles, en particulier sur apache ici. À ce stade, je fais confiance aux devs de Fail2ban pour que les filtres soient efficaces contre pas mal de choses. Mais l'examen des logs montre que c'est quand même perfectible.

Voici à quoi ressemble mon custom.conf actuellement, sur un serveur mail avec un bout de site apache.

[DEFAULT]
# Envoi un mail pour voir que ça marche...
destemail = monmail@mondomaine.org
sender = root
action = %(action_mwl)s
# Cette "action" envoie un courriel avec le détail de qui et pourquoi on bannit. C'est verbeux mais j'aime bien.

# Actions par défaut. Peut être surchargé dans les jails.
# Nombre de fois où une ip peut se planter 
maxRetry = 4
# Regarder les logs sur ce temps là pour voir à quel point les ip retentent le coup
# Pas besoin de mettre trop long, ça bouffe de la mémoire et on a autre chose pour virer 
# celles qui s'acharnent
findtime = 3h
# Durée du bannissement. 
bantime  = 3d
# Si on ban quelque part, c'est partout (en principe)
banaction = iptables-multiport

## Les services surveillés, dits "jail"
[sshd]
enabled = true
port = 22,226
bantime  = 10m

[apache-auth]
enabled = true
[apache-badbots]
enabled = true
[apache-noscript]
enabled = true
[apache-overflows]
enabled = true
[apache-nohome]
enabled = true
[apache-botsearch]
enabled = true
[apache-fakegooglebot]
enabled = true
[apache-modsecurity]
enabled = true
[apache-shellshock]
enabled = true

[dovecot]
enabled = true
port = pop3,pop3s,imap2,imaps,submission,465,sieve
#filter    = dovecot

[postfix]
enabled = true
port  = pop3,pop3s,imap2,imaps,submission,465,sieve
#filter = postfix

[sieve]
enabled = true

Ne pas oublier de redémarrer fail2ban ensuite.

fail2ban-server -t
systemctl restart fail2ban

Commandes fail2ban utilisées régulièrement

  • Liste des jails : fail2ban-client status
  • Statut d'une jail : fail2ban-client status <prison>
  • Vérifier la configuration avant de relancer : fail2ban-server -t
  • Bannir une ip en particulier : fail2ban-client set <prison> banip <adresse IP>
  • Et la débannir : fail2ban-client set <prison> unbanip <adresse IP>

Faire ses propres règles Fail2ban

Il y a quelques améliorations à faire concernant les filtres.

Rendre le filtre postfix par défaut plus agressif

Par défaut, la jail “postfix” va se baser sur le filtre dans /etc/fail2ban/filter.d/postfix.conf. Et, par défaut, celui-ci n'est pas trop vache, mais il peut le devenir.

Cherchez la ligne

mode = more

Et remplacer par

mode = aggressive

Et voilà, là, des messages comme “warning: non-SMTP command from …” seront détectés comme louches et bannis au bout du nombre de tentatives déclarés dans la jail “postfix” (ou la valeur par défaut si on n'a rien précisé).

Ajouter des regex et configurer une jail "aucune chance"

Malgré ça, j'ai encore quelques tentatives des plus douteuses, pas toujours repérées/bannies, et puis surtout, c'est tellement suspect qu'une seule tentative devrait suffire à bannir.

Voici un exemple de certaines lignes que je souhaite filtrer :

2023-10-09T22:48:16.607827+02:00 poste postfix/smtpd[6341]: improper command pipelining after CONNECT from unknown[192.241.223.63]: MGLNDD_109.190.202.194_25\n
2023-10-08T18:50:51.080640+02:00 poste postfix/smtpd[1963528]: NOQUEUE: reject: RCPT from unknown[87.120.84.203]: 504 5.5.2 <WIN-CLJ1B0GQ6JP>: Helo command rejected: need fully-qualified hostname; from=<spameri@tiscali.it> to=<spameri@tiscali.it> proto=ESMTP helo=<WIN-CLJ1B0GQ6JP>
2023-10-15T22:04:39.456433+02:00 poste postfix/submission/smtpd[749737]: connect from scanner-29.ch1.censys-scanner.com[167.248.133.189]
2023-07-28T09:19:04.783707+02:00 poste postfix/smtpd[608140]: warning: non-SMTP command from scan-15n.shadowserver.org[184.105.247.252]: GET / HTTP/1.1
  • Envoyer une commande foireuse ? Qui fait ça en dehors de ceux qui testent les fragilités d'une installation ?
  • Un hostname mal déclaré ? Sérieusement, c'est n'importe quoi.
  • Notez au passage que tout ce qui contient tiscali.it et censys est toujours bon à bloquer, c'est toujouuuurs des comportements douteux.
  • Une commande non SMTP ? Hey, t'as cru que c'était le web ?

On va donc se créer son propre filtre pour ces cochons, avec un sudo nano /etc/fail2ban/filter.d/XX_perso_postfix.conf1)

# Filtre perso alimenté par les détections de trucs vraiment louches.
[INCLUDES]
before = common.conf
[Definition]
failregex = ^.*\[<HOST>\].*tiscali.it.*
        ^.* NOQUEUE: reject: RCPT from unknown\[<HOST>\]: 504 5.5.2 .* Helo command rejected: need fully-qualified hostname; .*
        ^.*connect from .*censys.*\[<HOST>\]
ignoreregex =
[Init]
journalmatch = _SYSTEMD_UNIT=postfix.service

Notez que chaque ligne de la partie “failregex” correspond à une expression régulière différente. La partie importante est <HOST> qui correspond à l'ip à bannir ; il faut aussi commencer toute regex par ^ afin d'indiquer le début de ligne.

Par ailleurs il faut inclure common.conf au début… et indiquer les logs à checker dans la section Init.

On peut ensuite lancer cette commande pour voir si ça checke des correspondances :

sudo fail2ban-regex /var/log/mail.log /etc/fail2ban/filter.d/XX_perso_postfix.conf

Dans le résultat, on doit avoir quelque chose comme ça :

Failregex: 21 total
|-  #) [# of hits] regular expression
|   1) [9] ^.* improper command pipelining after CONNECT from unknown\[<HOST>\].*
|   2) [1] ^.*\[<HOST>\].*tiscali.it.*
|   3) [1] ^.* NOQUEUE: reject: RCPT from unknown\[<HOST>\]: 504 5.5.2 .* Helo command rejected: need fully-qualified hostname; .*
|   4) [10] ^.*connect from .*censys.*\[<HOST>\]
`-

Ici j'ai donc 9 correspondances sur la première expression, 1 pour chacune des deux suivants et 10 pour ce sale bot à la fin : c'est bon, ça scanne.

On ajoute ensuite la jail dans notre /etc/fail2ban/jail.d/custom.conf :

[XX_perso_postfix]
#mes propres bidouilles pour virer des chieurs bien repérés
enabled = true
port  = pop3,pop3s,imap2,imaps,submission,465,sieve
filter = XX_perso_postfix
maxretry = 1
findtime = 600
bantime = 30d
action   = iptables-ipset-proto4[name=blocklist_ip, protocol=tcp, bantime=0]
  • Le nom de la jail doit être celui du filtre, visiblement, sinon ben ça bugue.
  • Il va chercher tout seul le filtre dans /etc/fail2ban/filter.d et attends que ça se termine par conf, on ne met que le nom du fichier.
  • Les ports j'ai copié ce qui marchait avec la jail de base de postfix.
  • 1 tentative. Une seule. Limite je me demande pourquoi je déclare le findtime. Et ensuite 30 jours de bannissement !
  • l'action bannit avec ipset, mais là j'ai un peu des doutes sur ce que j'ai fait, ça va demander quelques essais.

Ensuite, on teste si on n'a pas fait de bêtise avec cette commande (ça évitera des agacements) :

sudo fail2ban-server -t

Tout marche ? alors, on charge :

sudo service fail2ban reload

Il faut améliorer les regexp (avec fail2ban-regex). pour virer plus large : - toute ip qui tente de se co en ssh avec un user qui n'est pas autorisé ⇒ ban définitif

Bannir définitivement les IP harcelantes

Lister les occurrences d'ip bannies

cat /var/log/fail2ban.lo* | grep -v "Restore" | grep "Ban" |awk '{print $6" "$8}'|sort|uniq -c|sort -nr | awk '{gsub(/^[ \t]+/,""); print$0}'
  • cat /var/log/fail2ban.lo* : va regarder tous les fichiers de log de fail2ban
  • grep -v “Restore” : exclure les moments où on restaure les ip (ça fout le dawa dans les résultats)
  • grep “Ban” : garder, dans ce qui reste, toutes les lignes où on bannit un truc
  • awk '{print $6" "$8}' : garder seulement la 6e et 7e partie (celle avec le nom du service et celle avec l'ip)
  • sort une fois pour que les ip identiques soient les unes à la suite des autres
  • uniq -c réunit les lignes communes et affiche devant le nombre de fois qu’elles apparaissent
  • un dernier sort (avec l’option reverse et l’option number) pour faire un tri inverse par nombre
  • awk '{gsub(/^[ \t]+/,""); print$0}' : compliqué à lire celui-ci. Il enlève les espaces au début, ce qui est utile pour se servir du truc dans un script par la suite.

Très beau, très simple, fonctionnel. Mais on va aller plus loin avec un petit cron qui lance de temps en temps une vérification et bannit définitivement les ip qui ont un peu trop essayé.

Script de bannissement définitif

J'ai mis ça dans /root/banip/ (dossier à créer donc).

mkdir /root/banip/
banip_auto.sh
#!/bin/bash
# Bannir automatiquement une liste d'ip qui ont abusé.
#fichier de log
folderbanip="/root/banip"
badiphuman="$folderbanip/badiphuman.txt"
todayiptable="$folderbanip/today_iptable.txt"
logban="$folderbanip/logban.log"
 
## Liste les ip gênantes, d'une façon lisible pour un humain 
# awk '{gsub(/^[ \t]+/,""); print$0}'  => enlève les espaces au début
cat /var/log/fail2ban.lo* | grep -v "Restore" | grep "Ban" |awk '{print $6" "$8}'|sort|uniq -c|sort -nr | awk '{gsub(/^[ \t]+/,""); print$0}' > $badiphuman
# sauvegarde les règles iptables et ipset actuelles pour comparer
iptables -L -n -v > $todayiptable
ipset list >> $todayiptable
 
# On alimente le fichier de log
echo "#####" >> $logban
date >> $logban
## Si l'ip est revenu plus d'un certain nombre de fois, alors on la sélectionne pour un ban définitif
# lire fichier $badiphuman 
cat $badiphuman | while IFS= read -r line; do
	tableau=(${line// /,})
	number=$(echo $tableau | cut -d ',' -f 1)
	ip=$(echo $tableau | cut -d ',' -f 3)
	#Si l'ip apparait 2 fois ou plus, on la bannit, sinon elle a sa chance
	if (($number >= 2))
		then
			# on va tester si on a déjà la règle
			if grep -q "$ip" $todayiptable
				then
				echo "IP address already blocked, skipping" >> $logban
				else
				ipset add blocklist_ip $ip
				echo "Blocking $ip because $number occurences" >> $logban
			fi
		else
			echo "$ip not blocking for the moment, only $number try" >> $logban
	fi
done
 
#Sauver les modifs
ipset save
netfilter-persistent save
#iptables-save >> /etc/iptables/rules.v4

Et maintenant un cron, une fois par jour, pour s'assurer qu'on bloque les plus méchants (et les moins futés, certes…)

crontab -e
30 0 * * * /root/banip/banip_auto.sh

Bannir des plages d'ip

Parfois des comportements malveillants viennent d'une plage d'ip et pas seulement d'une ip seule.

Il faut des alertes pour les repérer (ou si y'a moyen d'affiner les outils déjà présents, je ne sais pas encore comment). Et je suis contre le fait de bannir des pays entiers. D'autant que ça m'arrive d'avoir des échanges avec des gens dans un “mauvais” pays… Je peux comprendre qu'on utilise ça en cas de gros soucis mais tant que je peux m'en passer, je vais essayer de le faire.

La notation d'une plage d'ip est de la forme x.x.x.0/24. Enfin, les chiffres au bout varient parfois… Comment être sûr de son coup ?

Installer ipcalc. Puis demandez lui des détails sur une de ces adresses ip malveillantes :

% ipcalc 87.120.84.142
Address:   87.120.84.142        01010111.01111000.01010100. 10001110
Netmask:   255.255.255.0 = 24   11111111.11111111.11111111. 00000000
Wildcard:  0.0.0.255            00000000.00000000.00000000. 11111111
=>
Network:   87.120.84.0/24       01010111.01111000.01010100. 00000000
HostMin:   87.120.84.1          01010111.01111000.01010100. 00000001
HostMax:   87.120.84.254        01010111.01111000.01010100. 11111110
Broadcast: 87.120.84.255        01010111.01111000.01010100. 11111111
Hosts/Net: 254                   Class A

Network nous indique toute la plage associée, qui va de HostMin à HostMax. Vérifions…

% ipcalc 87.120.84.0/24
Address:   87.120.84.0          01010111.01111000.01010100. 00000000
Netmask:   255.255.255.0 = 24   11111111.11111111.11111111. 00000000
Wildcard:  0.0.0.255            00000000.00000000.00000000. 11111111
=>
Network:   87.120.84.0/24       01010111.01111000.01010100. 00000000
HostMin:   87.120.84.1          01010111.01111000.01010100. 00000001
HostMax:   87.120.84.254        01010111.01111000.01010100. 11111110
Broadcast: 87.120.84.255        01010111.01111000.01010100. 11111111
Hosts/Net: 254                   Class A

Ici 0/24 semble marcher. Hop, on ajoute ça dans le ban…

ipset add blocklist_ip 87.120.84.0/24

et ipset list va nous montrer les 254 nouvelles adresses bloquées… Pfiou !

D'où viennent les attaques ?

Là c'est de la curiosité car je ne pense pas que je puisse y faire grand chose. Mais, quand même, ça permet de voir la pertinence (ou pas) de bloquer un pays.

En premier, récupérer les logs montrant une “authentification failed”. Vu le nombre de personnes ayant accès à mon serveur, c'est *toujours* des attaques.

grep "authentication failed" /var/log/mail.log > /var/vmail/viewmail.log

Ensuite je me suis envoyée ce fichier via Mutt parce que ce n'était pas très pratique à distance, je l'ai nettoyé avec diverses bidouilles pour n'avoir que les ips et en un exemplaire (sort|uniq). Ça mériterais que je note la manip un jour… peut-être !

Et après, j'ai mouliné ce fichier appelé “badip.txt” avec ce petit script :

#!/bin/bash
# Savoir d'où vienne les méchantes ip
cat badip.txt | while IFS= read -r line; do
	tableau=(${line// /,})
	geo=$(geoiplookup $tableau)
	echo $geo >> country.txt
	cat country.txt | sort|uniq -c | sort > finalbadip.txt
done

Ce qui donne lors de ce test, 90 tentatives d'intrusion sur une seule journée, dont 33 en provenance de Chine et le reste réparti dans divers pays, de l'Australie aux USA en passant par l'Italie ou l'Allemagne.

Si je ne me vois pas bloquer ces pays (même la Chine), je me demande s'il y a moyen de filtrer quel pays a le droit de tester certaines actions, comme se connecter à un compte mail.

Une alternative via systemd

Pour les IPs qui ont le plus chercher à se connecter au serveur mail sans succès, pour une journée donnée :

journalctl --since=2023-10-06 --until=2023-10-07 --grep='SASL LOGIN authentication failed' --unit=postfix@-.service | sed 's/.*warning: \([^ ]*\): .*$/\1/' | sort | uniq --count | sort --human-numeric-sort --reverse | head

Et juste pour le jour même :

journalctl --since=today --grep='SASL LOGIN authentication failed' --unit=postfix@-.service | sed 's/.*warning: \([^ ]*\): .*$/\1/' | sort | uniq --count | sort --human-numeric-sort --reverse | head

Sources

1)
Vous l'appelez comme vous voulez, mais perso j'aime retrouver d'un coup d'œil ce que j'ai bidouillé et le préfixe XX marche bien, et ensuite il faut donner le même nom à la jail pour éviter les soucis.
CC Attribution-Noncommercial-Share Alike 4.0 International Driven by DokuWiki
pratique/informatique/fail2ban.txt · Dernière modification : 23/01/2024 11:48 de Zatalyz