fiddler二次轉發實現動態改包

  • 2019 年 10 月 6 日
  • 筆記

問題場景描述

正如我上一篇所提到的,如何更加精確有狀態地實現動態修改請求返回包?對有狀態這裡理解可能有點問題,我描述一個場景會更直觀一點。

一個應用軟體向伺服器請求時間戳,第一次請求返回為A,通過修改返回包,使第二次返回A+B,第三次返回A+B+B…..這裡面有一個遞增的關係,這就是我所描述的狀態。

常見的改包是無狀態的,即我使用burp,他的自動改包是一個正則表達式匹配的字元串替換;使用fiddler,通過的他腳本進行返回包修改,但修改函數是無狀態的,每請求一次,函數便重新運行一次,是無法計數的,也就是我所說的無狀態。

解決問題思考

要解決這個問題,首先想到的是重寫的一個代理,但這部分工作我覺得並不是那麼簡單,要做到像burp或者fiddler那樣成熟的工具,並不是個簡單的活。

偶然間的想法,讓我想到可以在fiddler這一層代理上,進行一個請求的二次「轉發」,這個轉發有點歧義,我所說的轉發是將請求的返回結果進行一次轉發,再發送到一個第三方伺服器,這個伺服器返回我們要的結果。自然,這個第三方伺服器是我們可以控制的,自然。

fiddler發送請求實現

查找資料發現fiddler的script可以通過以下三個函數進行請求發送:

  1. FiddlerApplication.oProxy.SendRequest
  2. FiddlerApplication.oProxy.SendRequestAndWait
  3. FiddlerObject.utilIssueRequest

SendRequest和SendRequestAndWait用法是一樣的,區別在於一個只是發送了請求,並不能處理返回包,SendRequestAndWait可以處理返回包,所以SendRequestAndWait就是我們需要的函數。utilIssueRequest也是發送請求無法處理返回包。

這裡也簡單提一下utilIssueRequest的使用方法,utilIssueRequest的使用比另外兩個函數要簡單得多,只是處理字元串,然後拼接成一個請求頭,而SendRequest和SendRequestAndWait得兩個參數分別是HTTPRequestHeaders和Byte[]類型。utilIssueRequest使用簡單demo如下,即向http://localhost:9090/發送了一個POST請求:

var method:String = 'POST';  var url:String = 'http://localhost:9090/';  var protocol = "HTTP/1.1";  raw += method + " " + url + " " + protocol + "rn";  var body = 'test';  raw += "rn" + body;  FiddlerObject.utilIssueRequest(raw);

回到真正所需要得SendRequestAndWait函數,這個函數用法挺難找的,所幸還是找到了,我最後寫的程式碼如下:

if (oSession.HostnameIs("www.humblegames.cn")&& oSession.uriContains('fightingx/utils/timeUtil2.php')){  			var responses = oSession.GetResponseBodyAsString();              oSession.utilDecodeResponse(); //解碼  			var Content: byte[] = System.Text.Encoding.UTF8.GetBytes(responses);  			var oRQH: HTTPRequestHeaders = new HTTPRequestHeaders("/", ['Host: 127.0.0.1:9090','Content-Length: '+Content.length.ToString(), 'Content-Type: application/x-www-url-encoded']);  			oRQH.HTTPMethod = "POST";  			var oSD = new System.Collections.Specialized.StringDictionary();  			var newSession = FiddlerApplication.oProxy.SendRequestAndWait(oRQH, Content, oSD, null);  			var second_res = newSession.GetResponseBodyAsString();  			FiddlerApplication.Log.LogString(second_res);  			oSession.utilSetResponseBody(second_res);          }

程式碼實現的內容:首先獲取當前請求的返回包,將返回包的body通過POST請求轉發到127.0.0.1:9090,再將127.0.0.1:9090返回的結果當作最後此次請求的返回body。

在9090埠也是一個簡單的flask伺服器,這裡通過一個計數器便可以解決上面的狀態問題:

# -*- coding: utf-8 -*-  from flask import Flask,request  app = Flask(__name__)    count = 0    @app.route('/', methods=['GET', 'POST'])  def index():      global count      count += 1      time = str(1569076091 + count * 21700)      return time      if __name__ == '__main__':      app.run(host='0.0.0.0',port=9090,debug=True)

這上面兩段程式碼也就解決了我一開始所描述的場景問題。

又一個問題

這裡我所實現的第三方伺服器是一個flask,但當請求返回的結果是一個複雜的html時,裡面有各種換行各種符號等等,將這種數據作為POST請求的data,在flask這邊是很難處理的。是否有更優雅更加完備的第三方伺服器實現方式,能夠獲取所有POST數據,處理這種問題?