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

news2024/12/25 0:10:36

手写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.coloradmin.cn/o/1831644.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AI写真:Stable Diffusion 之 IPAdapter-FaceId

自Stable Diffusion发布以来&#xff0c;AI写真一直是AIGC界的热门话题。 AI写真为摄影师和艺术家提供了全新的创作工具。通过AI技术&#xff0c;艺术家可以轻松实现复杂的图像效果&#xff0c;如风格迁移、图像合成等&#xff0c;AI写真能够在短时间内完成传统摄影师和设计师…

基于single flight来解决缓存击穿

目录 1. 缓存击穿2. 常见解决方案3.single flight方式3.1 模拟业务场景3.2 使用single flight的方式 缓存雪崩、缓存击穿、缓存穿透不单单是缓存领域的经典场景&#xff0c;更是面试当牛马时必备&#xff08;背&#xff09;八股文。 我们来讨论下缓存击穿场景下的解决方案。 …

2024年设计、数字化技术与新闻传播国际学术会议(ICDDTJ 2024)

2024年设计、数字化技术与新闻传播国际学术会议(ICDDTJ 2024) 2024 International Conference on Design, Digital Technology and Journalism 会议地点&#xff1a;哈尔滨&#xff0c;中国 网址&#xff1a;www.icddtj.com 邮箱: icddtjsub-conf.com 投稿主题请注明:ICDD…

Vue46-render函数

一、非单文件和单文件的main.js对比 1-1、非单文件的main.js 1-2、 单文件的main.js 将单文件的main.js中的render函数变成非单文件的main.js中的template形式&#xff0c;报如下错误&#xff1a; 解决方式&#xff1a; 二、解决方式 2-1、引入完成版的vue.js 精简版的vue&a…

Elixir学习笔记——Erlang 库

Elixir 提供了与 Erlang 库的出色互操作性。事实上&#xff0c;Elixir 不鼓励简单地包装 Erlang 库&#xff0c;而是直接与 Erlang 代码交互。在本节中&#xff0c;我们将介绍一些 Elixir 中没有的最常见和最有用的 Erlang 功能。 Erlang 模块的命名约定与 Elixir 不同&#x…

Windows电脑部署Jellyfin服务端并进行远程访问配置详细教程

文章目录 前言1. Jellyfin服务网站搭建1.1 Jellyfin下载和安装1.2 Jellyfin网页测试 2.本地网页发布2.1 cpolar的安装和注册2.2 Cpolar云端设置2.3 Cpolar本地设置 3.公网访问测试4. 结语 前言 本文主要分享如何使用Windows电脑本地部署Jellyfin影音服务并结合cpolar内网穿透工…

建筑效果图为啥要用渲染100?渲染100邀请码1a12

建筑效果图是建筑设计师向客户展示方案的重要手段&#xff0c;通常在完成建模和材质贴图后&#xff0c;设计师会把它通过本地电脑渲染出来&#xff0c;不过本地渲染效率低&#xff0c;时间长&#xff0c;所以很多时候设计师也会使用网渲平台&#xff0c;今天我们介绍的渲染100就…

onnx基本概念

onnx基本概念 参考 文章目录 onnx基本概念Input, Output, Node, Initializer, AttributesSerialization with protobuf元数据List of available operators and domains支持的类型Opset版本Subgraphs, tests and loopsExtensibilityFunctionsShape (and Type) Inferencetools O…

元宇宙三维虚拟场景制作平台为数字化营销发展注入了新的活力

​在数字化浪潮的推动下&#xff0c;我们迎来了全新的3D元宇宙场景在线制作编辑器&#xff0c;为您带来前所未有的创作体验。这款轻量级实时创作工具&#xff0c;让您轻松构建丰富的3D元宇宙场景&#xff0c;实现全网全终端的展示。 3D元宇宙场景在线制作编辑器拥有海量的3D模…

Go 并发控制:RWMutex 实战指南

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

HTML5新标签

HTML5 特点 新标签 <header>...<header> 头部标签 <footer>...<footer> 尾部标签 <section>...<section> 内容区块 <article>...&#xff0c;article> 表示页面中的独立内容 <aside>...<aside> 标签定义其所处…

掌控未来:用决策树算法揭秘胜利者的必胜策略!

掌控未来&#xff1a;用决策树算法揭秘胜利者的必胜策略&#xff01; 一、引言1.1. 决策树的定义1.2. 发展历程1.3. 当前应用概况1.4. 本文内容安排 二、决策树的基本概念2.1 节点和叶节点2.2 决策树的结构结构图示不同结构的决策树 三、决策树的算法原理3.1 基本思想3.2 核心算…

使用 Nstbrowser 管理多个帐户 - 2024 年最佳反检测浏览器

每个人一定都看过那些房间里全是窃听器的老间谍电影&#xff0c;对吧&#xff1f;现在这些电影可能看起来有点好笑&#xff0c;但互联网并没有好到哪里去&#xff01; 事实上&#xff0c;每个你打开的页面在你浏览时都在被监控&#xff01;此外&#xff0c;当你管理多个账户时…

Web应用安全测试-防护功能缺失

Web应用安全测试-防护功能缺失 1、Cookie属性问题 漏洞描述&#xff1a; Cookie属性缺乏相关的安全属性&#xff0c;如Secure属性、HttpOnly属性、Domain属性、Path属性、Expires属性等。 测试方法&#xff1a; 通过用web扫描工具进行对网站的扫描&#xff0c;如果存在相关…

成都某展厅2套2x2透明OLED拼接屏项目

成都某展厅的2套2x2透明OLED拼接屏展示设计具有独特的技术魅力和视觉效果。以下是关于这一展示设计的详细介绍&#xff1a; 1.产品规格 类型&#xff1a;透明OLED拼接屏 尺寸与配置&#xff1a;每套为2x2拼接&#xff0c;即每套由4块屏幕组成。 2.应用场景 成都某展厅&#…

实战 | 基于YOLOv10的车辆追踪与测速实战【附源码+步骤详解】

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

linux部署运维3——centos7.9离线安装部署配置涛思taos2.6时序数据库TDengine以及java项目链接问题处理(二)

上一篇讲了centos7.9如何安装涛思taos2.6时序数据库的操作步骤和方案&#xff0c;本篇主要讲解taos数据库的初始化&#xff0c;相关配置说明&#xff0c;数据库和表的创建问题以及java项目连接问题。 centos7.9如何离线安装taos2.6&#xff0c;请点击下方链接详细查看&#xf…

zotero style最新(可全文翻译)

问题&#xff1a;在下载zotero style的时候&#xff0c;总会出现各种奇奇怪怪的问题&#xff0c;不是期刊没有级别&#xff0c;就是没有IF之类的&#xff1b; 解决&#xff1a;https://github.com/MuiseDestiny/zotero-style/releases 在这里下载最新的版本 若要使用全文翻译…

【IPython使用技巧整理】内省功能历史命令执行Shell命令运行脚本导出为其他格式

本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明来源(注明:作者:王文峰…

最佳Google Chrome扩展和Mozilla Firefox扩展自动解决验证码

在这个信息爆炸的时代&#xff0c;我们每天都要处理大量的在线内容&#xff0c;验证码已成为不可避免的挑战。尽管它们旨在保护网站安全&#xff0c;但也常常成为我们获取信息的障碍。那么&#xff0c;有没有更简单的方法绕过这些验证码呢&#xff1f;答案是肯定的。通过使用一…