gophish-ruby 0.2.0 → 0.4.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -1
- data/README.md +199 -0
- data/Rakefile +1 -1
- data/docs/API_REFERENCE.md +320 -0
- data/docs/EXAMPLES.md +642 -0
- data/docs/GETTING_STARTED.md +156 -0
- data/lib/gophish/page.rb +56 -0
- data/lib/gophish/smtp.rb +99 -0
- data/lib/gophish/version.rb +1 -1
- data/lib/gophish-ruby.rb +2 -0
- metadata +3 -1
data/docs/EXAMPLES.md
CHANGED
@@ -7,6 +7,7 @@ This document contains practical examples for common use cases with the Gophish
|
|
7
7
|
- [Basic Operations](#basic-operations)
|
8
8
|
- [CSV Operations](#csv-operations)
|
9
9
|
- [Template Operations](#template-operations)
|
10
|
+
- [Page Operations](#page-operations)
|
10
11
|
- [Error Handling](#error-handling)
|
11
12
|
- [Advanced Scenarios](#advanced-scenarios)
|
12
13
|
- [Production Examples](#production-examples)
|
@@ -594,6 +595,647 @@ end
|
|
594
595
|
suite = create_template_suite("Q4 Security Training")
|
595
596
|
```
|
596
597
|
|
598
|
+
## Page Operations
|
599
|
+
|
600
|
+
### Basic Landing Page Creation
|
601
|
+
|
602
|
+
```ruby
|
603
|
+
# Simple landing page without credential capture
|
604
|
+
simple_page = Gophish::Page.new(
|
605
|
+
name: "Generic Thank You Page",
|
606
|
+
html: <<~HTML
|
607
|
+
<!DOCTYPE html>
|
608
|
+
<html>
|
609
|
+
<head>
|
610
|
+
<title>Thank You</title>
|
611
|
+
<style>
|
612
|
+
body {
|
613
|
+
font-family: Arial, sans-serif;
|
614
|
+
text-align: center;
|
615
|
+
background: #f0f0f0;
|
616
|
+
padding: 50px;
|
617
|
+
}
|
618
|
+
.container {
|
619
|
+
max-width: 500px;
|
620
|
+
margin: 0 auto;
|
621
|
+
background: white;
|
622
|
+
padding: 40px;
|
623
|
+
border-radius: 10px;
|
624
|
+
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
625
|
+
}
|
626
|
+
</style>
|
627
|
+
</head>
|
628
|
+
<body>
|
629
|
+
<div class="container">
|
630
|
+
<h1>Thank You!</h1>
|
631
|
+
<p>Your request has been processed successfully.</p>
|
632
|
+
<p>You will receive a confirmation email shortly.</p>
|
633
|
+
</div>
|
634
|
+
</body>
|
635
|
+
</html>
|
636
|
+
HTML
|
637
|
+
)
|
638
|
+
|
639
|
+
if simple_page.save
|
640
|
+
puts "✓ Simple page created: #{simple_page.id}"
|
641
|
+
end
|
642
|
+
```
|
643
|
+
|
644
|
+
### Landing Page with Credential Capture
|
645
|
+
|
646
|
+
```ruby
|
647
|
+
# Microsoft-style login page with credential capture
|
648
|
+
microsoft_page = Gophish::Page.new(
|
649
|
+
name: "Microsoft Office 365 Login Clone",
|
650
|
+
html: <<~HTML,
|
651
|
+
<!DOCTYPE html>
|
652
|
+
<html>
|
653
|
+
<head>
|
654
|
+
<title>Microsoft Office</title>
|
655
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
656
|
+
<style>
|
657
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
658
|
+
body {
|
659
|
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
660
|
+
background: #f5f5f5;
|
661
|
+
display: flex;
|
662
|
+
justify-content: center;
|
663
|
+
align-items: center;
|
664
|
+
min-height: 100vh;
|
665
|
+
}
|
666
|
+
.login-container {
|
667
|
+
background: white;
|
668
|
+
padding: 40px;
|
669
|
+
border-radius: 8px;
|
670
|
+
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
671
|
+
max-width: 400px;
|
672
|
+
width: 100%;
|
673
|
+
}
|
674
|
+
.logo {
|
675
|
+
text-align: center;
|
676
|
+
margin-bottom: 30px;
|
677
|
+
color: #737373;
|
678
|
+
font-size: 24px;
|
679
|
+
font-weight: 300;
|
680
|
+
}
|
681
|
+
h1 {
|
682
|
+
color: #1B1B1B;
|
683
|
+
font-size: 24px;
|
684
|
+
font-weight: 600;
|
685
|
+
margin-bottom: 20px;
|
686
|
+
}
|
687
|
+
.form-group {
|
688
|
+
margin-bottom: 20px;
|
689
|
+
}
|
690
|
+
input[type="email"], input[type="password"] {
|
691
|
+
width: 100%;
|
692
|
+
padding: 12px;
|
693
|
+
border: 1px solid #CCCCCC;
|
694
|
+
border-radius: 4px;
|
695
|
+
font-size: 14px;
|
696
|
+
transition: border-color 0.3s;
|
697
|
+
}
|
698
|
+
input[type="email"]:focus, input[type="password"]:focus {
|
699
|
+
outline: none;
|
700
|
+
border-color: #0078D4;
|
701
|
+
}
|
702
|
+
.signin-button {
|
703
|
+
width: 100%;
|
704
|
+
padding: 12px;
|
705
|
+
background: #0078D4;
|
706
|
+
color: white;
|
707
|
+
border: none;
|
708
|
+
border-radius: 4px;
|
709
|
+
font-size: 14px;
|
710
|
+
font-weight: 600;
|
711
|
+
cursor: pointer;
|
712
|
+
transition: background-color 0.3s;
|
713
|
+
}
|
714
|
+
.signin-button:hover {
|
715
|
+
background: #106EBE;
|
716
|
+
}
|
717
|
+
.footer-links {
|
718
|
+
text-align: center;
|
719
|
+
margin-top: 20px;
|
720
|
+
font-size: 12px;
|
721
|
+
}
|
722
|
+
.footer-links a {
|
723
|
+
color: #0078D4;
|
724
|
+
text-decoration: none;
|
725
|
+
margin: 0 10px;
|
726
|
+
}
|
727
|
+
</style>
|
728
|
+
</head>
|
729
|
+
<body>
|
730
|
+
<div class="login-container">
|
731
|
+
<div class="logo">Microsoft</div>
|
732
|
+
<h1>Sign in</h1>
|
733
|
+
<form method="post" action="">
|
734
|
+
<div class="form-group">
|
735
|
+
<input type="email" name="username" placeholder="Email, phone, or Skype" required>
|
736
|
+
</div>
|
737
|
+
<div class="form-group">
|
738
|
+
<input type="password" name="password" placeholder="Password" required>
|
739
|
+
</div>
|
740
|
+
<button type="submit" class="signin-button">Sign in</button>
|
741
|
+
</form>
|
742
|
+
<div class="footer-links">
|
743
|
+
<a href="#">Can't access your account?</a>
|
744
|
+
<a href="#">Sign-in options</a>
|
745
|
+
</div>
|
746
|
+
</div>
|
747
|
+
</body>
|
748
|
+
</html>
|
749
|
+
HTML
|
750
|
+
capture_credentials: true,
|
751
|
+
capture_passwords: true,
|
752
|
+
redirect_url: "https://office.com"
|
753
|
+
)
|
754
|
+
|
755
|
+
if microsoft_page.save
|
756
|
+
puts "✓ Microsoft login page created: #{microsoft_page.id}"
|
757
|
+
puts " Captures credentials: #{microsoft_page.captures_credentials?}"
|
758
|
+
puts " Captures passwords: #{microsoft_page.captures_passwords?}"
|
759
|
+
puts " Redirects to: #{microsoft_page.redirect_url}"
|
760
|
+
end
|
761
|
+
```
|
762
|
+
|
763
|
+
### Banking Login Page with Enhanced Security Theater
|
764
|
+
|
765
|
+
```ruby
|
766
|
+
# Realistic banking login page
|
767
|
+
banking_page = Gophish::Page.new(
|
768
|
+
name: "SecureBank Online Banking Portal",
|
769
|
+
html: <<~HTML,
|
770
|
+
<!DOCTYPE html>
|
771
|
+
<html>
|
772
|
+
<head>
|
773
|
+
<title>SecureBank - Online Banking</title>
|
774
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
775
|
+
<style>
|
776
|
+
body {
|
777
|
+
font-family: Arial, sans-serif;
|
778
|
+
margin: 0;
|
779
|
+
background: linear-gradient(135deg, #003366, #004499);
|
780
|
+
min-height: 100vh;
|
781
|
+
}
|
782
|
+
.header {
|
783
|
+
background: white;
|
784
|
+
padding: 15px 0;
|
785
|
+
border-bottom: 3px solid #003366;
|
786
|
+
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
787
|
+
}
|
788
|
+
.header-content {
|
789
|
+
max-width: 1200px;
|
790
|
+
margin: 0 auto;
|
791
|
+
padding: 0 20px;
|
792
|
+
display: flex;
|
793
|
+
align-items: center;
|
794
|
+
}
|
795
|
+
.logo {
|
796
|
+
font-size: 24px;
|
797
|
+
font-weight: bold;
|
798
|
+
color: #003366;
|
799
|
+
}
|
800
|
+
.security-badge {
|
801
|
+
margin-left: auto;
|
802
|
+
color: #28a745;
|
803
|
+
font-size: 12px;
|
804
|
+
display: flex;
|
805
|
+
align-items: center;
|
806
|
+
}
|
807
|
+
.security-badge::before {
|
808
|
+
content: "🔒";
|
809
|
+
margin-right: 5px;
|
810
|
+
}
|
811
|
+
.main-content {
|
812
|
+
display: flex;
|
813
|
+
justify-content: center;
|
814
|
+
align-items: center;
|
815
|
+
min-height: calc(100vh - 80px);
|
816
|
+
padding: 40px 20px;
|
817
|
+
}
|
818
|
+
.login-form {
|
819
|
+
background: white;
|
820
|
+
padding: 40px;
|
821
|
+
border-radius: 12px;
|
822
|
+
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
|
823
|
+
max-width: 400px;
|
824
|
+
width: 100%;
|
825
|
+
}
|
826
|
+
.form-title {
|
827
|
+
text-align: center;
|
828
|
+
color: #003366;
|
829
|
+
font-size: 28px;
|
830
|
+
margin-bottom: 30px;
|
831
|
+
font-weight: bold;
|
832
|
+
}
|
833
|
+
.security-notice {
|
834
|
+
background: #E8F4FD;
|
835
|
+
border: 1px solid #B8DAFF;
|
836
|
+
padding: 15px;
|
837
|
+
border-radius: 6px;
|
838
|
+
margin-bottom: 25px;
|
839
|
+
font-size: 14px;
|
840
|
+
color: #0C5460;
|
841
|
+
}
|
842
|
+
.form-group {
|
843
|
+
margin-bottom: 20px;
|
844
|
+
}
|
845
|
+
label {
|
846
|
+
display: block;
|
847
|
+
margin-bottom: 8px;
|
848
|
+
font-weight: bold;
|
849
|
+
color: #003366;
|
850
|
+
}
|
851
|
+
input[type="text"], input[type="password"] {
|
852
|
+
width: 100%;
|
853
|
+
padding: 15px;
|
854
|
+
border: 2px solid #CCC;
|
855
|
+
border-radius: 6px;
|
856
|
+
font-size: 16px;
|
857
|
+
transition: border-color 0.3s;
|
858
|
+
}
|
859
|
+
input[type="text"]:focus, input[type="password"]:focus {
|
860
|
+
outline: none;
|
861
|
+
border-color: #003366;
|
862
|
+
}
|
863
|
+
.login-button {
|
864
|
+
width: 100%;
|
865
|
+
padding: 15px;
|
866
|
+
background: #003366;
|
867
|
+
color: white;
|
868
|
+
border: none;
|
869
|
+
border-radius: 6px;
|
870
|
+
font-size: 18px;
|
871
|
+
font-weight: bold;
|
872
|
+
cursor: pointer;
|
873
|
+
transition: background-color 0.3s;
|
874
|
+
}
|
875
|
+
.login-button:hover {
|
876
|
+
background: #004499;
|
877
|
+
}
|
878
|
+
.footer-text {
|
879
|
+
text-align: center;
|
880
|
+
margin-top: 20px;
|
881
|
+
font-size: 12px;
|
882
|
+
color: #666;
|
883
|
+
}
|
884
|
+
</style>
|
885
|
+
</head>
|
886
|
+
<body>
|
887
|
+
<div class="header">
|
888
|
+
<div class="header-content">
|
889
|
+
<div class="logo">🏛️ SecureBank</div>
|
890
|
+
<div class="security-badge">256-bit SSL Encryption</div>
|
891
|
+
</div>
|
892
|
+
</div>
|
893
|
+
|
894
|
+
<div class="main-content">
|
895
|
+
<div class="login-form">
|
896
|
+
<h1 class="form-title">Secure Login</h1>
|
897
|
+
|
898
|
+
<div class="security-notice">
|
899
|
+
<strong>🔐 Security Notice:</strong> For your protection, please ensure you are on our secure website before entering your credentials.
|
900
|
+
</div>
|
901
|
+
|
902
|
+
<form method="post" action="">
|
903
|
+
<div class="form-group">
|
904
|
+
<label for="username">User ID:</label>
|
905
|
+
<input type="text" id="username" name="username" required autocomplete="username">
|
906
|
+
</div>
|
907
|
+
|
908
|
+
<div class="form-group">
|
909
|
+
<label for="password">Password:</label>
|
910
|
+
<input type="password" id="password" name="password" required autocomplete="current-password">
|
911
|
+
</div>
|
912
|
+
|
913
|
+
<button type="submit" class="login-button">Access My Account</button>
|
914
|
+
</form>
|
915
|
+
|
916
|
+
<div class="footer-text">
|
917
|
+
Your connection is secured with 256-bit encryption<br>
|
918
|
+
© 2024 SecureBank. All rights reserved.
|
919
|
+
</div>
|
920
|
+
</div>
|
921
|
+
</div>
|
922
|
+
</body>
|
923
|
+
</html>
|
924
|
+
HTML
|
925
|
+
capture_credentials: true,
|
926
|
+
capture_passwords: true,
|
927
|
+
redirect_url: "https://www.securebank.com/login-success"
|
928
|
+
)
|
929
|
+
|
930
|
+
if banking_page.save
|
931
|
+
puts "✓ Banking page created: #{banking_page.id}"
|
932
|
+
end
|
933
|
+
```
|
934
|
+
|
935
|
+
### Website Import Examples
|
936
|
+
|
937
|
+
```ruby
|
938
|
+
# Import real websites as landing pages
|
939
|
+
def import_website_examples
|
940
|
+
websites_to_import = [
|
941
|
+
{
|
942
|
+
url: "https://accounts.google.com/signin",
|
943
|
+
name: "Google Login Clone",
|
944
|
+
include_resources: true
|
945
|
+
},
|
946
|
+
{
|
947
|
+
url: "https://login.microsoftonline.com",
|
948
|
+
name: "Microsoft Azure Login Clone",
|
949
|
+
include_resources: false # Faster import, basic styling only
|
950
|
+
},
|
951
|
+
{
|
952
|
+
url: "https://www.paypal.com/signin",
|
953
|
+
name: "PayPal Login Clone",
|
954
|
+
include_resources: true
|
955
|
+
}
|
956
|
+
]
|
957
|
+
|
958
|
+
websites_to_import.each do |site_config|
|
959
|
+
puts "Importing #{site_config[:url]}"
|
960
|
+
|
961
|
+
begin
|
962
|
+
# Import the website
|
963
|
+
imported_data = Gophish::Page.import_site(
|
964
|
+
site_config[:url],
|
965
|
+
include_resources: site_config[:include_resources]
|
966
|
+
)
|
967
|
+
|
968
|
+
# Create page from imported data
|
969
|
+
page = Gophish::Page.new(imported_data)
|
970
|
+
page.name = site_config[:name]
|
971
|
+
page.capture_credentials = true
|
972
|
+
|
973
|
+
if page.save
|
974
|
+
puts " ✓ Successfully imported: #{page.name} (ID: #{page.id})"
|
975
|
+
puts " HTML size: #{page.html.length} characters"
|
976
|
+
puts " Captures credentials: #{page.captures_credentials?}"
|
977
|
+
else
|
978
|
+
puts " ✗ Failed to save: #{page.errors.full_messages.join(', ')}"
|
979
|
+
end
|
980
|
+
|
981
|
+
rescue StandardError => e
|
982
|
+
puts " ✗ Import failed: #{e.message}"
|
983
|
+
|
984
|
+
# Create fallback manual page
|
985
|
+
fallback_page = create_fallback_page(site_config[:name], site_config[:url])
|
986
|
+
if fallback_page
|
987
|
+
puts " ✓ Created fallback page: #{fallback_page.id}"
|
988
|
+
end
|
989
|
+
end
|
990
|
+
|
991
|
+
puts
|
992
|
+
end
|
993
|
+
end
|
994
|
+
|
995
|
+
def create_fallback_page(name, original_url)
|
996
|
+
# Extract domain name for styling
|
997
|
+
domain = URI.parse(original_url).host.gsub('www.', '')
|
998
|
+
|
999
|
+
fallback_page = Gophish::Page.new(
|
1000
|
+
name: "#{name} (Manual Fallback)",
|
1001
|
+
html: <<~HTML,
|
1002
|
+
<html>
|
1003
|
+
<head>
|
1004
|
+
<title>#{domain.capitalize}</title>
|
1005
|
+
<style>
|
1006
|
+
body { font-family: Arial, sans-serif; max-width: 400px; margin: 100px auto; padding: 40px; }
|
1007
|
+
.logo { font-size: 24px; margin-bottom: 30px; text-align: center; color: #333; }
|
1008
|
+
input { width: 100%; padding: 12px; margin: 10px 0; border: 1px solid #ddd; border-radius: 4px; }
|
1009
|
+
button { width: 100%; padding: 12px; background: #1a73e8; color: white; border: none; border-radius: 4px; cursor: pointer; }
|
1010
|
+
button:hover { background: #1557b0; }
|
1011
|
+
</style>
|
1012
|
+
</head>
|
1013
|
+
<body>
|
1014
|
+
<div class="logo">#{domain.capitalize}</div>
|
1015
|
+
<form method="post">
|
1016
|
+
<input type="email" name="username" placeholder="Email" required>
|
1017
|
+
<input type="password" name="password" placeholder="Password" required>
|
1018
|
+
<button type="submit">Sign in</button>
|
1019
|
+
</form>
|
1020
|
+
</body>
|
1021
|
+
</html>
|
1022
|
+
HTML
|
1023
|
+
capture_credentials: true
|
1024
|
+
)
|
1025
|
+
|
1026
|
+
fallback_page.save ? fallback_page : nil
|
1027
|
+
end
|
1028
|
+
|
1029
|
+
# Run the import
|
1030
|
+
import_website_examples
|
1031
|
+
```
|
1032
|
+
|
1033
|
+
### Page Management and Updates
|
1034
|
+
|
1035
|
+
```ruby
|
1036
|
+
# Comprehensive page management
|
1037
|
+
class PageManager
|
1038
|
+
def self.list_all_pages
|
1039
|
+
pages = Gophish::Page.all
|
1040
|
+
puts "Found #{pages.length} landing pages:"
|
1041
|
+
|
1042
|
+
pages.each do |page|
|
1043
|
+
features = []
|
1044
|
+
features << "🔑 Captures Credentials" if page.captures_credentials?
|
1045
|
+
features << "🔒 Captures Passwords" if page.captures_passwords?
|
1046
|
+
features << "🔄 Has Redirect" if page.has_redirect?
|
1047
|
+
|
1048
|
+
feature_text = features.any? ? " [#{features.join(', ')}]" : ""
|
1049
|
+
puts " #{page.id}: #{page.name}#{feature_text}"
|
1050
|
+
|
1051
|
+
if page.has_redirect?
|
1052
|
+
puts " → Redirects to: #{page.redirect_url}"
|
1053
|
+
end
|
1054
|
+
|
1055
|
+
puts " HTML size: #{page.html.length} characters"
|
1056
|
+
puts
|
1057
|
+
end
|
1058
|
+
end
|
1059
|
+
|
1060
|
+
def self.update_page_security(page_id, enable_credential_capture: false, redirect_to: nil)
|
1061
|
+
begin
|
1062
|
+
page = Gophish::Page.find(page_id)
|
1063
|
+
rescue StandardError
|
1064
|
+
puts "✗ Page #{page_id} not found"
|
1065
|
+
return false
|
1066
|
+
end
|
1067
|
+
|
1068
|
+
puts "Updating security settings for '#{page.name}'"
|
1069
|
+
|
1070
|
+
# Update credential capture settings
|
1071
|
+
if enable_credential_capture
|
1072
|
+
page.capture_credentials = true
|
1073
|
+
page.capture_passwords = true
|
1074
|
+
puts " ✓ Enabled credential capture"
|
1075
|
+
else
|
1076
|
+
page.capture_credentials = false
|
1077
|
+
page.capture_passwords = false
|
1078
|
+
puts " ✓ Disabled credential capture"
|
1079
|
+
end
|
1080
|
+
|
1081
|
+
# Update redirect URL
|
1082
|
+
if redirect_to
|
1083
|
+
page.redirect_url = redirect_to
|
1084
|
+
puts " ✓ Set redirect URL: #{redirect_to}"
|
1085
|
+
end
|
1086
|
+
|
1087
|
+
if page.save
|
1088
|
+
puts " ✓ Page updated successfully"
|
1089
|
+
true
|
1090
|
+
else
|
1091
|
+
puts " ✗ Update failed: #{page.errors.full_messages.join(', ')}"
|
1092
|
+
false
|
1093
|
+
end
|
1094
|
+
end
|
1095
|
+
|
1096
|
+
def self.clone_page(original_id, new_name, modifications = {})
|
1097
|
+
begin
|
1098
|
+
original = Gophish::Page.find(original_id)
|
1099
|
+
rescue StandardError
|
1100
|
+
puts "✗ Original page #{original_id} not found"
|
1101
|
+
return nil
|
1102
|
+
end
|
1103
|
+
|
1104
|
+
# Create clone
|
1105
|
+
cloned_page = Gophish::Page.new(
|
1106
|
+
name: new_name,
|
1107
|
+
html: original.html,
|
1108
|
+
capture_credentials: original.capture_credentials,
|
1109
|
+
capture_passwords: original.capture_passwords,
|
1110
|
+
redirect_url: original.redirect_url
|
1111
|
+
)
|
1112
|
+
|
1113
|
+
# Apply modifications
|
1114
|
+
modifications.each do |field, value|
|
1115
|
+
cloned_page.send("#{field}=", value) if cloned_page.respond_to?("#{field}=")
|
1116
|
+
end
|
1117
|
+
|
1118
|
+
if cloned_page.save
|
1119
|
+
puts "✓ Page cloned successfully: '#{new_name}' (ID: #{cloned_page.id})"
|
1120
|
+
cloned_page
|
1121
|
+
else
|
1122
|
+
puts "✗ Clone failed: #{cloned_page.errors.full_messages.join(', ')}"
|
1123
|
+
nil
|
1124
|
+
end
|
1125
|
+
end
|
1126
|
+
end
|
1127
|
+
|
1128
|
+
# Usage examples
|
1129
|
+
PageManager.list_all_pages
|
1130
|
+
|
1131
|
+
# Enable security features on an existing page
|
1132
|
+
PageManager.update_page_security(
|
1133
|
+
1,
|
1134
|
+
enable_credential_capture: true,
|
1135
|
+
redirect_to: "https://legitimate-site.com"
|
1136
|
+
)
|
1137
|
+
|
1138
|
+
# Clone a page with modifications
|
1139
|
+
PageManager.clone_page(
|
1140
|
+
1,
|
1141
|
+
"Modified Banking Page",
|
1142
|
+
{
|
1143
|
+
capture_passwords: false,
|
1144
|
+
redirect_url: "https://different-redirect.com"
|
1145
|
+
}
|
1146
|
+
)
|
1147
|
+
```
|
1148
|
+
|
1149
|
+
### A/B Testing with Multiple Page Variants
|
1150
|
+
|
1151
|
+
```ruby
|
1152
|
+
# Create multiple variants of the same phishing page for testing
|
1153
|
+
def create_page_variants(base_name, base_html, variants)
|
1154
|
+
created_pages = []
|
1155
|
+
|
1156
|
+
variants.each_with_index do |variant, index|
|
1157
|
+
variant_name = "#{base_name} - #{variant[:name]}"
|
1158
|
+
|
1159
|
+
# Start with base HTML
|
1160
|
+
modified_html = base_html.dup
|
1161
|
+
|
1162
|
+
# Apply modifications
|
1163
|
+
variant[:modifications].each do |search, replace|
|
1164
|
+
modified_html.gsub!(search, replace)
|
1165
|
+
end
|
1166
|
+
|
1167
|
+
page = Gophish::Page.new(
|
1168
|
+
name: variant_name,
|
1169
|
+
html: modified_html,
|
1170
|
+
capture_credentials: variant[:capture_credentials] || true,
|
1171
|
+
capture_passwords: variant[:capture_passwords] || true,
|
1172
|
+
redirect_url: variant[:redirect_url]
|
1173
|
+
)
|
1174
|
+
|
1175
|
+
if page.save
|
1176
|
+
puts "✓ Created variant #{index + 1}: #{variant_name} (ID: #{page.id})"
|
1177
|
+
created_pages << page
|
1178
|
+
else
|
1179
|
+
puts "✗ Failed to create variant #{index + 1}: #{page.errors.full_messages.join(', ')}"
|
1180
|
+
end
|
1181
|
+
end
|
1182
|
+
|
1183
|
+
created_pages
|
1184
|
+
end
|
1185
|
+
|
1186
|
+
# Example: Create different urgency levels for the same login page
|
1187
|
+
base_html = <<~HTML
|
1188
|
+
<html>
|
1189
|
+
<head><title>Account Security</title></head>
|
1190
|
+
<body>
|
1191
|
+
<h1>URGENCY_LEVEL</h1>
|
1192
|
+
<p>MESSAGE_TEXT</p>
|
1193
|
+
<form method="post">
|
1194
|
+
<input type="email" name="username" placeholder="Email" required>
|
1195
|
+
<input type="password" name="password" placeholder="Password" required>
|
1196
|
+
<button type="submit" style="background: BUTTON_COLOR;">BUTTON_TEXT</button>
|
1197
|
+
</form>
|
1198
|
+
</body>
|
1199
|
+
</html>
|
1200
|
+
HTML
|
1201
|
+
|
1202
|
+
variants = [
|
1203
|
+
{
|
1204
|
+
name: "Low Urgency",
|
1205
|
+
modifications: {
|
1206
|
+
"URGENCY_LEVEL" => "Account Update Available",
|
1207
|
+
"MESSAGE_TEXT" => "Please update your account information at your convenience.",
|
1208
|
+
"BUTTON_COLOR" => "#0078d4",
|
1209
|
+
"BUTTON_TEXT" => "Update Account"
|
1210
|
+
},
|
1211
|
+
redirect_url: "https://microsoft.com"
|
1212
|
+
},
|
1213
|
+
{
|
1214
|
+
name: "Medium Urgency",
|
1215
|
+
modifications: {
|
1216
|
+
"URGENCY_LEVEL" => "Security Alert",
|
1217
|
+
"MESSAGE_TEXT" => "We detected unusual activity. Please verify your account.",
|
1218
|
+
"BUTTON_COLOR" => "#ff8c00",
|
1219
|
+
"BUTTON_TEXT" => "Verify Now"
|
1220
|
+
},
|
1221
|
+
redirect_url: "https://microsoft.com/security"
|
1222
|
+
},
|
1223
|
+
{
|
1224
|
+
name: "High Urgency",
|
1225
|
+
modifications: {
|
1226
|
+
"URGENCY_LEVEL" => "IMMEDIATE ACTION REQUIRED",
|
1227
|
+
"MESSAGE_TEXT" => "Your account will be suspended in 24 hours! Login immediately.",
|
1228
|
+
"BUTTON_COLOR" => "#dc3545",
|
1229
|
+
"BUTTON_TEXT" => "SAVE MY ACCOUNT"
|
1230
|
+
},
|
1231
|
+
redirect_url: "https://microsoft.com/urgent"
|
1232
|
+
}
|
1233
|
+
]
|
1234
|
+
|
1235
|
+
pages = create_page_variants("Microsoft Security Alert", base_html, variants)
|
1236
|
+
puts "\nCreated #{pages.length} page variants for A/B testing"
|
1237
|
+
```
|
1238
|
+
|
597
1239
|
## Error Handling
|
598
1240
|
|
599
1241
|
### Comprehensive Error Handling
|