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

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

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

目录

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

1. 示例

1.1 主界面

在这里插入图片描述

1.2 开启反向代理

在这里插入图片描述

1.3 抓包

在这里插入图片描述

1.4 历史记录

在这里插入图片描述

1.5 重发

在这里插入图片描述

2. 核心代码

2.1 GUI

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 抓包

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(仅供学习)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/729434.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

国产32位高精度低功耗DSP音频处理芯片-DU561

DU561是一款集成多种音效算法高性能32位DSP音频处理芯片&#xff1b;具有高速、高精度、高稳定性等特点&#xff0c;能实现对音频信号的滤波、增强、降噪、混响、变调等处理&#xff0c;广泛应用于音频系统、通信系统、汽车音响、家庭影院、舞台设备等领域。 音频处理可以更好地…

ShuffleNet系列论文阅读笔记(ShuffleNetV1和ShuffleNetV2)

目录 ShuffleNet: An Extremely Efficient Convolutional Neural Network for Mobile Devices摘要Approach—方法Channel Shuffle for Group Convolutions—用于分组卷积的通道重排ShuffleNet Unit—ShuffleNet单元Network Architecture—网络体系结构 总结 ShuffleNet V2: Pra…

工业无线网关在实际生产中的应用效果和价值-天拓四方

随着智能制造的快速发展&#xff0c;工业无线网关作为关键通信设备&#xff0c;在提升生产效率、优化生产流程、实现设备间的互联互通等方面发挥着越来越重要的作用。以下是一个关于工业无线网关在智能制造行业应用的具体案例&#xff0c;展示了其在实际生产中的应用效果和价值…

toLocaleString浏览器兼容问题,导致时间在不同版本显示24/12小时制

先看toLocaleString结果区别 旧版 新版 问题原因 Google Chrome 和其他浏览器会定期更新&#xff0c;这些更新可能包括对 JavaScript 引擎和国际化的改进较新版本的 Chrome&#xff08;版本 125.0.6422.142&#xff09;已经更新了其国际化实现&#xff0c;以默认使用24小时制 …

SpringBoot整合justauth实现多种方式的第三方登陆

目录 0.准备工作 1.引入依赖 2.yml文件 3. Controller代码 4.效果 参考 0.准备工作 你需要获取三方登陆的client-id和client-secret 以github为例 申请地址&#xff1a;Sign in to GitHub GitHub 1.引入依赖 <?xml version"1.0" encoding"UTF-8&quo…

NAT Easyip实验

我们这篇博客将重点讲述easy ip的配置&#xff1a; 以下面的一个简单的实验拓扑图为例&#xff1a; 本实验使用的网络地址&#xff1a; 1. 我们先来完成基础配置&#xff1a; 1.1AR1的基础配置&#xff1a; 1.2AR2上的基础配置 1.3完成AR1和AR2的基础配置后&#xff0c;我们…

【SPIE出版】第六届无线通信与智能电网国际会议(ICWCSG 2024,7月26-28)

随着科技的飞速发展和能源需求的日益增长&#xff0c;智能电网技术逐渐成为电力行业的重要发展方向。与此同时&#xff0c;无线通信技术在近年来也取得了显著的进步&#xff0c;为智能电网的发展提供了强有力的支持。为了进一步推动无线通信与智能电网的结合与发展&#xff0c;…

Socket编程之多进程模型

一、多进程模型概述 基于最初的阻塞网络 I/O &#xff0c;若服务器要为多个客户端提供支持&#xff0c;在较为传统的手段中&#xff0c;多进程模型是常用的选择&#xff0c;即为每个客户端都分配一个进程来处理其请求。 服务器的主进程主要负责对客户连接的监听&#xff0c;一旦…

视频云沉浸式音视频技术能力探索与建设

概述 随着传输技术、显示技术与算力的持续提升&#xff0c;用户对于音视频体验的需求在提高&#xff0c;各家设备厂商也在探索和推出对应的技术与产品。打造空间感的空间视频与空间音频是其中最为关键的2项技术&#xff0c;bilibili视频云在这两项技术领域也进行了相关代探索与…

