对于我,一个有一点 golang
基础底子但不多的人,有时候想写点代码但是苦于脑中没有构思和对应库的详细使用经验,因此在开发过程中需要耗费大量的时间精力去百度查看文档。
机缘巧合下发现腾讯的混元大模型有代码生成和解释的能力,便尝试着使用该大模型来提高自己的代码能力,创造出一些适合自己的基础建设。
混元大模型地址:https://hunyuan.tencent.com
指纹识别
近期刚好需要开始铺设一条自动化发现和利用的基础架构,正好借着这个大模型来辅助开发。
我向混元进行提问:
用golang帮我编写一个Web指纹识别器,要求读取urls.txt中的URL地址并批量进行指纹识别,识别前会先发送HEAD请求进行存活探测,然后将识别到的内容输出
返回了一个代码片段,并给这段代码做出了解释:
package main
import (
"bufio"
"fmt"
"io/ioutil"
"net/http"
"os"
"strings"
)
func main() {
file, err: = os.Open("urls.txt")
if err != nil {
fmt.Println("Error opening file:", err)
return
}
defer file.Close()
scanner: = bufio.NewScanner(file)
for scanner.Scan() {
url: = scanner.Text()
if isAlive(url) {
fingerprint: = getFingerprint(url)
fmt.Printf("URL: %snFingerprint: %snn", url,
fingerprint)
} else {
fmt.Printf("URL: %s is not alivenn", url)
}
}
if err: = scanner.Err();
err != nil {
fmt.Println("Error reading file:", err)
}
}
func isAlive(url string) bool {
client: = & http.Client {}
req,
_: = http.NewRequest("HEAD", url, nil)
resp,
err: = client.Do(req)
if err != nil {
return false
}
defer resp.Body.Close()
return resp.StatusCode == http.StatusOK
}
func getFingerprint(url string) string {
client: = & http.Client {}
req,
_: = http.NewRequest("GET", url, nil)
resp,
err: = client.Do(req)
if err != nil {
return ""
}
defer resp.Body.Close()
body,
err: = ioutil.ReadAll(resp.Body)
if err != nil {
return ""
}
return strings.Join(strings.Fields(string(body)), " ")
}
我仔细看了一下生成的这个代码,可以说是把我的需求实现的非常准确!
但由于我没有告诉它如何识别指纹,因此这个 getFingerprint
函数的返回还不够细化,接着继续问:
我还需要一个finger.json的规则库,里面有必须存在的Path字段设置了该匹配什么URI路径,必须设置 的匹配类型字段Type可以选择MD5、HTTP状态码、响应Body中的正则字符串、网站标题的Title、 Cookie名称、某个响应的Header头,且还需要一个operator字段设置”or”或者”and”值,用于判断匹配 类型是满足其中一个还是都需要满足,请生成这样的json文件内容。
返回了一个 JSON
内容
{
"rules": [
{
"name": "Rule 1",
"path": "/example1",
"operator": "and",
"matches": [
{
"type": "md5",
"value": "abcd1234"
},
{
"type": "status_code",
"value": 200
},
{
"type": "regex",
"value": "example regex"
},
{
"type": "title",
"value": "Example Title"
},
{
"type": "cookie",
"name": "cookie_name",
"operator": "exists"
},
{
"type": "header",
"name": "X-Custom-Header",
"value": "custom_value"
}
]
}
]
}
同时给出修饰:
生成了 JSON
文件,自然就需要让大模型为我们修改之前的代码
根据这个JSON,我需要解析该finger.json文件,同时修改getFingerprint函数的内容,批量请求Json 中Path字段指定的地址并根据对应的type类型进行匹配
返回的结果也很有意思
package utils
import (
"bytes"
"crypto/md5"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"regexp"
"strings"
"sync"
"github.com/PuerkitoBio/goquery"
)
type Fingerprint struct {
Name string `json:"name"`
Path string `json:"path"`
Operator string `json:"operator"`
Matches[] Match `json:"matches"`
}
type Match struct {
Type string `json:"type"`
Value string `json:"value,omitempty"`
Name string `json:"name,omitempty"`
}
func main() {
jsonFile, err: = os.Open("finger.json")
if err != nil {
fmt.Println(err)
return
}
defer jsonFile.Close()
byteValue, _: = ioutil.ReadAll(jsonFile)
var fingerprints[] Fingerprint
json.Unmarshal(byteValue, & fingerprints)
var wg sync.WaitGroup
for _, fingerprint: = range fingerprints {
wg.Add(1)
go func(fingerprint Fingerprint) {
defer wg.Done()
result: = getFingerprint(fingerprint)
fmt.Printf("Result for %s: %vn", fingerprint.Name, result)
}(fingerprint)
}
wg.Wait()
}
func getFingerprint(fingerprint Fingerprint) bool {
client: = & http.Client {
CheckRedirect: func(req * http.Request, via[] * http.Request) error {
return http.ErrUseLastResponse
},
}
targetURL: = "http://example.com" + fingerprint.Path
req,
err: = http.NewRequest("GET", targetURL, nil)
if err != nil {
return false
}
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)
AppleWebKit / 537.36(KHTML, like Gecko) Chrome / 58.0.3029.110 Safari / 537.3 ")
resp, err: = client.Do(req) if err != nil {
return false
}
defer resp.Body.Close()
body, err: = ioutil.ReadAll(resp.Body) if err != nil {
return false
}
doc, err: = goquery.NewDocumentFromReader(bytes.NewReader(body)) if err != nil {
return false
}
var results[] bool
for _, match: = range fingerprint.Matches {
result: = false
switch match.Type {
case "md5":
result = checkMD5(body, match.Value)
case "status_code":
result = checkStatusCode(resp, match.Value)
case "regex":
result = checkRegex(string(body), match.Value)
case "title":
result = checkTitle(doc, match.Value)
case "cookie":
result = checkCookie(resp, match.Name, match.Operator)
case "header":
result = checkHeader(resp, match.Name, match.Value, match.Operator)
}
results = append(results, result)
}
if fingerprint.Operator == "and" {
for _, result: = range results {
if !result {
return false
}
}
return true
} else if fingerprint.Operator == "or" {
for _, result: = range results {
if result {
return true
}
}
return false
}
return false
}
func checkMD5(body[] byte, expectedMD5 string) bool {
return fmt.Sprintf("%x", md5.Sum(body)) == expectedMD5
}
func checkStatusCode(resp * http.Response, expectedStatusCode string) bool {
return fmt.Sprint(resp.StatusCode) == expectedStatusCode
}
func checkRegex(body string, regex string) bool {
matched, err: = regexp.MatchString(regex, body)
if err != nil {
return false
}
其实大致上功能逻辑都没问题, 但还是存在有少部分地方需要修改, 如结构体Matchs中没有
Operator, 大模型给误识别到。
还有一处是resp.Cookie, 但是这个 * http.Response是没有Cookie字段, 因为这里其实就是
return matched
}
func checkTitle(doc * goquery.Document, expectedTitle string) bool {
title: = doc.Find("title").Text()
return title == expectedTitle
}
func checkCookie(resp * http.Response, cookieName string, operator string) bool {
cookie, err: = resp.Cookie(cookieName)
if err != nil {
return false
}
switch operator {
case "exists":
return true
case "not_exists":
return false
default:
return false
}
}
func checkHeader(resp * http.Response, headerName string, expectedValue string,
operator string) bool {
headerValue: = resp.Header.Get(headerName)
switch operator {
case "equals":
return headerValue == expectedValue
case "not_equals":
return headerValue != expectedValue
case "contains":
return strings.Contains(headerValue, expectedValue)
case "not_contains":
return !strings.Contains(headerValue, expectedValue)
default:
return false
}
}
其实大致上功能逻辑都没问题,但还是存在有少部分地方需要修改,如结构体 Matchs
中没有 Operator
,大模型给误识别到。
还有一处是 resp.Cookie
,但是这个 *http.Response
是没有 Cookie
字段,因为这里其实就是 Header
头中的 Set-Cookie
字段。
于是我让混元大模型继续帮我修改问题:
func checkCookie(resp * http.Response, cookieName string, operator string) bool {
setCookieHeader: = resp.Header.Get("Set-Cookie")
if setCookieHeader == "" {
return false
}
switch operator {
case "exists":
return strings.Contains(setCookieHeader, cookieName)
case "not_exists":
return !strings.Contains(setCookieHeader, cookieName)
default:
return false
}
}
之后稍微检查一下逻辑并与之前的代码跑通就可以开始进行测试
有缺漏的地方也可以直接交给大模型继续修复
// 创建 Rules 结构体实例
var rules Rules
// 使用 Unmarshal 函数将 JSON 数据反序列化为 Rules 结构体实例
err: = json.Unmarshal([] byte(jsonData), & rules)
if err != nil {
fmt.Println("反序列化失败:", err)
return
}
运行测试
编写完成之后,就可以开始跑程序进行测试,由于 url
是需要批量的,因此肯定会用到协程的方式
完成任务。但是这个根据服务器或者机器的性能区别,要设置一个信号量在短时间内设置并发数量。
我用goroutine执行任务的时候,给它设置一个信号量,只允许最大并发数量10个线程来处理任务,请给 出代码
返回 demo
如下:
package main
import (
"fmt"
"sync"
)
// 定义一个信号量类型
type Semaphore struct {
ch chan struct {}
}
// 创建一个新的信号量实例,并设置最大并发数量
func NewSemaphore(maxConcurrency int) * Semaphore {
return &Semaphore {
ch: make(chan struct {}, maxConcurrency)
}
}
// 获取信号量
func(s * Semaphore) Acquire() {
s.ch < -struct {} {}
}
// 释放信号量
func(s * Semaphore) Release() { < -s.ch
}
// 任务函数
func task(i int, wg * sync.WaitGroup, sem * Semaphore) {
defer wg.Done()
sem.Acquire() // 获取信号量
fmt.Printf("Task %d startedn", i)
// 模拟任务执行时间
time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
fmt.Printf("Task %d finishedn", i)
sem.Release() // 释放信号量
}
func main() {
maxConcurrency: = 10
numTasks: = 20
// 创建一个新的信号量实例
sem: = NewSemaphore(maxConcurrency)
var wg sync.WaitGroup
wg.Add(numTasks)
// 使用goroutine执行任务
for i: = 0;i < numTasks;i++{
go task(i, & wg, sem)
}
// 等待所有任务完成
wg.Wait()
}
其实这里返回的代码虽然可以,但 golang
官方其实有类似的库 "golang.org/x/sync/semaphore"
关键代码如下所示:
var sem = semaphore.NewWeighted(10)
wg.Add(1)
go func(url string) {
defer wg.Done()
sem.Acquire(context.Background(), 1)
defer sem.Release(1)
fingerprint, isHave: = utils.GetFingerprint(url)
if isHave {
log.Printf("[+] URL: %s FingerPrint: %s", url, fingerprint)
} else {
log.Printf("[-] URL: %s not found fingerprint.", url)
}
}(url)
这里也能通过规则正确识别出来
扩展功能
有了这个,每次还需要写 json
感觉很麻烦,就接着问大模型让它帮我生成一个批量添加的
{ “rules”: [ { “name”: “Tencent OpenSource”, “path”: “/”, “condition”: “and”,”matches”: [ { “type”: “status_code”, “value”: “200” }, { “type”: “title”, “value”: “腾讯开源 | Tencent Open Source” } ] } }
根据上面的Json内容编写一个命令行生成工具,循环挨个询问每个字段需要填入的内容,最后输出完整 的JSON
给我生成了一个命令行的输出工具
package main
import (
"encoding/json"
"fmt"
)
type Rule struct {
Name string `json:"name"`
Path string `json:"path"`
Condition string `json:"condition"`
Matches[] Match `json:"matches"`
}
type Match struct {
Type string `json:"type"`
Value string `json:"value"`
}
func main() {
var rules[] Rule
for {
var rule Rule
fmt.Print("Enter rule name (or 'done' to finish): ")
var name string
fmt.Scanln( & name)
if name == "done" {
break
}
rule.Name = name
fmt.Print("Enter path: ")
fmt.Scanln( & rule.Path)
fmt.Print("Enter condition (and/or): ")
fmt.Scanln( & rule.Condition)
for {
var match Match
fmt.Print("Enter match type (or 'done' to finish): ")
var matchType string
fmt.Scanln( & matchType)
if matchType == "done" {
break
}
match.Type = matchType
fmt.Print("Enter match value: ")
fmt.Scanln( & match.Value)
rule.Matches = append(rule.Matches, match)
}
rules = append(rules, rule)
}
jsonData, err: = json.MarshalIndent(rules, "", " ")
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Generated JSON:")
fmt.Println(string(jsonData))
}
我测试了一下,除了生成的 json
格式没有外面的 rule
标签之外,还是挺正确的
总结
总体来说,我感觉借助大模型和自己的一些能看懂代码的基础上进行开发,完全是可以满足日常的需求,包括自己想实现什么样的功能都可以直接从大模型上进行询问、设计。
从个人的角度来说,很多时候开发只是需要满足某个功能点,可以让它先给出一个需求的大致实现,再慢慢询问优化,同时结合自己的一些主观想法做引导,最后再完善修改就能在提高开发效率的基础上达到准确的需求实现。
关注公众号后台回复 0001
领取域渗透思维导图,0002
领取VMware 17永久激活码,0003
获取SGK地址,0004
获取在线ChatGPT地址,0005
获取 Windows10渗透集成环境,0006
获取 CobaltStrike 4.9.1破解版
加我微信好友,邀请你进交流群
往期推荐
备用号,欢迎关注
原文始发于微信公众号(刨洞安全团队):使用腾讯混元LLM辅助红队代码能力建设