@@ -9,10 +9,10 @@ import (
99 "github.com/GhostTroops/scan4all/lib/util"
1010 "github.com/GhostTroops/scan4all/pkg/fingerprint"
1111 "github.com/antlabs/strsim"
12- "io/ioutil"
1312 "log"
1413 "mime"
1514 "net/url"
15+ "os"
1616 "path/filepath"
1717 "regexp"
1818 "strings"
@@ -123,14 +123,14 @@ var regs []string
123123var (
124124 regsMap = make (map [string ]* regexp.Regexp ) // fuzz 正则库
125125 disabledFileFuzz = false // 是否开启fuzz
126- NoDoPath = sync.Map {}
126+ NoDoPath sync.Map
127127 NoDoPathInit = false
128128)
129129
130130func DoInitMap () {
131131 if NoDoPathInit == false && "" != fingerprint .FgDictFile {
132132 NoDoPathInit = true
133- if data , err := ioutil .ReadFile (fingerprint .FgDictFile ); nil == err {
133+ if data , err := os .ReadFile (fingerprint .FgDictFile ); nil == err {
134134 a := strings .Split (strings .TrimSpace (string (data )), "\n " )
135135 for _ , k := range a {
136136 NoDoPath .Store (k , true )
@@ -181,13 +181,23 @@ type FuzzData struct {
181181}
182182
183183// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
184- var r001 = regexp .MustCompile (`\.(aac)|(abw)|(arc)|(avif)|(avi)|(azw)|(bin)|(bmp)|(bz)|(bz2)|(cda)|(csh)|(css)|(csv)|(doc)|(docx)|(eot)|(epub)|(gz)|(gif)|(ico)|(ics)|(jar)|(jpeg)|(jpg)|(js)|(json)|(jsonld)|(mid)|(midi)|(mjs)|(mp3)|(mp4)|(mpeg)|(mpkg)|(odp)|(ods)|(odt)|(oga)|(ogv)|(ogx)|(opus)|(otf)|(png)|(pdf)|(php)|(ppt)|(pptx)|(rar)|(rtf)|(sh)|(svg)|(tar)|(tif)|(tiff)|(ts)|(ttf)|(txt)|(vsd)|(wav)|(weba)|(webm)|(webp)|(woff)|(woff2)|(xhtml)|(xls)|(xlsx)|(xml)|(xul)|(zip)|(3gp)|(3g2)|(7z)$` )
184+ var (
185+ r001 = regexp .MustCompile (`\.(aac)|(abw)|(arc)|(avif)|(avi)|(azw)|(bin)|(bmp)|(bz)|(bz2)|(cda)|(csh)|(css)|(csv)|(doc)|(docx)|(eot)|(epub)|(gz)|(gif)|(ico)|(ics)|(jar)|(jpeg)|(jpg)|(js)|(json)|(jsonld)|(mid)|(midi)|(mjs)|(mp3)|(mp4)|(mpeg)|(mpkg)|(odp)|(ods)|(odt)|(oga)|(ogv)|(ogx)|(opus)|(otf)|(png)|(pdf)|(php)|(ppt)|(pptx)|(rar)|(rtf)|(sh)|(svg)|(tar)|(tif)|(tiff)|(ts)|(ttf)|(txt)|(vsd)|(wav)|(weba)|(webm)|(webp)|(woff)|(woff2)|(xhtml)|(xls)|(xlsx)|(xml)|(xul)|(zip)|(3gp)|(3g2)|(7z)$` )
186+ cT1 = make (chan struct {}, 1 ) // 每次只允许1个url fuzz
187+ )
185188
186189// 重写了fuzz:优化流程、优化算法、修复线程安全bug、增加智能功能
187190//
188191// 两次 ioutil.ReadAll(resp.Body),第二次就会 Read返回EOF error
189192// 去除指纹请求的路径,避免重复
190193func FileFuzz (u string , indexStatusCode int , indexContentLength int , indexbody string ) ([]string , []string ) {
194+ if util .TestRepeat (u ) {
195+ return []string {}, []string {}
196+ }
197+ cT1 <- struct {}{}
198+ defer func () {
199+ <- cT1
200+ }()
191201 if disabledFileFuzz {
192202 return []string {}, []string {}
193203 }
@@ -233,7 +243,9 @@ func FileFuzz(u string, indexStatusCode int, indexContentLength int, indexbody s
233243 }
234244 var wg sync.WaitGroup
235245 // 中途控制关闭当前目标所有fuzz
246+ // 终止fuzz任务
236247 ctx , stop := context .WithCancel (util .Ctx_global )
248+ // 终止 接收结果任务
237249 ctx2 , stop2 := context .WithCancel (util .Ctx_global )
238250 // 控制 fuzz 线程数
239251 var ch = make (chan struct {}, util .Fuzzthreads )
@@ -245,6 +257,7 @@ func FileFuzz(u string, indexStatusCode int, indexContentLength int, indexbody s
245257 if strings .HasPrefix (url404req .Protocol , "HTTP/2" ) || strings .HasPrefix (url404req .Protocol , "HTTP/3" ) {
246258 MaxErrorTimes = int32 (len (filedic ))
247259 }
260+ //var MaxErrorTimes int32 = 100
248261 if c1 := util .GetClient (u , map [string ]interface {}{"Timeout" : 15 * time .Second , "ErrLimit" : MaxErrorTimes }); nil != c1 {
249262 util .PutClientCc (u , c1 )
250263 }
@@ -258,7 +271,9 @@ func FileFuzz(u string, indexStatusCode int, indexContentLength int, indexbody s
258271 var lst200 * util.Response
259272 t001 := time .NewTicker (3 * time .Second )
260273 var nCnt int32 = 0
274+ // 异步 接收 fuzz 结果
261275 go func () {
276+ defer stop ()
262277 for {
263278 select {
264279 case <- ctx2 .Done ():
@@ -288,8 +303,6 @@ func FileFuzz(u string, indexStatusCode int, indexContentLength int, indexbody s
288303 } else {
289304 return
290305 }
291- default :
292- time .Sleep (33 * time .Second )
293306 // <-time.After(time.Duration(100) * time.Millisecond)
294307 }
295308 }
@@ -304,135 +317,133 @@ BreakAll:
304317 continue
305318 }
306319 // 接收到停止信号
307- if atomic .LoadInt32 (& errorTimes ) >= MaxErrorTimes {
320+ if errorTimes >= MaxErrorTimes {
321+ stop ()
308322 break
309323 }
310324 select {
311325 case <- ctx .Done ():
312326 break BreakAll
313327 default :
314328 {
315- //log.Println(u, " ", payload)
316329 endP := u [len (u )- 1 :] == "/"
317330 ch <- struct {}{}
318331 wg .Add (1 )
319332 go func (payload string ) {
320333 payload = strings .TrimSpace (payload )
321334 defer func () {
322- wg . Done () // 控制所有线程结束
323- <- ch // 并发控制
335+ <- ch // 并发控制
336+ wg . Done ()
324337 }()
325338 atomic .AddInt32 (& nCnt , 1 )
326- for {
327- select {
328- case <- ctx .Done (): // 00-捕获所有线程关闭信号,并退出,close for all
329- atomic .AddInt32 (& errorTimes , MaxErrorTimes )
339+ select {
340+ case <- ctx .Done (): // 00-捕获所有线程关闭信号,并退出,close for all
341+ atomic .AddInt32 (& errorTimes , MaxErrorTimes )
342+ return
343+ default :
344+ //if _, ok := noRpt.Load(szKey001Over); ok {
345+ // stop()
346+ // return
347+ //}
348+ // 01-异常>20关闭所有fuzz
349+ if errorTimes >= MaxErrorTimes {
350+ stop () //发停止指令
330351 return
331- default :
332- //if _, ok := noRpt.Load(szKey001Over); ok {
333- // stop()
334- // return
352+ }
353+ // 修复url,默认 认为 payload 不包含/
354+ szUrl := u + payload
355+ if strings .HasPrefix (payload , "/" ) && endP {
356+ szUrl = u + payload [1 :]
357+ }
358+ //log.Printf("start fuzz: [%s]", szUrl)
359+ if fuzzPage , req , err := reqPage (szUrl ); err == nil && nil != req && 0 < len (req .Body ) {
360+ if 200 == req .StatusCode {
361+ if nil == lst200 {
362+ lst200 = req
363+ } else if lst200 .Body == req .Body { // 无意义的 200
364+ return
365+ }
366+ if oU1 , err := url .Parse (szUrl ); nil == err {
367+ a50 := r001 .FindStringSubmatch (oU1 .Path )
368+ if 0 < len (a50 ) {
369+ s2 := mime .TypeByExtension (filepath .Ext (a50 [0 ]))
370+ ct := (* req ).Header .Get ("Content-Type" )
371+ if "" != ct && "" != s2 && strings .Contains (ct , s2 ) {
372+ return
373+ }
374+ }
375+ }
376+ //log.Printf("%d : %s \n", req.StatusCode, szUrl)
377+ if IsLoginPage (szUrl , req .Body , req .StatusCode ) {
378+ technologies = append (technologies , "loginpage" )
379+ }
380+ }
381+ go util .CheckHeader (req .Header , u )
382+ // 02-状态码和req1相同,且与req1相似度>9.5,关闭所有fuzz
383+ fXsd := strsim .Compare (url404req .Body , req .Body )
384+ bBig95 := 0.95 < fXsd
385+ //if "/bea_wls_internal/classes/mejb@/org/omg/stub/javax/management/j2ee/_ManagementHome_Stub.class" == payload {
386+ // log.Println("start debug")
335387 //}
336- // 01-异常>20关闭所有fuzz
337- if atomic .LoadInt32 (& errorTimes ) >= MaxErrorTimes {
388+ if url404 .StatusCode == fuzzPage .StatusCode && bBig95 {
338389 stop () //发停止指令
390+ atomic .AddInt32 (& errorTimes , MaxErrorTimes )
339391 return
340392 }
341- // 修复url,默认 认为 payload 不包含/
342- szUrl := u + payload
343- if strings .HasPrefix (payload , "/" ) && endP {
344- szUrl = u + payload [1 :]
345- }
346- //log.Printf("start fuzz: [%s]", szUrl)
347- if fuzzPage , req , err := reqPage (szUrl ); err == nil && nil != req && 0 < len (req .Body ) {
348- if 200 == req .StatusCode {
349- if nil == lst200 {
350- lst200 = req
351- } else if lst200 .Body == req .Body { // 无意义的 200
352- continue
353- }
354- if oU1 , err := url .Parse (szUrl ); nil == err {
355- a50 := r001 .FindStringSubmatch (oU1 .Path )
356- if 0 < len (a50 ) {
357- s2 := mime .TypeByExtension (filepath .Ext (a50 [0 ]))
358- ct := (* req ).Header .Get ("Content-Type" )
359- if "" != ct && "" != s2 && strings .Contains (ct , s2 ) {
360- continue
361- }
362- }
363- }
364- //log.Printf("%d : %s \n", req.StatusCode, szUrl)
365- if IsLoginPage (szUrl , req .Body , req .StatusCode ) {
366- technologies = append (technologies , "loginpage" )
367- }
393+ var path1 , technologies1 = []string {}, []string {}
394+ // 03-异常页面(>400),或相似度与404匹配
395+ if fuzzPage .StatusCode >= 400 || bBig95 || fuzzPage .StatusCode != 200 {
396+ // 03.01-异常页面指纹匹配
397+ technologies = Addfingerprints404 (technologies , req , fuzzPage ) //基于404页面文件扫描指纹添加
398+ // 03.02-与绝对404相似度低于0.8,添加body 404 body list
399+ // 03.03-添加404titlelist
400+ if 0.8 > fXsd && fuzzPage .StatusCode != 200 && fuzzPage .StatusCode != url404 .StatusCode {
401+ StudyErrPageAI (req , fuzzPage , "" ) // 异常页面学习
368402 }
369- go util .CheckHeader (req .Header , u )
370- // 02-状态码和req1相同,且与req1相似度>9.5,关闭所有fuzz
371- fXsd := strsim .Compare (url404req .Body , req .Body )
372- bBig95 := 9.5 < fXsd
373- //if "/bea_wls_internal/classes/mejb@/org/omg/stub/javax/management/j2ee/_ManagementHome_Stub.class" == payload {
374- // log.Println("start debug")
375- //}
376- if url404 .StatusCode == fuzzPage .StatusCode && bBig95 {
377- stop () //发停止指令
378- atomic .AddInt32 (& errorTimes , MaxErrorTimes )
379- return
380- }
381- var path1 , technologies1 = []string {}, []string {}
382- // 03-异常页面(>400),或相似度与404匹配
383- if fuzzPage .StatusCode >= 400 || bBig95 || fuzzPage .StatusCode != 200 {
384- // 03.01-异常页面指纹匹配
385- technologies = Addfingerprints404 (technologies , req , fuzzPage ) //基于404页面文件扫描指纹添加
386- // 03.02-与绝对404相似度低于0.8,添加body 404 body list
387- // 03.03-添加404titlelist
388- if 0.8 > fXsd && fuzzPage .StatusCode != 200 && fuzzPage .StatusCode != url404 .StatusCode {
389- StudyErrPageAI (req , fuzzPage , "" ) // 异常页面学习
390- }
391- // 04-403: 403 by pass
392- if fuzzPage .Is403 && ! url404 .Is403 {
393- a11 := ByPass403 (& u , & payload , & wg )
394- // 表示 ByPass403 成功了, 结果、控制台输出点什么?
395- if 0 < len (a11 ) {
396- async_data <- & FuzzData {Path : & a11 , Req : fuzzPage }
397- }
403+ // 04-403: 403 by pass
404+ if fuzzPage .Is403 && ! url404 .Is403 {
405+ a11 := ByPass403 (& u , & payload , & wg )
406+ // 表示 ByPass403 成功了, 结果、控制台输出点什么?
407+ if 0 < len (a11 ) {
408+ async_data <- & FuzzData {Path : & a11 , Req : fuzzPage }
398409 }
399- return
400- }
401- // 当前和绝对404不等于404,后续的比较也没有意义了,都等于[200,301,302]都没有意义了,都说明没有fuzz成功
402- if url404 .StatusCode != 404 && url404 .StatusCode == fuzzPage .StatusCode {
403- return
404410 }
411+ return
412+ }
413+ // 当前和绝对404不等于404,后续的比较也没有意义了,都等于[200,301,302]都没有意义了,都说明没有fuzz成功
414+ if url404 .StatusCode != 404 && url404 .StatusCode == fuzzPage .StatusCode {
415+ return
416+ }
405417
406- // 05-跳转检测,即便是跳转,如果和绝对404不一样,说明检测成功
407- //if CheckDirckt(fuzzPage, req) && url404.StatusCode != fuzzPage.StatusCode {
408- // return
418+ // 05-跳转检测,即便是跳转,如果和绝对404不一样,说明检测成功
419+ //if CheckDirckt(fuzzPage, req) && url404.StatusCode != fuzzPage.StatusCode {
420+ // return
421+ //}
422+ // 1、状态码和绝对404一样 2、智能识别算出来
423+ is404Page := url404 .StatusCode == fuzzPage .StatusCode || CheckIsErrPageAI (req , fuzzPage )
424+ // 06-成功页面, 非异常页面
425+ if ! is404Page || 200 == fuzzPage .StatusCode && url404 .StatusCode != fuzzPage .StatusCode {
426+ // 1、指纹匹配
427+ technologies1 = Addfingerprintsnormal (payload , technologies1 , req , fuzzPage ) // 基于200页面文件扫描指纹添加
428+ // 2、成功fuzz路径结果添加
429+ path1 = append (path1 , * fuzzPage .Url )
430+ }
431+ if 0 < len (path1 ) {
432+ async_data <- & FuzzData {Path : & path1 , Req : fuzzPage }
433+ }
434+ if 0 < len (technologies1 ) {
435+ async_technologies <- technologies1
436+ }
437+ } else { // 这里应该元子操作
438+ if nil != err {
439+ //if nil != client && strings.Contains(err.Error(), " connect: connection reset by peer") {
440+ // client.Client = client.GetClient(nil)
409441 //}
410- // 1、状态码和绝对404一样 2、智能识别算出来
411- is404Page := url404 .StatusCode == fuzzPage .StatusCode || CheckIsErrPageAI (req , fuzzPage )
412- // 06-成功页面, 非异常页面
413- if ! is404Page || 200 == fuzzPage .StatusCode && url404 .StatusCode != fuzzPage .StatusCode {
414- // 1、指纹匹配
415- technologies1 = Addfingerprintsnormal (payload , technologies1 , req , fuzzPage ) // 基于200页面文件扫描指纹添加
416- // 2、成功fuzz路径结果添加
417- path1 = append (path1 , * fuzzPage .Url )
418- }
419- if 0 < len (path1 ) {
420- async_data <- & FuzzData {Path : & path1 , Req : fuzzPage }
421- }
422- if 0 < len (technologies1 ) {
423- async_technologies <- technologies1
424- }
425- } else { // 这里应该元子操作
426- if nil != err {
427- //if nil != client && strings.Contains(err.Error(), " connect: connection reset by peer") {
428- // client.Client = client.GetClient(nil)
429- //}
430- //log.Printf("file fuzz %s is err %v\n", szUrl, err)
431- }
432- atomic .AddInt32 (& errorTimes , 1 )
442+ //log.Printf("file fuzz %s is err %v\n", szUrl, err)
433443 }
434- return
444+ atomic . AddInt32 ( & errorTimes , 1 )
435445 }
446+ return
436447 }
437448 }(payload )
438449 }
0 commit comments