Java SQL Inject/XSS/SSRF

Posted by sufian on Thu, 27 Jan 2022 02:38:09 +0100

Java SQL Inject

JDBC SQL Inject

If the JDBC native query is not precompiled but directly spliced with SQL statements, then the filtering is not strict, which will cause SQL injection problems. For example, the following code is a Demo with SQL injection vulnerabilities

Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/security?characterEncoding=utf8&useSSL=false&serverTimezone=UTC", "root", "123456");
String sql = "select * from users where id = '"+id+"'";
resp.getWriter().write("The SQL statement:" + sql + "\n");
Statement statement = conn.createStatement();
ResultSet resultSet = statement.executeQuery(sql);

Precompiled repair

Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/security?characterEncoding=utf8&useSSL=false&serverTimezone=UTC", "root", "123456");
String sql = "select * from users where id = ?";
PreparedStatement preparedStatement = conn.prepareStatement(sql);
preparedStatement.setString(1,id);
ResultSet resultSet = preparedStatement.executeQuery();

Mybatis SQL Inject

There are also two methods for Mybatis to execute SQL statements: precompile and direct splicing. If SQL statements are directly spliced and the filtering is not strict, SQL injection problems will occur. For example, the following query statement uses ${} direct splicing value

<select id="selectUserByName" resultType="com.mybatis.pojo.User">
    SELECT * FROM Users WHERE username = '${username}'
</select>

Using #{} for precompiling can effectively prevent SQL injection problems

<select id="selectUserByName" resultType="com.mybatis.pojo.User">
    SELECT * FROM Users WHERE username = '#{username}'
</select>

LIKE Query

For the Like query, the program will throw an exception if it is directly precompiled

<select id="selectUserByLikeName" resultType="com.mybatis.pojo.User">
    SELECT * FROM Users WHERE username like '%#{username}#'
</select>

If developers change to direct value in order to prevent error reporting and do not have enough filtering, SQL injection problems will occur

<select id="selectUserByLikeName" resultType="com.mybatis.pojo.User">
    SELECT * FROM Users WHERE username like '%${username}%'
</select>

Direct precompiling will report errors, so concat connection precompiling is used, which will not throw exceptions and prevent SQL injection

<select id="selectUserByLikeNameRepair" resultType="com.mybatis.pojo.User">
    SELECT * FROM Users WHERE username like concat('%',#{username},'%')
</select>

IN/ORDER BY Query

Similarly, the direct precompiling of IN/ORDER BY query will also cause the program to throw exceptions. If the developer constructs SQL statements in the way of direct splicing without sufficient filtering, SQL injection will be generated

JavaWeb Inject Demo : https://github.com/ky0103/JavaSecurityDemo/tree/main/SQLInject

You need to add the Myabtis/JDBC dependency to the WEB-INF/lib directory

Java XSS

In Java, XSS is generally generated by obtaining the parameter value in the Servlet and setting it in the request attribute. The value in the request can be directly referenced in the jsp file. If the parameter value is not filtered, XXS may occur. The following code sets the attribute value without filtering

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String username = req.getParameter("username");
    req.setAttribute("username",username);
    req.getRequestDispatcher("/index.jsp").forward(req,resp);
}

XSS defense can take advantage of ESAPI

ESAPI (Enterprise Security API) is a free and open source Web application API, which aims to help developers develop more secure code, and it is easy to call.

rely on

<dependency>
    <groupId>org.owasp.esapi</groupId>
    <artifactId>esapi</artifactId>
    <version>2.2.1.1</version>
</dependency>

Use ESAPI to filter before storing the value into the request

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String username = req.getParameter("username");
    ESAPI.encoder().encodeForJavaScript(username);
    req.setAttribute("username",username);
    req.getRequestDispatcher("/index.jsp").forward(req,resp);
}

JavaWeb Inject Demo : https://github.com/ky0103/JavaSecurityDemo/tree/main/XSS

You need to add ESAPI dependencies to the WEB-INF/lib directory

Java SSRF

The SSRF of HttpURLConnection class only supports HTTP/HTTPS protocol, not file and other protocols

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String url = req.getParameter("url");
    if (url != null){
        URL url1 = new URL(url);
        String htmlContent;
        URLConnection urlConnection = url1.openConnection();
        HttpURLConnection httpURLConnection = (HttpURLConnection)urlConnection;
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));
        StringBuffer html = new StringBuffer();
        while ((htmlContent = bufferedReader.readLine()) != null){
            html.append(htmlContent);
        }
        bufferedReader.close();
        resp.getWriter().println(html);
    }else {
        resp.getWriter().write("?url");
    }
}

URLConnection supports protocols such as HTTP/HTTPS/file

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String url = req.getParameter("url");
    if (url != null){
        URL url1 = new URL(url);
        String htmlContent;
        URLConnection urlConnection = url1.openConnection();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
        StringBuffer html = new StringBuffer();
        while ((htmlContent = bufferedReader.readLine()) != null){
            html.append(htmlContent);
        }
        bufferedReader.close();
        resp.getWriter().println(html);
    }else {
        resp.getWriter().write("?url");
    }
}

The file download under SSRF is actually to modify the response header

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String fileName = "secret.txt";
    resp.setHeader("content-disposition","attachment;fileName="+fileName);
    String url = req.getParameter("url");
    int length;
    URL u = new URL(url);
    InputStream inputStream = u.openStream();
    byte[] bytes = new byte[1024];
    while ((length = (inputStream.read(bytes))) > 0){
        resp.getOutputStream().write(bytes,0,length);
    }
}

When reading a file under SSRF, you cannot read a non picture file, but you can detect whether the file exists

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String url = req.getParameter("url");
    URL u = new URL(url);
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    InputStream inputStream1 = u.openStream();
    ImageInputStream imageInputStream = ImageIO.createImageInputStream(inputStream1);
    BufferedImage read = ImageIO.read(imageInputStream);
    ImageIO.write(read,"png",byteArrayOutputStream);
    InputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
    int length;
    byte[] bytes = new byte[1024];
    while ((length = (inputStream.read(bytes))) > 0){
        resp.getOutputStream().write(bytes,0,length);
    }
}

JavaWeb SSRF Demo : https://github.com/ky0103/JavaSecurityDemo/tree/main/XSS

Topics: Java SQL xss