pwn 0.5.708 → 0.5.710

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 (450) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -2
  3. data/documentation/Installation.md +1 -0
  4. data/etc/default_skills/exploitdev/SKILL.md +38 -0
  5. data/etc/default_skills/pwn/ai/agent/extrospection/osint/bridges/SKILL.md +30 -8
  6. data/etc/default_skills/pwn/ai/agent/extrospection/osint/social/SKILL.md +30 -8
  7. data/etc/default_skills/pwn/ai/agent/extrospection/osint/social/references/urls.md +1 -1
  8. data/etc/default_skills/pwn/ai/agent/extrospection/references/urls.md +0 -1
  9. data/etc/default_skills/pwn/memory_index/SKILL.md +0 -4
  10. data/etc/default_skills/pwn/plugins/aflplusplus/SKILL.md +49 -0
  11. data/etc/default_skills/pwn/plugins/android/SKILL.md +1 -0
  12. data/etc/default_skills/pwn/plugins/artifact_registry/SKILL.md +49 -0
  13. data/etc/default_skills/pwn/plugins/binary_parser/SKILL.md +54 -0
  14. data/etc/default_skills/pwn/plugins/credential_attack/SKILL.md +58 -0
  15. data/etc/default_skills/pwn/plugins/credential_attack/references/urls.md +3 -0
  16. data/etc/default_skills/pwn/plugins/exploit_db/SKILL.md +49 -0
  17. data/etc/default_skills/pwn/plugins/exploit_dev/SKILL.md +63 -0
  18. data/etc/default_skills/pwn/plugins/frida/SKILL.md +51 -0
  19. data/etc/default_skills/pwn/plugins/fuzz/SKILL.md +2 -0
  20. data/etc/default_skills/pwn/plugins/gdb/SKILL.md +53 -0
  21. data/etc/default_skills/pwn/plugins/jobs/SKILL.md +51 -0
  22. data/etc/default_skills/pwn/plugins/k8s/SKILL.md +51 -0
  23. data/etc/default_skills/pwn/plugins/nuclei/SKILL.md +50 -0
  24. data/etc/default_skills/pwn/plugins/preflight_checker/SKILL.md +59 -0
  25. data/etc/default_skills/pwn/plugins/process_tube/SKILL.md +53 -0
  26. data/etc/default_skills/pwn/plugins/radare2/SKILL.md +59 -0
  27. data/etc/default_skills/pwn/plugins/recon/SKILL.md +57 -0
  28. data/etc/default_skills/pwn/plugins/recon/references/urls.md +6 -0
  29. data/etc/default_skills/pwn/plugins/semgrep/SKILL.md +48 -0
  30. data/etc/default_skills/pwn/plugins/sqlmap/SKILL.md +48 -0
  31. data/etc/default_skills/pwn/plugins/transparent_browser/SKILL.md +0 -4
  32. data/etc/default_skills/pwn/plugins/volatility/SKILL.md +49 -0
  33. data/lib/pwn/ai/agent/assembly.rb +4 -1
  34. data/lib/pwn/ai/agent/btc.rb +4 -1
  35. data/lib/pwn/ai/agent/burp_suite.rb +5 -2
  36. data/lib/pwn/ai/agent/curriculum.rb +89 -30
  37. data/lib/pwn/ai/agent/dispatch.rb +27 -16
  38. data/lib/pwn/ai/agent/extrospection/osint/bridges.rb +9 -18
  39. data/lib/pwn/ai/agent/extrospection/osint/social.rb +9 -18
  40. data/lib/pwn/ai/agent/extrospection.rb +185 -60
  41. data/lib/pwn/ai/agent/gqrx.rb +4 -1
  42. data/lib/pwn/ai/agent/hacker_one.rb +5 -2
  43. data/lib/pwn/ai/agent/learning.rb +142 -25
  44. data/lib/pwn/ai/agent/loop.rb +53 -46
  45. data/lib/pwn/ai/agent/metrics.rb +133 -23
  46. data/lib/pwn/ai/agent/mistakes.rb +126 -17
  47. data/lib/pwn/ai/agent/open_goal.rb +25 -9
  48. data/lib/pwn/ai/agent/policy.rb +158 -18
  49. data/lib/pwn/ai/agent/prompt_builder.rb +21 -11
  50. data/lib/pwn/ai/agent/prompt_cache.rb +44 -13
  51. data/lib/pwn/ai/agent/reflect.rb +9 -5
  52. data/lib/pwn/ai/agent/registry.rb +65 -12
  53. data/lib/pwn/ai/agent/result.rb +19 -10
  54. data/lib/pwn/ai/agent/reward.rb +150 -32
  55. data/lib/pwn/ai/agent/sast.rb +4 -1
  56. data/lib/pwn/ai/agent/swarm.rb +72 -36
  57. data/lib/pwn/ai/agent/task_summarizer.rb +165 -36
  58. data/lib/pwn/ai/agent/tool_guard.rb +105 -6
  59. data/lib/pwn/ai/agent/tools/sessions.rb +8 -1
  60. data/lib/pwn/ai/agent/transparent_browser.rb +4 -1
  61. data/lib/pwn/ai/agent/turn_finalizer.rb +41 -21
  62. data/lib/pwn/ai/agent/vuln_gen.rb +6 -3
  63. data/lib/pwn/ai/agent.rb +4 -0
  64. data/lib/pwn/ai/anthropic.rb +41 -7
  65. data/lib/pwn/ai/gemini.rb +21 -11
  66. data/lib/pwn/ai/grok.rb +44 -6
  67. data/lib/pwn/ai/http_retry.rb +40 -12
  68. data/lib/pwn/ai/ollama.rb +19 -10
  69. data/lib/pwn/ai/open_ai.rb +81 -30
  70. data/lib/pwn/ai/open_web_ui.rb +20 -14
  71. data/lib/pwn/ai/red_team/agent_protocol_abuse.rb +7 -1
  72. data/lib/pwn/ai/red_team/data_and_model_poisoning.rb +7 -1
  73. data/lib/pwn/ai/red_team/excessive_agency.rb +7 -1
  74. data/lib/pwn/ai/red_team/hidden_context_exposure.rb +7 -1
  75. data/lib/pwn/ai/red_team/insecure_output_handling.rb +7 -1
  76. data/lib/pwn/ai/red_team/jailbreak.rb +7 -1
  77. data/lib/pwn/ai/red_team/memory_poisoning.rb +7 -1
  78. data/lib/pwn/ai/red_team/multimodal_injection.rb +7 -1
  79. data/lib/pwn/ai/red_team/overreliance.rb +7 -1
  80. data/lib/pwn/ai/red_team/payload_splitting.rb +7 -1
  81. data/lib/pwn/ai/red_team/prompt_injection.rb +7 -1
  82. data/lib/pwn/ai/red_team/rag_poisoning.rb +7 -1
  83. data/lib/pwn/ai/red_team/sensitive_information_disclosure.rb +7 -1
  84. data/lib/pwn/ai/red_team/supply_chain.rb +7 -1
  85. data/lib/pwn/ai/red_team/system_prompt_extraction.rb +7 -1
  86. data/lib/pwn/ai/red_team/test_case_engine.rb +12 -9
  87. data/lib/pwn/ai/red_team/token_smuggling.rb +7 -1
  88. data/lib/pwn/ai/red_team/unbounded_consumption.rb +7 -1
  89. data/lib/pwn/ai/red_team/vector_and_embedding_weaknesses.rb +7 -1
  90. data/lib/pwn/ai/red_team.rb +4 -0
  91. data/lib/pwn/ai.rb +4 -0
  92. data/lib/pwn/aws/acm.rb +5 -2
  93. data/lib/pwn/aws/api_gateway.rb +10 -7
  94. data/lib/pwn/aws/app_stream.rb +5 -2
  95. data/lib/pwn/aws/application_auto_scaling.rb +5 -2
  96. data/lib/pwn/aws/application_discovery_service.rb +5 -2
  97. data/lib/pwn/aws/auto_scaling.rb +5 -2
  98. data/lib/pwn/aws/batch.rb +5 -2
  99. data/lib/pwn/aws/budgets.rb +5 -2
  100. data/lib/pwn/aws/cloud_formation.rb +5 -2
  101. data/lib/pwn/aws/cloud_front.rb +7 -4
  102. data/lib/pwn/aws/cloud_hsm.rb +5 -2
  103. data/lib/pwn/aws/cloud_search.rb +5 -2
  104. data/lib/pwn/aws/cloud_search_domain.rb +5 -2
  105. data/lib/pwn/aws/cloud_trail.rb +5 -2
  106. data/lib/pwn/aws/cloud_watch.rb +5 -2
  107. data/lib/pwn/aws/cloud_watch_events.rb +5 -2
  108. data/lib/pwn/aws/cloud_watch_logs.rb +5 -2
  109. data/lib/pwn/aws/code_build.rb +5 -2
  110. data/lib/pwn/aws/code_commit.rb +5 -2
  111. data/lib/pwn/aws/code_deploy.rb +5 -2
  112. data/lib/pwn/aws/code_pipeline.rb +5 -2
  113. data/lib/pwn/aws/cognito_identity.rb +5 -2
  114. data/lib/pwn/aws/cognito_identity_provider.rb +5 -2
  115. data/lib/pwn/aws/cognito_sync.rb +5 -2
  116. data/lib/pwn/aws/config_service.rb +5 -2
  117. data/lib/pwn/aws/data_pipleline.rb +5 -2
  118. data/lib/pwn/aws/database_migration_service.rb +5 -2
  119. data/lib/pwn/aws/device_farm.rb +5 -2
  120. data/lib/pwn/aws/direct_connect.rb +5 -2
  121. data/lib/pwn/aws/directory_service.rb +5 -2
  122. data/lib/pwn/aws/dynamo_db.rb +5 -2
  123. data/lib/pwn/aws/dynamo_db_streams.rb +5 -2
  124. data/lib/pwn/aws/ec2.rb +5 -2
  125. data/lib/pwn/aws/ecr.rb +5 -2
  126. data/lib/pwn/aws/ecs.rb +5 -2
  127. data/lib/pwn/aws/efs.rb +5 -2
  128. data/lib/pwn/aws/elasti_cache.rb +5 -2
  129. data/lib/pwn/aws/elastic_beanstalk.rb +8 -5
  130. data/lib/pwn/aws/elastic_load_balancing.rb +5 -2
  131. data/lib/pwn/aws/elastic_load_balancing_v2.rb +6 -3
  132. data/lib/pwn/aws/elastic_transcoder.rb +5 -2
  133. data/lib/pwn/aws/elasticsearch_service.rb +5 -2
  134. data/lib/pwn/aws/emr.rb +5 -2
  135. data/lib/pwn/aws/firehose.rb +5 -2
  136. data/lib/pwn/aws/game_lift.rb +5 -2
  137. data/lib/pwn/aws/glacier.rb +6 -3
  138. data/lib/pwn/aws/health.rb +5 -2
  139. data/lib/pwn/aws/iam.rb +10 -4
  140. data/lib/pwn/aws/import_export.rb +5 -2
  141. data/lib/pwn/aws/inspector.rb +5 -2
  142. data/lib/pwn/aws/iot.rb +5 -2
  143. data/lib/pwn/aws/iot_data_plane.rb +5 -2
  144. data/lib/pwn/aws/kinesis.rb +5 -2
  145. data/lib/pwn/aws/kinesis_analytics.rb +5 -2
  146. data/lib/pwn/aws/kms.rb +5 -2
  147. data/lib/pwn/aws/lambda.rb +5 -2
  148. data/lib/pwn/aws/lambda_preview.rb +5 -2
  149. data/lib/pwn/aws/lex.rb +5 -2
  150. data/lib/pwn/aws/lightsail.rb +5 -2
  151. data/lib/pwn/aws/machine_learning.rb +5 -2
  152. data/lib/pwn/aws/marketplace_commerce_analytics.rb +5 -2
  153. data/lib/pwn/aws/marketplace_metering.rb +5 -2
  154. data/lib/pwn/aws/ops_works.rb +5 -2
  155. data/lib/pwn/aws/ops_works_cm.rb +5 -2
  156. data/lib/pwn/aws/pinpoint.rb +5 -2
  157. data/lib/pwn/aws/polly.rb +5 -2
  158. data/lib/pwn/aws/rds.rb +5 -2
  159. data/lib/pwn/aws/redshift.rb +5 -2
  160. data/lib/pwn/aws/rekognition.rb +5 -2
  161. data/lib/pwn/aws/route53.rb +5 -2
  162. data/lib/pwn/aws/route53_domains.rb +5 -2
  163. data/lib/pwn/aws/s3.rb +5 -2
  164. data/lib/pwn/aws/service_catalog.rb +5 -2
  165. data/lib/pwn/aws/ses.rb +5 -2
  166. data/lib/pwn/aws/shield.rb +5 -2
  167. data/lib/pwn/aws/simple_db.rb +5 -2
  168. data/lib/pwn/aws/sms.rb +5 -2
  169. data/lib/pwn/aws/snowball.rb +5 -2
  170. data/lib/pwn/aws/sns.rb +5 -2
  171. data/lib/pwn/aws/sqs.rb +5 -2
  172. data/lib/pwn/aws/ssm.rb +5 -2
  173. data/lib/pwn/aws/states.rb +5 -2
  174. data/lib/pwn/aws/storage_gateway.rb +5 -2
  175. data/lib/pwn/aws/sts.rb +4 -1
  176. data/lib/pwn/aws/support.rb +5 -2
  177. data/lib/pwn/aws/swf.rb +5 -2
  178. data/lib/pwn/aws/waf.rb +5 -2
  179. data/lib/pwn/aws/waf_regional.rb +5 -2
  180. data/lib/pwn/aws/workspaces.rb +5 -2
  181. data/lib/pwn/aws/x_ray.rb +5 -2
  182. data/lib/pwn/aws.rb +4 -0
  183. data/lib/pwn/banner/anon.rb +3 -0
  184. data/lib/pwn/banner/bubble.rb +3 -0
  185. data/lib/pwn/banner/cheshire.rb +3 -0
  186. data/lib/pwn/banner/code_cave.rb +3 -0
  187. data/lib/pwn/banner/dont_panic.rb +3 -0
  188. data/lib/pwn/banner/f_society.rb +3 -0
  189. data/lib/pwn/banner/fork_bomb.rb +3 -0
  190. data/lib/pwn/banner/jmp_esp.rb +3 -0
  191. data/lib/pwn/banner/matrix.rb +5 -1
  192. data/lib/pwn/banner/ninja.rb +3 -0
  193. data/lib/pwn/banner/off_the_air.rb +3 -0
  194. data/lib/pwn/banner/pirate.rb +3 -0
  195. data/lib/pwn/banner/radare2.rb +3 -0
  196. data/lib/pwn/banner/radare2_ai.rb +3 -0
  197. data/lib/pwn/banner/white_rabbit.rb +3 -0
  198. data/lib/pwn/banner.rb +6 -2
  199. data/lib/pwn/blockchain/btc.rb +8 -3
  200. data/lib/pwn/blockchain/eth.rb +10 -3
  201. data/lib/pwn/blockchain.rb +4 -0
  202. data/lib/pwn/bounty/lifecycle_authz_replay.rb +46 -27
  203. data/lib/pwn/bounty.rb +4 -0
  204. data/lib/pwn/config.rb +79 -13
  205. data/lib/pwn/cron.rb +297 -20
  206. data/lib/pwn/driver.rb +2 -18
  207. data/lib/pwn/ffi/adalm_pluto.rb +65 -11
  208. data/lib/pwn/ffi/fftw.rb +31 -6
  209. data/lib/pwn/ffi/hack_rf.rb +59 -8
  210. data/lib/pwn/ffi/liquid.rb +63 -10
  211. data/lib/pwn/ffi/rtl_sdr.rb +35 -5
  212. data/lib/pwn/ffi/soapy_sdr.rb +60 -10
  213. data/lib/pwn/ffi/stdio.rb +7 -8
  214. data/lib/pwn/ffi/volk.rb +36 -7
  215. data/lib/pwn/ffi.rb +12 -0
  216. data/lib/pwn/memory.rb +136 -16
  217. data/lib/pwn/memory_index.rb +34 -19
  218. data/lib/pwn/migrate.rb +34 -24
  219. data/lib/pwn/module_skills.rb +39 -8
  220. data/lib/pwn/plugins/aflplusplus.rb +72 -0
  221. data/lib/pwn/plugins/android.rb +71 -245
  222. data/lib/pwn/plugins/artifact_registry.rb +71 -0
  223. data/lib/pwn/plugins/assembly.rb +9 -4
  224. data/lib/pwn/plugins/authentication_helper.rb +8 -5
  225. data/lib/pwn/plugins/baresip.rb +59 -12
  226. data/lib/pwn/plugins/basic_auth.rb +9 -3
  227. data/lib/pwn/plugins/beef.rb +28 -18
  228. data/lib/pwn/plugins/binary_parser.rb +133 -0
  229. data/lib/pwn/plugins/black_duck_binary_analysis.rb +63 -39
  230. data/lib/pwn/plugins/burp_suite.rb +98 -68
  231. data/lib/pwn/plugins/bus_pirate.rb +15 -8
  232. data/lib/pwn/plugins/char.rb +33 -3
  233. data/lib/pwn/plugins/credential_attack.rb +158 -0
  234. data/lib/pwn/plugins/credit_card.rb +6 -1
  235. data/lib/pwn/plugins/dao_ldap.rb +19 -13
  236. data/lib/pwn/plugins/dao_mongo.rb +11 -5
  237. data/lib/pwn/plugins/dao_postgres.rb +28 -19
  238. data/lib/pwn/plugins/dao_sqlite3.rb +15 -6
  239. data/lib/pwn/plugins/defect_dojo.rb +38 -22
  240. data/lib/pwn/plugins/detect_os.rb +5 -0
  241. data/lib/pwn/plugins/ein.rb +3 -0
  242. data/lib/pwn/plugins/exploit_db.rb +69 -0
  243. data/lib/pwn/plugins/exploit_dev.rb +330 -0
  244. data/lib/pwn/plugins/file_fu.rb +11 -8
  245. data/lib/pwn/plugins/frida.rb +112 -0
  246. data/lib/pwn/plugins/fuzz.rb +42 -6
  247. data/lib/pwn/plugins/gdb.rb +115 -0
  248. data/lib/pwn/plugins/git.rb +19 -14
  249. data/lib/pwn/plugins/github.rb +38 -15
  250. data/lib/pwn/plugins/google_workspace.rb +188 -45
  251. data/lib/pwn/plugins/hacker_one.rb +159 -35
  252. data/lib/pwn/plugins/hunter.rb +6 -3
  253. data/lib/pwn/plugins/ip_info.rb +9 -4
  254. data/lib/pwn/plugins/irc.rb +28 -15
  255. data/lib/pwn/plugins/jenkins.rb +65 -57
  256. data/lib/pwn/plugins/jira_data_center.rb +30 -22
  257. data/lib/pwn/plugins/jobs.rb +110 -0
  258. data/lib/pwn/plugins/json_pathify.rb +9 -5
  259. data/lib/pwn/plugins/k8s.rb +73 -0
  260. data/lib/pwn/plugins/log.rb +113 -13
  261. data/lib/pwn/plugins/mail_agent.rb +87 -79
  262. data/lib/pwn/plugins/metasploit.rb +11 -6
  263. data/lib/pwn/plugins/monkey_patch.rb +3 -0
  264. data/lib/pwn/plugins/msr206.rb +42 -28
  265. data/lib/pwn/plugins/nessus_cloud.rb +44 -4
  266. data/lib/pwn/plugins/nexpose_vuln_scan.rb +40 -24
  267. data/lib/pwn/plugins/nmap_it.rb +14 -34
  268. data/lib/pwn/plugins/nuclei.rb +90 -0
  269. data/lib/pwn/plugins/oauth2.rb +11 -5
  270. data/lib/pwn/plugins/ocr.rb +3 -0
  271. data/lib/pwn/plugins/open_api.rb +5 -2
  272. data/lib/pwn/plugins/openvas.rb +33 -25
  273. data/lib/pwn/plugins/packet.rb +152 -31
  274. data/lib/pwn/plugins/pdf_parse.rb +5 -2
  275. data/lib/pwn/plugins/pony.rb +86 -1
  276. data/lib/pwn/plugins/preflight_checker.rb +166 -0
  277. data/lib/pwn/plugins/process_tube.rb +139 -0
  278. data/lib/pwn/plugins/ps.rb +7 -1
  279. data/lib/pwn/plugins/pwn_logger.rb +6 -2
  280. data/lib/pwn/plugins/rabbit_mq.rb +12 -7
  281. data/lib/pwn/plugins/radare2.rb +253 -0
  282. data/lib/pwn/plugins/recon.rb +196 -0
  283. data/lib/pwn/plugins/repl.rb +122 -1
  284. data/lib/pwn/plugins/scannable_codes.rb +5 -1
  285. data/lib/pwn/plugins/semgrep.rb +61 -0
  286. data/lib/pwn/plugins/serial.rb +24 -14
  287. data/lib/pwn/plugins/shodan.rb +54 -35
  288. data/lib/pwn/plugins/slack_client.rb +11 -6
  289. data/lib/pwn/plugins/sock.rb +17 -8
  290. data/lib/pwn/plugins/spider.rb +5 -2
  291. data/lib/pwn/plugins/sqlmap.rb +49 -0
  292. data/lib/pwn/plugins/ssn.rb +3 -0
  293. data/lib/pwn/plugins/thread_pool.rb +6 -9
  294. data/lib/pwn/plugins/tor.rb +9 -4
  295. data/lib/pwn/plugins/transparent_browser.rb +62 -107
  296. data/lib/pwn/plugins/tty_spinner.rb +16 -2
  297. data/lib/pwn/plugins/twitter_api.rb +6 -2
  298. data/lib/pwn/plugins/uri_scheme.rb +4 -1
  299. data/lib/pwn/plugins/vault.rb +12 -3
  300. data/lib/pwn/plugins/vin.rb +24 -12
  301. data/lib/pwn/plugins/voice.rb +7 -2
  302. data/lib/pwn/plugins/volatility.rb +67 -0
  303. data/lib/pwn/plugins/vsphere.rb +9 -5
  304. data/lib/pwn/plugins/xxd.rb +12 -43
  305. data/lib/pwn/plugins/zaproxy.rb +30 -16
  306. data/lib/pwn/plugins.rb +22 -0
  307. data/lib/pwn/reports/ai_red_team.rb +6 -2
  308. data/lib/pwn/reports/csv.rb +8 -1
  309. data/lib/pwn/reports/fuzz.rb +5 -2
  310. data/lib/pwn/reports/html.rb +8 -1
  311. data/lib/pwn/reports/html_footer.rb +4 -3
  312. data/lib/pwn/reports/html_header.rb +6 -2
  313. data/lib/pwn/reports/json.rb +8 -1
  314. data/lib/pwn/reports/markdown.rb +8 -1
  315. data/lib/pwn/reports/pdf.rb +8 -1
  316. data/lib/pwn/reports/phone.rb +5 -2
  317. data/lib/pwn/reports/sast.rb +6 -2
  318. data/lib/pwn/reports/uri_buster.rb +5 -2
  319. data/lib/pwn/reports/xml.rb +8 -1
  320. data/lib/pwn/reports.rb +19 -0
  321. data/lib/pwn/sast/amqp_connect_as_guest.rb +9 -3
  322. data/lib/pwn/sast/apache_file_system_util_api.rb +9 -3
  323. data/lib/pwn/sast/aws.rb +9 -3
  324. data/lib/pwn/sast/banned_function_calls_c.rb +9 -3
  325. data/lib/pwn/sast/base64.rb +9 -3
  326. data/lib/pwn/sast/beef_hook.rb +9 -3
  327. data/lib/pwn/sast/cmd_execution_go_lang.rb +9 -3
  328. data/lib/pwn/sast/cmd_execution_java.rb +9 -3
  329. data/lib/pwn/sast/cmd_execution_python.rb +9 -3
  330. data/lib/pwn/sast/cmd_execution_ruby.rb +9 -3
  331. data/lib/pwn/sast/cmd_execution_scala.rb +9 -3
  332. data/lib/pwn/sast/csrf.rb +9 -3
  333. data/lib/pwn/sast/deserial_java.rb +9 -3
  334. data/lib/pwn/sast/emoticon.rb +9 -3
  335. data/lib/pwn/sast/eval.rb +9 -3
  336. data/lib/pwn/sast/factory.rb +9 -3
  337. data/lib/pwn/sast/http_authorization_header.rb +9 -3
  338. data/lib/pwn/sast/inner_html.rb +9 -3
  339. data/lib/pwn/sast/keystore.rb +9 -3
  340. data/lib/pwn/sast/local_storage.rb +9 -3
  341. data/lib/pwn/sast/location_hash.rb +9 -3
  342. data/lib/pwn/sast/log4j.rb +9 -3
  343. data/lib/pwn/sast/logger.rb +9 -3
  344. data/lib/pwn/sast/md5.rb +9 -3
  345. data/lib/pwn/sast/outer_html.rb +9 -3
  346. data/lib/pwn/sast/padding_oracle.rb +9 -3
  347. data/lib/pwn/sast/password.rb +9 -3
  348. data/lib/pwn/sast/php_input_mechanisms.rb +9 -3
  349. data/lib/pwn/sast/php_type_juggling.rb +9 -3
  350. data/lib/pwn/sast/pom_version.rb +9 -3
  351. data/lib/pwn/sast/port.rb +9 -3
  352. data/lib/pwn/sast/post_message.rb +9 -3
  353. data/lib/pwn/sast/private_key.rb +9 -3
  354. data/lib/pwn/sast/redirect.rb +9 -3
  355. data/lib/pwn/sast/redos.rb +9 -3
  356. data/lib/pwn/sast/shell.rb +9 -3
  357. data/lib/pwn/sast/signature.rb +9 -3
  358. data/lib/pwn/sast/sql.rb +9 -3
  359. data/lib/pwn/sast/ssl.rb +9 -3
  360. data/lib/pwn/sast/sudo.rb +9 -3
  361. data/lib/pwn/sast/task_tag.rb +9 -3
  362. data/lib/pwn/sast/test_case_engine.rb +11 -7
  363. data/lib/pwn/sast/throw_errors.rb +9 -3
  364. data/lib/pwn/sast/token.rb +9 -3
  365. data/lib/pwn/sast/type_script_type_juggling.rb +9 -3
  366. data/lib/pwn/sast/use_after_free.rb +9 -3
  367. data/lib/pwn/sast/version.rb +9 -3
  368. data/lib/pwn/sast/window_location_hash.rb +9 -3
  369. data/lib/pwn/sast.rb +4 -0
  370. data/lib/pwn/sdr/decoder/adsb.rb +36 -5
  371. data/lib/pwn/sdr/decoder/apt.rb +9 -6
  372. data/lib/pwn/sdr/decoder/base.rb +74 -22
  373. data/lib/pwn/sdr/decoder/bluetooth.rb +17 -5
  374. data/lib/pwn/sdr/decoder/dect.rb +12 -3
  375. data/lib/pwn/sdr/decoder/dsp.rb +229 -39
  376. data/lib/pwn/sdr/decoder/flex.rb +59 -11
  377. data/lib/pwn/sdr/decoder/gps.rb +12 -3
  378. data/lib/pwn/sdr/decoder/gsm.rb +24 -4
  379. data/lib/pwn/sdr/decoder/iridium.rb +12 -3
  380. data/lib/pwn/sdr/decoder/lora.rb +13 -4
  381. data/lib/pwn/sdr/decoder/lte.rb +27 -3
  382. data/lib/pwn/sdr/decoder/morse.rb +12 -3
  383. data/lib/pwn/sdr/decoder/p25.rb +12 -3
  384. data/lib/pwn/sdr/decoder/pager.rb +8 -5
  385. data/lib/pwn/sdr/decoder/pocsag.rb +29 -9
  386. data/lib/pwn/sdr/decoder/rds.rb +14 -8
  387. data/lib/pwn/sdr/decoder/rfid.rb +12 -3
  388. data/lib/pwn/sdr/decoder/rtl433.rb +12 -3
  389. data/lib/pwn/sdr/decoder/rtty.rb +8 -5
  390. data/lib/pwn/sdr/decoder/wifi.rb +12 -3
  391. data/lib/pwn/sdr/decoder/zigbee.rb +12 -3
  392. data/lib/pwn/sdr/decoder.rb +9 -0
  393. data/lib/pwn/sdr/flipper_zero.rb +17 -10
  394. data/lib/pwn/sdr/frequency_allocation.rb +4 -1
  395. data/lib/pwn/sdr/gqrx.rb +178 -119
  396. data/lib/pwn/sdr/rfidler.rb +4 -1
  397. data/lib/pwn/sdr/son_micro_rfid.rb +37 -24
  398. data/lib/pwn/sdr.rb +14 -0
  399. data/lib/pwn/sessions.rb +86 -16
  400. data/lib/pwn/setup.rb +106 -37
  401. data/lib/pwn/version.rb +1 -1
  402. data/lib/pwn/www/app_cobalt_io.rb +11 -5
  403. data/lib/pwn/www/bing.rb +10 -5
  404. data/lib/pwn/www/bug_crowd.rb +11 -5
  405. data/lib/pwn/www/checkip.rb +8 -4
  406. data/lib/pwn/www/coinbase_pro.rb +11 -5
  407. data/lib/pwn/www/duckduckgo.rb +12 -6
  408. data/lib/pwn/www/facebook.rb +11 -5
  409. data/lib/pwn/www/github.rb +11 -5
  410. data/lib/pwn/www/google.rb +11 -5
  411. data/lib/pwn/www/hacker_one.rb +20 -9
  412. data/lib/pwn/www/linkedin.rb +11 -5
  413. data/lib/pwn/www/pandora.rb +11 -5
  414. data/lib/pwn/www/pastebin.rb +9 -4
  415. data/lib/pwn/www/paypal.rb +19 -11
  416. data/lib/pwn/www/synack.rb +11 -5
  417. data/lib/pwn/www/torch.rb +13 -8
  418. data/lib/pwn/www/trading_view.rb +11 -5
  419. data/lib/pwn/www/twitter.rb +11 -5
  420. data/lib/pwn/www/uber.rb +11 -5
  421. data/lib/pwn/www/upwork.rb +11 -5
  422. data/lib/pwn/www/wayback_machine.rb +12 -6
  423. data/lib/pwn/www/youtube.rb +10 -5
  424. data/lib/pwn/www.rb +4 -0
  425. data/spec/conventions_spec.rb +118 -2
  426. data/spec/integration/help_contract_spec.rb +2 -0
  427. data/spec/lib/pwn/ai/agent/reward_spec.rb +9 -0
  428. data/spec/lib/pwn/plugins/aflplusplus_spec.rb +13 -0
  429. data/spec/lib/pwn/plugins/artifact_registry_spec.rb +13 -0
  430. data/spec/lib/pwn/plugins/binary_parser_spec.rb +21 -0
  431. data/spec/lib/pwn/plugins/credential_attack_spec.rb +13 -0
  432. data/spec/lib/pwn/plugins/exploit_db_spec.rb +13 -0
  433. data/spec/lib/pwn/plugins/exploit_dev_spec.rb +23 -0
  434. data/spec/lib/pwn/plugins/frida_spec.rb +13 -0
  435. data/spec/lib/pwn/plugins/gdb_spec.rb +13 -0
  436. data/spec/lib/pwn/plugins/jobs_spec.rb +13 -0
  437. data/spec/lib/pwn/plugins/k8s_spec.rb +13 -0
  438. data/spec/lib/pwn/plugins/nuclei_spec.rb +13 -0
  439. data/spec/lib/pwn/plugins/preflight_checker_spec.rb +23 -0
  440. data/spec/lib/pwn/plugins/process_tube_spec.rb +13 -0
  441. data/spec/lib/pwn/plugins/radare2_spec.rb +13 -0
  442. data/spec/lib/pwn/plugins/recon_spec.rb +26 -0
  443. data/spec/lib/pwn/plugins/semgrep_spec.rb +13 -0
  444. data/spec/lib/pwn/plugins/sqlmap_spec.rb +13 -0
  445. data/spec/lib/pwn/plugins/volatility_spec.rb +13 -0
  446. data/spec/lib/pwn/req_queue_spec.rb +168 -0
  447. data/third_party/pwn_rdoc.jsonl +160 -5
  448. metadata +63 -7
  449. data/etc/default_skills/pwn/memory_index/references/urls.md +0 -4
  450. data/etc/default_skills/pwn/plugins/transparent_browser/references/urls.md +0 -3
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pty'
4
+ require 'timeout'
5
+ require 'socket'
6
+
7
+ module PWN
8
+ module Plugins
9
+ # PTY.spawn tube: sendline/recvuntil/recvline, persisted across pwn_eval.
10
+ module ProcessTube
11
+ @tubes = {}
12
+
13
+ public_class_method def self.required_bins
14
+ []
15
+ end
16
+
17
+ public_class_method def self.spawn(opts = {})
18
+ cmd = opts[:cmd] || opts[:command]
19
+ raise 'ERROR: cmd is required' if cmd.to_s.empty?
20
+
21
+ argv = cmd.is_a?(Array) ? cmd.map(&:to_s) : ['bash', '-lc', cmd.to_s]
22
+ r, w, pid = PTY.spawn(*argv)
23
+ id = "tube_#{pid}"
24
+ @tubes[id] = { r: r, w: w, pid: pid, buf: +'' }
25
+ { id: id, pid: pid }
26
+ end
27
+
28
+ public_class_method def self.connect(opts = {})
29
+ host = (opts[:host] || opts[:target]).to_s
30
+ port = opts[:port].to_i
31
+ raise 'ERROR: host and port are required' if host.empty? || port <= 0
32
+
33
+ sock = TCPSocket.new(host, port)
34
+ id = "sock_#{sock.object_id}"
35
+ @tubes[id] = { r: sock, w: sock, pid: nil, buf: +'' }
36
+ { id: id, host: host, port: port }
37
+ end
38
+
39
+ public_class_method def self.write_line(opts = {})
40
+ t = tube!(opts)
41
+ line = opts[:line] || opts[:data] || ''
42
+ t[:w].write("#{line}\n")
43
+ t[:w].flush
44
+ line.to_s
45
+ end
46
+
47
+ public_class_method def self.recvuntil(opts = {})
48
+ t = tube!(opts)
49
+ needle = opts[:until].to_s
50
+ raise 'ERROR: until is required' if needle.empty?
51
+
52
+ timeout = (opts[:timeout] || 5).to_f
53
+ Timeout.timeout(timeout) do
54
+ loop do
55
+ return t[:buf] if t[:buf].include?(needle)
56
+
57
+ ch = t[:r].read_nonblock(4_096)
58
+ t[:buf] << ch
59
+ rescue IO::WaitReadable
60
+ t[:r].wait_readable(0.2)
61
+ retry
62
+ end
63
+ end
64
+ end
65
+
66
+ public_class_method def self.recvline(opts = {})
67
+ recvuntil(opts.merge(until: "\n"))
68
+ end
69
+
70
+ public_class_method def self.close(opts = {})
71
+ t = tube!(opts)
72
+ t[:w].close
73
+ t[:r].close
74
+ Process.kill('TERM', t[:pid]) if t[:pid]
75
+ @tubes.delete(opts[:id].to_s)
76
+ true
77
+ rescue StandardError
78
+ @tubes.delete(opts[:id].to_s)
79
+ false
80
+ end
81
+
82
+ public_class_method def self.authors
83
+ "AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n"
84
+ end
85
+
86
+ public_class_method def self.help
87
+ puts "USAGE:
88
+ # List host binaries this module expects to be installed.
89
+ #{self}.required_bins
90
+
91
+ # Run spawn and return its result
92
+ #{self}.spawn(
93
+ cmd: 'required - command string to run (defaults to opts[:command])',
94
+ command: 'optional - command value consumed by #spawn'
95
+ )
96
+
97
+ # Connect a TCP tube with the same write_line/recvuntil API as spawn.
98
+ #{self}.connect(
99
+ host: 'required - hostname or IP address (defaults to opts[:target])',
100
+ target: 'optional - hostname, IP, or CIDR to scan',
101
+ port: 'required - TCP/UDP port number'
102
+ )
103
+
104
+ # Run write line and return its result
105
+ #{self}.write_line(
106
+ line: 'optional - line value consumed by #write_line',
107
+ data: 'optional - data value consumed by #write_line'
108
+ )
109
+
110
+ # Run recvuntil and return its result
111
+ #{self}.recvuntil(
112
+ until: 'required - until value consumed by #recvuntil',
113
+ timeout: 'optional - seconds to wait before giving up'
114
+ )
115
+
116
+ # Run recvline and return its result
117
+ #{self}.recvline
118
+
119
+ # Close a session previously returned by #open.
120
+ #{self}.close(
121
+ id: 'optional - id value consumed by #close'
122
+ )
123
+
124
+ # Print the AUTHOR(S) string for this module.
125
+ #{self}.authors
126
+ "
127
+ constants.sort
128
+ end
129
+
130
+ private_class_method def self.tube!(opts = {})
131
+ id = opts[:id].to_s
132
+ t = @tubes[id]
133
+ raise 'ERROR: id is required / unknown tube' unless t
134
+
135
+ t
136
+ end
137
+ end
138
+ end
139
+ end
@@ -76,14 +76,20 @@ module PWN
76
76
 
