evil_faker 0.1.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.
Files changed (135) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +62 -0
  3. data/GENERATORS.md +164 -0
  4. data/LICENSE.txt +21 -0
  5. data/NOTICE.md +196 -0
  6. data/README.md +156 -0
  7. data/Rakefile +12 -0
  8. data/lib/evil_faker/base.rb +50 -0
  9. data/lib/evil_faker/data/blns.txt +742 -0
  10. data/lib/evil_faker/data/groups/blns/emoji/emoji.txt +10 -0
  11. data/lib/evil_faker/data/groups/blns/emoji/emoticons.txt +12 -0
  12. data/lib/evil_faker/data/groups/blns/emoji/regional.txt +3 -0
  13. data/lib/evil_faker/data/groups/blns/exploits/cves.txt +4 -0
  14. data/lib/evil_faker/data/groups/blns/exploits/human.txt +1 -0
  15. data/lib/evil_faker/data/groups/blns/exploits/ios.txt +3 -0
  16. data/lib/evil_faker/data/groups/blns/exploits/irc.txt +1 -0
  17. data/lib/evil_faker/data/groups/blns/filenames.txt +14 -0
  18. data/lib/evil_faker/data/groups/blns/injection/command.txt +6 -0
  19. data/lib/evil_faker/data/groups/blns/injection/file_inclusion.txt +2 -0
  20. data/lib/evil_faker/data/groups/blns/injection/interpolation.txt +9 -0
  21. data/lib/evil_faker/data/groups/blns/injection/jinja2.txt +2 -0
  22. data/lib/evil_faker/data/groups/blns/injection/script.txt +236 -0
  23. data/lib/evil_faker/data/groups/blns/injection/server_code.txt +9 -0
  24. data/lib/evil_faker/data/groups/blns/injection/sql.txt +8 -0
  25. data/lib/evil_faker/data/groups/blns/injection/xxe.txt +1 -0
  26. data/lib/evil_faker/data/groups/blns/numeric/numeric.txt +71 -0
  27. data/lib/evil_faker/data/groups/blns/numeric/unicode_numbers.txt +2 -0
  28. data/lib/evil_faker/data/groups/blns/profanity.txt +22 -0
  29. data/lib/evil_faker/data/groups/blns/reserved.txt +19 -0
  30. data/lib/evil_faker/data/groups/blns/rtl.txt +7 -0
  31. data/lib/evil_faker/data/groups/blns/terminal.txt +3 -0
  32. data/lib/evil_faker/data/groups/blns/unicode/accents.txt +4 -0
  33. data/lib/evil_faker/data/groups/blns/unicode/bom.txt +2 -0
  34. data/lib/evil_faker/data/groups/blns/unicode/controls.txt +3 -0
  35. data/lib/evil_faker/data/groups/blns/unicode/font.txt +8 -0
  36. data/lib/evil_faker/data/groups/blns/unicode/lowercase.txt +2 -0
  37. data/lib/evil_faker/data/groups/blns/unicode/quotes.txt +11 -0
  38. data/lib/evil_faker/data/groups/blns/unicode/scripts.txt +2 -0
  39. data/lib/evil_faker/data/groups/blns/unicode/special.txt +4 -0
  40. data/lib/evil_faker/data/groups/blns/unicode/symbols.txt +12 -0
  41. data/lib/evil_faker/data/groups/blns/unicode/trick.txt +5 -0
  42. data/lib/evil_faker/data/groups/blns/unicode/two_byte.txt +10 -0
  43. data/lib/evil_faker/data/groups/blns/unicode/upsidedown.txt +2 -0
  44. data/lib/evil_faker/data/groups/blns/unicode/whitespace.txt +1 -0
  45. data/lib/evil_faker/data/groups/blns/zalgo.txt +5 -0
  46. data/lib/evil_faker/data/groups/fuzzdb/email/invalid.txt +26 -0
  47. data/lib/evil_faker/data/groups/fuzzdb/email/valid.txt +32 -0
  48. data/lib/evil_faker/data/groups/fuzzdb/emoji/emoji.txt +8 -0
  49. data/lib/evil_faker/data/groups/fuzzdb/emoji/emoticons.txt +11 -0
  50. data/lib/evil_faker/data/groups/fuzzdb/emoji/regional.txt +3 -0
  51. data/lib/evil_faker/data/groups/fuzzdb/exploits/ios.txt +1 -0
  52. data/lib/evil_faker/data/groups/fuzzdb/headers/mimetypes.txt +1864 -0
  53. data/lib/evil_faker/data/groups/fuzzdb/headers/protocol.txt +357 -0
  54. data/lib/evil_faker/data/groups/fuzzdb/injection/command.txt +1115 -0
  55. data/lib/evil_faker/data/groups/fuzzdb/injection/directory_traversal.txt +536 -0
  56. data/lib/evil_faker/data/groups/fuzzdb/injection/file_inclusion.txt +906 -0
  57. data/lib/evil_faker/data/groups/fuzzdb/injection/file_upload_bypass.txt +371 -0
  58. data/lib/evil_faker/data/groups/fuzzdb/injection/format_strings.txt +67 -0
  59. data/lib/evil_faker/data/groups/fuzzdb/injection/generic.txt +584 -0
  60. data/lib/evil_faker/data/groups/fuzzdb/injection/integer_overflow.txt +12 -0
  61. data/lib/evil_faker/data/groups/fuzzdb/injection/json.txt +89 -0
  62. data/lib/evil_faker/data/groups/fuzzdb/injection/ldap.txt +35 -0
  63. data/lib/evil_faker/data/groups/fuzzdb/injection/magic_hashes.txt +24 -0
  64. data/lib/evil_faker/data/groups/fuzzdb/injection/nosql.txt +17 -0
  65. data/lib/evil_faker/data/groups/fuzzdb/injection/open_redirect.txt +37 -0
  66. data/lib/evil_faker/data/groups/fuzzdb/injection/rfi.txt +2241 -0
  67. data/lib/evil_faker/data/groups/fuzzdb/injection/script.txt +930 -0
  68. data/lib/evil_faker/data/groups/fuzzdb/injection/server_side_include.txt +78 -0
  69. data/lib/evil_faker/data/groups/fuzzdb/injection/source_disclosure.txt +18 -0
  70. data/lib/evil_faker/data/groups/fuzzdb/injection/sql.txt +661 -0
  71. data/lib/evil_faker/data/groups/fuzzdb/injection/ssrf.txt +56 -0
  72. data/lib/evil_faker/data/groups/fuzzdb/injection/type_confusion.txt +329 -0
  73. data/lib/evil_faker/data/groups/fuzzdb/injection/xpath.txt +13 -0
  74. data/lib/evil_faker/data/groups/fuzzdb/injection/xxe.txt +65 -0
  75. data/lib/evil_faker/data/groups/fuzzdb/routes/debug_params.txt +157 -0
  76. data/lib/evil_faker/data/groups/fuzzdb/routes/directory_indexing.txt +15 -0
  77. data/lib/evil_faker/data/groups/fuzzdb/routes/local_paths.txt +26 -0
  78. data/lib/evil_faker/data/groups/fuzzdb/rtl.txt +5 -0
  79. data/lib/evil_faker/data/groups/fuzzdb/terminal.txt +3 -0
  80. data/lib/evil_faker/data/groups/fuzzdb/unicode/bad_chars.txt +15 -0
  81. data/lib/evil_faker/data/groups/fuzzdb/unicode/special.txt +31 -0
  82. data/lib/evil_faker/data/groups/fuzzdb/unicode/trick.txt +5 -0
  83. data/lib/evil_faker/data/groups/fuzzdb/unicode/two_byte.txt +9 -0
  84. data/lib/evil_faker/data/groups/fuzzdb/unicode/upsidedown.txt +2 -0
  85. data/lib/evil_faker/data/groups/intruder_payloads/filenames.txt +124 -0
  86. data/lib/evil_faker/data/groups/intruder_payloads/injection/command.txt +445 -0
  87. data/lib/evil_faker/data/groups/intruder_payloads/injection/directory_traversal.txt +2578 -0
  88. data/lib/evil_faker/data/groups/intruder_payloads/injection/file_inclusion.txt +698 -0
  89. data/lib/evil_faker/data/groups/intruder_payloads/injection/generic.txt +1401 -0
  90. data/lib/evil_faker/data/groups/intruder_payloads/injection/overflow.txt +36 -0
  91. data/lib/evil_faker/data/groups/intruder_payloads/injection/script.txt +61 -0
  92. data/lib/evil_faker/data/groups/intruder_payloads/injection/server_side_include.txt +18 -0
  93. data/lib/evil_faker/data/groups/intruder_payloads/injection/sql.txt +753 -0
  94. data/lib/evil_faker/data/groups/intruder_payloads/injection/xxe.txt +66 -0
  95. data/lib/evil_faker/data/groups/intruder_payloads/unicode/bad_chars.txt +1 -0
  96. data/lib/evil_faker/data/groups/payloads_all_the_things/headers/cache_deception.txt +1125 -0
  97. data/lib/evil_faker/data/groups/payloads_all_the_things/injection/command.txt +496 -0
  98. data/lib/evil_faker/data/groups/payloads_all_the_things/injection/directory_traversal.txt +22607 -0
  99. data/lib/evil_faker/data/groups/payloads_all_the_things/injection/file_inclusion.txt +4787 -0
  100. data/lib/evil_faker/data/groups/payloads_all_the_things/injection/ldap.txt +60 -0
  101. data/lib/evil_faker/data/groups/payloads_all_the_things/injection/nosql.txt +26 -0
  102. data/lib/evil_faker/data/groups/payloads_all_the_things/injection/open_redirect.txt +305 -0
  103. data/lib/evil_faker/data/groups/payloads_all_the_things/injection/script.txt +2165 -0
  104. data/lib/evil_faker/data/groups/payloads_all_the_things/injection/sql.txt +1354 -0
  105. data/lib/evil_faker/data/groups/payloads_all_the_things/injection/ssti.txt +105 -0
  106. data/lib/evil_faker/data/groups/payloads_all_the_things/injection/xxe.txt +102 -0
  107. data/lib/evil_faker/data/groups/payloads_all_the_things/routes/admin_interfaces.txt +52 -0
  108. data/lib/evil_faker/groups/email.rb +11 -0
  109. data/lib/evil_faker/groups/emoji.rb +12 -0
  110. data/lib/evil_faker/groups/exploits.rb +13 -0
  111. data/lib/evil_faker/groups/filenames.rb +8 -0
  112. data/lib/evil_faker/groups/headers.rb +12 -0
  113. data/lib/evil_faker/groups/injection.rb +35 -0
  114. data/lib/evil_faker/groups/numeric.rb +11 -0
  115. data/lib/evil_faker/groups/profanity.rb +8 -0
  116. data/lib/evil_faker/groups/reserved.rb +8 -0
  117. data/lib/evil_faker/groups/routes.rb +13 -0
  118. data/lib/evil_faker/groups/rtl.rb +8 -0
  119. data/lib/evil_faker/groups/terminal.rb +8 -0
  120. data/lib/evil_faker/groups/unicode.rb +23 -0
  121. data/lib/evil_faker/groups/zalgo.rb +8 -0
  122. data/lib/evil_faker/source_base.rb +30 -0
  123. data/lib/evil_faker/sources/blns.rb +8 -0
  124. data/lib/evil_faker/sources/fuzzdb.rb +8 -0
  125. data/lib/evil_faker/sources/intruder_payloads.rb +8 -0
  126. data/lib/evil_faker/sources/payloads_all_the_things.rb +8 -0
  127. data/lib/evil_faker/version.rb +5 -0
  128. data/lib/evil_faker.rb +13 -0
  129. data/scripts/blns_build_corpus.rb +159 -0
  130. data/scripts/fuzzdb_build_corpus.rb +166 -0
  131. data/scripts/generate_namespaces.rb +87 -0
  132. data/scripts/intruder_payloads_build_corpus.rb +112 -0
  133. data/scripts/payloads_all_the_things_build_corpus.rb +74 -0
  134. data/sig/evil_faker.rbs +4 -0
  135. metadata +181 -0
