记服务器数据库被攻击后修复经验

3 篇文章 0 订阅
1 篇文章 0 订阅

记服务器数据库被攻击后修复经验

前言

大概在11月初的时候,在腾讯云上租了一台轻量级应用服务器。当时是以学生价格入手的,非常便宜,性价比也非常高。当时还加了一点钱租了一个.design的域名,感觉非常划算。
之后就是部署项目的过程了,整个过程还算顺利。
如果大家想看javaweb项目上线过程请在我的个人博客中找,因为可能发布时间会在这篇文章之后。
上线之后,运行了几天,感觉还不错。访问速度很快,一切功能都正常,直到…

问题初现

项目是11月13日上线的,之后几天因为上学的缘故就没有管。直到11月18日打开网站,发现有一个留言板的功能无法正常使用。Ajax向后台发送数据得不到相应,笔者当时就有一种不好的预感。虽然网站没有什么东西,而且笔者早就知道这种安全级别肯定会被黑,但是心中不免还是为之一震,只得感叹“欢迎来到互联网”

果然,查询了后台log4j留下的日志,才发现数据库无法访问。当时觉得可能是数据库被删除了,不过数据库里面也没有什么重要的信息,而且也有快照备份,问题不大。

随后,笔者又尝试登陆了mysql的数据,发现黑客还留下一张新建的表。并且之前的业务数据库都被删除。
勒索数据信息
留下的线索是一张名字为WARNING的数据表,其中还有比特币的地址,还”贴心“地附上了联系邮箱。

那么下面就开始我们的分析过程吧!!!

邮箱查询

攻击者在数据库中留下了联系方式,那我们不妨就从联系方式下手。
通过攻击者留下的邮箱,我们可以尝试访问一下protonmail.com。

光是看这个网站就不难发现,这是一家在瑞士的安全邮件公司,也就是说邮件的信息完全是匿名的。
而且可以通过whois查询这个域名,也得不到任何有实际作用的信息。

数据库日志分析

经学习得知,Mysql数据库会自动记录数据库创建的时间,我们可以从那里找到一些线索。

查询所有表的创建时间
SELECT table_name,create_time FROM  information_schema.TABLES;
查询指定表的创建时间
SELECT table_name,create_time FROM information_schema.TABLES WHERE table_name = '表名';

最后返回的执行结果:
数据库创建时间
可以看到,WARING表是在2020年的11月17日的凌晨4时35分02秒被创建出来的,这非常像一个黑客出来整活的时间。同时,这也就印证了为什么网站在11月18日的时候无法读取数据库。

所以,可以初步确定,攻击事件是发生在11月17日凌晨4点左右。

Centos系统日志

在登陆ssh的时候会发现有上一次登陆失败的记录信息,可以看到后台肯定是遭遇到了暴力破解。

因为ssh已经存在过3万5千次的登陆失败
3万5千次的登陆失败
查阅过大量的资料之后,还可以发现Linux系列的系统都有两个命令。

last 和 lastb

这里进行分别讲解last和lastb命令。

LAST命令

执行last命令后,系统会从/var/log/wtmp处读取登录成功信息。如下,是执行结果:

last执行结果
还有更多的参数请自行查找资料,笔者这里不再过多赘述。
PS:遮挡信息为ip地址。

LASTB命令

执行lastb命令之后,系统会去读取/var/log/btmp,并且显示出所有登录失败的信息。
下图为执行结果:
因为实在是数量庞大,故只寻找11月17日凌晨四点左右的登录信息。
登陆失败信息
可以看到,其实系统的root密码已经被暴力破解了上百万次,但是在11月17日并未有成功登陆的信息,所以笔者可以得出第二个结论。
攻击者并未拿到系统管理权限,而是从前端页面下手,进行删除数据库操作的

因为网站的3306端口是常闭的,所以攻击者无法远程连接数据库。进而可以初步猜测,攻击手法为sql注入

安全分析

首先,因为本来网站体量就比较小,一共涉及到数据库操作的就只有两个功能,一个是留言板,另外一个则是云盘。

漏洞一:Fliter的错误设置

一开始笔者把测试重点放在了对于留言板功能的测试上。因为,留言板有一个限制较少的文本域,黑客很容易就从那里下手。
但是仔细想想,我在所有页面之上都部署了一个fliter用来过滤没有登陆的用户,并且将他们跳转到登录页面。而且登陆页面的密码也几乎不可能被暴力破解,所以黑客要进入站内一定是绕过去了。