redis.conf 参数详解,方便进行性能优化配置

以下是redis.conf中一些常见参数的详细说明&#xff1a; daemonize&#xff1a;是否以后台进程运行&#xff0c;默认为no&#xff1b; pidfile&#xff1a;如以后台进程运行&#xff0c;则需指定一个pid&#xff0c;默认为/var/run/redis.pid&#xff1b;bind&#xff1a;绑定主…

WPF——属性

一、属性 类最初只有字段与函数&#xff0c;字段为一个变量&#xff0c;访问权限可以是private&#xff0c;protected&#xff0c;public。而将字段设为private&#xff0c;不方便外界对类数据的操作&#xff0c;但是将字段设为public又怕外界对数据进行非法操作&#xff0c;于…

二叉树-二叉搜索树的最近公共祖先

目录 一、问题描述 二、解题思路 三、代码实现 四、刷题链接 一、问题描述 二、解题思路 这个问题和之前做过的问题很相似&#xff1a; 深度优先遍历-在二叉树中找到两个节点的最近公共祖先-CSDN博客文章浏览阅读80次。java刷题&#xff1a;在二叉树中找到两个结点的最近公…

用于快速充电站的 AC/DC 转换器概述

电动汽车构成了未来实现可持续交通部门的有前途技术的主要部分。AC/DC 转换器是扩展和改进 EV 功能的骨干组件。本文概述了 AC/DC 转换器、充电站类型、传统两电平 (2L) AC/DC 转换器面临的问题以及使用多电平转换器 (MLC) 的重要性。 AC/DC 充电器示意图&#xff08;&#xff…

2024广东省职业技能大赛云计算赛项实战——Minio服务搭建

Minio服务搭建 前言 这道题是比赛时考到的&#xff0c;没找到具体题目&#xff0c;但在公布的样题中找到了&#xff0c;虽然很短~ 使用提供的 OpenStack 云平台&#xff0c;申请一台云主机&#xff0c;使用提供的软件包安装部署 MINIO 服务并使用 systemctl 管理 Minio是一个…

关于接口测试——自动化框架的设计与实现

一、自动化测试框架 在大部分测试人员眼中只要沾上“框架”&#xff0c;就感觉非常神秘&#xff0c;非常遥远。大家之所以觉得复杂&#xff0c;是因为落地运用起来很复杂&#xff1b;每个公司&#xff0c;每个业务及产品线的业务流程都不一样&#xff0c;所以就导致了“自动化…

Linux_理解进程地址空间和页表

目录 1、进程地址空间示意图 2、验证进程地址空间的结构 3、验证进程地址空间是虚拟地址 4、页表-虚拟地址与物理地址 5、什么是进程地址空间 6、进程地址空间和页表的存在意义 6.1 原因一&#xff08;效率性&#xff09; 6.2 原因二&#xff08;安全性&#xff09; …

MVC模式中控制器、视图和模型之间的关系如何?

mvc模式将应用程序逻辑与表示层分离&#xff0c;包括控制器、视图和模型三个组件&#xff1a;控制器&#xff1a;协调用户输入&#xff0c;获取模型数据&#xff0c;验证输入&#xff0c;执行业务规则。视图&#xff1a;显示模型数据&#xff0c;不包含业务逻辑。模型&#xff…

如何使用AI解决所有EXCEL公式问题

有个假设前提&#xff0c;你略懂EXCEL公式 知道单元格“ $C1” 和 ”C1”的区别&#xff0c;当然你也可以自行度娘或问AI。 AI使用文心一言免费版方便容易获取。 第一步也是唯一的一步&#xff0c;向AI准确描述你的需求 示例&#xff1a;学生的成绩分布在0-100分之间&#x…

echarts+vue2实战(一)

目录 一、项目准备 二、(横向分页)柱状图 2.1、动态刷新 2.2、UI调整 2.3、分辨率适配 三、(竖向平移)柱状图 3.1、平移动画 3.2、不同数值显示不同颜色 四、(下拉切换)折线图 4.1、切换图表和分辨率适配 4.2、UI调整 五、(三级分类)饼图 5.1、数据切换 六、圆环…