J'ai lu L'histoire d'une attaque suspecte du monde entier dès que j'ai ouvert un blog sur mon propre serveur et vérifié le journal de mon serveur. Il a été confirmé que l'accès qui semble être le même objectif de craquage allait arriver.
Parmi eux, il y avait beaucoup d'attaques sur lesquelles je m'appuyais sans deviner le nom d'utilisateur et le mot de passe de phpMyAdmin, j'ai donc compté le nombre d'attaques contre eux et les ai classés.
J'ai obtenu le journal (/ var / log / httpd / access_log) du serveur HTTP Apache du serveur (CentOS 6.10) sous contrat avec Sakura VPS. Si vous regardez le contenu, vous pouvez voir que l'accès est tenté avec un nom d'utilisateur et un mot de passe qui ne s'appliquent pas à phpMyAdmin comme indiqué ci-dessous.
xxx.xxx.xxx.xxx - - [04/Oct/2018:02:57:44 +0900] "GET /phpMyAdmin/index.php?pma_username=root&pma_password=1qaz3edc5tgb&server=1 HTTP/1.1" 200 14538 "-" "Mozilla/5.0"
xxx.xxx.xxx.xxx - - [04/Oct/2018:02:57:46 +0900] "GET /phpMyAdmin/index.php?pma_username=root&pma_password=1qaz@123&server=1 HTTP/1.1" 200 14546 "-" "Mozilla/5.0"
xxx.xxx.xxx.xxx - - [04/Oct/2018:02:57:59 +0900] "GET /phpMyAdmin/index.php?pma_username=root&pma_password=1qaz@2wsx&server=1 HTTP/1.1" 200 14533 "-" "Mozilla/5.0"
xxx.xxx.xxx.xxx - - [04/Oct/2018:02:58:03 +0900] "GET /phpMyAdmin/index.php?pma_username=root&pma_password=1qaz@WSX&server=1 HTTP/1.1" 200 14543 "-" "Mozilla/5.0"
xxx.xxx.xxx.xxx - - [04/Oct/2018:02:58:06 +0900] "GET /phpMyAdmin/index.php?pma_username=root&pma_password=1qaz@WSX3edc&server=1 HTTP/1.1" 200 14538 "-" "Mozilla/5.0"
xxx.xxx.xxx.xxx - - [04/Oct/2018:02:58:09 +0900] "GET /phpMyAdmin/index.php?pma_username=root&pma_password=1qaz@wsx&server=1 HTTP/1.1" 200 14533 "-" "Mozilla/5.0"
J'ai extrait ces informations en utilisant python et créé des informations d'histogramme. Le code python est répertorié en annexe à la fin.
Période d'acquisition: du 26/09/2018 au 22/01/2020 Nombre total de lignes: 658858 lignes Parmi ceux-ci, ce qui semble être une attaque qui semble reposer sur le mot de passe de phpMyAdmin: ligne 186499
Classement | Nom d'utilisateur | Nombre de fois |
---|---|---|
1 | root | 185504 |
2 | wordpress | 183 |
3 | admin | 138 |
4 | wp | 47 |
5 | blog | 45 |
6 | pma | 45 |
7 | shop | 43 |
8 | money | 42 |
9 | popa3d | 40 |
10 | joomla | 39 |
11 | http | 35 |
12 | ueer | 35 |
13 | project | 35 |
14 | nginx | 33 |
15 | apache | 33 |
16 | sql | 33 |
17 | db | 32 |
18 | nas | 32 |
19 | shopdb | 31 |
20 | dbs | 31 |
21 | web | 28 |
22 | backupdb | 6 |
23 | wordspress | 5 |
24 | backup | 2 |
25 | backups | 2 |
Classement | mot de passe | Nombre de fois |
---|---|---|
1 | pass | 408 |
2 | password | 372 |
3 | 361 | |
4 | admin | 359 |
5 | 123 | 347 |
6 | root | 344 |
7 | 123456 | 326 |
8 | welcome | 323 |
9 | r00t | 322 |
10 | monkey | 322 |
11 | whatever | 322 |
12 | abc123 | 321 |
13 | aa123456 | 321 |
14 | 123123 | 319 |
15 | mysql | 318 |
16 | login | 318 |
17 | 111111 | 318 |
18 | password123 | 318 |
19 | 1234567890 | 317 |
20 | access | 317 |
21 | 666666 | 316 |
22 | apache | 315 |
23 | oracle | 315 |
24 | 654321 | 315 |
25 | root123 | 315 |
26 | 123qwe | 314 |
27 | 1234567 | 314 |
28 | 12345678 | 314 |
29 | pass123 | 314 |
30 | letmein | 313 |
Classement | chemin | Nombre de fois |
---|---|---|
1 | /phpmyadmin/index.php | 173687 |
2 | /phpMyAdmin/index.php | 12812 |
Tous les classements seront placés à ici.
L'écrasante majorité des noms d'utilisateur sont root, et d'autres termes liés aux blogs tels que wordpress et blog, les termes liés aux bases de données tels que admin et pma, et les termes liés au serveur tels que apache semblent être alignés. Par rapport à Article analysant le journal des attaques sur le serveur ssh, l'attaque sur ssh cible le nom de la personne et le nom du système d'exploitation, tandis que phpMyAdmin Il est intéressant de noter qu'il existe des différences subtiles dans les tendances, telles que les termes liés aux blogs ciblés dans les attaques contre.
Les trois principaux mots de passe étaient «pass», «password» et «» (aucun). Il n'y en avait pas beaucoup de proéminents, et il semblait que les choses qui avaient tendance à être visées étaient également ciblées. Il semble correspondre à la tendance du "pire mot de passe" comme indiqué dans ici. Les modèles étaient les suivants.
En outre, les chemins qui ont été les cibles de l'attaque ont également été tabulés. Seuls les deux types suivants ont été ciblés pour l'attaque.
Liste d'accès cible pour empêcher tout accès non autorisé Ou À propos des URL faciles à cibler La raison pour laquelle il y a peu de variations par rapport au chemin mentionné dans l'article est probablement parce que cette fois est le résultat après extraction de la ligne à la condition que "pma_password =" soit inclus. Quand j'ai effectivement regardé le journal avec la condition d'extraction définie sur "contient" phpMyAdmin "", j'ai trouvé que l'accès à des chemins autres que les deux types listés cette fois-ci était également tenté.
J'ai peu de connaissances en sécurité, donc je ne sais pas comment la sécuriser, mais au moins j'ai décidé de cesser d'utiliser le nom d'utilisateur et le mot de passe qui se trouvent souvent dans les bases de données dans le chemin par défaut.
C'est tout pour le texte. Merci pour la lecture. Ce qui suit est une annexe.
Code Python pour extraire les informations requises du journal. Cette fois, les lignes suivantes ont été analysées.
xxx.xxx.xxx.xxx - - [04/Oct/2018:02:58:03 +0900] "GET /phpMyAdmin/index.php?pma_username=root&pma_password=1qaz@WSX&server=1 HTTP/1.1" 200 14543 "-" "Mozilla/5.0"
Si "pma_password =" est inclus, il est considéré comme analysé. Les informations sont extraites d'ici en les divisant par des espaces, des caractères spécifiques ou des mots-clés. Voici un exemple d'informations et comment les récupérer. Cela peut différer en fonction des paramètres d'exportation du fichier journal, veuillez donc le corriger en conséquence.
information | Comment sortir |
---|---|
adresse IP | 0e divisé par l'espace |
Horodatage | "["Quand"]"Chaîne de caractères incluse dans |
Method (GET,POST etc.) | 6e divisé par l'espace. Cependant, comme le premier caractère est une double citation, supprimez-le |
chemin phpMyAdmin | À partir du 7e élément divisé par l'espace"?"Jusqu'à juste avant |
Nom d'utilisateur | "pma_username="Quand"&"Chaîne entre |
mot de passe | "pma_password="Quand"&"の間の文字列。(ただしこの部分のqueryでurlが終了している場合があり、そのQuandきは後ろの"&"が存在しないため、スペースの直前までQuandする) |
Toutes les lignes ne peuvent pas être extraites de cette façon, mais je l'ignore car je pense que certaines exceptions auront peu d'effet. Ce domaine est approprié. Après avoir récupéré l'élément, comptez le nombre de fois des informations d'intérêt (cette fois, chemin phpMyAdmin, nom d'utilisateur, mot de passe). Enfin, il est trié par ordre décroissant et affiché dans la sortie standard.
L'ensemble du code source ressemble à ce qui suit.
from collections import defaultdict
with open('/path/to/access_log','r') as f:
logs = f.readlines()
#Extraction d'attaques sur phpMyAdmin
pma_attacks = [log for log in logs if 'pma_password' in log]
#ip, time_stamp, method, path, username,Extraire le mot de passe
#Réécrire selon le cas selon le format du journal
extracted_pma_infos = []
for pma in pma_attacks:
#l'adresse IP est le 0ème élément séparé par des espaces
ip = pma.split(' ')[0]
#L'horodatage est"["De"]"Chaîne de caractères jusqu'à
time_stamp = pma.split('[')[1].split(']')[0]
#La méthode (POST, GET, etc.) est le sixième élément séparé par des espaces avec le premier caractère supprimé.
method = pma.split(' ')[5][1:]
#path est le sixième élément séparé par des espaces"?"Chaîne de caractères jusqu'à juste avant
path = pma.split(' ')[6].split('?')[0]
#Le nom d'utilisateur est"pma_username="Le plus récent"?"Chaîne de caractères jusqu'à
username = pma.split('pma_username=')[1].split('&')[0]
#Le mot de passe est"pma_password="Le plus récent"?"Chaîne de caractères jusqu'à
password = pma.split('pma_password=')[1].split('&')[0]
#Gestion des exceptions lorsque le mot de passe est la dernière requête
#En ce moment, le dernier"?"N'existe pas et est inclus jusqu'à la fin du journal, donc cela peut être fait juste avant l'espace
if ' ' in password:
password = password.split(' ')[0]
extracted_pma_infos.append([ip,time_stamp,method,path,username,password])
#Créez un histogramme des chemins, noms d'utilisateur et mots de passe attaqués
pathlist = defaultdict(int)
unlist = defaultdict(int)
pslist = defaultdict(int)
for pma in extracted_pma_infos:
path = pma[3]
un = pma[4]
ps = pma[5]
pathlist[path]+=1
unlist[un]+=1
pslist[ps]+=1
#Données d'histogramme d'argument(dict_obj)Une fonction qui analyse et crée une liste décroissante
def orderedlistFromDict(dict_obj):
count = list(set([dict_obj[v] for v in dict_obj]))
count.sort()
orderedlist = []
for c in count[::-1]:
for key in dict_obj:
if dict_obj[key] == c:
orderedlist.append((key,dict_obj[key]))
return orderedlist
#Liste des chemins, noms d'utilisateur et mots de passe attaqués
ordered_path = orderedlistFromDict(drlist)
ordered_un = orderedlistFromDict(unlist)
ordered_ps = orderedlistFromDict(pslist)
#Voir le classement des passes
for val in ordered_path:
print(val[0],val[1],sep=',')
#Afficher le classement des noms d'utilisateur
for val in ordered_un:
print(val[0],val[1],sep=',')
#Afficher le classement des mots de passe
for val in ordered_ps:
print(val[0],val[1],sep=',')
Recommended Posts