Golang poc编写教程
Go poc
希望代码没逝
事先声明:一般情况下请求包申明变量,习惯命名为req,返回包resp。(容易眼花)
为了方便区分我习惯将请求包命名为ask,并且为了本文简洁省略了资源的关闭
注意:关闭连接是ask.Close=true,resp.Body.Close()是关闭回包的缓存
为了直观感受到数据包,需要搭建一个服务器,方便查看执行结果(参考本文:服务器端搭建)
高并发要注意进程数,否则服务器可能会崩
请求
发送一个简单的网络请求
package main
import "net/http"
func main() {
URL1 := "http://127.0.0.1:2333/ping"
http.Get(URL1)
ask, _ := http.NewRequest("GET", URL1, nil)
http.DefaultClient.Do(ask)
}
运行结果
发送POST请求
package main
import (
"bytes"
"net/http"
"net/url"
)
func main() {
URL1 := "http://127.0.0.1:2333/form"
URL2 := "http://127.0.0.1:2333/form"
URL3 := "http://127.0.0.1:2333/form"
//以key-value形式传送数据
post_body := url.Values{} //构造post_body。注意:url为软件包名,在此之前不能申明名为url变量,否则冲突(最好别起这个名)
post_body.Add("Hello", "你在狗叫什么?")
http.PostForm(URL1, post_body)
//以json格式传送数据
post_body2 := bytes.NewBuffer([]byte(`{"code":0,"name":"wang"}`)) //Buffer这种形式,只能用一回
http.Post(URL2, "application/json", post_body2)
//key-value方式(同一)
post_body3 := url.Values{}
post_body3.Add("name", "海绵宝宝")
http.Post(URL3, "multipart/form-data", bytes.NewBuffer([]byte(post_body3.Encode())))
//url.Values可以多次使用去构造Buffer,但是由其产生的Buffer只能用一次,如boddy_3_1:=bytes.NewBuffer([]byte(post_body3.Encode()))这个body_3_1作为Body参数只能用一次
//自己构造请求对象
post_body4 := url.Values{}
post_body4.Add("dog", "大黄")
ask, _ := http.NewRequest("POST", URL2, bytes.NewBuffer([]byte(post_body4.Encode()))) //此处POST可以换成PUT等,post_body可以换成nil
http.DefaultClient.Do(ask)
}
执行结果
注意:url.Values可以多次使用去构造Buffer,但是由其产生的Buffer只能用一次,如boddy_3_1:=bytes.NewBuffer([]byte(post_body3.Encode()
body_3可以多次构造出body_3_1、body_3_2但是body_3_1只能用一次
带参GET
超级简单
package main
import (
"net/http"
"net/url"
)
func main() {
URL1 := "http://127.0.0.1:2333/query?name=三岁的狗&age=3"
URL2 := "http://127.0.0.1:2333/query?"
http.Get(URL1)
get_params := url.Values{}
get_params.Add("name", "八百岁的海龟")
get_params.Add("age", "800")
http.Get(URL2 + get_params.Encode())
}
直接在url加就行了
运行结果
json参数
package main
import (
"bytes"
"encoding/json"
"net/http"
)
func main() {
//方法一
URL1 := "http://127.0.0.1:2333/json"
json1, _ := json.Marshal(map[string]any{
"code": 1,
"name": "3岁的狗",
"age": 3,
"son_json": map[string]any{
"id": "user_100",
"num": 12345,
},
})
http.Post(URL1, "application/json", bytes.NewBuffer(json1))
/*
*/
//方法二
//使用结构体的方式传入json
//注意:结构体内的东西要大写开头否则不会导出
URL2 := "http://127.0.0.1:2333/json"
type data struct {
Name string `json:"name"`
Age int `json:"age"`
}
json2, _ := json.Marshal(data{Name: "五百岁的海龟", Age: 500})
http.Post(URL2, "application/json", bytes.NewBuffer(json2))
/*
*/
//方法三
//以json格式传送数据
post_body2 := bytes.NewBuffer([]byte(`{"code":3,"name":"袋鼠"}`))
http.Post(URL2, "application/json", post_body2)
}
运行结果
设置header
package main
import "net/http"
func main() {
URL1 := "http://127.0.0.1:2333/head"
ask, _ := http.NewRequest("GET", URL1, nil)
ask.Header.Set("user_id", "123") //设置
ask.Header.Add("user_id", "100") //添加
http.DefaultClient.Do(ask)
}
运行结果
设置Cookie
package main
import (
"net/http"
)
func main() {
URL1 := "http://127.0.0.1:2333/head"
ask, _ := http.NewRequest("GET", URL1, nil)
ask.AddCookie(&http.Cookie{Name: "age", Value: "18"})
ask.AddCookie(&http.Cookie{Name: "name", Value: "boy"})
//关于去重
/*
cookies := ask.Cookies() //从其它地方获得cookie,加入ask这个请求中,不重复添加
for _, i := range cookies {
_, err := ask.Cookie(i.Name) //若查找不到,则err
if err == nil { //无err说明查找到了
fmt.Println("重复cookie")
} else { //没找到cookie,可以添加
ask.AddCookie(i)
}
}
*/
http.DefaultClient.Do(ask)
}
运行结果
文件上传
package main
import (
"bytes"
"fmt"
"io"
"log"
"mime/multipart"
"net/http"
"os"
)
func CheckError(err error) {
if err != nil {
fmt.Println("发生错误!!")
log.Fatal(err)
}
}
func main() {
URL1 := "http://127.0.0.1:2333/file"
//创建缓存
bodyBuf := &bytes.Buffer{}
bodyWrite := multipart.NewWriter(bodyBuf)
//读取文件
file, err := os.Open("study/123.txt")
CheckError(err)
//创建传输格式,并将文件copy进去
fileWrite, err := bodyWrite.CreateFormFile("file", "xxx.txt")
_, err = io.Copy(fileWrite, file)
CheckError(err)
//获取ContentType并发送数据包
bodyWrite.Close() //先关闭在获取ContentType,否则会出问题
ContentType := bodyWrite.FormDataContentType()
http.Post(URL1, ContentType, bodyBuf)
//关闭资源
defer file.Close()
}
运行结果
上传多个文件
// 打开需要上传的文件
file, err := os.Open("1.txt")
CheckError(err)
defer file.Close()
// 创建body的写入器
body := &bytes.Buffer{} //分配一个缓冲
mulWriter := multipart.NewWriter(body)
mulWriter.SetBoundary("--3333333333333333333333333--")
//给写入器添加值1
err = mulWriter.WriteField("MAX_FILE_SIZE", "100000")
CheckError(err)
// 在body中创建文件(空间),并指明文件参数名和参数值
body_file, err := mulWriter.CreateFormFile("uploaded", "webshell.php")
CheckError(err)
// 复制文件内容到写入器中的文件空间
_, err = io.Copy(body_file, file)
CheckError(err)
//给写入器添加值2
err = mulWriter.WriteField("Upload", "Upload")
CheckError(err)
// 记得关闭,让缓冲区的内容写入body中
err = mulWriter.Close()
CheckError(err)
contentType := mulWriter.FormDataContentType()
ask, _ := http.NewRequest("POST", "http://192.168.108.133/vulnerabilities/upload/", body)
for _, a := range cook {
_, err2 := ask.Cookie(a.Name)
if err2 != nil {
ask.AddCookie(a)
}
}
ask.Header.Set("Content-Type", contentType)
resp,err := http.DefaultClient.Do(ask)
运行时发送的数据包
响应
json响应
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
URL1 := "http://127.0.0.1:2333/get_json"
ask, _ := http.NewRequest("GET", URL1, nil)
resp, _ := http.DefaultClient.Do(ask)
byteData, _ := io.ReadAll(resp.Body)
//响应方式1
fmt.Println(string(byteData))
//响应方式2
var json_data map[string]any
json.Unmarshal(byteData, &json_data)
fmt.Println("一整个:", json_data)
fmt.Println("取单个元素", json_data["code"])
}
运行结果
file响应
package main
import (
"io"
"net/http"
"os"
)
func main() {
URL1 := "http://127.0.0.1:2333/get_file"
resp, _ := http.Get(URL1)
byteData, _ := io.ReadAll(resp.Body)
os.WriteFile("uploads/download.txt", byteData, 0777)
}
运行结果
html响应 - goquery
需要第三方库
项目中终端执行
go get github.com/PuerkitoBio/goquery
package main
import (
"fmt"
"github.com/PuerkitoBio/goquery"
"log"
"net/http"
)
func main() {
URL1 := "http://127.0.0.1:2333/douban"
resp, _ := http.Get(URL1)
doc, err := goquery.NewDocumentFromReader(resp.Body)
checkError(err)
//打印html内容
fmt.Println(doc.Html())
//获得Title
fmt.Println(doc.Find("title").Text())
//获得dom结点
//该结点html代码如下
//<a class="title" href="https://m.douban.com/time/column/37?dt_time_source=douban-web_anonymous" target="_blank">邪典电影本纪——亚文化电影50讲</a>
fmt.Println(doc.Find("#anony-time > div > div.main > ul > li:nth-child(1) > a.title").Html())
node := doc.Find("#anony-time > div > div.main > ul > li:nth-child(1) > a.title").Nodes[0]
fmt.Println(node.Attr)
//获取属性
doc.Find("#anony-time > div > div.main > ul > li:nth-child(1) > a.title").Attr("href")
fmt.Println(doc.Find("#anony-nav > div.anony-srh > form > span.bn > input[type=submit]").Attr("value"))
}
func checkError(err error) {
if err != nil {
log.Fatal(err)
}
}
运行结果
怎么遍历同级标签
doc.Find("#app > div > div > div > dl > dd").Each(func(i int, selection *goquery.Selection) {
//提取电影标题与封面URL
title, _ := selection.Find("a").Attr("title")
imageURL, _ := selection.Find("a").Find("img.board-img").Attr("data-src")
fmt.Println(" ", title, " ", imageURL)
//保存图片
save_image(imageURL, title, Cook, client2)
})
Find中的选择器怎么编写?
在浏览器中检查
选中要选择的元素,复制为selector
有关代理
部分情况我们需要调试,那么可以设置代理到burp或者yakit,这样可以直观看见数据包并进行调整
//获取有代理的客户端,并发送数据包
proxy := func(_ *http.Request) (*url.URL, error) {
return url.Parse("http://192.168.108.134:8090")
}
transport := &http.Transport{Proxy: proxy}
client := &http.Client{Transport: transport} //有代理、跟随跳转
命令行传参
使用以下代码,在编译后可以使用命令行接受参数
flag.Parse()之后,a变量才会生效
--help的时候是不会执行flag.Parse()之后的代码的
a := flag.String("animal", "cat", "动物类型")
flag.Parse()
fmt.Println(*a)
服务器端搭建
可能需要自行下载gin框架
项目中的终端,执行
go get github.com/gin-gonic/gin
在项目中创建一个template文件夹,并放入如下内容(随便去网上搞两个html即可)
同时创建文件夹用于保存上传的文件
package main
import (
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"io"
)
func ping(c *gin.Context) {
fmt.Println("成功请求")
}
func get(c *gin.Context) {
fmt.Println("get请求")
}
func post(c *gin.Context) {
fmt.Println("post请求")
}
func put(c *gin.Context) {
fmt.Println("put请求")
}
func Delete(c *gin.Context) {
fmt.Println("delete请求")
}
func form(c *gin.Context) {
byteData, err := io.ReadAll(c.Request.Body)
fmt.Println(string(byteData), err, c.Request.Header.Get("Content-Type"))
}
func jsonM(c *gin.Context) {
byteData, err := io.ReadAll(c.Request.Body)
fmt.Println(string(byteData), err)
}
func query(c *gin.Context) {
byteData, err := json.Marshal(c.Request.URL.Query())
fmt.Println(string(byteData), err)
}
func head(c *gin.Context) {
byteData, err := json.Marshal(c.Request.Header)
fmt.Println(string(byteData), err)
}
func file(c *gin.Context) {
fileHeader, err := c.FormFile("file")
if err != nil {
return
}
fmt.Println(fileHeader.Filename)
c.SaveUploadedFile(fileHeader, "uploads/file/"+fileHeader.Filename)
}
func getFile(c *gin.Context) {
c.Header("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, "image.jpg"))
c.File("uploads/image.jpg")
}
func getJson(c *gin.Context) {
c.JSON(200, gin.H{
"code": 0,
"msg": "xxx",
"data": gin.H{},
})
}
func getHtml(c *gin.Context) {
c.HTML(200, "index.html", nil)
}
func douban(c *gin.Context) {
c.HTML(200, "douban.html", nil)
}
func main() {
router := gin.Default()
router.LoadHTMLGlob("template/**")
router.GET("/ping", ping)
router.GET("/get", get)
router.POST("/post", post)
router.POST("/form", form)
router.POST("/json", jsonM)
router.PUT("/put", put)
router.DELETE("/delete", Delete)
router.GET("/query", query)
router.GET("/head", head)
router.POST("/file", file)
router.GET("/get_file", getFile)
router.GET("/get_json", getJson)
router.GET("/get_html", getHtml)
router.GET("/douban", douban)
router.Run(":2333")
}
在线生成
直接问AI 文心一言 (baidu.com)
curl转go代码 curl to Go (curlconverter.com)
参考资料
https://docs.fengfengzhidao.com/#/docs/go%E7%88%AC%E8%99%AB/1.go%E7%88%AC%E8%99%AB
https://blog.csdn.net/chentaoxie/article/details/81369491
相信国家相信党,黑客没有好下场
请遵守相关法律法规,文中技术仅用于有授权的安全测试,禁止用于非法活动!
本文章仅面向拥有合法授权的渗透测试安全人员及进行常规操作的网络运维人员。
在操作的过程中,您应确保自己的所有行为符合当地法律法规,且不得进行违反中国人民共和国相关法律的活动。
作者不承担用户擅自使用相关技术从事任何活动所产生的任何责任。