77
77
  public_class_method def self.help
78
78
  puts "USAGE:
79
- proc_list_arr = #{self}.list
79
+ # Run list and return its result
80
+ #{self}.list(
81
+ pid: 'optional - pid value consumed by #list'
82
+ )
80
83
 
84
+ # Run cleanup pids and return its result
81
85
  #{self}.cleanup_pids(
82
86
  pids_arr: 'required - array of pids to kill'
83
87
  )
84
88
 
89
+ # Print the AUTHOR(S) string for this module.
85
90
  #{self}.authors
86
91
  "
92
+ constants.sort
87
93
  end
88
94
  end
89
95
  end
@@ -53,11 +53,15 @@ module PWN
53
53
 
54
54
  public_class_method def self.help
55
55
  puts "USAGE:
56
- logger = #{self}.create(
57
- level: 'optional - logging verbosity :debug|:error|:fatal|:info|:unknown|:warn (Defaults to :info)'
56
+ # Run create and return its result
57
+ #{self}.create(
58
+ level: 'optional - level value consumed by #create'
58
59
  )
60
+
61
+ # Print the AUTHOR(S) string for this module.
59
62
  #{self}.authors
60
63
  "
64
+ constants.sort
61
65
  end
62
66
  end
63
67
  end
@@ -50,20 +50,25 @@ module PWN
50
50
  # Display Usage for this Module
