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.
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