[LINUX] J'ai essayé de classer le nom d'utilisateur et le mot de passe de phpMyAdmin ciblés par l'attaque du serveur

Aperçu

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.

une analyse

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.

Informations de base du journal à analyser

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

Nombre d'attaques par nom d'utilisateur (25 types au total)

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

Nombre d'attaques par mot de passe (top 30 des 953 types)

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

(À propos) Les passes attaquées et le nombre de fois (2 types au total)

Classement chemin Nombre de fois
1 /phpmyadmin/index.php 173687
2 /phpMyAdmin/index.php 12812

Considération

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é.

en conclusion

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.

appendice

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

J'ai essayé de classer le nom d'utilisateur et le mot de passe de phpMyAdmin ciblés par l'attaque du serveur
J'ai essayé le serveur asynchrone de Django 3.0
J'ai essayé de vérifier et d'analyser l'accélération de Python par Cython
J'ai essayé de noter la syntaxe trop humoristique et humoristique en utilisant l'API COTOHA.
J'ai affiché le chat de YouTube Live et essayé de jouer
J'ai essayé de créer un script qui retrace les tweets d'un utilisateur spécifique sur Twitter et enregistre l'image publiée à la fois
J'ai refactoré "J'ai essayé de faire un script qui enregistre les images postées à la fois en retournant sur les tweets d'un utilisateur spécifique sur Twitter".
J'ai essayé de déplacer l'image vers le dossier spécifié en faisant un clic droit et un clic gauche
J'ai essayé de visualiser la tranche d'âge et la distribution des taux d'Atcoder
Le nom du fichier était mauvais en Python et j'étais accro à l'importation
J'ai essayé de trouver l'itinéraire optimal du pays des rêves par recuit (quantique)
J'ai essayé d'extraire et d'illustrer l'étape de l'histoire à l'aide de COTOHA
J'ai vérifié le nombre de magasins fermés et ouverts dans tout le pays par Corona
J'ai essayé de vérifier le résultat du test A / B avec le test du chi carré
L'arbre.plot_tree de scikit-learn était très simple et pratique, j'ai donc essayé de résumer comment l'utiliser facilement.
J'ai essayé de réveiller le nom de lieu qui apparaît dans les paroles de Masashi Sada sur la carte thermique
Ceci et celui de la notation d'inclusion.
J'ai essayé de notifier la mise à jour de "Hameln" en utilisant "Beautiful Soup" et "IFTTT"
Parlez des fonctionnalités dont les pandas et moi étions en charge dans le projet
J'ai essayé de prédire la présence ou l'absence de neige par apprentissage automatique.
J'ai essayé de récupérer les données de l'ordinateur portable en le démarrant sur Ubuntu
J'ai essayé de passer le test G et la qualification E en m'entraînant à partir de 50