51
51
 
52
52
  public_class_method def self.help
53
- puts %{USAGE:
54
- amqp_conn1 = #{self}.open(
55
- hostname: 'required',
53
+ puts "USAGE:
54
+ # Open a session or connection and return a handle.
55
+ #{self}.open(
56
+ hostname: 'required - hostname value consumed by #open',
56
57
  port: 'optional - defaults to 5672',
57
- username: 'optional',
58
- password: 'optional'
58
+ username: 'optional - username value consumed by #open',
59
+ password: 'optional - password value consumed by #open'
59
60
  )
60
61
 
62
+ # Close a session previously returned by #open.
61
63
  #{self}.close(
62
- amqp_oject: amqp_conn1
64
+ amqp_oject: 'optional - amqp oject value consumed by #close',
65
+ amqp_obj: 'optional - amqp obj value consumed by #close'
63
66
  )
64
67
 
68
+ # Print the AUTHOR(S) string for this module.
65
69
  #{self}.authors
66
- }
70
+ "
71
+ constants.sort
67
72
  end
68
73
  end
69
74
  end
@@ -0,0 +1,253 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'open3'
5
+ require 'securerandom'
6
+
7
+ module PWN
8
+ module Plugins
9
+ # Persistent r2pipe-style session: open/cmd/cmdj/close plus helpers.
10
+ module Radare2
11
+ @sessions = {}
12
+
13
+ public_class_method def self.required_bins
14
+ %w[r2]
15
+ end
16
+
17
+ # Supported Method Parameters::
18
+ # session = PWN::Plugins::Radare2.open(
19
+ # path: 'required - filesystem path to the binary r2 should open'
20
+ # )
21
+ public_class_method def self.open(opts = {})
22
+ PWN::Plugins::PreflightChecker.require_bin!(name: 'r2')
23
+ path = opts[:path].to_s
24
+ raise 'ERROR: path is required' if path.empty?
25
+ raise "ERROR: binary not found: #{path}" unless File.file?(path)
26
+
27
+ stdin, stdout, waiter = Open3.popen2('r2', '-q0', '-e', 'scr.color=0', path)
28
+ sid = SecureRandom.hex(8)
29
+ @sessions[sid] = { stdin: stdin, stdout: stdout, waiter: waiter, path: path }
30
+ read_until_null(io: stdout)
31
+ sid
32
+ end
33
+
34
+ # Supported Method Parameters::
35
+ # text = PWN::Plugins::Radare2.cmd(
36
+ # session: 'required - session id returned by #open',
37
+ # cmd: 'required - r2 command to run; returns raw text (e.g. pdf @ main)'
38
+ # )
39
+ public_class_method def self.cmd(opts = {})
40
+ sess = session!(opts)
41
+ line = opts[:cmd].to_s
42
+ raise 'ERROR: cmd is required' if line.empty?
43
+
44
+ sess[:stdin].write("#{line}\n")
45
+ sess[:stdin].flush
46
+ read_until_null(io: sess[:stdout])
47
+ end
48
+
49
+ # Supported Method Parameters::
50
+ # json = PWN::Plugins::Radare2.cmdj(
51
+ # session: 'required - session id returned by #open',
52
+ # cmd: 'required - r2 command; trailing j is added if missing and stdout is JSON.parse (e.g. afl or aflj)'
53
+ # )
54
+ public_class_method def self.cmdj(opts = {})
55
+ raw = cmd(opts.merge(cmd: opts[:cmd].to_s.sub(/j?\z/, 'j')))
56
+ JSON.parse(raw)
57
+ rescue JSON::ParserError
58
+ raw
59
+ end
60
+
61
+ # Supported Method Parameters::
62
+ # PWN::Plugins::Radare2.close(
63
+ # session: 'required - session id returned by #open'
64
+ # )
65
+ public_class_method def self.close(opts = {})
66
+ sess = session!(opts)
67
+ sess[:stdin].write("q\n")
68
+ sess[:stdin].close
69
+ sess[:stdout].close
70
+ @sessions.delete(opts[:session].to_s)
71
+ true
72
+ rescue StandardError
73
+ @sessions.delete(opts[:session].to_s)
74
+ false
75
+ end
76
+
77
+ # Supported Method Parameters::
78
+ # PWN::Plugins::Radare2.functions(
79
+ # session: 'required - session id returned by #open'
80
+ # )
81
+ public_class_method def self.functions(opts = {})
82
+ cmdj(opts.merge(cmd: 'aflj'))
83
+ end
84
+
85
+ # Supported Method Parameters::
86
+ # PWN::Plugins::Radare2.xrefs_to(
87
+ # session: 'required - session id returned by #open',
88
+ # addr: 'required - address or flag to list xrefs to (e.g. main or 0x401000)'
89
+ # )
90
+ public_class_method def self.xrefs_to(opts = {})
91
+ addr = opts[:addr].to_s
92
+ cmdj(opts.merge(cmd: "axtj #{addr}"))
93
+ end
94
+
95
+ # Supported Method Parameters::
96
+ # PWN::Plugins::Radare2.disasm(
97
+ # session: 'required - session id returned by #open',
98
+ # addr: 'required - address or flag to disassemble from',
99
+ # n: 'optional - instruction count (defaults to 32)'
100
+ # )
101
+ public_class_method def self.disasm(opts = {})
102
+ addr = opts[:addr].to_s
103
+ n = (opts[:n] || 32).to_i
104
+ cmd(opts.merge(cmd: "pd #{n} @ #{addr}"))
105
+ end
106
+
107
+ # Supported Method Parameters::
108
+ # PWN::Plugins::Radare2.strings(
109
+ # session: 'required - session id returned by #open'
110
+ # )
111
+ public_class_method def self.strings(opts = {})
112
+ cmdj(opts.merge(cmd: 'izj'))
113
+ end
114
+
115
+ # Supported Method Parameters::
116
+ # PWN::Plugins::Radare2.imports(
117
+ # session: 'required - session id returned by #open'
118
+ # )
119
+ public_class_method def self.imports(opts = {})
120
+ cmdj(opts.merge(cmd: 'iij'))
121
+ end
122
+
123
+ # Supported Method Parameters::
124
+ # PWN::Plugins::Radare2.sections(
125
+ # session: 'required - session id returned by #open'
126
+ # )
127
+ public_class_method def self.sections(opts = {})
128
+ cmdj(opts.merge(cmd: 'iSj'))
129
+ end
130
+
131
+ # Supported Method Parameters::
132
+ # PWN::Plugins::Radare2.binary_info(
133
+ # session: 'required - session id returned by #open'
134
+ # )
135
+ public_class_method def self.binary_info(opts = {})
136
+ cmdj(opts.merge(cmd: 'iIj'))
137
+ end
138
+
139
+ # Supported Method Parameters::
140
+ # PWN::Plugins::Radare2.decompile(
141
+ # session: 'required - session id returned by #open',
142
+ # addr: 'required - address or flag to decompile (needs r2ghidra)'
143
+ # )
144
+ public_class_method def self.decompile(opts = {})
145
+ addr = opts[:addr].to_s
146
+ cmd(opts.merge(cmd: "pdg @ #{addr}"))
147
+ rescue StandardError => e
148
+ { error: "#{e.class}: #{e.message}", hint: 'r2ghidra plugin may be absent' }
149
+ end
150
+
151
+ public_class_method def self.authors
152
+ "AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n"
153
+ end
154
+
155
+ public_class_method def self.help
156
+ puts "USAGE:
157
+ # List host binaries this module expects to be installed.
158
+ #{self}.required_bins
159
+
160
+ # Open the binary in r2 (-q0) and return a session id.
161
+ #{self}.open(
162
+ path: 'required - filesystem path to the binary r2 should open'
163
+ )
164
+
165
+ # Run a command and return raw text output.
166
+ #{self}.cmd(
167
+ session: 'required - session id returned by #open',
168
+ cmd: 'required - r2 command to run; returns raw text (e.g. pdf @ main)'
169
+ )
170
+
171
+ # Run a command, request JSON, and parse the result.
172
+ #{self}.cmdj(
173
+ session: 'required - session id returned by #open',
174
+ cmd: 'required - r2 command; trailing j is added if missing and stdout is JSON.parse (e.g. afl or aflj)'
175
+ )
176
+
177
+ # Close a session previously returned by #open.
178
+ #{self}.close(
179
+ session: 'required - session id returned by #open'
180
+ )
181
+
182
+ # List functions after analysis (aflj JSON).
183
+ #{self}.functions(
184
+ session: 'required - session id returned by #open'
185
+ )
186
+
187
+ # List xrefs to an address or flag (axtj JSON).
188
+ #{self}.xrefs_to(
189
+ session: 'required - session id returned by #open',
190
+ addr: 'required - address or flag to list xrefs to (e.g. main or 0x401000)'
191
+ )
192
+
193
+ # Disassemble n instructions at addr (pd text).
194
+ #{self}.disasm(
195
+ session: 'required - session id returned by #open',
196
+ addr: 'required - address or flag to disassemble from',
197
+ n: 'optional - instruction count (defaults to 32)'
198
+ )
199
+
200
+ # List strings in the binary (izj JSON).
201
+ #{self}.strings(
202
+ session: 'required - session id returned by #open'
203
+ )
204
+
205
+ # List imported symbols (iij JSON).
206
+ #{self}.imports(
207
+ session: 'required - session id returned by #open'
208
+ )
209
+
210
+ # List sections / segments (iSj JSON).
211
+ #{self}.sections(
212
+ session: 'required - session id returned by #open'
213
+ )
214
+
215
+ # Print binary header info (iIj JSON).
216
+ #{self}.binary_info(
217
+ session: 'required - session id returned by #open'
218
+ )
219
+
220
+ # Decompile a function at addr via r2ghidra (pdg text).
221
+ #{self}.decompile(
222
+ session: 'required - session id returned by #open',
223
+ addr: 'required - address or flag to decompile (needs r2ghidra)'
224
+ )
225
+
226
+ # Print the AUTHOR(S) string for this module.
227
+ #{self}.authors
228
+ "
229
+ constants.sort
230
+ end
231
+
232
+ private_class_method def self.session!(opts = {})
233
+ sid = opts[:session].to_s
234
+ sess = @sessions[sid]
235
+ raise 'ERROR: session is required / unknown' unless sess
236
+
237
+ sess
238
+ end
239
+
240
+ private_class_method def self.read_until_null(opts = {})
241
+ io = opts[:io]
242
+ buf = +''
243
+ loop do
244
+ ch = io.read(1)
245
+ break if ch.nil? || ch == "\x00"
246
+
247
+ buf << ch
248
+ end
249
+ buf
250
+ end
251
+ end
252
+ end
253
+ end
@@ -0,0 +1,196 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'open3'
5
+ require 'net/http'
6
+ require 'uri'
7
+ require 'timeout'
8
+
9
+ module PWN
10
+ module Plugins
11
+ # subfinder/httpx/masscan wrappers + cert-transparency (crt.sh, certspotter).
12
+ module Recon
13
+ UA = 'pwn-recon/1.0'
14
+
15
+ public_class_method def self.required_bins
16
+ []
17
+ end
18
+
19
+ public_class_method def self.subdomains(opts = {})
20
+ domain = opts[:domain].to_s.downcase.strip
21
+ raise 'ERROR: domain is required' if domain.empty?
22
+
23
+ names = []
24
+ if PWN::Plugins::PreflightChecker.bin?(name: 'subfinder')
25
+ stdout, = Open3.capture3('subfinder', '-silent', '-d', domain)
26
+ names.concat(stdout.lines.map(&:strip).reject(&:empty?))
27
+ end
28
+ if PWN::Plugins::PreflightChecker.bin?(name: 'amass')
29
+ stdout, = Open3.capture3('amass', 'enum', '-passive', '-d', domain, '-nocolor')
30
+ names.concat(stdout.lines.map(&:strip).reject(&:empty?))
31
+ end
32
+ names.concat(Array(crt_sh(domain: domain)))
33
+ normalize_names(names: names, domain: domain)
34
+ end
35
+
36
+ public_class_method def self.httpx(opts = {})
37
+ PWN::Plugins::PreflightChecker.require_bin!(name: 'httpx')
38
+ hosts = Array(opts[:hosts] || opts[:urls])
39
+ stdout, = Open3.capture3('httpx', '-silent', '-json', stdin_data: "#{hosts.join("\n")}\n")
40
+ stdout.each_line.filter_map do |ln|
41
+ JSON.parse(ln)
42
+ rescue JSON::ParserError
43
+ nil
44
+ end
45
+ end
46
+
47
+ public_class_method def self.masscan(opts = {})
48
+ bin = %w[masscan naabu].find { |b| PWN::Plugins::PreflightChecker.bin?(name: b) }
49
+ raise PWN::Plugins::PreflightChecker::MissingBinary, 'ERROR: masscan/naabu missing' unless bin
50
+
51
+ target = opts[:target].to_s
52
+ ports = (opts[:ports] || '1-1024').to_s
53
+ stdout, = Open3.capture3(bin, '-p', ports, target)
54
+ stdout
55
+ end
56
+
57
+ public_class_method def self.crt_sh(opts = {})
58
+ domain = opts[:domain].to_s.downcase.strip
59
+ raise 'ERROR: domain is required' if domain.empty?
60
+
61
+ errors = []
62
+ names = []
63
+ sources = [
64
+ "https://api.certspotter.com/v1/issuances?domain=#{URI.encode_www_form_component(domain)}&include_subdomains=true&expand=dns_names",
65
+ "https://crt.sh/?q=#{URI.encode_www_form_component(domain)}&output=json",
66
+ "https://crt.sh/?q=#{URI.encode_www_form_component("%.#{domain}")}&output=json"
67
+ ]
68
+ sources.each do |url|
69
+ next if !names.empty? && url.include?('crt.sh')
70
+
71
+ rows = http_json(url: url, timeout: url.include?('crt.sh') ? 8 : (opts[:timeout] || 15))
72
+ names.concat(extract_dns_names(rows: rows))
73
+ rescue StandardError => e
74
+ errors << "#{URI(url).host}: #{e.class}: #{e.message}"
75
+ end
76
+ out = normalize_names(names: names, domain: domain)
77
+ return out unless out.empty?
78
+
79
+ raise "ERROR: cert-transparency lookup failed for #{domain} (#{errors.join('; ')})"
80
+ end
81
+
82
+ public_class_method def self.amass(opts = {})
83
+ PWN::Plugins::PreflightChecker.require_bin!(name: 'amass')
84
+ domain = opts[:domain].to_s
85
+ raise 'ERROR: domain is required' if domain.empty?
86
+
87
+ stdout, = Open3.capture3('amass', 'enum', '-passive', '-d', domain, '-nocolor')
88
+ stdout.lines.map(&:strip).reject(&:empty?)
89
+ end
90
+
91
+ public_class_method def self.passive_dns(opts = {})
92
+ domain = opts[:domain].to_s.downcase.strip
93
+ raise 'ERROR: domain is required' if domain.empty?
94
+
95
+ uri = URI("https://api.hackertarget.com/hostsearch/?q=#{URI.encode_www_form_component(domain)}")
96
+ rows = http_json(url: uri.to_s, timeout: opts[:timeout] || 8)
97
+ Array(rows)
98
+ rescue StandardError => e
99
+ { error: "#{e.class}: #{e.message}", domain: domain }
100
+ end
101
+
102
+ public_class_method def self.authors
103
+ "AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n"
104
+ end
105
+
106
+ public_class_method def self.help
107
+ puts "USAGE:
108
+ # List host binaries this module expects to be installed.
109
+ #{self}.required_bins
110
+
111
+ # Run subdomains and return its result
112
+ #{self}.subdomains(
113
+ domain: 'required - FQDN to query (e.g. example.com)'
114
+ )
115
+
116
+ # Run httpx and return its result
117
+ #{self}.httpx(
118
+ hosts: 'optional - Array of hostnames or URLs to probe',
119
+ urls: 'optional - Array of HTTP(S) URLs'
120
+ )
121
+
122
+ # Run masscan and return its result
123
+ #{self}.masscan(
124
+ target: 'optional - hostname, IP, or CIDR to scan',
125
+ ports: 'optional - port, list, or range (e.g. 22,80,443 or 1-1024)'
126
+ )
127
+
128
+ # Run crt sh and return its result
129
+ #{self}.crt_sh(
130
+ domain: 'required - FQDN to query (e.g. example.com)',
131
+ timeout: 'optional - seconds to wait before giving up'
132
+ )
133
+
134
+ # Passive amass enum (requires amass).
135
+ #{self}.amass(
136
+ domain: 'required - FQDN to query (e.g. example.com)'
137
+ )
138
+
139
+ # Passive DNS hostsearch for a domain (hackertarget).
140
+ #{self}.passive_dns(
141
+ domain: 'required - FQDN to query (e.g. example.com)',
142
+ timeout: 'optional - seconds to wait before giving up'
143
+ )
144
+
145
+ # Print the AUTHOR(S) string for this module.
146
+ #{self}.authors
147
+ "
148
+ constants.sort
149
+ end
150
+
151
+ private_class_method def self.http_json(opts = {})
152
+ uri = URI(opts[:url].to_s)
153
+ timeout = (opts[:timeout] || 15).to_i
154
+ req = Net::HTTP::Get.new(uri)
155
+ req['User-Agent'] = UA
156
+ req['Accept'] = 'application/json'
157
+ http = Net::HTTP.new(uri.host, uri.port)
158
+ http.use_ssl = (uri.scheme == 'https')
159
+ http.open_timeout = [timeout, 8].min
160
+ http.read_timeout = timeout
161
+ http.max_retries = 0
162
+ res = Timeout.timeout(timeout + 2) { http.request(req) }
163
+ raise "HTTP #{res.code}" unless res.is_a?(Net::HTTPSuccess)
164
+
165
+ body = res.body.to_s
166
+ raise JSON::ParserError, body[0, 120] unless body.lstrip.start_with?('[', '{')
167
+
168
+ JSON.parse(body)
169
+ end
170
+
171
+ private_class_method def self.extract_dns_names(opts = {})
172
+ rows = opts[:rows]
173
+ return [] if rows.nil?
174
+
175
+ Array(rows).flat_map do |row|
176
+ next [] unless row.is_a?(Hash)
177
+
178
+ vals = []
179
+ vals.concat(Array(row['dns_names'] || row[:dns_names]))
180
+ vals.concat(row['name_value'].to_s.split(/[\s,]+/))
181
+ vals.concat(row['common_name'].to_s.split(/[\s,]+/))
182
+ vals
183
+ end
184
+ end
185
+
186
+ private_class_method def self.normalize_names(opts = {})
187
+ domain = opts[:domain].to_s.downcase
188
+ Array(opts[:names]).map { |n| n.to_s.strip.downcase.delete_prefix('*.') }
189
+ .reject(&:empty?)
190
+ .select { |n| n == domain || n.end_with?(".#{domain}") }
191
+ .uniq
192
+ .sort
193
+ end
194
+ end
195
+ end
196
+ end