利用反向代理编写HTTP抓包工具——可视化界面

手写HTTP抓包工具------可视化界面

项目 描述
语言 golang
可视化 fynev2
功能 代理抓包、重发、记录

目录

  • [1. 示例](#1. 示例)
    • [1.1 主界面](#1.1 主界面)
    • [1.2 开启反向代理](#1.2 开启反向代理)
    • [1.3 抓包](#1.3 抓包)
    • [1.4 历史记录](#1.4 历史记录)
    • [1.5 重发](#1.5 重发)
  • [2. 核心代码](#2. 核心代码)
    • [2.1 GUI](#2.1 GUI)
    • [2.1 抓包](#2.1 抓包)
  • [3. 结语](#3. 结语)
    • [3.1 传送门](#3.1 传送门)

1. 示例

1.1 主界面

1.2 开启反向代理

1.3 抓包

1.4 历史记录

1.5 重发

2. 核心代码

2.1 GUI

golang 复制代码
func (cf *Config) CreateUi() {
	myApp := app.New()
	mainWin := myApp.NewWindow("Request Handling Tool v1.0")
	// 创建数据绑定对象
	cf.MainWin = &mainWin
	// 创建可以多行输入的 Entry 并绑定数据
	requestEntry := widget.NewEntryWithData(types.RequestData)
	requestEntry.MultiLine = true
	requestEntry.Wrapping = fyne.TextWrapBreak
	responseEntry := widget.NewEntryWithData(types.ResponseData)
	responseEntry.MultiLine = true
	responseEntry.Wrapping = fyne.TextWrapBreak
	ErrEntry := widget.NewEntryWithData(types.ErrData)
	ErrEntry.MultiLine = true
	ErrEntry.Wrapping = fyne.TextWrapBreak
	hisreq1Entry := widget.NewEntryWithData(types.History_RequestD)
	hisreq1Entry.MultiLine = true
	hisreq1Entry.Wrapping = fyne.TextWrapBreak
	hisres2Entry := widget.NewEntryWithData(types.History_ResponseD)
	hisres2Entry.MultiLine = true
	hisres2Entry.Wrapping = fyne.TextWrapBreak

	repeat_req1Entry := widget.NewEntryWithData(types.Repeat_RequestD)
	repeat_req1Entry.MultiLine = true
	repeat_req1Entry.Wrapping = fyne.TextWrapBreak
	repeat_res2Entry := widget.NewEntryWithData(types.Repeat_ResponseD)
	repeat_res2Entry.MultiLine = true
	repeat_res2Entry.Wrapping = fyne.TextWrapBreak

	targetAddrEntry := widget.NewEntryWithData(types.TargetAD)
	types.TargetAD.Set("127.0.0.1:3443")
	serverAddrEntry := widget.NewEntryWithData(types.ServerAD)
	types.ServerAD.Set("0.0.0.0:8089")
	targetPMEntry := widget.NewEntryWithData(types.TargetPM)
	types.TargetPM.Set("https")
	targetAddrLabel := widget.NewLabel("TargetAddr:")
	serverAddrLabel := widget.NewLabel("ServerAddr:")
	targetPMLabel := widget.NewLabel("TargetPM:")
	// 设置请求和响应 Entry 控件铺满父容器

	check1 := widget.NewCheckWithData("AutoSend", types.AutoSData)
	check1.SetChecked(true)
	check_history := widget.NewCheckWithData("HistoryOK", types.HistoryOK)
	check_history.SetChecked(true)
	sendButton := widget.NewButton("Send", func() {
		cf.GUI_Send()
	})
	send2Button := widget.NewButton("SendRAW", func() {
		cf.GUI_Send_repeat()
	})
	discardButton := widget.NewButton("Discard", func() {
		cf.GUI_Discard()
	})
	nextButton := widget.NewButton("Next", func() {
		cf.GUI_Next()
	})
	sRepeatButton := widget.NewButton(">>Repeat", func() {
		cf.GUI_sRepeat()
	})
	clearButton := widget.NewButton("ClearHistory", func() {
		cf.GUI_Clear()
	})
	_history_dir_Button := widget.NewButton("ClearHistoryDirFile", func() {
		cf.GUI_history_dir_Button()
	})
	nextButton.Disable()
	sendButton.Disable()
	discardButton.Disable()

	cf.Sendbt = sendButton
	cf.Nextbt = nextButton
	cf.Discardbt = discardButton
	OKconfig := widget.NewButton("Save", func() {
		cf.GUI_Save_config()
	})
	OpenProxyconfig := widget.NewButton("OpenProxy", func() {
		cf.GUI_OpenProxyconfig()
	})

	CloseProxyconfig := widget.NewButton("CloseProxy", func() {
		cf.GUI_CloseProxyconfig()
	})
	CloseProxyconfig.Disable()
	OKconfig.Disable()
	cf.OpenProxybt = OpenProxyconfig
	cf.CloseProxybt = CloseProxyconfig
	cf.Savebt = OKconfig
	// 创建 Grid 布局
	grid_capture := container.NewGridWithColumns(3,
		container.NewStack(requestEntry),
		container.NewStack(responseEntry),
		container.NewVBox(check1, sendButton, discardButton, nextButton, sRepeatButton),
	)
	grid_config := container.NewGridWithColumns(3,
		container.NewVBox(
			container.NewVBox(targetAddrLabel, targetAddrEntry),
			container.NewVBox(serverAddrLabel, serverAddrEntry),
			container.NewVBox(targetPMLabel, targetPMEntry)),
		container.NewVBox(check_history, OKconfig, OpenProxyconfig, CloseProxyconfig, clearButton, _history_dir_Button),
		container.NewStack(ErrEntry),
	)

	table := widget.NewTable(
		// 返回表格的行数和列数
		func() (int, int) {
			return len(types.History_Data), len(types.History_Data[0]) // 第三列为按钮
		},
		// 返回每个单元格的 CanvasObject
		func() fyne.CanvasObject {
			entry := widget.NewEntry()
			ccButton := widget.NewButton("Select", nil)
			repeatButton := widget.NewButton(">>Repeat", nil)
			buttonContainer := container.NewGridWithColumns(2, ccButton, repeatButton)
			en1 := container.NewVBox(entry, buttonContainer)
			return en1
		},
		// 更新每个单元格的内容
		func(id widget.TableCellID, obj fyne.CanvasObject) {
			en1 := obj.(*fyne.Container)
			entry := en1.Objects[0].(*widget.Entry)
			buttonContainer := en1.Objects[1].(*fyne.Container)
			ccButton := buttonContainer.Objects[0].(*widget.Button)
			repeatButton := buttonContainer.Objects[1].(*widget.Button)

			if id.Col <= 1 { // 前两列显示数据
				entry.Show()           // 显示 Entry
				buttonContainer.Hide() // 隐藏按钮容器
				entry.SetText(types.History_Data[id.Row][id.Col])
			} else if id.Col > 1 { // 第三列显示按钮
				entry.Hide()           // 隐藏 Entry
				buttonContainer.Show() // 显示按钮容器
				ccButton.OnTapped = func(row int) func() {
					return func() {
						cf.GUI_Table_bt(row)
					}
				}(id.Row)
				repeatButton.OnTapped = func(row int) func() {
					return func() {
						cf.GUI_Table_Repeat_bt(row)
					}
				}(id.Row)
			}
		})
	cf.Table_history = table
	// 创建带有垂直滚动条的容器
	tableContainer := container.NewVScroll(table)
	// 创建histroy布局
	grid_history := container.NewGridWithRows(2,
		container.NewStack(tableContainer),
		container.NewGridWithColumns(2,
			container.NewStack(hisreq1Entry),
			container.NewStack(hisres2Entry),
		),
	)
	grid_repeat := container.NewGridWithColumns(3,
		container.NewStack(repeat_req1Entry),
		container.NewStack(repeat_res2Entry),
		container.NewVBox(send2Button),
	)
	tab2 := container.NewTabItem("capture", grid_capture)
	tab1 := container.NewTabItem("config", grid_config)
	tab3 := container.NewTabItem("history", grid_history)
	tab4 := container.NewTabItem("repeat", grid_repeat)
	tabContainer := container.NewAppTabs(tab1, tab2, tab3, tab4)
	tabContainer.SetTabLocation(container.TabLocationTop)
	// 布局
	// 拦截关闭事件
	mainWin.SetCloseIntercept(func() {
		mainWin.Hide() // 隐藏窗口
	})
	mainWin.SetContent(tabContainer)
	// 添加窗口大小变化监听器

	mainWin.Resize(fyne.NewSize(800, 600))

	mainWin.ShowAndRun()

}

2.1 抓包

python 复制代码
func Run(conf *Config) {
	for {
		select {
		case <-conf.RunTH:
			types.ErrMainData += fmt.Sprintln("[+] Close-Proxy-OK")
			// fmt.Println(1)
			return
		default:
			// fmt.Println(0)
		}
		if conf.ServerAddr == "" || conf.TargetAddr == "" || conf.TargetPM == "" || conf.Nextbt == nil {
			time.Sleep(2 * time.Second)
			types.ErrMainData += fmt.Sprintln("[-] Parameters not saved or initialization not completed")
		} else {
			break
		}

	}
	Init(conf)
	// 创建 HTTP 处理函数的中间件

	middleware := func(http.Handler) http.Handler {

		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

			types.CHT <- true
			hisD1 := []string{}
			hisD2 := []string{}
			defer func() { <-types.CHT }()

			// 获取原始请求的字符串表示
			dump, err := httputil.DumpRequest(r, true)
			utils.HandleErr(utils.GCFN(), err)
			dump, err = conf.HostFix(dump)
			utils.HandleErr(utils.GCFN(), err)
			if ok, err := types.HistoryOK.Get(); ok {
				utils.HandleErr(utils.GCFN(), err)
				hisD1 = append(hisD1, string(dump))
				hisD2 = append(hisD2, fmt.Sprintf("%v %v", r.Method, r.URL.String()))
			}

			// // 打印原始请求字符串
			// fmt.Printf("\033[32m%s\033[0m\n", dump)

			if ok, err := types.AutoSData.Get(); !ok {
				utils.HandleErr(utils.GCFN(), err)
				err = types.RequestData.Set(string(dump))
				utils.HandleErr(utils.GCFN(), err)
				conf.Cf_Enable()
			CC:
				for {

					select {
					case <-types.SendCH:
						rdata, err := types.RequestData.Get()
						utils.HandleErr(utils.GCFN(), err)
						// 将 rdata 解析成 *http.Request 对象
						r, err = http.ReadRequest(bufio.NewReader(bytes.NewBufferString(rdata)))
						utils.HandleErr(utils.GCFN(), err)
						break CC
					case <-types.DiscardCH:
						return
					default:

					}
					time.Sleep(100 * time.Millisecond)
				}

			} else {
				err = types.RequestData.Set("")
				utils.HandleErr(utils.GCFN(), err)
				err = types.ResponseData.Set("")
				utils.HandleErr(utils.GCFN(), err)

			}

			recorder := httptest.NewRecorder()
			recorder.Header().Add("Waf", "Coraza-v3")
			// 使用反向代理转发请求
			conf.Proxy.ServeHTTP(recorder, r)
			// 创建 http.Response 对象
			response := recorder.Result()

			// 使用 httputil.DumpResponse 来获取完整响应包
			res1, err := httputil.DumpResponse(response, true)
			utils.HandleErr(utils.GCFN(), err)
			if ok, _ := types.HistoryOK.Get(); ok {
				hisD1 = append(hisD1, string(res1))
				ff := utils.Wrtie_history_response(hisD1, conf.TargetAddr)
				hisD2 = append(hisD2, ff)
				types.History_Data = append(types.History_Data, hisD2)

			}
			if ok, err := types.AutoSData.Get(); !ok {
				utils.HandleErr(utils.GCFN(), err)
				err = types.ResponseData.Set(string(res1))
				utils.HandleErr(utils.GCFN(), err)
			}

			conf.TxProcessResponse(recorder, w, r)

			if ok, err := types.AutoSData.Get(); !ok {
				utils.HandleErr(utils.GCFN(), err)
			BB:
				for {
					select {
					case <-types.NextCH:
						err = types.RequestData.Set("")
						utils.HandleErr(utils.GCFN(), err)
						err = types.ResponseData.Set("")
						utils.HandleErr(utils.GCFN(), err)
						break BB
					default:
					}
					time.Sleep(100 * time.Millisecond)
				}

			} else {
				err = types.RequestData.Set("")
				utils.HandleErr(utils.GCFN(), err)
				err = types.ResponseData.Set("")
				utils.HandleErr(utils.GCFN(), err)
				conf.Cf_Disable()
			}

		})
	}
	server := &http.Server{
		Addr:    conf.ServerAddr,
		Handler: middleware(http.DefaultServeMux), // 使用中间件包裹默认的 ServeMux
	}

	go func() {
		types.ErrMainData += fmt.Sprintf("[+] Starting server at %v\n", conf.ServerAddr)
		if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			utils.HandleErr(utils.GCFN(), err)
		}
	}()

AA:
	for {
		select {
		case <-conf.RunTH:
			break AA
		default:
			time.Sleep(500 * time.Millisecond)
		}
	}
	// 通过 context 实现优雅关闭
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	if err := server.Shutdown(ctx); err != nil {
		types.ErrMainData += fmt.Sprintf("[-] Server shutdown failed:%v\n", err)
		if err := server.Close(); err != nil {
			types.ErrMainData += fmt.Sprintf("[!] Server Close failed:%v\n", err)
		} else {
			types.ErrMainData += fmt.Sprintln("[+] Close-Proxy-OK")
		}
	} else {
		types.ErrMainData += fmt.Sprintln("[+] Close-Proxy-OK")
	}

}

3. 结语

3.1 传送门

MiniBurp.exe(仅供学习)

相关推荐
m0_748240028 分钟前
Chromium 中chrome.webRequest扩展接口定义c++
网络·c++·chrome
終不似少年遊*16 分钟前
华为云计算HCIE笔记05
网络·华为云·云计算·学习笔记·hcie·认证·hcs
青灯文案120 分钟前
前端 HTTP 请求由 Nginx 反向代理和 API 网关到后端服务的流程
前端·nginx·http
蜜獾云30 分钟前
docker 安装雷池WAF防火墙 守护Web服务器
linux·运维·服务器·网络·网络安全·docker·容器
Narutolxy42 分钟前
深入探讨 Go 中的高级表单验证与翻译:Gin 与 Validator 的实践之道20241223
开发语言·golang·gin
Hello.Reader1 小时前
全面解析 Golang Gin 框架
开发语言·golang·gin
小林熬夜学编程2 小时前
【Linux网络编程】第十四弹---构建功能丰富的HTTP服务器:从状态码处理到服务函数扩展
linux·运维·服务器·c语言·网络·c++·http
Hacker_Fuchen2 小时前
天融信网络架构安全实践
网络·安全·架构
上海运维Q先生2 小时前
面试题整理15----K8s常见的网络插件有哪些
运维·网络·kubernetes
ProtonBase2 小时前
如何从 0 到 1 ,打造全新一代分布式数据架构
java·网络·数据库·数据仓库·分布式·云原生·架构