記服務器資料庫被攻擊后修復經驗
前言
大概在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千次的登陸失敗

查閱過大量的資料之后,還可以發現Linux系列的系統都有兩個命令,
last 和 lastb
這里進行分別講解last和lastb命令,
LAST命令
執行last命令后,系統會從/var/log/wtmp處讀取登錄成功資訊,如下,是執行結果:

還有更多的引數請自行查找資料,筆者這里不再過多贅述,
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是一個很好用的,限制錯誤登錄次數的程式,能在極大程度上保護服務器的安全,
具體安裝使用方法,請戳這里
結語
刪庫,被勒索這種事情絕對不是個案,在開發程序中留下的每一句代碼都有可能最終導致嚴重的結果,所以在開發時一定不要為了圖方便,以免最后釀成不可挽回的后果的時候才追悔莫及,資料庫也可以通程序式定時備份,以及時止損,
只有防患于未然的網路安全意識提高了,才能真正地減少這類事件的發生
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/228105.html
標籤:其他