仔细检查源码才发现,fliter只过滤了前端页面,但是并未过滤servlet,导致黑客可以直接通过猜测就得出servlet的名字,并且访问servlet。
但是Servlet的提交方法都是post,难不成黑客构建了post数据包去尝试sql注入?

漏洞二:BaseServlet

然而,因为整个网站的架构是基于Servlet反射来简化代码的,有一个BaseServlet类来拦截所有的Servlet请求,并且根据method参数来调用对应的方法,完成功能。
具体代码如下

public class BaseServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		doPost(req, res);
	}

	//调用对应方法
	protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		//Get parameter named method
		String md = req.getParameter("method");
		//Get class object by binary code
		Class clazz = this.getClass();
		//path after method's invoking 
		String path = null;
		
		try{
			Method method = clazz.getMethod(md, HttpServletRequest.class, HttpServletResponse.class);
			method.setAccessible(true);
			if(method!=null){
				method.invoke(this, req, res);
			}
		}catch (Exception e) {
			// 异常处理
		}
	}
}

然而,漏洞就发生在doGet方法中,doGet中直接转发给doPost(),间接导致了程序可以以get方式来请求和post一样的资源。所以也就印证了为什么黑客可以通过sql注入进行攻击。

攻击者只需要通过对前端页面的分析或者暴力破解Servlet的URL加上Get参数就可以对网站实现sql注入。并且可以轻易地绕过前端的验证。

那么,目前的任务就变成了找到网站中暗藏的sql注入点。

漏洞三: 拼接数据库查询语句

对于留言板的数据库操作都是用value方式实现的,类似于这样(事先构造PrepareStatement)

INSERT INTO XX.XX (Content,Timestamp) VALUES(?,?)

然后再插入?的数据。完整代码如下。

public static void addMessage(Message message) {

		PreparedStatement ps = null;
		try {
			String sql = "INSERT INTO XX.XX (Content,Timestamp) VALUES(?,?)";
			ps = JDBCUtil.getConnection().prepareStatement(sql);
			ps.setObject(1, message.getContent());
			ps.setObject(2, message.getTimestamp());

			ps.execute();
			ps.close();

		} catch (SQLException e) {
			//异常处理
		}

	}

这是一种非常安全的写法,这种写法非常不容易被SQL注入。

然而,我在检查云盘的数据库逻辑代码的时候,发现了当时为了偷懒而写下的数据库拼接语句。

ResultSet rs = JDBCUtil.getConnection().createStatement()
					.executeQuery("SELECT * FROM XX.XX WHERE code=\'" + code + "\';");

当时看到这句就知道,问题一定出在这里。

漏洞再现

在前端找到了这个页面,并且利用第一个漏洞直接访问Servlet,果然访问成功,没有要求输入密码进行验证。
用Get的方式提交参数,并且在code的参数里面写下万能sql注入语句:

’ or ‘1’ '=1

果然,后台豪不迟疑地就反馈出了数据。
之后,就可以很轻易地爆出表名,然后执行DROP了。
当然,最后再新建一个表并且留下勒索信息也是再简单不过了。

解决方案

关于sql注入的封堵

1.首先用当时储存的服务器快照还原服务器(包括数据库)。
2.改写代码,去掉BaseServlet中doGet()方法中的转发。
3.将以下代码改成prepareStatment的写法。

ResultSet rs = JDBCUtil.getConnection().createStatement()
					.executeQuery("SELECT * FROM XX.XX WHERE code=\'" + code + "\';");

4.增加Filter过滤范围。
5.在收到参数的时候添加正则表达式过滤,这里有一个比较好用的防止sql注入的正则表达式。

典型的SQL 注入攻击的正则表达式:/\w*((%27)|(\’))((%6F)|o|(%4F))((%72)|r|(%52))/ix

防止ssh被暴力破解

1.设置较强的密码。
2.修改22端口为其他端口。
3.安装并且配置fail2ban。
fail2ban是一个很好用的,限制错误登录次数的程序,能在极大程度上保护服务器的安全。
具体安装使用方法,请戳这里

结语

删库,被勒索这种事情绝对不是个案。在开发过程中留下的每一句代码都有可能最终导致严重的结果。所以在开发时一定不要为了图方便,以免最后酿成不可挽回的后果的时候才追悔莫及。数据库也可以通过程序定时备份,以及时止损。
只有防患于未然的网络安全意识提高了,才能真正地减少这类事件的发生

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值