java 过滤 非utf8_java_security_calendar_2019(day5day8)

简介

java_security_calendar_2019第5天-第8天的部份。分别为Dos(StringBuilder)、Dos(readAllBytes)、权限提升、未授权下载。

Day5

示例代码:

import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;

public class Request {
  public static String toString(HttpServletRequest req) {
    StringBuilder sb = new StringBuilder();
    String delimiter = req.getParameter("delim");
    Enumeration names = req.getParameterNames();while (names.hasMoreElements()) {
      String name = names.nextElement();if (!name.equals("delim")) {
        sb.append("" + name + ":
");
        String[] values = req.getParameterValues(name);for (String val : values) {
          sb.append(val);
          sb.append(delimiter);
          sb.append("
");
        }
      }
    }return sb.toString();
  }
}

看了半天也没发现哪里有问题,看了下提示,这个题是StringBuilder()引发的dos,大致原因是java.util.StringBuilder中,StringBuilder对象使用大小为16的数组初始化。每次附加新值时,StringBuilder实例都会检查数据是否适合该数组。如果不合适,则数组的大小加倍。而默认情况下,Apache Tomcat的POST请求限制为2MB,最大参数为10000。将传入的delim值结合数组和多个(例如10000个)HTTP参数提交非常大的参数值(例如1.8 MB),便会引起dos攻击。
了解了漏洞原因再看这段代码就比较容易了,方法toString将收到的所有参数,进行遍历,转化为html格式。直接写个脚本,注意先不要把参数写那么大,,,要不可能执行脚本的时候卡掉。。。慢慢的值改上去。

python写个脚本:

headers = {}
headers['User-Agent'] = 'Mozilla/5.0 ' \
                          '(Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 ' \
                          '(KHTML, like Gecko) Version/5.1 Safari/534.50'
url="http://localhost:8888/day5/Request"
delim = ""
data="delim=test"+delim
content=""

# 参数值的大小
for i in range(1,36000):
    content=content+"test"
# 参数的多少
for i in range(1,500):
    data=data+"&delim{index}=".format(index=i)+content
# print(data)

res=requests.post(url,headers=headers,data=data)
print(res.status_code)

当参数的值一调大以后,python脚本就报这个问题,google查了半天,发现在requests库下也有好多人提交了这个问题,也没找到合适的解决方案,不过思路应该没错。

requests.exceptions.ConnectionError: ('Connection aborted.', BrokenPipeError(32, 'Broken pipe'))

Day6

示例代码:

import java.io.*;
import java.nio.file.*;
import javax.servlet.http.*;

public class ReadFile extends HttpServlet {
  protected void doPost(HttpServletRequest request,HttpServletResponse response) throws IOException {
    try {
      String url = request.getParameter("url");
      String data = new String(Files.readAllBytes(Paths.get(url)));
    } catch (IOException e) {
      PrintWriter out = response.getWriter();
      out.print("File not found");
      out.flush();
    }
    //proceed with code
  }
}

刚开始以为是个文件遍历,仔细一看,没有对文件进行显示,返回“文件未找到”。

6ff7791d3f418ae4e50cf8e6817e40e8.png

原来又是一个dos。。。传入/dev/urandom,此时url对传入的值未进行任何过滤,通过Files.readAllBytes方法读取/dev/urandom下的字节,引起dos

098f22c5e42d0d80f03d2ebe548e4582.png

Day7

示例代码:

import com.fasterxml.jackson.core.*;
import javax.servlet.http.*;
import java.io.*;

public class ApiCache extends HttpServlet {
  protected void doPost(HttpServletRequest request,HttpServletResponse response) throws IOException {
    storeJson(request, "/tmp/getUserInformation.json");
  }

  protected void doGet(HttpServletRequest request,HttpServletResponse response) {
    loadJson();
  }

  public static void loadJson() {
      // Deserialize to an HashMap object with Jackson's JsonParser and read the first 2 entries of the file.
  }

  public static void storeJson(HttpServletRequest request, String filename) throws IOException {
    JsonFactory jsonobject = new JsonFactory();
    JsonGenerator jGenerator = jfactory.createGenerator(new File(filename), JsonEncoding.UTF8);
    jGenerator.writeStartObject();
    jGenerator.writeFieldName("username");
    jGenerator.writeRawValue("\"" + request.getParameter("username") + "\"");
    jGenerator.writeFieldName("permission");
    jGenerator.writeRawValue("\"none\"");
    jGenerator.writeEndObject();
    jGenerator.close();
  }
}

大致流程为用户传入username的值,写入到/tmp/getUserInformation.json中,然后读取该文件,进行解析。 流程很简单,肯定先关注用户输入地方,对username传入的数据未做清洗,导致可传入其他参数进行污染,在该功能下可导致权限提升。
先正常请求,返回如下:

6d86c17aa588066324fc568bdd69d74c.png

此时json文件为:

{
"username":"111111111",
"permission":"none
}

构造恶意请求,

username=111111111","permission":"all

可看到用户传入username的值已正确解析成username=111111111","permission":"all

51847309f3d04053aa0cf46e465d35f2.png

此时json文件为:

"username":"111111111"
"permission":"all"
"permission":"none"

注:若要成功利用此问题,该方法loadJson()必须仅反序列化每个键的第一次出现,以便忽略重复的键。

Day8

示例代码:

import java.io.File;
import java.io.IOException;
import javax.servlet.http.*;

public class GetPath extends HttpServlet {
    protected void doGet(HttpServletRequest request,HttpServletResponse response) throws IOException {
        try {
            String icons = request.getParameter("icons");
            String filename = request.getParameter("filename");

            File f_icons = new File(icons);
            File f_filename = new File(filename);

            if (!icons.equals(f_icons.getName())) {
                throw new Exception("File not within target directory!");
            }

            if (!filename.equals(f_filename.getName())) {
                throw new Exception("File not within target directory!");
            }

            String toDir = "/var/myapp/data/" + f_icons.getName() + "/";
            File file = new File(toDir, filename);

            // Download file...
        } catch(Exception e) {
            response.sendRedirect("/");
        }
    }
}

看到两个输入点,iconsfilename均未做任何过滤,用户传入数这两个参数后,对其名字做判断,其中判断使用的是getName()方法,该方法仅能做简单../的过滤,如/../../../../hack.txt转成hack.txt。然后执行到关键代码String toDir = "/var/myapp/data/" + f_icons.getName() + "/";,发现toDir的值为/var/myapp/data/f_icons.getName()拼接而成。此时通过../的形式对传入的值做控制,从而实现可以访问/var/myapp/目录下任意文件。

稍微修改代码,让程序跑起来。执行恶意payload,

8de253a0f6c2e3f5a7d8a18ff061e76d.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值