pwn 0.5.418 → 0.5.421

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -16,6 +16,7 @@ module PWN
16
16
  # open_ai_rest_call(
17
17
  # token: 'required - open_ai bearer token',
18
18
  # http_method: 'optional HTTP method (defaults to GET)
19
+ # base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
19
20
  # rest_call: 'required rest call to make per the schema',
20
21
  # params: 'optional params passed in the URI or HTTP Headers',
21
22
  # http_body: 'optional HTTP body sent in HTTP methods that support it e.g. POST',
@@ -30,6 +31,8 @@ module PWN
30
31
  else
31
32
  opts[:http_method].to_s.scrub.to_sym
32
33
  end
34
+
35
+ base_uri = opts[:base_uri] ||= 'https://api.openai.com/v1'
33
36
  rest_call = opts[:rest_call].to_s.scrub
34
37
  params = opts[:params]
35
38
  headers = {
@@ -45,8 +48,6 @@ module PWN
45
48
 
46
49
  spinner = opts[:spinner] || false
47
50
 
48
- base_open_ai_api_uri = 'https://api.openai.com/v1'
49
-
50
51
  browser_obj = PWN::Plugins::TransparentBrowser.open(browser_type: :rest)
51
52
  rest_client = browser_obj[:browser]::Request
52
53
 
@@ -60,7 +61,7 @@ module PWN
60
61
  headers[:params] = params
61
62
  response = rest_client.execute(
62
63
  method: http_method,
63
- url: "#{base_open_ai_api_uri}/#{rest_call}",
64
+ url: "#{base_uri}/#{rest_call}",
64
65
  headers: headers,
65
66
  verify_ssl: false,
66
67
  timeout: timeout
@@ -72,7 +73,7 @@ module PWN
72
73
 
73
74
  response = rest_client.execute(
74
75
  method: http_method,
75
- url: "#{base_open_ai_api_uri}/#{rest_call}",
76
+ url: "#{base_uri}/#{rest_call}",
76
77
  headers: headers,
77
78
  payload: http_body,
78
79
  verify_ssl: false,
@@ -81,7 +82,7 @@ module PWN
81
82
  else
82
83
  response = rest_client.execute(
83
84
  method: http_method,
84
- url: "#{base_open_ai_api_uri}/#{rest_call}",
85
+ url: "#{base_uri}/#{rest_call}",
85
86
  headers: headers,
86
87
  payload: http_body.to_json,
87
88
  verify_ssl: false,
@@ -108,15 +109,18 @@ module PWN
108
109
 
109
110
  # Supported Method Parameters::
110
111
  # response = PWN::AI::OpenAI.get_models(
112
+ # base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
111
113
  # token: 'required - Bearer token',
112
114
  # timeout: 'optional timeout in seconds (defaults to 180)'
113
115
  # )
114
116
 
115
117
  public_class_method def self.get_models(opts = {})
118
+ base_uri = opts[:base_uri]
116
119
  token = opts[:token]
117
120
  timeout = opts[:timeout]
118
121
 
119
122
  response = open_ai_rest_call(
123
+ base_uri: base_uri,
120
124
  token: token,
121
125
  rest_call: 'models'
122
126
  )
@@ -128,6 +132,7 @@ module PWN
128
132
 
129
133
  # Supported Method Parameters::
130
134
  # response = PWN::AI::OpenAI.chat(
135
+ # base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
131
136
  # token: 'required - Bearer token',
132
137
  # request: 'required - message to ChatGPT'
133
138
  # model: 'optional - model to use for text generation (defaults to gpt-5-chat-latest)',
@@ -140,6 +145,7 @@ module PWN
140
145
  # )
141
146
 
142
147
  public_class_method def self.chat(opts = {})
148
+ base_uri = opts[:base_uri]
143
149
  token = opts[:token]
144
150
  request = opts[:request]
145
151
 
@@ -224,6 +230,7 @@ module PWN
224
230
  spinner = opts[:spinner]
225
231
 
226
232
  response = open_ai_rest_call(
233
+ base_uri: base_uri,
227
234
  http_method: :post,
228
235
  token: token,
229
236
  rest_call: rest_call,
@@ -282,6 +289,7 @@ module PWN
282
289
 
283
290
  # Supported Method Parameters::
284
291
  # response = PWN::AI::OpenAI.img_gen(
292
+ # base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
285
293
  # token: 'required - Bearer token',
286
294
  # request: 'required - message to ChatGPT',
287
295
  # n: 'optional - number of images to generate (defaults to 1)',
@@ -290,6 +298,7 @@ module PWN
290
298
  # )
291
299
 
292
300
  public_class_method def self.img_gen(opts = {})
301
+ base_uri = opts[:base_uri]
293
302
  token = opts[:token]
294
303
  request = opts[:request]
295
304
  n = opts[:n]
@@ -307,6 +316,7 @@ module PWN
307
316
  }
308
317
 
309
318
  response = open_ai_rest_call(
319
+ base_uri: base_uri,
310
320
  http_method: :post,
311
321
  token: token,
312
322
  rest_call: rest_call,
@@ -321,6 +331,7 @@ module PWN
321
331
 
322
332
  # Supported Method Parameters::
323
333
  # response = PWN::AI::OpenAI.vision(
334
+ # base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
324
335
  # token: 'required - Bearer token',
325
336
  # img_path: 'required - path or URI of image to analyze',
326
337
  # request: 'optional - message to ChatGPT (defaults to, "what is in this image?")',
@@ -332,6 +343,7 @@ module PWN
332
343
  # )
333
344
 
334
345
  public_class_method def self.vision(opts = {})
346
+ base_uri = opts[:base_uri]
335
347
  token = opts[:token]
336
348
  img_path = opts[:img_path]
337
349
 
@@ -399,6 +411,7 @@ module PWN
399
411
  timeout = opts[:timeout]
400
412
 
401
413
  response = open_ai_rest_call(
414
+ base_uri: base_uri,
402
415
  http_method: :post,
403
416
  token: token,
404
417
  rest_call: rest_call,
@@ -429,6 +442,7 @@ module PWN
429
442
 
430
443
  # Supported Method Parameters::
431
444
  # response = PWN::AI::OpenAI.create_fine_tune(
445
+ # base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
432
446
  # token: 'required - Bearer token',
433
447
  # training_file: 'required - JSONL that contains OpenAI training data'
434
448
  # validation_file: 'optional - JSONL that contains OpenAI validation data'
@@ -445,6 +459,7 @@ module PWN
445
459
  # )
446
460
 
447
461
  public_class_method def self.create_fine_tune(opts = {})
462
+ base_uri = opts[:base_uri]
448
463
  token = opts[:token]
449
464
  training_file = opts[:training_file]
450
465
  validation_file = opts[:validation_file]
@@ -462,6 +477,7 @@ module PWN
462
477
  timeout = opts[:timeout]
463
478
 
464
479
  response = upload_file(
480
+ base_uri: base_uri,
465
481
  token: token,
466
482
  file: training_file
467
483
  )
@@ -469,6 +485,7 @@ module PWN
469
485
 
470
486
  if validation_file
471
487
  response = upload_file(
488
+ base_uri: base_uri,
472
489
  token: token,
473
490
  file: validation_file
474
491
  )
@@ -492,6 +509,7 @@ module PWN
492
509
  http_body[:suffix] = suffix if suffix
493
510
 
494
511
  response = open_ai_rest_call(
512
+ base_uri: base_uri,
495
513
  http_method: :post,
496
514
  token: token,
497
515
  rest_call: 'fine_tuning/jobs',
@@ -506,15 +524,18 @@ module PWN
506
524
 
507
525
  # Supported Method Parameters::
508
526
  # response = PWN::AI::OpenAI.list_fine_tunes(
527
+ # base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
509
528
  # token: 'required - Bearer token',
510
529
  # timeout: 'optional - timeout in seconds (defaults to 180)'
511
530
  # )
512
531
 
513
532
  public_class_method def self.list_fine_tunes(opts = {})
533
+ base_uri = opts[:base_uri]
514
534
  token = opts[:token]
515
535
  timeout = opts[:timeout]
516
536
 
517
537
  response = open_ai_rest_call(
538
+ base_uri: base_uri,
518
539
  token: token,
519
540
  rest_call: 'fine_tuning/jobs',
520
541
  timeout: timeout
@@ -527,12 +548,14 @@ module PWN
527
548
 
528
549
  # Supported Method Parameters::
529
550
  # response = PWN::AI::OpenAI.get_fine_tune_status(
551
+ # base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
530
552
  # token: 'required - Bearer token',
531
553
  # fine_tune_id: 'required - respective :id value returned from #list_fine_tunes',
532
554
  # timeout: 'optional - timeout in seconds (defaults to 180)'
533
555
  # )
534
556
 
535
557
  public_class_method def self.get_fine_tune_status(opts = {})
558
+ base_uri = opts[:base_uri]
536
559
  token = opts[:token]
537
560
  fine_tune_id = opts[:fine_tune_id]
538
561
  timeout = opts[:timeout]
@@ -540,6 +563,7 @@ module PWN
540
563
  rest_call = "fine_tuning/jobs/#{fine_tune_id}"
541
564
 
542
565
  response = open_ai_rest_call(
566
+ base_uri: base_uri,
543
567
  token: token,
544
568
  rest_call: rest_call,
545
569
  timeout: timeout
@@ -552,12 +576,14 @@ module PWN
552
576
 
553
577
  # Supported Method Parameters::
554
578
  # response = PWN::AI::OpenAI.cancel_fine_tune(
579
+ # base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
555
580
  # token: 'required - Bearer token',
556
581
  # fine_tune_id: 'required - respective :id value returned from #list_fine_tunes',
557
582
  # timeout: 'optional - timeout in seconds (defaults to 180)'
558
583
  # )
559
584
 
560
585
  public_class_method def self.cancel_fine_tune(opts = {})
586
+ base_uri = opts[:base_uri]
561
587
  token = opts[:token]
562
588
  fine_tune_id = opts[:fine_tune_id]
563
589
  timeout = opts[:timeout]
@@ -565,6 +591,7 @@ module PWN
565
591
  rest_call = "fine_tuning/jobs/#{fine_tune_id}/cancel"
566
592
 
567
593
  response = open_ai_rest_call(
594
+ base_uri: base_uri,
568
595
  http_method: :post,
569
596
  token: token,
570
597
  rest_call: rest_call,
@@ -578,12 +605,14 @@ module PWN
578
605
 
579
606
  # Supported Method Parameters::
580
607
  # response = PWN::AI::OpenAI.get_fine_tune_events(
608
+ # base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
581
609
  # token: 'required - Bearer token',
582
610
  # fine_tune_id: 'required - respective :id value returned from #list_fine_tunes',
583
611
  # timeout: 'optional - timeout in seconds (defaults to 180)'
584
612
  # )
585
613
 
586
614
  public_class_method def self.get_fine_tune_events(opts = {})
615
+ base_uri = opts[:base_uri]
587
616
  token = opts[:token]
588
617
  fine_tune_id = opts[:fine_tune_id]
589
618
  timeout = opts[:timeout]
@@ -591,6 +620,7 @@ module PWN
591
620
  rest_call = "fine_tuning/jobs/#{fine_tune_id}/events"
592
621
 
593
622
  response = open_ai_rest_call(
623
+ base_uri: base_uri,
594
624
  token: token,
595
625
  rest_call: rest_call,
596
626
  timeout: timeout
@@ -603,12 +633,14 @@ module PWN
603
633
 
604
634
  # Supported Method Parameters::
605
635
  # response = PWN::AI::OpenAI.delete_fine_tune_model(
636
+ # base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
606
637
  # token: 'required - Bearer token',
607
638
  # model: 'required - model to delete',
608
639
  # timeout: 'optional - timeout in seconds (defaults to 180)'
609
640
  # )
610
641
 
611
642
  public_class_method def self.delete_fine_tune_model(opts = {})
643
+ base_uri = opts[:base_uri]
612
644
  token = opts[:token]
613
645
  model = opts[:model]
614
646
  timeout = opts[:timeout]
@@ -616,6 +648,7 @@ module PWN
616
648
  rest_call = "models/#{model}"
617
649
 
618
650
  response = open_ai_rest_call(
651
+ base_uri: base_uri,
619
652
  http_method: :delete,
620
653
  token: token,
621
654
  rest_call: rest_call,
@@ -629,15 +662,18 @@ module PWN
629
662
 
630
663
  # Supported Method Parameters::
631
664
  # response = PWN::AI::OpenAI.list_files(
665
+ # base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
632
666
  # token: 'required - Bearer token',
633
667
  # timeout: 'optional - timeout in seconds (defaults to 180)'
634
668
  # )
635
669
 
636
670
  public_class_method def self.list_files(opts = {})
671
+ base_uri = opts[:base_uri]
637
672
  token = opts[:token]
638
673
  timeout = opts[:timeout]
639
674
 
640
675
  response = open_ai_rest_call(
676
+ base_uri: base_uri,
641
677
  token: token,
642
678
  rest_call: 'files',
643
679
  timeout: timeout
@@ -650,6 +686,7 @@ module PWN
650
686
 
651
687
  # Supported Method Parameters::
652
688
  # response = PWN::AI::OpenAI.upload_file(
689
+ # base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
653
690
  # token: 'required - Bearer token',
654
691
  # file: 'required - file to upload',
655
692
  # purpose: 'optional - intended purpose of the uploaded documents (defaults to fine-tune',
@@ -657,6 +694,7 @@ module PWN
657
694
  # )
658
695
 
659
696
  public_class_method def self.upload_file(opts = {})
697
+ base_uri = opts[:base_uri]
660
698
  token = opts[:token]
661
699
  file = opts[:file]
662
700
  raise "ERROR: #{file} not found." unless File.exist?(file)
@@ -672,6 +710,7 @@ module PWN
672
710
  }
673
711
 
674
712
  response = open_ai_rest_call(
713
+ base_uri: base_uri,
675
714
  http_method: :post,
676
715
  token: token,
677
716
  rest_call: 'files',
@@ -686,12 +725,14 @@ module PWN
686
725
 
687
726
  # Supported Method Parameters::
688
727
  # response = PWN::AI::OpenAI.delete_file(
728
+ # base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
689
729
  # token: 'required - Bearer token',
690
730
  # file: 'required - file to delete',
691
731
  # timeout: 'optional - timeout in seconds (defaults to 180)'
692
732
  # )
693
733
 
694
734
  public_class_method def self.delete_file(opts = {})
735
+ base_uri = opts[:base_uri]
695
736
  token = opts[:token]
696
737
  file = opts[:file]
697
738
  timeout = opts[:timeout]
@@ -702,6 +743,7 @@ module PWN
702
743
  rest_call = "files/#{file_id}"
703
744
 
704
745
  response = open_ai_rest_call(
746
+ base_uri: base_uri,
705
747
  http_method: :delete,
706
748
  token: token,
707
749
  rest_call: rest_call,
@@ -715,12 +757,14 @@ module PWN
715
757
 
716
758
  # Supported Method Parameters::
717
759
  # response = PWN::AI::OpenAI.get_file(
760
+ # base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
718
761
  # token: 'required - Bearer token',
719
762
  # file: 'required - file to delete',
720
763
  # timeout: 'optional - timeout in seconds (defaults to 180)'
721
764
  # )
722
765
 
723
766
  public_class_method def self.get_file(opts = {})
767
+ base_uri = opts[:base_uri]
724
768
  token = opts[:token]
725
769
  file = opts[:file]
726
770
  raise "ERROR: #{file} not found." unless File.exist?(file)
@@ -733,6 +777,7 @@ module PWN
733
777
  rest_call = "files/#{file_id}"
734
778
 
735
779
  response = open_ai_rest_call(
780
+ base_uri: base_uri,
736
781
  token: token,
737
782
  rest_call: rest_call,
738
783
  timeout: timeout
@@ -756,11 +801,13 @@ module PWN
756
801
  public_class_method def self.help
757
802
  puts "USAGE:
758
803
  response = #{self}.get_models(
804
+ base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
759
805
  token: 'required - Bearer token',
760
806
  timeout: 'optional - timeout in seconds (defaults to 180)'
761
807
  )
762
808
 
763
809
  response = #{self}.chat(
810
+ base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
764
811
  token: 'required - Bearer token',
765
812
  request: 'required - message to ChatGPT',
766
813
  model: 'optional - model to use for text generation (defaults to gpt-5-chat-latest)',
@@ -773,6 +820,7 @@ module PWN
773
820
  )
774
821
 
775
822
  response = #{self}.img_gen(
823
+ base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
776
824
  token: 'required - Bearer token',
777
825
  request: 'required - message to ChatGPT',
778
826
  n: 'optional - number of images to generate (defaults to 1)',
@@ -781,6 +829,7 @@ module PWN
781
829
  )
782
830
 
783
831
  response = #{self}.vision(
832
+ base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
784
833
  token: 'required - Bearer token',
785
834
  img_path: 'required - path or URI of image to analyze',
786
835
  request: 'optional - message to ChatGPT (defaults to, \"what is in this image?\")',
@@ -792,6 +841,7 @@ module PWN
792
841
  )
793
842
 
794
843
  response = #{self}.create_fine_tune(
844
+ base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
795
845
  token: 'required - Bearer token',
796
846
  training_file: 'required - JSONL that contains OpenAI training data'
797
847
  validation_file: 'optional - JSONL that contains OpenAI validation data'
@@ -808,52 +858,61 @@ module PWN
808
858
  )
809
859
 
810
860
  response = #{self}.list_fine_tunes(
861
+ base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
811
862
  token: 'required - Bearer token',
812
863
  timeout: 'optional - timeout in seconds (defaults to 180)'
813
864
  )
814
865
 
815
866
  response = #{self}.get_fine_tune_status(
867
+ base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
816
868
  token: 'required - Bearer token',
817
869
  fine_tune_id: 'required - respective :id value returned from #list_fine_tunes',
818
870
  timeout: 'optional - timeout in seconds (defaults to 180)'
819
871
  )
820
872
 
821
873
  response = #{self}.cancel_fine_tune(
874
+ base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
822
875
  token: 'required - Bearer token',
823
876
  fine_tune_id: 'required - respective :id value returned from #list_fine_tunes',
824
877
  timeout: 'optional - timeout in seconds (defaults to 180)'
825
878
  )
826
879
 
827
880
  response = #{self}.get_fine_tune_events(
881
+ base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
828
882
  token: 'required - Bearer token',
829
883
  fine_tune_id: 'required - respective :id value returned from #list_fine_tunes',
830
884
  timeout: 'optional - timeout in seconds (defaults to 180)'
831
885
  )
832
886
 
833
887
  response = #{self}.delete_fine_tune_model(
888
+ base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
834
889
  token: 'required - Bearer token',
835
890
  model: 'required - model to delete',
836
891
  timeout: 'optional - timeout in seconds (defaults to 180)'
837
892
  )
838
893
 
839
894
  response = #{self}.list_files(
895
+ base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
840
896
  token: 'required - Bearer token',
841
897
  timeout: 'optional - timeout in seconds (defaults to 180)'
842
898
  )
843
899
 
844
900
  response = #{self}.upload_file(
901
+ base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
845
902
  token: 'required - Bearer token',
846
903
  file: 'required - file to upload',
847
904
  timeout: 'optional - timeout in seconds (defaults to 180)'
848
905
  )
849
906
 
850
907
  response = #{self}.delete_file(
908
+ base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
851
909
  token: 'required - Bearer token',
852
910
  file: 'required - file to delete',
853
911
  timeout: 'optional - timeout in seconds (defaults to 180)'
854
912
  )
855
913
 
856
914
  response = #{self}.get_file(
915
+ base_uri: 'optional - base OpenAI API URI (defaults to https://api.openai.com/v1)',
857
916
  token: 'required - Bearer token',
858
917
  file: 'required - file to delete',
859
918
  timeout: 'optional - timeout in seconds (defaults to 180)'
@@ -360,7 +360,8 @@ module PWN
360
360
  # Supported Method Parameters::
361
361
  # json_sitemap = PWN::Plugins::BurpSuite.get_sitemap(
362
362
  # burp_obj: 'required - burp_obj returned by #start method',
363
- # keyword: 'optional - keyword to filter sitemap entries (default: nil)'
363
+ # keyword: 'optional - keyword to filter sitemap entries (default: nil)',
364
+ # return_as: 'optional - :base64 or :har (defaults to :base64)'
364
365
  # )
365
366
 
366
367
  public_class_method def self.get_sitemap(opts = {})
@@ -368,6 +369,7 @@ module PWN
368
369
  rest_browser = burp_obj[:rest_browser]
369
370
  mitm_rest_api = burp_obj[:mitm_rest_api]
370
371
  keyword = opts[:keyword]
372
+ return_as = opts[:return_as] ||= :base64
371
373
 
372
374
  rest_call = "http://#{mitm_rest_api}/sitemap"
373
375
 
@@ -385,6 +387,151 @@ module PWN
385
387
  end
386
388
  end
387
389
 
390
+ if return_as == :har
391
+ # Convert to HAR format
392
+ har_entries = sitemap_arr.map do |site|
393
+ decoded_request = Base64.strict_decode64(site[:request])
394
+
395
+ # Parse request head and body
396
+ if decoded_request.include?("\r\n\r\n")
397
+ request_head, request_body = decoded_request.split("\r\n\r\n", 2)
398
+ else
399
+ request_head = decoded_request
400
+ request_body = ''
401
+ end
402
+ request_lines = request_head.split("\r\n")
403
+ request_line = request_lines.shift
404
+ method, full_path, http_version = request_line.split(' ', 3)
405
+ headers = {}
406
+ request_lines.each do |line|
407
+ next if line.empty?
408
+
409
+ key, value = line.split(': ', 2)
410
+ headers[key] = value if key && value
411
+ end
412
+
413
+ host = headers['Host'] || raise('No Host header found in request')
414
+ scheme = 'http' # Hardcoded as protocol is not available; consider enhancing if available in site
415
+ url = "#{scheme}://#{host}#{full_path}"
416
+ uri = URI.parse(url)
417
+ query_string = uri.query ? URI.decode_www_form(uri.query).map { |k, v| { name: k, value: v.to_s } } : []
418
+
419
+ request_headers_size = request_head.bytesize + 4 # Account for \r\n\r\n
420
+ request_body_size = request_body.bytesize
421
+
422
+ request_obj = {
423
+ method: method,
424
+ url: uri.to_s,
425
+ httpVersion: http_version,
426
+ headers: headers.map { |k, v| { name: k, value: v } },
427
+ queryString: query_string,
428
+ headersSize: request_headers_size,
429
+ bodySize: request_body_size
430
+ }
431
+
432
+ if request_body_size.positive?
433
+ mime_type = headers['Content-Type'] || 'application/octet-stream'
434
+ post_data = {
435
+ mimeType: mime_type,
436
+ text: request_body
437
+ }
438
+ post_data[:params] = URI.decode_www_form(request_body).map { |k, v| { name: k, value: v.to_s } } if mime_type.include?('x-www-form-urlencoded')
439
+ request_obj[:postData] = post_data
440
+ end
441
+
442
+ if site[:response]
443
+ decoded_response = Base64.strict_decode64(site[:response])
444
+
445
+ # Parse response head and body
446
+ if decoded_response.include?("\r\n\r\n")
447
+ response_head, response_body = decoded_response.split("\r\n\r\n", 2)
448
+ else
449
+ response_head = decoded_response
450
+ response_body = ''
451
+ end
452
+ response_lines = response_head.split("\r\n")
453
+ status_line = response_lines.shift
454
+ version, status_str, status_text = status_line.split(' ', 3)
455
+ status = status_str.to_i
456
+ status_text ||= ''
457
+ response_headers = {}
458
+ response_lines.each do |line|
459
+ next if line.empty?
460
+
461
+ key, value = line.split(': ', 2)
462
+ response_headers[key] = value if key && value
463
+ end
464
+
465
+ response_headers_size = response_head.bytesize + 4 # Account for \r\n\r\n
466
+ response_body_size = response_body.bytesize
467
+ mime_type = response_headers['Content-Type'] || 'text/plain'
468
+
469
+ response_obj = {
470
+ status: status,
471
+ statusText: status_text,
472
+ httpVersion: version,
473
+ headers: response_headers.map { |k, v| { name: k, value: v } },
474
+ content: {
475
+ size: response_body_size,
476
+ mimeType: mime_type,
477
+ text: response_body
478
+ },
479
+ redirectURL: response_headers['Location'] || '',
480
+ headersSize: response_headers_size,
481
+ bodySize: response_body_size
482
+ }
483
+ else
484
+ response_obj = {
485
+ status: 0,
486
+ statusText: 'No response',
487
+ httpVersion: 'unknown',
488
+ headers: [],
489
+ content: {
490
+ size: 0,
491
+ mimeType: 'text/plain',
492
+ text: ''
493
+ },
494
+ redirectURL: '',
495
+ headersSize: -1,
496
+ bodySize: 0
497
+ }
498
+ end
499
+
500
+ {
501
+ startedDateTime: Time.now.iso8601,
502
+ time: 0,
503
+ request: request_obj,
504
+ response: response_obj,
505
+ cache: {},
506
+ timings: {
507
+ send: 0,
508
+ wait: 0,
509
+ receive: 0
510
+ },
511
+ pageref: 'page_1'
512
+ }
513
+ end
514
+
515
+ har_log = {
516
+ log: {
517
+ version: '1.2',
518
+ creator: {
519
+ name: 'BurpSuite via PWN::Plugins::BurpSuite',
520
+ version: '1.0'
521
+ },
522
+ pages: [{
523
+ startedDateTime: Time.now.iso8601,
524
+ id: 'page_1',
525
+ title: 'Sitemap Export',
526
+ pageTimings: {}
527
+ }],
528
+ entries: har_entries
529
+ }
530
+ }
531
+
532
+ sitemap_arr = har_log
533
+ end
534
+
388
535
  sitemap_arr.uniq
389
536
  rescue StandardError => e
390
537
  stop(burp_obj: burp_obj) unless burp_obj.nil?
@@ -1357,7 +1504,8 @@ module PWN
1357
1504
 
1358
1505
  json_sitemap = #{self}.get_sitemap(
1359
1506
  burp_obj: 'required - burp_obj returned by #start method',
1360
- keyword: 'optional - keyword to filter sitemap results (default: nil)'
1507
+ keyword: 'optional - keyword to filter sitemap results (default: nil)',
1508
+ return_as: 'optional - :base64 or :har (defaults to :base64)'
1361
1509
  )
1362
1510
 
1363
1511
  json_sitemap = #{self}.add_to_sitemap(