@@ -0,0 +1,159 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Regenerates the per-group corpus files from lib/evil_faker/data/blns.txt
4
+ # (Big List of Naughty Strings, MIT, Max Woolf -- github.com/minimaxir/big-list-of-naughty-strings).
5
+ #
6
+ # Output: lib/evil_faker/data/groups/blns/<namespace>.txt (single-topic namespaces)
7
+ # lib/evil_faker/data/groups/blns/<namespace>/<slug>.txt (namespaces with several sub-groups)
8
+ #
9
+ # Nested under blns/ because that's the source -- other sources get their own
10
+ # sibling folder (groups/payloads_all_the_things/, groups/intruder_payloads/),
11
+ # never mixed into this one.
12
+ #
13
+ # Usage: ruby scripts/blns_build_corpus.rb
14
+
15
+ ROOT = File.expand_path("..", __dir__)
16
+ OUT_DIR = File.join(ROOT, "lib/evil_faker/data/groups/blns")
17
+
18
+ BLNS_SOURCE = File.join(ROOT, "lib/evil_faker/data/blns.txt")
19
+
20
+ # Map: namespace -> { slug -> [title patterns] }.
21
+ # Patterns are matched as case-insensitive substrings against a section's title.
22
+ # Order matters: the first (namespace, slug) whose patterns match wins.
23
+ GROUPS = {
24
+ "injection" => {
25
+ "script" => ["Script Injection"],
26
+ "sql" => ["SQL Injection"],
27
+ "server_code" => ["Server Code Injection"],
28
+ "command" => ["Command Injection"],
29
+ "xxe" => ["XXE Injection"],
30
+ "interpolation" => ["Unwanted Interpolation"],
31
+ "file_inclusion" => ["File Inclusion"],
32
+ "jinja2" => ["jinja2 injection"]
33
+ },
34
+ "exploits" => {
35
+ "cves" => ["Known CVEs"],
36
+ "irc" => ["IRC specific"],
37
+ "human" => ["Human injection"],
38
+ "ios" => ["iOS Vulnerabilities"]
39
+ },
40
+ "emoji" => {
41
+ "emoji" => ["Emoji"],
42
+ "regional" => ["Regional Indicator"],
43
+ "emoticons" => ["Japanese Emoticons"]
44
+ },
45
+ "numeric" => {
46
+ "numeric" => ["Numeric Strings"],
47
+ "unicode_numbers" => ["Unicode Numbers"]
48
+ },
49
+ "reserved" => { "reserved" => ["Reserved Strings"] },
50
+ "rtl" => { "rtl" => ["Right-To-Left"] },
51
+ "zalgo" => { "zalgo" => ["Zalgo"] },
52
+ "filenames" => { "filenames" => ["MSDOS/Windows Special Filenames"] },
53
+ "profanity" => { "profanity" => ["Scunthorpe"] },
54
+ "terminal" => { "terminal" => ["Terminal escape codes"] },
55
+ # Catch-all for unicode weirdness: anything that breaks by rendering/encoding, not an attack.
56
+ # Kept last: its patterns are broad and would swallow more specific sections above.
57
+ "unicode" => {
58
+ "special" => ["Special Characters"],
59
+ "controls" => ["Non-whitespace C0", "Non-whitespace C1", "Unicode additional control"],
60
+ "whitespace" => ["Whitespace:"],
61
+ "bom" => ["Byte order marks"],
62
+ "symbols" => ["Unicode Symbols", "Special Unicode Characters Union"],
63
+ "accents" => ["Unicode Subscript/Superscript/Accents"],
64
+ "quotes" => ["Quotation Marks"],
65
+ "two_byte" => ["Two-Byte Characters", "two-byte letters"],
66
+ "lowercase" => ["Changing length when lowercased"],
67
+ "scripts" => ["Ogham", "Persian special characters"],
68
+ "trick" => ["Trick Unicode"],
69
+ "upsidedown" => ["Unicode Upsidedown"],
70
+ "font" => ["Unicode font"]
71
+ }
72
+ }.freeze
73
+
74
+ # Namespaces with exactly one slug get a flat file (groups/<namespace>.txt) instead
75
+ # of a folder with a single file in it.
76
+ FLAT_NAMESPACES = %w[reserved rtl zalgo filenames profanity terminal].freeze
77
+
78
+ # --- parse: raw BLNS section -> [strings] ---
79
+ class SectionParser
80
+ attr_reader :sections
81
+
82
+ def initialize
83
+ @sections = []
84
+ @prev_comment = false
85
+ @current = nil
86
+ end
87
+
88
+ def feed(line)
89
+ if line.start_with?("#")
90
+ start_section(line) unless @prev_comment
91
+ @prev_comment = true
92
+ else
93
+ @prev_comment = false
94
+ @current[:strings] << line if @current && !line.empty?
95
+ end
96
+ end
97
+
98
+ private
99
+
100
+ def start_section(line)
101
+ @current = { title: line.sub(/^#\s*/, "").strip, strings: [] }
102
+ @sections << @current
103
+ end
104
+ end
105
+
106
+ def parse_sections(path)
107
+ parser = SectionParser.new
108
+ File.readlines(path, chomp: true).each { |line| parser.feed(line) }
109
+ parser.sections
110
+ end
111
+
112
+ # --- classify each section into a (namespace, slug) ---
113
+ def classify(title)
114
+ GROUPS.each do |ns, slugs|
115
+ slugs.each do |slug, patterns|
116
+ return [ns, slug] if patterns.any? { |p| title.downcase.include?(p.downcase) }
117
+ end
118
+ end
119
+ nil
120
+ end
121
+
122
+ sections = parse_sections(BLNS_SOURCE)
123
+
124
+ buckets = Hash.new { |h, k| h[k] = Hash.new { |hh, kk| hh[kk] = [] } }
125
+ unmatched = []
126
+ sections.each do |sec|
127
+ ns_slug = classify(sec[:title])
128
+ if ns_slug
129
+ buckets[ns_slug.first][ns_slug.last].concat(sec[:strings])
130
+ else
131
+ unmatched << sec[:title]
132
+ end
133
+ end
134
+
135
+ # --- write one file per (namespace, slug), no headers: the path is the group ---
136
+ require "fileutils"
137
+ # Wipe first: a section BLNS removes/renames must not leave a stale file behind
138
+ # for Base's subtype auto-discovery to pick up.
139
+ FileUtils.rm_rf(OUT_DIR)
140
+ FileUtils.mkdir_p(OUT_DIR)
141
+
142
+ buckets.each do |ns, slugs|
143
+ flat = FLAT_NAMESPACES.include?(ns)
144
+ FileUtils.mkdir_p(File.join(OUT_DIR, ns)) unless flat
145
+
146
+ slugs.each do |slug, strings|
147
+ path = flat ? File.join(OUT_DIR, "#{ns}.txt") : File.join(OUT_DIR, ns, "#{slug}.txt")
148
+ File.open(path, "w") { |f| strings.each { |s| f.puts s } }
149
+ printf(" %<path>-40s %<count>3d strings\n", path: path.sub("#{OUT_DIR}/", ""), count: strings.size)
150
+ end
151
+ end
152
+
153
+ puts
154
+ if unmatched.empty?
155
+ puts "OK: all sections classified."
156
+ else
157
+ puts "UNCLASSIFIED (#{unmatched.size}):"
158
+ unmatched.each { |t| puts " - #{t[0, 70]}" }
159
+ end
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Vendors fuzzdb-project/fuzzdb's attack/ folder into
4
+ # lib/evil_faker/data/groups/fuzzdb/. Only attack/ is vendored -- discovery/,
5
+ # wordlists-misc/, wordlists-user-passwd/, web-backdoors/, docs/ and regex/
6
+ # are recon wordlists/tooling, out of scope (same criterion used for every
7
+ # other source: adversarial field input, not discovery/credential wordlists).
8
+ #
9
+ # fuzzdb has no declared license (no LICENSE file, license: null via the
10
+ # GitHub API), same gap as IntruderPayloads -- vendored anyway per explicit
11
+ # call. See NOTICE.md.
12
+ #
13
+ # Heavy overlap with payloads_all_the_things/ is expected and accepted: that
14
+ # source's SQL/traversal/command lists were themselves copied from fuzzdb
15
+ # (several files share the exact same name, e.g. traversals-8-deep-exotic-
16
+ # encoding.txt). Base already dedupes within a merged subtype's file list
17
+ # isn't performed across files at read time, but each importer dedupes its
18
+ # own output, so cross-source duplicate lines just mean a slightly larger
19
+ # corpus, not broken data.
20
+ #
21
+ # attack/file-upload/malicious-images/ is skipped: real binary POC files
22
+ # (images, an EICAR test string file), not text payloads.
23
+ #
24
+ # attack/xss/JHADDIX_XSS_WITH_CONTEXT.doc.txt is skipped: it's prose
25
+ # ("Exploit Name: ... Exploit String: ... Exploit Description: ...") not
26
+ # one payload per line -- importing it raw would inject description text
27
+ # as if it were a payload.
28
+ #
29
+ # Requires the `gh` CLI, authenticated (`gh auth status`).
30
+ #
31
+ # Usage: ruby scripts/fuzzdb_build_corpus.rb
32
+
33
+ require "open3"
34
+ require "fileutils"
35
+ require "json"
36
+
37
+ ROOT = File.expand_path("..", __dir__)
38
+ OUT_DIR = File.join(ROOT, "lib/evil_faker/data/groups/fuzzdb")
39
+ REPO = "fuzzdb-project/fuzzdb"
40
+
41
+ SKIP_FILES = ["README.md", "Readme.md", "docs.http-method-defs.html", "JHADDIX_XSS_WITH_CONTEXT.doc.txt"].freeze
42
+
43
+ # upstream attack/ folder -> [EvilFaker namespace, subtype]. Multiple folders
44
+ # can feed the same subtype (they're concatenated).
45
+ SOURCES = {
46
+ "attack/sql-injection/detect" => %w[injection sql],
47
+ "attack/sql-injection/exploit" => %w[injection sql],
48
+ "attack/sql-injection/payloads-sql-blind" => %w[injection sql],
49
+ "attack/xss" => %w[injection script],
50
+ "attack/html_js_fuzz" => %w[injection script],
51
+ "attack/xml" => %w[injection xxe],
52
+ "attack/os-cmd-execution" => %w[injection command],
53
+ "attack/string-expansion" => %w[injection command],
54
+ "attack/lfi" => %w[injection file_inclusion],
55
+ "attack/path-traversal" => %w[injection directory_traversal],
56
+ "attack/redirect" => %w[injection open_redirect],
57
+ "attack/no-sql-injection" => %w[injection nosql],
58
+ "attack/ldap" => %w[injection ldap],
59
+ "attack/server-side-include" => %w[injection server_side_include],
60
+ "attack/all-attacks" => %w[injection generic],
61
+ "attack/xpath" => %w[injection xpath],
62
+ "attack/integer-overflow" => %w[injection integer_overflow],
63
+ "attack/rfi" => %w[injection rfi],
64
+ "attack/ip" => %w[injection ssrf],
65
+ "attack/json" => %w[injection json],
66
+ "attack/format-strings" => %w[injection format_strings],
67
+ "attack/authentication" => %w[injection magic_hashes],
68
+ "attack/disclosure-source" => %w[injection source_disclosure],
69
+ "attack/file-upload" => %w[injection file_upload_bypass],
70
+ "attack/control-chars" => %w[injection type_confusion],
71
+ "attack/business-logic" => %w[routes debug_params],
72
+ "attack/disclosure-directory" => %w[routes directory_indexing],
73
+ "attack/os-dir-indexing" => %w[routes directory_indexing],
74
+ "attack/disclosure-localpaths/unix" => %w[routes local_paths],
75
+ "attack/http-protocol" => %w[headers protocol],
76
+ "attack/mimetypes" => %w[headers mimetypes]
77
+ }.freeze
78
+
79
+ # folder -> plain filename (no subtype bucket), merged into existing flat/
80
+ # subtyped namespaces from other sources.
81
+ MERGE_SOURCES = {
82
+ "attack/control-chars/terminal-escape-codes.txt" => %w[terminal], # flat: EvilFaker::Terminal
83
+ "attack/control-chars/imessage.txt" => %w[exploits ios],
84
+ "attack/unicode/specialchars.txt" => %w[unicode special],
85
+ "attack/unicode/two-byte-chars.txt" => %w[unicode two_byte],
86
+ "attack/unicode/upsidedown.txt" => %w[unicode upsidedown],
87
+ "attack/unicode/corrupted.txt" => %w[unicode trick],
88
+ "attack/unicode/naughty-unicode.txt" => %w[unicode bad_chars],
89
+ "attack/unicode/emoji.txt" => %w[emoji emoji],
90
+ "attack/unicode/japanese-emoticon.txt" => %w[emoji emoticons],
91
+ "attack/unicode/regionalindicators.txt" => %w[emoji regional],
92
+ "attack/unicode/right-to-left.txt" => %w[rtl] # flat: EvilFaker::Rtl
93
+ }.freeze
94
+
95
+ # a NEW namespace, Faker-parity: valid/invalid edge-case emails instead of
96
+ # realistic ones.
97
+ EMAIL_SOURCES = {
98
+ "attack/email/valid-email-addresses.txt" => "valid",
99
+ "attack/email/invalid-email-addresses.txt" => "invalid"
100
+ }.freeze
101
+
102
+ def gh_json(path)
103
+ out, status = Open3.capture2("gh", "api", "repos/#{REPO}/contents/#{path}")
104
+ raise "gh api failed for #{path}" unless status.success?
105
+
106
+ JSON.parse(out)
107
+ end
108
+
109
+ def gh_raw(path)
110
+ out, status = Open3.capture2(
111
+ "gh", "api", "-H", "Accept: application/vnd.github.raw", "repos/#{REPO}/contents/#{path}"
112
+ )
113
+ raise "gh api failed for #{path}" unless status.success?
114
+
115
+ out
116
+ end
117
+
118
+ def clean(lines)
119
+ lines.reject { |l| l.strip.empty? || l.start_with?("#") }.uniq
120
+ end
121
+
122
+ def write_grouped(namespace, slug, lines)
123
+ FileUtils.mkdir_p(File.join(OUT_DIR, namespace))
124
+ File.write(File.join(OUT_DIR, namespace, "#{slug}.txt"), lines.join("\n") << "\n")
125
+ printf(" %<path>-28s -> %<count>5d lines\n", path: "#{namespace}/#{slug}", count: lines.size)
126
+ end
127
+
128
+ def write_flat(namespace, lines)
129
+ File.write(File.join(OUT_DIR, "#{namespace}.txt"), lines.join("\n") << "\n")
130
+ printf(" %<path>-28s -> %<count>5d lines\n", path: namespace, count: lines.size)
131
+ end
132
+
133
+ FileUtils.mkdir_p(OUT_DIR)
134
+
135
+ buckets = Hash.new { |h, k| h[k] = [] }
136
+
137
+ SOURCES.each do |folder, (namespace, slug)|
138
+ files = gh_json(folder).select do |e|
139
+ e["type"] == "file" && e["name"].end_with?(".txt") && !SKIP_FILES.include?(e["name"])
140
+ end
141
+ buckets[[namespace, slug]].concat(files.flat_map { |e| gh_raw("#{folder}/#{e["name"]}").lines(chomp: true) })
142
+ end
143
+
144
+ MERGE_SOURCES.each do |path, dest|
145
+ lines = gh_raw(path).lines(chomp: true)
146
+ if dest.size == 1
147
+ buckets[[:flat, dest.first]].concat(lines)
148
+ else
149
+ buckets[dest].concat(lines)
150
+ end
151
+ end
152
+
153
+ buckets.each do |key, lines|
154
+ if key.first == :flat
155
+ write_flat(key.last, clean(lines))
156
+ else
157
+ namespace, slug = key
158
+ write_grouped(namespace, slug, clean(lines))
159
+ end
160
+ end
161
+
162
+ EMAIL_SOURCES.each do |path, slug|
163
+ write_grouped("email", slug, clean(gh_raw(path).lines(chomp: true)))
164
+ end
165
+
166
+ puts "\nDone. Run scripts/generate_namespaces.rb next to wire up any new subtypes."
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Generates one Ruby class per namespace found under lib/evil_faker/data/groups/,
4
+ # with an explicit `subtype` line for each sub-group file it finds -- plus one
5
+ # class per source (e.g. EvilFaker::Blns), exposing that source's full corpus
6
+ # unsorted by category.
7
+ #
8
+ # Reads namespace/subtype/source names straight off the filesystem (not off
9
+ # any *_build_corpus.rb script), so it works no matter which source(s)
10
+ # populated data/groups -- a namespace is whatever top-level entry (file or
11
+ # folder) exists under any groups/<source>/, and its subtypes are whatever
12
+ # .txt files live inside it.
13
+ #
14
+ # Usage: ruby scripts/generate_namespaces.rb
15
+ # Run after any of the scripts/*_build_corpus.rb importers.
16
+
17
+ require "fileutils"
18
+
19
+ ROOT = File.expand_path("..", __dir__)
20
+ GROUPS_ROOT = File.join(ROOT, "lib/evil_faker/data/groups")
21
+ OUT_DIR = File.join(ROOT, "lib/evil_faker/groups")
22
+ SOURCES_OUT_DIR = File.join(ROOT, "lib/evil_faker/sources")
23
+
24
+ def camelize(name)
25
+ name.split("_").map(&:capitalize).join
26
+ end
27
+
28
+ # namespace name -> subtype names (empty for a flat, single-file namespace)
29
+ namespace_subtypes = Hash.new { |h, k| h[k] = [] }
30
+
31
+ Dir.children(GROUPS_ROOT).sort.each do |source|
32
+ source_dir = File.join(GROUPS_ROOT, source)
33
+
34
+ Dir.children(source_dir).sort.each do |entry|
35
+ path = File.join(source_dir, entry)
36
+
37
+ if File.directory?(path)
38
+ ns = entry
39
+ subtypes = Dir.children(path).select { |f| f.end_with?(".txt") }.map { |f| File.basename(f, ".txt") }
40
+ namespace_subtypes[ns].concat(subtypes)
41
+ else
42
+ namespace_subtypes[File.basename(entry, ".txt")] # touch the key, no subtypes
43
+ end
44
+ end
45
+ end
46
+
47
+ FileUtils.rm_rf(OUT_DIR)
48
+ FileUtils.mkdir_p(OUT_DIR)
49
+
50
+ namespace_subtypes.sort.each do |ns, subtypes|
51
+ subtype_lines = subtypes.uniq.sort.map { |s| " subtype :#{s}\n" }.join
52
+
53
+ File.write(File.join(OUT_DIR, "#{ns}.rb"), <<~RUBY)
54
+ # frozen_string_literal: true
55
+
56
+ module EvilFaker
57
+ # Generated by scripts/generate_namespaces.rb -- do not edit by hand.
58
+ class #{camelize(ns)} < Base
59
+ group "#{ns}"
60
+ #{subtype_lines.empty? ? "" : "\n#{subtype_lines}"} end
61
+ end
62
+ RUBY
63
+ puts " #{ns}.rb#{subtypes.empty? ? "" : " (#{subtypes.uniq.size} subtypes)"}"
64
+ end
65
+
66
+ puts "\nGenerated #{namespace_subtypes.size} namespace classes in lib/evil_faker/groups/"
67
+
68
+ FileUtils.rm_rf(SOURCES_OUT_DIR)
69
+ FileUtils.mkdir_p(SOURCES_OUT_DIR)
70
+
71
+ sources = Dir.children(GROUPS_ROOT).sort
72
+
73
+ sources.each do |source|
74
+ File.write(File.join(SOURCES_OUT_DIR, "#{source}.rb"), <<~RUBY)
75
+ # frozen_string_literal: true
76
+
77
+ module EvilFaker
78
+ # Generated by scripts/generate_namespaces.rb -- do not edit by hand.
79
+ class #{camelize(source)} < SourceBase
80
+ source "#{source}"
81
+ end
82
+ end
83
+ RUBY
84
+ puts " #{source}.rb"
85
+ end
86
+
87
+ puts "\nGenerated #{sources.size} source classes in lib/evil_faker/sources/"
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Vendors a curated subset of 1N3/IntruderPayloads (MIT) into
4
+ # lib/evil_faker/data/groups/intruder_payloads/.
5
+ #
6
+ # Skipped entirely: BurpAttacks/ (binary .burp ZIP exports, not text),
7
+ # Plugins/ (.jar files), BurpBountyPayloads/ (JSON scanner-rule configs with
8
+ # only 1-2 payloads each behind a lot of scanner metadata -- not worth a
9
+ # parser for that little yield).
10
+ #
11
+ # Many FuzzLists/*.txt lines aren't standalone strings: they use the literal
12
+ # token INJECTX as a placeholder where Burp Intruder would splice in a
13
+ # payload from a *second* list. Those lines are meaningless out of context,
14
+ # so every line containing "injectx" (case-insensitive) is dropped. Three
15
+ # files are almost entirely such templates (xss_payloads_quick.txt,
16
+ # xss_remote_payloads-http(s).txt) and are skipped outright, as are
17
+ # grep_injectx.txt / payload_injectx.txt (pure template lists).
18
+ #
19
+ # Also skipped: dirbuster-*.txt / toplist-sorted.txt / passwords_*.txt /
20
+ # usernames.txt / vulnerability_discovery.txt (recon/credential wordlists,
21
+ # not adversarial field input) and url_payloads.txt (the author's own
22
+ # callback domains, not generically reusable).
23
+ #
24
+ # Uploads/ is different: the malicious payload IS the filename (e.g.
25
+ # `shell.php%00.jpg`), not file content -- so its entries are read from the
26
+ # directory listing itself and merged into the flat EvilFaker::Filenames group.
27
+ #
28
+ # Requires the `gh` CLI, authenticated (`gh auth status`).
29
+ #
30
+ # Usage: ruby scripts/intruder_payloads_build_corpus.rb
31
+
32
+ require "open3"
33
+ require "fileutils"
34
+ require "json"
35
+
36
+ ROOT = File.expand_path("..", __dir__)
37
+ OUT_DIR = File.join(ROOT, "lib/evil_faker/data/groups/intruder_payloads")
38
+ REPO = "1N3/IntruderPayloads"
39
+
40
+ # FuzzLists/<file> -> [EvilFaker namespace, subtype], merged file-by-file
41
+ # (unlike PayloadsAllTheThings, sources here are individual files, not
42
+ # whole folders).
43
+ FUZZLIST_SOURCES = {
44
+ "sqli-error-based.txt" => %w[injection sql],
45
+ "sqli-time-based.txt" => %w[injection sql],
46
+ "sqli-union-select.txt" => %w[injection sql],
47
+ "sqli_escape_chars.txt" => %w[injection sql],
48
+ "auth_bypass.txt" => %w[injection sql],
49
+ "xss_escape_chars.txt" => %w[injection script],
50
+ "xss_find_inject.txt" => %w[injection script],
51
+ "xss_funny_stored.txt" => %w[injection script],
52
+ "xss_grep.txt" => %w[injection script],
53
+ "xss_swf_fuzz.txt" => %w[injection script],
54
+ "lfi.txt" => %w[injection file_inclusion],
55
+ "traversal.txt" => %w[injection directory_traversal],
56
+ "traversal-short.txt" => %w[injection directory_traversal],
57
+ "xml-attacks.txt" => %w[injection xxe],
58
+ "command_exec.txt" => %w[injection command],
59
+ "ssi_quick.txt" => %w[injection server_side_include],
60
+ "overflow.txt" => %w[injection overflow],
61
+ "overflow-dos.txt" => %w[injection overflow],
62
+ "bad_chars.txt" => %w[unicode bad_chars],
63
+ "basic_fuzz.txt" => %w[injection generic],
64
+ "full_fuzz.txt" => %w[injection generic],
65
+ "quick_fuzz.txt" => %w[injection generic]
66
+ }.freeze
67
+
68
+ def gh_json(path)
69
+ out, status = Open3.capture2("gh", "api", "repos/#{REPO}/contents/#{path}")
70
+ raise "gh api failed for #{path}" unless status.success?
71
+
72
+ JSON.parse(out)
73
+ end
74
+
75
+ def gh_raw(path)
76
+ out, status = Open3.capture2(
77
+ "gh", "api", "-H", "Accept: application/vnd.github.raw", "repos/#{REPO}/contents/#{path}"
78
+ )
79
+ raise "gh api failed for #{path}" unless status.success?
80
+
81
+ out
82
+ end
83
+
84
+ def clean(lines)
85
+ lines.reject { |l| l.strip.empty? || l.start_with?("#") || l.match?(/injectx/i) }.uniq
86
+ end
87
+
88
+ def write(namespace, slug, lines)
89
+ FileUtils.mkdir_p(File.join(OUT_DIR, namespace))
90
+ File.write(File.join(OUT_DIR, namespace, "#{slug}.txt"), lines.join("\n") << "\n")
91
+ printf(" %<path>-28s -> %<count>5d lines\n", path: "#{namespace}/#{slug}", count: lines.size)
92
+ end
93
+
94
+ # Flat namespace (EvilFaker::Filenames has no subtypes) -> file goes straight at
95
+ # groups/intruder_payloads/<namespace>.txt, not nested in a subtype folder.
96
+ def write_flat(namespace, lines)
97
+ File.write(File.join(OUT_DIR, "#{namespace}.txt"), lines.join("\n") << "\n")
98
+ printf(" %<path>-28s -> %<count>5d lines\n", path: namespace, count: lines.size)
99
+ end
100
+
101
+ FileUtils.mkdir_p(OUT_DIR)
102
+
103
+ buckets = Hash.new { |h, k| h[k] = [] }
104
+ FUZZLIST_SOURCES.each do |file, (namespace, slug)|
105
+ buckets[[namespace, slug]].concat(gh_raw("FuzzLists/#{file}").lines(chomp: true))
106
+ end
107
+ buckets.each { |(namespace, slug), lines| write(namespace, slug, clean(lines)) }
108
+
109
+ upload_names = gh_json("Uploads").select { |e| e["type"] == "file" }.map { |e| e["name"] }
110
+ write_flat("filenames", upload_names.reject(&:empty?).uniq)
111
+
112
+ puts "\nDone. Run scripts/generate_namespaces.rb next to wire up any new subtypes."
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Vendors a curated subset of swisskyrepo/PayloadsAllTheThings (MIT) into
4
+ # lib/evil_faker/data/groups/payloads_all_the_things/.
5
+ #
6
+ # Only folders that ship a real Intruder/Intruders directory of plain .txt
7
+ # payloads are pulled in -- most of the repo's ~60 top-level folders are
8
+ # Markdown write-ups with no payload list to vendor, so this is a hand-picked
9
+ # allowlist, not a full mirror. Re-run to refresh; each namespace/slug's file
10
+ # is fully replaced from upstream every time (dedup + drop blank/comment lines).
11
+ #
12
+ # Requires the `gh` CLI, authenticated (`gh auth status`).
13
+ #
14
+ # Usage: ruby scripts/payloads_all_the_things_build_corpus.rb
15
+
16
+ require "open3"
17
+ require "fileutils"
18
+
19
+ ROOT = File.expand_path("..", __dir__)
20
+ OUT_DIR = File.join(ROOT, "lib/evil_faker/data/groups/payloads_all_the_things")
21
+ REPO = "swisskyrepo/PayloadsAllTheThings"
22
+
23
+ # upstream folder (with its Intruder/Intruders dir) -> [EvilFaker namespace, subtype]
24
+ SOURCES = {
25
+ "SQL Injection/Intruder" => %w[injection sql],
26
+ "NoSQL Injection/Intruder" => %w[injection nosql],
27
+ "LDAP Injection/Intruder" => %w[injection ldap],
28
+ "XSS Injection/Intruders" => %w[injection script],
29
+ "XXE Injection/Intruders" => %w[injection xxe],
30
+ "Server Side Template Injection/Intruder" => %w[injection ssti],
31
+ "Command Injection/Intruder" => %w[injection command],
32
+ "File Inclusion/Intruders" => %w[injection file_inclusion],
33
+ "Directory Traversal/Intruder" => %w[injection directory_traversal],
34
+ "Open Redirect/Intruder" => %w[injection open_redirect],
35
+ # Not injection payloads (single field strings) -- these are wordlists, so
36
+ # they get their own namespaces instead of forcing them into Injection.
37
+ "Insecure Management Interface/Intruder" => %w[routes admin_interfaces],
38
+ "Web Cache Deception/Intruders" => %w[headers cache_deception]
39
+ }.freeze
40
+
41
+ def gh_json(path)
42
+ out, status = Open3.capture2("gh", "api", "repos/#{REPO}/contents/#{path}")
43
+ raise "gh api failed for #{path}" unless status.success?
44
+
45
+ require "json"
46
+ JSON.parse(out)
47
+ end
48
+
49
+ def gh_raw(path)
50
+ out, status = Open3.capture2(
51
+ "gh", "api", "-H", "Accept: application/vnd.github.raw", "repos/#{REPO}/contents/#{path}"
52
+ )
53
+ raise "gh api failed for #{path}" unless status.success?
54
+
55
+ out
56
+ end
57
+
58
+ def clean(lines)
59
+ lines.reject { |l| l.strip.empty? || l.start_with?("#") }.uniq
60
+ end
61
+
62
+ def write(namespace, slug, lines)
63
+ FileUtils.mkdir_p(File.join(OUT_DIR, namespace))
64
+ File.write(File.join(OUT_DIR, namespace, "#{slug}.txt"), lines.join("\n") << "\n")
65
+ printf(" %<path>-28s -> %<count>5d lines\n", path: "#{namespace}/#{slug}", count: lines.size)
66
+ end
67
+
68
+ SOURCES.each do |folder, (namespace, slug)|
69
+ entries = gh_json(folder).select { |e| e["type"] == "file" }
70
+ lines = entries.flat_map { |e| gh_raw("#{folder}/#{e["name"]}").lines(chomp: true) }
71
+ write(namespace, slug, clean(lines))
72
+ end
73
+
74
+ puts "\nDone. Run scripts/generate_namespaces.rb next to wire up any new subtypes."
@@ -0,0 +1,4 @@
1
+ module EvilFaker
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end